[pypy-commit] pypy default: issue1861: trying to remove the "unicode + string_subclass" hack and
arigo
noreply at buildbot.pypy.org
Sat Sep 6 12:19:58 CEST 2014
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r73338:6a380bc4ae37
Date: 2014-09-06 12:19 +0200
http://bitbucket.org/pypy/pypy/changeset/6a380bc4ae37/
Log: issue1861: trying to remove the "unicode + string_subclass" hack and
replace it with a more general hack, based on detecting that the
left-hand-side argument is a "sequence". This is meant to follow
CPython, which uses sq_xxx methods which mess up with the
implementation of "+" and "*".
diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py
--- a/pypy/objspace/descroperation.py
+++ b/pypy/objspace/descroperation.py
@@ -671,6 +671,7 @@
left, right = specialnames
errormsg = "unsupported operand type(s) for %s: '%%N' and '%%N'" % (
symbol.replace('%', '%%'),)
+ seq_bug_compat = (symbol == '+' or symbol == '*')
def binop_impl(space, w_obj1, w_obj2):
w_typ1 = space.type(w_obj1)
@@ -686,20 +687,16 @@
# __xxx__ and __rxxx__ methods where found by identity.
# Note that space.is_w() is potentially not happy if one of them
# is None...
- 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)):
- if (w_left_src and w_right_src and
- not space.abstract_issubclass_w(w_left_src, w_right_src) and
+ if w_right_src and (w_left_src is not w_right_src) and w_left_src:
+ # 'seq_bug_compat' is for cpython bug-to-bug compatibility:
+ # see objspace/std/test/test_unicodeobject.*concat_overrides
+ # and objspace/test/test_descrobject.*rmul_overrides.
+ # For cases like "unicode + string subclass".
+ if ((seq_bug_compat and w_typ1.flag_sequence_bug_compat
+ and not w_typ2.flag_sequence_bug_compat)
+ # the non-bug-compat part is the following check:
+ or space.is_true(space.issubtype(w_typ2, w_typ1))):
+ if (not space.abstract_issubclass_w(w_left_src, w_right_src) and
not space.abstract_issubclass_w(w_typ1, w_right_src)):
w_obj1, w_obj2 = w_obj2, w_obj1
w_left_impl, w_right_impl = w_right_impl, w_left_impl
diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py
--- a/pypy/objspace/std/bytearrayobject.py
+++ b/pypy/objspace/std/bytearrayobject.py
@@ -1131,6 +1131,7 @@
reverse = interp2app(W_BytearrayObject.descr_reverse,
doc=BytearrayDocstrings.reverse.__doc__),
)
+W_BytearrayObject.typedef.flag_sequence_bug_compat = True
init_signature = Signature(['source', 'encoding', 'errors'], None, None)
init_defaults = [None, None, None]
diff --git a/pypy/objspace/std/bytesobject.py b/pypy/objspace/std/bytesobject.py
--- a/pypy/objspace/std/bytesobject.py
+++ b/pypy/objspace/std/bytesobject.py
@@ -951,6 +951,7 @@
_formatter_field_name_split =
interp2app(W_BytesObject.descr_formatter_field_name_split),
)
+W_BytesObject.typedef.flag_sequence_bug_compat = True
def string_escape_encode(s, quote):
diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py
--- a/pypy/objspace/std/listobject.py
+++ b/pypy/objspace/std/listobject.py
@@ -1874,3 +1874,4 @@
insert = interp2app(W_ListObject.descr_insert),
remove = interp2app(W_ListObject.descr_remove),
)
+W_ListObject.typedef.flag_sequence_bug_compat = True
diff --git a/pypy/objspace/std/stdtypedef.py b/pypy/objspace/std/stdtypedef.py
--- a/pypy/objspace/std/stdtypedef.py
+++ b/pypy/objspace/std/stdtypedef.py
@@ -93,6 +93,8 @@
overridetypedef=overridetypedef)
if typedef is not overridetypedef:
w_type.w_doc = space.wrap(typedef.doc)
+ if hasattr(typedef, 'flag_sequence_bug_compat'):
+ w_type.flag_sequence_bug_compat = typedef.flag_sequence_bug_compat
w_type.lazyloaders = lazyloaders
return w_type
diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py
--- a/pypy/objspace/std/tupleobject.py
+++ b/pypy/objspace/std/tupleobject.py
@@ -244,6 +244,7 @@
count = interp2app(W_AbstractTupleObject.descr_count),
index = interp2app(W_AbstractTupleObject.descr_index)
)
+W_AbstractTupleObject.typedef.flag_sequence_bug_compat = True
class W_TupleObject(W_AbstractTupleObject):
diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py
--- a/pypy/objspace/std/typeobject.py
+++ b/pypy/objspace/std/typeobject.py
@@ -67,6 +67,7 @@
_immutable_fields_ = ["flag_heaptype",
"flag_cpytype",
"flag_abstract?",
+ "flag_sequence_bug_compat",
'needsdel',
'weakrefable',
'hasdict',
@@ -104,6 +105,7 @@
w_self.flag_heaptype = False
w_self.flag_cpytype = False
w_self.flag_abstract = False
+ w_self.flag_sequence_bug_compat = False
w_self.instancetypedef = overridetypedef
if overridetypedef is not None:
diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py
--- a/pypy/objspace/std/unicodeobject.py
+++ b/pypy/objspace/std/unicodeobject.py
@@ -1068,6 +1068,7 @@
_formatter_field_name_split =
interp2app(W_UnicodeObject.descr_formatter_field_name_split),
)
+W_UnicodeObject.typedef.flag_sequence_bug_compat = True
def _create_list_from_unicode(value):
diff --git a/pypy/objspace/test/test_descroperation.py b/pypy/objspace/test/test_descroperation.py
--- a/pypy/objspace/test/test_descroperation.py
+++ b/pypy/objspace/test/test_descroperation.py
@@ -734,6 +734,44 @@
assert X() == 'hello'
+ def test_sequence_rmul_overrides(self):
+ class oops(object):
+ def __rmul__(self, other):
+ return 42
+ def __index__(self):
+ return 3
+ assert '2' * oops() == 42
+ assert [2] * oops() == 42
+ assert (2,) * oops() == 42
+ assert u'2' * oops() == 42
+ assert bytearray('2') * oops() == 42
+ assert 1000 * oops() == 42
+ assert '2'.__mul__(oops()) == '222'
+
+ def test_sequence_rmul_overrides_oldstyle(self):
+ class oops:
+ def __rmul__(self, other):
+ return 42
+ def __index__(self):
+ return 3
+ assert '2' * oops() == 42
+ assert [2] * oops() == 42
+ assert (2,) * oops() == 42
+ assert u'2' * oops() == 42
+ assert bytearray('2') * oops() == 42
+ assert 1000 * oops() == 42
+ assert '2'.__mul__(oops()) == '222'
+
+ def test_sequence_radd_overrides(self):
+ class A1(list):
+ pass
+ class A2(list):
+ def __radd__(self, other):
+ return 42
+ assert [2] + A1([3]) == [2, 3]
+ assert type([2] + A1([3])) is list
+ assert [2] + A2([3]) == 42
+
class AppTestWithBuiltinShortcut(AppTest_Descroperation):
spaceconfig = {'objspace.std.builtinshortcut': True}
More information about the pypy-commit
mailing list