Author: Armin Rigo <[email protected]>
Branch: cpyext-ext
Changeset: r83743:6940834b346d
Date: 2016-04-18 16:29 +0200
http://bitbucket.org/pypy/pypy/changeset/6940834b346d/
Log: Add another test in cpyext, and fix, including to
operator.is{Sequence,Mapping}Type()
diff --git a/pypy/module/cpyext/test/test_iterator.py
b/pypy/module/cpyext/test/test_iterator.py
--- a/pypy/module/cpyext/test/test_iterator.py
+++ b/pypy/module/cpyext/test/test_iterator.py
@@ -58,5 +58,53 @@
obj = module.test()
assert obj["hi there"] == 42
assert len(obj) == 2
+ assert not hasattr(obj, "__iter__")
e = raises(TypeError, iter, obj)
assert str(e.value).endswith("object is not iterable")
+ #
+ import operator
+ assert not operator.isSequenceType(obj)
+ assert operator.isMappingType(obj)
+
+ def test_iterable_nonmapping_object(self):
+ module = self.import_extension('foo', [
+ ("test", "METH_NOARGS",
+ '''
+ PyObject *obj;
+ Foo_Type.tp_flags = Py_TPFLAGS_DEFAULT;
+ Foo_Type.tp_as_sequence = &tp_as_sequence;
+ tp_as_sequence.sq_length = sq_length;
+ tp_as_sequence.sq_item = sq_item;
+ if (PyType_Ready(&Foo_Type) < 0) return NULL;
+ obj = PyObject_New(PyObject, &Foo_Type);
+ return obj;
+ '''
+ )],
+ '''
+ static PyObject *
+ sq_item(PyObject *self, Py_ssize_t size)
+ {
+ return PyInt_FromLong(42);
+ }
+ static Py_ssize_t
+ sq_length(PyObject *self)
+ {
+ return 2;
+ }
+ PySequenceMethods tp_as_sequence;
+ static PyTypeObject Foo_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "foo.foo",
+ };
+ ''')
+ obj = module.test()
+ assert obj[1] == 42
+ assert len(obj) == 2
+ assert not hasattr(obj, "__iter__")
+ it = iter(obj)
+ assert it.next() == 42
+ assert it.next() == 42
+ #
+ import operator
+ assert operator.isSequenceType(obj)
+ assert not operator.isMappingType(obj)
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -385,6 +385,12 @@
if not space.is_true(space.issubtype(self, space.w_type)):
self.flag_cpytype = True
self.flag_heaptype = False
+ # if a sequence or a mapping, then set the flag to force it
+ if pto.c_tp_as_sequence and pto.c_tp_as_sequence.c_sq_item:
+ self.flag_map_or_seq = 'S'
+ elif (pto.c_tp_as_mapping and pto.c_tp_as_mapping.c_mp_subscript and
+ not (pto.c_tp_as_sequence and pto.c_tp_as_sequence.c_sq_slice)):
+ self.flag_map_or_seq = 'M'
if pto.c_tp_doc:
self.w_doc = space.wrap(rffi.charp2str(pto.c_tp_doc))
diff --git a/pypy/module/operator/__init__.py b/pypy/module/operator/__init__.py
--- a/pypy/module/operator/__init__.py
+++ b/pypy/module/operator/__init__.py
@@ -18,7 +18,7 @@
app_names = ['__delslice__', '__getslice__', '__repeat__', '__setslice__',
'countOf', 'delslice', 'getslice', 'indexOf',
- 'isMappingType', 'isNumberType', 'isSequenceType',
+ 'isNumberType',
'repeat', 'setslice',
'attrgetter', 'itemgetter', 'methodcaller',
]
@@ -36,7 +36,8 @@
'sub', 'truediv', 'truth', 'xor',
'iadd', 'iand', 'iconcat', 'idiv', 'ifloordiv',
'ilshift', 'imod', 'imul', 'ior', 'ipow', 'irepeat',
- 'irshift', 'isub', 'itruediv', 'ixor', '_length_hint']
+ 'irshift', 'isub', 'itruediv', 'ixor', '_length_hint',
+ 'isSequenceType', 'isMappingType']
interpleveldefs = {
'_compare_digest': 'tscmp.compare_digest',
diff --git a/pypy/module/operator/app_operator.py
b/pypy/module/operator/app_operator.py
--- a/pypy/module/operator/app_operator.py
+++ b/pypy/module/operator/app_operator.py
@@ -6,6 +6,7 @@
'''
import types
+import __pypy__
def countOf(a,b):
@@ -39,27 +40,18 @@
index += 1
raise ValueError('sequence.index(x): x not in sequence')
-def isMappingType(obj,):
- 'isMappingType(a) -- Return True if a has a mapping type, False otherwise.'
- if isinstance(obj, types.InstanceType):
- return hasattr(obj, '__getitem__')
- return hasattr(obj, '__getitem__') and not hasattr(obj, '__getslice__')
-
def isNumberType(obj,):
'isNumberType(a) -- Return True if a has a numeric type, False otherwise.'
- return hasattr(obj, '__int__') or hasattr(obj, '__float__')
-
-def isSequenceType(obj,):
- 'isSequenceType(a) -- Return True if a has a sequence type, False
otherwise.'
- if isinstance(obj, dict):
- return False
- return hasattr(obj, '__getitem__')
+ return (__pypy__.lookup_special(obj, '__int__') is not None or
+ __pypy__.lookup_special(obj, '__float__') is not None)
def repeat(obj, num):
'repeat(a, b) -- Return a * b, where a is a sequence, and b is an integer.'
+ import operator
+
if not isinstance(num, (int, long)):
raise TypeError('an integer is required')
- if not isSequenceType(obj):
+ if not operator.isSequenceType(obj):
raise TypeError("non-sequence object can't be repeated")
return obj * num
diff --git a/pypy/module/operator/interp_operator.py
b/pypy/module/operator/interp_operator.py
--- a/pypy/module/operator/interp_operator.py
+++ b/pypy/module/operator/interp_operator.py
@@ -1,5 +1,6 @@
from pypy.interpreter.error import OperationError
from pypy.interpreter.gateway import unwrap_spec
+from pypy.module.__builtin__.interp_classobj import W_InstanceObject
def index(space, w_a):
@@ -247,3 +248,33 @@
@unwrap_spec(default=int)
def _length_hint(space, w_iterable, default):
return space.wrap(space.length_hint(w_iterable, default))
+
+
+def isMappingType(space, w_obj):
+ 'isMappingType(a) -- Return True if a has a mapping type, False otherwise.'
+ if space.is_oldstyle_instance(w_obj):
+ result = (space.findattr(w_obj, space.wrap('__getitem__')) is not None)
+ else:
+ flag = space.type(w_obj).flag_map_or_seq
+ if flag == 'M':
+ result = True
+ elif flag == 'S':
+ result = False
+ else:
+ result = (space.lookup(w_obj, '__getitem__') is not None and
+ space.lookup(w_obj, '__getslice__') is None)
+ return space.wrap(result)
+
+def isSequenceType(space, w_obj):
+ 'isSequenceType(a) -- Return True if a has a sequence type, False
otherwise.'
+ if space.is_oldstyle_instance(w_obj):
+ result = (space.findattr(w_obj, space.wrap('__getitem__')) is not None)
+ else:
+ flag = space.type(w_obj).flag_map_or_seq
+ if flag == 'M':
+ result = False
+ elif flag == 'S':
+ result = True
+ else:
+ result = (space.lookup(w_obj, '__getitem__') is not None)
+ return space.wrap(result)
diff --git a/pypy/module/operator/test/test_operator.py
b/pypy/module/operator/test/test_operator.py
--- a/pypy/module/operator/test/test_operator.py
+++ b/pypy/module/operator/test/test_operator.py
@@ -184,6 +184,19 @@
class Dict(dict): pass
assert not operator.isSequenceType(Dict())
+ def test_isXxxType_more(self):
+ import operator
+
+ assert not operator.isSequenceType(list)
+ assert not operator.isSequenceType(dict)
+ assert not operator.isSequenceType({})
+ assert not operator.isMappingType(list)
+ assert not operator.isMappingType(dict)
+ assert not operator.isMappingType([])
+ assert not operator.isMappingType(())
+ assert not operator.isNumberType(int)
+ assert not operator.isNumberType(float)
+
def test_inplace(self):
import operator
diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py
--- a/pypy/objspace/descroperation.py
+++ b/pypy/objspace/descroperation.py
@@ -273,7 +273,8 @@
def iter(space, w_obj):
w_descr = space.lookup(w_obj, '__iter__')
if w_descr is None:
- w_descr = space.lookup(w_obj, '__getitem__')
+ if space.type(w_obj).flag_map_or_seq != 'M':
+ w_descr = space.lookup(w_obj, '__getitem__')
if w_descr is None:
raise oefmt(space.w_TypeError,
"'%T' object is not iterable", w_obj)
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
@@ -90,6 +90,7 @@
self.builtin_types[typedef.name] = w_type
setattr(self, 'w_' + typedef.name, w_type)
self._interplevel_classes[w_type] = cls
+ self.w_dict.flag_map_or_seq = 'M'
self.builtin_types["NotImplemented"] = self.w_NotImplemented
self.builtin_types["Ellipsis"] = self.w_Ellipsis
self.w_basestring = self.builtin_types['basestring'] = \
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
@@ -126,6 +126,7 @@
"flag_cpytype",
"flag_abstract?",
"flag_sequence_bug_compat",
+ "flag_map_or_seq", # '?' or 'M' or 'S'
'needsdel',
'weakrefable',
'hasdict',
@@ -162,6 +163,7 @@
w_self.flag_cpytype = False
w_self.flag_abstract = False
w_self.flag_sequence_bug_compat = False
+ w_self.flag_map_or_seq = '?' # '?' means "don't know, check
otherwise"
if overridetypedef is not None:
assert not force_new_layout
@@ -1096,6 +1098,8 @@
continue
w_self.flag_cpytype |= w_base.flag_cpytype
w_self.flag_abstract |= w_base.flag_abstract
+ if w_self.flag_map_or_seq == '?':
+ w_self.flag_map_or_seq = w_base.flag_map_or_seq
hasoldstylebase = copy_flags_from_bases(w_self, w_bestbase)
layout = create_all_slots(w_self, hasoldstylebase, w_bestbase,
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit