Package cells :: Module family
[hide private]
[frames] | no frames]

Source Code for Module cells.family

  1  # PyCells: Automatic dataflow management for Python 
  2  # Copyright (C) 2006, Ryan Forsythe 
  3   
  4  # This library is free software; you can redistribute it and/or 
  5  # modify it under the terms of the GNU Lesser General Public 
  6  # License as published by the Free Software Foundation; either 
  7  # version 2.1 of the License, or (at your option) any later version. 
  8  # See LICENSE for the full license text. 
  9   
 10  # This library is distributed in the hope that it will be useful, 
 11  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
 13  # Lesser General Public License for more details. 
 14   
 15  # You should have received a copy of the GNU Lesser General Public 
 16  # License along with this library; if not, write to the Free Software 
 17  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA 
 18   
 19  """ 
 20  Family, a specialized C{L{Model}} for networks of C{L{Model}}s. 
 21   
 22  @var DEBUG: Turns on debugging messages for the cellattr module. 
 23  """ 
 24   
 25  DEBUG = False 
 26   
 27  import cells 
 28  from model import Model, ModelMetatype 
 29  from cellattr import CellAttr 
 30  from cell import ListCell 
 31   
32 -def _debug(*msgs):
33 """ 34 debug() -> None 35 36 Prints debug messages. 37 """ 38 msgs = list(msgs) 39 msgs.insert(0, "family".rjust(cells._DECO_OFFSET) + " > ") 40 if DEBUG or cells.DEBUG: 41 print " ".join(msgs)
42
43 -class Family(Model):
44 """ 45 Family 46 47 A specialized C{L{Model}} which has C{kids}, C{kid_slots}, and a 48 number of convenience functions for traversing the parent/child 49 graph. 50 51 @ivar kids: A list of Models which are guaranteed to have the 52 attribute overrides defined in C{L{kid_slots}} 53 54 @ivar kid_slots: An override definition for the Cells inserted 55 into the C{L{kids}} list. The attributes overridden are every 56 attribute defined in the class in C{kid_slots} minus the 57 attributes defined in every Model. 58 """ 59 kids = cells.makecell(celltype=ListCell, kid_overrides=False) 60 kid_slots = cells.makecell(value=Model, kid_overrides=False) 61
62 - def __init__(self, *args, **kwargs):
63 Model.__init__(self, *args, **kwargs)
64
65 - def _kid_instance(self, klass=None):
66 """ 67 _kid_instance(self, klass) -> Cell 68 69 Creates a new instance of a Cell based on the passed class (in 70 C{klass}) and the overrides defined in C{kid_slots}. 71 72 @param klass: The base type for the new kid instance 73 """ 74 if not klass: 75 klass = self.kid_slots 76 _debug("making an instance of", str(klass)) 77 # first, find the attributes the kid_slots attrib actual wants to 78 # define: 79 override_attrnames = [] 80 for attrname in dir(self.kid_slots): 81 cvar = getattr(self.kid_slots, attrname) 82 # if it's a cell attribute, check to see if it's one of 83 # the "special", non-overriding slots (eg kids) 84 if isinstance(cvar, CellAttr): 85 if cvar.kid_overrides: 86 # and if it isn't, add it to the list of overrides 87 override_attrnames.append(attrname) 88 # if it's a normal attribute, override only if it doesn't 89 # exist in the base class 90 else: 91 if attrname not in dir(cells.Family): 92 override_attrnames.append(attrname) 93 94 # now, do the overrides, bypassing normal getattrs 95 for attrib_name in override_attrnames: 96 _debug("overriding", attrib_name, "in", str(klass)) 97 setattr(klass, attrib_name, self.kid_slots.__dict__[attrib_name]) 98 99 # add any observers the kid_slots class defines: 100 klass._observernames.update(self.kid_slots._observernames) 101 102 # XXX: should we memoize all that work here? 103 104 # finally, return an instance of that munged class with this obj set 105 # as its parent: 106 i = klass(parent=self) 107 return i
108
109 - def make_kid(self, klass):
110 """ 111 make_kid(self, klass) -> None 112 113 Adds a new instance of a Cell based on the passed class (in 114 C{klass}) and the overrides defined in C{kid_slots} into the 115 C{kids} list 116 117 @param klass: the base type for the new kid instance 118 """ 119 _debug("make_kid called with", str(klass)) 120 self._add_kid(self._kid_instance(klass))
121
122 - def _add_kid(self, kid):
123 """ 124 _add_kid(self, kid) -> None 125 126 Inserts the kid into this Family's C{kids} list 127 128 @param kid: the Model instance to insert 129 """ 130 kid.parent = self 131 self.kids.append(kid)
132
133 - def position(self):
134 """ 135 position(self) -> int 136 137 Returns this instance's position in the enclosing Family's 138 C{kids} list. Returns -1 if there is no enclosing Family. 139 140 @raise FamilyTraversalError: Raises if there is no enclosing Family 141 """ 142 if self.parent: 143 return self.parent.kids.index(self) 144 raise FamilyTraversalError("No enclosing Family")
145
146 - def previous_sib(self):
147 """ 148 previous_sib(self) -> Model 149 150 Returns the Model previous to this Model in the enclosing 151 Family's C{kids} list 152 153 @raise FamilyTraversalError: Raises if there is no enclosing Family 154 """ 155 if self.parent and self.position() > 0: 156 return self.parent.kids[self.position() - 1] 157 raise FamilyTraversalError("No enclosing Family")
158
159 - def next_sib(self):
160 """ 161 previous_sib(self) -> Model 162 163 Returns the Model subsequent to this Model in the enclosing 164 Family's C{kids} list 165 166 @raise FamilyTraversalError: Raises if there is no enclosing Family 167 """ 168 if self.parent and self.position() < len(self.parent.kids) - 1: 169 return self.parent.kids[self.position() + 1] 170 raise FamilyTraversalError("No enclosing Family")
171
172 - def grandparent(self):
173 """ 174 grandparent(self) -> Model 175 176 Returns enclosing Family instance's enclosing Family instance, 177 or None if no such object exists. 178 """ 179 # raise or just return None? 180 if self.parent: 181 if self.parent.parent: 182 return self.parent.parent 183 return None
184
185 -class FamilyTraversalError(Exception):
186 """ 187 Raised when there's some sort of error in C{L{Family}}'s traversal 188 methods. 189 """
190 - def __init__(self, value):
191 self.value = value
192 - def __str__(self):
193 return repr(self.value)
194