Allow kw-only args after a py::args#3402
Conversation
This simplifies tracking the number of kw-only args by instead tracking the number of positional arguments (which is really what we care about everywhere this is used).
22c4fe0 to
751f176
Compare
This removes the constraint that py::args has to be last (or
second-last, with py::kwargs) and instead makes py::args imply
py::kw_only for any remaining arguments, allowing you to bind a function
that works the same way as a Python function such as:
def f(a, *args, b):
return a * b + sum(args)
f(10, 1, 2, 3, b=20) # == 206
With this change, you can bind such a function using:
m.def("f", [](int a, py::args args, int b) { /* ... */ },
"a"_a, "b"_a);
Or, to be more explicit about the keyword-only arguments:
m.def("g", [](int a, py::args args, int b) { /* ... */ },
"a"_a, py::kw_only{}, "b"_a);
(The only difference between the two is that the latter will fail at
binding time if the `kw_only{}` doesn't match the `py::args` position).
This doesn't affect backwards compatibility at all because, currently,
you can't have a py::args anywhere except the end/2nd-last.
751f176 to
bf1c991
Compare
| m.def("mixed_plus_args_kwargs_defaults", mixed_plus_both, | ||
| py::arg("i") = 1, py::arg("j") = 3.14159); | ||
|
|
||
| m.def("args_kwonly", |
There was a problem hiding this comment.
These tests should all pass py::args and py::kwargs by ref through the lambda since they are not trivially copyable. (This is the clang-tidy rule that fails).
|
Let's try to get the last few fixes in to 2.8.1, then merge this (also okay to branch, but since we are very close to a patch release, a few day delay is probably fine). Other than the tiny test fix, this sounds like a great idea. |
Co-authored-by: Henry Schreiner <HenrySchreinerIII@gmail.com>
|
It surprises me that py::args is not trivially copyable. |
|
|
|
Thanks for doing this! It was something I thought about briefly when adding You've mixed MD and RST syntax in the changelog entry above. ;) I think we need to bite the bullet and make the switch to MD for the changelog. Soon. |
Though considering that in order to touch any of this you have to hold the GIL, and thus the reference count doesn't even have to be atomic, it's fairly "trivial" in practice, just not in the C++ sense of the word. |
|
Just a quick note at the moment (I need to find time to debug): I'm seeing test breakages in Google's global testing that may be related to this PR. https://github.com/google/tensorstore |
|
Here's where the defs are: https://github.com/google/tensorstore/blob/1a59fcb310bc1feb13569f03f7134b4c3a5fa5f4/python/tensorstore/index_space.cc#L823 My guess is the logic for computing these is off (the |
|
Hi @jagerman, do you think you'll have time to look into this soon? As-is, I'm blocked from updating pybind11 for Google-internal use (smart_holder branch), which could turn into a secondary problem for OpenSpiel, which is using the smart_holder branch internally and externally. |
Description
This removes the constraint that
py::argshas to be last (or second-last, withpy::kwargs) and instead makespy::argsimplypy::kw_onlyfor any remaining arguments, allowing you to bind a function that works the same way as a Python function such as:With this PR you can now bind such a function using pybind11:
Or, to be more explicit about the keyword-only arguments:
The only difference between the two is that the latter will fail at binding time if the
py::kw_only{}position doesn't match the relative position of thepy::argsargument.(This doesn't affect backwards compatibility at all because, currently, you can't have a
py::argsanywhere except the end/2nd-last.)Suggested changelog entry: