-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Allow kw-only args after a py::args #3402
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
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
@@ -56,6 +56,23 @@ TEST_SUBMODULE(kwargs_and_defaults, m) { | |||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 <[email protected]>
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::args
has to be last (or second-last, withpy::kwargs
) and instead makespy::args
implypy::kw_only
for 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::args
argument.(This doesn't affect backwards compatibility at all because, currently, you can't have a
py::args
anywhere except the end/2nd-last.)Suggested changelog entry: