Skip to content

Commit b5ac95e

Browse files
committed
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.
1 parent 47681c1 commit b5ac95e

File tree

3 files changed

+29
-11
lines changed

3 files changed

+29
-11
lines changed

include/pybind11/cast.h

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ PYBIND11_NOINLINE inline std::string error_string() {
136136

137137
PyErr_NormalizeException(&scope.type, &scope.value, &scope.trace);
138138

139+
#if !defined(PYPY_VERSION)
139140
if (scope.trace) {
140141
PyFrameObject *frame = ((PyTracebackObject *) scope.trace)->tb_frame;
141142
if (frame) {
@@ -150,6 +151,7 @@ PYBIND11_NOINLINE inline std::string error_string() {
150151
}
151152
}
152153
}
154+
#endif
153155

154156
return errorString;
155157
}
@@ -166,7 +168,9 @@ PYBIND11_NOINLINE inline handle get_object_handle(const void *ptr, const detail:
166168
}
167169

168170
inline PyThreadState *get_thread_state_unchecked() {
169-
#if PY_VERSION_HEX < 0x03000000
171+
#if defined(PYPY_VERSION)
172+
return PyThreadState_GET();
173+
#elif PY_VERSION_HEX < 0x03000000
170174
return _PyThreadState_Current;
171175
#elif PY_VERSION_HEX < 0x03050000
172176
return (PyThreadState*) _Py_atomic_load_relaxed(&_PyThreadState_Current);
@@ -214,7 +218,7 @@ class type_caster_generic {
214218

215219
/* If this is a python class, also check the parents recursively */
216220
auto const &type_dict = get_internals().registered_types_py;
217-
bool new_style_class = PyType_Check(tobj);
221+
bool new_style_class = PyType_Check((PyObject *) tobj);
218222
if (type_dict.find(tobj) == type_dict.end() && new_style_class && tobj->tp_bases) {
219223
auto parents = reinterpret_borrow<tuple>(tobj->tp_bases);
220224
for (handle parent : parents) {
@@ -644,10 +648,10 @@ template <> class type_caster<std::wstring> {
644648
#if PY_MAJOR_VERSION >= 3
645649
buffer = PyUnicode_AsWideCharString(load_src.ptr(), &length);
646650
#else
647-
temp = reinterpret_steal<object>(
648-
sizeof(wchar_t) == sizeof(short)
649-
? PyUnicode_AsUTF16String(load_src.ptr())
650-
: PyUnicode_AsUTF32String(load_src.ptr()));
651+
temp = reinterpret_steal<object>(PyUnicode_AsEncodedString(
652+
load_src.ptr(), sizeof(wchar_t) == sizeof(short)
653+
? "utf16" : "utf32", nullptr));
654+
651655
if (temp) {
652656
int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), (char **) &buffer, &length);
653657
if (err == -1) { buffer = nullptr; } // TypeError
@@ -901,7 +905,7 @@ template <typename type, typename holder_type> class type_caster_holder : public
901905

902906
/* If this is a python class, also check the parents recursively */
903907
auto const &type_dict = get_internals().registered_types_py;
904-
bool new_style_class = PyType_Check(tobj);
908+
bool new_style_class = PyType_Check((PyObject *) tobj);
905909
if (type_dict.find(tobj) == type_dict.end() && new_style_class && tobj->tp_bases) {
906910
auto parents = reinterpret_borrow<tuple>(tobj->tp_bases);
907911
for (handle parent : parents) {

include/pybind11/pybind11.h

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ class cpp_function : public function {
261261
detail::function_record *chain = nullptr, *chain_start = rec;
262262
if (rec->sibling) {
263263
if (PyCFunction_Check(rec->sibling.ptr())) {
264-
auto rec_capsule = reinterpret_borrow<capsule>(PyCFunction_GetSelf(rec->sibling.ptr()));
264+
auto rec_capsule = reinterpret_borrow<capsule>(PyCFunction_GET_SELF(rec->sibling.ptr()));
265265
chain = (detail::function_record *) rec_capsule;
266266
/* Never append a method to an overload chain of a parent class;
267267
instead, hide the parent's overloads in this case */
@@ -1183,7 +1183,7 @@ class class_ : public detail::generic_type {
11831183

11841184
static detail::function_record *get_function_record(handle h) {
11851185
h = detail::get_function(h);
1186-
return h ? (detail::function_record *) reinterpret_borrow<capsule>(PyCFunction_GetSelf(h.ptr()))
1186+
return h ? (detail::function_record *) reinterpret_borrow<capsule>(PyCFunction_GET_SELF(h.ptr()))
11871187
: nullptr;
11881188
}
11891189
};
@@ -1519,7 +1519,7 @@ void print(Args &&...args) {
15191519
detail::print(c.args(), c.kwargs());
15201520
}
15211521

1522-
#if defined(WITH_THREAD)
1522+
#if defined(WITH_THREAD) && !defined(PYPY_VERSION)
15231523

15241524
/* The functions below essentially reproduce the PyGILState_* API using a RAII
15251525
* pattern, but there are a few important differences:
@@ -1647,6 +1647,12 @@ class gil_scoped_acquire { };
16471647
class gil_scoped_release { };
16481648
#endif
16491649

1650+
#if defined(PYPY_VERSION)
1651+
inline bool PyWeakref_Check(PyObject *obj) {
1652+
return module::import("weakref").attr("ref").ptr() == obj;
1653+
}
1654+
#endif
1655+
16501656
inline function get_type_overload(const void *this_ptr, const detail::type_info *this_type, const char *name) {
16511657
handle py_object = detail::get_object_handle(this_ptr, this_type);
16521658
if (!py_object)
@@ -1666,7 +1672,9 @@ inline function get_type_overload(const void *this_ptr, const detail::type_info
16661672
return function();
16671673
}
16681674

1669-
/* Don't call dispatch code if invoked from overridden function */
1675+
/* Don't call dispatch code if invoked from overridden function.
1676+
Unfortunately this doesn't work on PyPy. */
1677+
#if !defined(PYPY_VERSION)
16701678
PyFrameObject *frame = PyThreadState_Get()->frame;
16711679
if (frame && (std::string) str(frame->f_code->co_name) == name &&
16721680
frame->f_code->co_argcount > 0) {
@@ -1676,6 +1684,8 @@ inline function get_type_overload(const void *this_ptr, const detail::type_info
16761684
if (self_caller == py_object.ptr())
16771685
return function();
16781686
}
1687+
#endif
1688+
16791689
return overload;
16801690
}
16811691

include/pybind11/pytypes.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,10 @@ class float_ : public object {
678678
operator double() const { return (double) PyFloat_AsDouble(m_ptr); }
679679
};
680680

681+
#if defined(PYPY_VERSION)
682+
inline bool PyWeakref_Check(PyObject *obj);
683+
#endif
684+
681685
class weakref : public object {
682686
public:
683687
PYBIND11_OBJECT_DEFAULT(weakref, object, PyWeakref_Check)

0 commit comments

Comments
 (0)