11# -*- coding: utf-8
2+ import collections
23import uuid
34
45from . import base
@@ -31,6 +32,11 @@ class BaseSection(base.sectionable, Section):
3132 def __init__ (self , name , type = None , parent = None ,
3233 definition = None , reference = None ,
3334 repository = None , link = None , include = None , id = None ):
35+
36+ # Sets _sections Smartlist and _repository to None, so run first.
37+ super (BaseSection , self ).__init__ ()
38+ self ._props = base .SmartList ()
39+
3440 try :
3541 if id is not None :
3642 self ._id = str (uuid .UUID (id ))
@@ -40,17 +46,16 @@ def __init__(self, name, type=None, parent=None,
4046 print (e )
4147 self ._id = str (uuid .uuid4 ())
4248
43- self ._parent = None
4449 self ._name = name
45- self ._props = base .SmartList ()
4650 self ._definition = definition
4751 self ._reference = reference
4852 self ._repository = repository
4953 self ._link = link
5054 self ._include = include
51- super ( BaseSection , self ). __init__ ()
55+
5256 # this may fire a change event, so have the section setup then
5357 self .type = type
58+ self ._parent = None
5459 self .parent = parent
5560
5661 def __repr__ (self ):
@@ -254,47 +259,94 @@ def get_merged_equivalent(self):
254259 """
255260 return self ._merged
256261
257- def __append (self , obj ):
262+ def append (self , obj ):
258263 """
259- Append a Section or Property
264+ Method adds single Sections and Properties to the respective child-lists
265+ of the current Section.
266+
267+ :param obj: Section or Property object.
260268 """
261269 if isinstance (obj , Section ):
262270 self ._sections .append (obj )
263271 obj ._parent = self
264272 elif isinstance (obj , Property ):
265273 self ._props .append (obj )
266274 obj ._parent = self
275+ elif isinstance (obj , collections .Iterable ) and not isinstance (obj , str ):
276+ raise ValueError ("odml.Section.append: "
277+ "Use extend to add a list of Sections or Properties." )
267278 else :
268- raise ValueError ("Can only append sections and properties" )
279+ raise ValueError ("odml.Section.append: "
280+ "Can only append Sections or Properties." )
269281
270- def append (self , * obj_tuple ):
282+ def extend (self , obj_list ):
271283 """
272- Append Sections or Properties
284+ Method adds Sections and Properties to the respective child-lists
285+ of the current Section.
286+
287+ :param obj_list: Iterable containing Section and Property entries.
273288 """
274- for obj in obj_tuple :
275- self .__append (obj )
289+ if not isinstance (obj_list , collections .Iterable ):
290+ raise TypeError ("'%s' object is not iterable" % type (obj_list ).__name__ )
291+
292+ # Make sure only Sections and Properties with unique names will be added.
293+ for obj in obj_list :
294+ if not isinstance (obj , Section ) and not isinstance (obj , Property ):
295+ raise ValueError ("odml.Section.extend: "
296+ "Can only extend sections and properties." )
297+
298+ elif isinstance (obj , Section ) and obj .name in self .sections :
299+ raise KeyError ("odml.Section.extend: "
300+ "Section with name '%s' already exists." % obj .name )
301+
302+ elif isinstance (obj , Property ) and obj .name in self .properties :
303+ raise KeyError ("odml.Section.extend: "
304+ "Property with name '%s' already exists." % obj .name )
305+
306+ for obj in obj_list :
307+ self .append (obj )
276308
277309 def insert (self , position , obj ):
278310 """
279- Insert a Section or Property at the respective position
311+ Insert a Section or a Property at the respective child-list position.
312+ A ValueError will be raised, if a Section or a Property with the same
313+ name already exists in the respective child-list.
314+
315+ :param position: index at which the object should be inserted.
316+ :param obj: Section or Property object.
280317 """
281318 if isinstance (obj , Section ):
319+ if obj .name in self .sections :
320+ raise ValueError ("odml.Section.insert: "
321+ "Section with name '%s' already exists." % obj .name )
322+
282323 self ._sections .insert (position , obj )
283324 obj ._parent = self
284325 elif isinstance (obj , Property ):
326+ if obj .name in self .properties :
327+ raise ValueError ("odml.Section.insert: "
328+ "Property with name '%s' already exists." % obj .name )
329+
285330 self ._props .insert (position , obj )
286- obj ._section = self
331+ obj ._parent = self
287332 else :
288333 raise ValueError ("Can only insert sections and properties" )
289334
290335 def remove (self , obj ):
291- # TODO make sure this is not compare based
336+ """
337+ Remove a Section or a Property from the respective child-lists of the current
338+ Section and sets the parent attribute of the handed in object to None.
339+ Raises a ValueError if the object is not a Section or a Property or if
340+ the object is not contained in the child-lists.
341+
342+ :param obj: Section or Property object.
343+ """
292344 if isinstance (obj , Section ):
293345 self ._sections .remove (obj )
294346 obj ._parent = None
295347 elif isinstance (obj , Property ):
296348 self ._props .remove (obj )
297- obj ._section = None
349+ obj ._parent = None
298350 else :
299351 raise ValueError ("Can only remove sections and properties" )
300352
@@ -330,21 +382,36 @@ def clone(self, children=True):
330382
331383 def contains (self , obj ):
332384 """
333- Finds a property or section with the same name&type properties or None
385+ If the child-lists of the current Section contain a Section with
386+ the same *name* and *type* or a Property with the same *name* as
387+ the provided object, the found Section or Property is returned.
388+
389+ :param obj: Section or Property object.
334390 """
335391 if isinstance (obj , Section ):
336392 return super (BaseSection , self ).contains (obj )
337- for i in self ._props :
338- if obj .name == i .name :
339- return i
340393
341- def merge (self , section = None ):
394+ elif isinstance (obj , Property ):
395+ for i in self ._props :
396+ if obj .name == i .name :
397+ return i
398+ else :
399+ raise ValueError ("odml.Section.contains:"
400+ "Section or Property object expected." )
401+
402+ def merge (self , section = None , strict = True ):
342403 """
343- Merges this section with another *section*
404+ Merges this section with another *section*.
344405 See also: :py:attr:`odml.section.BaseSection.link`
345406 If section is none, sets the link/include attribute (if _link or
346407 _include are set), causing the section to be automatically merged
347408 to the referenced section.
409+
410+ :param section: an odML Section. If section is None, *link* or *include*
411+ will be resolved instead.
412+ :param strict: Bool value to indicate whether the attributes of affected
413+ child Properties except their ids and values have to be identical
414+ to be merged. Default is True.
348415 """
349416 if section is None :
350417 # for the high level interface
@@ -357,7 +424,7 @@ def merge(self, section=None):
357424 for obj in section :
358425 mine = self .contains (obj )
359426 if mine is not None :
360- mine .merge (obj )
427+ mine .merge (obj , strict )
361428 else :
362429 mine = obj .clone ()
363430 mine ._merged = obj
@@ -414,4 +481,30 @@ def can_be_merged(self):
414481 """
415482 Returns True if either a *link* or an *include* attribute is specified
416483 """
417- return self ._link is not None or self ._include is not None
484+ return self ._link is not None or self ._include is not None
485+
486+ def _reorder (self , childlist , new_index ):
487+ l = childlist
488+ old_index = l .index (self )
489+
490+ # 2 cases: insert after old_index / insert before
491+ if new_index > old_index :
492+ new_index += 1
493+ l .insert (new_index , self )
494+ if new_index < old_index :
495+ del l [old_index + 1 ]
496+ else :
497+ del l [old_index ]
498+ return old_index
499+
500+ def reorder (self , new_index ):
501+ """
502+ Move this object in its parent child-list to the position *new_index*.
503+
504+ :return: The old index at which the object was found.
505+ """
506+ if not self .parent :
507+ raise ValueError ("odml.Section.reorder: "
508+ "Section has no parent, cannot reorder in parent list." )
509+
510+ return self ._reorder (self .parent .sections , new_index )
0 commit comments