Changeset 548
- Timestamp:
- 06/03/03 08:14:22 (5 years ago)
- Files:
-
- trunk/RBFoundation/RBFoundation/Objects/Relations.py (modified) (6 diffs)
- trunk/RBFoundation/RBFoundation/SubObs/Event.py (modified) (2 diffs)
- trunk/RBFoundation/RBFoundation/SubObs/Interface/__init__.py (modified) (1 diff)
- trunk/RBFoundation/RBFoundation/SubObs/Publish.py (modified) (3 diffs)
- trunk/RBFoundation/plans/todo.txt (modified) (1 diff)
- trunk/RBFoundation/test/Objects/test_Relations.py (modified) (2 diffs)
- trunk/RBFoundation/test/test_URIparser.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/RBFoundation/RBFoundation/Objects/Relations.py
r547 r548 24 24 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 25 25 26 from __future__ import generators 27 from RBFoundation.Objects.Properties import LazyProperty 28 from RBFoundation.SubObs.Event import EventSubjectProperty 29 26 30 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 27 31 #~ Definitions … … 29 33 30 34 class RelationsCollection(object): 35 OnModifying = EventSubjectProperty() # (collection, [items]) 36 OnModified = EventSubjectProperty() # (collection, [items]) 37 31 38 def __len__(self): 32 39 return len(list(iter(self))) … … 47 54 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 48 55 56 class NullRelations(RelationsCollection): 57 """An empty compliant implementation of RelationsCollection""" 58 def __len__(self): 59 return 0 60 61 def __iter__(self): 62 raise StopIteration 63 64 def __contains__(self, item): 65 return False 66 67 def extend(self, relations): 68 raise NotImplementedError 69 70 def append(self, relation): 71 raise NotImplementedError 72 73 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 74 49 75 class RelationsBag(RelationsCollection): 50 """A simple, modifyable implementation of RelationsCollection""" 51 52 def __init__(self): 53 self.bag = list() 76 """A simple, modifyable implementation of RelationsCollection as a list""" 77 78 def __init__(self, bag=None): 79 if bag is None: 80 self.bag = list() 81 else: 82 self.bag = bag 54 83 55 84 def __contains__(self, relation): … … 63 92 64 93 def append(self, relation): 65 return self.bag.append(relation) 94 self.OnModifying(self, [relation]) 95 self.bag.append(relation) 96 self.OnModified(self, [relation]) 66 97 67 98 def extend(self, relations): 68 return self.bag.extend(relations) 69 70 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 71 72 class Relationships(RelationsCollection): 99 self.OnModifying(self, relations) 100 self.bag.extend(relations) 101 self.OnModified(self, relations) 102 103 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 104 105 class RelationsLookup(RelationsCollection): 106 """A simple, modifyable implementation of RelationsCollection as a dictionary""" 107 73 108 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 74 109 #~ Constants / Variables / Etc. 75 110 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 76 111 77 defaultKind = None 112 defaultkey = None 113 keyname = None 114 itemfactory = None 78 115 79 116 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ … … 81 118 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 82 119 83 def __init__(self, dataitem=None): 120 def __init__(self, keyname=None, defaultkey=None, itemfactory=None, lookup=None): 121 if keyname is not None: 122 self.keyname = keyname 123 124 if defaultkey is not None: 125 self.defaultkey = defaultkey 126 127 if itemfactory is not None: 128 self.itemfactory = itemfactory 129 130 if lookup is None: 131 self.lookup = dict() 132 else: 133 self.lookup = lookup 134 135 def __contains__(self, relation): 136 return relation in self.lookup 137 138 def __len__(self): 139 return len(self.lookup) 140 141 def __iter__(self): 142 return self.lookup.itervalues() 143 144 def getkey(self, relation): 145 if self.keyname is None: 146 raise ValueError, 'Cannot infer key for relation "%s"' % (relation,) 147 148 try: 149 return relation.Metadata(self.keyname) 150 except KeyError: 151 if self.defaultkey is None: 152 raise KeyError, 'Relation "%s" metadata has no key "%s"' % (relation, self.keyname) 153 else: 154 return self.defaultkey 155 156 def append(self, relation): 157 key = self.getkey(relation) 158 self.OnModifying(self, (key, value)) 159 self.lookup[key] = relation 160 self.OnModified(self, (key, value)) 161 162 def extend(self, relations): 163 items = [(self.getkey(relation), relation) for relation in self.relations] 164 self.OnModifying(self, items) 165 self.lookup.update(items) 166 self.OnModified(self, items) 167 168 #~ dict adapter ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 169 170 def __getitem__(self, key): 171 try: 172 return self.lookup[key] 173 except LookupError: 174 if self.itemfactory is not None: 175 result = self.lookup[key] = self.itemfactory() 176 return result 177 else: 178 raise 179 180 def __setitem__(self, key, value): 181 self.OnModifying(self, [(key, value)]) 182 self.lookup[key] = value 183 self.OnModified(self, [(key, value)]) 184 185 def __delitem__(self, key): 186 self.OnModifying(self, [(key, None)]) 187 del self.lookup[key] 188 self.OnModified(self, [(key, None)]) 189 190 def keys(self): 191 return self.lookup.keys() 192 193 def values(self): 194 return self.lookup.values() 195 196 def items(self): 197 return self.lookup.items() 198 199 def iterkeys(self): 200 return self.lookup.iterkeys() 201 202 def iteritems(self): 203 return self.lookup.iteritems() 204 205 def itervalues(self): 206 return self.lookup.itervalues() 207 208 209 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 210 211 class AbstractRelationships(object): 212 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 213 #~ Public Methods 214 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 215 216 def __init__(self, dataitem=None, metarelationship=None): 84 217 if dataitem is not None: 85 218 self.SetDataItem(dataitem) 219 220 if metarelationship is not None: 221 self.SetMetaRelationship(metarelationship) 86 222 87 223 def GetDataItem(self): … … 93 229 self.dataitem = dataitem 94 230 95 def Metadata(self): 231 def DelDataItem(self): 232 """Ability to remove the dataitem""" 233 del self.dataitem 234 235 DataItem = property(GetDataItem, SetDataItem, DelDataItem) 236 237 def GetMetaRelationship(self): 238 """Returns the relationship "above" the current level... a relationship of relationships""" 239 return self.metarelationship 240 241 def SetMetaRelationship(self, metarelationship): 242 """Sets the relationship "above" the current level... a relationship of relationships""" 243 self.metarelationship = metarelationship 244 245 def DelMetaRelationship(self): 246 """Removes the relationship "above" the current level... a relationship of relationships""" 247 del self.metarelationship 248 249 MetaRelationship = property(GetMetaRelationship, SetMetaRelationship, DelMetaRelationship) 250 251 def Metadata(self, *keys): 96 252 """Returns the metadata about this relationship""" 97 253 try: 98 re turnself.metadata254 result = self.metadata 99 255 except AttributeError: 100 self.metadata = {} 101 return self.metadata 102 103 #def MetaRelationship(self): 104 # """Returns the relationship "above" the current level... a relationship of relationships""" 105 # return self.metarelationship 106 107 #~ Relations related ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 108 109 def AddRelation(self, other, kind=None): 256 if keys: 257 # Don't force the creation of the dictionary 258 result = {} 259 else: 260 self.metadata = {} 261 result = self.metadata 262 if keys: 263 if len(keys) == 1: 264 result = result[keys[0]] 265 elif len(keys) > 1: 266 result = [result[key] for key in keys] 267 return result 268 269 #~ Default Relations helpers ~~~~~~~~~~~~~~~~~~~~~~~~ 270 271 def __iter__(self): 272 """Iterable of the default relation""" 273 return iter(self.DefaultRelations()) 274 275 def __contains__(self, relation): 276 """Tests for membership in the default relation""" 277 return relation in self.DefaultRelations() 278 279 def __len__(self): 280 """Length of the default relation""" 281 return len(self.DefaultRelations()) 282 283 def DefaultRelations(self): 284 """Note: if this is not supported, raise NotImplementedError""" 285 raise NotImplementedError 286 287 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 288 289 class Relationships(AbstractRelationships): 290 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 291 #~ Constants / Variables / Etc. 292 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 293 294 relations = LazyProperty(RelationsLookup) 295 defaultKind = None 296 297 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 298 #~ Public Methods 299 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 300 301 def AddRelation(self, other, kind=None, **kw): 110 302 if kind is None: kind = self.defaultKind 111 self. Relations(kind).append(other)303 self.relations[kind].append(other, **kw) 112 304 113 305 def AddRelationKind(self, kind, relationcollection): 114 self. _getRelations()[kind] = relationcollection306 self.relations[kind] = relationcollection 115 307 116 308 def Relations(self, kind=None): 117 309 if kind is None: kind = self.defaultKind 118 return self._getRelations()[kind] 119 120 def AllRelations(self): 121 return self._getRelations().iteritems() 310 return self.relations[kind] 122 311 123 312 def RelationKinds(self): 124 return self._getRelations().iterkeys() 125 126 def _getRelations(self): 127 try: 128 return self.relations 129 except AttributeError: 130 self.relations = self._RelationsFactory() 131 return self.relations 132 133 def _RelationsFactory(self): 134 return {} 135 136 #~ RelationCollection stand in for defaultKind ~~~~~~ 137 138 def __iter__(self): 139 """Iterable of the default relation""" 140 return iter(self.Relations(self.defaultKind)) 141 142 def __contains__(self, relation): 143 """Tests for membership in the default relation""" 144 return relation in self.Relations(self.defaultKind) 145 146 def __len__(self): 147 """Length of the default relation""" 148 return len(self.Relations(self.defaultKind)) 149 150 def append(self, relation): 151 """Appends to the default relation""" 152 return self.Relations(self.defaultKind).append(relation) 153 154 def extend(self, relations): 155 """Extends the default relation""" 156 return self.Relations(self.defaultKind).extend(relations) 157 313 return self.relations.iterkeys() 314 315 def DefaultRelations(self): 316 """Note: if this is not supported, raise NotImplementedError""" 317 return self.Relations(self.defaultKind) 318 trunk/RBFoundation/RBFoundation/SubObs/Event.py
r537 r548 24 24 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 25 25 26 import Interface 26 27 from AccessRules import IgnoreAccess 27 28 from Interface.EventSubject import EventSubjectTemplate … … 44 45 EventSubjectList = EventSubjectWeakList 45 46 EventSubject = EventSubjectWeakList # Set the default 47 48 class EventSubjectProperty(Interface.AbstractProperty): 49 EventFactory = EventSubject 46 50 47 51 #~ Sets if they exist ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ trunk/RBFoundation/RBFoundation/SubObs/Interface/__init__.py
r458 r548 49 49 def _Notify(self, *args, **kw): 50 50 return self._NotifyExplicit(args, kw) 51 52 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 53 54 try: 55 from RBFoundation.Objects import Properties 56 CachedPropertyBase = Properties.CachedPropertyBase 57 except ImportError, AttributeError: 58 pass 59 else: 60 class AbstractProperty(CachedPropertyBase): 61 _factory_curry = (), {} 62 def __init__(self, *args, **kw): 63 if args or kw: 64 self._factory_curry = args, kw 65 def GetValue(self, obj): 66 args, kw = self._factory_curry 67 return self.EventFactory(*args, **kw) 68 69 def _CacheName(self, *args): 70 return '__event_' + self._GetName(*args) 71 trunk/RBFoundation/RBFoundation/SubObs/Publish.py
r541 r548 24 24 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 25 25 26 import Interface 26 27 from AccessRules import IgnoreAccess 27 28 from Interface.Publisher import PublisherTemplate … … 49 50 Publisher = PublisherWeakList # Set default 50 51 52 class PublisherProperty(Interface.AbstractProperty): 53 EventFactory = Publisher 54 51 55 # Data publishers 52 56 from LogicRules import ListCollection … … 56 60 DataPublisher = DataPublisherWeakList # Set default 57 61 62 class DataPublisherProperty(Interface.AbstractProperty): 63 EventFactory = DataPublisher 64 trunk/RBFoundation/plans/todo.txt
r511 r548 27 27 Queues that can be checked in a loop 28 28 Wrappers for cross-thread calling 29 Based upon WeakRef/StrongRef -- PostponedRef? 29 30 30 31 trunk/RBFoundation/test/Objects/test_Relations.py
r547 r548 76 76 self.items = [Relations.Relationships(di) for di in range(3)] 77 77 78 self.categoryA.AddRelation(self.items[0])79 self.categoryB.AddRelation(self.items[1])80 self.categoryA.AddRelation(self.items[2])81 self.categoryB.AddRelation(self.items[2])82 83 78 def tearDown(self): 84 79 del self.categoryA … … 87 82 88 83 def testMembership(self): 84 self.failIf(self.items[0] in self.categoryA) 85 self.failIf(self.items[0] in self.categoryB) 86 self.categoryA.AddRelation(self.items[0]) 89 87 self.failUnless(self.items[0] in self.categoryA) 88 self.failIf(self.items[0] in self.categoryB) 89 90 self.failIf(self.items[1] in self.categoryA) 91 self.failIf(self.items[1] in self.categoryB) 92 self.categoryB.AddRelation(self.items[1]) 93 self.failIf(self.items[1] in self.categoryA) 90 94 self.failUnless(self.items[1] in self.categoryB) 95 96 self.failIf(self.items[2] in self.categoryA) 97 self.categoryA.AddRelation(self.items[2]) 98 self.failUnless(self.items[2] in self.categoryA) 99 self.failIf(self.items[2] in self.categoryB) 100 self.categoryB.AddRelation(self.items[2]) 91 101 self.failUnless(self.items[2] in self.categoryA) 92 102 self.failUnless(self.items[2] in self.categoryB) 103 104 def testEventOops(self): 105 self.failUnlessRaises(AttributeError, getattr, self.categoryA, 'OnModifying') 106 self.failUnlessRaises(AttributeError, getattr, self.categoryA, 'OnModified') 107 108 def testEvents(self): 109 cA = self.categoryA.DefaultRelations() 110 cB = self.categoryB.DefaultRelations() 111 track = {cA:"modify", cB:"modify"} 112 113 def OnModifying(coll, items): 114 track[coll] = track[coll] + " ing" 115 def OnModified(coll, items): 116 track[coll] = track[coll] + " ed" 117 118 cA.OnModifying.Add(OnModifying) 119 cA.OnModified.Add(OnModified) 120 cB.OnModifying.Add(OnModifying) 121 cB.OnModified.Add(OnModified) 122 123 self.failUnlessEqual(track[cA], "modify") 124 self.failUnlessEqual(track[cB], "modify") 125 126 self.categoryA.AddRelation(self.items[0]) 127 self.failUnlessEqual(track[cA], "modify ing ed") 128 self.failUnlessEqual(track[cB], "modify") 129 130 self.categoryB.AddRelation(self.items[1]) 131 self.failUnlessEqual(track[cA], "modify ing ed") 132 self.failUnlessEqual(track[cB], "modify ing ed") 133 134 self.categoryA.AddRelation(self.items[2]) 135 self.failUnlessEqual(track[cA], "modify ing ed ing ed") 136 self.failUnlessEqual(track[cB], "modify ing ed") 137 138 self.categoryB.AddRelation(self.items[2]) 139 self.failUnlessEqual(track[cA], "modify ing ed ing ed") 140 self.failUnlessEqual(track[cB], "modify ing ed ing ed") 93 141 94 142 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ trunk/RBFoundation/test/test_URIparser.py
r403 r548 26 26 # Path adjustmet so the test can run out of the box 27 27 import sys; sys.path.append('..') 28 from test import test_support29 28 import unittest 30 29
