mirror of
https://github.com/pybind/pybind11.git
synced 2025-01-31 07:10:30 +00:00
Defer None loading to second pass
Many of our `is_none()` checks in type caster loading return true, but this should really be considered a deferral so that, for example, an overload with a `py::none` argument would win over one that takes `py::none` as a null option. This keeps None-accepting for the `!convert` pass only for std::optional and void casters. (The `char` caster already deferred None; this just extends that behaviour to other casters).
This commit is contained in:
parent
7fb01ecd9c
commit
93e3eac6f9
@ -218,6 +218,8 @@ public:
|
||||
if (!src || !typeinfo)
|
||||
return false;
|
||||
if (src.is_none()) {
|
||||
// Defer accepting None to other overloads (if we aren't in convert mode):
|
||||
if (!convert) return false;
|
||||
value = nullptr;
|
||||
return true;
|
||||
}
|
||||
@ -982,6 +984,8 @@ public:
|
||||
if (!src || !typeinfo)
|
||||
return false;
|
||||
if (src.is_none()) {
|
||||
// Defer accepting None to other overloads (if we aren't in convert mode):
|
||||
if (!convert) return false;
|
||||
value = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
@ -22,9 +22,12 @@ struct type_caster<std::function<Return(Args...)>> {
|
||||
using function_type = Return (*) (Args...);
|
||||
|
||||
public:
|
||||
bool load(handle src, bool) {
|
||||
if (src.is_none())
|
||||
bool load(handle src, bool convert) {
|
||||
if (src.is_none()) {
|
||||
// Defer accepting None to other overloads (if we aren't in convert mode):
|
||||
if (!convert) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!isinstance<function>(src))
|
||||
return false;
|
||||
|
@ -500,6 +500,18 @@ test_initializer python_types([](py::module &m) {
|
||||
m.def("return_none_int", []() -> int * { return nullptr; });
|
||||
m.def("return_none_float", []() -> float * { return nullptr; });
|
||||
|
||||
m.def("defer_none_cstring", [](char *) { return false; });
|
||||
m.def("defer_none_cstring", [](py::none) { return true; });
|
||||
m.def("defer_none_custom", [](ExamplePythonTypes *) { return false; });
|
||||
m.def("defer_none_custom", [](py::none) { return true; });
|
||||
// void and optional, however, don't defer:
|
||||
m.def("nodefer_none_void", [](void *) { return true; });
|
||||
m.def("nodefer_none_void", [](py::none) { return false; });
|
||||
#ifdef PYBIND11_HAS_OPTIONAL
|
||||
m.def("nodefer_none_optional", [](std::optional<int>) { return true; });
|
||||
m.def("nodefer_none_optional", [](py::none) { return false; });
|
||||
#endif
|
||||
|
||||
m.def("return_capsule_with_destructor",
|
||||
[]() {
|
||||
py::print("creating capsule");
|
||||
|
@ -550,8 +550,22 @@ def test_builtins_cast_return_none():
|
||||
assert m.return_none_float() is None
|
||||
|
||||
|
||||
def test_none_deferred():
|
||||
"""None passed as various argument types should defer to other overloads"""
|
||||
import pybind11_tests as m
|
||||
|
||||
assert not m.defer_none_cstring("abc")
|
||||
assert m.defer_none_cstring(None)
|
||||
assert not m.defer_none_custom(m.ExamplePythonTypes.new_instance())
|
||||
assert m.defer_none_custom(None)
|
||||
assert m.nodefer_none_void(None)
|
||||
if has_optional:
|
||||
assert m.nodefer_none_optional(None)
|
||||
|
||||
|
||||
def test_capsule_with_destructor(capture):
|
||||
import pybind11_tests as m
|
||||
pytest.gc_collect()
|
||||
with capture:
|
||||
a = m.return_capsule_with_destructor()
|
||||
del a
|
||||
|
Loading…
Reference in New Issue
Block a user