Author: Manuel Jacob <m...@manueljacob.de> Branch: py3.6 Changeset: r92514:d4a38e82d0d7 Date: 2017-09-29 19:50 +0200 http://bitbucket.org/pypy/pypy/changeset/d4a38e82d0d7/
Log: hg merge py3.5 diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -669,7 +669,7 @@ 'PySlice_Type': 'space.gettypeobject(W_SliceObject.typedef)', 'PyStaticMethod_Type': 'space.gettypeobject(StaticMethod.typedef)', 'PyCFunction_Type': 'space.gettypeobject(cpyext.methodobject.W_PyCFunctionObject.typedef)', - 'PyWrapperDescr_Type': 'space.gettypeobject(cpyext.methodobject.W_PyCMethodObject.typedef)', + 'PyWrapperDescr_Type': 'space.gettypeobject(cpyext.methodobject.W_PyCWrapperObject.typedef)', 'PyInstanceMethod_Type': 'space.gettypeobject(cpyext.classobject.InstanceMethod.typedef)', }.items(): register_global(cpyname, 'PyTypeObject*', pypyexpr, header=pypy_decl) @@ -1338,17 +1338,20 @@ for decl in FORWARD_DECLS: decls[pypy_decl].append("%s;" % (decl,)) decls[pypy_decl].append(""" - /* hack for https://bugs.python.org/issue29943 */ - PyAPI_FUNC(int) %s(PySliceObject *arg0, - Signed arg1, Signed *arg2, - Signed *arg3, Signed *arg4, Signed *arg5); - static int PySlice_GetIndicesEx(PySliceObject *arg0, Py_ssize_t arg1, - Py_ssize_t *arg2, Py_ssize_t *arg3, Py_ssize_t *arg4, - Py_ssize_t *arg5) { - return %s(arg0, arg1, arg2, arg3, - arg4, arg5); - } - """ % ((mangle_name(prefix, 'PySlice_GetIndicesEx'),)*2)) +/* hack for https://bugs.python.org/issue29943 */ + +PyAPI_FUNC(int) %s(PyObject *arg0, + Signed arg1, Signed *arg2, + Signed *arg3, Signed *arg4, Signed *arg5); +#ifdef __GNUC__ +__attribute__((__unused__)) +#endif +static int PySlice_GetIndicesEx(PyObject *arg0, Py_ssize_t arg1, + Py_ssize_t *arg2, Py_ssize_t *arg3, Py_ssize_t *arg4, + Py_ssize_t *arg5) { + return %s(arg0, arg1, arg2, arg3, + arg4, arg5); +}""" % ((mangle_name(prefix, 'PySlice_GetIndicesEx'),)*2)) for header_name, header_functions in FUNCTIONS_BY_HEADER.iteritems(): header = decls[header_name] diff --git a/pypy/module/cpyext/include/descrobject.h b/pypy/module/cpyext/include/descrobject.h --- a/pypy/module/cpyext/include/descrobject.h +++ b/pypy/module/cpyext/include/descrobject.h @@ -1,34 +1,6 @@ #ifndef Py_DESCROBJECT_H #define Py_DESCROBJECT_H -#define PyDescr_COMMON \ - PyObject_HEAD \ - PyTypeObject *d_type; \ - PyObject *d_name - -typedef struct { - PyDescr_COMMON; -} PyDescrObject; - -typedef struct { - PyDescr_COMMON; - PyMethodDef *d_method; -} PyMethodDescrObject; - -typedef struct { - PyDescr_COMMON; - struct PyMemberDef *d_member; -} PyMemberDescrObject; - -typedef struct { - PyDescr_COMMON; - PyGetSetDef *d_getset; -} PyGetSetDescrObject; - -typedef struct { - PyDescr_COMMON; - struct wrapperbase *d_base; - void *d_wrapped; /* This can be any function pointer */ -} PyWrapperDescrObject; +#include "cpyext_descrobject.h" #endif diff --git a/pypy/module/cpyext/methodobject.py b/pypy/module/cpyext/methodobject.py --- a/pypy/module/cpyext/methodobject.py +++ b/pypy/module/cpyext/methodobject.py @@ -1,4 +1,4 @@ -from rpython.rtyper.lltypesystem import lltype, rffi, llmemory +from rpython.rtyper.lltypesystem import lltype, rffi from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError, oefmt @@ -10,8 +10,8 @@ from pypy.module.cpyext.api import ( CONST_STRING, METH_CLASS, METH_COEXIST, METH_KEYWORDS, METH_NOARGS, METH_O, METH_STATIC, METH_VARARGS, PyObject, bootstrap_function, - cpython_api, generic_cpy_call, CANNOT_FAIL, - PyTypeObjectPtr, slot_function, cts) + cpython_api, generic_cpy_call, CANNOT_FAIL, slot_function, cts, + build_type_checkers) from pypy.module.cpyext.pyobject import ( Py_DecRef, from_ref, make_ref, as_pyobj, make_typedescr) @@ -102,7 +102,7 @@ return self.space.unwrap(self.descr_method_repr()) def descr_method_repr(self): - w_objclass = self.w_objclass + w_objclass = self.w_objclass assert isinstance(w_objclass, W_TypeObject) return self.space.newtext("<method '%s' of '%s' objects>" % ( self.name, w_objclass.name)) @@ -110,7 +110,7 @@ def descr_call(self, space, __args__): args_w, kw_w = __args__.unpack() if len(args_w) < 1: - w_objclass = self.w_objclass + w_objclass = self.w_objclass assert isinstance(w_objclass, W_TypeObject) raise oefmt(space.w_TypeError, "descriptor '%8' of '%s' object needs an argument", @@ -118,7 +118,7 @@ w_instance = args_w[0] # XXX: needs a stricter test if not space.isinstance_w(w_instance, self.w_objclass): - w_objclass = self.w_objclass + w_objclass = self.w_objclass assert isinstance(w_objclass, W_TypeObject) raise oefmt(space.w_TypeError, "descriptor '%8' requires a '%s' object but received a '%T'", @@ -130,6 +130,10 @@ ret = self.call(space, w_instance, w_args, w_kw) return ret +# PyPy addition, for Cython +_, _ = build_type_checkers("MethodDescr", W_PyCMethodObject) + + @cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL) def PyCFunction_Check(space, w_obj): from pypy.interpreter.function import BuiltinFunction @@ -156,6 +160,7 @@ (self.name.decode('utf-8'), self.w_objclass.getname(self.space))) + class W_PyCWrapperObject(W_Root): def __init__(self, space, pto, method_name, wrapper_func, wrapper_func_kwds, doc, func, offset=None): @@ -323,11 +328,15 @@ def PyClassMethod_New(space, w_func): return ClassMethod(w_func) -@cpython_api([PyTypeObjectPtr, lltype.Ptr(PyMethodDef)], PyObject) +@cts.decl(""" + PyObject * + PyDescr_NewClassMethod(PyTypeObject *type, PyMethodDef *method)""") def PyDescr_NewMethod(space, w_type, method): return W_PyCMethodObject(space, method, w_type) -@cpython_api([PyObject, lltype.Ptr(PyMethodDef)], PyObject) +@cts.decl(""" + PyObject * + PyDescr_NewClassMethod(PyTypeObject *type, PyMethodDef *method)""") def PyDescr_NewClassMethod(space, w_type, method): return W_PyCClassMethodObject(space, method, w_type) diff --git a/pypy/module/cpyext/parse/cpyext_descrobject.h b/pypy/module/cpyext/parse/cpyext_descrobject.h new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/parse/cpyext_descrobject.h @@ -0,0 +1,29 @@ +typedef struct { + PyObject_HEAD + PyTypeObject *d_type; + PyObject *d_name; + PyObject *d_qualname; +} PyDescrObject; + +#define PyDescr_COMMON PyDescrObject d_common + +typedef struct { + PyDescr_COMMON; + PyMethodDef *d_method; +} PyMethodDescrObject; + +typedef struct { + PyDescr_COMMON; + struct PyMemberDef *d_member; +} PyMemberDescrObject; + +typedef struct { + PyDescr_COMMON; + PyGetSetDef *d_getset; +} PyGetSetDescrObject; + +typedef struct { + PyDescr_COMMON; + struct wrapperbase *d_base; + void *d_wrapped; /* This can be any function pointer */ +} PyWrapperDescrObject; diff --git a/pypy/module/cpyext/test/foo.c b/pypy/module/cpyext/test/foo.c --- a/pypy/module/cpyext/test/foo.c +++ b/pypy/module/cpyext/test/foo.c @@ -83,6 +83,35 @@ return cls; } +// for CPython +#ifndef PyMethodDescr_Check +int PyMethodDescr_Check(PyObject* method) +{ + PyObject *meth = PyObject_GetAttrString((PyObject*)&PyList_Type, "append"); + if (!meth) return 0; + int res = PyObject_TypeCheck(method, meth->ob_type); + Py_DECREF(meth); + return res; +} +#endif + +PyObject* make_classmethod(PyObject* method) +{ + // adapted from __Pyx_Method_ClassMethod + if (PyMethodDescr_Check(method)) { + PyMethodDescrObject *descr = (PyMethodDescrObject *)method; + PyTypeObject *d_type = descr->d_common.d_type; + return PyDescr_NewClassMethod(d_type, descr->d_method); + } + else if (PyMethod_Check(method)) { + return PyClassMethod_New(PyMethod_GET_FUNCTION(method)); + } + else { + PyErr_SetString(PyExc_TypeError, "unknown method kind"); + return NULL; + } +} + static PyObject * foo_unset(fooobject *self) { @@ -95,6 +124,7 @@ {"copy", (PyCFunction)foo_copy, METH_NOARGS, NULL}, {"create", (PyCFunction)foo_create, METH_NOARGS|METH_STATIC, NULL}, {"classmeth", (PyCFunction)foo_classmeth, METH_NOARGS|METH_CLASS, NULL}, + {"fake_classmeth", (PyCFunction)foo_classmeth, METH_NOARGS, NULL}, {"unset_string_member", (PyCFunction)foo_unset, METH_NOARGS, NULL}, {NULL, NULL} /* sentinel */ }; @@ -167,19 +197,19 @@ /* copied from numpy scalartypes.c for inherited classes */ if (t->tp_bases && (PyTuple_GET_SIZE(t->tp_bases) > 1)) { - PyTypeObject *sup; - /* We are inheriting from a Python type as well so + PyTypeObject *sup; + /* We are inheriting from a Python type as well so give it first dibs on conversion */ sup = (PyTypeObject *)PyTuple_GET_ITEM(t->tp_bases, 1); - /* Prevent recursion */ - if (new_fooType != sup->tp_new) + /* Prevent recursion */ + if (new_fooType != sup->tp_new) { o = sup->tp_new(t, args, kwds); return o; } } o = t->tp_alloc(t, 0); - return o; + return o; }; static PyMemberDef foo_members[] = { @@ -717,7 +747,7 @@ "foo", "Module Doc", -1, - foo_functions, + foo_functions, NULL, NULL, NULL, @@ -751,6 +781,7 @@ #endif { PyObject *d; + PyObject *fake_classmeth, *classmeth; #if PY_MAJOR_VERSION >= 3 PyObject *module = PyModule_Create(&moduledef); #else @@ -808,6 +839,12 @@ INITERROR; gettype2 = PyObject_New(PyObject, &GetType2); + fake_classmeth = PyDict_GetItemString((PyObject *)fooType.tp_dict, "fake_classmeth"); + classmeth = make_classmethod(fake_classmeth); + if (classmeth == NULL) + INITERROR; + if (PyDict_SetItemString((PyObject *)fooType.tp_dict, "fake_classmeth", classmeth) < 0) + INITERROR; d = PyModule_GetDict(module); if (d == NULL) diff --git a/pypy/module/cpyext/test/test_fileobject.py b/pypy/module/cpyext/test/test_fileobject.py --- a/pypy/module/cpyext/test/test_fileobject.py +++ b/pypy/module/cpyext/test/test_fileobject.py @@ -7,7 +7,7 @@ module = self.import_extension('foo', [ ("defenc", "METH_NOARGS", """ - return PyString_FromString(Py_FileSystemDefaultEncoding); + return PyUnicode_FromString(Py_FileSystemDefaultEncoding); """), ]) assert module.defenc() == sys.getfilesystemencoding() 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 @@ -135,6 +135,12 @@ "<method 'copy' of 'foo' objects>") raises(TypeError, descr, None) + def test_cython_fake_classmethod(self): + module = self.import_module(name='foo') + print(module.fooType.fake_classmeth) + print(type(module.fooType.fake_classmeth)) + assert module.fooType.fake_classmeth() is module.fooType + def test_new(self): # XXX cpython segfaults but if run singly (with -k test_new) this passes module = self.import_module(name='foo') @@ -1315,6 +1321,47 @@ assert Asize == Bsize assert Asize > basesize + def test_multiple_inheritance_bug1(self): + module = self.import_extension('foo', [ + ("get_type", "METH_NOARGS", + ''' + Py_INCREF(&Foo_Type); + return (PyObject *)&Foo_Type; + ''' + ), ("forty_two", "METH_O", + ''' + return PyLong_FromLong(42); + ''' + )], prologue=''' + static PyTypeObject Foo_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "foo.foo", + }; + static PyObject *dummy_new(PyTypeObject *t, PyObject *a, + PyObject *k) + { + abort(); /* never actually called in CPython */ + } + ''', more_init = ''' + Foo_Type.tp_base = (PyTypeObject *)PyExc_Exception; + Foo_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; + Foo_Type.tp_new = dummy_new; + if (PyType_Ready(&Foo_Type) < 0) INITERROR; + ''') + Foo = module.get_type() + class A(Foo, SyntaxError): + pass + assert A.__base__ is SyntaxError + A(42) # assert is not aborting + + class Bar(Exception): + __new__ = module.forty_two + + class B(Bar, SyntaxError): + pass + + assert B() == 42 + class AppTestHashable(AppTestCpythonExtensionBase): def test_unhashable(self): 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 @@ -12,7 +12,7 @@ from pypy.module.cpyext.api import ( cpython_api, cpython_struct, bootstrap_function, Py_ssize_t, slot_function, generic_cpy_call, METH_VARARGS, METH_KEYWORDS, CANNOT_FAIL, - build_type_checkers_flags, cts, parse_dir, PyObjectFields, PyTypeObject, + build_type_checkers_flags, cts, parse_dir, PyTypeObject, PyTypeObjectPtr, Py_buffer, Py_TPFLAGS_HEAPTYPE, Py_TPFLAGS_READY, Py_TPFLAGS_READYING, Py_TPFLAGS_LONG_SUBCLASS, Py_TPFLAGS_LIST_SUBCLASS, @@ -39,12 +39,14 @@ from pypy.objspace.std.typeobject import W_TypeObject, find_best_base + #WARN_ABOUT_MISSING_SLOT_FUNCTIONS = False PyType_Check, PyType_CheckExact = build_type_checkers_flags("Type") PyHeapTypeObject = cts.gettype('PyHeapTypeObject *') +cts.parse_header(parse_dir / "cpyext_descrobject.h") cts.parse_header(parse_dir / "typeslots.h") @@ -115,57 +117,24 @@ ) assert not W_MemberDescr.typedef.acceptable_as_base_class # no __new__ -PyDescrObject = lltype.ForwardReference() -PyDescrObjectPtr = lltype.Ptr(PyDescrObject) -PyDescrObjectFields = PyObjectFields + ( - ("d_type", PyTypeObjectPtr), - ("d_name", PyObject), - ) -cpython_struct("PyDescrObject", PyDescrObjectFields, - PyDescrObject) - -PyMemberDescrObjectStruct = lltype.ForwardReference() -PyMemberDescrObject = lltype.Ptr(PyMemberDescrObjectStruct) -PyMemberDescrObjectFields = PyDescrObjectFields + ( - ("d_member", lltype.Ptr(PyMemberDef)), - ) -cpython_struct("PyMemberDescrObject", PyMemberDescrObjectFields, - PyMemberDescrObjectStruct, level=2) - -PyGetSetDescrObjectStruct = lltype.ForwardReference() -PyGetSetDescrObject = lltype.Ptr(PyGetSetDescrObjectStruct) -PyGetSetDescrObjectFields = PyDescrObjectFields + ( - ("d_getset", lltype.Ptr(PyGetSetDef)), - ) -cpython_struct("PyGetSetDescrObject", PyGetSetDescrObjectFields, - PyGetSetDescrObjectStruct, level=2) - -PyMethodDescrObjectStruct = lltype.ForwardReference() -PyMethodDescrObject = lltype.Ptr(PyMethodDescrObjectStruct) -PyMethodDescrObjectFields = PyDescrObjectFields + ( - ("d_method", lltype.Ptr(PyMethodDef)), - ) -cpython_struct("PyMethodDescrObject", PyMethodDescrObjectFields, - PyMethodDescrObjectStruct, level=2) - @bootstrap_function def init_memberdescrobject(space): make_typedescr(W_MemberDescr.typedef, - basestruct=PyMemberDescrObject.TO, + basestruct=cts.gettype('PyMemberDescrObject'), attach=memberdescr_attach, realize=memberdescr_realize, ) make_typedescr(W_GetSetPropertyEx.typedef, - basestruct=PyGetSetDescrObject.TO, + basestruct=cts.gettype('PyGetSetDescrObject'), attach=getsetdescr_attach, ) make_typedescr(W_PyCClassMethodObject.typedef, - basestruct=PyMethodDescrObject.TO, + basestruct=cts.gettype('PyMethodDescrObject'), attach=methoddescr_attach, realize=classmethoddescr_realize, ) make_typedescr(W_PyCMethodObject.typedef, - basestruct=PyMethodDescrObject.TO, + basestruct=cts.gettype('PyMethodDescrObject'), attach=methoddescr_attach, realize=methoddescr_realize, ) @@ -175,7 +144,7 @@ Fills a newly allocated PyMemberDescrObject with the given W_MemberDescr object. The values must not be modified. """ - py_memberdescr = rffi.cast(PyMemberDescrObject, py_obj) + py_memberdescr = cts.cast('PyMemberDescrObject*', py_obj) # XXX assign to d_dname, d_type? assert isinstance(w_obj, W_MemberDescr) py_memberdescr.c_d_member = w_obj.member @@ -194,7 +163,7 @@ Fills a newly allocated PyGetSetDescrObject with the given W_GetSetPropertyEx object. The values must not be modified. """ - py_getsetdescr = rffi.cast(PyGetSetDescrObject, py_obj) + py_getsetdescr = cts.cast('PyGetSetDescrObject*', py_obj) if isinstance(w_obj, GetSetProperty): py_getsetdef = make_GetSet(space, w_obj) assert space.isinstance_w(w_userdata, space.w_type) @@ -206,7 +175,7 @@ py_getsetdescr.c_d_getset = w_obj.getset def methoddescr_attach(space, py_obj, w_obj, w_userdata=None): - py_methoddescr = rffi.cast(PyMethodDescrObject, py_obj) + py_methoddescr = cts.cast('PyMethodDescrObject*', py_obj) # XXX assign to d_dname, d_type? assert isinstance(w_obj, W_PyCFunctionObject) py_methoddescr.c_d_method = w_obj.ml @@ -426,6 +395,9 @@ ptr = get_new_method_def(space) ptr.c_ml_meth = rffi.cast(PyCFunction, llslot(space, tp_new_wrapper)) +def is_tp_new_wrapper(space, ml): + return ml.c_ml_meth == rffi.cast(PyCFunction, llslot(space, tp_new_wrapper)) + def add_tp_new_wrapper(space, dict_w, pto): if "__new__" in dict_w: return 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 @@ -641,6 +641,12 @@ if w_newdescr is None: # see test_crash_mro_without_object_1 raise oefmt(space.w_TypeError, "cannot create '%N' instances", self) + # + # issue #2666 + if space.config.objspace.usemodules.cpyext: + w_newtype, w_newdescr = self.hack_which_new_to_call( + w_newtype, w_newdescr) + # w_newfunc = space.get(w_newdescr, space.w_None, w_type=self) if (space.config.objspace.std.newshortcut and not we_are_jitted() and @@ -661,6 +667,30 @@ "__init__() should return None") return w_newobject + def hack_which_new_to_call(self, w_newtype, w_newdescr): + # issue #2666: for cpyext, we need to hack in order to reproduce + # an "optimization" of CPython that actually changes behaviour + # in corner cases. + # + # * Normally, we use the __new__ found in the MRO in the normal way. + # + # * If by chance this __new__ happens to be implemented as a C + # function, then instead, we discard it and use directly + # self.__base__.tp_new. + # + # * Most of the time this is the same (and faster for CPython), but + # it can fail if self.__base__ happens not to be the first base. + # + from pypy.module.cpyext.methodobject import W_PyCFunctionObject + from pypy.module.cpyext.typeobject import is_tp_new_wrapper + + if (isinstance(w_newdescr, W_PyCFunctionObject) and + is_tp_new_wrapper(self.space, w_newdescr.ml)): + w_bestbase = find_best_base(self.bases_w) + return w_bestbase.lookup_where('__new__') + else: + return w_newtype, w_newdescr + def descr_repr(self, space): w_mod = self.get_module() if w_mod is None or not space.isinstance_w(w_mod, space.w_text): diff --git a/pypy/pytest-A.cfg b/pypy/pytest-A.cfg --- a/pypy/pytest-A.cfg +++ b/pypy/pytest-A.cfg @@ -1,5 +1,8 @@ +import sys cherrypick = ['interpreter', 'objspace/test', 'objspace/std', 'module'] interp = ['python'] -test_driver = ['test_all.py', '-A', '--python=goal/pypy3-c'] - +if sys.platform == 'win32': + test_driver = ['test_all.py', '-A', '--python=goal/pypy3-cw.exe'] +else: + test_driver = ['test_all.py', '-A', '--python=goal/pypy3-c'] _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit