From b5ac95e1c6d2c93b7f314d79d0933bbaefad0bcf Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Tue, 22 Nov 2016 15:59:59 +0100 Subject: [PATCH] WIP: PyPy support This commit includes a few minor modifications to pybind11 that are needed to get simple hello-world style functions to compile and run on the latest PyPy. Sadly, more complex things are still broken: for instance, creating new types fails with the error message 'TypeError: can't set attributes on type object <..>' when pybind11 tries to set the __module__ attribute. Digging into the pip codebase indicates that it believes that the underlying type is not a heap type, which is incorrect. So this is likely a PyPy bug. --- include/pybind11/cast.h | 18 +++++++++++------- include/pybind11/pybind11.h | 18 ++++++++++++++---- include/pybind11/pytypes.h | 4 ++++ 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index a4e47d38f6..a5cf39f075 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -136,6 +136,7 @@ PYBIND11_NOINLINE inline std::string error_string() { PyErr_NormalizeException(&scope.type, &scope.value, &scope.trace); +#if !defined(PYPY_VERSION) if (scope.trace) { PyFrameObject *frame = ((PyTracebackObject *) scope.trace)->tb_frame; if (frame) { @@ -150,6 +151,7 @@ PYBIND11_NOINLINE inline std::string error_string() { } } } +#endif return errorString; } @@ -166,7 +168,9 @@ PYBIND11_NOINLINE inline handle get_object_handle(const void *ptr, const detail: } inline PyThreadState *get_thread_state_unchecked() { -#if PY_VERSION_HEX < 0x03000000 +#if defined(PYPY_VERSION) + return PyThreadState_GET(); +#elif PY_VERSION_HEX < 0x03000000 return _PyThreadState_Current; #elif PY_VERSION_HEX < 0x03050000 return (PyThreadState*) _Py_atomic_load_relaxed(&_PyThreadState_Current); @@ -214,7 +218,7 @@ class type_caster_generic { /* If this is a python class, also check the parents recursively */ auto const &type_dict = get_internals().registered_types_py; - bool new_style_class = PyType_Check(tobj); + bool new_style_class = PyType_Check((PyObject *) tobj); if (type_dict.find(tobj) == type_dict.end() && new_style_class && tobj->tp_bases) { auto parents = reinterpret_borrow(tobj->tp_bases); for (handle parent : parents) { @@ -644,10 +648,10 @@ template <> class type_caster { #if PY_MAJOR_VERSION >= 3 buffer = PyUnicode_AsWideCharString(load_src.ptr(), &length); #else - temp = reinterpret_steal( - sizeof(wchar_t) == sizeof(short) - ? PyUnicode_AsUTF16String(load_src.ptr()) - : PyUnicode_AsUTF32String(load_src.ptr())); + temp = reinterpret_steal(PyUnicode_AsEncodedString( + load_src.ptr(), sizeof(wchar_t) == sizeof(short) + ? "utf16" : "utf32", nullptr)); + if (temp) { int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), (char **) &buffer, &length); if (err == -1) { buffer = nullptr; } // TypeError @@ -901,7 +905,7 @@ template class type_caster_holder : public /* If this is a python class, also check the parents recursively */ auto const &type_dict = get_internals().registered_types_py; - bool new_style_class = PyType_Check(tobj); + bool new_style_class = PyType_Check((PyObject *) tobj); if (type_dict.find(tobj) == type_dict.end() && new_style_class && tobj->tp_bases) { auto parents = reinterpret_borrow(tobj->tp_bases); for (handle parent : parents) { diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index b7d75d9814..e8aaf4db7c 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -261,7 +261,7 @@ class cpp_function : public function { detail::function_record *chain = nullptr, *chain_start = rec; if (rec->sibling) { if (PyCFunction_Check(rec->sibling.ptr())) { - auto rec_capsule = reinterpret_borrow(PyCFunction_GetSelf(rec->sibling.ptr())); + auto rec_capsule = reinterpret_borrow(PyCFunction_GET_SELF(rec->sibling.ptr())); chain = (detail::function_record *) rec_capsule; /* Never append a method to an overload chain of a parent class; instead, hide the parent's overloads in this case */ @@ -1183,7 +1183,7 @@ class class_ : public detail::generic_type { static detail::function_record *get_function_record(handle h) { h = detail::get_function(h); - return h ? (detail::function_record *) reinterpret_borrow(PyCFunction_GetSelf(h.ptr())) + return h ? (detail::function_record *) reinterpret_borrow(PyCFunction_GET_SELF(h.ptr())) : nullptr; } }; @@ -1519,7 +1519,7 @@ void print(Args &&...args) { detail::print(c.args(), c.kwargs()); } -#if defined(WITH_THREAD) +#if defined(WITH_THREAD) && !defined(PYPY_VERSION) /* The functions below essentially reproduce the PyGILState_* API using a RAII * pattern, but there are a few important differences: @@ -1647,6 +1647,12 @@ class gil_scoped_acquire { }; class gil_scoped_release { }; #endif +#if defined(PYPY_VERSION) +inline bool PyWeakref_Check(PyObject *obj) { + return module::import("weakref").attr("ref").ptr() == obj; +} +#endif + inline function get_type_overload(const void *this_ptr, const detail::type_info *this_type, const char *name) { handle py_object = detail::get_object_handle(this_ptr, this_type); if (!py_object) @@ -1666,7 +1672,9 @@ inline function get_type_overload(const void *this_ptr, const detail::type_info return function(); } - /* Don't call dispatch code if invoked from overridden function */ + /* Don't call dispatch code if invoked from overridden function. + Unfortunately this doesn't work on PyPy. */ +#if !defined(PYPY_VERSION) PyFrameObject *frame = PyThreadState_Get()->frame; if (frame && (std::string) str(frame->f_code->co_name) == name && frame->f_code->co_argcount > 0) { @@ -1676,6 +1684,8 @@ inline function get_type_overload(const void *this_ptr, const detail::type_info if (self_caller == py_object.ptr()) return function(); } +#endif + return overload; } diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index d078d58e0b..4aa999b48d 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -678,6 +678,10 @@ class float_ : public object { operator double() const { return (double) PyFloat_AsDouble(m_ptr); } }; +#if defined(PYPY_VERSION) +inline bool PyWeakref_Check(PyObject *obj); +#endif + class weakref : public object { public: PYBIND11_OBJECT_DEFAULT(weakref, object, PyWeakref_Check)