Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions include/pybind11/cast.h
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,8 @@ class type_caster_generic {
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;
}
Expand Down Expand Up @@ -978,6 +980,8 @@ struct copyable_holder_caster : public type_caster_base<type> {
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;
}
Expand Down
7 changes: 5 additions & 2 deletions include/pybind11/functional.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
12 changes: 12 additions & 0 deletions tests/test_python_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,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");
Expand Down
14 changes: 14 additions & 0 deletions tests/test_python_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -549,8 +549,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
Expand Down