You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The documentation at https://pybind11.readthedocs.io/en/stable/advanced/cast/custom.html suggests that custom type casters do not need to clear any Python exception that may have been set (the implementation of load basically returning !PyErr_Occurred()). Upon first reading, this seems reasonable as pybind11 may perhaps use that info for better error reporting. However, type casters actually need to clear the exception -- at least to make variant loading work.
I don't know if this should be fixed on the docs side, or on the implementation side.
#include<pybind11/pybind11.h>
#include<pybind11/stl.h>structinty { long long_value; };
namespacepybind11 { namespacedetail {
template <> structtype_caster<inty> {
public:/** * This macro establishes the name 'inty' in * function signatures and declares a local variable * 'value' of type inty*/PYBIND11_TYPE_CASTER(inty, _("inty"));
/** * Conversion part 1 (Python->C++): convert a PyObject into a inty * instance or return false upon failure. The second argument * indicates whether implicit conversions should be applied.*/boolload(handle src, bool) {
/* Extract PyObject from handle */
PyObject *source = src.ptr();
/* Try converting into a Python integer value */
PyObject *tmp = PyNumber_Long(source);
if (!tmp) {
returnfalse;
}
/* Now try to convert into a C++ int */
value.long_value = PyLong_AsLong(tmp);
Py_DECREF(tmp);
/* Ensure return code was OK (to avoid out-of-range errors etc) */return !(value.long_value == -1 && !PyErr_Occurred());
}
/** * Conversion part 2 (C++ -> Python): convert an inty instance into * a Python object. The second and third arguments are used to * indicate the return value policy and parent object (for * ``return_value_policy::reference_internal``) and are generally * ignored by implicit casters.*/static handle cast(inty src, return_value_policy /* policy */, handle /* parent */) {
returnPyLong_FromLong(src.long_value);
}
};
}}
PYBIND11_MODULE(python_example, m) {
m.def("get_index", [](std::variant<inty, std::string> v) { return v.index(); });
}
Calling get_index("a") throws
ValueError: invalid literal for int() with base 10: 'a'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<string>", line 1, in <module>
SystemError: <built-in method get_index of PyCapsule object at 0x7fda858a08d0> returned a result with an error set
Fixing the implementation of load to always clear set exceptions instead makes get_index("a") correctly return 1.
The text was updated successfully, but these errors were encountered:
When calling into the raw C API, you're always expected to check for errors as ... well, you've just circumvented pybind11 and called the Python C API.
So the docs are indeed (very) wrong here, I believe. @bstaletic?
Issue description
The documentation at https://pybind11.readthedocs.io/en/stable/advanced/cast/custom.html suggests that custom type casters do not need to clear any Python exception that may have been set (the implementation of
load
basically returning!PyErr_Occurred()
). Upon first reading, this seems reasonable as pybind11 may perhaps use that info for better error reporting. However, type casters actually need to clear the exception -- at least to make variant loading work.I don't know if this should be fixed on the docs side, or on the implementation side.
Reproducible example code
The entire example, except the PYBIND11_MODULE block, is copied verbatim from https://pybind11.readthedocs.io/en/stable/advanced/cast/custom.html.
Calling
get_index("a")
throwsFixing the implementation of
load
to always clear set exceptions instead makesget_index("a")
correctly return 1.The text was updated successfully, but these errors were encountered: