mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-22 05:05:11 +00:00
fix: Reject keyword argument None
with .none(false)
(#2611)
* demo kwarg with none(false) * Reorder and extend tests for arg::none(false) in test_methods_and_attributes.py::test_accepts_none * Fix arg::none() for keyword arguments * Add changelog note * Fix names of no_none_kw test functions Co-authored-by: Yannick Jadoul <yannick.jadoul@belgacom.net>
This commit is contained in:
parent
7f9445a626
commit
6edd0e6d90
@ -204,6 +204,9 @@ Smaller or developer focused features and fixes:
|
||||
* Avoid a segfault on some compilers when types are removed in Python.
|
||||
`#2564 <https://github.com/pybind/pybind11/pull/2564>`_
|
||||
|
||||
* ``py::arg::none()`` is now also respected when passing keyword arguments.
|
||||
`#2611 <https://github.com/pybind/pybind11/pull/2611>`_
|
||||
|
||||
* PyPy fixes, PyPy 7.3.x now supported, including PyPy3. (Known issue with
|
||||
PyPy2 and Windows `#2596 <https://github.com/pybind/pybind11/issues/2596>`_).
|
||||
`#2146 <https://github.com/pybind/pybind11/pull/2146>`_
|
||||
|
@ -606,15 +606,15 @@ protected:
|
||||
// 1.5. Fill in any missing pos_only args from defaults if they exist
|
||||
if (args_copied < func.nargs_pos_only) {
|
||||
for (; args_copied < func.nargs_pos_only; ++args_copied) {
|
||||
const auto &arg = func.args[args_copied];
|
||||
const auto &arg_rec = func.args[args_copied];
|
||||
handle value;
|
||||
|
||||
if (arg.value) {
|
||||
value = arg.value;
|
||||
if (arg_rec.value) {
|
||||
value = arg_rec.value;
|
||||
}
|
||||
if (value) {
|
||||
call.args.push_back(value);
|
||||
call.args_convert.push_back(arg.convert);
|
||||
call.args_convert.push_back(arg_rec.convert);
|
||||
} else
|
||||
break;
|
||||
}
|
||||
@ -628,11 +628,11 @@ protected:
|
||||
bool copied_kwargs = false;
|
||||
|
||||
for (; args_copied < num_args; ++args_copied) {
|
||||
const auto &arg = func.args[args_copied];
|
||||
const auto &arg_rec = func.args[args_copied];
|
||||
|
||||
handle value;
|
||||
if (kwargs_in && arg.name)
|
||||
value = PyDict_GetItemString(kwargs.ptr(), arg.name);
|
||||
if (kwargs_in && arg_rec.name)
|
||||
value = PyDict_GetItemString(kwargs.ptr(), arg_rec.name);
|
||||
|
||||
if (value) {
|
||||
// Consume a kwargs value
|
||||
@ -640,14 +640,18 @@ protected:
|
||||
kwargs = reinterpret_steal<dict>(PyDict_Copy(kwargs.ptr()));
|
||||
copied_kwargs = true;
|
||||
}
|
||||
PyDict_DelItemString(kwargs.ptr(), arg.name);
|
||||
} else if (arg.value) {
|
||||
value = arg.value;
|
||||
PyDict_DelItemString(kwargs.ptr(), arg_rec.name);
|
||||
} else if (arg_rec.value) {
|
||||
value = arg_rec.value;
|
||||
}
|
||||
|
||||
if (!arg_rec.none && value.is_none()) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (value) {
|
||||
call.args.push_back(value);
|
||||
call.args_convert.push_back(arg.convert);
|
||||
call.args_convert.push_back(arg_rec.convert);
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
@ -336,6 +336,9 @@ TEST_SUBMODULE(methods_and_attributes, m) {
|
||||
m.def("ok_none4", &none4, py::arg().none(true));
|
||||
m.def("ok_none5", &none5);
|
||||
|
||||
m.def("no_none_kwarg", &none2, py::arg("a").none(false));
|
||||
m.def("no_none_kwarg_kw_only", &none2, py::kw_only(), py::arg("a").none(false));
|
||||
|
||||
// test_str_issue
|
||||
// Issue #283: __str__ called on uninitialized instance when constructor arguments invalid
|
||||
py::class_<StrIssue>(m, "StrIssue")
|
||||
|
@ -404,6 +404,19 @@ def test_accepts_none(msg):
|
||||
assert m.ok_none4(None) == -1
|
||||
assert m.ok_none5(None) == -1
|
||||
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
m.no_none_kwarg(None)
|
||||
assert "incompatible function arguments" in str(excinfo.value)
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
m.no_none_kwarg(a=None)
|
||||
assert "incompatible function arguments" in str(excinfo.value)
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
m.no_none_kwarg_kw_only(None)
|
||||
assert "incompatible function arguments" in str(excinfo.value)
|
||||
with pytest.raises(TypeError) as excinfo:
|
||||
m.no_none_kwarg_kw_only(a=None)
|
||||
assert "incompatible function arguments" in str(excinfo.value)
|
||||
|
||||
|
||||
def test_str_issue(msg):
|
||||
"""#283: __str__ called on uninitialized instance when constructor arguments invalid"""
|
||||
|
Loading…
Reference in New Issue
Block a user