diff --git a/docs/advanced/functions.rst b/docs/advanced/functions.rst index c7790533b..984b046ef 100644 --- a/docs/advanced/functions.rst +++ b/docs/advanced/functions.rst @@ -378,14 +378,14 @@ argument in a function definition: f(1, b=2) # good f(1, 2) # TypeError: f() takes 1 positional argument but 2 were given -Pybind11 provides a ``py::args_kw_only`` object that allows you to implement +Pybind11 provides a ``py::kwonly`` object that allows you to implement the same behaviour by specifying the object between positional and keyword-only argument annotations when registering the function: .. code-block:: cpp m.def("f", [](int a, int b) { /* ... */ }, - py::arg("a"), py::args_kw_only(), py::arg("b")); + py::arg("a"), py::kwonly(), py::arg("b")); Note that, as in Python, you cannot combine this with a ``py::args`` argument. This feature does *not* require Python 3 to work. diff --git a/include/pybind11/attr.h b/include/pybind11/attr.h index 70325510d..58390239a 100644 --- a/include/pybind11/attr.h +++ b/include/pybind11/attr.h @@ -138,7 +138,7 @@ struct function_record { function_record() : is_constructor(false), is_new_style_constructor(false), is_stateless(false), is_operator(false), is_method(false), - has_args(false), has_kwargs(false), has_kw_only_args(false) { } + has_args(false), has_kwargs(false), has_kwonly_args(false) { } /// Function name char *name = nullptr; /* why no C++ strings? They generate heavier code.. */ @@ -185,8 +185,8 @@ struct function_record { /// True if the function has a '**kwargs' argument bool has_kwargs : 1; - /// True once a 'py::args_kw_only' is encountered (any following args are keyword-only) - bool has_kw_only_args : 1; + /// True once a 'py::kwonly' is encountered (any following args are keyword-only) + bool has_kwonly_args : 1; /// Number of arguments (including py::args and/or py::kwargs, if present) std::uint16_t nargs; @@ -368,7 +368,7 @@ template <> struct process_attribute : process_attribu inline void process_kwonly_arg(const arg &a, function_record *r) { if (!a.name || strlen(a.name) == 0) - pybind11_fail("arg(): cannot specify an unnamed argument after an args_kw_only() annotation"); + pybind11_fail("arg(): cannot specify an unnamed argument after an kwonly() annotation"); ++r->nargs_kwonly; } @@ -379,7 +379,7 @@ template <> struct process_attribute : process_attribute_default { r->args.emplace_back("self", nullptr, handle(), true /*convert*/, false /*none not allowed*/); r->args.emplace_back(a.name, nullptr, handle(), !a.flag_noconvert, a.flag_none); - if (r->has_kw_only_args) process_kwonly_arg(a, r); + if (r->has_kwonly_args) process_kwonly_arg(a, r); } }; @@ -412,14 +412,14 @@ template <> struct process_attribute : process_attribute_default { } r->args.emplace_back(a.name, a.descr, a.value.inc_ref(), !a.flag_noconvert, a.flag_none); - if (r->has_kw_only_args) process_kwonly_arg(a, r); + if (r->has_kwonly_args) process_kwonly_arg(a, r); } }; /// Process a keyword-only-arguments-follow pseudo argument -template <> struct process_attribute : process_attribute_default { - static void init(const args_kw_only &, function_record *r) { - r->has_kw_only_args = true; +template <> struct process_attribute : process_attribute_default { + static void init(const kwonly &, function_record *r) { + r->has_kwonly_args = true; } }; diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 2ea1c635b..91c9ce753 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -1890,7 +1890,7 @@ public: /// \ingroup annotations /// Annotation indicating that all following arguments are keyword-only; the is the equivalent of an /// unnamed '*' argument (in Python 3) -struct args_kw_only {}; +struct kwonly {}; template arg_v arg::operator=(T &&value) const { return {std::move(*this), std::forward(value)}; } diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index ff586033d..722a19a1a 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -169,11 +169,11 @@ protected: process_attributes::init(extra..., rec); { - constexpr bool has_kw_only_args = any_of...>::value, + constexpr bool has_kwonly_args = any_of...>::value, has_args = any_of...>::value, has_arg_annotations = any_of...>::value; - static_assert(has_arg_annotations || !has_kw_only_args, "py::args_kw_only requires the use of argument annotations"); - static_assert(!(has_args && has_kw_only_args), "py::args_kw_only cannot be combined with a py::args argument"); + static_assert(has_arg_annotations || !has_kwonly_args, "py::kwonly requires the use of argument annotations"); + static_assert(!(has_args && has_kwonly_args), "py::kwonly cannot be combined with a py::args argument"); } /* Generate a readable signature describing the function's arguments and return value types */ diff --git a/tests/test_kwargs_and_defaults.cpp b/tests/test_kwargs_and_defaults.cpp index 6c4971404..8f095fe4a 100644 --- a/tests/test_kwargs_and_defaults.cpp +++ b/tests/test_kwargs_and_defaults.cpp @@ -96,27 +96,27 @@ TEST_SUBMODULE(kwargs_and_defaults, m) { // test_keyword_only_args m.def("kwonly_all", [](int i, int j) { return py::make_tuple(i, j); }, - py::args_kw_only(), py::arg("i"), py::arg("j")); + py::kwonly(), py::arg("i"), py::arg("j")); m.def("kwonly_some", [](int i, int j, int k) { return py::make_tuple(i, j, k); }, - py::arg(), py::args_kw_only(), py::arg("j"), py::arg("k")); + py::arg(), py::kwonly(), py::arg("j"), py::arg("k")); m.def("kwonly_with_defaults", [](int i, int j, int k, int z) { return py::make_tuple(i, j, k, z); }, - py::arg() = 3, "j"_a = 4, py::args_kw_only(), "k"_a = 5, "z"_a); + py::arg() = 3, "j"_a = 4, py::kwonly(), "k"_a = 5, "z"_a); m.def("kwonly_mixed", [](int i, int j) { return py::make_tuple(i, j); }, - "i"_a, py::args_kw_only(), "j"_a); + "i"_a, py::kwonly(), "j"_a); m.def("kwonly_plus_more", [](int i, int j, int k, py::kwargs kwargs) { return py::make_tuple(i, j, k, kwargs); }, - py::arg() /* positional */, py::arg("j") = -1 /* both */, py::args_kw_only(), py::arg("k") /* kw-only */); + py::arg() /* positional */, py::arg("j") = -1 /* both */, py::kwonly(), py::arg("k") /* kw-only */); m.def("register_invalid_kwonly", [](py::module m) { m.def("bad_kwonly", [](int i, int j) { return py::make_tuple(i, j); }, - py::args_kw_only(), py::arg() /* invalid unnamed argument */, "j"_a); + py::kwonly(), py::arg() /* invalid unnamed argument */, "j"_a); }); // These should fail to compile: - // argument annotations are required when using args_kw_only -// m.def("bad_kwonly1", [](int) {}, py::args_kw_only()); - // can't specify both `py::args_kw_only` and a `py::args` argument -// m.def("bad_kwonly2", [](int i, py::args) {}, py::args_kw_only(), "i"_a); + // argument annotations are required when using kwonly +// m.def("bad_kwonly1", [](int) {}, py::kwonly()); + // can't specify both `py::kwonly` and a `py::args` argument +// m.def("bad_kwonly2", [](int i, py::args) {}, py::kwonly(), "i"_a); // test_function_signatures (along with most of the above) struct KWClass { void foo(int, float) {} }; diff --git a/tests/test_kwargs_and_defaults.py b/tests/test_kwargs_and_defaults.py index fa90140fd..bad6636cb 100644 --- a/tests/test_kwargs_and_defaults.py +++ b/tests/test_kwargs_and_defaults.py @@ -141,7 +141,7 @@ def test_keyword_only_args(msg): with pytest.raises(RuntimeError) as excinfo: m.register_invalid_kwonly(m) assert msg(excinfo.value) == """ - arg(): cannot specify an unnamed argument after an args_kw_only() annotation + arg(): cannot specify an unnamed argument after an kwonly() annotation """