Author: Brian Kearns <bdkea...@gmail.com> Branch: Changeset: r68514:4cc2e74ada93 Date: 2013-12-20 14:54 -0500 http://bitbucket.org/pypy/pypy/changeset/4cc2e74ada93/
Log: merge heads diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py --- a/pypy/objspace/descroperation.py +++ b/pypy/objspace/descroperation.py @@ -51,6 +51,13 @@ return w_iter list_iter._annspecialcase_ = 'specialize:memo' +def tuple_iter(space): + "Utility that returns the app-level descriptor tuple.__iter__." + w_src, w_iter = space.lookup_in_type_where(space.w_tuple, + '__iter__') + return w_iter +tuple_iter._annspecialcase_ = 'specialize:memo' + def raiseattrerror(space, w_obj, name, w_descr=None): if w_descr is None: raise operationerrfmt(space.w_AttributeError, 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 @@ -945,7 +945,8 @@ def _extend_from_iterable(self, w_list, w_iterable): space = self.space - if isinstance(w_iterable, W_AbstractTupleObject): + if (isinstance(w_iterable, W_AbstractTupleObject) + and space._uses_tuple_iter(w_iterable)): w_list.__init__(space, w_iterable.getitems_copy()) return diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -382,7 +382,7 @@ self.wrap("expected length %d, got %d" % (expected, got))) def unpackiterable(self, w_obj, expected_length=-1): - if isinstance(w_obj, W_AbstractTupleObject): + if isinstance(w_obj, W_AbstractTupleObject) and self._uses_tuple_iter(w_obj): t = w_obj.getitems_copy() elif type(w_obj) is W_ListObject: t = w_obj.getitems_copy() @@ -396,7 +396,7 @@ def fixedview(self, w_obj, expected_length=-1, unroll=False): """ Fast paths """ - if isinstance(w_obj, W_AbstractTupleObject): + if isinstance(w_obj, W_AbstractTupleObject) and self._uses_tuple_iter(w_obj): t = w_obj.tolist() elif type(w_obj) is W_ListObject: if unroll: @@ -421,7 +421,7 @@ def listview(self, w_obj, expected_length=-1): if type(w_obj) is W_ListObject: t = w_obj.getitems() - elif isinstance(w_obj, W_AbstractTupleObject): + elif isinstance(w_obj, W_AbstractTupleObject) and self._uses_tuple_iter(w_obj): t = w_obj.getitems_copy() elif isinstance(w_obj, W_ListObject) and self._uses_list_iter(w_obj): t = w_obj.getitems() @@ -440,7 +440,7 @@ return w_obj.listview_str() if type(w_obj) is W_SetObject or type(w_obj) is W_FrozensetObject: return w_obj.listview_str() - if isinstance(w_obj, W_StringObject): + if isinstance(w_obj, W_StringObject) and self._uses_no_iter(w_obj): return w_obj.listview_str() if isinstance(w_obj, W_ListObject) and self._uses_list_iter(w_obj): return w_obj.getitems_str() @@ -455,7 +455,7 @@ return w_obj.listview_unicode() if type(w_obj) is W_SetObject or type(w_obj) is W_FrozensetObject: return w_obj.listview_unicode() - if isinstance(w_obj, W_UnicodeObject): + if isinstance(w_obj, W_UnicodeObject) and self._uses_no_iter(w_obj): return w_obj.listview_unicode() if isinstance(w_obj, W_ListObject) and self._uses_list_iter(w_obj): return w_obj.getitems_unicode() @@ -490,6 +490,13 @@ from pypy.objspace.descroperation import list_iter return self.lookup(w_obj, '__iter__') is list_iter(self) + def _uses_tuple_iter(self, w_obj): + from pypy.objspace.descroperation import tuple_iter + return self.lookup(w_obj, '__iter__') is tuple_iter(self) + + def _uses_no_iter(self, w_obj): + return self.lookup(w_obj, '__iter__') is None + def sliceindices(self, w_slice, w_length): if isinstance(w_slice, W_SliceObject): a, b, c = w_slice.indices3(self, self.int_w(w_length)) diff --git a/pypy/objspace/std/test/test_listobject.py b/pypy/objspace/std/test/test_listobject.py --- a/pypy/objspace/std/test/test_listobject.py +++ b/pypy/objspace/std/test/test_listobject.py @@ -1314,6 +1314,57 @@ non_list = NonList() assert [] != non_list + def test_extend_from_empty_list_with_subclasses(self): + # some of these tests used to fail by ignoring the + # custom __iter__() --- but only if the list has so + # far the empty strategy, as opposed to .extend()ing + # a non-empty list. + class T(tuple): + def __iter__(self): + yield "ok" + assert list(T([5, 6])) == ["ok"] + # + class L(list): + def __iter__(self): + yield "ok" + assert list(L([5, 6])) == ["ok"] + assert list(L([5.2, 6.3])) == ["ok"] + # + class S(str): + def __iter__(self): + yield "ok" + assert list(S("don't see me")) == ["ok"] + # + class U(unicode): + def __iter__(self): + yield "ok" + assert list(U(u"don't see me")) == ["ok"] + + def test_extend_from_nonempty_list_with_subclasses(self): + l = ["hi!"] + class T(tuple): + def __iter__(self): + yield "okT" + l.extend(T([5, 6])) + # + class L(list): + def __iter__(self): + yield "okL" + l.extend(L([5, 6])) + l.extend(L([5.2, 6.3])) + # + class S(str): + def __iter__(self): + yield "okS" + l.extend(S("don't see me")) + # + class U(unicode): + def __iter__(self): + yield "okU" + l.extend(U(u"don't see me")) + # + assert l == ["hi!", "okT", "okL", "okL", "okS", "okU"] + class AppTestForRangeLists(AppTestW_ListObject): spaceconfig = {"objspace.std.withrangelist": True} _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit