Commits

Philip Jenvey committed dcbcd0a

branch for adding a couple helper format specifiers to operationerrfmt:
o add %T to return the type name. operationerrfmt has to get space w/ an awful
hack (but the hack is already necessary for py3k)
o operationerrfmt now requires a type object for its first arg to make this
simpler

Comments (0)

Files changed (2)

pypy/interpreter/error.py

 import cStringIO
+import itertools
 import os
 import sys
 import traceback
 
 _fmtcache = {}
 _fmtcache2 = {}
+_FMTS = tuple('sdT')
 
 def decompose_valuefmt(valuefmt):
     """Returns a tuple of string parts extracted from valuefmt,
     parts = valuefmt.split('%')
     i = 1
     while i < len(parts):
-        if parts[i].startswith('s') or parts[i].startswith('d'):
+        if parts[i].startswith(_FMTS):
             formats.append(parts[i][0])
             parts[i] = parts[i][1:]
             i += 1
             parts[i-1] += '%' + parts[i+1]
             del parts[i:i+2]
         else:
-            raise ValueError("invalid format string (only %s or %d supported)")
+            fmts = '%%%s or %%%s' % (', %'.join(_FMTS[:-1]), _FMTS[-1])
+            raise ValueError("invalid format string (only %s supported)" %
+                             fmts)
     assert len(formats) > 0, "unsupported: no % command found"
     return tuple(parts), tuple(formats)
 
+def _is_type(w_obj):
+    from pypy.objspace.std.typeobject import W_TypeObject
+    # HACK: isinstance(w_obj, W_TypeObject) won't translate under the
+    # fake objspace, but w_obj.__class__ is W_TypeObject does and short
+    # circuits to a False constant there, causing the isinstance to be
+    # ignored =[
+    return (w_obj is not None and w_obj.__class__ is W_TypeObject and
+            isinstance(w_obj, W_TypeObject))
+
 def get_operrcls2(valuefmt):
     strings, formats = decompose_valuefmt(valuefmt)
     assert len(strings) == len(formats) + 1
     except KeyError:
         from rpython.rlib.unroll import unrolling_iterable
         attrs = ['x%d' % i for i in range(len(formats))]
-        entries = unrolling_iterable(enumerate(attrs))
+        entries = unrolling_iterable(zip(itertools.count(), formats, attrs))
 
         class OpErrFmt(OperationError):
             def __init__(self, w_type, strings, *args):
                 self.setup(w_type)
                 assert len(args) == len(strings) - 1
                 self.xstrings = strings
-                for i, attr in entries:
+                for i, _, attr in entries:
                     setattr(self, attr, args[i])
-                assert w_type is not None
+                assert _is_type(w_type)
 
             def _compute_value(self):
                 lst = [None] * (len(formats) + len(formats) + 1)
-                for i, attr in entries:
+                for i, fmt, attr in entries:
                     string = self.xstrings[i]
                     value = getattr(self, attr)
                     lst[i+i] = string
-                    lst[i+i+1] = str(value)
+                    if fmt == 'T':
+                        space = self.w_type.space
+                        lst[i+i+1] = space.type(value).getname(space)
+                    else:
+                        lst[i+i+1] = str(value)
                 lst[-1] = self.xstrings[-1]
                 return ''.join(lst)
         #

pypy/interpreter/test/test_error.py

     assert (decompose_valuefmt("%s%d%%%s") ==
             (("", "", "%", ""), ('s', 'd', 's')))
 
-def test_get_operrcls2():
+def test_get_operrcls2(space):
     cls, strings = get_operrcls2('abc %s def %d')
     assert strings == ("abc ", " def ", "")
     assert issubclass(cls, OperationError)
-    inst = cls("w_type", strings, "hello", 42)
+    inst = cls(space.w_OSError, strings, "hello", 42)
     assert inst._compute_value() == "abc hello def 42"
     cls2, strings2 = get_operrcls2('a %s b %d c')
     assert cls2 is cls     # caching
     assert strings2 == ("a ", " b ", " c")
 
-def test_operationerrfmt():
-    operr = operationerrfmt("w_type", "abc %s def %d", "foo", 42)
+def test_operationerrfmt(space):
+    w_exc = space.w_IOError
+    operr = operationerrfmt(w_exc, "abc %s def %d", "foo", 42)
     assert isinstance(operr, OperationError)
-    assert operr.w_type == "w_type"
+    assert operr.w_type == w_exc
     assert operr._w_value is None
     assert operr._compute_value() == "abc foo def 42"
-    operr2 = operationerrfmt("w_type2", "a %s b %d c", "bar", 43)
+    operr2 = operationerrfmt(w_exc, "a %s b %d c", "bar", 43)
     assert operr2.__class__ is operr.__class__
-    operr3 = operationerrfmt("w_type2", "a %s b %s c", "bar", "4b")
+    operr3 = operationerrfmt(w_exc, "a %s b %s c", "bar", "4b")
     assert operr3.__class__ is not operr.__class__
 
+def test_operationerrfmt_T(space):
+    operr = operationerrfmt(space.w_AttributeError,
+                            "'%T' object has no attribute '%s'",
+                            space.wrap('foo'), 'foo')
+    assert operr._compute_value() == "'str' object has no attribute 'foo'"
+
 def test_operationerrfmt_empty():
     py.test.raises(AssertionError, operationerrfmt, "w_type", "foobar")