[pypy-svn] r26426 - in pypy/dist/pypy/module/_weakref: . test

cfbolz at codespeak.net cfbolz at codespeak.net
Thu Apr 27 11:35:45 CEST 2006


Author: cfbolz
Date: Thu Apr 27 11:35:44 2006
New Revision: 26426

Modified:
   pypy/dist/pypy/module/_weakref/__init__.py
   pypy/dist/pypy/module/_weakref/interp__weakref.py
   pypy/dist/pypy/module/_weakref/test/test_weakref.py
Log:
fix some problems in weakref, add getweakrefs and getweakrefcount


Modified: pypy/dist/pypy/module/_weakref/__init__.py
==============================================================================
--- pypy/dist/pypy/module/_weakref/__init__.py	(original)
+++ pypy/dist/pypy/module/_weakref/__init__.py	Thu Apr 27 11:35:44 2006
@@ -4,5 +4,8 @@
     appleveldefs = {
     }
     interpleveldefs = {
-        'ref': 'interp__weakref.W_Weakref'
+        'ref': 'interp__weakref.W_Weakref',
+        'getweakrefcount': 'interp__weakref.getweakrefcount',
+        'getweakrefs': 'interp__weakref.getweakrefs',
+        'ReferenceType': 'interp__weakref.W_Weakref',
     }

Modified: pypy/dist/pypy/module/_weakref/interp__weakref.py
==============================================================================
--- pypy/dist/pypy/module/_weakref/interp__weakref.py	(original)
+++ pypy/dist/pypy/module/_weakref/interp__weakref.py	Thu Apr 27 11:35:44 2006
@@ -4,46 +4,92 @@
 from pypy.interpreter.typedef import GetSetProperty, TypeDef
 from pypy.interpreter.gateway import interp2app
 from pypy.rpython.objectmodel import cast_address_to_object, cast_object_to_address
-class W_Weakref(Wrappable):
-    pass
+from pypy.rpython.lltypesystem.llmemory import NULL
 
 W_Weakrefable = W_Root
 W_Weakrefable.__lifeline__ = None
 
 class W_Weakref(Wrappable):
-    def __init__(w_self, space, w_obj, w_callable):
+    def __init__(w_self, space, lifeline, index, w_obj, w_callable):
         w_self.space = space
         w_self.address = cast_object_to_address(w_obj)
         w_self.w_callable = w_callable
+        w_self.addr_lifeline = cast_object_to_address(lifeline)
+        w_self.index = index
     
     def descr__call__(self):
         return cast_address_to_object(self.address, W_Weakrefable)
 
     def invalidate(w_self):
-        from pypy.rpython.lltypesystem.llmemory import NULL
-        import os
         w_self.address = NULL
+
+    def activate_callback(w_self):
+        import os
         if not w_self.space.is_w(w_self.w_callable, w_self.space.w_None):
             try:
                 w_self.space.call_function(w_self.w_callable, w_self)
             except OperationError, e:
                 os.write(2, "XXX\n")
 
+    def __del__(w_self):
+        if w_self.address != NULL:
+            lifeline = cast_address_to_object(w_self.addr_lifeline,
+                                              WeakrefLifeline)
+            lifeline.ref_is_dead(w_self.index)
+
 class WeakrefLifeline(object):
     def __init__(self):
-        self.refs_w = []
+        self.addr_refs = []
         
     def __del__(self):
-        for i in range(len(self.refs_w) - 1, -1, -1):
-            w_ref = self.refs_w[i]
-            w_ref.invalidate()
+        for i in range(len(self.addr_refs) - 1, -1, -1):
+            addr_ref = self.addr_refs[i]
+            if addr_ref != NULL:
+                w_ref = cast_address_to_object(addr_ref, W_Weakref)
+                w_ref.invalidate()
+        for i in range(len(self.addr_refs) - 1, -1, -1):
+            addr_ref = self.addr_refs[i]
+            if addr_ref != NULL:
+                w_ref = cast_address_to_object(addr_ref, W_Weakref)
+                w_ref.activate_callback()
     
     def get_weakref(self, space, w_subtype, w_obj, w_callable):
         w_ref = space.allocate_instance(W_Weakref, w_subtype)
-        W_Weakref.__init__(w_ref, space, w_obj, w_callable)
-        self.refs_w.append(w_ref)
+        W_Weakref.__init__(w_ref, space, self, len(self.addr_refs),
+                           w_obj, w_callable)
+        self.addr_refs.append(cast_object_to_address(w_ref))
         return w_ref
 
+    def ref_is_dead(self, index):
+        self.addr_refs[index] = NULL
+
+def getweakrefcount(space, w_obj):
+    if not isinstance(w_obj, W_Weakrefable):
+        return space.wrap(0)
+    if w_obj.__lifeline__ is None:
+        return space.wrap(0)
+    else:
+        lifeline = w_obj.__lifeline__
+        result = 0
+        for i in range(len(lifeline.addr_refs)):
+            if lifeline.addr_refs[i] != NULL:
+                result += 1
+        return space.wrap(result)
+
+def getweakrefs(space, w_obj):
+    if not isinstance(w_obj, W_Weakrefable):
+        return space.newlist()
+    if w_obj.__lifeline__ is None:
+        return space.newlist()
+    else:
+        lifeline = w_obj.__lifeline__
+        result = []
+        for i in range(len(lifeline.addr_refs)):
+            addr = lifeline.addr_refs[i]
+            if addr != NULL:
+                result.append(cast_address_to_object(addr, W_Weakref))
+        return space.newlist(result)
+
 def descr__new__(space, w_subtype, w_obj, w_callable=None):
     assert isinstance(w_obj, W_Weakrefable)
     if w_obj.__lifeline__ is None:

Modified: pypy/dist/pypy/module/_weakref/test/test_weakref.py
==============================================================================
--- pypy/dist/pypy/module/_weakref/test/test_weakref.py	(original)
+++ pypy/dist/pypy/module/_weakref/test/test_weakref.py	Thu Apr 27 11:35:44 2006
@@ -10,8 +10,10 @@
         class A:
             pass
         a = A()
+        assert _weakref.getweakrefcount(a) == 0
         ref = _weakref.ref(a)
         assert ref() is a
+        assert _weakref.getweakrefcount(a) == 1
         del a
         assert ref() is None
 
@@ -25,6 +27,7 @@
             a2.ref = ref()
         ref1 = _weakref.ref(a1, callback)
         ref2 = _weakref.ref(a1)
+        assert _weakref.getweakrefcount(a1) == 2
         del a1
         assert ref1() is None
         assert a2.ref is None
@@ -44,3 +47,33 @@
         del a1
         assert a2.x == 42
         
+    def test_dont_callback_if_weakref_dead(self):
+        import _weakref
+        class A:
+            pass
+        a1 = A()
+        a1.x = 40
+        a2 = A()
+        def callback(ref):
+            a1.x = 42
+        assert _weakref.getweakrefcount(a2) == 0
+        ref = _weakref.ref(a2, callback)
+        assert _weakref.getweakrefcount(a2) == 1
+        ref = None
+        assert _weakref.getweakrefcount(a2) == 0
+        a2 = None
+        assert a1.x == 40
+
+    def test_callback_cannot_ressurect(self):
+        import _weakref
+        class A:
+            pass
+        a = A()
+        alive = A()
+        alive.a = 1
+        def callback(ref2):
+            alive.a = ref1()
+        ref1 = _weakref.ref(a, callback)
+        ref2 = _weakref.ref(a, callback)
+        del a
+        assert alive.a is None



More information about the Pypy-commit mailing list