Skip to content

Commit a66ecdf

Browse files
authored
Merge pull request #271 from mpsonntag/secUpdate
Section updates
2 parents 9d8af75 + 31b8ff1 commit a66ecdf

5 files changed

Lines changed: 584 additions & 123 deletions

File tree

odml/base.py

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -77,28 +77,6 @@ def clone(self, children=True):
7777
obj = copy.copy(self)
7878
return obj
7979

80-
def _reorder(self, childlist, new_index):
81-
l = childlist
82-
old_index = l.index(self)
83-
84-
# 2 cases: insert after old_index / insert before
85-
if new_index > old_index:
86-
new_index += 1
87-
l.insert(new_index, self)
88-
if new_index < old_index:
89-
del l[old_index + 1]
90-
else:
91-
del l[old_index]
92-
return old_index
93-
94-
def reorder(self, new_index):
95-
"""
96-
Move this object in its parent child-list to the position *new_index*
97-
98-
Returns the old index at which the object was found
99-
"""
100-
raise NotImplementedError
101-
10280
def __hash__(self):
10381
"""
10482
Allow all odML objects to be hash-able.
@@ -217,10 +195,6 @@ def append(self, *vsection_tuple):
217195
self._sections.append(vsection)
218196
vsection._parent = self
219197

220-
@inherit_docstring
221-
def reorder(self, new_index):
222-
return self._reorder(self.parent.sections, new_index)
223-
224198
def remove(self, section):
225199
""" Removes the specified child-section """
226200
self._sections.remove(section)

odml/section.py

Lines changed: 115 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# -*- coding: utf-8
2+
import collections
23
import uuid
34

45
from . 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)

test/test_msec.py

Lines changed: 0 additions & 67 deletions
This file was deleted.

0 commit comments

Comments
 (0)