2002-10-12 11:37:38 +00:00
|
|
|
'''
|
|
|
|
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
|
|
|
|
'''
|
2003-01-06 17:27:43 +00:00
|
|
|
#import copy,types
|
|
|
|
import types
|
2002-10-12 11:37:38 +00:00
|
|
|
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)
|
|
|
|
|
|
|
|
|