-
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
Update dict.get_item binding to use PyDict_GetItemRef #4355
Conversation
57a0855
to
b18581f
Compare
In the interest of testing this better, I wrote a module that makes sure the error path works correctly: https://github.com/ngoldbaum/pyo3-dict-test. I'd like to integrate this with the rest of the pyo3 tests but have a question. Are there other tests that have little sidecar python files like I used? Or should I just figure out how to write that tiny toy |
Thanks for this! I will try to review tonight although I am struggling with OSS availablity right now due to young kids not sleeping |
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 very much for this! Overall looks correct though I have a few suggestions I'd like to see.
In the interest of testing this better, I wrote a module that makes sure the error path works correctly: https://github.com/ngoldbaum/pyo3-dict-test.
I'd like to integrate this with the rest of the pyo3 tests but have a question. Are there other tests that have little sidecar python files like I used? Or should I just figure out how to write that tiny toy HashErrors class in rust using pyo3?
Both options are possible. You can have inline Python inside the Rust source files using e.g. py_run!
macro, though that tends to not be fun for longer snippets.
You could write a unit test inside types/dict.rs
which uses the #[pyclass]
macro to build a type from Rust. See e.g. src/impl_/pyclass.rs
and the tests gated on #[cfg(feature = "macros")]
.
There is also the pytests/
subdirectory which builds a complete Rust extension and then runs some tests under pytest
. Though I think in this case a unit test in types/dict.rs
seems more fitting personally.
b18581f
to
414dc28
Compare
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 all for the reviews! I think the latest push addresses everything.
1164054
to
a46443b
Compare
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, this looks great to me. Just some tiny finishing nits I'd like to have tweaked please 😁
@davidhewitt I'm not sure if a pub unsafe fn PyDict_GetItemRef(
dp: *mut PyObject,
key: *mut PyObject,
result: *mut *mut PyObject,
) -> c_int {
#[cfg(Py_3_13)]
{
extern "C" {
#[link_name = "PyDict_GetItemRef"]
pub fn ActualPyDict_GetItemRef(
dp: *mut PyObject,
key: *mut PyObject,
result: *mut *mut PyObject,
) -> c_int;
}
ActualPyDict_GetItemRef(dp, key, result)
}
#[cfg(not(Py_3_13))]
{
// shim
}
} We have other functions that are shimmed in similar ways, like |
@mejrs I take your point and I do agree that the documentation needs to reflect where we actually make these functions available. Also I agree that adding a public What I do feel reasonably strongly about is that we should try as much as possible to keep the existing files in Isolating the compat code to a separate file seems like a good idea to me to separate out the deviations from the headers, though I am open to not having the new public I think the question comes down to this: do we want If we want ease-of-use, I think just having If we want to prioritise being a thin wrapper around the CPython API, I think having I am open to all parties' opinions on this question!
Probably we should tackle that case in a separate PR. |
I am concerned that people end up writing code like pub mod pyo3_ffi{
pub mod compat {
pub fn PyDict_GetItemRef(){}
}
mod dictobject{
pub fn PyDict_GetItemRef(){}
}
pub use dictobject::*;
}
use pyo3_ffi::*;
use pyo3_ffi::compat::*;
fn main(){
PyDict_GetItemRef();
} which would raise ambiguous import errors if both are defined. |
That's a strong point against a |
I think we can make a #![cfg_attr(docsrs, feature(doc_cfg))]
pub mod pyo3_ffi{
pub mod compat {
#[cfg_attr(docsrs, doc(cfg()))]
#[cfg(Py_3_13)]
pub use super::dictobject::PyDict_GetItemRef;
// shim
#[cfg_attr(docsrs, doc(cfg()))]
#[cfg(not(Py_3_13))]
pub fn PyDict_GetItemRef(){}
}
mod dictobject{
#[cfg(Py_3_13)]
pub fn PyDict_GetItemRef(){}
}
pub use dictobject::*;
}
use pyo3_ffi::*;
use pyo3_ffi::compat::*;
fn main(){
PyDict_GetItemRef();
} |
I think I correctly applied the suggestion from #4355 (comment) in the last commit. Let me know if I messed that up, it took me about 20 minutes of searching and then finding this discussion thread before I understood what the suggestion was. |
Hmm, nope, that broke the docs build. I think this has to do with pyo3-ffi being a workspace dependency, so the rustdoc configuration to set |
Try adding |
This comment was marked as outdated.
This comment was marked as outdated.
Finally got it, you need to declare features in the top-level |
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.
This looks working to me! @mejrs are you happy with the compat
namespace now it is set up in this way?
120ab18
to
03a69ff
Compare
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
I think hopefully #4397 will resolve. |
03a69ff
to
ca1653c
Compare
This comment was marked as outdated.
This comment was marked as outdated.
ca1653c
to
963f6c2
Compare
* Update dict.get_item binding to use PyDict_GetItemRef Refs #4265 * test: add test for dict.get_item error path * test: add test for dict.get_item error path * test: add test for dict.get_item error path * fix: fix logic error in dict.get_item bindings * update: apply david's review suggestions for dict.get_item bindings * update: create ffi::compat to store compatibility shims * update: move PyDict_GetItemRef bindings to spot in order from dictobject.h * build: fix build warning with --no-default-features * doc: expand release note fragments * fix: fix clippy warnings * respond to review comments * Apply suggestion from @mejrs * refactor so cfg is applied to functions * properly set cfgs * fix clippy lints * Apply @davidhewitt's suggestion * deal with upstream deprecation of new_bound
* Update dict.get_item binding to use PyDict_GetItemRef Refs #4265 * test: add test for dict.get_item error path * test: add test for dict.get_item error path * test: add test for dict.get_item error path * fix: fix logic error in dict.get_item bindings * update: apply david's review suggestions for dict.get_item bindings * update: create ffi::compat to store compatibility shims * update: move PyDict_GetItemRef bindings to spot in order from dictobject.h * build: fix build warning with --no-default-features * doc: expand release note fragments * fix: fix clippy warnings * respond to review comments * Apply suggestion from @mejrs * refactor so cfg is applied to functions * properly set cfgs * fix clippy lints * Apply @davidhewitt's suggestion * deal with upstream deprecation of new_bound
Refs #4265
See the CPython C API docs for this new function. Also see PEP 703 for how this relates to free-threading support.