-
Notifications
You must be signed in to change notification settings - Fork 779
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
Add extract_bound
method to FromPyObject
#3706
Conversation
fad596b
to
c47e528
Compare
CodSpeed Performance ReportMerging #3706 will degrade performances by 32.02%Comparing Summary
Benchmarks breakdown
|
/// Extracts `Self` from the source GIL Ref `obj`. | ||
/// | ||
/// Implementors are encouraged to implement `extract_bound` and leave this method as the | ||
/// default implementation, which will forward calls to `extract_bound`. | ||
fn extract(ob: &'source PyAny) -> PyResult<Self> { | ||
Self::extract_bound(&ob.as_borrowed()) | ||
} | ||
|
||
/// Extracts `Self` from the bound smart pointer `obj`. | ||
/// | ||
/// Implementors are encouraged to implement this method and leave `extract` defaulted, as | ||
/// this will be most compatible with PyO3's future API. | ||
fn extract_bound(ob: &Bound<'source, PyAny>) -> PyResult<Self> { | ||
Self::extract(ob.clone().into_gil_ref()) | ||
} |
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 default implementation has infinite recursion if a user implements neither method. This is a slightly clunky footgun but I'm fine with it as a temporary measure; I think in 0.22 once we start pushing harder then we can just default extract
and require an implementation of extract_bound
.
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.
Does implementing this using only the defaults trigger a warning due to unconditional mutual recursion?
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.
Sadly no, it just leads to a stack overflow at runtime. I've tried to repeat the expectation in documentation that implementors should implement extract_bound
.
Hopefully it's a fairly obvious programming error, and at least we can get rid of the .extract_bound()
default in 0.22 and remove this footgun again.
Unless we can think of alternatives here, I'd quite like to merge this PR, as merging this unblocks us to migrate the rest of PyO3's implementations of |
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 agree that the general approach is the best we can do for 0.21. I think this should be highlighted in the migration guide though, either as part of this PR or as a task item on the tracking issue.
Thank you for all the reviews today! I'll have plenty of PRs to push once this one goes in ;) Completely agree that this is worthy of going in the migration guide. I'll add it to this PR; I'll rebase once #3755 goes in and add some detail before merging this. |
68927d8
to
ffaa03e
Compare
This PR proposes a way that we can support migration of
FromPyObject
off the GIL Refs API in a backwards-compatible fashion.It does so by adding a new
extract_bound
method toFromPyObject<'py>
, which takes&Bound<'py, PyAny>
. Note that the lifetime'py
in the trait becomes only the'py
lifetime and not the lifetime for which theBound
smart pointer is alive. This is important for backwards-compatibility; maybe in the future we could haveFromPyObject<'a, 'py>
and the argument could be&'a Bound<'py, PyAny>
, but let's cross that bridge another time.Also for backwards-compatibility's sake, both
extract
andextract_bound
have default implementations in terms of each other. This allows for users to migrate from using one set of implementations to the other at their own pace. The documentation encourages to implement justextract_bound
, as the default implementation requires a.into_gil_ref()
call to insert into the pool.To avoid a huge diff here, I've pushed a second commit which just includes a couple of randomly-selected implementations which I migrate from
extract
toextract_bound
, to give a feeling for how this works.If we like this and merge it, I can work on one or more follow-ups which migrate the rest of our internals to
extract_bound
(which will go a long way towards getting PyO3's internals off the pool).