[pypy-svn] pypy default: Fix __format__ with oldstyle classes, warning related tests commented out ATM because I can't figure out how to run them.

alex_gaynor commits-noreply at bitbucket.org
Tue Jan 18 19:17:34 CET 2011


Author: Alex Gaynor <alex.gaynor at gmail.com>
Branch: 
Changeset: r40895:ccc2c698dfaa
Date: 2011-01-18 12:16 -0600
http://bitbucket.org/pypy/pypy/changeset/ccc2c698dfaa/

Log:	Fix __format__ with oldstyle classes, warning related tests
	commented out ATM because I can't figure out how to run them.

diff --git a/pypy/module/__builtin__/interp_classobj.py b/pypy/module/__builtin__/interp_classobj.py
--- a/pypy/module/__builtin__/interp_classobj.py
+++ b/pypy/module/__builtin__/interp_classobj.py
@@ -1,7 +1,7 @@
 import new
 from pypy.interpreter.error import OperationError, operationerrfmt
-from pypy.interpreter.gateway import ObjSpace, W_Root, NoneNotWrapped, applevel
-from pypy.interpreter.gateway import interp2app, ObjSpace
+from pypy.interpreter.gateway import (ObjSpace, W_Root, NoneNotWrapped,
+    applevel, interp2app, ObjSpace, unwrap_spec)
 from pypy.interpreter.typedef import TypeDef, make_weakref_descr
 from pypy.interpreter.argument import Arguments
 from pypy.interpreter.baseobjspace import Wrappable
@@ -31,7 +31,7 @@
 def descr_classobj_new(space, w_subtype, w_name, w_bases, w_dict):
     if not space.is_true(space.isinstance(w_bases, space.w_tuple)):
         raise_type_err(space, 'bases', 'tuple', w_bases)
-    
+
     if not space.is_true(space.isinstance(w_dict, space.w_dict)):
         raise_type_err(space, 'bases', 'tuple', w_bases)
 
@@ -39,7 +39,7 @@
         space.setitem(w_dict, space.wrap("__doc__"), space.w_None)
 
     # XXX missing: lengthy and obscure logic about "__module__"
-        
+
     bases_w = space.fixedview(w_bases)
     for w_base in bases_w:
         if not isinstance(w_base, W_ClassObject):
@@ -58,7 +58,7 @@
         make_sure_not_resized(bases)
         self.bases_w = bases
         self.w_dict = w_dict
- 
+
     def instantiate(self, space):
         cache = space.fromcache(Cache)
         if self.lookup(space, '__del__') is not None:
@@ -87,7 +87,7 @@
     def setbases(self, space, w_bases):
         # XXX in theory, this misses a check against inheritance cycles
         # although on pypy we don't get a segfault for infinite
-        # recursion anyway 
+        # recursion anyway
         if not space.is_true(space.isinstance(w_bases, space.w_tuple)):
             raise OperationError(
                     space.w_TypeError,
@@ -454,6 +454,24 @@
             return self.descr_str(space)
         return space.call_function(w_meth)
 
+    @unwrap_spec("self", ObjSpace, W_Root)
+    def descr_format(self, space, w_format_spec):
+        w_meth = self.getattr(space, "__format__", False)
+        if w_meth is not None:
+            return space.call_function(w_meth, w_format_spec)
+        else:
+            if space.isinstance_w(w_format_spec, space.w_unicode):
+                w_as_str = self.descr_unicode(space)
+            else:
+                w_as_str = self.descr_str(space)
+            if space.int_w(space.len(w_format_spec)) > 0:
+                space.warn(
+                    ("object.__format__ with a non-empty format string is "
+                        "deprecated"),
+                    space.w_PendingDeprecationWarning
+                )
+            return space.format(w_as_str, w_format_spec)
+
     def descr_len(self, space):
         w_meth = self.getattr(space, '__len__')
         w_result = space.call_function(w_meth)
@@ -772,6 +790,7 @@
                          unwrap_spec=['self', ObjSpace]),
     __unicode__ = interp2app(W_InstanceObject.descr_unicode,
                          unwrap_spec=['self', ObjSpace]),
+    __format__ = interp2app(W_InstanceObject.descr_format),
     __len__ = interp2app(W_InstanceObject.descr_len,
                          unwrap_spec=['self', ObjSpace]),
     __getitem__ = interp2app(W_InstanceObject.descr_getitem,

diff --git a/pypy/objspace/std/test/test_newformat.py b/pypy/objspace/std/test/test_newformat.py
--- a/pypy/objspace/std/test/test_newformat.py
+++ b/pypy/objspace/std/test/test_newformat.py
@@ -101,6 +101,56 @@
     def test_non_ascii_presentation(self):
         raises(ValueError, format, self.s(""), "\x234")
 
+    def test_oldstyle_custom_format(self):
+        class C:
+            def __init__(self, x=100):
+                self._x = x
+            def __format__(self, spec):
+                return spec
+        class D:
+            def __init__(self, x):
+                self.x = x
+            def __format__(self, spec):
+                return str(self.x)
+        class E:
+            def __init__(self, x):
+                self.x = x
+            def __str__(self):
+                return 'E(' + self.x + ')'
+        class G:
+            def __init__(self, x):
+                self.x = x
+            def __str__(self):
+                return "string is " + self.x
+            def __format__(self, format_spec):
+                if format_spec == 'd':
+                    return 'G(' + self.x + ')'
+                return object.__format__(self, format_spec)
+
+        assert self.s("{1}{0}").format(D(10), D(20)) == self.s("2010")
+        assert self.s("{0._x.x}").format(C(D("abc"))) == self.s("abc")
+        assert self.s("{0[1][0].x}").format(["abc", [D("def")]]) == self.s("def")
+        assert self.s("{0}").format(E("data")) == self.s("E(data)")
+        assert self.s("{0:d}").format(G("data")) == self.s("G(data)")
+        assert self.s("{0!s}").format(G("data")) == self.s("string is data")
+
+        # XXX: run thests tests, self.space isn't available at app-level
+#        warnings = []
+#        def my_warn(msg, warning_cls):
+#            warnings.append((msg, warning_cls))
+#        prev_warning = self.space.warn
+#        space.warn = prev_warning
+#        expected_warning = [
+#            ("object.__format__ with a non-empty format string is deprecated", PendingDeprecationWarning)
+#        ]
+
+        assert self.s("{0:^10}").format(E("data")) == self.s(" E(data)  ")
+#        assert warnings == expected_warning
+        assert self.s("{0:^10s}").format(E("data")) == self.s(" E(data)  ")
+#        assert warnings == expected_warning * 2
+        assert self.s("{0:>15s}").format(G("data")) == self.s(" string is data")
+#        assert warnings == expected_warning * 3
+#        self.space.warn = prev_warn
 
 
 class AppTestUnicodeFormat(BaseStringFormatTests):


More information about the Pypy-commit mailing list