Changeset 527

Show
Ignore:
Timestamp:
04/24/03 23:09:38 (5 years ago)
Author:
sholloway
Message:

Depreciating WeakBind? and removing

Files:

Legend:

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

    r432 r527  
    2020##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    2121 
    22 """weakref for callable objects. 
    23  
    24 See WeakBoundCallable and BindCallable for more details 
    25 """ 
    26  
    2722#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    2823#~ Imports  
    2924#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    3025 
    31 import weakref 
    32 import type
     26from BindCallable import * 
     27import warning
    3328 
    3429#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    35 #~ Definitions  
     30#~ Warnings 
    3631#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    3732 
    38 typesBindMethods = (types.MethodType, types.BuiltinMethodType ) 
    39 typesInstances = (types.ObjectType, types.InstanceType) 
    40 typesRequireBinding = typesBindMethods + typesInstances 
     33warnings.warn("WeakBind module has been renamed to BindCallable", DeprecationWarning, stacklevel=2) 
    4134 
    42 typesNonBindMethods = (types.FunctionType, types.LambdaType, types.GeneratorType, types.BuiltinFunctionType) 
    43 typesNonBind = typesNonBindMethods + (types.ClassType, types.ModuleType) 
    44  
    45 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    46 #~ Callable Aspects 
    47 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    48  
    49 #~ Test Utilities ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    50  
    51 def _PrintOnRelease(wr): 
    52     print "Released weakref" 
    53  
    54 class _TestObject(object): 
    55     def TestMethod(self, *args, **kw): 
    56         return args, kw 
    57  
    58 #~ Class Bases ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    59  
    60 class BoundCallableBase(object): 
    61     """Ultimate baseclass of BoundCallable objects.  Derive from this object if the class  
    62     handles references to itself, by itself.""" 
    63     pass 
    64  
    65 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    66  
    67 class WeakBoundCallable(BoundCallableBase): 
    68     """weakref for callable objects. 
    69      
    70     Weakref objects have become a matter of necessity for managing the scope of interconnected 
    71     networks of objects, defining owner and owned, while still allow for reference loops. 
    72     However, weakref-ing a bound method always returns a dead weakref, but true references keep 
    73     the "owner" class around.  WeakBoundCallable's intention is to provide weakref-type support  
    74     for bound methods, as well as all other callable objects. 
    75      
    76     As a related sidenote, the ContextApply module builds upon this concepts to bind method variables 
    77     to bound-callable objects. 
    78      
    79     >>> t = _TestObject() 
    80     >>> wbc = WeakBoundCallable(t.TestMethod, _PrintOnRelease) 
    81     >>> wbc(1,2,3,four=4) 
    82     ((1, 2, 3), {'four': 4}) 
    83     >>> del t 
    84     Released weakref 
    85  
    86     """ 
    87      
    88     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    89     #~ Constants / Variables / Etc.  
    90     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    91  
    92     im_self = None 
    93     im_func = None 
    94  
    95     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    96     #~ Special  
    97     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    98  
    99     def __init__(self, Callable, *weakrefArgs, **weakrefKw): 
    100         if Callable is None:  
    101             # A "None" method... it should expire immediately 
    102             pass 
    103         elif isinstance(Callable, BoundCallableBase): 
    104             # One of those weird instances where we are proxying for an object very similar to ourself...  
    105             # keep a hard reference to the BoundCallableBase 
    106             self.im_func = Callable 
    107         elif isinstance(Callable, typesBindMethods): 
    108             # Wrap up the method and potential instance 
    109             self.im_func = getattr(Callable, 'im_func', Callable) 
    110             if getattr(Callable, 'im_self', None) is not None:  
    111                 self.im_self = weakref.ref(Callable.im_self, *weakrefArgs, **weakrefKw) 
    112             else: 
    113                 pass 
    114         elif isinstance(Callable, typesInstances): 
    115             # This is a "callable object", make a weakref to it 
    116             self.im_self = weakref.ref(Callable, *weakrefArgs, **weakrefKw) 
    117             self.im_func = None 
    118         elif callable(Callable): 
    119             # What the heck is it?  well... its supposed to be callable... 
    120             self.im_func = Callable 
    121  
    122     def __nonzero__(self): 
    123         if self.im_self is not None: 
    124             return self.im_self() is not None and 1 or 0 
    125         else:  
    126             return self.im_func and 1 or 0 
    127  
    128     def __hash__(self): 
    129         if self.im_self is not None: 
    130             return hash(self.im_self) 
    131         else:  
    132             return hash(self.im_func) 
    133  
    134     def __eq__(self, other): 
    135         if isinstance(other, WeakBoundCallable): 
    136             return (self.im_self == other.im_self) and (self.im_func == other.im_func)  
    137         elif isinstance(other, weakref.ReferenceType):  
    138             return self.im_func == other or self.im_self == other 
    139         elif callable(other):  
    140             return self == WeakBoundCallable(other) 
    141         else: return self is other 
    142  
    143     def __ne__(self, other): 
    144         return not self.__eq__(other) 
    145  
    146     def _DoCall(self, *args, **kw): 
    147         if self.im_self: 
    148             im_self = self.im_self() 
    149             if im_self is not None:  
    150                 if self.im_func: 
    151                     return self.im_func(im_self, *args, **kw) 
    152                 else: return im_self(*args, **kw) 
    153             else: raise weakref.ReferenceError, "weakly-referenced object no longer exists" 
    154         else: return self.im_func(*args, **kw) 
    155  
    156     #def __call__(self, *args, **kw): 
    157     #    return self._DoCall(args, kw) 
    158     __call__ = _DoCall 
    159  
    160 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    161  
    162 BoundCallable = WeakBoundCallable 
    163  
    164 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    165  
    166 class StrongBoundCallable(BoundCallableBase): 
    167     """Provides the same interface as WeakBoundCallable, but maintains strong references 
    168     to both class instances and callable objects.  Used mainly in ContextApply to build  
    169     upon a common class interface. 
    170      
    171     >>> t = _TestObject() 
    172     >>> sbc = StrongBoundCallable(t.TestMethod) 
    173     >>> sbc(1,2,3,four=4) 
    174     ((1, 2, 3), {'four': 4}) 
    175     """ 
    176  
    177     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    178     #~ Constants / Variables / Etc.  
    179     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    180  
    181     Callable = None 
    182  
    183     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    184     #~ Special  
    185     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    186  
    187     def __init__(self, Callable): 
    188         if Callable is None:  
    189             pass # A "None" method... it should expire immediately 
    190         elif callable(Callable): 
    191             self.Callable = Callable 
    192  
    193     def __nonzero__(self): 
    194         return self.Callable is not None and 1 or 0 
    195  
    196     def __hash__(self): 
    197         return hash(self.Callable) 
    198  
    199     def __eq__(self, other): 
    200         if isinstance(other, StrongBoundCallable): 
    201             return self.Callable == other.Callable 
    202         elif callable(other):  
    203             return self == StrongBoundCallable(other) 
    204         else: return self is other 
    205  
    206     def __ne__(self, other): 
    207         return not self.__eq__(other) 
    208  
    209     def _DoCall(self, *args, **kw): 
    210         return self.Callable(*args, **kw) 
    211  
    212     #def __call__(self, *args, **kw): 
    213     #    return self._DoCall(args, kw) 
    214     __call__ = _DoCall 
    215  
    216 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    217  
    218 def BindCallable(Callable, BindClass=BoundCallable, *args, **kw): 
    219     """Binds a callable object using BindClass only if needed. 
    220      
    221     >>> BindCallable(_PrintOnRelease) is _PrintOnRelease 
    222     1 
    223     >>> BindCallable(_TestObject.TestMethod) is not _TestObject.TestMethod 
    224     1 
    225     """  
    226     if isinstance(Callable, BoundCallableBase): 
    227         # It's already bound in some form or another,  
    228         # but we have to guard it from being wrapped 
    229         # again, because it is itself an instance. 
    230         return Callable 
    231     elif isinstance(Callable, typesNonBind): 
    232         # Doesn't need to be bound 
    233         return Callable 
    234     elif isinstance(Callable, typesRequireBinding): 
    235         # Well if it requires binding, then we should do so! 
    236         return BindClass(Callable, *args, **kw) 
    237     else: 
    238         # not quite sure what it is, but it does not require binding 
    239         return Callable 
    240  
    241 def WeakBindCallable(Callable, *args, **kw): 
    242     """Weakly binds a callable object only if needed. 
    243  
    244     >>> WeakBindCallable(_TestObject.TestMethod) is not _TestObject.TestMethod 
    245     1 
    246     >>> WeakBindCallable(_TestObject().TestMethod) and 1 or 0 
    247     0 
    248     >>> t = _TestObject() 
    249     >>> wbc = WeakBindCallable(t.TestMethod) 
    250     >>> wbc is not t.TestMethod 
    251     1 
    252     >>> t.TestMethod() == wbc() 
    253     1 
    254     >>> del t 
    255     >>> wbc and 1 or 0 
    256     0 
    257     """ 
    258     return BindCallable(Callable, WeakBoundCallable, *args, **kw) 
    259  
    260 def StrongBindCallable(Callable, *args, **kw): 
    261     """Strongly binds a callable object only if needed. 
    262  
    263     >>> StrongBindCallable(_TestObject.TestMethod) is not _TestObject.TestMethod 
    264     1 
    265     >>> StrongBindCallable(_TestObject().TestMethod) and 1 or 0 
    266     1 
    267     >>> t = _TestObject() 
    268     >>> sbc = StrongBindCallable(t.TestMethod) 
    269     >>> sbc is not t.TestMethod 
    270     1 
    271     >>> t.TestMethod() == sbc() 
    272     1 
    273     >>> del t 
    274     >>> sbc and 1 or 0 
    275     1 
    276     """ 
    277     return BindCallable(Callable, StrongBoundCallable, *args, **kw) 
    278  
    279 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    280 #~ Testing  
    281 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    282  
    283 if __name__ == '__main__': 
    284     print "Testing..." 
    285     import doctest, WeakBind 
    286     doctest.testmod(WeakBind) 
    287  
    288     import sys 
    289  
    290     class _Test: 
    291         def you(self): 
    292             return self 
    293         def me(self): 
    294             return self 
    295      
    296     def onrelease(wr): 
    297         print "Released wr:", wr 
    298  
    299     a = _Test() 
    300     assert(sys.getrefcount(a) == 2) 
    301  
    302     b1 = WeakBindCallable(a.me, onrelease) 
    303     assert(b1) 
    304     assert(sys.getrefcount(a) == 2) 
    305  
    306     b2 = WeakBindCallable(a.me, onrelease) 
    307     assert(b2) 
    308     assert(sys.getrefcount(a) == 2) 
    309  
    310     assert(b1 == b2) 
    311     assert(sys.getrefcount(a) == 2) 
    312  
    313     assert(a.me == b1) 
    314     assert(a.me == b2) 
    315     assert(b1 == b2) 
    316     assert(b2 == b1) 
    317  
    318     b3 = WeakBindCallable(a.you, onrelease) 
    319     assert(not b1 == b3) 
    320     assert(b1 != b3) 
    321  
    322     del a 
    323  
    324     try: 
    325         b1() 
    326         assert(0, "Shouldn't ever get here") 
    327     except weakref.ReferenceError: 
    328         pass 
    329  
    330     try: 
    331         if b2: 
    332             b2() 
    333             assert(0, "Shouldn't ever get here") 
    334     except weakref.ReferenceError: 
    335         assert(0, "Shouldn't ever get here") 
    336  
    337     print "Test complete."