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