[pypy-commit] pypy release-5.x: Probable fix for issue #2383: have 'list(S())' call 'S.__getitem__' if S
arigo
pypy.commits at gmail.com
Fri Sep 9 13:28:37 EDT 2016
Author: Armin Rigo <arigo at tunes.org>
Branch: release-5.x
Changeset: r86978:eacdeb58a9ec
Date: 2016-08-29 20:32 +0200
http://bitbucket.org/pypy/pypy/changeset/eacdeb58a9ec/
Log: Probable fix for issue #2383: have 'list(S())' call 'S.__getitem__'
if S is a subclass of str with a custom __getitem__. (grafted from
990f5b2322e124bbbfd7d9ab56d44a77f0085a8a)
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)
More information about the pypy-commit
mailing list