[pypy-svn] r55442 - in pypy/dist/pypy/objspace: . std std/test

arigo at codespeak.net arigo at codespeak.net
Sat May 31 11:00:32 CEST 2008


Author: arigo
Date: Sat May 31 11:00:30 2008
New Revision: 55442

Modified:
   pypy/dist/pypy/objspace/descroperation.py
   pypy/dist/pypy/objspace/std/test/test_unicodeobject.py
   pypy/dist/pypy/objspace/std/unicodeobject.py
Log:
A minimal change that fixes the bug compatibility issue with
"unicode + string subclass".  The change is similar to the
Jython fix (mostly by accident, the extra check is smaller than
in Jython).


Modified: pypy/dist/pypy/objspace/descroperation.py
==============================================================================
--- pypy/dist/pypy/objspace/descroperation.py	(original)
+++ pypy/dist/pypy/objspace/descroperation.py	Sat May 31 11:00:30 2008
@@ -460,10 +460,20 @@
             # __xxx__ and __rxxx__ methods where found by identity.
             # Note that space.is_w() is potentially not happy if one of them
             # is None (e.g. with the thunk space)...
-            if (w_left_src is not w_right_src    # XXX
-                and space.is_true(space.issubtype(w_typ2, w_typ1))):
-                w_obj1, w_obj2 = w_obj2, w_obj1
-                w_left_impl, w_right_impl = w_right_impl, w_left_impl
+            if w_left_src is not w_right_src:    # XXX
+                # -- cpython bug compatibility: see objspace/std/test/
+                # -- test_unicodeobject.test_str_unicode_concat_overrides.
+                # -- The following handles "unicode + string subclass" by
+                # -- pretending that the unicode is a superclass of the
+                # -- string, thus giving priority to the string subclass'
+                # -- __radd__() method.  The case "string + unicode subclass"
+                # -- is handled directly by add__String_Unicode().
+                if symbol == '+' and space.is_w(w_typ1, space.w_unicode):
+                    w_typ1 = space.w_basestring
+                # -- end of bug compatibility
+                if space.is_true(space.issubtype(w_typ2, w_typ1)):
+                    w_obj1, w_obj2 = w_obj2, w_obj1
+                    w_left_impl, w_right_impl = w_right_impl, w_left_impl
 
         w_res = _invoke_binop(space, w_left_impl, w_obj1, w_obj2)
         if w_res is not None:

Modified: pypy/dist/pypy/objspace/std/test/test_unicodeobject.py
==============================================================================
--- pypy/dist/pypy/objspace/std/test/test_unicodeobject.py	(original)
+++ pypy/dist/pypy/objspace/std/test/test_unicodeobject.py	Sat May 31 11:00:30 2008
@@ -554,3 +554,52 @@
                             '\x00X\x00Y',
                             'X\x00\x00\x00Y\x00\x00\x00',
                             '\x00\x00\x00X\x00\x00\x00Y']
+
+    def test_call_special_methods(self):
+        # xxx not completely clear if these are implementation details or not
+        assert 'abc'.__add__(u'def') == u'abcdef'
+        assert u'abc'.__add__(u'def') == u'abcdef'
+        assert u'abc'.__add__('def') == u'abcdef'
+        # xxx CPython has no str.__radd__ and no unicode.__radd__
+
+    def test_str_unicode_concat_overrides(self):
+        "Test from Jython about being bug-compatible with CPython."
+
+        def check(value, expected):
+            assert type(value) == type(expected)
+            assert value == expected
+
+        def _test_concat(t1, t2):
+            tprecedent = str
+            if issubclass(t1, unicode) or issubclass(t2, unicode):
+                tprecedent = unicode
+
+            class SubclassB(t2):
+                def __add__(self, other):
+                    return SubclassB(t2(self) + t2(other))
+            check(SubclassB('py') + SubclassB('thon'), SubclassB('python'))
+            check(t1('python') + SubclassB('3'), tprecedent('python3'))
+            check(SubclassB('py') + t1('py'), SubclassB('pypy'))
+
+            class SubclassC(t2):
+                def __radd__(self, other):
+                    return SubclassC(t2(other) + t2(self))
+            check(SubclassC('stack') + SubclassC('less'), t2('stackless'))
+            check(t1('iron') + SubclassC('python'), SubclassC('ironpython'))
+            check(SubclassC('tiny') + t1('py'), tprecedent('tinypy'))
+
+            class SubclassD(t2):
+                def __add__(self, other):
+                    return SubclassD(t2(self) + t2(other))
+
+                def __radd__(self, other):
+                    return SubclassD(t2(other) + t2(self))
+            check(SubclassD('di') + SubclassD('ct'), SubclassD('dict'))
+            check(t1('list') + SubclassD(' comp'), SubclassD('list comp'))
+            check(SubclassD('dun') + t1('der'), SubclassD('dunder'))
+
+        _test_concat(str, str)
+        _test_concat(unicode, unicode)
+        # the following two cases are really there to emulate a CPython bug.
+        _test_concat(str, unicode)   # uses hack in add__String_Unicode()
+        _test_concat(unicode, str)   # uses hack in descroperation.binop_impl()

Modified: pypy/dist/pypy/objspace/std/unicodeobject.py
==============================================================================
--- pypy/dist/pypy/objspace/std/unicodeobject.py	(original)
+++ pypy/dist/pypy/objspace/std/unicodeobject.py	Sat May 31 11:00:30 2008
@@ -100,14 +100,28 @@
     return W_UnicodeObject(w_left._value + w_right._value)
 
 def add__String_Unicode(space, w_left, w_right):
+    # this function is needed to make 'abc'.__add__(u'def') return
+    # u'abcdef' instead of NotImplemented.  This is what occurs on
+    # top of CPython.
     from pypy.objspace.std.unicodetype import unicode_from_string
+    # XXX fragile implementation detail: for "string + unicode subclass",
+    # if the unicode subclass overrides __radd__(), then it will be
+    # called (see test_str_unicode_concat_overrides).  This occurs as a
+    # result of the following call to space.add() in which the first
+    # argument is a unicode and the second argument a subclass of unicode
+    # (and thus the usual logic about calling __radd__() first applies).
     return space.add(unicode_from_string(space, w_left) , w_right)
 
 add__Rope_Unicode = add__String_Unicode
 
 def add__Unicode_String(space, w_left, w_right):
+    # this function is needed to make 'abc'.__radd__(u'def') return
+    # u'defabc', although it's completely unclear if that's necessary
+    # given that CPython doesn't even have a method str.__radd__().
     from pypy.objspace.std.unicodetype import unicode_from_string
     return space.add(w_left, unicode_from_string(space, w_right))
+    # Note about "unicode + string subclass": look for
+    # "cpython bug compatibility" in descroperation.py
 
 add__Unicode_Rope = add__Unicode_String
 



More information about the Pypy-commit mailing list