123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- """
- provides node functionality for the eventable odml types
- Document, Section, Property and Value
- additionally implements change notifications up to the corresponding section
- """
- import odml.property
- import odml.tools.event as event
- def identity_index(obj, val):
- """
- same as obj.index(val) but will only return a position
- if the object val is found in the list
- i.e.
- >>> identity_index(["1"], "1")
- will raise an ValueError because the two strings
- are different objects with the same content
- >>> a = "1"
- >>> identity_index([a], a)
- 0
- The difference to obj.index comes apparent here as well:
- >>> a="1", b="1"
- >>> identity_index([a,b], b)
- 1
- >>> [a,b].index(b)
- 0
- """
- for i, v in enumerate(obj):
- if v is val: return i
- import pdb; pdb.set_trace()
- raise ValueError("%s does not contain the item %s" % (repr(obj), repr(val)))
- class RootNode(object):
- @property
- def children(self):
- return self._sections
- def from_path(self, path):
- child = self.children[path[0]]
- if len(path) == 1:
- return child
- return child.from_path(path[1:])
- def to_path(self, parent=None):
- return ()
- def path_to(self, child):
- """return the path from this node to its direct child *child*"""
- return (identity_index(self._sections, child),)
- class ParentedNode(RootNode):
- def to_path(self, parent=None):
- if self.parent is parent:
- return self.parent.path_to(self)
- return self.parent.to_path(parent) + self.parent.path_to(self)
- def successor(self):
- return self.parent.children[self.position + 1]
- def next(self):
- """
- returns the next section following in this section's parent's list of sections
- returns None if there is no further element available
- i.e.:
- parent
- sec-a (<- self)
- sec-b
- will return sec-b
- """
- try:
- return self.successor()
- except IndexError:
- return None
- @property
- def position(self):
- return self.parent.path_to(self)[-1]
- class SectionNode(ParentedNode):
- """
- SectionNodes are special as they wrap two types of sub-nodes:
- * SubSections (path = (0, idx))
- * Properties (path = (1, idx))
- """
- def from_path(self, path):
- assert len(path) > 1
- if path[0] == 0: # sections
- return super(SectionNode, self).from_path(path[1:])
- # else: properties
- child = self._props[path[1]]
- if len(path) == 2:
- return child
- return child.from_path(path[2:])
- def path_to(self, child):
- if isinstance(child, odml.property.Property):
- return (1, identity_index(self._props, child))
- return (0, identity_index(self._sections, child))
- class PropertyNode(ParentedNode):
- @property
- def children(self):
- return self.values
- def successor(self):
- return self.parent._props[self.position + 1]
- def path_to(self, child):
- return (identity_index(self.values, child),)
- class ValueNode(ParentedNode):
- def path_from(self, path):
- raise TypeError("Value objects have no children")
- def path_to(self, child):
- raise TypeError("Value objects have no children")
- #TODO? provide this externally?
- name = "nodes"
- provides = event.provides + ["nodes"]
- class Document(event.Document, RootNode): pass
- class Value(event.Value, ValueNode): pass
- class Property(event.Property, PropertyNode): pass
- class Section(event.Section, SectionNode): pass
- import sys, odml
- odml.addImplementation(sys.modules[__name__])
|