From c386c8e4ce0cb72435790543acb74e9becfb057d Mon Sep 17 00:00:00 2001 From: Icxolu <10486322+Icxolu@users.noreply.github.com> Date: Fri, 22 Nov 2024 13:43:41 +0100 Subject: [PATCH] update `pyo3` to 0.23 (#457) * remove `gil-ref` feature * initial migration to pyo3 0.23 * fix all deprecations * reintroduce names with `_bound` suffix * switch from `ToPyObject` to `IntoPyObject` * bump to pyo3 0.23 release * fix doc-tests * add changelog --- CHANGELOG.md | 6 + Cargo.toml | 9 +- README.md | 10 +- benches/array.rs | 20 +- benches/borrow.rs | 6 +- examples/linalg/Cargo.lock | 73 +-- examples/linalg/Cargo.toml | 2 +- examples/linalg/src/lib.rs | 2 +- examples/parallel/Cargo.toml | 2 +- examples/parallel/src/lib.rs | 2 +- examples/simple/Cargo.toml | 2 +- examples/simple/src/lib.rs | 10 +- src/array.rs | 1069 ++++++---------------------------- src/array_like.rs | 6 +- src/borrow/mod.rs | 68 ++- src/borrow/shared.rs | 75 +-- src/convert.rs | 77 +-- src/datetime.rs | 50 +- src/dtype.rs | 406 ++++--------- src/error.rs | 15 +- src/lib.rs | 65 +-- src/npyffi/array.rs | 6 +- src/npyffi/mod.rs | 2 +- src/npyffi/objects.rs | 13 - src/strings.rs | 8 +- src/sum_products.rs | 145 ++--- src/untyped_array.rs | 223 +------ tests/array.rs | 280 +++------ tests/array_like.rs | 35 +- tests/borrow.rs | 115 ++-- tests/sum_products.rs | 70 ++- tests/to_py.rs | 64 +- 32 files changed, 839 insertions(+), 2097 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c15cc0b03..9b748cf6f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Changelog - v0.23.0 - Drop support for PyPy 3.7 and 3.8. ([#470](https://github.com/PyO3/rust-numpy/pull/470)) + - Require `Element: Sync` as part of the free-threading support in PyO3 0.23 ([#469](https://github.com/PyO3/rust-numpy/pull/469)) + - Bump PyO3 dependency to v0.23.0 ([[#457](https://github.com/PyO3/rust-numpy/pull/457)]) + - removed the `gil-refs` feature + - reintroduced function names without `_bound` suffix + deprecating the old names + - switched to `IntoPyObject` as trait bound + - v0.22.1 - Fix building on 32-bit Windows. ([#463](https://github.com/PyO3/rust-numpy/pull/463)) - Add `PyReadwriteArray::make_nonwriteable`. ([#462](https://github.com/PyO3/rust-numpy/pull/462)) diff --git a/Cargo.toml b/Cargo.toml index 5c9e852c9..90c74f452 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "numpy" -version = "0.22.1" +version = "0.23.0-dev" authors = [ "The rust-numpy Project Developers", "PyO3 Project and Contributors " @@ -22,15 +22,12 @@ num-complex = ">= 0.2, < 0.5" num-integer = "0.1" num-traits = "0.2" ndarray = ">= 0.15, < 0.17" -pyo3 = { version = "0.22.0", default-features = false, features = ["macros"] } +pyo3 = { version = "0.23.0", default-features = false, features = ["macros"] } rustc-hash = "1.1" [dev-dependencies] -pyo3 = { version = "0.22.0", default-features = false, features = ["auto-initialize"] } +pyo3 = { version = "0.23.0", default-features = false, features = ["auto-initialize"] } nalgebra = { version = ">=0.30, <0.34", default-features = false, features = ["std"] } [package.metadata.docs.rs] all-features = true - -[features] -gil-refs = ["pyo3/gil-refs"] diff --git a/README.md b/README.md index 80945c746..32e72eebd 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ fn rust_ext<'py>(_py: Python<'py>, m: &Bound<'py, PyModule>) -> PyResult<()> { let x = x.as_array(); let y = y.as_array(); let z = axpy(a, x, y); - z.into_pyarray_bound(py) + z.into_pyarray(py) } // wrapper of `mult` @@ -99,15 +99,15 @@ numpy = "0.22" ```rust use numpy::{PyArray1, PyArrayMethods}; -use pyo3::{types::{IntoPyDict, PyAnyMethods}, PyResult, Python}; +use pyo3::{types::{IntoPyDict, PyAnyMethods}, PyResult, Python, ffi::c_str}; fn main() -> PyResult<()> { Python::with_gil(|py| { - let np = py.import_bound("numpy")?; - let locals = [("np", np)].into_py_dict_bound(py); + let np = py.import("numpy")?; + let locals = [("np", np)].into_py_dict(py)?; let pyarray = py - .eval_bound("np.absolute(np.array([-1, -2, -3], dtype='int32'))", Some(&locals), None)? + .eval(c_str!("np.absolute(np.array([-1, -2, -3], dtype='int32'))"), Some(&locals), None)? .downcast_into::>()?; let readonly = pyarray.readonly(); diff --git a/benches/array.rs b/benches/array.rs index 56d4bd117..3df2321bb 100644 --- a/benches/array.rs +++ b/benches/array.rs @@ -6,12 +6,12 @@ use test::{black_box, Bencher}; use std::ops::Range; use numpy::{PyArray1, PyArray2, PyArray3}; -use pyo3::{types::PyAnyMethods, Bound, Python, ToPyObject}; +use pyo3::{types::PyAnyMethods, Bound, Python}; #[bench] fn extract_success(bencher: &mut Bencher) { Python::with_gil(|py| { - let any = PyArray2::::zeros_bound(py, (10, 10), false).into_any(); + let any = PyArray2::::zeros(py, (10, 10), false).into_any(); bencher.iter(|| { black_box(&any) @@ -24,7 +24,7 @@ fn extract_success(bencher: &mut Bencher) { #[bench] fn extract_failure(bencher: &mut Bencher) { Python::with_gil(|py| { - let any = PyArray2::::zeros_bound(py, (10, 10), false).into_any(); + let any = PyArray2::::zeros(py, (10, 10), false).into_any(); bencher.iter(|| { black_box(&any) @@ -37,7 +37,7 @@ fn extract_failure(bencher: &mut Bencher) { #[bench] fn downcast_success(bencher: &mut Bencher) { Python::with_gil(|py| { - let any = PyArray2::::zeros_bound(py, (10, 10), false).into_any(); + let any = PyArray2::::zeros(py, (10, 10), false).into_any(); bencher.iter(|| black_box(&any).downcast::>().unwrap()); }); @@ -46,7 +46,7 @@ fn downcast_success(bencher: &mut Bencher) { #[bench] fn downcast_failure(bencher: &mut Bencher) { Python::with_gil(|py| { - let any = PyArray2::::zeros_bound(py, (10, 10), false).into_any(); + let any = PyArray2::::zeros(py, (10, 10), false).into_any(); bencher.iter(|| black_box(&any).downcast::>().unwrap_err()); }); @@ -67,7 +67,7 @@ fn from_iter(bencher: &mut Bencher, size: usize) { bencher.iter(|| { let iter = black_box(Iter(0..size)); - PyArray1::from_iter_bound(py, iter) + PyArray1::from_iter(py, iter) }); }); } @@ -94,7 +94,7 @@ fn from_slice(bencher: &mut Bencher, size: usize) { bencher.iter(|| { let slice = black_box(&vec); - PyArray1::from_slice_bound(py, slice) + PyArray1::from_slice(py, slice) }); }); } @@ -121,7 +121,7 @@ fn from_object_slice(bencher: &mut Bencher, size: usize) { bencher.iter(|| { let slice = black_box(&vec); - PyArray1::from_slice_bound(py, slice) + PyArray1::from_slice(py, slice) }); }); } @@ -148,7 +148,7 @@ fn from_vec2(bencher: &mut Bencher, size: usize) { bencher.iter(|| { let vec2 = black_box(&vec2); - PyArray2::from_vec2_bound(py, vec2).unwrap() + PyArray2::from_vec2(py, vec2).unwrap() }); }); } @@ -175,7 +175,7 @@ fn from_vec3(bencher: &mut Bencher, size: usize) { bencher.iter(|| { let vec3 = black_box(&vec3); - PyArray3::from_vec3_bound(py, vec3).unwrap() + PyArray3::from_vec3(py, vec3).unwrap() }); }); } diff --git a/benches/borrow.rs b/benches/borrow.rs index 79e7dc030..f7c0c7641 100644 --- a/benches/borrow.rs +++ b/benches/borrow.rs @@ -9,7 +9,7 @@ use pyo3::Python; #[bench] fn initial_shared_borrow(bencher: &mut Bencher) { Python::with_gil(|py| { - let array = PyArray::::zeros_bound(py, (6, 5, 4, 3, 2, 1), false); + let array = PyArray::::zeros(py, (6, 5, 4, 3, 2, 1), false); bencher.iter(|| { let array = black_box(&array); @@ -22,7 +22,7 @@ fn initial_shared_borrow(bencher: &mut Bencher) { #[bench] fn additional_shared_borrow(bencher: &mut Bencher) { Python::with_gil(|py| { - let array = PyArray::::zeros_bound(py, (6, 5, 4, 3, 2, 1), false); + let array = PyArray::::zeros(py, (6, 5, 4, 3, 2, 1), false); let _shared = (0..128).map(|_| array.readonly()).collect::>(); @@ -37,7 +37,7 @@ fn additional_shared_borrow(bencher: &mut Bencher) { #[bench] fn exclusive_borrow(bencher: &mut Bencher) { Python::with_gil(|py| { - let array = PyArray::::zeros_bound(py, (6, 5, 4, 3, 2, 1), false); + let array = PyArray::::zeros(py, (6, 5, 4, 3, 2, 1), false); bencher.iter(|| { let array = black_box(&array); diff --git a/examples/linalg/Cargo.lock b/examples/linalg/Cargo.lock index 2ad2745c3..2a6c81d79 100644 --- a/examples/linalg/Cargo.lock +++ b/examples/linalg/Cargo.lock @@ -209,9 +209,9 @@ dependencies = [ [[package]] name = "heck" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "idna" @@ -285,16 +285,6 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] - [[package]] name = "log" version = "0.4.22" @@ -408,7 +398,7 @@ dependencies = [ [[package]] name = "numpy" -version = "0.21.0" +version = "0.23.0-dev" dependencies = [ "libc", "ndarray", @@ -495,29 +485,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "parking_lot" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets", -] - [[package]] name = "percent-encoding" version = "2.3.1" @@ -556,15 +523,15 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.21.2" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e00b96a521718e08e03b1a622f01c8a8deb50719335de3f60b3b3950f069d8" +checksum = "7ebb0c0cc0de9678e53be9ccf8a2ab53045e6e3a8be03393ceccc5e7396ccb40" dependencies = [ "cfg-if", "indoc", "libc", "memoffset", - "parking_lot", + "once_cell", "portable-atomic", "pyo3-build-config", "pyo3-ffi", @@ -574,9 +541,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.21.2" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7883df5835fafdad87c0d888b266c8ec0f4c9ca48a5bed6bbb592e8dedee1b50" +checksum = "80e3ce69c4ec34476534b490e412b871ba03a82e35604c3dfb95fcb6bfb60c09" dependencies = [ "once_cell", "target-lexicon", @@ -584,9 +551,9 @@ dependencies = [ [[package]] name = "pyo3-ffi" -version = "0.21.2" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01be5843dc60b916ab4dad1dca6d20b9b4e6ddc8e15f50c47fe6d85f1fb97403" +checksum = "3b09f311c76b36dfd6dd6f7fa6f9f18e7e46a1c937110d283e80b12ba2468a75" dependencies = [ "libc", "pyo3-build-config", @@ -594,9 +561,9 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.21.2" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77b34069fc0682e11b31dbd10321cbf94808394c56fd996796ce45217dfac53c" +checksum = "fd4f74086536d1e1deaff99ec0387481fb3325c82e4e48be0e75ab3d3fcb487a" dependencies = [ "proc-macro2", "pyo3-macros-backend", @@ -606,9 +573,9 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.21.2" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08260721f32db5e1a5beae69a55553f56b99bd0e1c3e6e0a5e8851a9d0f5a85c" +checksum = "9e77dfeb76b32bbf069144a5ea0a36176ab59c8db9ce28732d0f06f096bbfbc8" dependencies = [ "heck", "proc-macro2", @@ -757,12 +724,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - [[package]] name = "security-framework" version = "2.11.1" @@ -812,12 +773,6 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" -[[package]] -name = "smallvec" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" - [[package]] name = "syn" version = "2.0.75" diff --git a/examples/linalg/Cargo.toml b/examples/linalg/Cargo.toml index fc4a3a29c..3faa3acd0 100644 --- a/examples/linalg/Cargo.toml +++ b/examples/linalg/Cargo.toml @@ -9,7 +9,7 @@ name = "rust_linalg" crate-type = ["cdylib"] [dependencies] -pyo3 = { version = "0.22.0", features = ["extension-module"] } +pyo3 = { version = "0.23.0", features = ["extension-module"] } numpy = { path = "../.." } ndarray-linalg = { version = "0.14.1", features = ["openblas-system"] } diff --git a/examples/linalg/src/lib.rs b/examples/linalg/src/lib.rs index 729c965e7..27b333edd 100755 --- a/examples/linalg/src/lib.rs +++ b/examples/linalg/src/lib.rs @@ -13,7 +13,7 @@ fn rust_linalg<'py>(m: &Bound<'py, PyModule>) -> PyResult<()> { let y = x .inv() .map_err(|e| PyRuntimeError::new_err(e.to_string()))?; - Ok(y.into_pyarray_bound(py)) + Ok(y.into_pyarray(py)) } Ok(()) } diff --git a/examples/parallel/Cargo.toml b/examples/parallel/Cargo.toml index af40e2fec..0ed28cb71 100644 --- a/examples/parallel/Cargo.toml +++ b/examples/parallel/Cargo.toml @@ -9,7 +9,7 @@ name = "rust_parallel" crate-type = ["cdylib"] [dependencies] -pyo3 = { version = "0.22.0", features = ["extension-module", "multiple-pymethods"] } +pyo3 = { version = "0.23.0", features = ["extension-module", "multiple-pymethods"] } numpy = { path = "../.." } ndarray = { version = "0.16", features = ["rayon", "blas"] } blas-src = { version = "0.8", features = ["openblas"] } diff --git a/examples/parallel/src/lib.rs b/examples/parallel/src/lib.rs index 20a04d331..b1adc1cae 100755 --- a/examples/parallel/src/lib.rs +++ b/examples/parallel/src/lib.rs @@ -16,7 +16,7 @@ fn rust_parallel<'py>(m: &Bound<'py, PyModule>) -> PyResult<()> { let x = x.as_array(); let y = y.as_array(); let z = Zip::from(x.rows()).par_map_collect(|row| row.dot(&y)); - z.into_pyarray_bound(py) + z.into_pyarray(py) } Ok(()) } diff --git a/examples/simple/Cargo.toml b/examples/simple/Cargo.toml index b3fd06bca..c180039f7 100644 --- a/examples/simple/Cargo.toml +++ b/examples/simple/Cargo.toml @@ -9,7 +9,7 @@ name = "rust_ext" crate-type = ["cdylib"] [dependencies] -pyo3 = { version = "0.22.0", features = ["extension-module", "abi3-py37"] } +pyo3 = { version = "0.23.0", features = ["extension-module", "abi3-py37"] } numpy = { path = "../.." } [workspace] diff --git a/examples/simple/src/lib.rs b/examples/simple/src/lib.rs index fa1c844c7..3bb29e3e1 100644 --- a/examples/simple/src/lib.rs +++ b/examples/simple/src/lib.rs @@ -64,7 +64,7 @@ fn rust_ext<'py>(m: &Bound<'py, PyModule>) -> PyResult<()> { let x = x.as_array(); let y = y.as_array(); let z = axpy(a, x, y); - z.into_pyarray_bound(py) + z.into_pyarray(py) } // wrapper of `mult` @@ -82,7 +82,7 @@ fn rust_ext<'py>(m: &Bound<'py, PyModule>) -> PyResult<()> { py: Python<'py>, x: PyReadonlyArrayDyn<'py, Complex64>, ) -> Bound<'py, PyArrayDyn> { - conj(x.as_array()).into_pyarray_bound(py) + conj(x.as_array()).into_pyarray(py) } // example of how to extract an array from a dictionary @@ -131,13 +131,13 @@ fn rust_ext<'py>(m: &Bound<'py, PyModule>) -> PyResult<()> { x.readonly().as_array(), y.readonly().as_array(), ) - .into_pyarray_bound(x.py()) + .into_pyarray(x.py()) .into_any()), (SupportedArray::I64(x), SupportedArray::I64(y)) => Ok(generic_add( x.readonly().as_array(), y.readonly().as_array(), ) - .into_pyarray_bound(x.py()) + .into_pyarray(x.py()) .into_any()), (SupportedArray::F64(x), SupportedArray::I64(y)) | (SupportedArray::I64(y), SupportedArray::F64(x)) => { @@ -145,7 +145,7 @@ fn rust_ext<'py>(m: &Bound<'py, PyModule>) -> PyResult<()> { Ok( generic_add(x.readonly().as_array(), y.readonly().as_array()) - .into_pyarray_bound(x.py()) + .into_pyarray(x.py()) .into_any(), ) } diff --git a/src/array.rs b/src/array.rs index cdaead703..81ad31045 100644 --- a/src/array.rs +++ b/src/array.rs @@ -5,7 +5,6 @@ use std::{ marker::PhantomData, mem, - ops::Deref, os::raw::{c_int, c_void}, ptr, slice, }; @@ -17,13 +16,10 @@ use ndarray::{ }; use num_traits::AsPrimitive; use pyo3::{ - ffi, pyobject_native_type_base, + ffi, types::{DerefToPyAny, PyAnyMethods, PyModule}, - AsPyPointer, Bound, DowncastError, IntoPy, Py, PyAny, PyErr, PyObject, PyResult, PyTypeInfo, - Python, + Bound, DowncastError, Py, PyAny, PyErr, PyObject, PyResult, PyTypeInfo, Python, }; -#[cfg(feature = "gil-refs")] -use pyo3::{FromPyObject, PyNativeType}; use crate::borrow::{PyReadonlyArray, PyReadwriteArray}; use crate::cold; @@ -88,7 +84,7 @@ use crate::untyped_array::{PyUntypedArray, PyUntypedArrayMethods}; /// use pyo3::Python; /// /// Python::with_gil(|py| { -/// let pyarray = PyArray::arange_bound(py, 0., 4., 1.).reshape([2, 2]).unwrap(); +/// let pyarray = PyArray::arange(py, 0., 4., 1.).reshape([2, 2]).unwrap(); /// let array = array![[3., 4.], [5., 6.]]; /// /// assert_eq!( @@ -122,7 +118,7 @@ pub type PyArrayDyn = PyArray; /// Returns a handle to NumPy's multiarray module. pub fn get_array_module<'py>(py: Python<'py>) -> PyResult> { - PyModule::import_bound(py, npyffi::array::mod_name(py)?) + PyModule::import(py, npyffi::array::mod_name(py)?) } impl DerefToPyAny for PyArray {} @@ -135,134 +131,11 @@ unsafe impl PyTypeInfo for PyArray { unsafe { npyffi::PY_ARRAY_API.get_type_object(py, npyffi::NpyTypes::PyArray_Type) } } - fn is_type_of_bound(ob: &Bound<'_, PyAny>) -> bool { + fn is_type_of(ob: &Bound<'_, PyAny>) -> bool { Self::extract::(ob).is_ok() } } -pyobject_native_type_base!(PyArray; T; D); - -impl AsRef for PyArray { - #[inline] - fn as_ref(&self) -> &PyAny { - &self.0 - } -} - -impl Deref for PyArray { - type Target = PyUntypedArray; - - #[inline] - fn deref(&self) -> &Self::Target { - self.as_untyped() - } -} - -unsafe impl AsPyPointer for PyArray { - #[inline] - fn as_ptr(&self) -> *mut ffi::PyObject { - self.0.as_ptr() - } -} - -impl IntoPy>> for &'_ PyArray { - #[inline] - fn into_py<'py>(self, py: Python<'py>) -> Py> { - unsafe { Py::from_borrowed_ptr(py, self.as_ptr()) } - } -} - -#[cfg(feature = "gil-refs")] -impl From<&'_ PyArray> for Py> { - #[inline] - fn from(other: &PyArray) -> Self { - unsafe { Py::from_borrowed_ptr(other.py(), other.as_ptr()) } - } -} - -impl<'a, T, D> From<&'a PyArray> for &'a PyAny { - fn from(ob: &'a PyArray) -> Self { - unsafe { &*(ob as *const PyArray as *const PyAny) } - } -} - -impl IntoPy for PyArray { - fn into_py<'py>(self, py: Python<'py>) -> PyObject { - unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) } - } -} - -#[cfg(feature = "gil-refs")] -impl<'py, T: Element, D: Dimension> FromPyObject<'py> for &'py PyArray { - fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { - PyArray::extract(ob).cloned().map(Bound::into_gil_ref) - } -} - -impl PyArray { - /// Access an untyped representation of this array. - #[inline(always)] - pub fn as_untyped(&self) -> &PyUntypedArray { - unsafe { &*(self as *const Self as *const PyUntypedArray) } - } -} - -#[cfg(feature = "gil-refs")] -impl PyArray { - /// Turn `&PyArray` into `Py>`, - /// i.e. a pointer into Python's heap which is independent of the GIL lifetime. - /// - /// This method can be used to avoid lifetime annotations of function arguments - /// or return values. - /// - /// # Example - /// - /// ``` - /// use numpy::{PyArray1, PyArrayMethods}; - /// use pyo3::{Py, Python}; - /// - /// let array: Py> = Python::with_gil(|py| { - /// PyArray1::zeros_bound(py, 5, false).unbind() - /// }); - /// - /// Python::with_gil(|py| { - /// assert_eq!(array.bind(py).readonly().as_slice().unwrap(), [0.0; 5]); - /// }); - /// ``` - #[deprecated(since = "0.21.0", note = "use Bound::unbind() instead")] - pub fn to_owned(&self) -> Py { - unsafe { Py::from_borrowed_ptr(self.py(), self.as_ptr()) } - } - - /// Constructs a reference to a `PyArray` from a raw pointer to a Python object. - /// - /// # Safety - /// - /// This is a wrapper around [`pyo3::FromPyPointer::from_owned_ptr_or_opt`] and inherits its safety contract. - #[deprecated(since = "0.21.0", note = "use Bound::from_owned_ptr() instead")] - pub unsafe fn from_owned_ptr<'py>(py: Python<'py>, ptr: *mut ffi::PyObject) -> &'py Self { - #![allow(deprecated)] - py.from_owned_ptr(ptr) - } - - /// Constructs a reference to a `PyArray` from a raw point to a Python object. - /// - /// # Safety - /// - /// This is a wrapper around [`pyo3::FromPyPointer::from_borrowed_ptr_or_opt`] and inherits its safety contract. - #[deprecated(since = "0.21.0", note = "use Bound::from_borrowed_ptr() instead")] - pub unsafe fn from_borrowed_ptr<'py>(py: Python<'py>, ptr: *mut ffi::PyObject) -> &'py Self { - #![allow(deprecated)] - py.from_borrowed_ptr(ptr) - } - - /// Returns a pointer to the first element of the array. - #[inline(always)] - pub fn data(&self) -> *mut T { - unsafe { (*self.as_array_ptr()).data as *mut _ } - } -} - impl PyArray { fn extract<'a, 'py, E>(ob: &'a Bound<'py, PyAny>) -> Result<&'a Bound<'py, Self>, E> where @@ -286,7 +159,7 @@ impl PyArray { // Check if the element type matches `T`. let src_dtype = array.dtype(); - let dst_dtype = T::get_dtype_bound(ob.py()); + let dst_dtype = T::get_dtype(ob.py()); if !src_dtype.is_equiv_to(&dst_dtype) { return Err(TypeError::new(src_dtype, dst_dtype).into()); } @@ -319,7 +192,7 @@ impl PyArray { /// /// Python::with_gil(|py| { /// let arr = unsafe { - /// let arr = PyArray3::::new_bound(py, [4, 5, 6], false); + /// let arr = PyArray3::::new(py, [4, 5, 6], false); /// /// for i in 0..4 { /// for j in 0..5 { @@ -335,6 +208,20 @@ impl PyArray { /// assert_eq!(arr.shape(), &[4, 5, 6]); /// }); /// ``` + pub unsafe fn new<'py, ID>(py: Python<'py>, dims: ID, is_fortran: bool) -> Bound<'py, Self> + where + ID: IntoDimension, + { + let flags = c_int::from(is_fortran); + Self::new_uninit(py, dims, ptr::null_mut(), flags) + } + + /// Deprecated name for [`PyArray::new`]. + /// + /// # Safety + /// See [`PyArray::new`]. + #[deprecated(since = "0.23.0", note = "renamed to `PyArray::new`")] + #[inline] pub unsafe fn new_bound<'py, ID>( py: Python<'py>, dims: ID, @@ -343,8 +230,7 @@ impl PyArray { where ID: IntoDimension, { - let flags = c_int::from(is_fortran); - Self::new_uninit(py, dims, ptr::null_mut(), flags) + Self::new(py, dims, is_fortran) } pub(crate) unsafe fn new_uninit<'py, ID>( @@ -360,7 +246,7 @@ impl PyArray { let ptr = PY_ARRAY_API.PyArray_NewFromDescr( py, PY_ARRAY_API.get_type_object(py, npyffi::NpyTypes::PyArray_Type), - T::get_dtype_bound(py).into_dtype_ptr(), + T::get_dtype(py).into_dtype_ptr(), dims.ndim_cint(), dims.as_dims_ptr(), strides as *mut npy_intp, // strides @@ -386,7 +272,7 @@ impl PyArray { let ptr = PY_ARRAY_API.PyArray_NewFromDescr( py, PY_ARRAY_API.get_type_object(py, npyffi::NpyTypes::PyArray_Type), - T::get_dtype_bound(py).into_dtype_ptr(), + T::get_dtype(py).into_dtype_ptr(), dims.ndim_cint(), dims.as_dims_ptr(), strides as *mut npy_intp, // strides @@ -447,11 +333,11 @@ impl PyArray { /// /// // SAFETY: The memory backing `array` will stay valid as long as this object is alive /// // as we do not modify `array` in any way which would cause it to be reallocated. - /// unsafe { PyArray1::borrow_from_array_bound(array, this.into_any()) } + /// unsafe { PyArray1::borrow_from_array(array, this.into_any()) } /// } /// } /// ``` - pub unsafe fn borrow_from_array_bound<'py, S>( + pub unsafe fn borrow_from_array<'py, S>( array: &ArrayBase, container: Bound<'py, PyAny>, ) -> Bound<'py, Self> @@ -472,6 +358,22 @@ impl PyArray { ) } + /// Deprecated name for [`PyArray::borrow_from_array`]. + /// + /// # Safety + /// See [`PyArray::borrow_from_array`] + #[deprecated(since = "0.23.0", note = "renamed to `PyArray::borrow_from_array`")] + #[inline] + pub unsafe fn borrow_from_array_bound<'py, S>( + array: &ArrayBase, + container: Bound<'py, PyAny>, + ) -> Bound<'py, Self> + where + S: Data, + { + Self::borrow_from_array(array, container) + } + /// Construct a new NumPy array filled with zeros. /// /// If `is_fortran` is true, then it has Fortran/column-major order, @@ -489,7 +391,7 @@ impl PyArray { /// use pyo3::Python; /// /// Python::with_gil(|py| { - /// let pyarray = PyArray2::::zeros_bound(py, [2, 2], true); + /// let pyarray = PyArray2::::zeros(py, [2, 2], true); /// /// assert_eq!(pyarray.readonly().as_slice().unwrap(), [0; 4]); /// }); @@ -497,7 +399,7 @@ impl PyArray { /// /// [numpy-zeros]: https://numpy.org/doc/stable/reference/generated/numpy.zeros.html /// [PyArray_Zeros]: https://numpy.org/doc/stable/reference/c-api/array.html#c.PyArray_Zeros - pub fn zeros_bound(py: Python<'_>, dims: ID, is_fortran: bool) -> Bound<'_, Self> + pub fn zeros(py: Python<'_>, dims: ID, is_fortran: bool) -> Bound<'_, Self> where ID: IntoDimension, { @@ -507,13 +409,23 @@ impl PyArray { py, dims.ndim_cint(), dims.as_dims_ptr(), - T::get_dtype_bound(py).into_dtype_ptr(), + T::get_dtype(py).into_dtype_ptr(), if is_fortran { -1 } else { 0 }, ); Bound::from_owned_ptr(py, ptr).downcast_into_unchecked() } } + /// Deprecated name for [`PyArray::zeros`]. + #[deprecated(since = "0.23.0", note = "renamed to `PyArray::zeros`")] + #[inline] + pub fn zeros_bound(py: Python<'_>, dims: ID, is_fortran: bool) -> Bound<'_, Self> + where + ID: IntoDimension, + { + Self::zeros(py, dims, is_fortran) + } + /// Constructs a NumPy from an [`ndarray::Array`] /// /// This method uses the internal [`Vec`] of the [`ndarray::Array`] as the base object of the NumPy array. @@ -526,12 +438,12 @@ impl PyArray { /// use pyo3::Python; /// /// Python::with_gil(|py| { - /// let pyarray = PyArray::from_owned_array_bound(py, array![[1, 2], [3, 4]]); + /// let pyarray = PyArray::from_owned_array(py, array![[1, 2], [3, 4]]); /// /// assert_eq!(pyarray.readonly().as_array(), array![[1, 2], [3, 4]]); /// }); /// ``` - pub fn from_owned_array_bound(py: Python<'_>, mut arr: Array) -> Bound<'_, Self> { + pub fn from_owned_array(py: Python<'_>, mut arr: Array) -> Bound<'_, Self> { let (strides, dims) = (arr.npy_strides(), arr.raw_dim()); let data_ptr = arr.as_mut_ptr(); unsafe { @@ -544,477 +456,50 @@ impl PyArray { ) } } + /// Deprecated name for [`PyArray::from_owned_array`]. + #[deprecated(since = "0.23.0", note = "renamed to `PyArray::from_owned_array`")] + #[inline] + pub fn from_owned_array_bound(py: Python<'_>, arr: Array) -> Bound<'_, Self> { + Self::from_owned_array(py, arr) + } /// Construct a NumPy array from a [`ndarray::ArrayBase`]. /// /// This method allocates memory in Python's heap via the NumPy API, - /// and then copies all elements of the array there. - /// - /// # Example - /// - /// ``` - /// use numpy::{PyArray, PyArrayMethods}; - /// use ndarray::array; - /// use pyo3::Python; - /// - /// Python::with_gil(|py| { - /// let pyarray = PyArray::from_array_bound(py, &array![[1, 2], [3, 4]]); - /// - /// assert_eq!(pyarray.readonly().as_array(), array![[1, 2], [3, 4]]); - /// }); - /// ``` - pub fn from_array_bound<'py, S>(py: Python<'py>, arr: &ArrayBase) -> Bound<'py, Self> - where - S: Data, - { - ToPyArray::to_pyarray_bound(arr, py) - } -} - -#[cfg(feature = "gil-refs")] -impl PyArray { - /// Same as [`shape`][PyUntypedArray::shape], but returns `D` instead of `&[usize]`. - #[inline(always)] - pub fn dims(&self) -> D { - D::from_dimension(&Dim(self.shape())).expect(DIMENSIONALITY_MISMATCH_ERR) - } - - /// Deprecated form of [`PyArray::new_bound`] - /// - /// # Safety - /// Same as [`PyArray::new_bound`] - #[deprecated( - since = "0.21.0", - note = "will be replaced by `PyArray::new_bound` in the future" - )] - pub unsafe fn new<'py, ID>(py: Python<'py>, dims: ID, is_fortran: bool) -> &Self - where - ID: IntoDimension, - { - Self::new_bound(py, dims, is_fortran).into_gil_ref() - } - - /// Deprecated form of [`PyArray::borrow_from_array_bound`] - /// - /// # Safety - /// Same as [`PyArray::borrow_from_array_bound`] - #[deprecated( - since = "0.21.0", - note = "will be replaced by `PyArray::borrow_from_array_bound` in the future" - )] - pub unsafe fn borrow_from_array<'py, S>( - array: &ArrayBase, - container: &'py PyAny, - ) -> &'py Self - where - S: Data, - { - Self::borrow_from_array_bound(array, (*container.as_borrowed()).clone()).into_gil_ref() - } - - /// Deprecated form of [`PyArray::zeros_bound`] - #[deprecated( - since = "0.21.0", - note = "will be replaced by `PyArray::zeros_bound` in the future" - )] - pub fn zeros<'py, ID>(py: Python<'py>, dims: ID, is_fortran: bool) -> &Self - where - ID: IntoDimension, - { - Self::zeros_bound(py, dims, is_fortran).into_gil_ref() - } - - /// Returns an immutable view of the internal data as a slice. - /// - /// # Safety - /// - /// Calling this method is undefined behaviour if the underlying array - /// is aliased mutably by other instances of `PyArray` - /// or concurrently modified by Python or other native code. - /// - /// Please consider the safe alternative [`PyReadonlyArray::as_slice`]. - pub unsafe fn as_slice(&self) -> Result<&[T], NotContiguousError> { - if self.is_contiguous() { - Ok(slice::from_raw_parts(self.data(), self.len())) - } else { - Err(NotContiguousError) - } - } - - /// Returns a mutable view of the internal data as a slice. - /// - /// # Safety - /// - /// Calling this method is undefined behaviour if the underlying array - /// is aliased immutably or mutably by other instances of [`PyArray`] - /// or concurrently modified by Python or other native code. - /// - /// Please consider the safe alternative [`PyReadwriteArray::as_slice_mut`]. - pub unsafe fn as_slice_mut(&self) -> Result<&mut [T], NotContiguousError> { - if self.is_contiguous() { - Ok(slice::from_raw_parts_mut(self.data(), self.len())) - } else { - Err(NotContiguousError) - } - } - - /// Deprecated form of [`PyArray::from_owned_array_bound`] - #[deprecated( - since = "0.21.0", - note = "will be replaced by PyArray::from_owned_array_bound in the future" - )] - pub fn from_owned_array<'py>(py: Python<'py>, arr: Array) -> &'py Self { - Self::from_owned_array_bound(py, arr).into_gil_ref() - } - - /// Get a reference of the specified element if the given index is valid. - /// - /// # Safety - /// - /// Calling this method is undefined behaviour if the underlying array - /// is aliased mutably by other instances of `PyArray` - /// or concurrently modified by Python or other native code. - /// - /// Consider using safe alternatives like [`PyReadonlyArray::get`]. - /// - /// # Example - /// - /// ``` - /// use numpy::{PyArray, PyArrayMethods}; - /// use pyo3::Python; - /// - /// Python::with_gil(|py| { - /// let pyarray = PyArray::arange_bound(py, 0, 16, 1).reshape([2, 2, 4]).unwrap(); - /// - /// assert_eq!(unsafe { *pyarray.get([1, 0, 3]).unwrap() }, 11); - /// }); - /// ``` - #[inline(always)] - pub unsafe fn get(&self, index: impl NpyIndex) -> Option<&T> { - let ptr = get_raw(&self.as_borrowed(), index)?; - Some(&*ptr) - } - - /// Same as [`get`][Self::get], but returns `Option<&mut T>`. - /// - /// # Safety - /// - /// Calling this method is undefined behaviour if the underlying array - /// is aliased immutably or mutably by other instances of [`PyArray`] - /// or concurrently modified by Python or other native code. - /// - /// Consider using safe alternatives like [`PyReadwriteArray::get_mut`]. - /// - /// # Example - /// - /// ``` - /// use numpy::{PyArray, PyArrayMethods}; - /// use pyo3::Python; - /// - /// Python::with_gil(|py| { - /// let pyarray = PyArray::arange_bound(py, 0, 16, 1).reshape([2, 2, 4]).unwrap(); - /// - /// unsafe { - /// *pyarray.get_mut([1, 0, 3]).unwrap() = 42; - /// } - /// - /// assert_eq!(unsafe { *pyarray.get([1, 0, 3]).unwrap() }, 42); - /// }); - /// ``` - #[inline(always)] - pub unsafe fn get_mut(&self, index: impl NpyIndex) -> Option<&mut T> { - let ptr = get_raw(&self.as_borrowed(), index)?; - Some(&mut *ptr) - } - - /// Get an immutable reference of the specified element, - /// without checking the given index. - /// - /// See [`NpyIndex`] for what types can be used as the index. - /// - /// # Safety - /// - /// Passing an invalid index is undefined behavior. - /// The element must also have been initialized and - /// all other references to it is must also be shared. - /// - /// See [`PyReadonlyArray::get`] for a safe alternative. - /// - /// # Example - /// - /// ``` - /// use numpy::{PyArray, PyArrayMethods}; - /// use pyo3::Python; - /// - /// Python::with_gil(|py| { - /// let pyarray = PyArray::arange_bound(py, 0, 16, 1).reshape([2, 2, 4]).unwrap(); - /// - /// assert_eq!(unsafe { *pyarray.uget([1, 0, 3]) }, 11); - /// }); - /// ``` - #[inline(always)] - pub unsafe fn uget(&self, index: Idx) -> &T - where - Idx: NpyIndex, - { - &*self.uget_raw(index) - } - - /// Same as [`uget`](Self::uget), but returns `&mut T`. - /// - /// # Safety - /// - /// Passing an invalid index is undefined behavior. - /// The element must also have been initialized and - /// other references to it must not exist. - /// - /// See [`PyReadwriteArray::get_mut`] for a safe alternative. - #[inline(always)] - #[allow(clippy::mut_from_ref)] - pub unsafe fn uget_mut(&self, index: Idx) -> &mut T - where - Idx: NpyIndex, - { - &mut *self.uget_raw(index) - } - - /// Same as [`uget`][Self::uget], but returns `*mut T`. - /// - /// # Safety - /// - /// Passing an invalid index is undefined behavior. - #[inline(always)] - pub unsafe fn uget_raw(&self, index: Idx) -> *mut T - where - Idx: NpyIndex, - { - self.as_borrowed().uget_raw(index) - } - - /// Get a copy of the specified element in the array. - /// - /// See [`NpyIndex`] for what types can be used as the index. - /// - /// # Example - /// ``` - /// use numpy::{PyArray, PyArrayMethods}; - /// use pyo3::Python; - /// - /// Python::with_gil(|py| { - /// let pyarray = PyArray::arange_bound(py, 0, 16, 1).reshape([2, 2, 4]).unwrap(); - /// - /// assert_eq!(pyarray.get_owned([1, 0, 3]), Some(11)); - /// }); - /// ``` - pub fn get_owned(&self, index: Idx) -> Option - where - Idx: NpyIndex, - { - self.as_borrowed().get_owned(index) - } - - /// Turn an array with fixed dimensionality into one with dynamic dimensionality. - pub fn to_dyn(&self) -> &PyArray { - self.as_borrowed().to_dyn().clone().into_gil_ref() - } - - /// Returns a copy of the internal data of the array as a [`Vec`]. - /// - /// Fails if the internal array is not contiguous. See also [`as_slice`][Self::as_slice]. - /// - /// # Example - /// - /// ``` - /// use numpy::{PyArray2, PyArrayMethods}; - /// use pyo3::{Python, types::PyAnyMethods}; - /// - /// Python::with_gil(|py| { - /// let pyarray= py - /// .eval_bound("__import__('numpy').array([[0, 1], [2, 3]], dtype='int64')", None, None) - /// .unwrap() - /// .downcast_into::>() - /// .unwrap(); - /// - /// assert_eq!(pyarray.to_vec().unwrap(), vec![0, 1, 2, 3]); - /// }); - /// ``` - pub fn to_vec(&self) -> Result, NotContiguousError> { - self.as_borrowed().to_vec() - } - - /// Deprecated form of [`PyArray::from_array_bound`] - #[deprecated( - since = "0.21.0", - note = "will be replaced by PyArray::from_array_bound in the future" - )] - pub fn from_array<'py, S>(py: Python<'py>, arr: &ArrayBase) -> &'py Self - where - S: Data, - { - Self::from_array_bound(py, arr).into_gil_ref() - } - - /// Get an immutable borrow of the NumPy array - pub fn try_readonly(&self) -> Result, BorrowError> { - PyReadonlyArray::try_new(self.as_borrowed().to_owned()) - } - - /// Get an immutable borrow of the NumPy array - /// - /// # Panics - /// - /// Panics if the allocation backing the array is currently mutably borrowed. - /// - /// For a non-panicking variant, use [`try_readonly`][Self::try_readonly]. - pub fn readonly(&self) -> PyReadonlyArray<'_, T, D> { - self.try_readonly().unwrap() - } - - /// Get a mutable borrow of the NumPy array - pub fn try_readwrite(&self) -> Result, BorrowError> { - PyReadwriteArray::try_new(self.as_borrowed().to_owned()) - } - - /// Get a mutable borrow of the NumPy array - /// - /// # Panics - /// - /// Panics if the allocation backing the array is currently borrowed or - /// if the array is [flagged as][flags] not writeable. - /// - /// For a non-panicking variant, use [`try_readwrite`][Self::try_readwrite]. - /// - /// [flags]: https://numpy.org/doc/stable/reference/generated/numpy.ndarray.flags.html - pub fn readwrite(&self) -> PyReadwriteArray<'_, T, D> { - self.try_readwrite().unwrap() - } - - /// Returns an [`ArrayView`] of the internal array. - /// - /// See also [`PyReadonlyArray::as_array`]. - /// - /// # Safety - /// - /// Calling this method invalidates all exclusive references to the internal data, e.g. `&mut [T]` or `ArrayViewMut`. - pub unsafe fn as_array(&self) -> ArrayView<'_, T, D> { - as_view(&self.as_borrowed(), |shape, ptr| { - ArrayView::from_shape_ptr(shape, ptr) - }) - } - - /// Returns an [`ArrayViewMut`] of the internal array. - /// - /// See also [`PyReadwriteArray::as_array_mut`]. - /// - /// # Safety - /// - /// Calling this method invalidates all other references to the internal data, e.g. `ArrayView` or `ArrayViewMut`. - pub unsafe fn as_array_mut(&self) -> ArrayViewMut<'_, T, D> { - as_view(&self.as_borrowed(), |shape, ptr| { - ArrayViewMut::from_shape_ptr(shape, ptr) - }) - } - - /// Returns the internal array as [`RawArrayView`] enabling element access via raw pointers - pub fn as_raw_array(&self) -> RawArrayView { - self.as_borrowed().as_raw_array() - } - - /// Returns the internal array as [`RawArrayViewMut`] enabling element access via raw pointers - pub fn as_raw_array_mut(&self) -> RawArrayViewMut { - self.as_borrowed().as_raw_array_mut() - } - - /// Get a copy of the array as an [`ndarray::Array`]. - /// - /// # Example - /// - /// ``` - /// use numpy::{PyArray, PyArrayMethods}; - /// use ndarray::array; - /// use pyo3::Python; - /// - /// Python::with_gil(|py| { - /// let pyarray = PyArray::arange_bound(py, 0, 4, 1).reshape([2, 2]).unwrap(); - /// - /// assert_eq!( - /// pyarray.to_owned_array(), - /// array![[0, 1], [2, 3]] - /// ) - /// }); - /// ``` - pub fn to_owned_array(&self) -> Array { - self.as_borrowed().to_owned_array() - } -} - -#[cfg(feature = "nalgebra")] -#[cfg(feature = "gil-refs")] -impl PyArray -where - N: nalgebra::Scalar + Element, - D: Dimension, -{ - /// Try to convert this array into a [`nalgebra::MatrixView`] using the given shape and strides. + /// and then copies all elements of the array there. /// - /// See [`PyReadonlyArray::try_as_matrix`] for a discussion of the memory layout requirements. + /// # Example /// - /// # Safety + /// ``` + /// use numpy::{PyArray, PyArrayMethods}; + /// use ndarray::array; + /// use pyo3::Python; /// - /// Calling this method invalidates all exclusive references to the internal data, e.g. `ArrayViewMut` or `MatrixSliceMut`. - #[doc(alias = "nalgebra")] - pub unsafe fn try_as_matrix( - &self, - ) -> Option> + /// Python::with_gil(|py| { + /// let pyarray = PyArray::from_array(py, &array![[1, 2], [3, 4]]); + /// + /// assert_eq!(pyarray.readonly().as_array(), array![[1, 2], [3, 4]]); + /// }); + /// ``` + pub fn from_array<'py, S>(py: Python<'py>, arr: &ArrayBase) -> Bound<'py, Self> where - R: nalgebra::Dim, - C: nalgebra::Dim, - RStride: nalgebra::Dim, - CStride: nalgebra::Dim, + S: Data, { - let (shape, strides) = try_as_matrix_shape_strides(&self.as_borrowed())?; - - let storage = nalgebra::ViewStorage::from_raw_parts(self.data(), shape, strides); - - Some(nalgebra::Matrix::from_data(storage)) + ToPyArray::to_pyarray(arr, py) } - /// Try to convert this array into a [`nalgebra::MatrixViewMut`] using the given shape and strides. - /// - /// See [`PyReadonlyArray::try_as_matrix`] for a discussion of the memory layout requirements. - /// - /// # Safety - /// - /// Calling this method invalidates all other references to the internal data, e.g. `ArrayView`, `MatrixSlice`, `ArrayViewMut` or `MatrixSliceMut`. - #[doc(alias = "nalgebra")] - pub unsafe fn try_as_matrix_mut( - &self, - ) -> Option> + /// Deprecated name for [`PyArray::from_array`]. + #[deprecated(since = "0.23.0", note = "renamed to `PyArray::from_array`")] + #[inline] + pub fn from_array_bound<'py, S>(py: Python<'py>, arr: &ArrayBase) -> Bound<'py, Self> where - R: nalgebra::Dim, - C: nalgebra::Dim, - RStride: nalgebra::Dim, - CStride: nalgebra::Dim, + S: Data, { - let (shape, strides) = try_as_matrix_shape_strides(&self.as_borrowed())?; - - let storage = nalgebra::ViewStorageMut::from_raw_parts(self.data(), shape, strides); - - Some(nalgebra::Matrix::from_data(storage)) + Self::from_array(py, arr) } } impl PyArray { - /// Deprecated form of [`PyArray::from_owned_object_array_bound`] - #[cfg(feature = "gil-refs")] - #[deprecated( - since = "0.21.0", - note = "will be replaced by PyArray::from_owned_object_array_bound in the future" - )] - pub fn from_owned_object_array<'py, T>(py: Python<'py>, arr: Array, D>) -> &'py Self { - Self::from_owned_object_array_bound(py, arr).into_gil_ref() - } - /// Construct a NumPy array containing objects stored in a [`ndarray::Array`] /// /// This method uses the internal [`Vec`] of the [`ndarray::Array`] as the base object of the NumPy array. @@ -1045,15 +530,12 @@ impl PyArray { /// }).unwrap(), /// ]; /// - /// let pyarray = PyArray::from_owned_object_array_bound(py, array); + /// let pyarray = PyArray::from_owned_object_array(py, array); /// /// assert!(pyarray.readonly().as_array().get(0).unwrap().bind(py).is_instance_of::()); /// }); /// ``` - pub fn from_owned_object_array_bound( - py: Python<'_>, - mut arr: Array, D>, - ) -> Bound<'_, Self> { + pub fn from_owned_object_array(py: Python<'_>, mut arr: Array, D>) -> Bound<'_, Self> { let (strides, dims) = (arr.npy_strides(), arr.raw_dim()); let data_ptr = arr.as_mut_ptr() as *const PyObject; unsafe { @@ -1066,15 +548,18 @@ impl PyArray { ) } } -} -#[cfg(feature = "gil-refs")] -impl PyArray { - /// Get the single element of a zero-dimensional array. - /// - /// See [`inner`][crate::inner] for an example. - pub fn item(&self) -> T { - self.as_borrowed().item() + /// Deprecated name for [`PyArray::from_owned_object_array`]. + #[deprecated( + since = "0.23.0", + note = "renamed to `PyArray::from_owned_object_array`" + )] + #[inline] + pub fn from_owned_object_array_bound( + py: Python<'_>, + arr: Array, D>, + ) -> Bound<'_, Self> { + Self::from_owned_object_array(py, arr) } } @@ -1089,19 +574,26 @@ impl PyArray { /// /// Python::with_gil(|py| { /// let slice = &[1, 2, 3, 4, 5]; - /// let pyarray = PyArray::from_slice_bound(py, slice); + /// let pyarray = PyArray::from_slice(py, slice); /// assert_eq!(pyarray.readonly().as_slice().unwrap(), &[1, 2, 3, 4, 5]); /// }); /// ``` - pub fn from_slice_bound<'py>(py: Python<'py>, slice: &[T]) -> Bound<'py, Self> { + pub fn from_slice<'py>(py: Python<'py>, slice: &[T]) -> Bound<'py, Self> { unsafe { - let array = PyArray::new_bound(py, [slice.len()], false); + let array = PyArray::new(py, [slice.len()], false); let mut data_ptr = array.data(); clone_elements(py, slice, &mut data_ptr); array } } + /// Deprecated name for [`PyArray::from_slice`]. + #[deprecated(since = "0.23.0", note = "renamed to `PyArray::from_slice`")] + #[inline] + pub fn from_slice_bound<'py>(py: Python<'py>, slice: &[T]) -> Bound<'py, Self> { + Self::from_slice(py, slice) + } + /// Construct a one-dimensional array from a [`Vec`][Vec]. /// /// # Example @@ -1112,13 +604,20 @@ impl PyArray { /// /// Python::with_gil(|py| { /// let vec = vec![1, 2, 3, 4, 5]; - /// let pyarray = PyArray::from_vec_bound(py, vec); + /// let pyarray = PyArray::from_vec(py, vec); /// assert_eq!(pyarray.readonly().as_slice().unwrap(), &[1, 2, 3, 4, 5]); /// }); /// ``` #[inline(always)] + pub fn from_vec<'py>(py: Python<'py>, vec: Vec) -> Bound<'py, Self> { + vec.into_pyarray(py) + } + + /// Deprecated name for [`PyArray::from_vec`]. + #[deprecated(since = "0.23.0", note = "renamed to `PyArray::from_vec`")] + #[inline] pub fn from_vec_bound<'py>(py: Python<'py>, vec: Vec) -> Bound<'py, Self> { - vec.into_pyarray_bound(py) + Self::from_vec(py, vec) } /// Construct a one-dimensional array from an [`Iterator`]. @@ -1133,64 +632,30 @@ impl PyArray { /// use pyo3::Python; /// /// Python::with_gil(|py| { - /// let pyarray = PyArray::from_iter_bound(py, "abcde".chars().map(u32::from)); + /// let pyarray = PyArray::from_iter(py, "abcde".chars().map(u32::from)); /// assert_eq!(pyarray.readonly().as_slice().unwrap(), &[97, 98, 99, 100, 101]); /// }); /// ``` - pub fn from_iter_bound(py: Python<'_>, iter: I) -> Bound<'_, Self> + pub fn from_iter(py: Python<'_>, iter: I) -> Bound<'_, Self> where I: IntoIterator, { let data = iter.into_iter().collect::>(); - data.into_pyarray_bound(py) - } -} - -#[cfg(feature = "gil-refs")] -impl PyArray { - /// Deprecated form of [`PyArray::from_slice_bound`] - #[deprecated( - since = "0.21.0", - note = "will be replaced by `PyArray::from_slice_bound` in the future" - )] - pub fn from_slice<'py>(py: Python<'py>, slice: &[T]) -> &'py Self { - Self::from_slice_bound(py, slice).into_gil_ref() - } - - /// Deprecated form of [`PyArray::from_vec_bound`] - #[inline(always)] - #[deprecated( - since = "0.21.0", - note = "will be replaced by `PyArray::from_vec_bound` in the future" - )] - pub fn from_vec<'py>(py: Python<'py>, vec: Vec) -> &'py Self { - Self::from_vec_bound(py, vec).into_gil_ref() + data.into_pyarray(py) } - /// Deprecated form of [`PyArray::from_iter_bound`] - #[deprecated( - since = "0.21.0", - note = "will be replaced by PyArray::from_iter_bound in the future" - )] - pub fn from_iter<'py, I>(py: Python<'py>, iter: I) -> &'py Self + /// Deprecated name for [`PyArray::from_iter`]. + #[deprecated(since = "0.23.0", note = "renamed to `PyArray::from_iter`")] + #[inline] + pub fn from_iter_bound(py: Python<'_>, iter: I) -> Bound<'_, Self> where I: IntoIterator, { - Self::from_iter_bound(py, iter).into_gil_ref() + Self::from_iter(py, iter) } } impl PyArray { - /// Deprecated form of [`PyArray::from_vec2_bound`] - #[cfg(feature = "gil-refs")] - #[deprecated( - since = "0.21.0", - note = "will be replaced by `PyArray::from_vec2_bound` in the future" - )] - pub fn from_vec2<'py>(py: Python<'py>, v: &[Vec]) -> Result<&'py Self, FromVecError> { - Self::from_vec2_bound(py, v).map(Bound::into_gil_ref) - } - /// Construct a two-dimension array from a [`Vec>`][Vec]. /// /// This function checks all dimensions of the inner vectors and returns @@ -1205,22 +670,19 @@ impl PyArray { /// /// Python::with_gil(|py| { /// let vec2 = vec![vec![11, 12], vec![21, 22]]; - /// let pyarray = PyArray::from_vec2_bound(py, &vec2).unwrap(); + /// let pyarray = PyArray::from_vec2(py, &vec2).unwrap(); /// assert_eq!(pyarray.readonly().as_array(), array![[11, 12], [21, 22]]); /// /// let ragged_vec2 = vec![vec![11, 12], vec![21]]; - /// assert!(PyArray::from_vec2_bound(py, &ragged_vec2).is_err()); + /// assert!(PyArray::from_vec2(py, &ragged_vec2).is_err()); /// }); /// ``` - pub fn from_vec2_bound<'py>( - py: Python<'py>, - v: &[Vec], - ) -> Result, FromVecError> { + pub fn from_vec2<'py>(py: Python<'py>, v: &[Vec]) -> Result, FromVecError> { let len2 = v.first().map_or(0, |v| v.len()); let dims = [v.len(), len2]; // SAFETY: The result of `Self::new` is always safe to drop. unsafe { - let array = Self::new_bound(py, dims, false); + let array = Self::new(py, dims, false); let mut data_ptr = array.data(); for v in v { if v.len() != len2 { @@ -1232,19 +694,19 @@ impl PyArray { Ok(array) } } -} -impl PyArray { - /// Deprecated form of [`PyArray::from_vec3_bound`] - #[cfg(feature = "gil-refs")] - #[deprecated( - since = "0.21.0", - note = "will be replaced by `PyArray::from_vec3_bound` in the future" - )] - pub fn from_vec3<'py>(py: Python<'py>, v: &[Vec>]) -> Result<&'py Self, FromVecError> { - Self::from_vec3_bound(py, v).map(Bound::into_gil_ref) + /// Deprecated name for [`PyArray::from_vec2`]. + #[deprecated(since = "0.23.0", note = "renamed to `PyArray::from_vec2`")] + #[inline] + pub fn from_vec2_bound<'py>( + py: Python<'py>, + v: &[Vec], + ) -> Result, FromVecError> { + Self::from_vec2(py, v) } +} +impl PyArray { /// Construct a three-dimensional array from a [`Vec>>`][Vec]. /// /// This function checks all dimensions of the inner vectors and returns @@ -1262,7 +724,7 @@ impl PyArray { /// vec![vec![111, 112], vec![121, 122]], /// vec![vec![211, 212], vec![221, 222]], /// ]; - /// let pyarray = PyArray::from_vec3_bound(py, &vec3).unwrap(); + /// let pyarray = PyArray::from_vec3(py, &vec3).unwrap(); /// assert_eq!( /// pyarray.readonly().as_array(), /// array![[[111, 112], [121, 122]], [[211, 212], [221, 222]]] @@ -1272,10 +734,10 @@ impl PyArray { /// vec![vec![111, 112], vec![121, 122]], /// vec![vec![211], vec![221, 222]], /// ]; - /// assert!(PyArray::from_vec3_bound(py, &ragged_vec3).is_err()); + /// assert!(PyArray::from_vec3(py, &ragged_vec3).is_err()); /// }); /// ``` - pub fn from_vec3_bound<'py>( + pub fn from_vec3<'py>( py: Python<'py>, v: &[Vec>], ) -> Result, FromVecError> { @@ -1284,7 +746,7 @@ impl PyArray { let dims = [v.len(), len2, len3]; // SAFETY: The result of `Self::new` is always safe to drop. unsafe { - let array = Self::new_bound(py, dims, false); + let array = Self::new(py, dims, false); let mut data_ptr = array.data(); for v in v { if v.len() != len2 { @@ -1302,190 +764,19 @@ impl PyArray { Ok(array) } } -} - -#[cfg(feature = "gil-refs")] -impl PyArray { - /// Copies `self` into `other`, performing a data type conversion if necessary. - /// - /// See also [`PyArray_CopyInto`][PyArray_CopyInto]. - /// - /// # Example - /// - /// ``` - /// use numpy::{PyArray, PyArrayMethods}; - /// use pyo3::Python; - /// - /// Python::with_gil(|py| { - /// let pyarray_f = PyArray::arange_bound(py, 2.0, 5.0, 1.0); - /// let pyarray_i = unsafe { PyArray::::new_bound(py, [3], false) }; - /// - /// assert!(pyarray_f.copy_to(&pyarray_i).is_ok()); - /// - /// assert_eq!(pyarray_i.readonly().as_slice().unwrap(), &[2, 3, 4]); - /// }); - /// ``` - /// - /// [PyArray_CopyInto]: https://numpy.org/doc/stable/reference/c-api/array.html#c.PyArray_CopyInto - pub fn copy_to(&self, other: &PyArray) -> PyResult<()> { - self.as_borrowed().copy_to(&other.as_borrowed()) - } - - /// Cast the `PyArray` to `PyArray`, by allocating a new array. - /// - /// See also [`PyArray_CastToType`][PyArray_CastToType]. - /// - /// # Example - /// - /// ``` - /// use numpy::{PyArray, PyArrayMethods}; - /// use pyo3::Python; - /// - /// Python::with_gil(|py| { - /// let pyarray_f = PyArray::arange_bound(py, 2.0, 5.0, 1.0); - /// - /// let pyarray_i = pyarray_f.cast::(false).unwrap(); - /// - /// assert_eq!(pyarray_i.readonly().as_slice().unwrap(), &[2, 3, 4]); - /// }); - /// ``` - /// - /// [PyArray_CastToType]: https://numpy.org/doc/stable/reference/c-api/array.html#c.PyArray_CastToType - pub fn cast<'py, U: Element>(&'py self, is_fortran: bool) -> PyResult<&'py PyArray> { - self.as_borrowed().cast(is_fortran).map(Bound::into_gil_ref) - } - - /// A view of `self` with a different order of axes determined by `axes`. - /// - /// If `axes` is `None`, the order of axes is reversed which corresponds to the standard matrix transpose. - /// - /// See also [`numpy.transpose`][numpy-transpose] and [`PyArray_Transpose`][PyArray_Transpose]. - /// - /// # Example - /// - /// ``` - /// use numpy::prelude::*; - /// use numpy::PyArray; - /// use pyo3::Python; - /// use ndarray::array; - /// - /// Python::with_gil(|py| { - /// let array = array![[0, 1, 2], [3, 4, 5]].into_pyarray(py); - /// - /// let array = array.permute(Some([1, 0])).unwrap(); - /// - /// assert_eq!(array.readonly().as_array(), array![[0, 3], [1, 4], [2, 5]]); - /// }); - /// ``` - /// - /// [numpy-transpose]: https://numpy.org/doc/stable/reference/generated/numpy.transpose.html - /// [PyArray_Transpose]: https://numpy.org/doc/stable/reference/c-api/array.html#c.PyArray_Transpose - pub fn permute<'py, ID: IntoDimension>( - &'py self, - axes: Option, - ) -> PyResult<&'py PyArray> { - self.as_borrowed().permute(axes).map(Bound::into_gil_ref) - } - - /// Special case of [`permute`][Self::permute] which reverses the order the axes. - pub fn transpose<'py>(&'py self) -> PyResult<&'py PyArray> { - self.as_borrowed().transpose().map(Bound::into_gil_ref) - } - - /// Construct a new array which has same values as self, - /// but has different dimensions specified by `shape` - /// and a possibly different memory order specified by `order`. - /// - /// See also [`numpy.reshape`][numpy-reshape] and [`PyArray_Newshape`][PyArray_Newshape]. - /// - /// # Example - /// - /// ``` - /// use numpy::prelude::*; - /// use numpy::{npyffi::NPY_ORDER, PyArray}; - /// use pyo3::Python; - /// use ndarray::array; - /// - /// Python::with_gil(|py| { - /// let array = - /// PyArray::from_iter_bound(py, 0..9).reshape_with_order([3, 3], NPY_ORDER::NPY_FORTRANORDER).unwrap(); - /// - /// assert_eq!(array.readonly().as_array(), array![[0, 3, 6], [1, 4, 7], [2, 5, 8]]); - /// assert!(array.is_fortran_contiguous()); - /// - /// assert!(array.reshape([5]).is_err()); - /// }); - /// ``` - /// - /// [numpy-reshape]: https://numpy.org/doc/stable/reference/generated/numpy.reshape.html - /// [PyArray_Newshape]: https://numpy.org/doc/stable/reference/c-api/array.html#c.PyArray_Newshape - pub fn reshape_with_order<'py, ID: IntoDimension>( - &'py self, - shape: ID, - order: NPY_ORDER, - ) -> PyResult<&'py PyArray> { - self.as_borrowed() - .reshape_with_order(shape, order) - .map(Bound::into_gil_ref) - } - - /// Special case of [`reshape_with_order`][Self::reshape_with_order] which keeps the memory order the same. - #[inline(always)] - pub fn reshape<'py, ID: IntoDimension>( - &'py self, - shape: ID, - ) -> PyResult<&'py PyArray> { - self.as_borrowed().reshape(shape).map(Bound::into_gil_ref) - } - /// Extends or truncates the dimensions of an array. - /// - /// This method works only on [contiguous][PyUntypedArray::is_contiguous] arrays. - /// Missing elements will be initialized as if calling [`zeros`][Self::zeros]. - /// - /// See also [`ndarray.resize`][ndarray-resize] and [`PyArray_Resize`][PyArray_Resize]. - /// - /// # Safety - /// - /// There should be no outstanding references (shared or exclusive) into the array - /// as this method might re-allocate it and thereby invalidate all pointers into it. - /// - /// # Example - /// - /// ``` - /// use numpy::prelude::*; - /// use numpy::PyArray; - /// use pyo3::Python; - /// - /// Python::with_gil(|py| { - /// let pyarray = PyArray::::zeros_bound(py, (10, 10), false); - /// assert_eq!(pyarray.shape(), [10, 10]); - /// - /// unsafe { - /// pyarray.resize((100, 100)).unwrap(); - /// } - /// assert_eq!(pyarray.shape(), [100, 100]); - /// }); - /// ``` - /// - /// [ndarray-resize]: https://numpy.org/doc/stable/reference/generated/numpy.ndarray.resize.html - /// [PyArray_Resize]: https://numpy.org/doc/stable/reference/c-api/array.html#c.PyArray_Resize - pub unsafe fn resize(&self, newshape: ID) -> PyResult<()> { - self.as_borrowed().resize(newshape) + /// Deprecated name for [`PyArray::from_vec3`]. + #[deprecated(since = "0.23.0", note = "renamed to `PyArray::from_vec3`")] + #[inline] + pub fn from_vec3_bound<'py>( + py: Python<'py>, + v: &[Vec>], + ) -> Result, FromVecError> { + Self::from_vec3(py, v) } } impl> PyArray { - /// Deprecated form of [`PyArray::arange_bound`] - #[cfg(feature = "gil-refs")] - #[deprecated( - since = "0.21.0", - note = "will be replaced by PyArray::arange_bound in the future" - )] - pub fn arange<'py>(py: Python<'py>, start: T, stop: T, step: T) -> &Self { - Self::arange_bound(py, start, stop, step).into_gil_ref() - } - /// Return evenly spaced values within a given interval. /// /// See [numpy.arange][numpy.arange] for the Python API and [PyArray_Arange][PyArray_Arange] for the C API. @@ -1497,28 +788,35 @@ impl> PyArray { /// use pyo3::Python; /// /// Python::with_gil(|py| { - /// let pyarray = PyArray::arange_bound(py, 2.0, 4.0, 0.5); + /// let pyarray = PyArray::arange(py, 2.0, 4.0, 0.5); /// assert_eq!(pyarray.readonly().as_slice().unwrap(), &[2.0, 2.5, 3.0, 3.5]); /// - /// let pyarray = PyArray::arange_bound(py, -2, 4, 3); + /// let pyarray = PyArray::arange(py, -2, 4, 3); /// assert_eq!(pyarray.readonly().as_slice().unwrap(), &[-2, 1]); /// }); /// ``` /// /// [numpy.arange]: https://numpy.org/doc/stable/reference/generated/numpy.arange.html /// [PyArray_Arange]: https://numpy.org/doc/stable/reference/c-api/array.html#c.PyArray_Arange - pub fn arange_bound<'py>(py: Python<'py>, start: T, stop: T, step: T) -> Bound<'py, Self> { + pub fn arange<'py>(py: Python<'py>, start: T, stop: T, step: T) -> Bound<'py, Self> { unsafe { let ptr = PY_ARRAY_API.PyArray_Arange( py, start.as_(), stop.as_(), step.as_(), - T::get_dtype_bound(py).num(), + T::get_dtype(py).num(), ); Bound::from_owned_ptr(py, ptr).downcast_into_unchecked() } } + + /// Deprecated name for [`PyArray::arange`]. + #[deprecated(since = "0.23.0", note = "renamed to `PyArray::arange`")] + #[inline] + pub fn arange_bound<'py>(py: Python<'py>, start: T, stop: T, step: T) -> Bound<'py, Self> { + Self::arange(py, start, stop, step) + } } unsafe fn clone_elements(py: Python<'_>, elems: &[T], data_ptr: &mut *mut T) { @@ -1610,7 +908,7 @@ pub trait PyArrayMethods<'py, T, D>: PyUntypedArrayMethods<'py> { /// use pyo3::Python; /// /// Python::with_gil(|py| { - /// let pyarray = PyArray::arange_bound(py, 0, 16, 1).reshape([2, 2, 4]).unwrap(); + /// let pyarray = PyArray::arange(py, 0, 16, 1).reshape([2, 2, 4]).unwrap(); /// /// assert_eq!(unsafe { *pyarray.get([1, 0, 3]).unwrap() }, 11); /// }); @@ -1637,7 +935,7 @@ pub trait PyArrayMethods<'py, T, D>: PyUntypedArrayMethods<'py> { /// use pyo3::Python; /// /// Python::with_gil(|py| { - /// let pyarray = PyArray::arange_bound(py, 0, 16, 1).reshape([2, 2, 4]).unwrap(); + /// let pyarray = PyArray::arange(py, 0, 16, 1).reshape([2, 2, 4]).unwrap(); /// /// unsafe { /// *pyarray.get_mut([1, 0, 3]).unwrap() = 42; @@ -1671,7 +969,7 @@ pub trait PyArrayMethods<'py, T, D>: PyUntypedArrayMethods<'py> { /// use pyo3::Python; /// /// Python::with_gil(|py| { - /// let pyarray = PyArray::arange_bound(py, 0, 16, 1).reshape([2, 2, 4]).unwrap(); + /// let pyarray = PyArray::arange(py, 0, 16, 1).reshape([2, 2, 4]).unwrap(); /// /// assert_eq!(unsafe { *pyarray.uget([1, 0, 3]) }, 11); /// }); @@ -1732,7 +1030,7 @@ pub trait PyArrayMethods<'py, T, D>: PyUntypedArrayMethods<'py> { /// use pyo3::Python; /// /// Python::with_gil(|py| { - /// let pyarray = PyArray::arange_bound(py, 0, 16, 1).reshape([2, 2, 4]).unwrap(); + /// let pyarray = PyArray::arange(py, 0, 16, 1).reshape([2, 2, 4]).unwrap(); /// /// assert_eq!(pyarray.get_owned([1, 0, 3]), Some(11)); /// }); @@ -1757,17 +1055,18 @@ pub trait PyArrayMethods<'py, T, D>: PyUntypedArrayMethods<'py> { /// /// ``` /// use numpy::{PyArray2, PyArrayMethods}; - /// use pyo3::{Python, types::PyAnyMethods}; + /// use pyo3::{Python, types::PyAnyMethods, ffi::c_str}; /// + /// # fn main() -> pyo3::PyResult<()> { /// Python::with_gil(|py| { /// let pyarray= py - /// .eval_bound("__import__('numpy').array([[0, 1], [2, 3]], dtype='int64')", None, None) - /// .unwrap() - /// .downcast_into::>() - /// .unwrap(); + /// .eval(c_str!("__import__('numpy').array([[0, 1], [2, 3]], dtype='int64')"), None, None)? + /// .downcast_into::>()?; /// - /// assert_eq!(pyarray.to_vec().unwrap(), vec![0, 1, 2, 3]); - /// }); + /// assert_eq!(pyarray.to_vec()?, vec![0, 1, 2, 3]); + /// # Ok(()) + /// }) + /// # } /// ``` fn to_vec(&self) -> Result, NotContiguousError> where @@ -1865,7 +1164,7 @@ pub trait PyArrayMethods<'py, T, D>: PyUntypedArrayMethods<'py> { /// use pyo3::Python; /// /// Python::with_gil(|py| { - /// let pyarray = PyArray::arange_bound(py, 0, 4, 1).reshape([2, 2]).unwrap(); + /// let pyarray = PyArray::arange(py, 0, 4, 1).reshape([2, 2]).unwrap(); /// /// assert_eq!( /// pyarray.to_owned_array(), @@ -1889,8 +1188,8 @@ pub trait PyArrayMethods<'py, T, D>: PyUntypedArrayMethods<'py> { /// use pyo3::Python; /// /// Python::with_gil(|py| { - /// let pyarray_f = PyArray::arange_bound(py, 2.0, 5.0, 1.0); - /// let pyarray_i = unsafe { PyArray::::new_bound(py, [3], false) }; + /// let pyarray_f = PyArray::arange(py, 2.0, 5.0, 1.0); + /// let pyarray_i = unsafe { PyArray::::new(py, [3], false) }; /// /// assert!(pyarray_f.copy_to(&pyarray_i).is_ok()); /// @@ -1914,7 +1213,7 @@ pub trait PyArrayMethods<'py, T, D>: PyUntypedArrayMethods<'py> { /// use pyo3::Python; /// /// Python::with_gil(|py| { - /// let pyarray_f = PyArray::arange_bound(py, 2.0, 5.0, 1.0); + /// let pyarray_f = PyArray::arange(py, 2.0, 5.0, 1.0); /// /// let pyarray_i = pyarray_f.cast::(false).unwrap(); /// @@ -1942,7 +1241,7 @@ pub trait PyArrayMethods<'py, T, D>: PyUntypedArrayMethods<'py> { /// use ndarray::array; /// /// Python::with_gil(|py| { - /// let array = array![[0, 1, 2], [3, 4, 5]].into_pyarray_bound(py); + /// let array = array![[0, 1, 2], [3, 4, 5]].into_pyarray(py); /// /// let array = array.permute(Some([1, 0])).unwrap(); /// @@ -1980,7 +1279,7 @@ pub trait PyArrayMethods<'py, T, D>: PyUntypedArrayMethods<'py> { /// /// Python::with_gil(|py| { /// let array = - /// PyArray::from_iter_bound(py, 0..9).reshape_with_order([3, 3], NPY_ORDER::NPY_FORTRANORDER).unwrap(); + /// PyArray::from_iter(py, 0..9).reshape_with_order([3, 3], NPY_ORDER::NPY_FORTRANORDER).unwrap(); /// /// assert_eq!(array.readonly().as_array(), array![[0, 3, 6], [1, 4, 7], [2, 5, 8]]); /// assert!(array.is_fortran_contiguous()); @@ -2011,7 +1310,7 @@ pub trait PyArrayMethods<'py, T, D>: PyUntypedArrayMethods<'py> { /// Extends or truncates the dimensions of an array. /// /// This method works only on [contiguous][PyUntypedArrayMethods::is_contiguous] arrays. - /// Missing elements will be initialized as if calling [`zeros`][PyArray::zeros_bound]. + /// Missing elements will be initialized as if calling [`zeros`][PyArray::zeros]. /// /// See also [`ndarray.resize`][ndarray-resize] and [`PyArray_Resize`][PyArray_Resize]. /// @@ -2028,7 +1327,7 @@ pub trait PyArrayMethods<'py, T, D>: PyUntypedArrayMethods<'py> { /// use pyo3::Python; /// /// Python::with_gil(|py| { - /// let pyarray = PyArray::::zeros_bound(py, (10, 10), false); + /// let pyarray = PyArray::::zeros(py, (10, 10), false); /// assert_eq!(pyarray.shape(), [10, 10]); /// /// unsafe { @@ -2358,7 +1657,7 @@ impl<'py, T, D> PyArrayMethods<'py, T, D> for Bound<'py, PyArray> { PY_ARRAY_API.PyArray_CastToType( self.py(), self.as_array_ptr(), - U::get_dtype_bound(self.py()).into_dtype_ptr(), + U::get_dtype(self.py()).into_dtype_ptr(), if is_fortran { -1 } else { 0 }, ) }; @@ -2476,7 +1775,7 @@ mod tests { #[test] fn test_dyn_to_owned_array() { Python::with_gil(|py| { - let array = PyArray::from_vec2_bound(py, &[vec![1, 2], vec![3, 4]]) + let array = PyArray::from_vec2(py, &[vec![1, 2], vec![3, 4]]) .unwrap() .to_dyn() .to_owned_array(); @@ -2489,7 +1788,7 @@ mod tests { fn test_hasobject_flag() { Python::with_gil(|py| { let array: Bound<'_, PyArray> = - PyArray1::from_slice_bound(py, &[PyList::empty_bound(py).into()]); + PyArray1::from_slice(py, &[PyList::empty(py).into()]); py_run!(py, array, "assert array.dtype.hasobject"); }); diff --git a/src/array_like.rs b/src/array_like.rs index 7f7749477..1c7a0b36b 100644 --- a/src/array_like.rs +++ b/src/array_like.rs @@ -154,7 +154,7 @@ where let array = Array1::from(vec) .into_dimensionality() .expect("D being compatible to Ix1") - .into_pyarray_bound(py) + .into_pyarray(py) .readonly(); return Ok(Self(array, PhantomData)); } @@ -169,8 +169,8 @@ where .bind(py); let kwargs = if C::VAL { - let kwargs = PyDict::new_bound(py); - kwargs.set_item(intern!(py, "dtype"), T::get_dtype_bound(py))?; + let kwargs = PyDict::new(py); + kwargs.set_item(intern!(py, "dtype"), T::get_dtype(py))?; Some(kwargs) } else { None diff --git a/src/borrow/mod.rs b/src/borrow/mod.rs index bcfb4028c..de709c193 100644 --- a/src/borrow/mod.rs +++ b/src/borrow/mod.rs @@ -41,9 +41,9 @@ //! } //! //! Python::with_gil(|py| { -//! let x = PyArray1::::zeros_bound(py, 42, false); -//! let y = PyArray1::::zeros_bound(py, 42, false); -//! let z = PyArray1::::zeros_bound(py, 42, false); +//! let x = PyArray1::::zeros(py, 42, false); +//! let y = PyArray1::::zeros(py, 42, false); +//! let z = PyArray1::::zeros(py, 42, false); //! //! // Will work as the three arrays are distinct. //! add(&x, &y, &z); @@ -63,16 +63,17 @@ //! //! ```rust //! use numpy::{PyArray1, PyArrayMethods}; -//! use pyo3::{types::{IntoPyDict, PyAnyMethods}, Python}; +//! use pyo3::{types::{IntoPyDict, PyAnyMethods}, Python, ffi::c_str}; //! +//! # fn main() -> pyo3::PyResult<()> { //! Python::with_gil(|py| { -//! let array = PyArray1::arange_bound(py, 0.0, 10.0, 1.0); -//! let locals = [("array", array)].into_py_dict_bound(py); +//! let array = PyArray1::arange(py, 0.0, 10.0, 1.0); +//! let locals = [("array", array)].into_py_dict(py)?; //! -//! let view1 = py.eval_bound("array[:5]", None, Some(&locals)).unwrap().downcast_into::>().unwrap(); -//! let view2 = py.eval_bound("array[5:]", None, Some(&locals)).unwrap().downcast_into::>().unwrap(); -//! let view3 = py.eval_bound("array[::2]", None, Some(&locals)).unwrap().downcast_into::>().unwrap(); -//! let view4 = py.eval_bound("array[1::2]", None, Some(&locals)).unwrap().downcast_into::>().unwrap(); +//! let view1 = py.eval(c_str!("array[:5]"), None, Some(&locals))?.downcast_into::>()?; +//! let view2 = py.eval(c_str!("array[5:]"), None, Some(&locals))?.downcast_into::>()?; +//! let view3 = py.eval(c_str!("array[::2]"), None, Some(&locals))?.downcast_into::>()?; +//! let view4 = py.eval(c_str!("array[1::2]"), None, Some(&locals))?.downcast_into::>()?; //! //! { //! let _view1 = view1.readwrite(); @@ -83,7 +84,9 @@ //! let _view3 = view3.readwrite(); //! let _view4 = view4.readwrite(); //! } -//! }); +//! # Ok(()) +//! }) +//! # } //! ``` //! //! The third example shows that some views are incorrectly rejected since the borrows are over-approximated. @@ -92,14 +95,15 @@ //! # use std::panic::{catch_unwind, AssertUnwindSafe}; //! # //! use numpy::{PyArray2, PyArrayMethods}; -//! use pyo3::{types::{IntoPyDict, PyAnyMethods}, Python}; +//! use pyo3::{types::{IntoPyDict, PyAnyMethods}, Python, ffi::c_str}; //! +//! # fn main() -> pyo3::PyResult<()> { //! Python::with_gil(|py| { -//! let array = PyArray2::::zeros_bound(py, (10, 10), false); -//! let locals = [("array", array)].into_py_dict_bound(py); +//! let array = PyArray2::::zeros(py, (10, 10), false); +//! let locals = [("array", array)].into_py_dict(py)?; //! -//! let view1 = py.eval_bound("array[:, ::3]", None, Some(&locals)).unwrap().downcast_into::>().unwrap(); -//! let view2 = py.eval_bound("array[:, 1::3]", None, Some(&locals)).unwrap().downcast_into::>().unwrap(); +//! let view1 = py.eval(c_str!("array[:, ::3]"), None, Some(&locals))?.downcast_into::>()?; +//! let view2 = py.eval(c_str!("array[:, 1::3]"), None, Some(&locals))?.downcast_into::>()?; //! //! // A false conflict as the views do not actually share any elements. //! let res = catch_unwind(AssertUnwindSafe(|| { @@ -107,7 +111,9 @@ //! let _view2 = view2.readwrite(); //! })); //! assert!(res.is_err()); -//! }); +//! # Ok(()) +//! }) +//! # } //! ``` //! //! # Rationale @@ -289,7 +295,7 @@ where /// /// ```rust /// # use pyo3::prelude::*; - /// use pyo3::py_run; + /// use pyo3::{py_run, ffi::c_str}; /// use numpy::{get_array_module, PyReadonlyArray2}; /// use nalgebra::{MatrixView, Const, Dyn}; /// @@ -305,17 +311,20 @@ where /// matrix.map(|matrix| matrix.sum()) /// } /// + /// # fn main() -> pyo3::PyResult<()> { /// Python::with_gil(|py| { - /// let np = py.eval_bound("__import__('numpy')", None, None).unwrap(); - /// let sum_standard_layout = wrap_pyfunction!(sum_standard_layout)(py).unwrap(); - /// let sum_dynamic_strides = wrap_pyfunction!(sum_dynamic_strides)(py).unwrap(); + /// let np = py.eval(c_str!("__import__('numpy')"), None, None)?; + /// let sum_standard_layout = wrap_pyfunction!(sum_standard_layout)(py)?; + /// let sum_dynamic_strides = wrap_pyfunction!(sum_dynamic_strides)(py)?; /// /// py_run!(py, np sum_standard_layout, r"assert sum_standard_layout(np.ones((2, 2), order='F')) == 4."); /// py_run!(py, np sum_standard_layout, r"assert sum_standard_layout(np.ones((2, 2, 2))[:,:,0]) is None"); /// /// py_run!(py, np sum_dynamic_strides, r"assert sum_dynamic_strides(np.ones((2, 2), order='F')) == 4."); /// py_run!(py, np sum_dynamic_strides, r"assert sum_dynamic_strides(np.ones((2, 2, 2))[:,:,0]) == 4."); - /// }); + /// # Ok(()) + /// }) + /// # } /// ``` #[doc(alias = "nalgebra")] pub fn try_as_matrix( @@ -596,7 +605,7 @@ where /// use pyo3::Python; /// /// Python::with_gil(|py| { - /// let pyarray = PyArray::arange_bound(py, 0, 10, 1); + /// let pyarray = PyArray::arange(py, 0, 10, 1); /// assert_eq!(pyarray.len(), 10); /// /// let pyarray = pyarray.readwrite(); @@ -654,11 +663,12 @@ mod tests { use pyo3::{types::IntoPyDict, Python}; use crate::array::PyArray1; + use pyo3::ffi::c_str; #[test] fn test_debug_formatting() { Python::with_gil(|py| { - let array = PyArray::::zeros_bound(py, (1, 2, 3), false); + let array = PyArray::::zeros(py, (1, 2, 3), false); { let shared = array.readonly(); @@ -684,7 +694,7 @@ mod tests { #[should_panic(expected = "AlreadyBorrowed")] fn cannot_clone_exclusive_borrow_via_deref() { Python::with_gil(|py| { - let array = PyArray::::zeros_bound(py, (3, 2, 1), false); + let array = PyArray::::zeros(py, (3, 2, 1), false); let exclusive = array.readwrite(); let _shared = exclusive.clone(); @@ -694,12 +704,12 @@ mod tests { #[test] fn failed_resize_does_not_double_release() { Python::with_gil(|py| { - let array = PyArray::::zeros_bound(py, 10, false); + let array = PyArray::::zeros(py, 10, false); // The view will make the internal reference check of `PyArray_Resize` fail. - let locals = [("array", &array)].into_py_dict_bound(py); + let locals = [("array", &array)].into_py_dict(py).unwrap(); let _view = py - .eval_bound("array[:]", None, Some(&locals)) + .eval(c_str!("array[:]"), None, Some(&locals)) .unwrap() .downcast_into::>() .unwrap(); @@ -712,7 +722,7 @@ mod tests { #[test] fn ineffective_resize_does_not_conflict() { Python::with_gil(|py| { - let array = PyArray::::zeros_bound(py, 10, false); + let array = PyArray::::zeros(py, 10, false); let exclusive = array.readwrite(); assert!(exclusive.resize(10).is_ok()); diff --git a/src/borrow/shared.rs b/src/borrow/shared.rs index 38f8963e5..36860b275 100644 --- a/src/borrow/shared.rs +++ b/src/borrow/shared.rs @@ -136,7 +136,7 @@ fn insert_shared<'py>(py: Python<'py>) -> PyResult<*const Shared> { release_mut: release_mut_shared, }; - let capsule = PyCapsule::new_bound_with_destructor( + let capsule = PyCapsule::new_with_destructor( py, shared, Some(CString::new("_RUST_NUMPY_BORROW_CHECKING_API").unwrap()), @@ -450,6 +450,7 @@ mod tests { use crate::array::{PyArray, PyArray1, PyArray2, PyArray3, PyArrayMethods}; use crate::convert::IntoPyArray; use crate::untyped_array::PyUntypedArrayMethods; + use pyo3::ffi::c_str; fn get_borrow_flags<'py>(py: Python<'py>) -> &'py BorrowFlagsInner { let shared = get_or_insert_shared(py).unwrap(); @@ -460,7 +461,7 @@ mod tests { #[test] fn without_base_object() { Python::with_gil(|py| { - let array = PyArray::::zeros_bound(py, (1, 2, 3), false); + let array = PyArray::::zeros(py, (1, 2, 3), false); let base = unsafe { (*array.as_array_ptr()).base }; assert!(base.is_null()); @@ -477,7 +478,7 @@ mod tests { #[test] fn with_base_object() { Python::with_gil(|py| { - let array = Array::::zeros((1, 2, 3)).into_pyarray_bound(py); + let array = Array::::zeros((1, 2, 3)).into_pyarray(py); let base = unsafe { (*array.as_array_ptr()).base }; assert!(!base.is_null()); @@ -497,11 +498,11 @@ mod tests { #[test] fn view_without_base_object() { Python::with_gil(|py| { - let array = PyArray::::zeros_bound(py, (1, 2, 3), false); + let array = PyArray::::zeros(py, (1, 2, 3), false); - let locals = [("array", &array)].into_py_dict_bound(py); + let locals = [("array", &array)].into_py_dict(py).unwrap(); let view = py - .eval_bound("array[:,:,0]", None, Some(&locals)) + .eval(c_str!("array[:,:,0]"), None, Some(&locals)) .unwrap() .downcast_into::>() .unwrap(); @@ -526,11 +527,11 @@ mod tests { #[test] fn view_with_base_object() { Python::with_gil(|py| { - let array = Array::::zeros((1, 2, 3)).into_pyarray_bound(py); + let array = Array::::zeros((1, 2, 3)).into_pyarray(py); - let locals = [("array", &array)].into_py_dict_bound(py); + let locals = [("array", &array)].into_py_dict(py).unwrap(); let view = py - .eval_bound("array[:,:,0]", None, Some(&locals)) + .eval(c_str!("array[:,:,0]"), None, Some(&locals)) .unwrap() .downcast_into::>() .unwrap(); @@ -561,11 +562,11 @@ mod tests { #[test] fn view_of_view_without_base_object() { Python::with_gil(|py| { - let array = PyArray::::zeros_bound(py, (1, 2, 3), false); + let array = PyArray::::zeros(py, (1, 2, 3), false); - let locals = [("array", &array)].into_py_dict_bound(py); + let locals = [("array", &array)].into_py_dict(py).unwrap(); let view1 = py - .eval_bound("array[:,:,0]", None, Some(&locals)) + .eval(c_str!("array[:,:,0]"), None, Some(&locals)) .unwrap() .downcast_into::>() .unwrap(); @@ -574,9 +575,9 @@ mod tests { array.as_ptr().cast::() ); - let locals = [("view1", &view1)].into_py_dict_bound(py); + let locals = [("view1", &view1)].into_py_dict(py).unwrap(); let view2 = py - .eval_bound("view1[:,0]", None, Some(&locals)) + .eval(c_str!("view1[:,0]"), None, Some(&locals)) .unwrap() .downcast_into::>() .unwrap(); @@ -609,11 +610,11 @@ mod tests { #[test] fn view_of_view_with_base_object() { Python::with_gil(|py| { - let array = Array::::zeros((1, 2, 3)).into_pyarray_bound(py); + let array = Array::::zeros((1, 2, 3)).into_pyarray(py); - let locals = [("array", &array)].into_py_dict_bound(py); + let locals = [("array", &array)].into_py_dict(py).unwrap(); let view1 = py - .eval_bound("array[:,:,0]", None, Some(&locals)) + .eval(c_str!("array[:,:,0]"), None, Some(&locals)) .unwrap() .downcast_into::>() .unwrap(); @@ -622,9 +623,9 @@ mod tests { array.as_ptr().cast::(), ); - let locals = [("view1", &view1)].into_py_dict_bound(py); + let locals = [("view1", &view1)].into_py_dict(py).unwrap(); let view2 = py - .eval_bound("view1[:,0]", None, Some(&locals)) + .eval(c_str!("view1[:,0]"), None, Some(&locals)) .unwrap() .downcast_into::>() .unwrap(); @@ -663,11 +664,11 @@ mod tests { #[test] fn view_with_negative_strides() { Python::with_gil(|py| { - let array = PyArray::::zeros_bound(py, (1, 2, 3), false); + let array = PyArray::::zeros(py, (1, 2, 3), false); - let locals = [("array", &array)].into_py_dict_bound(py); + let locals = [("array", &array)].into_py_dict(py).unwrap(); let view = py - .eval_bound("array[::-1,:,::-1]", None, Some(&locals)) + .eval(c_str!("array[::-1,:,::-1]"), None, Some(&locals)) .unwrap() .downcast_into::>() .unwrap(); @@ -695,7 +696,7 @@ mod tests { #[test] fn array_with_zero_dimensions() { Python::with_gil(|py| { - let array = PyArray::::zeros_bound(py, (1, 0, 3), false); + let array = PyArray::::zeros(py, (1, 0, 3), false); let base = unsafe { (*array.as_array_ptr()).base }; assert!(base.is_null()); @@ -712,11 +713,11 @@ mod tests { #[test] fn view_with_non_dividing_strides() { Python::with_gil(|py| { - let array = PyArray::::zeros_bound(py, (10, 10), false); - let locals = [("array", array)].into_py_dict_bound(py); + let array = PyArray::::zeros(py, (10, 10), false); + let locals = [("array", array)].into_py_dict(py).unwrap(); let view1 = py - .eval_bound("array[:,::3]", None, Some(&locals)) + .eval(c_str!("array[:,::3]"), None, Some(&locals)) .unwrap() .downcast_into::>() .unwrap(); @@ -727,7 +728,7 @@ mod tests { assert_eq!(key1.gcd_strides, 8); let view2 = py - .eval_bound("array[:,1::3]", None, Some(&locals)) + .eval(c_str!("array[:,1::3]"), None, Some(&locals)) .unwrap() .downcast_into::>() .unwrap(); @@ -738,7 +739,7 @@ mod tests { assert_eq!(key2.gcd_strides, 8); let view3 = py - .eval_bound("array[:,::2]", None, Some(&locals)) + .eval(c_str!("array[:,::2]"), None, Some(&locals)) .unwrap() .downcast_into::>() .unwrap(); @@ -749,7 +750,7 @@ mod tests { assert_eq!(key3.gcd_strides, 16); let view4 = py - .eval_bound("array[:,1::2]", None, Some(&locals)) + .eval(c_str!("array[:,1::2]"), None, Some(&locals)) .unwrap() .downcast_into::>() .unwrap(); @@ -771,8 +772,8 @@ mod tests { #[test] fn borrow_multiple_arrays() { Python::with_gil(|py| { - let array1 = PyArray::::zeros_bound(py, 10, false); - let array2 = PyArray::::zeros_bound(py, 10, false); + let array1 = PyArray::::zeros(py, 10, false); + let array2 = PyArray::::zeros(py, 10, false); let base1 = base_address(py, array1.as_array_ptr()); let base2 = base_address(py, array2.as_array_ptr()); @@ -816,13 +817,13 @@ mod tests { #[test] fn borrow_multiple_views() { Python::with_gil(|py| { - let array = PyArray::::zeros_bound(py, 10, false); + let array = PyArray::::zeros(py, 10, false); let base = base_address(py, array.as_array_ptr()); - let locals = [("array", array)].into_py_dict_bound(py); + let locals = [("array", array)].into_py_dict(py).unwrap(); let view1 = py - .eval_bound("array[:5]", None, Some(&locals)) + .eval(c_str!("array[:5]"), None, Some(&locals)) .unwrap() .downcast_into::>() .unwrap(); @@ -842,7 +843,7 @@ mod tests { } let view2 = py - .eval_bound("array[5:]", None, Some(&locals)) + .eval(c_str!("array[5:]"), None, Some(&locals)) .unwrap() .downcast_into::>() .unwrap(); @@ -865,7 +866,7 @@ mod tests { } let view3 = py - .eval_bound("array[5:]", None, Some(&locals)) + .eval(c_str!("array[5:]"), None, Some(&locals)) .unwrap() .downcast_into::>() .unwrap(); @@ -891,7 +892,7 @@ mod tests { } let view4 = py - .eval_bound("array[7:]", None, Some(&locals)) + .eval(c_str!("array[7:]"), None, Some(&locals)) .unwrap() .downcast_into::>() .unwrap(); diff --git a/src/convert.rs b/src/convert.rs index a58d5c427..66c557b1b 100644 --- a/src/convert.rs +++ b/src/convert.rs @@ -24,7 +24,7 @@ use crate::slice_container::PySliceContainer; /// use pyo3::Python; /// /// Python::with_gil(|py| { -/// let py_array = vec![1, 2, 3].into_pyarray_bound(py); +/// let py_array = vec![1, 2, 3].into_pyarray(py); /// /// assert_eq!(py_array.readonly().as_slice().unwrap(), &[1, 2, 3]); /// @@ -40,29 +40,25 @@ pub trait IntoPyArray: Sized { /// The dimension type of the resulting array. type Dim: Dimension; - /// Deprecated form of [`IntoPyArray::into_pyarray_bound`] - #[deprecated( - since = "0.21.0", - note = "will be replaced by `IntoPyArray::into_pyarray_bound` in the future" - )] - #[cfg(feature = "gil-refs")] - fn into_pyarray<'py>(self, py: Python<'py>) -> &'py PyArray { - Self::into_pyarray_bound(self, py).into_gil_ref() - } - /// Consumes `self` and moves its data into a NumPy array. - fn into_pyarray_bound<'py>(self, py: Python<'py>) - -> Bound<'py, PyArray>; + fn into_pyarray<'py>(self, py: Python<'py>) -> Bound<'py, PyArray>; + + /// Deprecated name for [`IntoPyArray::into_pyarray`]. + #[deprecated(since = "0.23.0", note = "renamed to `IntoPyArray::into_pyarray`")] + #[inline] + fn into_pyarray_bound<'py>( + self, + py: Python<'py>, + ) -> Bound<'py, PyArray> { + self.into_pyarray(py) + } } impl IntoPyArray for Box<[T]> { type Item = T; type Dim = Ix1; - fn into_pyarray_bound<'py>( - self, - py: Python<'py>, - ) -> Bound<'py, PyArray> { + fn into_pyarray<'py>(self, py: Python<'py>) -> Bound<'py, PyArray> { let container = PySliceContainer::from(self); let dims = Dim([container.len]); let strides = [mem::size_of::() as npy_intp]; @@ -78,10 +74,7 @@ impl IntoPyArray for Vec { type Item = T; type Dim = Ix1; - fn into_pyarray_bound<'py>( - mut self, - py: Python<'py>, - ) -> Bound<'py, PyArray> { + fn into_pyarray<'py>(mut self, py: Python<'py>) -> Bound<'py, PyArray> { let dims = Dim([self.len()]); let strides = [mem::size_of::() as npy_intp]; let data_ptr = self.as_mut_ptr(); @@ -105,11 +98,8 @@ where type Item = A; type Dim = D; - fn into_pyarray_bound<'py>( - self, - py: Python<'py>, - ) -> Bound<'py, PyArray> { - PyArray::from_owned_array_bound(py, self) + fn into_pyarray<'py>(self, py: Python<'py>) -> Bound<'py, PyArray> { + PyArray::from_owned_array(py, self) } } @@ -124,7 +114,7 @@ where /// use pyo3::Python; /// /// Python::with_gil(|py| { -/// let py_array = vec![1, 2, 3].to_pyarray_bound(py); +/// let py_array = vec![1, 2, 3].to_pyarray(py); /// /// assert_eq!(py_array.readonly().as_slice().unwrap(), &[1, 2, 3]); /// }); @@ -140,7 +130,7 @@ where /// /// Python::with_gil(|py| { /// let array = arr3(&[[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]]); -/// let py_array = array.slice(s![.., 0..1, ..]).to_pyarray_bound(py); +/// let py_array = array.slice(s![.., 0..1, ..]).to_pyarray(py); /// /// assert_eq!(py_array.readonly().as_array(), arr3(&[[[1, 2, 3]], [[7, 8, 9]]])); /// assert!(py_array.is_c_contiguous()); @@ -152,26 +142,23 @@ pub trait ToPyArray { /// The dimension type of the resulting array. type Dim: Dimension; - /// Deprecated form of [`ToPyArray::to_pyarray_bound`] - #[deprecated( - since = "0.21.0", - note = "will be replaced by `ToPyArray::to_pyarray_bound` in the future" - )] - #[cfg(feature = "gil-refs")] - fn to_pyarray<'py>(&self, py: Python<'py>) -> &'py PyArray { - Self::to_pyarray_bound(self, py).into_gil_ref() - } - /// Copies the content pointed to by `&self` into a newly allocated NumPy array. - fn to_pyarray_bound<'py>(&self, py: Python<'py>) -> Bound<'py, PyArray>; + fn to_pyarray<'py>(&self, py: Python<'py>) -> Bound<'py, PyArray>; + + /// Deprecated name for [ToPyArray::to_pyarray`]. + #[deprecated(since = "0.23.0", note = "renamed to ToPyArray::to_pyarray`")] + #[inline] + fn to_pyarray_bound<'py>(&self, py: Python<'py>) -> Bound<'py, PyArray> { + self.to_pyarray(py) + } } impl ToPyArray for [T] { type Item = T; type Dim = Ix1; - fn to_pyarray_bound<'py>(&self, py: Python<'py>) -> Bound<'py, PyArray> { - PyArray::from_slice_bound(py, self) + fn to_pyarray<'py>(&self, py: Python<'py>) -> Bound<'py, PyArray> { + PyArray::from_slice(py, self) } } @@ -184,7 +171,7 @@ where type Item = A; type Dim = D; - fn to_pyarray_bound<'py>(&self, py: Python<'py>) -> Bound<'py, PyArray> { + fn to_pyarray<'py>(&self, py: Python<'py>) -> Bound<'py, PyArray> { let len = self.len(); match self.order() { Some(flag) if A::IS_COPY => { @@ -200,7 +187,7 @@ where // if the array is not contiguous, copy all elements by `ArrayBase::iter`. let dim = self.raw_dim(); unsafe { - let array = PyArray::::new_bound(py, dim, false); + let array = PyArray::::new(py, dim, false); let mut data_ptr = array.data(); for item in self.iter() { data_ptr.write(item.clone_ref(py)); @@ -228,9 +215,9 @@ where /// matching the [memory layout][memory-layout] used by [`nalgebra`]. /// /// [memory-layout]: https://nalgebra.org/docs/faq/#what-is-the-memory-layout-of-matrices - fn to_pyarray_bound<'py>(&self, py: Python<'py>) -> Bound<'py, PyArray> { + fn to_pyarray<'py>(&self, py: Python<'py>) -> Bound<'py, PyArray> { unsafe { - let array = PyArray::::new_bound(py, (self.nrows(), self.ncols()), true); + let array = PyArray::::new(py, (self.nrows(), self.ncols()), true); let mut data_ptr = array.data(); if self.data.is_contiguous() { ptr::copy_nonoverlapping(self.data.ptr(), data_ptr, self.len()); diff --git a/src/datetime.rs b/src/datetime.rs index 50daa269c..3eef346d8 100644 --- a/src/datetime.rs +++ b/src/datetime.rs @@ -11,25 +11,22 @@ //! //! ``` //! use numpy::{datetime::{units, Datetime, Timedelta}, PyArray1, PyArrayMethods}; -//! use pyo3::{Python, types::PyAnyMethods}; +//! use pyo3::{Python, types::PyAnyMethods, ffi::c_str}; //! # use pyo3::types::PyDict; //! +//! # fn main() -> pyo3::PyResult<()> { //! Python::with_gil(|py| { //! # let locals = py -//! # .eval_bound("{ 'np': __import__('numpy') }", None, None) -//! # .unwrap() -//! # .downcast_into::() -//! # .unwrap(); +//! # .eval(c_str!("{ 'np': __import__('numpy') }"), None, None)? +//! # .downcast_into::()?; //! # //! let array = py -//! .eval_bound( -//! "np.array([np.datetime64('2017-04-21')])", +//! .eval( +//! c_str!("np.array([np.datetime64('2017-04-21')])"), //! None, //! Some(&locals), -//! ) -//! .unwrap() -//! .downcast_into::>>() -//! .unwrap(); +//! )? +//! .downcast_into::>>()?; //! //! assert_eq!( //! array.get_owned(0).unwrap(), @@ -37,20 +34,20 @@ //! ); //! //! let array = py -//! .eval_bound( -//! "np.array([np.datetime64('2022-03-29')]) - np.array([np.datetime64('2017-04-21')])", +//! .eval( +//! c_str!("np.array([np.datetime64('2022-03-29')]) - np.array([np.datetime64('2017-04-21')])"), //! None, //! Some(&locals), -//! ) -//! .unwrap() -//! .downcast_into::>>() -//! .unwrap(); +//! )? +//! .downcast_into::>>()?; //! //! assert_eq!( //! array.get_owned(0).unwrap(), //! Timedelta::::from(1_803) //! ); -//! }); +//! # Ok(()) +//! }) +//! # } //! ``` //! //! [datetime]: https://numpy.org/doc/stable/reference/arrays.datetime.html @@ -158,7 +155,7 @@ impl From> for i64 { unsafe impl Element for Datetime { const IS_COPY: bool = true; - fn get_dtype_bound(py: Python<'_>) -> Bound<'_, PyArrayDescr> { + fn get_dtype(py: Python<'_>) -> Bound<'_, PyArrayDescr> { static DTYPES: TypeDescriptors = unsafe { TypeDescriptors::new(NPY_TYPES::NPY_DATETIME) }; DTYPES.from_unit(py, U::UNIT) @@ -195,7 +192,7 @@ impl From> for i64 { unsafe impl Element for Timedelta { const IS_COPY: bool = true; - fn get_dtype_bound(py: Python<'_>) -> Bound<'_, PyArrayDescr> { + fn get_dtype(py: Python<'_>) -> Bound<'_, PyArrayDescr> { static DTYPES: TypeDescriptors = unsafe { TypeDescriptors::new(NPY_TYPES::NPY_TIMEDELTA) }; DTYPES.from_unit(py, U::UNIT) @@ -256,6 +253,7 @@ mod tests { use super::*; use pyo3::{ + ffi::c_str, py_run, types::{PyAnyMethods, PyDict, PyModule}, }; @@ -266,14 +264,14 @@ mod tests { fn from_python_to_rust() { Python::with_gil(|py| { let locals = py - .eval_bound("{ 'np': __import__('numpy') }", None, None) + .eval(c_str!("{ 'np': __import__('numpy') }"), None, None) .unwrap() .downcast_into::() .unwrap(); let array = py - .eval_bound( - "np.array([np.datetime64('1970-01-01')])", + .eval( + c_str!("np.array([np.datetime64('1970-01-01')])"), None, Some(&locals), ) @@ -289,12 +287,12 @@ mod tests { #[test] fn from_rust_to_python() { Python::with_gil(|py| { - let array = PyArray1::>::zeros_bound(py, 1, false); + let array = PyArray1::>::zeros(py, 1, false); *array.readwrite().get_mut(0).unwrap() = Timedelta::::from(5); let np = py - .eval_bound("__import__('numpy')", None, None) + .eval(c_str!("__import__('numpy')"), None, None) .unwrap() .downcast_into::() .unwrap(); @@ -321,7 +319,7 @@ mod tests { fn unit_conversion() { #[track_caller] fn convert<'py, S: Unit, D: Unit>(py: Python<'py>, expected_value: i64) { - let array = PyArray1::>::from_slice_bound(py, &[Timedelta::::from(1)]); + let array = PyArray1::>::from_slice(py, &[Timedelta::::from(1)]); let array = array.cast::>(false).unwrap(); let value: i64 = array.get_owned(0).unwrap().into(); diff --git a/src/dtype.rs b/src/dtype.rs index e22ac20ac..fd45bb5ec 100644 --- a/src/dtype.rs +++ b/src/dtype.rs @@ -8,14 +8,13 @@ use num_traits::{Bounded, Zero}; #[cfg(feature = "half")] use pyo3::sync::GILOnceCell; use pyo3::{ + conversion::IntoPyObject, exceptions::{PyIndexError, PyValueError}, ffi::{self, PyTuple_Size}, - pyobject_native_type_extract, pyobject_native_type_named, + pyobject_native_type_named, types::{PyAnyMethods, PyDict, PyDictMethods, PyTuple, PyType}, - Borrowed, Bound, Py, PyAny, PyObject, PyResult, PyTypeInfo, Python, ToPyObject, + Borrowed, Bound, Py, PyAny, PyObject, PyResult, PyTypeInfo, Python, }; -#[cfg(feature = "gil-refs")] -use pyo3::{AsPyPointer, PyNativeType}; use crate::npyffi::{ NpyTypes, PyArray_Descr, PyDataType_ALIGNMENT, PyDataType_ELSIZE, PyDataType_FIELDS, @@ -30,20 +29,21 @@ pub use num_complex::{Complex32, Complex64}; /// # Example /// /// ``` -/// use numpy::{dtype_bound, get_array_module, PyArrayDescr, PyArrayDescrMethods}; -/// use numpy::pyo3::{types::{IntoPyDict, PyAnyMethods}, Python}; +/// use numpy::{dtype, get_array_module, PyArrayDescr, PyArrayDescrMethods}; +/// use numpy::pyo3::{types::{IntoPyDict, PyAnyMethods}, Python, ffi::c_str}; /// +/// # fn main() -> pyo3::PyResult<()> { /// Python::with_gil(|py| { -/// let locals = [("np", get_array_module(py).unwrap())].into_py_dict_bound(py); +/// let locals = [("np", get_array_module(py)?)].into_py_dict(py)?; /// /// let dt = py -/// .eval_bound("np.array([1, 2, 3.0]).dtype", Some(&locals), None) -/// .unwrap() -/// .downcast_into::() -/// .unwrap(); +/// .eval(c_str!("np.array([1, 2, 3.0]).dtype"), Some(&locals), None)? +/// .downcast_into::()?; /// -/// assert!(dt.is_equiv_to(&dtype_bound::(py))); -/// }); +/// assert!(dt.is_equiv_to(&dtype::(py))); +/// # Ok(()) +/// }) +/// # } /// ``` /// /// [dtype]: https://numpy.org/doc/stable/reference/generated/numpy.dtype.html @@ -60,28 +60,19 @@ unsafe impl PyTypeInfo for PyArrayDescr { fn type_object_raw<'py>(py: Python<'py>) -> *mut ffi::PyTypeObject { unsafe { PY_ARRAY_API.get_type_object(py, NpyTypes::PyArrayDescr_Type) } } - - #[cfg(feature = "gil-refs")] - fn is_type_of(ob: &PyAny) -> bool { - unsafe { ffi::PyObject_TypeCheck(ob.as_ptr(), Self::type_object_raw(ob.py())) > 0 } - } } -pyobject_native_type_extract!(PyArrayDescr); - /// Returns the type descriptor ("dtype") for a registered type. -#[cfg(feature = "gil-refs")] -#[deprecated( - since = "0.21.0", - note = "This will be replaced by `dtype_bound` in the future." -)] -pub fn dtype<'py, T: Element>(py: Python<'py>) -> &'py PyArrayDescr { - T::get_dtype_bound(py).into_gil_ref() +#[inline] +pub fn dtype<'py, T: Element>(py: Python<'py>) -> Bound<'py, PyArrayDescr> { + T::get_dtype(py) } -/// Returns the type descriptor ("dtype") for a registered type. +/// Deprecated name for [`dtype`]. +#[deprecated(since = "0.23.0", note = "renamed to `dtype`")] +#[inline] pub fn dtype_bound<'py, T: Element>(py: Python<'py>) -> Bound<'py, PyArrayDescr> { - T::get_dtype_bound(py) + dtype::(py) } impl PyArrayDescr { @@ -91,11 +82,14 @@ impl PyArrayDescr { /// /// [dtype]: https://numpy.org/doc/stable/reference/generated/numpy.dtype.html #[inline] - pub fn new_bound<'py, T: ToPyObject + ?Sized>( - py: Python<'py>, - ob: &T, - ) -> PyResult> { - fn inner(py: Python<'_>, obj: PyObject) -> PyResult> { + pub fn new<'a, 'py, T>(py: Python<'py>, ob: T) -> PyResult> + where + T: IntoPyObject<'py>, + { + fn inner<'py>( + py: Python<'py>, + obj: Borrowed<'_, 'py, PyAny>, + ) -> PyResult> { let mut descr: *mut PyArray_Descr = ptr::null_mut(); unsafe { // None is an invalid input here and is not converted to NPY_DEFAULT_TYPE @@ -105,17 +99,50 @@ impl PyArrayDescr { } } - inner(py, ob.to_object(py)) + inner( + py, + ob.into_pyobject(py) + .map_err(Into::into)? + .into_any() + .as_borrowed(), + ) + } + + /// Deprecated name for [`PyArrayDescr::new`]. + #[deprecated(since = "0.23.0", note = "renamed to `PyArrayDescr::new`")] + #[allow(deprecated)] + #[inline] + pub fn new_bound<'py, T: pyo3::ToPyObject + ?Sized>( + py: Python<'py>, + ob: &T, + ) -> PyResult> { + Self::new(py, ob.to_object(py)) } /// Shortcut for creating a type descriptor of `object` type. - pub fn object_bound(py: Python<'_>) -> Bound<'_, Self> { + #[inline] + pub fn object(py: Python<'_>) -> Bound<'_, Self> { Self::from_npy_type(py, NPY_TYPES::NPY_OBJECT) } + /// Deprecated name for [`PyArrayDescr::object`]. + #[deprecated(since = "0.23.0", note = "renamed to `PyArrayDescr::object`")] + #[inline] + pub fn object_bound(py: Python<'_>) -> Bound<'_, Self> { + Self::object(py) + } + /// Returns the type descriptor for a registered type. + #[inline] + pub fn of<'py, T: Element>(py: Python<'py>) -> Bound<'py, Self> { + T::get_dtype(py) + } + + /// Deprecated name for [`PyArrayDescr::of`]. + #[deprecated(since = "0.23.0", note = "renamed to `PyArrayDescr::of`")] + #[inline] pub fn of_bound<'py, T: Element>(py: Python<'py>) -> Bound<'py, Self> { - T::get_dtype_bound(py) + Self::of::(py) } fn from_npy_type<'py>(py: Python<'py>, npy_type: NPY_TYPES) -> Bound<'py, Self> { @@ -133,237 +160,6 @@ impl PyArrayDescr { } } -#[cfg(feature = "gil-refs")] -impl PyArrayDescr { - /// Creates a new type descriptor ("dtype") object from an arbitrary object. - /// - /// Equivalent to invoking the constructor of [`numpy.dtype`][dtype]. - /// - /// [dtype]: https://numpy.org/doc/stable/reference/generated/numpy.dtype.html - #[deprecated( - since = "0.21.0", - note = "This will be replace by `new_bound` in the future." - )] - pub fn new<'py, T: ToPyObject + ?Sized>(py: Python<'py>, ob: &T) -> PyResult<&'py Self> { - Self::new_bound(py, ob).map(Bound::into_gil_ref) - } - - /// Returns `self` as `*mut PyArray_Descr`. - pub fn as_dtype_ptr(&self) -> *mut PyArray_Descr { - self.as_borrowed().as_dtype_ptr() - } - - /// Returns `self` as `*mut PyArray_Descr` while increasing the reference count. - /// - /// Useful in cases where the descriptor is stolen by the API. - pub fn into_dtype_ptr(&self) -> *mut PyArray_Descr { - self.as_borrowed().to_owned().into_dtype_ptr() - } - - /// Shortcut for creating a type descriptor of `object` type. - #[deprecated( - since = "0.21.0", - note = "This will be replaced by `object_bound` in the future." - )] - pub fn object<'py>(py: Python<'py>) -> &'py Self { - Self::object_bound(py).into_gil_ref() - } - - /// Returns the type descriptor for a registered type. - #[deprecated( - since = "0.21.0", - note = "This will be replaced by `of_bound` in the future." - )] - pub fn of<'py, T: Element>(py: Python<'py>) -> &'py Self { - Self::of_bound::(py).into_gil_ref() - } - - /// Returns true if two type descriptors are equivalent. - pub fn is_equiv_to(&self, other: &Self) -> bool { - self.as_borrowed().is_equiv_to(&other.as_borrowed()) - } - - /// Returns the [array scalar][arrays-scalars] corresponding to this type descriptor. - /// - /// Equivalent to [`numpy.dtype.type`][dtype-type]. - /// - /// [arrays-scalars]: https://numpy.org/doc/stable/reference/arrays.scalars.html - /// [dtype-type]: https://numpy.org/doc/stable/reference/generated/numpy.dtype.type.html - pub fn typeobj(&self) -> &PyType { - self.as_borrowed().typeobj().into_gil_ref() - } - - /// Returns a unique number for each of the 21 different built-in - /// [enumerated types][enumerated-types]. - /// - /// These are roughly ordered from least-to-most precision. - /// - /// Equivalent to [`numpy.dtype.num`][dtype-num]. - /// - /// [enumerated-types]: https://numpy.org/doc/stable/reference/c-api/dtype.html#enumerated-types - /// [dtype-num]: https://numpy.org/doc/stable/reference/generated/numpy.dtype.num.html - pub fn num(&self) -> c_int { - self.as_borrowed().num() - } - - /// Returns the element size of this type descriptor. - /// - /// Equivalent to [`numpy.dtype.itemsize`][dtype-itemsize]. - /// - /// [dtype-itemsiize]: https://numpy.org/doc/stable/reference/generated/numpy.dtype.itemsize.html - pub fn itemsize(&self) -> usize { - self.as_borrowed().itemsize() - } - - /// Returns the required alignment (bytes) of this type descriptor according to the compiler. - /// - /// Equivalent to [`numpy.dtype.alignment`][dtype-alignment]. - /// - /// [dtype-alignment]: https://numpy.org/doc/stable/reference/generated/numpy.dtype.alignment.html - pub fn alignment(&self) -> usize { - self.as_borrowed().alignment() - } - - /// Returns an ASCII character indicating the byte-order of this type descriptor object. - /// - /// All built-in data-type objects have byteorder either `=` or `|`. - /// - /// Equivalent to [`numpy.dtype.byteorder`][dtype-byteorder]. - /// - /// [dtype-byteorder]: https://numpy.org/doc/stable/reference/generated/numpy.dtype.byteorder.html - pub fn byteorder(&self) -> u8 { - self.as_borrowed().byteorder() - } - - /// Returns a unique ASCII character for each of the 21 different built-in types. - /// - /// Note that structured data types are categorized as `V` (void). - /// - /// Equivalent to [`numpy.dtype.char`][dtype-char]. - /// - /// [dtype-char]: https://numpy.org/doc/stable/reference/generated/numpy.dtype.char.html - pub fn char(&self) -> u8 { - self.as_borrowed().char() - } - - /// Returns an ASCII character (one of `biufcmMOSUV`) identifying the general kind of data. - /// - /// Note that structured data types are categorized as `V` (void). - /// - /// Equivalent to [`numpy.dtype.kind`][dtype-kind]. - /// - /// [dtype-kind]: https://numpy.org/doc/stable/reference/generated/numpy.dtype.kind.html - pub fn kind(&self) -> u8 { - self.as_borrowed().kind() - } - - /// Returns bit-flags describing how this type descriptor is to be interpreted. - /// - /// Equivalent to [`numpy.dtype.flags`][dtype-flags]. - /// - /// In numpy 2 the flags field was widened to allow for more flags. - /// - /// [dtype-flags]: https://numpy.org/doc/stable/reference/generated/numpy.dtype.flags.html - /// [dtype-changes]: https://numpy.org/devdocs/numpy_2_0_migration_guide.html#the-pyarray-descr-struct-has-been-changed - pub fn flags(&self) -> u64 { - self.as_borrowed().flags() - } - - /// Returns the number of dimensions if this type descriptor represents a sub-array, and zero otherwise. - /// - /// Equivalent to [`numpy.dtype.ndim`][dtype-ndim]. - /// - /// [dtype-ndim]: https://numpy.org/doc/stable/reference/generated/numpy.dtype.ndim.html - pub fn ndim(&self) -> usize { - self.as_borrowed().ndim() - } - - /// Returns the type descriptor for the base element of subarrays, regardless of their dimension or shape. - /// - /// If the dtype is not a subarray, returns self. - /// - /// Equivalent to [`numpy.dtype.base`][dtype-base]. - /// - /// [dtype-base]: https://numpy.org/doc/stable/reference/generated/numpy.dtype.base.html - pub fn base(&self) -> &PyArrayDescr { - self.as_borrowed().base().into_gil_ref() - } - - /// Returns the shape of the sub-array. - /// - /// If the dtype is not a sub-array, an empty vector is returned. - /// - /// Equivalent to [`numpy.dtype.shape`][dtype-shape]. - /// - /// [dtype-shape]: https://numpy.org/doc/stable/reference/generated/numpy.dtype.shape.html - pub fn shape(&self) -> Vec { - self.as_borrowed().shape() - } - - /// Returns true if the type descriptor contains any reference-counted objects in any fields or sub-dtypes. - /// - /// Equivalent to [`numpy.dtype.hasobject`][dtype-hasobject]. - /// - /// [dtype-hasobject]: https://numpy.org/doc/stable/reference/generated/numpy.dtype.hasobject.html - pub fn has_object(&self) -> bool { - self.as_borrowed().has_object() - } - - /// Returns true if the type descriptor is a struct which maintains field alignment. - /// - /// This flag is sticky, so when combining multiple structs together, it is preserved - /// and produces new dtypes which are also aligned. - /// - /// Equivalent to [`numpy.dtype.isalignedstruct`][dtype-isalignedstruct]. - /// - /// [dtype-isalignedstruct]: https://numpy.org/doc/stable/reference/generated/numpy.dtype.isalignedstruct.html - pub fn is_aligned_struct(&self) -> bool { - self.as_borrowed().is_aligned_struct() - } - - /// Returns true if the type descriptor is a sub-array. - pub fn has_subarray(&self) -> bool { - self.as_borrowed().has_subarray() - } - - /// Returns true if the type descriptor is a structured type. - pub fn has_fields(&self) -> bool { - self.as_borrowed().has_fields() - } - - /// Returns true if type descriptor byteorder is native, or `None` if not applicable. - pub fn is_native_byteorder(&self) -> Option { - self.as_borrowed().is_native_byteorder() - } - - /// Returns an ordered list of field names, or `None` if there are no fields. - /// - /// The names are ordered according to increasing byte offset. - /// - /// Equivalent to [`numpy.dtype.names`][dtype-names]. - /// - /// [dtype-names]: https://numpy.org/doc/stable/reference/generated/numpy.dtype.names.html - pub fn names(&self) -> Option> { - self.as_borrowed().names() - } - - /// Returns the type descriptor and offset of the field with the given name. - /// - /// This method will return an error if this type descriptor is not structured, - /// or if it does not contain a field with a given name. - /// - /// The list of all names can be found via [`PyArrayDescr::names`]. - /// - /// Equivalent to retrieving a single item from [`numpy.dtype.fields`][dtype-fields]. - /// - /// [dtype-fields]: https://numpy.org/doc/stable/reference/generated/numpy.dtype.fields.html - pub fn get_field(&self, name: &str) -> PyResult<(&PyArrayDescr, usize)> { - self.as_borrowed() - .get_field(name) - .map(|(descr, n)| (descr.into_gil_ref(), n)) - } -} - /// Implementation of functionality for [`PyArrayDescr`]. #[doc(alias = "PyArrayDescr")] pub trait PyArrayDescrMethods<'py>: Sealed { @@ -396,7 +192,7 @@ pub trait PyArrayDescrMethods<'py>: Sealed { /// [enumerated-types]: https://numpy.org/doc/stable/reference/c-api/dtype.html#enumerated-types /// [dtype-num]: https://numpy.org/doc/stable/reference/generated/numpy.dtype.num.html fn num(&self) -> c_int { - unsafe { *self.as_dtype_ptr() }.type_num + unsafe { &*self.as_dtype_ptr() }.type_num } /// Returns the element size of this type descriptor. @@ -421,7 +217,7 @@ pub trait PyArrayDescrMethods<'py>: Sealed { /// /// [dtype-byteorder]: https://numpy.org/doc/stable/reference/generated/numpy.dtype.byteorder.html fn byteorder(&self) -> u8 { - unsafe { *self.as_dtype_ptr() }.byteorder.max(0) as _ + unsafe { &*self.as_dtype_ptr() }.byteorder.max(0) as _ } /// Returns a unique ASCII character for each of the 21 different built-in types. @@ -432,7 +228,7 @@ pub trait PyArrayDescrMethods<'py>: Sealed { /// /// [dtype-char]: https://numpy.org/doc/stable/reference/generated/numpy.dtype.char.html fn char(&self) -> u8 { - unsafe { *self.as_dtype_ptr() }.type_.max(0) as _ + unsafe { &*self.as_dtype_ptr() }.type_.max(0) as _ } /// Returns an ASCII character (one of `biufcmMOSUV`) identifying the general kind of data. @@ -443,7 +239,7 @@ pub trait PyArrayDescrMethods<'py>: Sealed { /// /// [dtype-kind]: https://numpy.org/doc/stable/reference/generated/numpy.dtype.kind.html fn kind(&self) -> u8 { - unsafe { *self.as_dtype_ptr() }.kind.max(0) as _ + unsafe { &*self.as_dtype_ptr() }.kind.max(0) as _ } /// Returns bit-flags describing how this type descriptor is to be interpreted. @@ -567,7 +363,7 @@ impl<'py> PyArrayDescrMethods<'py> for Bound<'py, PyArrayDescr> { } fn typeobj(&self) -> Bound<'py, PyType> { - let dtype_type_ptr = unsafe { *self.as_dtype_ptr() }.typeobj; + let dtype_type_ptr = unsafe { &*self.as_dtype_ptr() }.typeobj; unsafe { PyType::from_borrowed_type_ptr(self.py(), dtype_type_ptr) } } @@ -708,17 +504,14 @@ pub unsafe trait Element: Sized + Send + Sync { const IS_COPY: bool; /// Returns the associated type descriptor ("dtype") for the given element type. - #[cfg(feature = "gil-refs")] - #[deprecated( - since = "0.21.0", - note = "This will be replaced by `get_dtype_bound` in the future." - )] - fn get_dtype<'py>(py: Python<'py>) -> &'py PyArrayDescr { - Self::get_dtype_bound(py).into_gil_ref() - } + fn get_dtype(py: Python<'_>) -> Bound<'_, PyArrayDescr>; - /// Returns the associated type descriptor ("dtype") for the given element type. - fn get_dtype_bound(py: Python<'_>) -> Bound<'_, PyArrayDescr>; + /// Deprecated name for [`Element::get_dtype`]. + #[deprecated(since = "0.23.0", note = "renamed to `Element::get_dtype`")] + #[inline] + fn get_dtype_bound(py: Python<'_>) -> Bound<'_, PyArrayDescr> { + Self::get_dtype(py) + } /// Create a clone of the value while the GIL is guaranteed to be held. fn clone_ref(&self, py: Python<'_>) -> Self; @@ -820,6 +613,7 @@ macro_rules! clone_methods_impl { }; } pub(crate) use clone_methods_impl; +use pyo3::BoundObject; macro_rules! impl_element_scalar { (@impl: $ty:ty, $npy_type:expr $(,#[$meta:meta])*) => { @@ -827,7 +621,7 @@ macro_rules! impl_element_scalar { unsafe impl Element for $ty { const IS_COPY: bool = true; - fn get_dtype_bound(py: Python<'_>) -> Bound<'_, PyArrayDescr> { + fn get_dtype(py: Python<'_>) -> Bound<'_, PyArrayDescr> { PyArrayDescr::from_npy_type(py, $npy_type) } @@ -857,12 +651,12 @@ impl_element_scalar!(f16 => NPY_HALF); unsafe impl Element for bf16 { const IS_COPY: bool = true; - fn get_dtype_bound(py: Python<'_>) -> Bound<'_, PyArrayDescr> { + fn get_dtype(py: Python<'_>) -> Bound<'_, PyArrayDescr> { static DTYPE: GILOnceCell> = GILOnceCell::new(); DTYPE .get_or_init(py, || { - PyArrayDescr::new_bound(py, "bfloat16").expect("A package which provides a `bfloat16` data type for NumPy is required to use the `half::bf16` element type.").unbind() + PyArrayDescr::new(py, "bfloat16").expect("A package which provides a `bfloat16` data type for NumPy is required to use the `half::bf16` element type.").unbind() }) .clone_ref(py) .into_bound(py) @@ -882,8 +676,8 @@ impl_element_scalar!(usize, isize); unsafe impl Element for PyObject { const IS_COPY: bool = false; - fn get_dtype_bound(py: Python<'_>) -> Bound<'_, PyArrayDescr> { - PyArrayDescr::object_bound(py) + fn get_dtype(py: Python<'_>) -> Bound<'_, PyArrayDescr> { + PyArrayDescr::object(py) } #[inline] @@ -904,28 +698,24 @@ mod tests { #[test] fn test_dtype_new() { Python::with_gil(|py| { - assert!(PyArrayDescr::new_bound(py, "float64") + assert!(PyArrayDescr::new(py, "float64") .unwrap() - .is(&dtype_bound::(py))); + .is(&dtype::(py))); - let dt = PyArrayDescr::new_bound(py, [("a", "O"), ("b", "?")].as_ref()).unwrap(); + let dt = PyArrayDescr::new(py, [("a", "O"), ("b", "?")].as_ref()).unwrap(); assert_eq!(dt.names(), Some(vec!["a".to_owned(), "b".to_owned()])); assert!(dt.has_object()); - assert!(dt - .get_field("a") - .unwrap() - .0 - .is(&dtype_bound::(py))); - assert!(dt.get_field("b").unwrap().0.is(&dtype_bound::(py))); + assert!(dt.get_field("a").unwrap().0.is(&dtype::(py))); + assert!(dt.get_field("b").unwrap().0.is(&dtype::(py))); - assert!(PyArrayDescr::new_bound(py, &123_usize).is_err()); + assert!(PyArrayDescr::new(py, 123_usize).is_err()); }); } #[test] fn test_dtype_names() { fn type_name(py: Python<'_>) -> Bound<'_, PyString> { - dtype_bound::(py).typeobj().qualname().unwrap() + dtype::(py).typeobj().qualname().unwrap() } Python::with_gil(|py| { if is_numpy_2(py) { @@ -965,7 +755,7 @@ mod tests { #[test] fn test_dtype_methods_scalar() { Python::with_gil(|py| { - let dt = dtype_bound::(py); + let dt = dtype::(py); assert_eq!(dt.num(), NPY_TYPES::NPY_DOUBLE as c_int); assert_eq!(dt.flags(), 0); @@ -983,14 +773,14 @@ mod tests { assert!(!dt.has_subarray()); assert!(dt.base().is_equiv_to(&dt)); assert_eq!(dt.ndim(), 0); - assert_eq!(dt.shape(), vec![]); + assert_eq!(dt.shape(), Vec::::new()); }); } #[test] fn test_dtype_methods_subarray() { Python::with_gil(|py| { - let locals = PyDict::new_bound(py); + let locals = PyDict::new(py); py_run!( py, *locals, @@ -1019,14 +809,14 @@ mod tests { assert!(dt.has_subarray()); assert_eq!(dt.ndim(), 2); assert_eq!(dt.shape(), vec![2, 3]); - assert!(dt.base().is_equiv_to(&dtype_bound::(py))); + assert!(dt.base().is_equiv_to(&dtype::(py))); }); } #[test] fn test_dtype_methods_record() { Python::with_gil(|py| { - let locals = PyDict::new_bound(py); + let locals = PyDict::new(py); py_run!( py, *locals, @@ -1059,16 +849,16 @@ mod tests { assert!(dt.is_aligned_struct()); assert!(!dt.has_subarray()); assert_eq!(dt.ndim(), 0); - assert_eq!(dt.shape(), vec![]); + assert_eq!(dt.shape(), Vec::::new()); assert!(dt.base().is_equiv_to(&dt)); let x = dt.get_field("x").unwrap(); - assert!(x.0.is_equiv_to(&dtype_bound::(py))); + assert!(x.0.is_equiv_to(&dtype::(py))); assert_eq!(x.1, 0); let y = dt.get_field("y").unwrap(); - assert!(y.0.is_equiv_to(&dtype_bound::(py))); + assert!(y.0.is_equiv_to(&dtype::(py))); assert_eq!(y.1, 8); let z = dt.get_field("z").unwrap(); - assert!(z.0.is_equiv_to(&dtype_bound::(py))); + assert!(z.0.is_equiv_to(&dtype::(py))); assert_eq!(z.1, 16); }); } diff --git a/src/error.rs b/src/error.rs index 26b91fef6..7293488fe 100644 --- a/src/error.rs +++ b/src/error.rs @@ -4,7 +4,8 @@ use std::error::Error; use std::fmt; use pyo3::{ - exceptions::PyTypeError, Bound, Py, PyErr, PyErrArguments, PyObject, Python, ToPyObject, + conversion::IntoPyObject, exceptions::PyTypeError, Bound, Py, PyErr, PyErrArguments, PyObject, + Python, }; use crate::dtype::PyArrayDescr; @@ -22,7 +23,11 @@ macro_rules! impl_pyerr { impl PyErrArguments for $err_type { fn arguments<'py>(self, py: Python<'py>) -> PyObject { - self.to_string().to_object(py) + self.to_string() + .into_pyobject(py) + .unwrap() + .into_any() + .unbind() } } @@ -92,7 +97,11 @@ impl PyErrArguments for TypeErrorArguments { to: self.to.into_bound(py), }; - err.to_string().to_object(py) + err.to_string() + .into_pyobject(py) + .unwrap() + .into_any() + .unbind() } } diff --git a/src/lib.rs b/src/lib.rs index 6b72c2151..e147a9c18 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,7 +26,7 @@ as well as the [`PyReadonlyArray::try_as_matrix`] and [`PyReadwriteArray::try_as //! use numpy::{ToPyArray, PyArray, PyArrayMethods}; //! //! Python::with_gil(|py| { -//! let py_array = array![[1i64, 2], [3, 4]].to_pyarray_bound(py); +//! let py_array = array![[1i64, 2], [3, 4]].to_pyarray(py); //! //! assert_eq!( //! py_array.readonly().as_array(), @@ -39,10 +39,10 @@ as well as the [`PyReadonlyArray::try_as_matrix`] and [`PyReadwriteArray::try_as #![cfg_attr(not(feature = "nalgebra"), doc = "```rust,ignore")] //! use numpy::pyo3::Python; //! use numpy::nalgebra::Matrix3; -//! use numpy::{pyarray_bound, ToPyArray, PyArrayMethods}; +//! use numpy::{pyarray, ToPyArray, PyArrayMethods}; //! //! Python::with_gil(|py| { -//! let py_array = pyarray_bound![py, [0, 1, 2], [3, 4, 5], [6, 7, 8]]; +//! let py_array = pyarray![py, [0, 1, 2], [3, 4, 5], [6, 7, 8]]; //! //! let py_array_square; //! @@ -70,9 +70,6 @@ as well as the [`PyReadonlyArray::try_as_matrix`] and [`PyReadwriteArray::try_as //! [c-api]: https://numpy.org/doc/stable/reference/c-api //! [ndarray]: https://numpy.org/doc/stable/reference/arrays.ndarray.html #![deny(missing_docs)] -// requiring `Debug` impls is not relevant without gil-refs since `&PyArray` -// and similar aren't constructible -#![cfg_attr(feature = "gil-refs", deny(missing_debug_implementations))] pub mod array; mod array_like; @@ -108,18 +105,14 @@ pub use crate::borrow::{ PyReadwriteArray5, PyReadwriteArray6, PyReadwriteArrayDyn, }; pub use crate::convert::{IntoPyArray, NpyIndex, ToNpyDims, ToPyArray}; -#[cfg(feature = "gil-refs")] #[allow(deprecated)] -pub use crate::dtype::dtype; -pub use crate::dtype::{ - dtype_bound, Complex32, Complex64, Element, PyArrayDescr, PyArrayDescrMethods, -}; +pub use crate::dtype::dtype_bound; +pub use crate::dtype::{dtype, Complex32, Complex64, Element, PyArrayDescr, PyArrayDescrMethods}; pub use crate::error::{BorrowError, FromVecError, NotContiguousError}; pub use crate::npyffi::{PY_ARRAY_API, PY_UFUNC_API}; pub use crate::strings::{PyFixedString, PyFixedUnicode}; -#[cfg(feature = "gil-refs")] -#[allow(deprecated)] pub use crate::sum_products::{dot, einsum, inner}; +#[allow(deprecated)] pub use crate::sum_products::{dot_bound, einsum_bound, inner_bound}; pub use crate::untyped_array::{PyUntypedArray, PyUntypedArrayMethods}; @@ -156,27 +149,6 @@ mod doctest { #[inline(always)] fn cold() {} -/// Deprecated form of [`pyarray_bound`] -#[deprecated( - since = "0.21.0", - note = "will be replace by `pyarray_bound` in the future" -)] -#[macro_export] -macro_rules! pyarray { - ($py: ident, $([$([$($x:expr),* $(,)*]),+ $(,)*]),+ $(,)*) => {{ - #[allow(deprecated)] - $crate::IntoPyArray::into_pyarray($crate::array![$([$([$($x,)*],)*],)*], $py) - }}; - ($py: ident, $([$($x:expr),* $(,)*]),+ $(,)*) => {{ - #[allow(deprecated)] - $crate::IntoPyArray::into_pyarray($crate::array![$([$($x,)*],)*], $py) - }}; - ($py: ident, $($x:expr),* $(,)*) => {{ - #[allow(deprecated)] - $crate::IntoPyArray::into_pyarray($crate::array![$($x,)*], $py) - }}; -} - /// Create a [`PyArray`] with one, two or three dimensions. /// /// This macro is backed by [`ndarray::array`]. @@ -186,10 +158,10 @@ macro_rules! pyarray { /// ``` /// use numpy::pyo3::Python; /// use numpy::ndarray::array; -/// use numpy::{pyarray_bound, PyArrayMethods}; +/// use numpy::{pyarray, PyArrayMethods}; /// /// Python::with_gil(|py| { -/// let array = pyarray_bound![py, [1, 2], [3, 4]]; +/// let array = pyarray![py, [1, 2], [3, 4]]; /// /// assert_eq!( /// array.readonly().as_array(), @@ -197,14 +169,29 @@ macro_rules! pyarray { /// ); /// }); #[macro_export] +macro_rules! pyarray { + ($py: ident, $([$([$($x:expr),* $(,)*]),+ $(,)*]),+ $(,)*) => {{ + $crate::IntoPyArray::into_pyarray($crate::array![$([$([$($x,)*],)*],)*], $py) + }}; + ($py: ident, $([$($x:expr),* $(,)*]),+ $(,)*) => {{ + $crate::IntoPyArray::into_pyarray($crate::array![$([$($x,)*],)*], $py) + }}; + ($py: ident, $($x:expr),* $(,)*) => {{ + $crate::IntoPyArray::into_pyarray($crate::array![$($x,)*], $py) + }}; +} + +/// Deprecated name for [`pyarray`]. +#[deprecated(since = "0.23.0", note = "renamed to `pyarray`")] +#[macro_export] macro_rules! pyarray_bound { ($py: ident, $([$([$($x:expr),* $(,)*]),+ $(,)*]),+ $(,)*) => {{ - $crate::IntoPyArray::into_pyarray_bound($crate::array![$([$([$($x,)*],)*],)*], $py) + $crate::IntoPyArray::into_pyarray($crate::array![$([$([$($x,)*],)*],)*], $py) }}; ($py: ident, $([$($x:expr),* $(,)*]),+ $(,)*) => {{ - $crate::IntoPyArray::into_pyarray_bound($crate::array![$([$($x,)*],)*], $py) + $crate::IntoPyArray::into_pyarray($crate::array![$([$($x,)*],)*], $py) }}; ($py: ident, $($x:expr),* $(,)*) => {{ - $crate::IntoPyArray::into_pyarray_bound($crate::array![$($x,)*], $py) + $crate::IntoPyArray::into_pyarray($crate::array![$($x,)*], $py) }}; } diff --git a/src/npyffi/array.rs b/src/npyffi/array.rs index 9689e89df..55fe64ded 100644 --- a/src/npyffi/array.rs +++ b/src/npyffi/array.rs @@ -23,10 +23,10 @@ pub(crate) fn numpy_core_name(py: Python<'_>) -> PyResult<&'static str> { // strategy mirrored from https://github.com/pybind/pybind11/blob/af67e87393b0f867ccffc2702885eea12de063fc/include/pybind11/numpy.h#L175-L195 - let numpy = PyModule::import_bound(py, "numpy")?; + let numpy = PyModule::import(py, "numpy")?; let version_string = numpy.getattr("__version__")?; - let numpy_lib = PyModule::import_bound(py, "numpy.lib")?; + let numpy_lib = PyModule::import(py, "numpy.lib")?; let numpy_version = numpy_lib .getattr("NumpyVersion")? .call1((version_string,))?; @@ -65,7 +65,7 @@ const CAPSULE_NAME: &str = "_ARRAY_API"; /// use numpy::prelude::*; /// use numpy::{PyArray, npyffi::types::NPY_SORTKIND, PY_ARRAY_API}; /// pyo3::Python::with_gil(|py| { -/// let array = PyArray::from_slice_bound(py, &[3, 2, 4]); +/// let array = PyArray::from_slice(py, &[3, 2, 4]); /// unsafe { /// PY_ARRAY_API.PyArray_Sort(py, array.as_array_ptr(), 0, NPY_SORTKIND::NPY_QUICKSORT); /// } diff --git a/src/npyffi/mod.rs b/src/npyffi/mod.rs index 8a75dff8b..b96e69344 100644 --- a/src/npyffi/mod.rs +++ b/src/npyffi/mod.rs @@ -27,7 +27,7 @@ fn get_numpy_api<'py>( module: &str, capsule: &str, ) -> PyResult<*const *const c_void> { - let module = PyModule::import_bound(py, module)?; + let module = PyModule::import(py, module)?; let capsule = module.getattr(capsule)?.downcast_into::()?; let api = capsule.pointer() as *const *const c_void; diff --git a/src/npyffi/objects.rs b/src/npyffi/objects.rs index fa0fb403c..d28e88b7e 100644 --- a/src/npyffi/objects.rs +++ b/src/npyffi/objects.rs @@ -11,7 +11,6 @@ use super::types::*; use crate::npyffi::*; #[repr(C)] -#[derive(Copy, Clone)] pub struct PyArrayObject { pub ob_base: PyObject, pub data: *mut c_char, @@ -25,7 +24,6 @@ pub struct PyArrayObject { } #[repr(C)] -#[derive(Copy, Clone)] pub struct PyArray_Descr { pub ob_base: PyObject, pub typeobj: *mut PyTypeObject, @@ -37,7 +35,6 @@ pub struct PyArray_Descr { } #[repr(C)] -#[derive(Copy, Clone)] pub struct PyArray_DescrProto { pub ob_base: PyObject, pub typeobj: *mut PyTypeObject, @@ -58,7 +55,6 @@ pub struct PyArray_DescrProto { } #[repr(C)] -#[derive(Copy, Clone)] pub struct _PyArray_DescrNumPy2 { pub ob_base: PyObject, pub typeobj: *mut PyTypeObject, @@ -76,7 +72,6 @@ pub struct _PyArray_DescrNumPy2 { } #[repr(C)] -#[derive(Copy, Clone)] struct _PyArray_LegacyDescr { pub ob_base: PyObject, pub typeobj: *mut PyTypeObject, @@ -310,7 +305,6 @@ pub type PyArray_FastTakeFunc = Option< >; #[repr(C)] -#[derive(Clone, Copy)] pub struct PyArrayFlagsObject { pub ob_base: PyObject, pub arr: *mut PyObject, @@ -325,7 +319,6 @@ pub struct PyArray_Dims { } #[repr(C)] -#[derive(Clone, Copy)] pub struct PyArray_Chunk { pub ob_base: PyObject, pub base: *mut PyObject, @@ -349,7 +342,6 @@ pub struct PyArrayInterface { } #[repr(C)] -#[derive(Clone, Copy)] pub struct PyUFuncObject { pub ob_base: PyObject, pub nin: c_int, @@ -428,7 +420,6 @@ pub type PyUFunc_MaskedInnerLoopSelectionFunc = Option< pub struct NpyIter([u8; 0]); #[repr(C)] -#[derive(Clone, Copy)] pub struct PyArrayIterObject { pub ob_base: PyObject, pub nd_m1: c_int, @@ -449,7 +440,6 @@ pub struct PyArrayIterObject { } #[repr(C)] -#[derive(Clone, Copy)] pub struct PyArrayMultiIterObject { pub ob_base: PyObject, pub numiter: c_int, @@ -461,7 +451,6 @@ pub struct PyArrayMultiIterObject { } #[repr(C)] -#[derive(Clone, Copy)] pub struct PyArrayNeighborhoodIterObject { pub ob_base: PyObject, pub nd_m1: c_int, @@ -487,7 +476,6 @@ pub struct PyArrayNeighborhoodIterObject { } #[repr(C)] -#[derive(Clone, Copy)] pub struct PyArrayMapIterObject { pub ob_base: PyObject, pub numiter: c_int, @@ -571,7 +559,6 @@ pub struct npy_static_string { } #[repr(C)] -#[derive(Clone, Copy)] pub struct PyArray_StringDTypeObject { pub base: PyArray_Descr, pub na_object: *mut PyObject, diff --git a/src/strings.rs b/src/strings.rs index 3e184d144..067327865 100644 --- a/src/strings.rs +++ b/src/strings.rs @@ -51,7 +51,7 @@ use crate::npyffi::NPY_TYPES; /// use numpy::{PyArray1, PyUntypedArrayMethods, PyFixedString}; /// /// # Python::with_gil(|py| { -/// let array = PyArray1::>::from_vec_bound(py, vec![[b'f', b'o', b'o'].into()]); +/// let array = PyArray1::>::from_vec(py, vec![[b'f', b'o', b'o'].into()]); /// /// assert!(array.dtype().to_string().contains("S3")); /// # }); @@ -77,7 +77,7 @@ impl From<[Py_UCS1; N]> for PyFixedString { unsafe impl Element for PyFixedString { const IS_COPY: bool = true; - fn get_dtype_bound(py: Python<'_>) -> Bound<'_, PyArrayDescr> { + fn get_dtype(py: Python<'_>) -> Bound<'_, PyArrayDescr> { static DTYPES: TypeDescriptors = TypeDescriptors::new(); unsafe { DTYPES.from_size(py, NPY_TYPES::NPY_STRING, b'|' as _, size_of::()) } @@ -116,7 +116,7 @@ unsafe impl Element for PyFixedString { /// use numpy::{PyArray1, PyUntypedArrayMethods, PyFixedUnicode}; /// /// # Python::with_gil(|py| { -/// let array = PyArray1::>::from_vec_bound(py, vec![[b'b' as _, b'a' as _, b'r' as _].into()]); +/// let array = PyArray1::>::from_vec(py, vec![[b'b' as _, b'a' as _, b'r' as _].into()]); /// /// assert!(array.dtype().to_string().contains("U3")); /// # }); @@ -150,7 +150,7 @@ impl From<[Py_UCS4; N]> for PyFixedUnicode { unsafe impl Element for PyFixedUnicode { const IS_COPY: bool = true; - fn get_dtype_bound(py: Python<'_>) -> Bound<'_, PyArrayDescr> { + fn get_dtype(py: Python<'_>) -> Bound<'_, PyArrayDescr> { static DTYPES: TypeDescriptors = TypeDescriptors::new(); unsafe { DTYPES.from_size(py, NPY_TYPES::NPY_UNICODE, b'=' as _, size_of::()) } diff --git a/src/sum_products.rs b/src/sum_products.rs index 0101f7212..8aadbdc66 100644 --- a/src/sum_products.rs +++ b/src/sum_products.rs @@ -4,8 +4,6 @@ use std::ptr::null_mut; use ndarray::{Dimension, IxDyn}; use pyo3::types::PyAnyMethods; -#[cfg(feature = "gil-refs")] -use pyo3::PyNativeType; use pyo3::{Borrowed, Bound, FromPyObject, PyResult}; use crate::array::PyArray; @@ -15,14 +13,6 @@ use crate::npyffi::{array::PY_ARRAY_API, NPY_CASTING, NPY_ORDER}; /// Return value of a function that can yield either an array or a scalar. pub trait ArrayOrScalar<'py, T>: FromPyObject<'py> {} -#[cfg(feature = "gil-refs")] -impl<'py, T, D> ArrayOrScalar<'py, T> for &'py PyArray -where - T: Element, - D: Dimension, -{ -} - impl<'py, T, D> ArrayOrScalar<'py, T> for Bound<'py, PyArray> where T: Element, @@ -32,25 +22,6 @@ where impl<'py, T> ArrayOrScalar<'py, T> for T where T: Element + FromPyObject<'py> {} -/// Deprecated form of [`inner_bound`] -#[deprecated( - since = "0.21.0", - note = "will be replaced by `inner_bound` in the future" -)] -#[cfg(feature = "gil-refs")] -pub fn inner<'py, T, DIN1, DIN2, OUT>( - array1: &'py PyArray, - array2: &'py PyArray, -) -> PyResult -where - T: Element, - DIN1: Dimension, - DIN2: Dimension, - OUT: ArrayOrScalar<'py, T>, -{ - inner_bound(&array1.as_borrowed(), &array2.as_borrowed()) -} - /// Return the inner product of two arrays. /// /// [NumPy's documentation][inner] has the details. @@ -61,11 +32,11 @@ where /// /// ``` /// use pyo3::Python; -/// use numpy::{inner_bound, pyarray_bound, PyArray0}; +/// use numpy::{inner, pyarray, PyArray0}; /// /// Python::with_gil(|py| { -/// let vector = pyarray_bound![py, 1.0, 2.0, 3.0]; -/// let result: f64 = inner_bound(&vector, &vector).unwrap(); +/// let vector = pyarray![py, 1.0, 2.0, 3.0]; +/// let result: f64 = inner(&vector, &vector).unwrap(); /// assert_eq!(result, 14.0); /// }); /// ``` @@ -75,17 +46,17 @@ where /// ``` /// use pyo3::{Python, Bound}; /// use numpy::prelude::*; -/// use numpy::{inner_bound, pyarray_bound, PyArray0}; +/// use numpy::{inner, pyarray, PyArray0}; /// /// Python::with_gil(|py| { -/// let vector = pyarray_bound![py, 1, 2, 3]; -/// let result: Bound<'_, PyArray0<_>> = inner_bound(&vector, &vector).unwrap(); +/// let vector = pyarray![py, 1, 2, 3]; +/// let result: Bound<'_, PyArray0<_>> = inner(&vector, &vector).unwrap(); /// assert_eq!(result.item(), 14); /// }); /// ``` /// /// [inner]: https://numpy.org/doc/stable/reference/generated/numpy.inner.html -pub fn inner_bound<'py, T, DIN1, DIN2, OUT>( +pub fn inner<'py, T, DIN1, DIN2, OUT>( array1: &Bound<'py, PyArray>, array2: &Bound<'py, PyArray>, ) -> PyResult @@ -103,15 +74,12 @@ where obj.extract() } -/// Deprecated form of [`dot_bound`] -#[cfg(feature = "gil-refs")] -#[deprecated( - since = "0.21.0", - note = "will be replaced by `dot_bound` in the future" -)] -pub fn dot<'py, T, DIN1, DIN2, OUT>( - array1: &'py PyArray, - array2: &'py PyArray, +/// Deprecated name for [`inner`]. +#[deprecated(since = "0.23.0", note = "renamed to `inner`")] +#[inline] +pub fn inner_bound<'py, T, DIN1, DIN2, OUT>( + array1: &Bound<'py, PyArray>, + array2: &Bound<'py, PyArray>, ) -> PyResult where T: Element, @@ -119,7 +87,7 @@ where DIN2: Dimension, OUT: ArrayOrScalar<'py, T>, { - dot_bound(&array1.as_borrowed(), &array2.as_borrowed()) + inner(array1, array2) } /// Return the dot product of two arrays. @@ -133,13 +101,13 @@ where /// ``` /// use pyo3::{Python, Bound}; /// use ndarray::array; -/// use numpy::{dot_bound, pyarray_bound, PyArray2, PyArrayMethods}; +/// use numpy::{dot, pyarray, PyArray2, PyArrayMethods}; /// /// Python::with_gil(|py| { -/// let matrix = pyarray_bound![py, [1, 0], [0, 1]]; -/// let another_matrix = pyarray_bound![py, [4, 1], [2, 2]]; +/// let matrix = pyarray![py, [1, 0], [0, 1]]; +/// let another_matrix = pyarray![py, [4, 1], [2, 2]]; /// -/// let result: Bound<'_, PyArray2<_>> = dot_bound(&matrix, &another_matrix).unwrap(); +/// let result: Bound<'_, PyArray2<_>> = dot(&matrix, &another_matrix).unwrap(); /// /// assert_eq!( /// result.readonly().as_array(), @@ -152,17 +120,17 @@ where /// /// ``` /// use pyo3::Python; -/// use numpy::{dot_bound, pyarray_bound, PyArray0}; +/// use numpy::{dot, pyarray, PyArray0}; /// /// Python::with_gil(|py| { -/// let vector = pyarray_bound![py, 1.0, 2.0, 3.0]; -/// let result: f64 = dot_bound(&vector, &vector).unwrap(); +/// let vector = pyarray![py, 1.0, 2.0, 3.0]; +/// let result: f64 = dot(&vector, &vector).unwrap(); /// assert_eq!(result, 14.0); /// }); /// ``` /// /// [dot]: https://numpy.org/doc/stable/reference/generated/numpy.dot.html -pub fn dot_bound<'py, T, DIN1, DIN2, OUT>( +pub fn dot<'py, T, DIN1, DIN2, OUT>( array1: &Bound<'py, PyArray>, array2: &Bound<'py, PyArray>, ) -> PyResult @@ -180,28 +148,26 @@ where obj.extract() } -/// Deprecated form of [`einsum_bound`] -#[cfg(feature = "gil-refs")] -#[deprecated( - since = "0.21.0", - note = "will be replaced by `einsum_bound` in the future" -)] -pub fn einsum<'py, T, OUT>(subscripts: &str, arrays: &[&'py PyArray]) -> PyResult +/// Deprecated name for [`dot`]. +#[deprecated(since = "0.23.0", note = "renamed to `dot`")] +#[inline] +pub fn dot_bound<'py, T, DIN1, DIN2, OUT>( + array1: &Bound<'py, PyArray>, + array2: &Bound<'py, PyArray>, +) -> PyResult where T: Element, + DIN1: Dimension, + DIN2: Dimension, OUT: ArrayOrScalar<'py, T>, { - // Safety: &PyArray has the same size and layout in memory as - // Borrowed<'_, '_, PyArray> - einsum_bound(subscripts, unsafe { - std::slice::from_raw_parts(arrays.as_ptr().cast(), arrays.len()) - }) + dot(array1, array2) } /// Return the Einstein summation convention of given tensors. /// /// This is usually invoked via the the [`einsum!`][crate::einsum!] macro. -pub fn einsum_bound<'py, T, OUT>( +pub fn einsum<'py, T, OUT>( subscripts: &str, arrays: &[Borrowed<'_, 'py, PyArray>], ) -> PyResult @@ -231,19 +197,18 @@ where obj.extract() } -/// Deprecated form of [`einsum_bound!`][crate::einsum_bound!] -#[cfg(feature = "gil-refs")] -#[deprecated( - since = "0.21.0", - note = "will be replaced by `einsum_bound!` in the future" -)] -#[macro_export] -macro_rules! einsum { - ($subscripts:literal $(,$array:ident)+ $(,)*) => {{ - use pyo3::PyNativeType; - let arrays = [$($array.to_dyn().as_borrowed(),)+]; - $crate::einsum_bound(concat!($subscripts, "\0"), &arrays) - }}; +/// Deprecated name for [`einsum`]. +#[deprecated(since = "0.23.0", note = "renamed to `einsum`")] +#[inline] +pub fn einsum_bound<'py, T, OUT>( + subscripts: &str, + arrays: &[Borrowed<'_, 'py, PyArray>], +) -> PyResult +where + T: Element, + OUT: ArrayOrScalar<'py, T>, +{ + einsum(subscripts, arrays) } /// Return the Einstein summation convention of given tensors. @@ -256,13 +221,13 @@ macro_rules! einsum { /// ``` /// use pyo3::{Python, Bound}; /// use ndarray::array; -/// use numpy::{einsum_bound, pyarray_bound, PyArray, PyArray2, PyArrayMethods}; +/// use numpy::{einsum, pyarray, PyArray, PyArray2, PyArrayMethods}; /// /// Python::with_gil(|py| { -/// let tensor = PyArray::arange_bound(py, 0, 2 * 3 * 4, 1).reshape([2, 3, 4]).unwrap(); -/// let another_tensor = pyarray_bound![py, [20, 30], [40, 50], [60, 70]]; +/// let tensor = PyArray::arange(py, 0, 2 * 3 * 4, 1).reshape([2, 3, 4]).unwrap(); +/// let another_tensor = pyarray![py, [20, 30], [40, 50], [60, 70]]; /// -/// let result: Bound<'_, PyArray2<_>> = einsum_bound!("ijk,ji->ik", tensor, another_tensor).unwrap(); +/// let result: Bound<'_, PyArray2<_>> = einsum!("ijk,ji->ik", tensor, another_tensor).unwrap(); /// /// assert_eq!( /// result.readonly().as_array(), @@ -273,9 +238,19 @@ macro_rules! einsum { /// /// [einsum]: https://numpy.org/doc/stable/reference/generated/numpy.einsum.html #[macro_export] +macro_rules! einsum { + ($subscripts:literal $(,$array:ident)+ $(,)*) => {{ + let arrays = [$($array.to_dyn().as_borrowed(),)+]; + $crate::einsum(concat!($subscripts, "\0"), &arrays) + }}; +} + +/// Deprecated name for [`einsum!`]. +#[deprecated(since = "0.23.0", note = "renamed to `einsum!`")] +#[macro_export] macro_rules! einsum_bound { ($subscripts:literal $(,$array:ident)+ $(,)*) => {{ let arrays = [$($array.to_dyn().as_borrowed(),)+]; - $crate::einsum_bound(concat!($subscripts, "\0"), &arrays) + $crate::einsum(concat!($subscripts, "\0"), &arrays) }}; } diff --git a/src/untyped_array.rs b/src/untyped_array.rs index d70dfb5c4..aca2dea5b 100644 --- a/src/untyped_array.rs +++ b/src/untyped_array.rs @@ -3,11 +3,8 @@ //! [ndarray]: https://numpy.org/doc/stable/reference/arrays.ndarray.html use std::slice; -#[cfg(feature = "gil-refs")] -use pyo3::PyNativeType; use pyo3::{ - ffi, pyobject_native_type_extract, pyobject_native_type_named, types::PyAnyMethods, - AsPyPointer, Bound, IntoPy, PyAny, PyObject, PyTypeInfo, Python, + ffi, pyobject_native_type_named, types::PyAnyMethods, Bound, PyAny, PyTypeInfo, Python, }; use crate::array::{PyArray, PyArrayMethods}; @@ -30,7 +27,7 @@ use crate::npyffi; /// ``` /// # use pyo3::prelude::*; /// use pyo3::exceptions::PyTypeError; -/// use numpy::{Element, PyUntypedArray, PyArray1, dtype_bound}; +/// use numpy::{Element, PyUntypedArray, PyArray1, dtype}; /// use numpy::{PyUntypedArrayMethods, PyArrayMethods, PyArrayDescrMethods}; /// /// #[pyfunction] @@ -43,11 +40,11 @@ use crate::npyffi; /// /// let element_type = array.dtype(); /// -/// if element_type.is_equiv_to(&dtype_bound::(py)) { +/// if element_type.is_equiv_to(&dtype::(py)) { /// let array = array.downcast::>()?; /// /// implementation(array) -/// } else if element_type.is_equiv_to(&dtype_bound::(py)) { +/// } else if element_type.is_equiv_to(&dtype::(py)) { /// let array = array.downcast::>()?; /// /// implementation(array) @@ -57,7 +54,7 @@ use crate::npyffi; /// } /// # /// # Python::with_gil(|py| { -/// # let array = PyArray1::::zeros_bound(py, 42, false); +/// # let array = PyArray1::::zeros(py, 42, false); /// # entry_point(py, array.as_untyped()) /// # }).unwrap(); /// ``` @@ -72,194 +69,13 @@ unsafe impl PyTypeInfo for PyUntypedArray { unsafe { npyffi::PY_ARRAY_API.get_type_object(py, npyffi::NpyTypes::PyArray_Type) } } - fn is_type_of_bound(ob: &Bound<'_, PyAny>) -> bool { + fn is_type_of(ob: &Bound<'_, PyAny>) -> bool { unsafe { npyffi::PyArray_Check(ob.py(), ob.as_ptr()) != 0 } } } pyobject_native_type_named!(PyUntypedArray); -impl IntoPy for PyUntypedArray { - fn into_py<'py>(self, py: Python<'py>) -> PyObject { - unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) } - } -} - -pyobject_native_type_extract!(PyUntypedArray); - -#[cfg(feature = "gil-refs")] -impl PyUntypedArray { - /// Returns a raw pointer to the underlying [`PyArrayObject`][npyffi::PyArrayObject]. - #[inline] - pub fn as_array_ptr(&self) -> *mut npyffi::PyArrayObject { - self.as_borrowed().as_array_ptr() - } - - /// Returns the `dtype` of the array. - /// - /// See also [`ndarray.dtype`][ndarray-dtype] and [`PyArray_DTYPE`][PyArray_DTYPE]. - /// - /// # Example - /// - /// ``` - /// use numpy::prelude::*; - /// use numpy::{dtype_bound, PyArray}; - /// use pyo3::Python; - /// - /// Python::with_gil(|py| { - /// let array = PyArray::from_vec_bound(py, vec![1_i32, 2, 3]); - /// - /// assert!(array.dtype().is_equiv_to(&dtype_bound::(py))); - /// }); - /// ``` - /// - /// [ndarray-dtype]: https://numpy.org/doc/stable/reference/generated/numpy.ndarray.dtype.html - /// [PyArray_DTYPE]: https://numpy.org/doc/stable/reference/c-api/array.html#c.PyArray_DTYPE - #[inline] - pub fn dtype(&self) -> &PyArrayDescr { - self.as_borrowed().dtype().into_gil_ref() - } - - /// Returns `true` if the internal data of the array is contiguous, - /// indepedently of whether C-style/row-major or Fortran-style/column-major. - /// - /// # Example - /// - /// ``` - /// use numpy::{PyArray1, PyUntypedArrayMethods}; - /// use pyo3::{types::{IntoPyDict, PyAnyMethods}, Python}; - /// - /// Python::with_gil(|py| { - /// let array = PyArray1::arange_bound(py, 0, 10, 1); - /// assert!(array.is_contiguous()); - /// - /// let view = py - /// .eval_bound("array[::2]", None, Some(&[("array", array)].into_py_dict_bound(py))) - /// .unwrap() - /// .downcast_into::>() - /// .unwrap(); - /// assert!(!view.is_contiguous()); - /// }); - /// ``` - #[inline] - pub fn is_contiguous(&self) -> bool { - self.as_borrowed().is_contiguous() - } - - /// Returns `true` if the internal data of the array is Fortran-style/column-major contiguous. - #[inline] - pub fn is_fortran_contiguous(&self) -> bool { - self.as_borrowed().is_fortran_contiguous() - } - - /// Returns `true` if the internal data of the array is C-style/row-major contiguous. - #[inline] - pub fn is_c_contiguous(&self) -> bool { - self.as_borrowed().is_c_contiguous() - } - - /// Returns the number of dimensions of the array. - /// - /// See also [`ndarray.ndim`][ndarray-ndim] and [`PyArray_NDIM`][PyArray_NDIM]. - /// - /// # Example - /// - /// ``` - /// use numpy::{PyArray3, PyUntypedArrayMethods}; - /// use pyo3::Python; - /// - /// Python::with_gil(|py| { - /// let arr = PyArray3::::zeros_bound(py, [4, 5, 6], false); - /// - /// assert_eq!(arr.ndim(), 3); - /// }); - /// ``` - /// - /// [ndarray-ndim]: https://numpy.org/doc/stable/reference/generated/numpy.ndarray.ndim.html - /// [PyArray_NDIM]: https://numpy.org/doc/stable/reference/c-api/array.html#c.PyArray_NDIM - #[inline] - pub fn ndim(&self) -> usize { - self.as_borrowed().ndim() - } - - /// Returns a slice indicating how many bytes to advance when iterating along each axis. - /// - /// See also [`ndarray.strides`][ndarray-strides] and [`PyArray_STRIDES`][PyArray_STRIDES]. - /// - /// # Example - /// - /// ``` - /// use numpy::{PyArray3, PyUntypedArrayMethods}; - /// use pyo3::Python; - /// - /// Python::with_gil(|py| { - /// let arr = PyArray3::::zeros_bound(py, [4, 5, 6], false); - /// - /// assert_eq!(arr.strides(), &[240, 48, 8]); - /// }); - /// ``` - /// [ndarray-strides]: https://numpy.org/doc/stable/reference/generated/numpy.ndarray.strides.html - /// [PyArray_STRIDES]: https://numpy.org/doc/stable/reference/c-api/array.html#c.PyArray_STRIDES - #[inline] - pub fn strides(&self) -> &[isize] { - let n = self.ndim(); - if n == 0 { - cold(); - return &[]; - } - let ptr = self.as_array_ptr(); - unsafe { - let p = (*ptr).strides; - slice::from_raw_parts(p, n) - } - } - - /// Returns a slice which contains dimmensions of the array. - /// - /// See also [`ndarray.shape`][ndaray-shape] and [`PyArray_DIMS`][PyArray_DIMS]. - /// - /// # Example - /// - /// ``` - /// use numpy::{PyArray3, PyUntypedArrayMethods}; - /// use pyo3::Python; - /// - /// Python::with_gil(|py| { - /// let arr = PyArray3::::zeros_bound(py, [4, 5, 6], false); - /// - /// assert_eq!(arr.shape(), &[4, 5, 6]); - /// }); - /// ``` - /// - /// [ndarray-shape]: https://numpy.org/doc/stable/reference/generated/numpy.ndarray.shape.html - /// [PyArray_DIMS]: https://numpy.org/doc/stable/reference/c-api/array.html#c.PyArray_DIMS - #[inline] - pub fn shape(&self) -> &[usize] { - let n = self.ndim(); - if n == 0 { - cold(); - return &[]; - } - let ptr = self.as_array_ptr(); - unsafe { - let p = (*ptr).dimensions as *mut usize; - slice::from_raw_parts(p, n) - } - } - - /// Calculates the total number of elements in the array. - #[inline] - pub fn len(&self) -> usize { - self.as_borrowed().len() - } - - /// Returns `true` if the there are no elements in the array. - #[inline] - pub fn is_empty(&self) -> bool { - self.as_borrowed().is_empty() - } -} - /// Implementation of functionality for [`PyUntypedArray`]. #[doc(alias = "PyUntypedArray")] pub trait PyUntypedArrayMethods<'py>: Sealed { @@ -274,13 +90,13 @@ pub trait PyUntypedArrayMethods<'py>: Sealed { /// /// ``` /// use numpy::prelude::*; - /// use numpy::{dtype_bound, PyArray}; + /// use numpy::{dtype, PyArray}; /// use pyo3::Python; /// /// Python::with_gil(|py| { - /// let array = PyArray::from_vec_bound(py, vec![1_i32, 2, 3]); + /// let array = PyArray::from_vec(py, vec![1_i32, 2, 3]); /// - /// assert!(array.dtype().is_equiv_to(&dtype_bound::(py))); + /// assert!(array.dtype().is_equiv_to(&dtype::(py))); /// }); /// ``` /// @@ -295,19 +111,20 @@ pub trait PyUntypedArrayMethods<'py>: Sealed { /// /// ``` /// use numpy::{PyArray1, PyUntypedArrayMethods}; - /// use pyo3::{types::{IntoPyDict, PyAnyMethods}, Python}; + /// use pyo3::{types::{IntoPyDict, PyAnyMethods}, Python, ffi::c_str}; /// + /// # fn main() -> pyo3::PyResult<()> { /// Python::with_gil(|py| { - /// let array = PyArray1::arange_bound(py, 0, 10, 1); + /// let array = PyArray1::arange(py, 0, 10, 1); /// assert!(array.is_contiguous()); /// /// let view = py - /// .eval_bound("array[::2]", None, Some(&[("array", array)].into_py_dict_bound(py))) - /// .unwrap() - /// .downcast_into::>() - /// .unwrap(); + /// .eval(c_str!("array[::2]"), None, Some(&[("array", array)].into_py_dict(py)?))? + /// .downcast_into::>()?; /// assert!(!view.is_contiguous()); - /// }); + /// # Ok(()) + /// }) + /// # } /// ``` fn is_contiguous(&self) -> bool { unsafe { @@ -339,7 +156,7 @@ pub trait PyUntypedArrayMethods<'py>: Sealed { /// use pyo3::Python; /// /// Python::with_gil(|py| { - /// let arr = PyArray3::::zeros_bound(py, [4, 5, 6], false); + /// let arr = PyArray3::::zeros(py, [4, 5, 6], false); /// /// assert_eq!(arr.ndim(), 3); /// }); @@ -363,7 +180,7 @@ pub trait PyUntypedArrayMethods<'py>: Sealed { /// use pyo3::Python; /// /// Python::with_gil(|py| { - /// let arr = PyArray3::::zeros_bound(py, [4, 5, 6], false); + /// let arr = PyArray3::::zeros(py, [4, 5, 6], false); /// /// assert_eq!(arr.strides(), &[240, 48, 8]); /// }); @@ -395,7 +212,7 @@ pub trait PyUntypedArrayMethods<'py>: Sealed { /// use pyo3::Python; /// /// Python::with_gil(|py| { - /// let arr = PyArray3::::zeros_bound(py, [4, 5, 6], false); + /// let arr = PyArray3::::zeros(py, [4, 5, 6], false); /// /// assert_eq!(arr.shape(), &[4, 5, 6]); /// }); diff --git a/tests/array.rs b/tests/array.rs index 856d4af10..af4bee1b2 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -5,24 +5,25 @@ use half::{bf16, f16}; use ndarray::{array, s, Array1, Dim}; use numpy::prelude::*; use numpy::{ - dtype_bound, get_array_module, npyffi::NPY_ORDER, pyarray_bound, PyArray, PyArray1, PyArray2, - PyArrayDescr, PyFixedString, PyFixedUnicode, + dtype, get_array_module, npyffi::NPY_ORDER, pyarray, PyArray, PyArray1, PyArray2, PyArrayDescr, + PyFixedString, PyFixedUnicode, }; +use pyo3::ffi::c_str; use pyo3::{ py_run, pyclass, pymethods, types::{IntoPyDict, PyAnyMethods, PyDict, PyList}, Bound, Py, Python, }; -#[cfg(feature = "gil-refs")] -use {numpy::PyArrayDyn, pyo3::PyResult}; fn get_np_locals(py: Python<'_>) -> Bound<'_, PyDict> { - [("np", get_array_module(py).unwrap())].into_py_dict_bound(py) + [("np", get_array_module(py).unwrap())] + .into_py_dict(py) + .unwrap() } fn not_contiguous_array(py: Python<'_>) -> Bound<'_, PyArray1> { - py.eval_bound( - "np.array([1, 2, 3, 4], dtype='int32')[::2]", + py.eval( + c_str!("np.array([1, 2, 3, 4], dtype='int32')[::2]"), None, Some(&get_np_locals(py)), ) @@ -36,7 +37,7 @@ fn new_c_order() { Python::with_gil(|py| { let dims = [3, 5]; - let arr = PyArray::::zeros_bound(py, dims, false); + let arr = PyArray::::zeros(py, dims, false); assert!(arr.ndim() == 2); assert!(arr.dims() == dims); @@ -58,7 +59,7 @@ fn new_fortran_order() { Python::with_gil(|py| { let dims = [3, 5]; - let arr = PyArray::::zeros_bound(py, dims, true); + let arr = PyArray::::zeros(py, dims, true); assert!(arr.ndim() == 2); assert!(arr.dims() == dims); @@ -80,7 +81,7 @@ fn tuple_as_dim() { Python::with_gil(|py| { let dims = (3, 5); - let arr = PyArray::::zeros_bound(py, dims, false); + let arr = PyArray::::zeros(py, dims, false); assert!(arr.ndim() == 2); assert!(arr.dims() == [3, 5]); @@ -90,11 +91,11 @@ fn tuple_as_dim() { #[test] fn rank_zero_array_has_invalid_strides_dimensions() { Python::with_gil(|py| { - let arr = PyArray::::zeros_bound(py, (), false); + let arr = PyArray::::zeros(py, (), false); assert_eq!(arr.ndim(), 0); - assert_eq!(arr.strides(), &[]); - assert_eq!(arr.shape(), &[]); + assert_eq!(arr.strides(), &[] as &[isize]); + assert_eq!(arr.shape(), &[] as &[usize]); assert_eq!(arr.len(), 1); assert!(!arr.is_empty()); @@ -108,7 +109,7 @@ fn zeros() { Python::with_gil(|py| { let dims = [3, 4]; - let arr = PyArray::::zeros_bound(py, dims, false); + let arr = PyArray::::zeros(py, dims, false); assert!(arr.ndim() == 2); assert!(arr.dims() == dims); @@ -116,7 +117,7 @@ fn zeros() { let size = size_of::() as isize; assert!(arr.strides() == [dims[1] as isize * size, size]); - let arr = PyArray::::zeros_bound(py, dims, true); + let arr = PyArray::::zeros(py, dims, true); assert!(arr.ndim() == 2); assert!(arr.dims() == dims); @@ -129,7 +130,7 @@ fn zeros() { #[test] fn arange() { Python::with_gil(|py| { - let arr = PyArray::::arange_bound(py, 0.0, 1.0, 0.1); + let arr = PyArray::::arange(py, 0.0, 1.0, 0.1); assert_eq!(arr.ndim(), 1); assert_eq!(arr.dims(), Dim([10])); @@ -139,7 +140,7 @@ fn arange() { #[test] fn as_array() { Python::with_gil(|py| { - let pyarr = PyArray::::zeros_bound(py, [3, 2, 4], false).readonly(); + let pyarr = PyArray::::zeros(py, [3, 2, 4], false).readonly(); let arr = pyarr.as_array(); assert_eq!(pyarr.shape(), arr.shape()); @@ -173,7 +174,7 @@ fn as_raw_array() { #[test] fn as_slice() { Python::with_gil(|py| { - let arr = PyArray::::zeros_bound(py, [3, 2, 4], false); + let arr = PyArray::::zeros(py, [3, 2, 4], false); assert_eq!(arr.readonly().as_slice().unwrap().len(), 3 * 2 * 4); let not_contiguous = not_contiguous_array(py); @@ -185,7 +186,7 @@ fn as_slice() { #[test] fn is_instance() { Python::with_gil(|py| { - let arr = PyArray2::::zeros_bound(py, [3, 5], false); + let arr = PyArray2::::zeros(py, [3, 5], false); assert!(arr.is_instance_of::>()); assert!(!arr.is_instance_of::()); @@ -195,7 +196,7 @@ fn is_instance() { #[test] fn from_vec2() { Python::with_gil(|py| { - let pyarray = PyArray::from_vec2_bound(py, &[vec![1, 2, 3], vec![4, 5, 6]]).unwrap(); + let pyarray = PyArray::from_vec2(py, &[vec![1, 2, 3], vec![4, 5, 6]]).unwrap(); assert_eq!(pyarray.readonly().as_array(), array![[1, 2, 3], [4, 5, 6]]); }); @@ -204,7 +205,7 @@ fn from_vec2() { #[test] fn from_vec2_ragged() { Python::with_gil(|py| { - let pyarray = PyArray::from_vec2_bound(py, &[vec![1, 2, 3], vec![4, 5]]); + let pyarray = PyArray::from_vec2(py, &[vec![1, 2, 3], vec![4, 5]]); let err = pyarray.unwrap_err(); assert_eq!(err.to_string(), "invalid length: 2, but expected 3"); @@ -214,7 +215,7 @@ fn from_vec2_ragged() { #[test] fn from_vec3() { Python::with_gil(|py| { - let pyarray = PyArray::from_vec3_bound( + let pyarray = PyArray::from_vec3( py, &[ vec![vec![1, 2], vec![3, 4]], @@ -234,7 +235,7 @@ fn from_vec3() { #[test] fn from_vec3_ragged() { Python::with_gil(|py| { - let pyarray = PyArray::from_vec3_bound( + let pyarray = PyArray::from_vec3( py, &[ vec![vec![1, 2], vec![3, 4]], @@ -246,7 +247,7 @@ fn from_vec3_ragged() { let err = pyarray.unwrap_err(); assert_eq!(err.to_string(), "invalid length: 1, but expected 2"); - let pyarray = PyArray::from_vec3_bound( + let pyarray = PyArray::from_vec3( py, &[ vec![vec![1, 2], vec![3, 4]], @@ -260,101 +261,10 @@ fn from_vec3_ragged() { }); } -#[test] -#[cfg(feature = "gil-refs")] -fn extract_as_fixed() { - Python::with_gil(|py| { - let locals = get_np_locals(py); - let pyarray: &PyArray1 = py - .eval_bound("np.array([1, 2, 3], dtype='int32')", Some(&locals), None) - .unwrap() - .extract() - .unwrap(); - - assert_eq!(pyarray.readonly().as_array(), array![1, 2, 3]); - }); -} - -#[test] -#[cfg(feature = "gil-refs")] -fn extract_as_dyn() { - Python::with_gil(|py| { - let locals = get_np_locals(py); - let pyarray: &PyArrayDyn = py - .eval_bound( - "np.array([[1, 2], [3, 4]], dtype='int32')", - Some(&locals), - None, - ) - .unwrap() - .extract() - .unwrap(); - - assert_eq!( - pyarray.readonly().as_array(), - array![[1, 2], [3, 4]].into_dyn() - ); - }); -} - -#[test] -#[cfg(feature = "gil-refs")] -fn extract_fail_by_check() { - Python::with_gil(|py| { - let locals = get_np_locals(py); - let pyarray: PyResult<&PyArray2> = py - .eval_bound("[1, 2, 3]", Some(&locals), None) - .unwrap() - .extract(); - - let err = pyarray.unwrap_err(); - assert_eq!( - err.to_string(), - "TypeError: 'list' object cannot be converted to 'PyArray'" - ); - }); -} - -#[test] -#[cfg(feature = "gil-refs")] -fn extract_fail_by_dim() { - Python::with_gil(|py| { - let locals = get_np_locals(py); - let pyarray: PyResult<&PyArray2> = py - .eval_bound("np.array([1, 2, 3], dtype='int32')", Some(&locals), None) - .unwrap() - .extract(); - - let err = pyarray.unwrap_err(); - assert_eq!( - err.to_string(), - "TypeError: dimensionality mismatch:\n from=1, to=2" - ); - }); -} - -#[test] -#[cfg(feature = "gil-refs")] -fn extract_fail_by_dtype() { - Python::with_gil(|py| { - let locals = get_np_locals(py); - let pyarray: PyResult<&PyArray1> = py - .eval_bound("np.array([1, 2, 3], dtype='float64')", Some(&locals), None) - .unwrap() - .extract(); - - let err = pyarray.unwrap_err(); - assert_eq!( - err.to_string(), - "TypeError: type mismatch:\n from=float64, to=int32" - ); - }); -} - #[test] fn array_cast() { Python::with_gil(|py| { - let arr_f64 = pyarray_bound![py, [1.5, 2.5, 3.5], [1.5, 2.5, 3.5]]; + let arr_f64 = pyarray![py, [1.5, 2.5, 3.5], [1.5, 2.5, 3.5]]; let arr_i32 = arr_f64.cast::(false).unwrap(); assert_eq!(arr_i32.readonly().as_array(), array![[1, 2, 3], [1, 2, 3]]); @@ -365,12 +275,12 @@ fn array_cast() { fn handle_negative_strides() { Python::with_gil(|py| { let arr = array![[2, 3], [4, 5u32]]; - let pyarr = arr.to_pyarray_bound(py); + let pyarr = arr.to_pyarray(py); let neg_str_pyarr = py - .eval_bound( - "a[::-1]", - Some(&[("a", pyarr)].into_py_dict_bound(py)), + .eval( + c_str!("a[::-1]"), + Some(&[("a", pyarr)].into_py_dict(py).unwrap()), None, ) .unwrap() @@ -388,19 +298,19 @@ fn handle_negative_strides() { fn dtype_via_python_attribute() { Python::with_gil(|py| { let arr = array![[2, 3], [4, 5u32]]; - let pyarr = arr.to_pyarray_bound(py); + let pyarr = arr.to_pyarray(py); let dt = py - .eval_bound( - "a.dtype", - Some(&[("a", pyarr)].into_py_dict_bound(py)), + .eval( + c_str!("a.dtype"), + Some(&[("a", pyarr)].into_py_dict(py).unwrap()), None, ) .unwrap() .downcast_into::() .unwrap(); - assert!(dt.is_equiv_to(&dtype_bound::(py))); + assert!(dt.is_equiv_to(&dtype::(py))); }); } @@ -415,7 +325,7 @@ impl Owner { fn array(this: Bound<'_, Self>) -> Bound<'_, PyArray1> { let array = &this.borrow().array; - unsafe { PyArray1::borrow_from_array_bound(array, this.into_any()) } + unsafe { PyArray1::borrow_from_array(array, this.into_any()) } } } @@ -441,7 +351,7 @@ fn borrow_from_array_works() { #[test] fn downcasting_works() { Python::with_gil(|py| { - let ob = PyArray::from_slice_bound(py, &[1_i32, 2, 3]).into_any(); + let ob = PyArray::from_slice(py, &[1_i32, 2, 3]).into_any(); assert!(ob.downcast::>().is_ok()); }); @@ -450,7 +360,7 @@ fn downcasting_works() { #[test] fn downcasting_respects_element_type() { Python::with_gil(|py| { - let ob = PyArray::from_slice_bound(py, &[1_i32, 2, 3]).into_any(); + let ob = PyArray::from_slice(py, &[1_i32, 2, 3]).into_any(); assert!(ob.downcast::>().is_err()); }); @@ -459,7 +369,7 @@ fn downcasting_respects_element_type() { #[test] fn downcasting_respects_dimensionality() { Python::with_gil(|py| { - let ob = PyArray::from_slice_bound(py, &[1_i32, 2, 3]).into_any(); + let ob = PyArray::from_slice(py, &[1_i32, 2, 3]).into_any(); assert!(ob.downcast::>().is_err()); }); @@ -468,7 +378,7 @@ fn downcasting_respects_dimensionality() { #[test] fn unbind_works() { let arr: Py> = Python::with_gil(|py| { - let arr = PyArray::from_slice_bound(py, &[1_i32, 2, 3]); + let arr = PyArray::from_slice(py, &[1_i32, 2, 3]); arr.unbind() }); @@ -480,28 +390,11 @@ fn unbind_works() { }); } -#[test] -#[cfg(feature = "gil-refs")] -fn to_owned_works() { - let arr: Py> = Python::with_gil(|py| { - let arr = PyArray::from_slice_bound(py, &[1_i32, 2, 3]); - - #[allow(deprecated)] - arr.as_gil_ref().to_owned() - }); - - Python::with_gil(|py| { - let arr = arr.bind(py); - - assert_eq!(arr.readonly().as_slice().unwrap(), &[1, 2, 3]); - }); -} - #[test] fn copy_to_works() { Python::with_gil(|py| { - let arr1 = PyArray::arange_bound(py, 2.0, 5.0, 1.0); - let arr2 = unsafe { PyArray::::new_bound(py, [3], false) }; + let arr1 = PyArray::arange(py, 2.0, 5.0, 1.0); + let arr2 = unsafe { PyArray::::new(py, [3], false) }; arr1.copy_to(&arr2).unwrap(); @@ -512,7 +405,7 @@ fn copy_to_works() { #[test] fn get_works() { Python::with_gil(|py| { - let array = pyarray_bound![py, [[1, 2], [3, 4]], [[5, 6], [7, 8]], [[9, 10], [11, 12]]]; + let array = pyarray![py, [[1, 2], [3, 4]], [[5, 6], [7, 8]], [[9, 10], [11, 12]]]; unsafe { assert_eq!(array.get([0, 0, 0]), Some(&1)); @@ -531,7 +424,7 @@ fn get_works() { #[test] fn permute_and_transpose() { Python::with_gil(|py| { - let array = array![[0, 1, 2], [3, 4, 5]].into_pyarray_bound(py); + let array = array![[0, 1, 2], [3, 4, 5]].into_pyarray(py); let permuted = array.permute(Some([1, 0])).unwrap(); assert_eq!( @@ -551,7 +444,7 @@ fn permute_and_transpose() { array![[0, 3], [1, 4], [2, 5]] ); - let array = pyarray_bound![py, [[1, 2], [3, 4]], [[5, 6], [7, 8]], [[9, 10], [11, 12]]]; + let array = pyarray![py, [[1, 2], [3, 4]], [[5, 6], [7, 8]], [[9, 10], [11, 12]]]; let permuted = array.permute(Some([0, 2, 1])).unwrap(); assert_eq!( @@ -564,7 +457,7 @@ fn permute_and_transpose() { #[test] fn reshape() { Python::with_gil(|py| { - let array = PyArray::from_iter_bound(py, 0..9) + let array = PyArray::from_iter(py, 0..9) .reshape_with_order([3, 3], NPY_ORDER::NPY_FORTRANORDER) .unwrap(); @@ -582,12 +475,12 @@ fn reshape() { #[test] fn half_f16_works() { Python::with_gil(|py| { - let np = py.eval_bound("__import__('numpy')", None, None).unwrap(); - let locals = [("np", &np)].into_py_dict_bound(py); + let np = py.eval(c_str!("__import__('numpy')"), None, None).unwrap(); + let locals = [("np", &np)].into_py_dict(py).unwrap(); let array = py - .eval_bound( - "np.array([[1, 2], [3, 4]], dtype='float16')", + .eval( + c_str!("np.array([[1, 2], [3, 4]], dtype='float16')"), None, Some(&locals), ) @@ -620,17 +513,17 @@ fn half_f16_works() { #[test] fn half_bf16_works() { Python::with_gil(|py| { - let np = py.eval_bound("__import__('numpy')", None, None).unwrap(); + let np = py.eval(c_str!("__import__('numpy')"), None, None).unwrap(); // NumPy itself does not provide a `bfloat16` dtype itself, // so we import ml_dtypes which does register such a dtype. let mldt = py - .eval_bound("__import__('ml_dtypes')", None, None) + .eval(c_str!("__import__('ml_dtypes')"), None, None) .unwrap(); - let locals = [("np", &np), ("mldt", &mldt)].into_py_dict_bound(py); + let locals = [("np", &np), ("mldt", &mldt)].into_py_dict(py).unwrap(); let array = py - .eval_bound( - "np.array([[1, 2], [3, 4]], dtype='bfloat16')", + .eval( + c_str!("np.array([[1, 2], [3, 4]], dtype='bfloat16')"), None, Some(&locals), ) @@ -662,12 +555,12 @@ fn half_bf16_works() { #[test] fn ascii_strings_with_explicit_dtype_works() { Python::with_gil(|py| { - let np = py.eval_bound("__import__('numpy')", None, None).unwrap(); - let locals = [("np", &np)].into_py_dict_bound(py); + let np = py.eval(c_str!("__import__('numpy')"), None, None).unwrap(); + let locals = [("np", &np)].into_py_dict(py).unwrap(); let array = py - .eval_bound( - "np.array([b'foo', b'bar', b'foobar'], dtype='S6')", + .eval( + c_str!("np.array([b'foo', b'bar', b'foobar'], dtype='S6')"), None, Some(&locals), ) @@ -698,12 +591,12 @@ fn ascii_strings_with_explicit_dtype_works() { #[test] fn unicode_strings_with_explicit_dtype_works() { Python::with_gil(|py| { - let np = py.eval_bound("__import__('numpy')", None, None).unwrap(); - let locals = [("np", &np)].into_py_dict_bound(py); + let np = py.eval(c_str!("__import__('numpy')"), None, None).unwrap(); + let locals = [("np", &np)].into_py_dict(py).unwrap(); let array = py - .eval_bound( - "np.array(['foo', 'bar', 'foobar'], dtype='U6')", + .eval( + c_str!("np.array(['foo', 'bar', 'foobar'], dtype='U6')"), None, Some(&locals), ) @@ -719,7 +612,14 @@ fn unicode_strings_with_explicit_dtype_works() { assert_eq!(array[1].0, [b'b' as _, b'a' as _, b'r' as _, 0, 0, 0]); assert_eq!( array[2].0, - [b'f' as _, b'o' as _, b'o' as _, b'b' as _, b'a' as _, b'r' as _] + [ + b'f' as u32, + b'o' as _, + b'o' as _, + b'b' as _, + b'a' as _, + b'r' as _ + ] ); } @@ -737,12 +637,12 @@ fn unicode_strings_with_explicit_dtype_works() { #[test] fn ascii_strings_ignore_byteorder() { Python::with_gil(|py| { - let np = py.eval_bound("__import__('numpy')", None, None).unwrap(); - let locals = [("np", &np)].into_py_dict_bound(py); + let np = py.eval(c_str!("__import__('numpy')"), None, None).unwrap(); + let locals = [("np", &np)].into_py_dict(py).unwrap(); let native_endian_works = py - .eval_bound( - "np.array([b'foo', b'bar'], dtype='=S3')", + .eval( + c_str!("np.array([b'foo', b'bar'], dtype='=S3')"), None, Some(&locals), ) @@ -751,8 +651,8 @@ fn ascii_strings_ignore_byteorder() { .is_ok(); let little_endian_works = py - .eval_bound( - "np.array(['bfoo', b'bar'], dtype='>>() .is_ok(); let little_endian_works = py - .eval_bound("np.array(['foo', 'bar'], dtype='>>() .is_ok(); let big_endian_works = py - .eval_bound("np.array(['foo', 'bar'], dtype='>U3')", None, Some(&locals)) + .eval( + c_str!("np.array(['foo', 'bar'], dtype='>U3')"), + None, + Some(&locals), + ) .unwrap() .downcast::>>() .is_ok(); diff --git a/tests/array_like.rs b/tests/array_like.rs index cd96f63f5..aa185b174 100644 --- a/tests/array_like.rs +++ b/tests/array_like.rs @@ -1,12 +1,15 @@ use ndarray::array; use numpy::{get_array_module, AllowTypeChange, PyArrayLike1, PyArrayLike2, PyArrayLikeDyn}; use pyo3::{ + ffi::c_str, types::{IntoPyDict, PyAnyMethods, PyDict}, Bound, Python, }; fn get_np_locals(py: Python<'_>) -> Bound<'_, PyDict> { - [("np", get_array_module(py).unwrap())].into_py_dict_bound(py) + [("np", get_array_module(py).unwrap())] + .into_py_dict(py) + .unwrap() } #[test] @@ -14,8 +17,8 @@ fn extract_reference() { Python::with_gil(|py| { let locals = get_np_locals(py); let py_array = py - .eval_bound( - "np.array([[1,2],[3,4]], dtype='float64')", + .eval( + c_str!("np.array([[1,2],[3,4]], dtype='float64')"), Some(&locals), None, ) @@ -34,8 +37,8 @@ fn convert_array_on_extract() { Python::with_gil(|py| { let locals = get_np_locals(py); let py_array = py - .eval_bound( - "np.array([[1,2],[3,4]], dtype='int32')", + .eval( + c_str!("np.array([[1,2],[3,4]], dtype='int32')"), Some(&locals), None, ) @@ -54,7 +57,9 @@ fn convert_array_on_extract() { #[test] fn convert_list_on_extract() { Python::with_gil(|py| { - let py_list = py.eval_bound("[[1.0,2.0],[3.0,4.0]]", None, None).unwrap(); + let py_list = py + .eval(c_str!("[[1.0,2.0],[3.0,4.0]]"), None, None) + .unwrap(); let extracted_array = py_list.extract::>().unwrap(); assert_eq!(array![[1.0, 2.0], [3.0, 4.0]], extracted_array.as_array()); @@ -66,7 +71,11 @@ fn convert_array_in_list_on_extract() { Python::with_gil(|py| { let locals = get_np_locals(py); let py_array = py - .eval_bound("[np.array([1.0, 2.0]), [3.0, 4.0]]", Some(&locals), None) + .eval( + c_str!("[np.array([1.0, 2.0]), [3.0, 4.0]]"), + Some(&locals), + None, + ) .unwrap(); let extracted_array = py_array.extract::>().unwrap(); @@ -78,7 +87,7 @@ fn convert_array_in_list_on_extract() { fn convert_list_on_extract_dyn() { Python::with_gil(|py| { let py_list = py - .eval_bound("[[[1,2],[3,4]],[[5,6],[7,8]]]", None, None) + .eval(c_str!("[[[1,2],[3,4]],[[5,6],[7,8]]]"), None, None) .unwrap(); let extracted_array = py_list .extract::>() @@ -94,7 +103,7 @@ fn convert_list_on_extract_dyn() { #[test] fn convert_1d_list_on_extract() { Python::with_gil(|py| { - let py_list = py.eval_bound("[1,2,3,4]", None, None).unwrap(); + let py_list = py.eval(c_str!("[1,2,3,4]"), None, None).unwrap(); let extracted_array_1d = py_list.extract::>().unwrap(); let extracted_array_dyn = py_list.extract::>().unwrap(); @@ -111,8 +120,8 @@ fn unsafe_cast_shall_fail() { Python::with_gil(|py| { let locals = get_np_locals(py); let py_list = py - .eval_bound( - "np.array([1.1,2.2,3.3,4.4], dtype='float64')", + .eval( + c_str!("np.array([1.1,2.2,3.3,4.4], dtype='float64')"), Some(&locals), None, ) @@ -128,8 +137,8 @@ fn unsafe_cast_with_coerce_works() { Python::with_gil(|py| { let locals = get_np_locals(py); let py_list = py - .eval_bound( - "np.array([1.1,2.2,3.3,4.4], dtype='float64')", + .eval( + c_str!("np.array([1.1,2.2,3.3,4.4], dtype='float64')"), Some(&locals), None, ) diff --git a/tests/borrow.rs b/tests/borrow.rs index 356046c65..2cf38bb84 100644 --- a/tests/borrow.rs +++ b/tests/borrow.rs @@ -5,6 +5,7 @@ use numpy::{ PyReadonlyArray3, PyReadwriteArray3, PyUntypedArrayMethods, }; use pyo3::{ + ffi::c_str, py_run, pyclass, pymethods, types::{IntoPyDict, PyAnyMethods}, Py, Python, @@ -13,8 +14,8 @@ use pyo3::{ #[test] fn distinct_borrows() { Python::with_gil(|py| { - let array1 = PyArray::::zeros_bound(py, (1, 2, 3), false); - let array2 = PyArray::::zeros_bound(py, (1, 2, 3), false); + let array1 = PyArray::::zeros(py, (1, 2, 3), false); + let array2 = PyArray::::zeros(py, (1, 2, 3), false); let exclusive1 = array1.readwrite(); let exclusive2 = array2.readwrite(); @@ -27,7 +28,7 @@ fn distinct_borrows() { #[test] fn multiple_shared_borrows() { Python::with_gil(|py| { - let array = PyArray::::zeros_bound(py, (1, 2, 3), false); + let array = PyArray::::zeros(py, (1, 2, 3), false); let shared1 = array.readonly(); let shared2 = array.readonly(); @@ -41,7 +42,7 @@ fn multiple_shared_borrows() { #[should_panic(expected = "AlreadyBorrowed")] fn exclusive_and_shared_borrows() { Python::with_gil(|py| { - let array = PyArray::::zeros_bound(py, (1, 2, 3), false); + let array = PyArray::::zeros(py, (1, 2, 3), false); let _exclusive = array.readwrite(); let _shared = array.readonly(); @@ -52,7 +53,7 @@ fn exclusive_and_shared_borrows() { #[should_panic(expected = "AlreadyBorrowed")] fn shared_and_exclusive_borrows() { Python::with_gil(|py| { - let array = PyArray::::zeros_bound(py, (1, 2, 3), false); + let array = PyArray::::zeros(py, (1, 2, 3), false); let _shared = array.readonly(); let _exclusive = array.readwrite(); @@ -62,7 +63,7 @@ fn shared_and_exclusive_borrows() { #[test] fn multiple_exclusive_borrows() { Python::with_gil(|py| { - let array = PyArray::::zeros_bound(py, (1, 2, 3), false); + let array = PyArray::::zeros(py, (1, 2, 3), false); let _exclusive = array.try_readwrite().unwrap(); @@ -74,7 +75,7 @@ fn multiple_exclusive_borrows() { #[test] fn exclusive_borrow_requires_writeable() { Python::with_gil(|py| { - let array = PyArray::::zeros_bound(py, (1, 2, 3), false); + let array = PyArray::::zeros(py, (1, 2, 3), false); unsafe { (*array.as_array_ptr()).flags &= !NPY_ARRAY_WRITEABLE; @@ -101,7 +102,7 @@ fn borrows_span_frames() { Python::with_gil(|py| { let borrower = Py::new(py, Borrower).unwrap(); - let array = PyArray::::zeros_bound(py, (1, 2, 3), false); + let array = PyArray::::zeros(py, (1, 2, 3), false); let _exclusive = array.readwrite(); @@ -112,7 +113,7 @@ fn borrows_span_frames() { #[test] fn borrows_span_threads() { Python::with_gil(|py| { - let array = PyArray::::zeros_bound(py, (1, 2, 3), false); + let array = PyArray::::zeros(py, (1, 2, 3), false); let _exclusive = array.readwrite(); @@ -135,7 +136,7 @@ fn borrows_span_threads() { #[test] fn shared_borrows_can_be_cloned() { Python::with_gil(|py| { - let array = PyArray::::zeros_bound(py, (1, 2, 3), false); + let array = PyArray::::zeros(py, (1, 2, 3), false); let shared1 = array.readonly(); let shared2 = shared1.clone(); @@ -149,18 +150,18 @@ fn shared_borrows_can_be_cloned() { #[should_panic(expected = "AlreadyBorrowed")] fn overlapping_views_conflict() { Python::with_gil(|py| { - let array = PyArray::::zeros_bound(py, (1, 2, 3), false); - let locals = [("array", array)].into_py_dict_bound(py); + let array = PyArray::::zeros(py, (1, 2, 3), false); + let locals = [("array", array)].into_py_dict(py).unwrap(); let view1 = py - .eval_bound("array[0,0,0:2]", None, Some(&locals)) + .eval(c_str!("array[0,0,0:2]"), None, Some(&locals)) .unwrap() .downcast_into::>() .unwrap(); assert_eq!(view1.shape(), [2]); let view2 = py - .eval_bound("array[0,0,1:3]", None, Some(&locals)) + .eval(c_str!("array[0,0,1:3]"), None, Some(&locals)) .unwrap() .downcast_into::>() .unwrap(); @@ -174,18 +175,18 @@ fn overlapping_views_conflict() { #[test] fn non_overlapping_views_do_not_conflict() { Python::with_gil(|py| { - let array = PyArray::::zeros_bound(py, (1, 2, 3), false); - let locals = [("array", array)].into_py_dict_bound(py); + let array = PyArray::::zeros(py, (1, 2, 3), false); + let locals = [("array", array)].into_py_dict(py).unwrap(); let view1 = py - .eval_bound("array[0,0,0:1]", None, Some(&locals)) + .eval(c_str!("array[0,0,0:1]"), None, Some(&locals)) .unwrap() .downcast_into::>() .unwrap(); assert_eq!(view1.shape(), [1]); let view2 = py - .eval_bound("array[0,0,2:3]", None, Some(&locals)) + .eval(c_str!("array[0,0,2:3]"), None, Some(&locals)) .unwrap() .downcast_into::>() .unwrap(); @@ -203,18 +204,18 @@ fn non_overlapping_views_do_not_conflict() { #[should_panic(expected = "AlreadyBorrowed")] fn conflict_due_to_overlapping_views() { Python::with_gil(|py| { - let array = PyArray::::zeros_bound(py, 3, false); - let locals = [("array", array)].into_py_dict_bound(py); + let array = PyArray::::zeros(py, 3, false); + let locals = [("array", array)].into_py_dict(py).unwrap(); let view1 = py - .eval_bound("array[0:2]", None, Some(&locals)) + .eval(c_str!("array[0:2]"), None, Some(&locals)) .unwrap() .downcast_into::>() .unwrap(); assert_eq!(view1.shape(), [2]); let view2 = py - .eval_bound("array[1:3]", None, Some(&locals)) + .eval(c_str!("array[1:3]"), None, Some(&locals)) .unwrap() .downcast_into::>() .unwrap(); @@ -229,18 +230,18 @@ fn conflict_due_to_overlapping_views() { #[should_panic(expected = "AlreadyBorrowed")] fn conflict_due_to_reborrow_of_overlapping_views() { Python::with_gil(|py| { - let array = PyArray::::zeros_bound(py, 3, false); - let locals = [("array", array)].into_py_dict_bound(py); + let array = PyArray::::zeros(py, 3, false); + let locals = [("array", array)].into_py_dict(py).unwrap(); let view1 = py - .eval_bound("array[0:2]", None, Some(&locals)) + .eval(c_str!("array[0:2]"), None, Some(&locals)) .unwrap() .downcast_into::>() .unwrap(); assert_eq!(view1.shape(), [2]); let view2 = py - .eval_bound("array[1:3]", None, Some(&locals)) + .eval(c_str!("array[1:3]"), None, Some(&locals)) .unwrap() .downcast_into::>() .unwrap(); @@ -257,25 +258,25 @@ fn conflict_due_to_reborrow_of_overlapping_views() { #[test] fn interleaved_views_do_not_conflict() { Python::with_gil(|py| { - let array = PyArray::::zeros_bound(py, (23, 42, 3), false); - let locals = [("array", array)].into_py_dict_bound(py); + let array = PyArray::::zeros(py, (23, 42, 3), false); + let locals = [("array", array)].into_py_dict(py).unwrap(); let view1 = py - .eval_bound("array[:,:,0]", None, Some(&locals)) + .eval(c_str!("array[:,:,0]"), None, Some(&locals)) .unwrap() .downcast_into::>() .unwrap(); assert_eq!(view1.shape(), [23, 42]); let view2 = py - .eval_bound("array[:,:,1]", None, Some(&locals)) + .eval(c_str!("array[:,:,1]"), None, Some(&locals)) .unwrap() .downcast_into::>() .unwrap(); assert_eq!(view2.shape(), [23, 42]); let view3 = py - .eval_bound("array[:,:,2]", None, Some(&locals)) + .eval(c_str!("array[:,:,2]"), None, Some(&locals)) .unwrap() .downcast_into::>() .unwrap(); @@ -294,7 +295,7 @@ fn interleaved_views_do_not_conflict() { #[test] fn extract_readonly() { Python::with_gil(|py| { - let ob = PyArray::::zeros_bound(py, (1, 2, 3), false).into_any(); + let ob = PyArray::::zeros(py, (1, 2, 3), false).into_any(); ob.extract::>().unwrap(); }); } @@ -302,7 +303,7 @@ fn extract_readonly() { #[test] fn extract_readwrite() { Python::with_gil(|py| { - let ob = PyArray::::zeros_bound(py, (1, 2, 3), false).into_any(); + let ob = PyArray::::zeros(py, (1, 2, 3), false).into_any(); ob.extract::>().unwrap(); }); } @@ -310,7 +311,7 @@ fn extract_readwrite() { #[test] fn readonly_as_array_slice_get() { Python::with_gil(|py| { - let array = PyArray::::zeros_bound(py, (1, 2, 3), false); + let array = PyArray::::zeros(py, (1, 2, 3), false); let array = array.readonly(); assert_eq!(array.as_array().shape(), [1, 2, 3]); @@ -322,7 +323,7 @@ fn readonly_as_array_slice_get() { #[test] fn readwrite_as_array_slice() { Python::with_gil(|py| { - let array = PyArray::::zeros_bound(py, (1, 2, 3), false); + let array = PyArray::::zeros(py, (1, 2, 3), false); let mut array = array.readwrite(); assert_eq!(array.as_array().shape(), [1, 2, 3]); @@ -337,7 +338,7 @@ fn readwrite_as_array_slice() { #[test] fn resize_using_exclusive_borrow() { Python::with_gil(|py| { - let array = PyArray::::zeros_bound(py, 3, false); + let array = PyArray::::zeros(py, 3, false); assert_eq!(array.shape(), [3]); let mut array = array.readwrite(); @@ -351,11 +352,15 @@ fn resize_using_exclusive_borrow() { #[test] fn can_make_python_array_nonwriteable() { Python::with_gil(|py| { - let array = PyArray1::::zeros_bound(py, 10, false); - let locals = [("array", &array)].into_py_dict_bound(py); + let array = PyArray1::::zeros(py, 10, false); + let locals = [("array", &array)].into_py_dict(py).unwrap(); array.readwrite().make_nonwriteable(); assert!(!py - .eval_bound("array.flags.writeable", None, Some(&locals)) + .eval( + pyo3::ffi::c_str!("array.flags.writeable"), + None, + Some(&locals) + ) .unwrap() .extract::() .unwrap()) @@ -366,7 +371,7 @@ fn can_make_python_array_nonwriteable() { #[test] fn matrix_from_numpy() { Python::with_gil(|py| { - let array = numpy::pyarray_bound![py, [0, 1, 2], [3, 4, 5], [6, 7, 8]]; + let array = numpy::pyarray![py, [0, 1, 2], [3, 4, 5], [6, 7, 8]]; { let array = array.readonly(); @@ -404,7 +409,7 @@ fn matrix_from_numpy() { }); Python::with_gil(|py| { - let array = numpy::pyarray_bound![py, 0, 1, 2]; + let array = numpy::pyarray![py, 0, 1, 2]; { let array = array.readonly(); @@ -430,7 +435,7 @@ fn matrix_from_numpy() { }); Python::with_gil(|py| { - let array = PyArray::::zeros_bound(py, (2, 2, 2), false); + let array = PyArray::::zeros(py, (2, 2, 2), false); let array = array.readonly(); let matrix: Option> = @@ -439,11 +444,11 @@ fn matrix_from_numpy() { }); Python::with_gil(|py| { - let array = numpy::pyarray_bound![py, [0, 1, 2], [3, 4, 5], [6, 7, 8]]; + let array = numpy::pyarray![py, [0, 1, 2], [3, 4, 5], [6, 7, 8]]; let array = py - .eval_bound( - "a[::-1]", - Some(&[("a", array)].into_py_dict_bound(py)), + .eval( + c_str!("a[::-1]"), + Some(&[("a", array)].into_py_dict(py).unwrap()), None, ) .unwrap() @@ -457,11 +462,11 @@ fn matrix_from_numpy() { }); Python::with_gil(|py| { - let array = numpy::pyarray_bound![py, [[0, 1], [2, 3]], [[4, 5], [6, 7]]]; + let array = numpy::pyarray![py, [[0, 1], [2, 3]], [[4, 5], [6, 7]]]; let array = py - .eval_bound( - "a[:,:,0]", - Some(&[("a", &array)].into_py_dict_bound(py)), + .eval( + c_str!("a[:,:,0]"), + Some(&[("a", &array)].into_py_dict(py).unwrap()), None, ) .unwrap() @@ -481,11 +486,11 @@ fn matrix_from_numpy() { }); Python::with_gil(|py| { - let array = numpy::pyarray_bound![py, [[0, 1], [2, 3]], [[4, 5], [6, 7]]]; + let array = numpy::pyarray![py, [[0, 1], [2, 3]], [[4, 5], [6, 7]]]; let array = py - .eval_bound( - "a[:,:,0]", - Some(&[("a", &array)].into_py_dict_bound(py)), + .eval( + c_str!("a[:,:,0]"), + Some(&[("a", &array)].into_py_dict(py).unwrap()), None, ) .unwrap() @@ -505,7 +510,7 @@ fn matrix_from_numpy() { }); Python::with_gil(|py| { - let array = numpy::pyarray_bound![py, [0, 1, 2], [3, 4, 5], [6, 7, 8]]; + let array = numpy::pyarray![py, [0, 1, 2], [3, 4, 5], [6, 7, 8]]; let array = array.readonly(); let matrix: Option< diff --git a/tests/sum_products.rs b/tests/sum_products.rs index c41076127..05dfca14a 100644 --- a/tests/sum_products.rs +++ b/tests/sum_products.rs @@ -1,31 +1,29 @@ use numpy::prelude::*; -use numpy::{ - array, dot_bound, einsum_bound, inner_bound, pyarray_bound, PyArray0, PyArray1, PyArray2, -}; +use numpy::{array, dot, einsum, inner, pyarray, PyArray0, PyArray1, PyArray2}; use pyo3::{Bound, Python}; #[test] fn test_dot() { Python::with_gil(|py| { - let a = pyarray_bound![py, [1, 0], [0, 1]]; - let b = pyarray_bound![py, [4, 1], [2, 2]]; - let c: Bound<'_, PyArray2<_>> = dot_bound(&a, &b).unwrap(); + let a = pyarray![py, [1, 0], [0, 1]]; + let b = pyarray![py, [4, 1], [2, 2]]; + let c: Bound<'_, PyArray2<_>> = dot(&a, &b).unwrap(); assert_eq!(c.readonly().as_array(), array![[4, 1], [2, 2]]); - let a = pyarray_bound![py, 1, 2, 3]; - let err = dot_bound::<_, _, _, Bound<'_, PyArray2<_>>>(&a, &b).unwrap_err(); + let a = pyarray![py, 1, 2, 3]; + let err = dot::<_, _, _, Bound<'_, PyArray2<_>>>(&a, &b).unwrap_err(); assert!(err.to_string().contains("not aligned"), "{}", err); - let a = pyarray_bound![py, 1, 2, 3]; - let b = pyarray_bound![py, 0, 1, 0]; - let c: Bound<'_, PyArray0<_>> = dot_bound(&a, &b).unwrap(); + let a = pyarray![py, 1, 2, 3]; + let b = pyarray![py, 0, 1, 0]; + let c: Bound<'_, PyArray0<_>> = dot(&a, &b).unwrap(); assert_eq!(c.item(), 2); - let c: i32 = dot_bound(&a, &b).unwrap(); + let c: i32 = dot(&a, &b).unwrap(); assert_eq!(c, 2); - let a = pyarray_bound![py, 1.0, 2.0, 3.0]; - let b = pyarray_bound![py, 0.0, 0.0, 0.0]; - let c: f64 = dot_bound(&a, &b).unwrap(); + let a = pyarray![py, 1.0, 2.0, 3.0]; + let b = pyarray![py, 0.0, 0.0, 0.0]; + let c: f64 = dot(&a, &b).unwrap(); assert_eq!(c, 0.0); }); } @@ -33,25 +31,25 @@ fn test_dot() { #[test] fn test_inner() { Python::with_gil(|py| { - let a = pyarray_bound![py, 1, 2, 3]; - let b = pyarray_bound![py, 0, 1, 0]; - let c: Bound<'_, PyArray0<_>> = inner_bound(&a, &b).unwrap(); + let a = pyarray![py, 1, 2, 3]; + let b = pyarray![py, 0, 1, 0]; + let c: Bound<'_, PyArray0<_>> = inner(&a, &b).unwrap(); assert_eq!(c.item(), 2); - let c: i32 = inner_bound(&a, &b).unwrap(); + let c: i32 = inner(&a, &b).unwrap(); assert_eq!(c, 2); - let a = pyarray_bound![py, 1.0, 2.0, 3.0]; - let b = pyarray_bound![py, 0.0, 0.0, 0.0]; - let c: f64 = inner_bound(&a, &b).unwrap(); + let a = pyarray![py, 1.0, 2.0, 3.0]; + let b = pyarray![py, 0.0, 0.0, 0.0]; + let c: f64 = inner(&a, &b).unwrap(); assert_eq!(c, 0.0); - let a = pyarray_bound![py, [1, 0], [0, 1]]; - let b = pyarray_bound![py, [4, 1], [2, 2]]; - let c: Bound<'_, PyArray2<_>> = inner_bound(&a, &b).unwrap(); + let a = pyarray![py, [1, 0], [0, 1]]; + let b = pyarray![py, [4, 1], [2, 2]]; + let c: Bound<'_, PyArray2<_>> = inner(&a, &b).unwrap(); assert_eq!(c.readonly().as_array(), array![[4, 2], [1, 2]]); - let a = pyarray_bound![py, 1, 2, 3]; - let err = inner_bound::<_, _, _, Bound<'_, PyArray2<_>>>(&a, &b).unwrap_err(); + let a = pyarray![py, 1, 2, 3]; + let err = inner::<_, _, _, Bound<'_, PyArray2<_>>>(&a, &b).unwrap_err(); assert!(err.to_string().contains("not aligned"), "{}", err); }); } @@ -59,28 +57,28 @@ fn test_inner() { #[test] fn test_einsum() { Python::with_gil(|py| { - let a = PyArray1::::arange_bound(py, 0, 25, 1) + let a = PyArray1::::arange(py, 0, 25, 1) .reshape([5, 5]) .unwrap(); - let b = pyarray_bound![py, 0, 1, 2, 3, 4]; - let c = pyarray_bound![py, [0, 1, 2], [3, 4, 5]]; + let b = pyarray![py, 0, 1, 2, 3, 4]; + let c = pyarray![py, [0, 1, 2], [3, 4, 5]]; - let d: Bound<'_, PyArray0<_>> = einsum_bound!("ii", a).unwrap(); + let d: Bound<'_, PyArray0<_>> = einsum!("ii", a).unwrap(); assert_eq!(d.item(), 60); - let d: i32 = einsum_bound!("ii", a).unwrap(); + let d: i32 = einsum!("ii", a).unwrap(); assert_eq!(d, 60); - let d: Bound<'_, PyArray1<_>> = einsum_bound!("ii->i", a).unwrap(); + let d: Bound<'_, PyArray1<_>> = einsum!("ii->i", a).unwrap(); assert_eq!(d.readonly().as_array(), array![0, 6, 12, 18, 24]); - let d: Bound<'_, PyArray1<_>> = einsum_bound!("ij->i", a).unwrap(); + let d: Bound<'_, PyArray1<_>> = einsum!("ij->i", a).unwrap(); assert_eq!(d.readonly().as_array(), array![10, 35, 60, 85, 110]); - let d: Bound<'_, PyArray2<_>> = einsum_bound!("ji", c).unwrap(); + let d: Bound<'_, PyArray2<_>> = einsum!("ji", c).unwrap(); assert_eq!(d.readonly().as_array(), array![[0, 3], [1, 4], [2, 5]]); - let d: Bound<'_, PyArray1<_>> = einsum_bound!("ij,j", a, b).unwrap(); + let d: Bound<'_, PyArray1<_>> = einsum!("ij,j", a, b).unwrap(); assert_eq!(d.readonly().as_array(), array![30, 80, 130, 180, 230]); }); } diff --git a/tests/to_py.rs b/tests/to_py.rs index a68ae38e0..c18d2d6db 100644 --- a/tests/to_py.rs +++ b/tests/to_py.rs @@ -6,14 +6,14 @@ use numpy::{prelude::*, PyArray}; use pyo3::{ py_run, types::{PyAnyMethods, PyDict, PyString}, - Python, ToPyObject, + Python, }; #[test] fn to_pyarray_vec() { Python::with_gil(|py| { #[allow(clippy::useless_vec)] - let arr = vec![1, 2, 3].to_pyarray_bound(py); + let arr = vec![1, 2, 3].to_pyarray(py); assert_eq!(arr.shape(), [3]); assert_eq!(arr.readonly().as_slice().unwrap(), &[1, 2, 3]) @@ -23,7 +23,7 @@ fn to_pyarray_vec() { #[test] fn to_pyarray_boxed_slice() { Python::with_gil(|py| { - let arr = vec![1, 2, 3].into_boxed_slice().to_pyarray_bound(py); + let arr = vec![1, 2, 3].into_boxed_slice().to_pyarray(py); assert_eq!(arr.shape(), [3]); assert_eq!(arr.readonly().as_slice().unwrap(), &[1, 2, 3]) @@ -42,7 +42,7 @@ fn to_pyarray_array() { .map(|dim| dim * size_of::() as isize) .collect::>(); - let py_arr = PyArray::from_array_bound(py, &arr); + let py_arr = PyArray::from_array(py, &arr); assert_eq!(py_arr.shape(), shape.as_slice()); assert_eq!(py_arr.strides(), strides.as_slice()); @@ -52,7 +52,7 @@ fn to_pyarray_array() { #[test] fn iter_to_pyarray() { Python::with_gil(|py| { - let arr = PyArray::from_iter_bound(py, (0..10).map(|x| x * x)); + let arr = PyArray::from_iter(py, (0..10).map(|x| x * x)); assert_eq!( arr.readonly().as_slice().unwrap(), @@ -64,7 +64,7 @@ fn iter_to_pyarray() { #[test] fn long_iter_to_pyarray() { Python::with_gil(|py| { - let arr = PyArray::from_iter_bound(py, 0_u32..512); + let arr = PyArray::from_iter(py, 0_u32..512); assert_eq!( arr.readonly().as_slice().unwrap(), @@ -80,7 +80,7 @@ fn from_small_array() { $({ Python::with_gil(|py| { let array: [$t; 2] = [<$t>::MIN, <$t>::MAX]; - let pyarray = array.to_pyarray_bound(py); + let pyarray = array.to_pyarray(py); assert_eq!( pyarray.readonly().as_slice().unwrap(), @@ -97,7 +97,7 @@ fn from_small_array() { #[test] fn usize_dtype() { Python::with_gil(|py| { - let x = vec![1_usize, 2, 3].into_pyarray_bound(py); + let x = vec![1_usize, 2, 3].into_pyarray(py); if cfg!(target_pointer_width = "64") { py_run!(py, x, "assert str(x.dtype) == 'uint64'") @@ -110,7 +110,7 @@ fn usize_dtype() { #[test] fn into_pyarray_vec() { Python::with_gil(|py| { - let arr = vec![1, 2, 3].into_pyarray_bound(py); + let arr = vec![1, 2, 3].into_pyarray(py); assert_eq!(arr.readonly().as_slice().unwrap(), &[1, 2, 3]) }); @@ -119,7 +119,7 @@ fn into_pyarray_vec() { #[test] fn into_pyarray_boxed_slice() { Python::with_gil(|py| { - let arr = vec![1, 2, 3].into_boxed_slice().into_pyarray_bound(py); + let arr = vec![1, 2, 3].into_boxed_slice().into_pyarray(py); assert_eq!(arr.readonly().as_slice().unwrap(), &[1, 2, 3]) }); @@ -137,7 +137,7 @@ fn into_pyarray_array() { .map(|dim| dim * size_of::() as isize) .collect::>(); - let py_arr = arr.into_pyarray_bound(py); + let py_arr = arr.into_pyarray(py); assert_eq!(py_arr.shape(), shape.as_slice()); assert_eq!(py_arr.strides(), strides.as_slice()); @@ -147,7 +147,7 @@ fn into_pyarray_array() { #[test] fn into_pyarray_cannot_resize() { Python::with_gil(|py| { - let arr = vec![1, 2, 3].into_pyarray_bound(py); + let arr = vec![1, 2, 3].into_pyarray(py); unsafe { assert!(arr.resize(100).is_err()); @@ -158,7 +158,7 @@ fn into_pyarray_cannot_resize() { #[test] fn into_pyarray_can_write() { Python::with_gil(|py| { - let arr = vec![1, 2, 3].into_pyarray_bound(py); + let arr = vec![1, 2, 3].into_pyarray(py); py_run!(py, arr, "assert arr.flags['WRITEABLE']"); py_run!(py, arr, "arr[1] = 4"); @@ -175,7 +175,7 @@ fn collapsed_into_pyarray() { arr.slice_collapse(s![1.., ..]); let cloned_arr = arr.clone(); - let py_arr = arr.into_pyarray_bound(py); + let py_arr = arr.into_pyarray(py); assert_eq!(py_arr.readonly().as_array(), cloned_arr); }); @@ -187,7 +187,7 @@ fn sliced_to_pyarray() { let matrix = Array2::from_shape_vec([4, 2], vec![0, 1, 2, 3, 4, 5, 6, 7]).unwrap(); let sliced_matrix = matrix.slice(s![1..4; -1, ..]); - let py_arr = sliced_matrix.to_pyarray_bound(py); + let py_arr = sliced_matrix.to_pyarray(py); assert_eq!(py_arr.readonly().as_array(), array![[6, 7], [4, 5], [2, 3]],); @@ -201,7 +201,7 @@ fn forder_to_pyarray() { let matrix = Array2::from_shape_vec([4, 2], vec![0, 1, 2, 3, 4, 5, 6, 7]).unwrap(); let forder_matrix = matrix.reversed_axes(); - let py_arr = forder_matrix.to_pyarray_bound(py); + let py_arr = forder_matrix.to_pyarray(py); assert_eq!( py_arr.readonly().as_array(), @@ -218,7 +218,7 @@ fn forder_into_pyarray() { let matrix = Array2::from_shape_vec([4, 2], vec![0, 1, 2, 3, 4, 5, 6, 7]).unwrap(); let forder_matrix = matrix.reversed_axes(); - let py_arr = forder_matrix.into_pyarray_bound(py); + let py_arr = forder_matrix.into_pyarray(py); assert_eq!( py_arr.readonly().as_array(), @@ -232,12 +232,12 @@ fn forder_into_pyarray() { #[test] fn to_pyarray_object_vec() { Python::with_gil(|py| { - let dict = PyDict::new_bound(py); - let string = PyString::new_bound(py, "Hello:)"); + let dict = PyDict::new(py); + let string = PyString::new(py, "Hello:)"); #[allow(clippy::useless_vec)] // otherwise we do not test the right trait impl - let vec = vec![dict.to_object(py), string.to_object(py)]; + let vec = vec![dict.into_any().unbind(), string.into_any().unbind()]; - let arr = vec.to_pyarray_bound(py); + let arr = vec.to_pyarray(py); for (a, b) in vec.iter().zip(arr.readonly().as_slice().unwrap().iter()) { assert_eq!( @@ -252,10 +252,10 @@ fn to_pyarray_object_vec() { fn to_pyarray_object_array() { Python::with_gil(|py| { let mut nd_arr = Array2::from_shape_fn((2, 3), |(_, _)| py.None()); - nd_arr[(0, 2)] = PyDict::new_bound(py).to_object(py); - nd_arr[(1, 0)] = PyString::new_bound(py, "Hello:)").to_object(py); + nd_arr[(0, 2)] = PyDict::new(py).into_any().unbind(); + nd_arr[(1, 0)] = PyString::new(py, "Hello:)").into_any().unbind(); - let py_arr = nd_arr.to_pyarray_bound(py); + let py_arr = nd_arr.to_pyarray(py); for (a, b) in nd_arr .as_slice() @@ -275,16 +275,16 @@ fn to_pyarray_object_array() { fn slice_container_type_confusion() { Python::with_gil(|py| { let mut nd_arr = Array2::from_shape_fn((2, 3), |(_, _)| py.None()); - nd_arr[(0, 2)] = PyDict::new_bound(py).to_object(py); - nd_arr[(1, 0)] = PyString::new_bound(py, "Hello:)").to_object(py); + nd_arr[(0, 2)] = PyDict::new(py).into_any().unbind(); + nd_arr[(1, 0)] = PyString::new(py, "Hello:)").into_any().unbind(); - let _py_arr = nd_arr.into_pyarray_bound(py); + let _py_arr = nd_arr.into_pyarray(py); // Dropping `_py_arr` used to trigger a segmentation fault due to calling `Py_DECREF` // on 1, 2 and 3 interpreted as pointers into the Python heap // after having created a `SliceBox` backing `_py_arr`, // c.f. https://github.com/PyO3/rust-numpy/issues/232. - let _py_arr = vec![1, 2, 3].into_pyarray_bound(py); + let _py_arr = vec![1, 2, 3].into_pyarray(py); }); } @@ -295,7 +295,7 @@ fn matrix_to_numpy() { assert!(nalgebra::RawStorage::is_contiguous(&matrix.data)); Python::with_gil(|py| { - let array = matrix.to_pyarray_bound(py); + let array = matrix.to_pyarray(py); assert_eq!( array.readonly().as_array(), @@ -307,7 +307,7 @@ fn matrix_to_numpy() { assert!(!nalgebra::RawStorage::is_contiguous(&matrix.data)); Python::with_gil(|py| { - let array = matrix.to_pyarray_bound(py); + let array = matrix.to_pyarray(py); assert_eq!(array.readonly().as_array(), array![[0, 1, 2]]); }); @@ -315,7 +315,7 @@ fn matrix_to_numpy() { let vector = nalgebra::Vector4::::new(-4, 1, 2, 3); Python::with_gil(|py| { - let array = vector.to_pyarray_bound(py); + let array = vector.to_pyarray(py); assert_eq!(array.readonly().as_array(), array![[-4], [1], [2], [3]]); }); @@ -323,7 +323,7 @@ fn matrix_to_numpy() { let vector = nalgebra::RowVector2::::new(23, 42); Python::with_gil(|py| { - let array = vector.to_pyarray_bound(py); + let array = vector.to_pyarray(py); assert_eq!(array.readonly().as_array(), array![[23, 42]]); });