[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