[pypy-commit] pypy stdlib-2.7.13: Give up, revert and skip the cpython test, and document in

arigo pypy.commits at gmail.com
Sun Dec 18 15:28:07 EST 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: stdlib-2.7.13
Changeset: r89163:803a7b9b59bf
Date: 2016-12-18 21:27 +0100
http://bitbucket.org/pypy/pypy/changeset/803a7b9b59bf/

Log:	Give up, revert and skip the cpython test, and document in
	cpython_differences.rst

diff --git a/lib-python/2.7/test/test_format.py b/lib-python/2.7/test/test_format.py
--- a/lib-python/2.7/test/test_format.py
+++ b/lib-python/2.7/test/test_format.py
@@ -337,8 +337,10 @@
             except exc:
                 pass
             else:
-                self.fail('%s not raised for %r format of %r' %
-                          (exc.__name__, fmt, result))
+                if test_support.check_impl_detail():
+                    self.fail('%s not raised for %r format of %r' %
+                              (exc.__name__, fmt, result))
+                #else (PyPy): at least it didn't explode, good enough
 
 
 def test_main():
diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst
--- a/pypy/doc/cpython_differences.rst
+++ b/pypy/doc/cpython_differences.rst
@@ -478,6 +478,16 @@
   from the Makefile used to build the interpreter. PyPy should bake the values
   in during compilation, but does not do that yet.
 
+* ``"%d" % x`` and ``"%x" % x`` and similar constructs, where ``x`` is
+  an instance of a subclass of ``long`` that overrides the special
+  methods ``__str__`` or ``__hex__`` or ``__oct__``: PyPy doesn't call
+  the special methods; CPython does---but only if it is a subclass of
+  ``long``, not ``int``.  CPython's behavior is really messy: e.g. for
+  ``%x`` it calls ``__hex__()``, which is supposed to return a string
+  like ``-0x123L``; then the ``0x`` and the final ``L`` are removed, and
+  the rest is kept.  If you return an unexpected string from
+  ``__hex__()`` you get an exception (or a crash before CPython 2.7.13).
+
 .. _`is ignored in PyPy`: http://bugs.python.org/issue14621
 .. _`little point`: http://events.ccc.de/congress/2012/Fahrplan/events/5152.en.html
 .. _`#2072`: https://bitbucket.org/pypy/pypy/issue/2072/
diff --git a/pypy/objspace/std/formatting.py b/pypy/objspace/std/formatting.py
--- a/pypy/objspace/std/formatting.py
+++ b/pypy/objspace/std/formatting.py
@@ -547,7 +547,7 @@
     # make sure that w_value is a wrapped float
     return space.float(w_value)
 
-def format_num_helper_generator(fmt, digits, method, remove_prefix=''):
+def format_num_helper_generator(fmt, digits):
     def format_num_helper(space, w_value):
         if (not space.isinstance_w(w_value, space.w_int) and
             not space.isinstance_w(w_value, space.w_long)):
@@ -563,27 +563,17 @@
                         "%s format: a number is required, not %T", fmt, w_value)
                 else:
                     raise
-        if space.isinstance_w(w_value, space.w_long):
-            text = space.str_w(space.call_method(w_value, method))
-            skip_left = 0
-            skip_right = len(text)
-            if remove_prefix:
-                if not text.startswith(remove_prefix):
-                    raise oefmt(space.w_ValueError,
-                                "%s format: invalid result of %s (type=%T)",
-                                fmt, method, w_value)
-                skip_left = len(remove_prefix)
-            if text.endswith('L'):
-                skip_right = len(text) - 1
-                assert skip_right >= 0
-            return text[skip_left : skip_right]
-        else:
+        try:
             value = space.int_w(w_value)
             return fmt % (value,)
+        except OperationError as operr:
+            if not operr.match(space, space.w_OverflowError):
+                raise
+            num = space.bigint_w(w_value)
+            return num.format(digits)
     return func_with_new_name(format_num_helper,
                               'base%d_num_helper' % len(digits))
 
-int_num_helper = format_num_helper_generator('%d', '0123456789', '__str__')
-oct_num_helper = format_num_helper_generator('%o', '01234567', '__oct__', '0')
-hex_num_helper = format_num_helper_generator('%x', '0123456789abcdef',
-                                             '__hex__', '0x')
+int_num_helper = format_num_helper_generator('%d', '0123456789')
+oct_num_helper = format_num_helper_generator('%o', '01234567')
+hex_num_helper = format_num_helper_generator('%x', '0123456789abcdef')
diff --git a/pypy/objspace/std/test/test_stringformat.py b/pypy/objspace/std/test/test_stringformat.py
--- a/pypy/objspace/std/test/test_stringformat.py
+++ b/pypy/objspace/std/test/test_stringformat.py
@@ -138,11 +138,6 @@
         assert '%d' % sl == '4800000000'
 
     def test_format_subclass_with_str(self):
-        import sys
-        if sys.version_info < (2, 7, 13):
-            skip("CPython gives SystemError before 2.7.13")
-            #...and behaves inconsistently in 2.7.13, but we reproduce that
-
         class SubInt2(int):
             def __str__(self):
                 assert False, "not called"
@@ -162,6 +157,12 @@
         assert '%X' % sl == '7B'
         assert '%o' % sl == '173'
 
+        skip("the rest of this test is serious nonsense imho, changed "
+             "only on 2.7.13, and is different on 3.x anyway.  We could "
+             "reproduce it by writing lengthy logic, then get again the "
+             "reasonable performance by special-casing the exact type "
+             "'long'.  And all for 2.7.13 only.  Let's give up.")
+
         class SubLong2(long):
             def __str__(self):
                 return extra_stuff + 'Xx'


More information about the pypy-commit mailing list