[pypy-svn] r57810 - in pypy/branch/2.5-features/pypy/interpreter: . test

arigo at codespeak.net arigo at codespeak.net
Thu Sep 4 16:18:11 CEST 2008


Author: arigo
Date: Thu Sep  4 16:18:08 2008
New Revision: 57810

Modified:
   pypy/branch/2.5-features/pypy/interpreter/error.py
   pypy/branch/2.5-features/pypy/interpreter/test/test_raise.py
Log:
Fix OperationError.normalize_exception() to handle old-style classes
and to do the right thing about space.full_exceptions.  Add comments
about all cases and about space.full_exceptions, and factor out a
helper because that starts to look much too long.  This fixes the
failure in objspace/flow/.


Modified: pypy/branch/2.5-features/pypy/interpreter/error.py
==============================================================================
--- pypy/branch/2.5-features/pypy/interpreter/error.py	(original)
+++ pypy/branch/2.5-features/pypy/interpreter/error.py	Thu Sep  4 16:18:08 2008
@@ -145,14 +145,39 @@
         """Normalize the OperationError.  In other words, fix w_type and/or
         w_value to make sure that the __class__ of w_value is exactly w_type.
         """
+        #
+        # This method covers all ways in which the Python statement
+        # "raise X, Y" can produce a valid exception type and instance.
+        #
+        # In the following table, 'Class' means a subclass of BaseException
+        # and 'inst' is an instance of either 'Class' or a subclass of it.
+        # Or 'Class' can also be an old-style class and 'inst' an old-style
+        # instance of it.
+        #
+        # Note that 'space.full_exceptions' is set to False by the flow
+        # object space; in this case we must assume that we are in a
+        # non-advanced case, and ignore the advanced cases.  Old-style
+        # classes and instances *are* advanced.
+        #
+        #  input (w_type, w_value)... becomes...                advanced case?
+        # ---------------------------------------------------------------------
+        #  (tuple, w_value)           (tuple[0], w_value)             yes
+        #  (Class, None)              (Class, Class())                no
+        #  (Class, inst)              (inst.__class__, inst)          no
+        #  (Class, tuple)             (Class, Class(*tuple))          yes
+        #  (Class, x)                 (Class, Class(x))               no
+        #  ("string", ...)            ("string", ...)              deprecated
+        #  (inst, None)               (inst.__class__, inst)          no
+        #
         w_type  = self.w_type
         w_value = self.w_value
         if space.full_exceptions:
             while space.is_true(space.isinstance(w_type, space.w_tuple)):
                 w_type = space.getitem(w_type, space.wrap(0))
-        if space.full_exceptions and (
-                space.is_true(space.abstract_isclass(w_type)) and 
-                space.is_true(space.issubtype(w_type, space.w_BaseException))):
+
+        if (space.is_true(space.abstract_isclass(w_type)) and
+            is_valid_exception_class(space, w_type)):
+            # this is for all cases of the form (Class, something)
             if space.is_w(w_value, space.w_None):
                 # raise Type: we assume we have to instantiate Type
                 w_value = space.call_function(w_type)
@@ -179,20 +204,22 @@
             space.warn("raising a string exception is deprecated", 
                        space.w_DeprecationWarning)
 
-        elif space.full_exceptions and space.is_true(space.isinstance(w_type, 
-                                                     space.w_BaseException)):
+        else:
+            # the only case left here is (inst, None), from a 'raise inst'.
+            w_inst = w_type
+            w_instclass = space.abstract_getclass(w_inst)
+            if not is_valid_exception_class(space, w_instclass):
+                instclassname = w_instclass.getname(space, '?')
+                msg = ("exceptions must be classes, or instances,"
+                       "or strings (deprecated) not %s" % (instclassname,))
+                raise OperationError(space.w_TypeError, space.wrap(msg))
+
             if not space.is_w(w_value, space.w_None):
                 raise OperationError(space.w_TypeError,
                                      space.wrap("instance exception may not "
                                                 "have a separate value"))
-            w_value = w_type
-            w_type = space.abstract_getclass(w_value)
-
-        else:
-            if space.full_exceptions:
-                msg = ("exceptions must be classes, or instances,"
-                    "or strings (deprecated) not %s" % (w_type.typedef.name))
-                raise OperationError(space.w_TypeError, space.wrap(msg))
+            w_value = w_inst
+            w_type = w_instclass
 
         self.w_type  = w_type
         self.w_value = w_value
@@ -213,6 +240,22 @@
             pass   # ignored
 
 
+def is_valid_exception_class(space, w_type):
+    """Assuming that 'w_type' is a new-style or old-style class, is it
+    correct to use it as the class of an exception?  The answer is no
+    if it is a new-style class that doesn't inherit from BaseException.
+    """
+    if not space.full_exceptions:
+        return True         # always, for the flow space
+    try:
+        return space.is_true(
+            space.issubtype(w_type, space.w_BaseException))
+    except OperationError, e:
+        if not e.match(space, space.w_TypeError):
+            raise
+        return True         # assuming w_type is an old-style class
+
+
 # Utilities
 from pypy.tool.ansi_print import ansi_print
 

Modified: pypy/branch/2.5-features/pypy/interpreter/test/test_raise.py
==============================================================================
--- pypy/branch/2.5-features/pypy/interpreter/test/test_raise.py	(original)
+++ pypy/branch/2.5-features/pypy/interpreter/test/test_raise.py	Thu Sep  4 16:18:08 2008
@@ -107,24 +107,19 @@
         raises(StopIteration, f)
 
     def test_userclass(self):
-        # PyPy classes are new-style so can't be raised
+        # new-style classes can't be raised unless they inherit from
+        # BaseException
 
-        class A:
+        class A(object):
             def __init__(self, x=None):
                 self.x = x
         
         def f():
-            try:
-                raise A
-            except A, a:
-                assert a.x == None
+            raise A
         raises(TypeError, f)
 
         def f():
-            try:
-                raise A(42)
-            except A, a:
-                assert a.x == 42
+            raise A(42)
         raises(TypeError, f)
 
     def test_it(self):
@@ -134,3 +129,49 @@
             {}[C]
         except KeyError:
             pass
+
+    def test_oldstyle_userclass(self):
+        class A:
+            __metaclass__ = _classobj
+            def __init__(self, val=None):
+                self.val = val
+        class Sub(A):
+            pass
+
+        try:
+            raise Sub
+        except IndexError:
+            assert 0
+        except A, a:
+            assert a.__class__ is Sub
+
+        sub = Sub()
+        try:
+            raise sub
+        except IndexError:
+            assert 0
+        except A, a:
+            assert a is sub
+
+        try:
+            raise A, sub
+        except IndexError:
+            assert 0
+        except A, a:
+            assert a is sub
+            assert sub.val is None
+
+        try:
+            raise Sub, 42
+        except IndexError:
+            assert 0
+        except A, a:
+            assert a.__class__ is Sub
+            assert a.val == 42
+
+        try:
+            {}[5]
+        except A, a:
+            assert 0
+        except KeyError:
+            pass



More information about the Pypy-commit mailing list