-
Notifications
You must be signed in to change notification settings - Fork 802
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
migrate PyDictMethods
trait bounds
#4493
Conversation
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 first commit looks good to me.
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.
Thanks, agreed on the first commit looking great! Some suggestions on the second commit...
src/types/dict.rs
Outdated
pub trait IntoPyDict<'py>: Sized { | ||
/// Converts self into a `PyDict` object pointer. Whether pointer owned or borrowed | ||
/// depends on implementation. | ||
fn into_py_dict(self, py: Python<'_>) -> Bound<'_, PyDict>; | ||
fn into_py_dict(self, py: Python<'py>) -> Bound<'_, PyDict>; |
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 think we can take the opportunity here to make the return type fallible? AFAIK one of the most likely panics on current conversion traits is unhashable keys.
(This method is new for 0.23 replacing the removed GIL Ref form)
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.
That makes sense, I will adapt that 👍
src/types/dict.rs
Outdated
/// Represents a tuple which can be used as a PyDict item. | ||
pub trait PyDictItem { | ||
type K: ToPyObject; | ||
type V: ToPyObject; | ||
fn key(&self) -> &Self::K; | ||
fn value(&self) -> &Self::V; | ||
pub trait PyDictItem<'py> { | ||
type K: IntoPyObject<'py>; | ||
type V: IntoPyObject<'py>; | ||
fn unpack(self) -> (Self::K, Self::V); | ||
} |
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's kind of breaking, but I can't really see a better way forward. Maybe we just mention this in the migration guide? Most users are not implementing / using this trait, I think.
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.
Actually I think PyDictItem
is completely internal to PyO3 and is invisible from the outside (it's only mentioned inside dict.rs
which is a pub(crate)
module). So maybe we just remove pub
here to make that clear? Also we should update the example that's already in the migration guide in that regard. I will fix it up together with the fallibility mention.
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.
Ah perfect, even better! We might need to have pub
for the trait implementation, not sure.
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 removed it and nothing complained, so it guess it's fine 😁
@@ -557,76 +557,73 @@ pub(crate) use borrowed_iter::BorrowedDictIter; | |||
|
|||
/// Conversion trait that allows a sequence of tuples to be converted into `PyDict` | |||
/// Primary use case for this trait is `call` and `call_method` methods as keywords argument. | |||
pub trait IntoPyDict: Sized { | |||
pub trait IntoPyDict<'py>: Sized { |
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 guess the alternative is keep the existing form around for a while and add a new trait IntoPyDictObject
or similar which we can eventually rename back to just this. But I'm unsure how much value there really is in that, for this small corner of the API.
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 have the feeling that this is mostly used to get access to the constructors we provide and is probably not often implemented on custom types. So I think it would likely cause more churn doing the renaming business.
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.
Agreed, let's keep with this current pathway 👍
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.
Looks great to me, thanks! Basically just some closing thoughts / observations remaining. Please feel free to merge 👍
@@ -557,76 +557,73 @@ pub(crate) use borrowed_iter::BorrowedDictIter; | |||
|
|||
/// Conversion trait that allows a sequence of tuples to be converted into `PyDict` | |||
/// Primary use case for this trait is `call` and `call_method` methods as keywords argument. | |||
pub trait IntoPyDict: Sized { | |||
pub trait IntoPyDict<'py>: Sized { |
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.
Agreed, let's keep with this current pathway 👍
for item in self { | ||
dict.set_item(item.key(), item.value()) | ||
.expect("Failed to set_item on dict"); | ||
let (key, value) = item.unpack(); | ||
dict.set_item(key, value)?; | ||
} |
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.
(Probably one for a future PR) I guess after I read https://medium.com/@veedrac/rust-is-slow-and-i-am-the-cure-32facc0fdcb we should eventually consider try_for_each
or similar iterator algorithms for these loops. Potentially extra relevant after #4439.
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.
Interesting read, thanks for linking. Might be interesting to do some benchmarks whether we can actually measure any difference. Sounds good for a future PR for me too.
src/types/dict.rs
Outdated
/// Represents a tuple which can be used as a PyDict item. | ||
pub trait PyDictItem { | ||
type K: ToPyObject; | ||
type V: ToPyObject; | ||
fn key(&self) -> &Self::K; | ||
fn value(&self) -> &Self::V; | ||
pub trait PyDictItem<'py> { | ||
type K: IntoPyObject<'py>; | ||
type V: IntoPyObject<'py>; | ||
fn unpack(self) -> (Self::K, Self::V); | ||
} |
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.
Ah perfect, even better! We might need to have pub
for the trait implementation, not sure.
Co-authored-by: David Hewitt <[email protected]>
This migrates
PyDictMethods
toIntoPyObject
and cleans up the map impls. I was not super sure how we want to deal withIntoPyDict
, so I added a proposal as a second commit, but we can also drop that for now, if we need more discussion for that. In case we want to leave it like this, I will add changelog and migration entries.