[pypy-svn] r70808 - in pypy/branch/lazy-operr-format/pypy/interpreter: . test

arigo at codespeak.net arigo at codespeak.net
Sun Jan 24 20:29:51 CET 2010


Author: arigo
Date: Sun Jan 24 20:29:50 2010
New Revision: 70808

Added:
   pypy/branch/lazy-operr-format/pypy/interpreter/test/test_error.py   (contents, props changed)
Modified:
   pypy/branch/lazy-operr-format/pypy/interpreter/error.py
Log:
First version.


Modified: pypy/branch/lazy-operr-format/pypy/interpreter/error.py
==============================================================================
--- pypy/branch/lazy-operr-format/pypy/interpreter/error.py	(original)
+++ pypy/branch/lazy-operr-format/pypy/interpreter/error.py	Sun Jan 24 20:29:50 2010
@@ -21,7 +21,7 @@
             from pypy.tool.error import FlowingError
             raise FlowingError(w_value)
         self.w_type = w_type
-        self.w_value = w_value
+        self._w_value = w_value
         self.application_traceback = tb
         if not we_are_translated():
             self.debug_excs = []
@@ -29,7 +29,7 @@
     def clear(self, space):
         # for sys.exc_clear()
         self.w_type = space.w_None
-        self.w_value = space.w_None
+        self._w_value = space.w_None
         self.application_traceback = None
         if not we_are_translated():
             del self.debug_excs[:]
@@ -45,14 +45,15 @@
 
     def __str__(self):
         "NOT_RPYTHON: Convenience for tracebacks."
-        return '[%s: %s]' % (self.w_type, self.w_value)
+        return '[%s: %s]' % (self.w_type, self._w_value)
 
     def errorstr(self, space):
         "The exception class and value, as a string."
+        w_value = self.get_w_value(space)
         if space is None:
             # this part NOT_RPYTHON
             exc_typename = str(self.w_type)
-            exc_value    = str(self.w_value)
+            exc_value    = str(w_value)
         else:
             w = space.wrap
             if space.is_w(space.type(self.w_type), space.w_str):
@@ -60,11 +61,11 @@
             else:
                 exc_typename = space.str_w(
                     space.getattr(self.w_type, w('__name__')))
-            if space.is_w(self.w_value, space.w_None):
+            if space.is_w(w_value, space.w_None):
                 exc_value = ""
             else:
                 try:
-                    exc_value = space.str_w(space.str(self.w_value))
+                    exc_value = space.str_w(space.str(w_value))
                 except OperationError:
                     # oups, cannot __str__ the exception object
                     exc_value = "<oups, exception object itself cannot be str'd>"
@@ -165,7 +166,7 @@
         #  (inst, None)               (inst.__class__, inst)          no
         #
         w_type  = self.w_type
-        w_value = self.w_value
+        w_value = self.get_w_value(space)
         if space.full_exceptions:
             while space.is_true(space.isinstance(w_type, space.w_tuple)):
                 w_type = space.getitem(w_type, space.wrap(0))
@@ -214,8 +215,8 @@
             w_value = w_inst
             w_type = w_instclass
 
-        self.w_type  = w_type
-        self.w_value = w_value
+        self.w_type   = w_type
+        self._w_value = w_value
 
     def write_unraisable(self, space, where, w_object=None):
         if w_object is None:
@@ -232,6 +233,83 @@
         except OperationError:
             pass   # ignored
 
+    def get_w_value(self, space):
+        w_value = self.w_value
+        if w_value is None:
+            value = self._compute_value()
+            self.w_value = w_value = space.wrap(value)
+        return w_value
+
+    def _compute_value(self):
+        raise NotImplementedError
+
+# ____________________________________________________________
+# optimization only: avoid the slowest operation -- the string
+# formatting with '%' -- in the common case were we don't
+# actually need the message.  Only supports %s and %d.
+
+_fmtcache = {}
+_fmtcache2 = {}
+
+def decompose_valuefmt(valuefmt):
+    formats = []
+    parts = valuefmt.split('%')
+    i = 1
+    while i < len(parts):
+        if parts[i].startswith('s') or parts[i].startswith('d'):
+            formats.append(parts[i][0])
+            parts[i] = parts[i][1:]
+            i += 1
+        elif parts[i].startswith('%'):
+            parts[i-1] += parts.pop(i)
+        else:
+            raise ValueError("invalid format string (only %s or %d supported)")
+    return tuple(parts), tuple(formats)
+
+def get_operrcls2(valuefmt):
+    strings, formats = decompose_valuefmt(valuefmt)
+    assert len(strings) == len(formats) + 1
+    try:
+        OpErrFmt = _fmtcache2[formats]
+    except KeyError:
+        from pypy.rlib.unroll import unrolling_iterable
+        attrs = ['x%d' % i for i in range(len(formats))]
+        entries = unrolling_iterable(enumerate(attrs))
+        #
+        class OpErrFmt(OperationError):
+            def __init__(self, w_type, strings, *args):
+                OperationError.__init__(self, w_type, None)
+                assert len(args) == len(strings) - 1
+                self.xstrings = strings
+                for i, attr in entries:
+                    setattr(self, attr, args[i])
+            def _compute_value(self):
+                lst = [None] * (len(formats) + len(formats) + 1)
+                for i, attr in entries:
+                    string = self.xstrings[i]
+                    value = getattr(self, attr)
+                    lst[i+i] = string
+                    lst[i+i+1] = str(value)
+                lst[-1] = self.xstrings[-1]
+                return ''.join(lst)
+        #
+        _fmtcache2[formats] = OpErrFmt
+    return OpErrFmt, strings
+
+def get_operationerr_class(valuefmt):
+    try:
+        result = _fmtcache[valuefmt]
+    except KeyError:
+        result = _fmtcache[valuefmt] = get_operrcls2(valuefmt)
+    return result
+get_operationerr_class._annspecialcase_ = 'specialize:memo'
+
+def operationerrfmt(w_type, valuefmt, *args):
+    OpErrFmt, strings = get_operationerr_class(valuefmt)
+    return OpErrFmt(w_type, strings, *args)
+
+# ____________________________________________________________
+
 # Utilities
 from pypy.tool.ansi_print import ansi_print
 

Added: pypy/branch/lazy-operr-format/pypy/interpreter/test/test_error.py
==============================================================================
--- (empty file)
+++ pypy/branch/lazy-operr-format/pypy/interpreter/test/test_error.py	Sun Jan 24 20:29:50 2010
@@ -0,0 +1,23 @@
+from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.interpreter.error import decompose_valuefmt, get_operrcls2
+
+
+def test_decompose_valuefmt():
+    assert (decompose_valuefmt("abc %s def") ==
+            (("abc ", " def"), ('s',)))
+    assert (decompose_valuefmt("%s%d%s") ==
+            (("", "", "", ""), ('s', 'd', 's')))
+
+def test_get_operrcls2():
+    cls, strings = get_operrcls2('abc %s def %d')
+    assert strings == ("abc ", " def ", "")
+    assert issubclass(cls, OperationError)
+    inst = cls("w_type", strings, "hello", 42)
+    assert inst._compute_value() == "abc hello def 42"
+
+def test_operationerrfmt():
+    operr = operationerrfmt("w_type", "abc %s def %d", "foo", 42)
+    assert isinstance(operr, OperationError)
+    assert operr.w_type == "w_type"
+    assert operr._w_value is None
+    assert operr._compute_value() == "abc foo def 42"



More information about the Pypy-commit mailing list