1from Attr import Attr 2 3 4class ListAttr(Attr): 5 """This is an attribute that refers to a set of other user-defined objects. 6 7 It cannot include basic data types or instances of classes that are not part 8 of the object model. 9 """ 10 11 def __init__(self, attr): 12 Attr.__init__(self, attr) 13 self._className = attr['Type'].rsplit(None, 1)[-1] 14 self._backRefAttr = None # init'ed in awakeFromRead() 15 if self.get('Min') is not None: 16 self['Min'] = int(self['Min']) 17 if self.get('Max') is not None: 18 self['Max'] = int(self['Max']) 19 20 def className(self): 21 """Return the name of the base class that this obj ref attribute points to.""" 22 return self._className 23 24 def backRefAttrName(self): 25 """Return the name of the back-reference attribute in the referenced class. 26 27 It is necessary to be able to override the default back ref to create 28 data structures like trees, in which a Middle object might reference 29 a parent and multiple children, all of the same class as itself. 30 """ 31 assert self._backRefAttr is not None 32 return self._backRefAttr 33 34 def awakeFromRead(self): 35 """Check that the target class and backRefAttr actually exist.""" 36 # Check that for "list of Foo", Foo actually exists. And, 37 # Compute self._targetKlass. 38 from Model import ModelError 39 self._targetKlass = self.model().klass(self.className(), None) 40 if not self._targetKlass: 41 raise ModelError('class %s: attr %s:' 42 ' cannot locate target class %s for this list.' 43 % (self.klass().name(), self.name(), self.className())) 44 45 # Compute self._backRefAttr. 46 if 'BackRefAttr' in self: 47 backRefName = self['BackRefAttr'] 48 else: 49 backRefName = self.klass().name() 50 attr = self._targetKlass.lookupAttr(backRefName, None) 51 if attr is None: 52 className = self.klass().name() 53 backRefName = className[0].lower() + className[1:] 54 self._backRefAttr = backRefName 55 56 # Check that the backRefAttr, whether explicit or implicit, exists in the target class. 57 backRefAttr = self._targetKlass.lookupAttr(self.backRefAttrName(), None) 58 if backRefAttr is None: 59 raise ModelError('class %s: attr %s: cannot locate backref attr' 60 ' %s.%s for this list.' % (self.klass().name(), self.name(), 61 self.className(), self.backRefAttrName())) 62 backRefAttr['isBackRefAttr'] = True 63