-
Notifications
You must be signed in to change notification settings - Fork 132
Update to target ABI v2 #537
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
Open
mattiapenati
wants to merge
6
commits into
PyO3:main
Choose a base branch
from
mattiapenati:target-abi-v2
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
f165f14
Spread usage of NonNull to mark the pointer returned from capsules
mattiapenati 6118c0f
Update multiarray API to match ABI v2
mattiapenati b735453
Update ufunc API to match ABI v2
mattiapenati 986f75e
Fix missing PyUFunc_Type
mattiapenati 821f1ed
Update FFI associated types and constants
mattiapenati 113893f
Check compatibility with chosen ABI/API versions
mattiapenati File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,44 +11,40 @@ | |
|
|
||
| use std::mem::forget; | ||
| use std::os::raw::{c_uint, c_void}; | ||
| use std::ptr::NonNull; | ||
|
|
||
| use pyo3::{ | ||
| ffi::PyTypeObject, | ||
| sync::PyOnceLock, | ||
| types::{PyAnyMethods, PyCapsule, PyCapsuleMethods, PyModule}, | ||
| PyResult, Python, | ||
| }; | ||
|
|
||
| pub const API_VERSION_2_0: c_uint = 0x00000012; | ||
|
|
||
| static API_VERSION: PyOnceLock<c_uint> = PyOnceLock::new(); | ||
|
|
||
| fn get_numpy_api<'py>( | ||
| py: Python<'py>, | ||
| module: &str, | ||
| capsule: &str, | ||
| ) -> PyResult<*const *const c_void> { | ||
| ) -> PyResult<NonNull<*const c_void>> { | ||
| let module = PyModule::import(py, module)?; | ||
| let capsule = module.getattr(capsule)?.cast_into::<PyCapsule>()?; | ||
|
|
||
| let api = capsule | ||
| .pointer_checked(None)? | ||
| .cast::<*const c_void>() | ||
| .as_ptr() | ||
| .cast_const(); | ||
| let api = capsule.pointer_checked(None)?; | ||
|
|
||
| // Intentionally leak a reference to the capsule | ||
| // so we can safely cache a pointer into its interior. | ||
| forget(capsule); | ||
|
|
||
| Ok(api) | ||
| Ok(api.cast()) | ||
| } | ||
|
|
||
| /// Returns whether the runtime `numpy` version is 2.0 or greater. | ||
| pub fn is_numpy_2<'py>(py: Python<'py>) -> bool { | ||
| let api_version = *API_VERSION.get_or_init(py, || unsafe { | ||
| PY_ARRAY_API.PyArray_GetNDArrayCFeatureVersion(py) | ||
| }); | ||
| api_version >= API_VERSION_2_0 | ||
| api_version >= NPY_2_0_API_VERSION | ||
| } | ||
|
|
||
| // Implements wrappers for NumPy's Array and UFunc API | ||
|
|
@@ -57,52 +53,90 @@ macro_rules! impl_api { | |
| [$offset: expr; $fname: ident ($($arg: ident: $t: ty),* $(,)?) $(-> $ret: ty)?] => { | ||
| #[allow(non_snake_case)] | ||
| pub unsafe fn $fname<'py>(&self, py: Python<'py>, $($arg : $t), *) $(-> $ret)* { | ||
| let fptr = self.get(py, $offset) as *const extern "C" fn ($($arg : $t), *) $(-> $ret)*; | ||
| (*fptr)($($arg), *) | ||
| let f: extern "C" fn ($($arg : $t), *) $(-> $ret)* = self.get(py, $offset).cast().read(); | ||
| f($($arg), *) | ||
| } | ||
| }; | ||
| } | ||
|
|
||
| // API with version constraints, checked at runtime | ||
| [$offset: expr; NumPy1; $fname: ident ($($arg: ident: $t: ty),* $(,)?) $(-> $ret: ty)?] => { | ||
| #[allow(non_snake_case)] | ||
| pub unsafe fn $fname<'py>(&self, py: Python<'py>, $($arg : $t), *) $(-> $ret)* { | ||
| assert!( | ||
| !is_numpy_2(py), | ||
| "{} requires API < {:08X} (NumPy 1) but the runtime version is API {:08X}", | ||
| stringify!($fname), | ||
| API_VERSION_2_0, | ||
| *API_VERSION.get(py).expect("API_VERSION is initialized"), | ||
| ); | ||
| let fptr = self.get(py, $offset) as *const extern "C" fn ($($arg: $t), *) $(-> $ret)*; | ||
| (*fptr)($($arg), *) | ||
| } | ||
| // Define type objects associated with the NumPy API | ||
| macro_rules! impl_array_type { | ||
| ($(($api:ident [ $offset:expr ] , $tname:ident)),* $(,)?) => { | ||
| /// All type objects exported by the NumPy API. | ||
| #[allow(non_camel_case_types)] | ||
| pub enum NpyTypes { $($tname),* } | ||
|
|
||
| }; | ||
| [$offset: expr; NumPy2; $fname: ident ($($arg: ident: $t: ty),* $(,)?) $(-> $ret: ty)?] => { | ||
| #[allow(non_snake_case)] | ||
| pub unsafe fn $fname<'py>(&self, py: Python<'py>, $($arg : $t), *) $(-> $ret)* { | ||
| assert!( | ||
| is_numpy_2(py), | ||
| "{} requires API {:08X} or greater (NumPy 2) but the runtime version is API {:08X}", | ||
| stringify!($fname), | ||
| API_VERSION_2_0, | ||
| *API_VERSION.get(py).expect("API_VERSION is initialized"), | ||
| ); | ||
| let fptr = self.get(py, $offset) as *const extern "C" fn ($($arg: $t), *) $(-> $ret)*; | ||
| (*fptr)($($arg), *) | ||
| /// Get a pointer of the type object associated with `ty`. | ||
| pub unsafe fn get_type_object<'py>(py: Python<'py>, ty: NpyTypes) -> *mut PyTypeObject { | ||
| match ty { | ||
| $( NpyTypes::$tname => $api.get(py, $offset).read() as _ ),* | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| }; | ||
| impl_array_type! { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Smart, I like the syntax and that this can now support returning type objects from different APIs. |
||
| // Multiarray API | ||
| // Slot 1 was never meaningfully used by NumPy | ||
| (PY_ARRAY_API[2], PyArray_Type), | ||
| (PY_ARRAY_API[3], PyArrayDescr_Type), | ||
| // Unused slot 4, was `PyArrayFlags_Type` | ||
| (PY_ARRAY_API[5], PyArrayIter_Type), | ||
| (PY_ARRAY_API[6], PyArrayMultiIter_Type), | ||
| // (PY_ARRAY_API[7], NPY_NUMUSERTYPES) -> c_int, | ||
| (PY_ARRAY_API[8], PyBoolArrType_Type), | ||
| // (PY_ARRAY_API[9], _PyArrayScalar_BoolValues) -> *mut PyBoolScalarObject, | ||
| (PY_ARRAY_API[10], PyGenericArrType_Type), | ||
| (PY_ARRAY_API[11], PyNumberArrType_Type), | ||
| (PY_ARRAY_API[12], PyIntegerArrType_Type), | ||
| (PY_ARRAY_API[13], PySignedIntegerArrType_Type), | ||
| (PY_ARRAY_API[14], PyUnsignedIntegerArrType_Type), | ||
| (PY_ARRAY_API[15], PyInexactArrType_Type), | ||
| (PY_ARRAY_API[16], PyFloatingArrType_Type), | ||
| (PY_ARRAY_API[17], PyComplexFloatingArrType_Type), | ||
| (PY_ARRAY_API[18], PyFlexibleArrType_Type), | ||
| (PY_ARRAY_API[19], PyCharacterArrType_Type), | ||
| (PY_ARRAY_API[20], PyByteArrType_Type), | ||
| (PY_ARRAY_API[21], PyShortArrType_Type), | ||
| (PY_ARRAY_API[22], PyIntArrType_Type), | ||
| (PY_ARRAY_API[23], PyLongArrType_Type), | ||
| (PY_ARRAY_API[24], PyLongLongArrType_Type), | ||
| (PY_ARRAY_API[25], PyUByteArrType_Type), | ||
| (PY_ARRAY_API[26], PyUShortArrType_Type), | ||
| (PY_ARRAY_API[27], PyUIntArrType_Type), | ||
| (PY_ARRAY_API[28], PyULongArrType_Type), | ||
| (PY_ARRAY_API[29], PyULongLongArrType_Type), | ||
| (PY_ARRAY_API[30], PyFloatArrType_Type), | ||
| (PY_ARRAY_API[31], PyDoubleArrType_Type), | ||
| (PY_ARRAY_API[32], PyLongDoubleArrType_Type), | ||
| (PY_ARRAY_API[33], PyCFloatArrType_Type), | ||
| (PY_ARRAY_API[34], PyCDoubleArrType_Type), | ||
| (PY_ARRAY_API[35], PyCLongDoubleArrType_Type), | ||
| (PY_ARRAY_API[36], PyObjectArrType_Type), | ||
| (PY_ARRAY_API[37], PyStringArrType_Type), | ||
| (PY_ARRAY_API[38], PyUnicodeArrType_Type), | ||
| (PY_ARRAY_API[39], PyVoidArrType_Type), | ||
| (PY_ARRAY_API[214], PyTimeIntegerArrType_Type), | ||
| (PY_ARRAY_API[215], PyDatetimeArrType_Type), | ||
| (PY_ARRAY_API[216], PyTimedeltaArrType_Type), | ||
| (PY_ARRAY_API[217], PyHalfArrType_Type), | ||
| (PY_ARRAY_API[218], NpyIter_Type), | ||
| // UFunc API | ||
| (PY_UFUNC_API[0], PyUFunc_Type), | ||
| } | ||
|
|
||
| pub mod array; | ||
| pub mod flags; | ||
| mod npy_common; | ||
| mod numpyconfig; | ||
| pub mod objects; | ||
| pub mod types; | ||
| pub mod ufunc; | ||
|
|
||
| pub use self::array::*; | ||
| pub use self::flags::*; | ||
| pub use self::npy_common::*; | ||
| pub use self::numpyconfig::*; | ||
| pub use self::objects::*; | ||
| pub use self::types::*; | ||
| pub use self::ufunc::*; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| use std::ffi::c_int; | ||
|
|
||
| /// Unknown CPU endianness. | ||
| pub const NPY_CPU_UNKNOWN_ENDIAN: c_int = 0; | ||
| /// CPU is little-endian. | ||
| pub const NPY_CPU_LITTLE: c_int = 1; | ||
| /// CPU is big-endian. | ||
| pub const NPY_CPU_BIG: c_int = 2; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| // This file matches the numpyconfig.h header. | ||
|
|
||
| use std::ffi::c_uint; | ||
|
|
||
| /// The current target ABI version | ||
| const NPY_ABI_VERSION: c_uint = 0x02000000; | ||
|
|
||
| /// The current target API version (v1.15) | ||
| const NPY_API_VERSION: c_uint = 0x0000000c; | ||
|
|
||
| pub(super) const NPY_2_0_API_VERSION: c_uint = 0x00000012; | ||
|
|
||
| /// The current version of the `ndarray` object (ABI version). | ||
| pub const NPY_VERSION: c_uint = NPY_ABI_VERSION; | ||
| /// The current version of C API. | ||
| pub const NPY_FEATURE_VERSION: c_uint = NPY_API_VERSION; | ||
| /// The string representation of current version C API. | ||
| pub const NPY_FEATURE_VERSION_STRING: &str = "1.15"; |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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 need to look at the usages of this. These are used to conditionally cast structures, which we should not do anymore now that we are targeting a single ABI, right?