Author: Matti Picus <matti.pi...@gmail.com> Branch: cpyext-add_newdoc Changeset: r91847:641767ad7623 Date: 2017-07-09 17:20 +0300 http://bitbucket.org/pypy/pypy/changeset/641767ad7623/
Log: merge default into branch diff --git a/pypy/module/__builtin__/functional.py b/pypy/module/__builtin__/functional.py --- a/pypy/module/__builtin__/functional.py +++ b/pypy/module/__builtin__/functional.py @@ -346,9 +346,9 @@ class W_ReversedIterator(W_Root): def __init__(self, space, w_sequence): self.remaining = space.len_w(w_sequence) - 1 - if space.lookup(w_sequence, "__getitem__") is None: + if not space.issequence_w(w_sequence): raise oefmt(space.w_TypeError, - "reversed() argument must be a sequence") + "argument to reversed() must be a sequence") self.w_sequence = w_sequence def descr___iter__(self, space): diff --git a/pypy/module/__builtin__/test/test_functional.py b/pypy/module/__builtin__/test/test_functional.py --- a/pypy/module/__builtin__/test/test_functional.py +++ b/pypy/module/__builtin__/test/test_functional.py @@ -227,6 +227,45 @@ assert list(reversed(list(reversed("hello")))) == ['h','e','l','l','o'] raises(TypeError, reversed, reversed("hello")) + def test_reversed_user_type(self): + class X(object): + def __getitem__(self, index): + return str(index) + def __len__(self): + return 5 + assert list(reversed(X())) == ["4", "3", "2", "1", "0"] + + def test_reversed_not_for_mapping(self): + raises(TypeError, reversed, {}) + raises(TypeError, reversed, {2: 3}) + assert not hasattr(dict, '__reversed__') + raises(TypeError, reversed, int.__dict__) + + def test_reversed_type_with_no_len(self): + class X(object): + def __getitem__(self, key): + raise ValueError + raises(TypeError, reversed, X()) + + def test_reversed_length_hint(self): + lst = [1, 2, 3] + r = reversed(lst) + assert r.__length_hint__() == 3 + assert next(r) == 3 + assert r.__length_hint__() == 2 + lst.pop() + assert r.__length_hint__() == 2 + lst.pop() + assert r.__length_hint__() == 0 + raises(StopIteration, next, r) + # + r = reversed(lst) + assert r.__length_hint__() == 1 + assert next(r) == 1 + assert r.__length_hint__() == 0 + raises(StopIteration, next, r) + assert r.__length_hint__() == 0 + class AppTestApply: def test_apply(self): diff --git a/pypy/module/cpyext/pyerrors.py b/pypy/module/cpyext/pyerrors.py --- a/pypy/module/cpyext/pyerrors.py +++ b/pypy/module/cpyext/pyerrors.py @@ -95,8 +95,18 @@ not an instance of the same class. This function can be used to instantiate the class in that case. If the values are already normalized, nothing happens. The delayed normalization is implemented to improve performance.""" - operr = OperationError(from_ref(space, exc_p[0]), - from_ref(space, val_p[0])) + if exc_p[0]: + w_etype = from_ref(space, exc_p[0]) + else: + # There is no exception, so nothing to do + return + if val_p[0]: + w_evalue = from_ref(space, val_p[0]) + else: + # On CPython, PyErr_SetNone actually sets val to NULL. + # Sensible code should probably never trigger this path on PyPy, but... + w_evalue = space.w_None + operr = OperationError(w_etype, w_evalue) operr.normalize_exception(space) Py_DecRef(space, exc_p[0]) Py_DecRef(space, val_p[0]) @@ -388,9 +398,9 @@ freshly raised. This function steals the references of the arguments. To clear the exception state, pass *NULL* for all three arguments. For general rules about the three arguments, see :c:func:`PyErr_Restore`. - + .. note:: - + This function is not normally used by code that wants to handle exceptions. Rather, it can be used when code needs to save and restore the exception state temporarily. Use diff --git a/pypy/module/cpyext/slotdefs.py b/pypy/module/cpyext/slotdefs.py --- a/pypy/module/cpyext/slotdefs.py +++ b/pypy/module/cpyext/slotdefs.py @@ -466,7 +466,7 @@ ('tp_iter', '__iter__'), ]: if name == tp_name: - slot_fn = w_type.getdictvalue(space, attr) + slot_fn = w_type.lookup(attr) if slot_fn is None: return @@ -481,7 +481,7 @@ ('tp_as_mapping.c_mp_length', '__len__'), ]: if name == tp_name: - slot_fn = w_type.getdictvalue(space, attr) + slot_fn = w_type.lookup(attr) if slot_fn is None: return @slot_function([PyObject], lltype.Signed, error=-1) @@ -508,7 +508,7 @@ ('tp_as_mapping.c_mp_subscript', '__getitem__'), ]: if name == tp_name: - slot_fn = w_type.getdictvalue(space, attr) + slot_fn = w_type.lookup(attr) if slot_fn is None: return @@ -525,7 +525,7 @@ ('tp_as_sequence.c_sq_inplace_repeat', '__imul__'), ]: if name == tp_name: - slot_fn = w_type.getdictvalue(space, attr) + slot_fn = w_type.lookup(attr) if slot_fn is None: return @@ -539,7 +539,7 @@ for tp_name, attr in [('tp_as_number.c_nb_power', '__pow__'), ]: if name == tp_name: - slot_fn = w_type.getdictvalue(space, attr) + slot_fn = w_type.lookup(attr) if slot_fn is None: return @@ -552,10 +552,10 @@ for tp_name, attr in [('tp_as_mapping.c_mp_ass_subscript', '__setitem__'), ]: if name == tp_name: - slot_ass = w_type.getdictvalue(space, attr) + slot_ass = w_type.lookup(attr) if slot_ass is None: return - slot_del = w_type.getdictvalue(space, '__delitem__') + slot_del = w_type.lookup('__delitem__') if slot_del is None: return @@ -573,10 +573,10 @@ for tp_name, attr in [('tp_as_sequence.c_sq_ass_item', '__setitem__'), ]: if name == tp_name: - slot_ass = w_type.getdictvalue(space, attr) + slot_ass = w_type.lookup(attr) if slot_ass is None: return - slot_del = w_type.getdictvalue(space, '__delitem__') + slot_del = w_type.lookup('__delitem__') if slot_del is None: return @@ -593,8 +593,8 @@ if handled: pass elif name == 'tp_setattro': - setattr_fn = w_type.getdictvalue(space, '__setattr__') - delattr_fn = w_type.getdictvalue(space, '__delattr__') + setattr_fn = w_type.lookup('__setattr__') + delattr_fn = w_type.lookup('__delattr__') if setattr_fn is None: return @@ -609,7 +609,7 @@ return 0 slot_func = slot_tp_setattro elif name == 'tp_getattro': - getattr_fn = w_type.getdictvalue(space, '__getattribute__') + getattr_fn = w_type.lookup('__getattribute__') if getattr_fn is None: return @@ -620,7 +620,7 @@ slot_func = slot_tp_getattro elif name == 'tp_call': - call_fn = w_type.getdictvalue(space, '__call__') + call_fn = w_type.lookup('__call__') if call_fn is None: return @@ -633,7 +633,7 @@ slot_func = slot_tp_call elif name == 'tp_iternext': - iternext_fn = w_type.getdictvalue(space, 'next') + iternext_fn = w_type.lookup('next') if iternext_fn is None: return @@ -649,7 +649,7 @@ slot_func = slot_tp_iternext elif name == 'tp_init': - init_fn = w_type.getdictvalue(space, '__init__') + init_fn = w_type.lookup('__init__') if init_fn is None: return @@ -662,7 +662,7 @@ return 0 slot_func = slot_tp_init elif name == 'tp_new': - new_fn = w_type.getdictvalue(space, '__new__') + new_fn = w_type.lookup('__new__') if new_fn is None: return @@ -674,7 +674,7 @@ return space.call_args(space.get(new_fn, w_self), args) slot_func = slot_tp_new elif name == 'tp_as_buffer.c_bf_getbuffer': - buff_fn = w_type.getdictvalue(space, '__buffer__') + buff_fn = w_type.lookup('__buffer__') if buff_fn is not None: buff_w = slot_from___buffer__(space, typedef, buff_fn) elif typedef.buffer: @@ -683,7 +683,7 @@ return slot_func = buff_w elif name == 'tp_descr_get': - get_fn = w_type.getdictvalue(space, '__get__') + get_fn = w_type.lookup('__get__') if get_fn is None: return @@ -695,8 +695,8 @@ return space.call_function(get_fn, w_self, w_obj, w_value) slot_func = slot_tp_descr_get elif name == 'tp_descr_set': - set_fn = w_type.getdictvalue(space, '__set__') - delete_fn = w_type.getdictvalue(space, '__delete__') + set_fn = w_type.lookup('__set__') + delete_fn = w_type.lookup('__delete__') if set_fn is None and delete_fn is None: return diff --git a/pypy/module/cpyext/test/test_boolobject.py b/pypy/module/cpyext/test/test_boolobject.py --- a/pypy/module/cpyext/test/test_boolobject.py +++ b/pypy/module/cpyext/test/test_boolobject.py @@ -26,3 +26,20 @@ ]) assert module.get_true() == True assert module.get_false() == False + + def test_toint(self): + module = self.import_extension('foo', [ + ("to_int", "METH_O", + ''' + if (args->ob_type->tp_as_number && args->ob_type->tp_as_number->nb_int) { + return args->ob_type->tp_as_number->nb_int(args); + } + else { + PyErr_SetString(PyExc_TypeError,"cannot convert bool to int"); + return NULL; + } + '''), ]) + assert module.to_int(False) == 0 + assert module.to_int(True) == 1 + + diff --git a/pypy/module/cpyext/test/test_pyerrors.py b/pypy/module/cpyext/test/test_pyerrors.py --- a/pypy/module/cpyext/test/test_pyerrors.py +++ b/pypy/module/cpyext/test/test_pyerrors.py @@ -177,6 +177,23 @@ ]) assert module.check_error() + def test_normalize_no_exception(self): + module = self.import_extension('foo', [ + ("check_error", "METH_NOARGS", + ''' + PyObject *type, *val, *tb; + PyErr_Fetch(&type, &val, &tb); + if (type != NULL) + Py_RETURN_FALSE; + if (val != NULL) + Py_RETURN_FALSE; + PyErr_NormalizeException(&type, &val, &tb); + Py_RETURN_TRUE; + ''' + ), + ]) + assert module.check_error() + def test_SetFromErrno(self): import sys if sys.platform != 'win32': diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -236,10 +236,6 @@ "an internal 'del' on the dictionary failed to find " "the key") - def descr_reversed(self, space): - raise oefmt(space.w_TypeError, - "argument to reversed() must be a sequence") - def descr_copy(self, space): """D.copy() -> a shallow copy of D""" w_new = W_DictMultiObject.allocate_and_init_instance(space) @@ -517,7 +513,6 @@ __setitem__ = interp2app(W_DictMultiObject.descr_setitem), __delitem__ = interp2app(W_DictMultiObject.descr_delitem), - __reversed__ = interp2app(W_DictMultiObject.descr_reversed), copy = interp2app(W_DictMultiObject.descr_copy), items = interp2app(W_DictMultiObject.descr_items), keys = interp2app(W_DictMultiObject.descr_keys), diff --git a/pypy/objspace/std/dictproxyobject.py b/pypy/objspace/std/dictproxyobject.py --- a/pypy/objspace/std/dictproxyobject.py +++ b/pypy/objspace/std/dictproxyobject.py @@ -99,3 +99,7 @@ copy=interp2app(W_DictProxyObject.copy_w), **cmp_methods ) + +def _set_flag_map_or_seq(space): + w_type = space.gettypeobject(W_DictProxyObject.typedef) + w_type.flag_map_or_seq = 'M' 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 @@ -96,6 +96,10 @@ self._interplevel_classes[w_type] = cls self.w_text = self.w_bytes # 'space.w_text' is w_unicode on Py3 self.w_dict.flag_map_or_seq = 'M' + from pypy.objspace.std import dictproxyobject + dictproxyobject._set_flag_map_or_seq(self) + self.w_list.flag_map_or_seq = 'S' + self.w_tuple.flag_map_or_seq = 'S' 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/test/test_dictproxy.py b/pypy/objspace/std/test/test_dictproxy.py --- a/pypy/objspace/std/test/test_dictproxy.py +++ b/pypy/objspace/std/test/test_dictproxy.py @@ -78,6 +78,8 @@ raises(TypeError, "proxy['a'] = 4") raises(TypeError, "del proxy['a']") raises(AttributeError, "proxy.clear()") + raises(TypeError, reversed, proxy) + class AppTestUserObjectMethodCache(AppTestUserObject): spaceconfig = {"objspace.std.withmethodcachecounter": True} _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit