Changeset 548

Show
Ignore:
Timestamp:
06/03/03 08:14:22 (5 years ago)
Author:
sholloway
Message:

*** empty log message ***

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/RBFoundation/RBFoundation/Objects/Relations.py

    r547 r548  
    2424#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    2525 
     26from __future__ import generators 
     27from RBFoundation.Objects.Properties import LazyProperty 
     28from RBFoundation.SubObs.Event import EventSubjectProperty 
     29 
    2630#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    2731#~ Definitions  
     
    2933 
    3034class RelationsCollection(object): 
     35    OnModifying = EventSubjectProperty() # (collection, [items]) 
     36    OnModified = EventSubjectProperty() # (collection, [items]) 
     37 
    3138    def __len__(self):  
    3239        return len(list(iter(self))) 
     
    4754#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    4855 
     56class 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 
    4975class 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 
    5483 
    5584    def __contains__(self, relation): 
     
    6392 
    6493    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]) 
    6697 
    6798    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 
     105class RelationsLookup(RelationsCollection): 
     106    """A simple, modifyable implementation of RelationsCollection as a dictionary""" 
     107 
    73108    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    74109    #~ Constants / Variables / Etc.  
    75110    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    76111 
    77     defaultKind = None 
     112    defaultkey = None 
     113    keyname = None 
     114    itemfactory = None 
    78115 
    79116    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
     
    81118    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    82119 
    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 
     211class AbstractRelationships(object): 
     212    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
     213    #~ Public Methods  
     214    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
     215 
     216    def __init__(self, dataitem=None, metarelationship=None): 
    84217        if dataitem is not None: 
    85218            self.SetDataItem(dataitem) 
     219 
     220        if metarelationship is not None: 
     221            self.SetMetaRelationship(metarelationship) 
    86222 
    87223    def GetDataItem(self): 
     
    93229        self.dataitem = dataitem 
    94230 
    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): 
    96252        """Returns the metadata about this relationship""" 
    97253        try: 
    98             return self.metadata 
     254            result = self.metadata 
    99255        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 
     289class 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): 
    110302        if kind is None: kind = self.defaultKind 
    111         self.Relations(kind).append(other
     303        self.relations[kind].append(other, **kw
    112304 
    113305    def AddRelationKind(self, kind, relationcollection): 
    114         self._getRelations()[kind] = relationcollection 
     306        self.relations[kind] = relationcollection 
    115307 
    116308    def Relations(self, kind=None): 
    117309        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] 
    122311 
    123312    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  
    2424#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    2525 
     26import Interface 
    2627from AccessRules import IgnoreAccess 
    2728from Interface.EventSubject import EventSubjectTemplate 
     
    4445EventSubjectList = EventSubjectWeakList 
    4546EventSubject = EventSubjectWeakList # Set the default 
     47 
     48class EventSubjectProperty(Interface.AbstractProperty): 
     49    EventFactory = EventSubject 
    4650 
    4751#~ Sets if they exist ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
  • trunk/RBFoundation/RBFoundation/SubObs/Interface/__init__.py

    r458 r548  
    4949    def _Notify(self, *args, **kw): 
    5050        return self._NotifyExplicit(args, kw) 
     51 
     52#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
     53 
     54try: 
     55    from RBFoundation.Objects import Properties 
     56    CachedPropertyBase = Properties.CachedPropertyBase 
     57except ImportError, AttributeError: 
     58    pass 
     59else: 
     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  
    2424#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    2525 
     26import Interface 
    2627from AccessRules import IgnoreAccess 
    2728from Interface.Publisher import PublisherTemplate 
     
    4950Publisher = PublisherWeakList # Set default 
    5051 
     52class PublisherProperty(Interface.AbstractProperty): 
     53    EventFactory = Publisher 
     54 
    5155# Data publishers 
    5256from LogicRules import ListCollection 
     
    5660DataPublisher = DataPublisherWeakList # Set default 
    5761 
     62class DataPublisherProperty(Interface.AbstractProperty): 
     63    EventFactory = DataPublisher 
     64 
  • trunk/RBFoundation/plans/todo.txt

    r511 r548  
    2727        Queues that can be checked in a loop 
    2828        Wrappers for cross-thread calling 
     29        Based upon WeakRef/StrongRef -- PostponedRef? 
    2930 
    3031 
  • trunk/RBFoundation/test/Objects/test_Relations.py

    r547 r548  
    7676        self.items = [Relations.Relationships(di) for di in range(3)] 
    7777 
    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  
    8378    def tearDown(self): 
    8479        del self.categoryA 
     
    8782 
    8883    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]) 
    8987        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) 
    9094        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]) 
    91101        self.failUnless(self.items[2] in self.categoryA) 
    92102        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") 
    93141 
    94142#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
  • trunk/RBFoundation/test/test_URIparser.py

    r403 r548  
    2626# Path adjustmet so the test can run out of the box 
    2727import sys; sys.path.append('..') 
    28 from test import test_support 
    2928import unittest 
    3029