mirror of
https://github.com/RYDE-WORK/pybind11.git
synced 2026-02-05 23:13:36 +08: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)
|
if (!src || !typeinfo)
|
||||||
return false;
|
return false;
|
||||||
if (src.is_none()) {
|
if (src.is_none()) {
|
||||||
|
// Defer accepting None to other overloads (if we aren't in convert mode):
|
||||||
|
if (!convert) return false;
|
||||||
value = nullptr;
|
value = nullptr;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -982,6 +984,8 @@ public:
|
|||||||
if (!src || !typeinfo)
|
if (!src || !typeinfo)
|
||||||
return false;
|
return false;
|
||||||
if (src.is_none()) {
|
if (src.is_none()) {
|
||||||
|
// Defer accepting None to other overloads (if we aren't in convert mode):
|
||||||
|
if (!convert) return false;
|
||||||
value = nullptr;
|
value = nullptr;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,9 +22,12 @@ struct type_caster<std::function<Return(Args...)>> {
|
|||||||
using function_type = Return (*) (Args...);
|
using function_type = Return (*) (Args...);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool load(handle src, bool) {
|
bool load(handle src, bool convert) {
|
||||||
if (src.is_none())
|
if (src.is_none()) {
|
||||||
|
// Defer accepting None to other overloads (if we aren't in convert mode):
|
||||||
|
if (!convert) return false;
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!isinstance<function>(src))
|
if (!isinstance<function>(src))
|
||||||
return false;
|
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_int", []() -> int * { return nullptr; });
|
||||||
m.def("return_none_float", []() -> float * { 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",
|
m.def("return_capsule_with_destructor",
|
||||||
[]() {
|
[]() {
|
||||||
py::print("creating capsule");
|
py::print("creating capsule");
|
||||||
|
|||||||
@ -550,8 +550,22 @@ def test_builtins_cast_return_none():
|
|||||||
assert m.return_none_float() is 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):
|
def test_capsule_with_destructor(capture):
|
||||||
import pybind11_tests as m
|
import pybind11_tests as m
|
||||||
|
pytest.gc_collect()
|
||||||
with capture:
|
with capture:
|
||||||
a = m.return_capsule_with_destructor()
|
a = m.return_capsule_with_destructor()
|
||||||
del a
|
del a
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user