Compare commits

...

2 Commits

Author SHA1 Message Date
Ralf W. Grosse-Kunstleve b516c19e2f
Merge bb02ebc654 into 5efc7439d4 2024-09-10 14:26:57 +02:00
Ralf W. Grosse-Kunstleve bb02ebc654 Backport of https://github.com/google/pywrapcc/pull/30064
This is a very simple change in support of the PyCLIF-pybind11 integration work:

Merely an extra `if` to pre-empt `TypeError: pybind11::init(): factory function returned nullptr`. This allows the factory function to set a custom Python error instead.

Manually written factory functions could `throw error_already_set()` directly, but in the context of PyCLIF that is very difficult (compared to this very simple PR), because the factory function can be completely unaware of pybind11.
2023-09-12 16:46:00 -07:00
3 changed files with 20 additions and 0 deletions

View File

@ -38,6 +38,9 @@ PYBIND11_NAMESPACE_BEGIN(initimpl)
inline void no_nullptr(void *ptr) {
if (!ptr) {
if (PyErr_Occurred()) {
throw error_already_set();
}
throw type_error("pybind11::init(): factory function returned nullptr");
}
}

View File

@ -412,6 +412,16 @@ TEST_SUBMODULE(factory_constructors, m) {
"__init__", [](NoisyAlloc &a, int i, const std::string &) { new (&a) NoisyAlloc(i); });
});
struct FactoryErrorAlreadySet {};
py::class_<FactoryErrorAlreadySet>(m, "FactoryErrorAlreadySet")
.def(py::init([](bool set_error) -> FactoryErrorAlreadySet * {
if (!set_error) {
return new FactoryErrorAlreadySet();
}
py::set_error(PyExc_ValueError, "factory sets error and returns nullptr");
return nullptr;
}));
// static_assert testing (the following def's should all fail with appropriate compilation
// errors):
#if 0

View File

@ -516,3 +516,10 @@ def test_invalid_self():
str(excinfo.value)
== "__init__(self, ...) called with invalid or missing `self` argument"
)
def test_factory_error_already_set():
obj = m.FactoryErrorAlreadySet(False)
assert isinstance(obj, m.FactoryErrorAlreadySet)
with pytest.raises(ValueError, match="factory sets error and returns nullptr"):
m.FactoryErrorAlreadySet(True)