-
Notifications
You must be signed in to change notification settings - Fork 770
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
Make #wrap_pyfunction return a Bound value #3808
Conversation
CodSpeed Performance ReportMerging #3808 will degrade performances by 12.82%Comparing Summary
Benchmarks breakdown
|
There might be an option to avoid the breakage for |
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 would definitely be nice to avoid breaking existing calls to add_function
. I wonder if the below idea might work?
@Icxolu The downside I could see to adding some type deduction inside wrap_pyfunction
would be that I think existing assignments like this become ambiguous:
let f = wrap_pyfunction!(...)
Maybe there are breakages caused by what I suggest too?
@@ -348,7 +348,7 @@ impl PyModule { | |||
/// | |||
/// [1]: crate::prelude::pyfunction | |||
/// [2]: crate::wrap_pyfunction | |||
pub fn add_function<'a>(&'a self, fun: &'a PyCFunction) -> PyResult<()> { | |||
pub fn add_function<'a>(&'a self, fun: Bound<'a, PyCFunction>) -> PyResult<()> { |
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.
Maybe here we could just take fun: impl ToPyObject
? That would avoid breaking existing direct calls, and we plan to remove this function anyway.
We could add a note to document the strange generic signature is for backwards compatibility while this API is on its way out.
Might make the implementation a little messier, but I'm sure it could work.
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.
Either way, by changing this function I think we need a 3808.changed.md
newsfragment.
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.
Maybe here we could just take fun: impl ToPyObject? That would avoid breaking existing direct calls, and we plan to remove this function anyway.
impl trait in argument position is a bit of a smell for library API because callers have a hard time defining the implicit type argument (only via casts and and such, potentially requiring a additional closure around the call). But adding a generic argument would strictly speaking not be backwards compatible.
I am not sure yet why we do not just have add_function
and add_function_bound
(or add_bound_function
)?
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.
The main problem is what do to with wrap_pyfunction!
, and whether we want to change it.
At the moment we have:
#[pymodule]
fn my_module(py: Python, m: &PyModule) {
m.add_function(wrap_pyfunction!(foo, m)?)?;
}
If we don't change wrap_pyfunction
, and go for wrap_pyfunction_bound
, then we end up with this:
#[pymodule]
fn my_module(py: Python, m: &Bound<PyModule>) {
m.add_function(wrap_pyfunction_bound!(foo, m)?)?;
}
Which creates a bigger diff the more functions the user has. I guess it's not too bad, though.
If we change wrap_pyfunction!
return type like like we changed intern!
, then the only thing users would need to change is the module type:
#[pymodule]
fn my_module(py: Python, m: &Bound<PyModule>) {
m.add_function(wrap_pyfunction!(foo, m)?)?;
}
... but maybe we're making this more complicated than it needs to be, and we should just add wrap_pyfunction_bound
? I guess unlike intern!
, most wrap_pyfunction!
calls will all be located in one place in the #[pymodule]
. So it's not a very hard transformation.
... @snuderl what do you think of this? I guess adding wrap_pyfunction_bound!
creates a bigger diff, but maybe it's not too bad?
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.
Yeah adding wrap_pyfunction_bound!
should be pretty trivial it just hopped it could be avoided :)
There are 174 usages in the PyO3 repo, I guess we want to switch all of them right?
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.
Thinking about it, probably adding wrap_pyfunction_bound
gets very messy without the second commit I have in #3744, which allowed &Bound<PyModule>
in #[pymodule]
. Because I think we would want to have have wrap_pyfunction_bound!
used in #[pymodule]
which use &Bound<PyModule>
, and then maybe we keep just one test which uses the deprecated &PyModule
to
I really need to tidy that PR up and get it ready for review... 😢
Part of Part of #3684
This is a tehnically a breaking change. The diff is pretty simple though which hopefully means not many users would be impacted in practice. Thoughts?