diff options
Diffstat (limited to 'intern/python/modules/mcf/utils/hierobj.py')
-rw-r--r-- | intern/python/modules/mcf/utils/hierobj.py | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/intern/python/modules/mcf/utils/hierobj.py b/intern/python/modules/mcf/utils/hierobj.py new file mode 100644 index 00000000000..7730b4d3ba4 --- /dev/null +++ b/intern/python/modules/mcf/utils/hierobj.py @@ -0,0 +1,133 @@ +''' +Generic Hierarchic Objects Module +Hierobj's store their children (which can be anything) in their +__childlist__ attribute, and provide methods for walking the +hierarchy, either collecting results or not. + +The index function returns an index of the objects (effectively a +flattened copy of the hierarchy) + +97-03-17 Added ability to pass arguments to hier_rapply and hier_rreturn. +97-10-31 Removed dependencies on mcf.store +''' +import copy,types +import singletonlist, hier_rx + +class Hierobj: + ''' + An abstract class which handles hierarchic functions and information + # remade as a DAG 97-04-02, also reduced memory overhead for + hier-r* functions by using while-del-IndexError construct versus + for loop (probably makes it slower though) + If you require a true hierarchy, use the TrueHierobj class below... + ''' + def __init__(self, parent=None, childlist=None): + if parent is None: # passed no parents + self.__dict__['__parent__'] = [] + elif type(parent) == types.ListType: # passed a list of parents + self.__dict__['__parent__'] = parent + else: # passed a single parent + self.__dict__['__parent__'] = [parent] + self.__dict__['__childlist__'] = childlist or [] + for child in self.__childlist__: + try: + child.__parent__.append(self) + except: + pass + # import simple hierarchic processing methods + hier_rapply = hier_rx.hier_rapply + hier_rreturn = hier_rx.hier_rreturn + hier_rgetattr = hier_rx.hier_rgetattr + hier_rmethod = hier_rx.hier_rmethod + + + def hier_addchild(self, child): + ''' + Add a single child to the childlist + ''' + self.__childlist__.append(child) + try: + # Hierobj-aware child + child.__parent__.append(self) # raises error if not hier_obj aware + except (TypeError, AttributeError): + # Non Hierobj-aware child + pass + append = hier_addchild + def hier_remchild(self, child): + ''' + Breaks the child relationship with child, including the + reciprocal parent relationship + ''' + try: + self.__childlist__.remove(child) + try: + child.hier_remparent(self) # if this fails, no problem + except AttributeError: pass + except (AttributeError,ValueError): + return 0 # didn't manage to remove the child + return 1 # succeeded + def hier_remparent(self, parent): + ''' + Normally only called by hier_remchild of the parent, + just removes the parent from the child's parent list, + but leaves child in parent's childlist + ''' + try: + self.__parent__.remove(parent) + except (AttributeError,ValueError): + return 0 + return 1 + def hier_replacewith(self,newel): + ''' + As far as the hierarchy is concerned, the new element + is exactly the same as the old element, it has all + the same children, all the same parents. The old + element becomes completely disconnected from the hierarchy, + but it still retains all of its references + + For every parent, replace this as a child + For every child, replace this as the parent + ''' + for parent in self.__parent__: + try: + parent.hier_replacechild(self, newel) + except AttributeError: + pass + for child in self.__childlist__: + try: + child.hier_replaceparent(self,parent) + except AttributeError: + pass + def hier_replaceparent(self, oldparent, newparent): + ind = self.__parent__.index(oldparent) + self.__parent__[ind] = newparent + def hier_replacechild(self, oldchild, newchild): + ind = self.__childlist__.index(oldchild) + self.__childlist__[ind] = newchild + +class TrueHierobj(Hierobj): + ''' + An inefficient implementation of an Hierobj which limits the + __parent__ attribute to a single element. This will likely be + _slower_ than an equivalent Hierobj. That will have to be fixed + eventually. + ''' + def __init__(self, parent=None, childlist=[]): + if parent is None: # passed no parents + self.__dict__['__parent__'] = singletonlist.SingletonList() + else: # passed a single parent + self.__dict__['__parent__'] = singletonlist.SingletonList(parent) + self.__dict__['__childlist__'] = copy.copy(childlist) + for child in self.__childlist__: + try: + child.__parent__.append(self) + except: + pass + +def index(grove): + ''' + Returns a flattened version of the grove + ''' + return grove.hier_rreturn(lambda x: x) + + |