[pypy-svn] r15698 - in pypy/dist/pypy: interpreter objspace/std/test

arigo at codespeak.net arigo at codespeak.net
Fri Aug 5 17:23:34 CEST 2005


Author: arigo
Date: Fri Aug  5 17:23:30 2005
New Revision: 15698

Modified:
   pypy/dist/pypy/interpreter/error.py
   pypy/dist/pypy/interpreter/typedef.py
   pypy/dist/pypy/objspace/std/test/test_userobject.py
Log:
More support for __del__() methods.  This one catches and prints an error
message.  This was more delicate than expected because of GC cycles that kept
the 'self' object alive just a bit longer than the __del__() execution.  This
systematically triggers another call to __del__() when the GC breaks the
cycle...

Added a test.


Modified: pypy/dist/pypy/interpreter/error.py
==============================================================================
--- pypy/dist/pypy/interpreter/error.py	(original)
+++ pypy/dist/pypy/interpreter/error.py	Fri Aug  5 17:23:30 2005
@@ -37,19 +37,20 @@
         return '[%s: %s]' % (self.w_type, self.w_value)
 
     def errorstr(self, space):
-        "NOT_RPYTHON: The exception class and value, as a string."
+        "The exception class and value, as a string."
         if space is None:
+            # this part NOT_RPYTHON
             exc_typename = str(self.w_type)
-            exc_value    = self.w_value
+            exc_value    = str(self.w_value)
         else:
             w = space.wrap
-            if space.is_true(space.is_(space.type(self.w_type), space.w_str)):
+            if space.is_w(space.type(self.w_type), space.w_str):
                 exc_typename = space.str_w(self.w_type)
             else:
                 exc_typename = space.str_w(
                     space.getattr(self.w_type, w('__name__')))
-            if self.w_value == space.w_None:
-                exc_value = None
+            if space.is_w(self.w_value, space.w_None):
+                exc_value = ""
             else:
                 try:
                     exc_value = space.str_w(space.str(self.w_value))
@@ -193,6 +194,21 @@
         self.w_type  = w_type
         self.w_value = w_value
 
+    def write_unraisable(self, space, where, w_object=None):
+        if w_object is None:
+            objrepr = ''
+        else:
+            try:
+                objrepr = space.str_w(space.repr(w_object))
+            except OperationError:
+                objrepr = '?'
+        msg = 'Exception "%s" in %s%s ignored\n' % (self.errorstr(space),
+                                                    where, objrepr)
+        try:
+            space.call_method(space.sys.get('stderr'), 'write', space.wrap(msg))
+        except OperationError:
+            pass   # ignored
+
 
 # Utilities
 from pypy.tool.ansi_print import ansi_print

Modified: pypy/dist/pypy/interpreter/typedef.py
==============================================================================
--- pypy/dist/pypy/interpreter/typedef.py	(original)
+++ pypy/dist/pypy/interpreter/typedef.py	Fri Aug  5 17:23:30 2005
@@ -86,7 +86,11 @@
             self.w__class__ = w_subtype
 
         def __del__(self):
-            self.space.userdel(self)
+            try:
+                self.space.userdel(self)
+            except OperationError, e:
+                e.write_unraisable(self.space, 'method __del__ of ', self)
+                e.clear(self.space)   # break up reference cycles
 
         if wants_slots:
             def user_setup_slots(self, nslots):

Modified: pypy/dist/pypy/objspace/std/test/test_userobject.py
==============================================================================
--- pypy/dist/pypy/objspace/std/test/test_userobject.py	(original)
+++ pypy/dist/pypy/objspace/std/test/test_userobject.py	Fri Aug  5 17:23:30 2005
@@ -141,3 +141,37 @@
         a.__dict__ = {'y': 6}
         assert a.y == 6
         assert not hasattr(a, 'x')
+
+    def test_del(self):
+        lst = []
+        class A(object):
+            def __del__(self):
+                lst.append(42)
+        A()
+        assert lst == [42]
+
+    def test_del_exception(self):
+        import sys, StringIO
+        class A(object):
+            def __del__(self):
+                yaddadlaouti
+        prev = sys.stderr
+        try:
+            sys.stderr = StringIO.StringIO()
+            A()
+            res = sys.stderr.getvalue()
+            A()
+            res2 = sys.stderr.getvalue()
+        finally:
+            sys.stderr = prev
+        assert res.startswith('Exception')
+        assert 'NameError' in res
+        assert 'yaddadlaouti' in res
+        assert 'ignored' in res
+        assert res.count('\n') == 1    # a single line
+        assert res2.count('\n') == 2   # two lines
+        line2 = res2.split('\n')[1]
+        assert line2.startswith('Exception')
+        assert 'NameError' in line2
+        assert 'yaddadlaouti' in line2
+        assert 'ignored' in line2



More information about the Pypy-commit mailing list