[pypy-commit] pypy cpyext-add_newdoc: merge default into branch

mattip pypy.commits at gmail.com
Sun Jul 9 16:29:41 EDT 2017


Author: Matti Picus <matti.picus at 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}


More information about the pypy-commit mailing list