Author: Ronan Lamy <ronan.l...@gmail.com>
Branch: py3.5
Changeset: r91837:920958a93997
Date: 2017-07-08 01:18 +0100
http://bitbucket.org/pypy/pypy/changeset/920958a93997/

Log:    hg merge default

diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -21,3 +21,7 @@
 .. branch: issue-2592
 
 CPyext PyListObject.pop must return the value
+
+.. branch: cpyext-hash_notimpl
+
+If ``tp_hash`` is ``PyObject_HashNotImplemented``, set 
``obj.__dict__['__hash__']`` to None
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
@@ -125,8 +125,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])
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
@@ -174,6 +174,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/module/cpyext/test/test_typeobject.py 
b/pypy/module/cpyext/test/test_typeobject.py
--- a/pypy/module/cpyext/test/test_typeobject.py
+++ b/pypy/module/cpyext/test/test_typeobject.py
@@ -1301,3 +1301,33 @@
         Bsize = module.get_basicsize(B)
         assert Asize == Bsize
         assert Asize > basesize
+
+
+class AppTestHashable(AppTestCpythonExtensionBase):
+    def test_unhashable(self):
+        if not self.runappdirect:
+            skip('pointer to function equality available'
+                 ' only after translation')
+        module = self.import_extension('foo', [
+           ("new_obj", "METH_NOARGS",
+            '''
+                PyObject *obj;
+                obj = PyObject_New(PyObject, &Foo_Type);
+                return obj;
+            '''
+            )], prologue='''
+            static PyTypeObject Foo_Type = {
+                PyVarObject_HEAD_INIT(NULL, 0)
+                "foo.foo",
+            };
+            ''', more_init = '''
+                Foo_Type.tp_flags = Py_TPFLAGS_DEFAULT;
+                Foo_Type.tp_hash = PyObject_HashNotImplemented;
+                if (PyType_Ready(&Foo_Type) < 0) INITERROR;
+            ''')
+        obj = module.new_obj()
+        raises(TypeError, hash, obj)
+        assert type(obj).__dict__['__hash__'] is None
+        # this is equivalent to
+        from collections import Hashable
+        assert not isinstance(obj, Hashable)
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
@@ -337,13 +337,19 @@
                 setattr(struct, slot_names[1], slot_func_helper)
 
 def add_operators(space, dict_w, pto):
-    # XXX support PyObject_HashNotImplemented
+    from pypy.module.cpyext.object import PyObject_HashNotImplemented
+    hash_not_impl = PyObject_HashNotImplemented.api_func.get_llhelper(space)
     for method_name, slot_names, wrapper_func, wrapper_func_kwds, doc in 
slotdefs_for_wrappers:
         if method_name in dict_w:
             continue
         offset = [rffi.offsetof(lltype.typeOf(pto).TO, slot_names[0])]
         if len(slot_names) == 1:
             func = getattr(pto, slot_names[0])
+            if slot_names[0] == 'c_tp_hash':
+                if hash_not_impl == func:
+                    # special case for tp_hash == PyObject_HashNotImplemented
+                    dict_w[method_name] = space.w_None
+                    continue
         else:
             assert len(slot_names) == 2
             struct = getattr(pto, slot_names[0])
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to