[pypy-svn] r49755 - in pypy/branch/interplevel-oldstyle-classes/pypy/module/__builtin__: . test

cfbolz at codespeak.net cfbolz at codespeak.net
Fri Dec 14 01:06:58 CET 2007


Author: cfbolz
Date: Fri Dec 14 01:06:57 2007
New Revision: 49755

Modified:
   pypy/branch/interplevel-oldstyle-classes/pypy/module/__builtin__/interp_classobj.py
   pypy/branch/interplevel-oldstyle-classes/pypy/module/__builtin__/test/test_classobj.py
Log:
support for __del__. not quite elegant, but works.


Modified: pypy/branch/interplevel-oldstyle-classes/pypy/module/__builtin__/interp_classobj.py
==============================================================================
--- pypy/branch/interplevel-oldstyle-classes/pypy/module/__builtin__/interp_classobj.py	(original)
+++ pypy/branch/interplevel-oldstyle-classes/pypy/module/__builtin__/interp_classobj.py	Fri Dec 14 01:06:57 2007
@@ -44,7 +44,7 @@
         self.name = space.str_w(w_name)
         self.bases_w = bases
         self.w_dict = w_dict
-
+ 
     def getdict(self):
         return self.w_dict
 
@@ -144,7 +144,10 @@
         return space.call_function(w_descr_get, w_value, space.w_None, self)
         
     def descr_call(self, space, __args__):
-        w_inst = W_InstanceObject(space, self)
+        if self.lookup(space, space.wrap('__del__')) is not None:
+            w_inst = W_InstanceObjectWithDel(space, self)
+        else:
+            w_inst = W_InstanceObject(space, self)
         w_init = w_inst.getattr(space, space.wrap('__init__'), False)
         if w_init is not None:
             w_result = space.call_args(w_init, __args__)
@@ -274,6 +277,7 @@
         assert isinstance(w_class, W_ClassObject)
         self.w_class = w_class
         self.w_dict = w_dict
+        self.space = space
 
     def getdict(self):
         return self.w_dict
@@ -669,3 +673,28 @@
     **rawdict
 )
 
+class W_InstanceObjectWithDel(W_InstanceObject):
+    # XXX this is code duplication from pypy.interpreter.typedef
+    # find a way to prevent this.
+    def __del__(self):
+        
+        lifeline = self.getweakref()
+        if lifeline is not None:
+            # Clear all weakrefs to this object before we call
+            # the app-level __del__.  We detach the lifeline
+            # first: if the app-level __del__ tries to use
+            # weakrefs again, they won't reuse the broken
+            # (already-cleared) ones from this lifeline.
+            self.setweakref(self.space, None)
+            lifeline.clear_all_weakrefs()
+        try:
+            self.descr_del()
+        except OperationError, e:
+            e.write_unraisable(self.space, 'method __del__ of ', self)
+            e.clear(self.space)   # break up reference cycles
+
+    def descr_del(self):
+        space = self.space
+        w_func = self.getattr(space, space.wrap('__del__'), False)
+        if w_func is not None:
+            space.call_function(w_func)

Modified: pypy/branch/interplevel-oldstyle-classes/pypy/module/__builtin__/test/test_classobj.py
==============================================================================
--- pypy/branch/interplevel-oldstyle-classes/pypy/module/__builtin__/test/test_classobj.py	(original)
+++ pypy/branch/interplevel-oldstyle-classes/pypy/module/__builtin__/test/test_classobj.py	Fri Dec 14 01:06:57 2007
@@ -577,3 +577,24 @@
         a = type(a).__new__(type(a), A, {'c': 2})
         assert a.b == 1
         assert a.c == 2
+
+    def test_del(self):
+        import gc
+        l = []
+        class A:
+            def __del__(self):
+                l.append(1)
+        a = A()
+        a = None
+        gc.collect()
+        gc.collect()
+        gc.collect()
+        assert l == [1]
+        class B(A):
+            pass
+        b = B()
+        b = None
+        gc.collect()
+        gc.collect()
+        gc.collect()
+        assert l == [1, 1]



More information about the Pypy-commit mailing list