[pypy-svn] r5353 - in pypy/trunk/src/pypy: interpreter interpreter/test objspace/flow

arigo at codespeak.net arigo at codespeak.net
Sat Jun 26 14:49:22 CEST 2004


Author: arigo
Date: Sat Jun 26 14:47:07 2004
New Revision: 5353

Added:
   pypy/trunk/src/pypy/interpreter/test/test_raise.py
      - copied, changed from r5339, pypy/trunk/src/pypy/interpreter/test/test_interpreter.py
Modified:
   pypy/trunk/src/pypy/interpreter/pyframe.py
   pypy/trunk/src/pypy/interpreter/pyopcode.py
   pypy/trunk/src/pypy/interpreter/test/test_interpreter.py
   pypy/trunk/src/pypy/objspace/flow/specialcase.py
Log:
* Exceptions were still not right.
* Unified prepare_raise() and normalize_exception(), which looks better.
* Lots of tests.  Moved them to a new test_raise, even.


Modified: pypy/trunk/src/pypy/interpreter/pyframe.py
==============================================================================
--- pypy/trunk/src/pypy/interpreter/pyframe.py	(original)
+++ pypy/trunk/src/pypy/interpreter/pyframe.py	Sat Jun 26 14:47:07 2004
@@ -152,8 +152,10 @@
             if frame.space.full_exceptions:
                 w_normalized = normalize_exception(frame.space, w_type, w_value)
                 w_type, w_value = frame.space.unpacktuple(w_normalized, 2)
-                # this is to make sure that sys.exc_info() etc see
-                # normalized exception -- not sure here is best place!
+                # save the normalized exception back into the OperationError
+                # -- in particular it makes sure that sys.exc_info() etc see
+                #    normalized exception.
+                operationerr.w_type = w_type
                 operationerr.w_value = w_value
             # the stack setup is slightly different than in CPython:
             # instead of the traceback, we store the unroller object,
@@ -165,25 +167,43 @@
             return True  # stop unrolling
         return False
 
-def app_normalize_exception(etype, evalue):
-    # XXX should really be defined as a method on OperationError,
-    # but this is not so easy because OperationError cannot be
-    # at the same time an old-style subclass of Exception and a
-    # new-style subclass of Wrappable :-(
-    # moreover, try importing gateway from errors.py and you'll see :-(
-    
+def app_normalize_exception(etype, value):
+    """Normalize an (exc_type, exc_value) pair:
+    exc_value will be an exception instance and exc_type its class.
+    """
     # mistakes here usually show up as infinite recursion, which is fun.
-    if isinstance(evalue, etype):
-        return etype, evalue
-    if isinstance(etype, type) and issubclass(etype, Exception):
-        if evalue is None:
-            evalue = ()
-        elif not isinstance(evalue, tuple):
-            evalue = (evalue,)
-        evalue = etype(*evalue)
+    while isinstance(etype, tuple):
+        etype = etype[0]
+    if isinstance(etype, type):
+        if not isinstance(value, etype):
+            if value is None:
+                # raise Type: we assume we have to instantiate Type
+                value = etype()
+            elif isinstance(value, tuple):
+                # raise Type, Tuple: assume Tuple contains the constructor args
+                value = etype(*value)
+            else:
+                # raise Type, X: assume X is the constructor argument
+                value = etype(value)
+        # raise Type, Instance: let etype be the exact type of value
+        etype = value.__class__
+    elif type(etype) is str:
+        # XXX warn -- deprecated
+        if value is not None and type(value) is not str:
+            raise TypeError("string exceptions can only have a string value")
     else:
-        raise Exception, "?!"   # XXX
-    return etype, evalue
+        # raise X: we assume that X is an already-built instance
+        if value is not None:
+            raise TypeError("instance exception may not have a separate value")
+        value = etype
+        etype = value.__class__
+        # for the sake of language consistency we should not allow
+        # things like 'raise 1', but it's probably fine (i.e.
+        # not ambiguous) to allow them in the explicit form 'raise int, 1'
+        if not hasattr(value, '__dict__') and not hasattr(value, '__slots__'):
+            raise TypeError("raising built-in objects can be ambiguous, "
+                            "use 'raise type, value' instead")
+    return etype, value
 normalize_exception = gateway.app2interp(app_normalize_exception)
 
 

Modified: pypy/trunk/src/pypy/interpreter/pyopcode.py
==============================================================================
--- pypy/trunk/src/pypy/interpreter/pyopcode.py	(original)
+++ pypy/trunk/src/pypy/interpreter/pyopcode.py	Sat Jun 26 14:47:07 2004
@@ -316,7 +316,7 @@
         if nbargs >= 3: w_traceback = f.valuestack.pop()
         if nbargs >= 2: w_value     = f.valuestack.pop()
         if 1:           w_type      = f.valuestack.pop()
-        w_resulttuple = prepare_raise(f.space, w_type, w_value)
+        w_resulttuple = pyframe.normalize_exception(f.space, w_type, w_value)
         w_type, w_value = f.space.unpacktuple(w_resulttuple, 2)
         tb = f.space.unwrap(w_traceback)
         if tb is not None:
@@ -834,41 +834,6 @@
     stream.write("\n")
     file_softspace(stream, False)
 
-def app_prepare_raise(etype, value):
-    # careful if 'import types' is added here!
-    # we get an infinite loop if this import fails:
-    #    import types -> IMPORT_NAME -> import_name -> raise ImportError
-    #    -> RAISE_VARARGS -> prepare_raise -> import types ...
-    while isinstance(etype, tuple):
-        etype = etype[0]
-    if isinstance(etype, type):
-        if not isinstance(value, etype):
-            if value is None:
-                # raise Type: we assume we have to instantiate Type
-                value = etype()
-            else:
-                # raise Type, X: assume X is the constructor argument
-                value = etype(value)
-        # raise Type, Instance: let etype be the exact type of value
-        etype = value.__class__
-    elif type(etype) is str:
-        # XXX warn -- deprecated
-        if value is not None and type(value) is not str:
-            raise TypeError("string exceptions can only have a string value")
-    else:
-        # raise X: we assume that X is an already-built instance
-        if value is not None:
-            raise TypeError("instance exception may not have a separate value")
-        value = etype
-        etype = value.__class__
-        # for the sake of language consistency we should not allow
-        # things like 'raise 1', but it's probably fine (i.e.
-        # not ambiguous) to allow them in the explicit form 'raise int, 1'
-        if not hasattr(value, '__dict__') and not hasattr(value, '__slots__'):
-            raise TypeError("raising built-in objects can be ambiguous, "
-                            "use 'raise type, value' instead")
-    return etype, value
-
 def app_find_metaclass(bases, namespace, globals):
     if '__metaclass__' in namespace:
         return namespace['__metaclass__']

Modified: pypy/trunk/src/pypy/interpreter/test/test_interpreter.py
==============================================================================
--- pypy/trunk/src/pypy/interpreter/test/test_interpreter.py	(original)
+++ pypy/trunk/src/pypy/interpreter/test/test_interpreter.py	Sat Jun 26 14:47:07 2004
@@ -143,61 +143,10 @@
                           1+2+3 + 5+6+7+8+900)
 
 class AppTestInterpreter(testit.AppTestCase):
-    def test_exception(self):
-        try:
-            raise Exception, 1
-        except Exception, e:
-            self.assertEquals(e.args[0], 1)
-
     def test_trivial(self):
         x = 42
         self.assertEquals(x, 42)
 
-    def test_raise(self):
-        def f():
-            raise Exception
-        self.assertRaises(Exception, f)
-
-    def test_exception(self):
-        try:
-            raise Exception
-            self.fail("exception failed to raise")
-        except:
-            pass
-        else:
-            self.fail("exception executing else clause!")
-
-    def test_raise2(self):
-        def f(r):
-            try:
-                raise r
-            except LookupError:
-                return 1
-        self.assertRaises(Exception, f, Exception)
-        self.assertEquals(f(IndexError), 1)
-
-    def test_raise3(self):
-        try:
-            raise 1
-        except TypeError:
-            pass
-        else:
-            self.fail("shouldn't be able to raise 1")
-
-    def test_raise_three_args(self):
-        import sys
-        try:
-            raise ValueError
-        except:
-            exc_type,exc_val,exc_tb = sys.exc_info()
-        try:
-            raise exc_type,exc_val,exc_tb
-        except:
-            exc_type2,exc_val2,exc_tb2 = sys.exc_info()
-        self.assertEquals(exc_type,exc_type2)
-        self.assertEquals(exc_val,exc_val2)
-        self.assertEquals(exc_tb,exc_tb2)
-
     def test_trivial_call(self):
         def f(): return 42
         self.assertEquals(f(), 42)

Copied: pypy/trunk/src/pypy/interpreter/test/test_raise.py (from r5339, pypy/trunk/src/pypy/interpreter/test/test_interpreter.py)
==============================================================================
--- pypy/trunk/src/pypy/interpreter/test/test_interpreter.py	(original)
+++ pypy/trunk/src/pypy/interpreter/test/test_raise.py	Sat Jun 26 14:47:07 2004
@@ -1,173 +1,67 @@
 import autopath
 from pypy.tool import testit
 
-class TestInterpreter(testit.TestCase):
 
-    def codetest(self, source, functionname, args):
-        """Compile and run the given code string, and then call its function
-        named by 'functionname' with arguments 'args'."""
-        from pypy.interpreter import baseobjspace, executioncontext
-        from pypy.interpreter import pyframe, gateway, module
-        space = self.space
-
-        compile = space.builtin.compile
-        w = space.wrap
-        w_code = compile(w(source), w('<string>'), w('exec'), w(0), w(0))
-
-        ec = executioncontext.ExecutionContext(space)
-
-        tempmodule = module.Module(space, w("__temp__"))
-        w_glob = tempmodule.w_dict
-        space.setitem(w_glob, w("__builtins__"), space.w_builtins)
-
-        code = space.unwrap(w_code)
-        code.exec_code(space, w_glob, w_glob)
-
-        wrappedargs = [w(a) for a in args]
-        wrappedfunc = space.getitem(w_glob, w(functionname))
-        try:
-            w_output = space.call_function(wrappedfunc, *wrappedargs)
-        except baseobjspace.OperationError, e:
-            #e.print_detailed_traceback(space)
-            return '<<<%s>>>' % e.errorstr(space)
+class AppTestRaise(testit.AppTestCase):
+    def test_control_flow(self):
+        try:
+            raise Exception
+            self.fail("exception failed to raise")
+        except:
+            pass
         else:
-            return space.unwrap(w_output)
+            self.fail("exception executing else clause!")
 
-    def setUp(self):
-        self.space = testit.objspace()
+    def test_1arg(self):
+        try:
+            raise SystemError, 1
+        except Exception, e:
+            self.assertEquals(e.args[0], 1)
 
-    def test_exception_trivial(self):
-        x = self.codetest('''
-def f():
-    try:
-        raise Exception()
-    except Exception, e:
-        return 1
-    return 2
-''', 'f', [])
-        self.assertEquals(x, 1)
-
-    def test_exception(self):
-        x = self.codetest('''
-def f():
-    try:
-        raise Exception, 1
-    except Exception, e:
-        return e.args[0]
-''', 'f', [])
-        self.assertEquals(x, 1)
-
-    def test_finally(self):
-        code = '''
-def f(a):
-    try:
-        if a:
-            raise Exception
-        a = -12
-    finally:
-        return a
-'''
-        self.assertEquals(self.codetest(code, 'f', [0]), -12)
-        self.assertEquals(self.codetest(code, 'f', [1]), 1)
-
-##     def test_raise(self):
-##         x = self.codetest('''
-## def f():
-##     raise 1
-## ''', 'f', [])
-##         self.assertEquals(x, '<<<TypeError: exceptions must be instances or subclasses of Exception or strings (deprecated), not int>>>')
-
-    def test_except2(self):
-        x = self.codetest('''
-def f():
-    try:
-        z = 0
-        try:
-            "x"+1
-        except TypeError, e:
-            z = 5
-            raise e
-    except TypeError:
-        return z
-''', 'f', [])
-        self.assertEquals(x, 5)
-
-    def test_except3(self):
-        code = '''
-def f(v):
-    z = 0
-    try:
-        z = 1//v
-    except ZeroDivisionError, e:
-        z = "infinite result"
-    return z
-'''
-        self.assertEquals(self.codetest(code, 'f', [2]), 0)
-        self.assertEquals(self.codetest(code, 'f', [0]), "infinite result")
-        ess = "TypeError: unsupported operand type"
-        res = self.codetest(code, 'f', ['x'])
-        self.failUnless(res.find(ess) >= 0)
-        # the following (original) test was a bit too strict...:
-        # self.assertEquals(self.codetest(code, 'f', ['x']), "<<<TypeError: unsupported operand type(s) for //: 'int' and 'str'>>>")
-
-    def test_break(self):
-        code = '''
-def f(n):
-    total = 0
-    for i in range(n):
-        try:
-            if i == 4:
-                break
-        finally:
-            total += i
-    return total
-'''
-        self.assertEquals(self.codetest(code, 'f', [4]), 1+2+3)
-        self.assertEquals(self.codetest(code, 'f', [9]), 1+2+3+4)
-
-    def test_continue(self):
-        code = '''
-def f(n):
-    total = 0
-    for i in range(n):
-        try:
-            if i == 4:
-                continue
-        finally:
-            total += 100
-        total += i
-    return total
-'''
-        self.assertEquals(self.codetest(code, 'f', [4]), 1+2+3+400)
-        self.assertEquals(self.codetest(code, 'f', [9]),
-                          1+2+3 + 5+6+7+8+900)
+    def test_2args(self):
+        try:
+            raise SystemError, (1, 2)
+        except Exception, e:
+            self.assertEquals(e.args[0], 1)
+            self.assertEquals(e.args[1], 2)
 
-class AppTestInterpreter(testit.AppTestCase):
-    def test_exception(self):
+    def test_instancearg(self):
         try:
-            raise Exception, 1
+            raise SystemError, SystemError(1, 2)
         except Exception, e:
             self.assertEquals(e.args[0], 1)
+            self.assertEquals(e.args[1], 2)
 
-    def test_trivial(self):
-        x = 42
-        self.assertEquals(x, 42)
+    def test_more_precise_instancearg(self):
+        try:
+            raise Exception, SystemError(1, 2)
+        except SystemError, e:
+            self.assertEquals(e.args[0], 1)
+            self.assertEquals(e.args[1], 2)
 
-    def test_raise(self):
-        def f():
-            raise Exception
-        self.assertRaises(Exception, f)
+    def test_stringexc(self):
+        a = "hello world"
+        try:
+            raise a
+        except a, e:
+            self.assertEquals(e, None)
+        try:
+            raise a, "message"
+        except a, e:
+            self.assertEquals(e, "message")
 
-    def test_exception(self):
+    def test_builtin_exc(self):
         try:
-            raise Exception
-            self.fail("exception failed to raise")
-        except:
-            pass
-        else:
-            self.fail("exception executing else clause!")
+            [][0]
+        except IndexError, e:
+            self.assert_(isinstance(e, IndexError))
+
+    def test_raise_cls(self):
+        def f():
+            raise IndexError
+        self.assertRaises(IndexError, f)
 
-    def test_raise2(self):
+    def test_raise_cls_catch(self):
         def f(r):
             try:
                 raise r
@@ -176,7 +70,7 @@
         self.assertRaises(Exception, f, Exception)
         self.assertEquals(f(IndexError), 1)
 
-    def test_raise3(self):
+    def test_raise_wrong(self):
         try:
             raise 1
         except TypeError:
@@ -198,34 +92,38 @@
         self.assertEquals(exc_val,exc_val2)
         self.assertEquals(exc_tb,exc_tb2)
 
-    def test_trivial_call(self):
-        def f(): return 42
-        self.assertEquals(f(), 42)
-
-    def test_trivial_call2(self):
-        def f(): return 1 + 1
-        self.assertEquals(f(), 2)
-
-    def test_print(self):
-        import sys
-        save = sys.stdout 
-        class Out:
-            def __init__(self):
-                self.args = []
-            def write(self, *args):
-                self.args.extend(args)
-        out = Out()
-        try:
-            sys.stdout = out
-            print 10
-            self.assertEquals(out.args, ['10','\n'])
-        finally:
-            sys.stdout = save
-
-    def test_identity(self):
-        def f(x): return x
-        self.assertEquals(f(666), 666)
+    def test_tuple_type(self):
+        def f():
+            raise ((StopIteration, 123), 456, 789)
+        self.assertRaises(StopIteration, f)
 
+    def test_userclass(self):
+        class A:
+            def __init__(self, x=None):
+                self.x = x
+        class B(A):
+            pass
+        try:
+            raise A
+        except A, a:
+            self.assertEquals(a.x, None)
+        try:
+            raise A(42)
+        except A, a:
+            self.assertEquals(a.x, 42)
+        try:
+            raise A, 42
+        except A, a:
+            self.assertEquals(a.x, 42)
+        try:
+            raise B
+        except A, b:
+            self.assertEquals(type(b), B)
+        try:
+            raise A, B(42)
+        except B, b:
+            self.assertEquals(type(b), B)
+            self.assertEquals(b.x, 42)
 
 if __name__ == '__main__':
     testit.main()

Modified: pypy/trunk/src/pypy/objspace/flow/specialcase.py
==============================================================================
--- pypy/trunk/src/pypy/objspace/flow/specialcase.py	(original)
+++ pypy/trunk/src/pypy/objspace/flow/specialcase.py	Sat Jun 26 14:47:07 2004
@@ -1,5 +1,5 @@
 import types
-from pypy.interpreter import pyopcode
+from pypy.interpreter import pyframe
 from pypy.interpreter.error import OperationError
 from pypy.objspace.flow.objspace import UnwrapException
 from pypy.objspace.flow.model import Variable
@@ -48,5 +48,5 @@
 
 def setup(space):
     return {
-        pyopcode.prepare_raise.get_function(space): prepare_raise,
+        pyframe.normalize_exception.get_function(space): prepare_raise,
         }



More information about the Pypy-commit mailing list