Author: Armin Rigo <ar...@tunes.org> Branch: Changeset: r86709:990f5b2322e1 Date: 2016-08-29 20:32 +0200 http://bitbucket.org/pypy/pypy/changeset/990f5b2322e1/
Log: Probable fix for issue #2383: have 'list(S())' call 'S.__getitem__' if S is a subclass of str with a custom __getitem__. diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py --- a/pypy/objspace/descroperation.py +++ b/pypy/objspace/descroperation.py @@ -58,6 +58,20 @@ return w_iter tuple_iter._annspecialcase_ = 'specialize:memo' +def str_getitem(space): + "Utility that returns the app-level descriptor str.__getitem__." + w_src, w_iter = space.lookup_in_type_where(space.w_str, + '__getitem__') + return w_iter +str_getitem._annspecialcase_ = 'specialize:memo' + +def unicode_getitem(space): + "Utility that returns the app-level descriptor unicode.__getitem__." + w_src, w_iter = space.lookup_in_type_where(space.w_unicode, + '__getitem__') + return w_iter +unicode_getitem._annspecialcase_ = 'specialize:memo' + def raiseattrerror(space, w_obj, name, w_descr=None): if w_descr is None: raise oefmt(space.w_AttributeError, 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 @@ -445,7 +445,7 @@ return w_obj.listview_bytes() if type(w_obj) is W_SetObject or type(w_obj) is W_FrozensetObject: return w_obj.listview_bytes() - if isinstance(w_obj, W_BytesObject) and self._uses_no_iter(w_obj): + if isinstance(w_obj, W_BytesObject) and self._str_uses_no_iter(w_obj): return w_obj.listview_bytes() if isinstance(w_obj, W_ListObject) and self._uses_list_iter(w_obj): return w_obj.getitems_bytes() @@ -460,7 +460,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) and self._uses_no_iter(w_obj): + if isinstance(w_obj, W_UnicodeObject) and self._uni_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() @@ -504,8 +504,15 @@ 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 _str_uses_no_iter(self, w_obj): + from pypy.objspace.descroperation import str_getitem + return (self.lookup(w_obj, '__iter__') is None and + self.lookup(w_obj, '__getitem__') is str_getitem(self)) + + def _uni_uses_no_iter(self, w_obj): + from pypy.objspace.descroperation import unicode_getitem + return (self.lookup(w_obj, '__iter__') is None and + self.lookup(w_obj, '__getitem__') is unicode_getitem(self)) def sliceindices(self, w_slice, w_length): if isinstance(w_slice, W_SliceObject): 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 @@ -432,7 +432,7 @@ class AppTestListObject(object): - spaceconfig = {"objspace.std.withliststrategies": True} # it's the default + #spaceconfig = {"objspace.std.withliststrategies": True} # it's the default def setup_class(cls): import platform @@ -1518,6 +1518,16 @@ def __iter__(self): yield "ok" assert list(U(u"don't see me")) == ["ok"] + # + class S(str): + def __getitem__(self, index): + return str.__getitem__(self, index).upper() + assert list(S("abc")) == list("ABC") + # + class U(unicode): + def __getitem__(self, index): + return unicode.__getitem__(self, index).upper() + assert list(U(u"abc")) == list(u"ABC") def test_extend_from_nonempty_list_with_subclasses(self): l = ["hi!"] @@ -1543,6 +1553,20 @@ l.extend(U(u"don't see me")) # assert l == ["hi!", "okT", "okL", "okL", "okS", "okU"] + # + class S(str): + def __getitem__(self, index): + return str.__getitem__(self, index).upper() + l = [] + l.extend(S("abc")) + assert l == list("ABC") + # + class U(unicode): + def __getitem__(self, index): + return unicode.__getitem__(self, index).upper() + l = [] + l.extend(U(u"abc")) + assert l == list(u"ABC") def test_no_len_on_range_iter(self): iterable = range(10) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit