-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Add support for non-converting arguments #634
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
I had the same thoughts recently, see #338 (comment) Basically, we need to be able to accept "lvalues" (e.g. NumPy arrays that are to mutated in place), which is something that's not possible with auto conversion. Will read this in more detail and reply tomorrow :) |
Yeah, your #338 comments were part of the reason to do this globally rather than just the Eigen hack. |
template <typename T> | ||
arg_v(const char *name, T &&x, const char *descr = nullptr) | ||
: arg(name), | ||
arg_v(arg &&base, T &&x, const char *descr = nullptr) |
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.
I didn't understand this change -- why the rvalue?
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.
It was to potentially avoid a copy--that's now just a private constructor with the common code, invoked with an rvalue arg
from the direct (first public) or converted-from-arg (second public) constructors.
I think this is a great API -- it's simple to use and leads to nice and readable binding code. Questions from my end would be:
|
That depends a lot on the future, I guess. I toyed with a change to pass a custom argument info struct into load (with some clever detection of whether a type_caster has a
I measured this, and meant to include it in the PR message (but apparently forgot). Commenting out the added tests, the .so increase (under gcc) is pretty small:
|
cc304f6
to
f5b3697
Compare
One other thing that I had in mind when writing this PR (but that belongs in a future PR) is that it makes it reasonably easy to implement a two-pass function call procedure, where we first try to call the function with |
f5b3697
to
d63633f
Compare
Arithmetic and complex casters now only do a converting cast when `convert=true`; previously they would convert always (e.g. when passing an int to a float-accepting function, or a float to complex-accepting function).
This adds support for controlling the `convert` flag of arguments through the py::arg annotation. This then allows arguments to be flagged as non-converting, which the type_caster is able to use to request different behaviour. Currently, AFAICS `convert` is only used for type converters of regular pybind11-registered types; all of the other core type_casters ignore it. We can, however, repurpose it to control internal conversion of converters like Eigen and `array`: most usefully to give callers a way to disable the conversion that would otherwise occur when a `Eigen::Ref<const Eigen::Matrix>` argument is passed a numpy array that requires conversion (either because it has an incompatible stride or the wrong dtype). Specifying a noconvert looks like one of these: m.def("f1", &f, "a"_a.noconvert() = "default"); // Named, default, noconvert m.def("f2", &f, "a"_a.noconvert()); // Named, no default, no converting m.def("f3", &f, py::arg().noconvert()); // Unnamed, no default, no converting (The last part--being able to declare a py::arg without a name--is new: previous py::arg() only accepted named keyword arguments). Such an non-convert argument is then passed `convert = false` by the type caster when loading the argument. Whether this has an effect is up to the type caster itself, but as mentioned above, this would be extremely helpful for the Eigen support to give a nicer way to specify a "no-copy" mode than the custom wrapper in the current PR, and moreover isn't an Eigen-specific hack.
82c9e66
to
abc29ca
Compare
Merged! |
This adds no-convert support to the Eigen code via the new `py::arg().noconvert()` support added in PR pybind#634. `Eigen::Ref<const M>` arguments bound with `.noconvert()` won't be copied. (`Eigen::Ref<M>` for non-const `M` continue to never allow copying).
With PR pybind#634, `py::arg` instances don't necessarily have a name, but the debugging output for failed casting of defaults was using `a.name`. This fixes it to substitute "arg" if the argument doesn't have a name of its own.
This fixes a couple bugs with nameless py::arg() (introduced in pybind#634) annotations: - the argument name was being used in debug mode without checking that it exists (which would result in the std::string construction throwing an exception for being invoked with a nullptr) - the error output says "keyword arguments", but py::arg_v() can now also be used for positional argument defaults. - the debugging output "in function named 'blah'" was overly verbose: changed it to just "in function 'blah'".
This fixes a couple bugs with nameless py::arg() (introduced in pybind#634) annotations: - the argument name was being used in debug mode without checking that it exists (which would result in the std::string construction throwing an exception for being invoked with a nullptr) - the error output says "keyword arguments", but py::arg_v() can now also be used for positional argument defaults. - the debugging output "in function named 'blah'" was overly verbose: changed it to just "in function 'blah'".
* Fix debugging output for nameless py::arg annotations This fixes a couple bugs with nameless py::arg() (introduced in #634) annotations: - the argument name was being used in debug mode without checking that it exists (which would result in the std::string construction throwing an exception for being invoked with a nullptr) - the error output says "keyword arguments", but py::arg_v() can now also be used for positional argument defaults. - the debugging output "in function named 'blah'" was overly verbose: changed it to just "in function 'blah'". * Fix missing space in debug test string * Moved tests from issues to methods_and_attributes
This commit largely rewrites the Eigen dense matrix support to avoid copying in many cases: Eigen arguments can now reference numpy data, and numpy objects can now reference Eigen data (given compatible types). Eigen::Ref<...> arguments now also make use of the new `convert` argument use (added in PR pybind#634) to avoid conversion, allowing `py::arg().noconvert()` to be used when binding a function to prohibit copying when invoking the function. Respecting `convert` also means Eigen overloads that avoid copying will be preferred during overload resolution to ones that require copying. This commit also rewrites the Eigen documentation and test suite to explain and test the new capabilities.
This commit largely rewrites the Eigen dense matrix support to avoid copying in many cases: Eigen arguments can now reference numpy data, and numpy objects can now reference Eigen data (given compatible types). Eigen::Ref<...> arguments now also make use of the new `convert` argument use (added in PR pybind#634) to avoid conversion, allowing `py::arg().noconvert()` to be used when binding a function to prohibit copying when invoking the function. Respecting `convert` also means Eigen overloads that avoid copying will be preferred during overload resolution to ones that require copying. This commit also rewrites the Eigen documentation and test suite to explain and test the new capabilities.
This commit largely rewrites the Eigen dense matrix support to avoid copying in many cases: Eigen arguments can now reference numpy data, and numpy objects can now reference Eigen data (given compatible types). Eigen::Ref<...> arguments now also make use of the new `convert` argument use (added in PR #634) to avoid conversion, allowing `py::arg().noconvert()` to be used when binding a function to prohibit copying when invoking the function. Respecting `convert` also means Eigen overloads that avoid copying will be preferred during overload resolution to ones that require copying. This commit also rewrites the Eigen documentation and test suite to explain and test the new capabilities.
This adds support for controlling the
convert
flag of arguments through thepy::arg
annotation. This then allows arguments to be flagged as non-converting, which thetype_caster<X>
is able to use to implement different behaviour.Currently, as far as I can see,
convert
is only used for type converters of regular pybind11-registered types (to prevent implicit conversions from recursing); all of the other core type_casters just ignore the argument. We can, however, repurpose it to control internal conversion of converters like Eigen andarray
: most usefully to give callers a way to disable the conversion that would otherwise occur when aEigen::Ref<const Eigen::Matrix>
argument is passed a numpy array that requires conversion (either because it has an incompatible stride or the wrong dtype).Specifying a
noconvert
argument looks like one of these:(The last one—being able to declare a py::arg without a name—is new: previously
py::arg()
only accepted named keyword arguments).Such an non-convert argument is then passed
convert = false
by the type caster when loading the argument. Whether this has an effect is up to the type caster itself, but as mentioned above, this would be extremely helpful for the Eigen support to give a nicer way to specify a "no-copy" mode than the custom wrapper in the current PR, and moreover isn't an Eigen-specific hack.The relevant bit of the internal Eigen type caster would then contain something like:
and binding code that wanted to say "do not copy data" would then use:
rather than the current PR's ugly proposal of:
While that workaround works for Eigen, it's not exactly elegant, and I think this no-convert argument could be useful elsewhere, too.
Thoughts/comments/suggestions?