Skip to content

Commit 6aad7ae

Browse files
authored
Merge pull request #116 from kngwyu/vec_obj
Disable Vec<*mut ffi::PyObject> <-> numpy.ndarray conversion
2 parents 51d6020 + 5bfecc4 commit 6aad7ae

File tree

12 files changed

+133
-172
lines changed

12 files changed

+133
-172
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ crate-type = ["cdylib"]
9999

100100
[dependencies]
101101
numpy = "0.7.0"
102-
ndarray = "0.12"
102+
ndarray = "0.13"
103103

104104
[dependencies.pyo3]
105105
version = "0.8"

examples/linalg/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ crate-type = ["cdylib"]
1010

1111
[dependencies]
1212
numpy = { path = "../.." }
13-
ndarray = "0.12"
13+
ndarray = ">= 0.12"
1414
ndarray-linalg = { version = "0.10", features = ["openblas"] }
1515

1616
[dependencies.pyo3]

examples/simple-extension/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ crate-type = ["cdylib"]
1010

1111
[dependencies]
1212
numpy = { path = "../.." }
13-
ndarray = "0.12"
13+
ndarray = ">= 0.12"
1414

1515
[dependencies.pyo3]
1616
version = "0.8"

src/array.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ use crate::types::{NpyDataType, TypeNum};
5050
/// All data types you can use implements [TypeNum](../types/trait.TypeNum.html).
5151
///
5252
/// Dimensions are represented by ndarray's
53-
/// [Dimension](https://docs.rs/ndarray/0.12/ndarray/trait.Dimension.html) trait.
53+
/// [Dimension](https://docs.rs/ndarray/latest/ndarray/trait.Dimension.html) trait.
5454
///
5555
/// Typically, you can use `Ix1, Ix2, ..` for fixed size arrays, and use `IxDyn` for dynamic
5656
/// dimensioned arrays. They're re-exported from `ndarray` crate.
@@ -59,7 +59,7 @@ use crate::types::{NpyDataType, TypeNum};
5959
/// or [`PyArrayDyn`](./type.PyArrayDyn.html).
6060
///
6161
/// To specify concrete dimension like `3×4×5`, you can use types which implements ndarray's
62-
/// [`IntoDimension`](https://docs.rs/ndarray/0.12/ndarray/dimension/conversion/trait.IntoDimension.html)
62+
/// [`IntoDimension`](https://docs.rs/ndarray/latest/ndarray/dimension/conversion/trait.IntoDimension.html)
6363
/// trait. Typically, you can use array(e.g. `[3, 4, 5]`) or tuple(e.g. `(3, 4, 5)`) as a dimension.
6464
///
6565
/// # Example
@@ -379,7 +379,7 @@ impl<T: TypeNum, D: Dimension> PyArray<T, D> {
379379
pub(crate) unsafe fn from_boxed_slice<'py, ID>(
380380
py: Python<'py>,
381381
dims: ID,
382-
strides: *mut npy_intp,
382+
strides: *const npy_intp,
383383
slice: Box<[T]>,
384384
) -> &'py Self
385385
where
@@ -392,11 +392,11 @@ impl<T: TypeNum, D: Dimension> PyArray<T, D> {
392392
dims.ndim_cint(),
393393
dims.as_dims_ptr(),
394394
T::typenum_default(),
395-
strides, // strides
396-
slice.data(), // data
397-
0, // itemsize
398-
0, // flag
399-
::std::ptr::null_mut(), //obj
395+
strides as *mut _, // strides
396+
slice.data(), // data
397+
mem::size_of::<T>() as i32, // itemsize
398+
0, // flag
399+
::std::ptr::null_mut(), //obj
400400
);
401401
PY_ARRAY_API.PyArray_SetBaseObject(ptr as *mut npyffi::PyArrayObject, slice.as_ptr());
402402
Self::from_owned_ptr(py, ptr)
@@ -497,7 +497,7 @@ impl<T: TypeNum, D: Dimension> PyArray<T, D> {
497497
}
498498

499499
/// Construct PyArray from
500-
/// [`ndarray::Array`](https://docs.rs/ndarray/0.12/ndarray/type.Array.html).
500+
/// [`ndarray::Array`](https://docs.rs/ndarray/latest/ndarray/type.Array.html).
501501
///
502502
/// This method uses internal [`Vec`](https://doc.rust-lang.org/std/vec/struct.Vec.html)
503503
/// of `ndarray::Array` as numpy array.
@@ -516,7 +516,7 @@ impl<T: TypeNum, D: Dimension> PyArray<T, D> {
516516
}
517517

518518
/// Get the immutable view of the internal data of `PyArray`, as
519-
/// [`ndarray::ArrayView`](https://docs.rs/ndarray/0.12/ndarray/type.ArrayView.html).
519+
/// [`ndarray::ArrayView`](https://docs.rs/ndarray/latest/ndarray/type.ArrayView.html).
520520
///
521521
/// # Example
522522
/// ```
@@ -659,7 +659,7 @@ impl<T: TypeNum, D: Dimension> PyArray<T, D> {
659659

660660
impl<T: TypeNum + Clone, D: Dimension> PyArray<T, D> {
661661
/// Get a copy of `PyArray` as
662-
/// [`ndarray::Array`](https://docs.rs/ndarray/0.12/ndarray/type.Array.html).
662+
/// [`ndarray::Array`](https://docs.rs/ndarray/latest/ndarray/type.Array.html).
663663
///
664664
/// # Example
665665
/// ```

src/convert.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use pyo3::Python;
55

66
use std::mem;
77
use std::os::raw::c_int;
8-
use std::ptr;
98

109
use super::*;
1110
use crate::npyffi::npy_intp;
@@ -38,7 +37,8 @@ impl<T: TypeNum> IntoPyArray for Box<[T]> {
3837
type Dim = Ix1;
3938
fn into_pyarray<'py>(self, py: Python<'py>) -> &'py PyArray<Self::Item, Self::Dim> {
4039
let len = self.len();
41-
unsafe { PyArray::from_boxed_slice(py, [len], ptr::null_mut(), self) }
40+
let strides = [mem::size_of::<T>() as npy_intp];
41+
unsafe { PyArray::from_boxed_slice(py, [len], strides.as_ptr(), self) }
4242
}
4343
}
4444

@@ -58,10 +58,10 @@ where
5858
type Item = A;
5959
type Dim = D;
6060
fn into_pyarray<'py>(self, py: Python<'py>) -> &'py PyArray<Self::Item, Self::Dim> {
61-
let mut strides = npy_strides(&self);
61+
let strides = npy_strides(&self);
6262
let dim = self.raw_dim();
6363
let boxed = self.into_raw_vec().into_boxed_slice();
64-
unsafe { PyArray::from_boxed_slice(py, dim, strides.as_mut_ptr() as *mut npy_intp, boxed) }
64+
unsafe { PyArray::from_boxed_slice(py, dim, strides.as_ptr(), boxed) }
6565
}
6666
}
6767

@@ -150,7 +150,7 @@ impl<D: Dimension> ToNpyDims for D {
150150
/// Types that can be used to index an array.
151151
///
152152
/// See
153-
/// [IntoDimension](https://docs.rs/ndarray/0.12/ndarray/dimension/conversion/trait.IntoDimension.html)
153+
/// [IntoDimension](https://docs.rs/ndarray/latest/ndarray/dimension/conversion/trait.IntoDimension.html)
154154
/// for what types you can use as `NpyIndex`.
155155
///
156156
/// But basically, you can use

src/npyffi/mod.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,7 @@
11
//! Low-Level bindings for NumPy C API.
22
//!
33
//! https://docs.scipy.org/doc/numpy/reference/c-api.html
4-
//!
5-
//! Most of functions in this submodule are unsafe.
6-
//! If you use functions in this submodule, you need to understand
7-
//! basic usage of Python C API, especially for the reference counting.
8-
//!
9-
//! - http://docs.python.jp/3/c-api/
10-
//! - http://dgrunwald.github.io/rust-pyo3/doc/pyo3/
4+
#![allow(non_camel_case_types)]
115

126
use pyo3::ffi;
137
use std::ffi::CString;
@@ -41,7 +35,7 @@ macro_rules! impl_api {
4135
#[allow(non_snake_case)]
4236
pub unsafe fn $fname(&self, $($arg : $t), *) $( -> $ret )* {
4337
let fptr = self.0.offset($offset)
44-
as (*const extern fn ($($arg : $t), *) $( -> $ret )* );
38+
as *const extern fn ($($arg : $t), *) $( -> $ret )*;
4539
(*fptr)($($arg), *)
4640
}
4741
}

src/npyffi/objects.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Low-Lebel binding for NumPy C API C-objects
22
//!
33
//! https://docs.scipy.org/doc/numpy/reference/c-api.types-and-structures.html
4-
#![allow(non_camel_case_types, non_snake_case)]
4+
#![allow(non_camel_case_types)]
55

66
use libc::FILE;
77
use pyo3::ffi::*;

src/npyffi/types.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#![allow(non_camel_case_types)]
2-
31
use pyo3::ffi::{Py_hash_t, Py_intptr_t, Py_uintptr_t};
42
use std::os::raw::*;
53

src/types.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ pub use num_complex::Complex32 as c32;
55
pub use num_complex::Complex64 as c64;
66

77
use super::npyffi::NPY_TYPES;
8-
use pyo3::ffi::PyObject;
98

109
/// An enum type represents numpy data type.
1110
///
@@ -25,7 +24,6 @@ pub enum NpyDataType {
2524
Float64,
2625
Complex32,
2726
Complex64,
28-
PyObject,
2927
Unsupported,
3028
}
3129

@@ -47,7 +45,6 @@ impl NpyDataType {
4745
x if x == NPY_TYPES::NPY_DOUBLE as i32 => NpyDataType::Float64,
4846
x if x == NPY_TYPES::NPY_CFLOAT as i32 => NpyDataType::Complex32,
4947
x if x == NPY_TYPES::NPY_CDOUBLE as i32 => NpyDataType::Complex64,
50-
x if x == NPY_TYPES::NPY_OBJECT as i32 => NpyDataType::PyObject,
5148
_ => NpyDataType::Unsupported,
5249
}
5350
}
@@ -103,7 +100,6 @@ impl_type_num!(f32, Float32, NPY_FLOAT);
103100
impl_type_num!(f64, Float64, NPY_DOUBLE);
104101
impl_type_num!(c32, Complex32, NPY_CFLOAT);
105102
impl_type_num!(c64, Complex64, NPY_CDOUBLE);
106-
impl_type_num!(*mut PyObject, PyObject, NPY_OBJECT);
107103

108104
cfg_if! {
109105
if #[cfg(all(target_pointer_width = "64", windows))] {

tests/array.rs

Lines changed: 0 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use pyo3::{
44
prelude::*,
55
types::PyList,
66
types::{IntoPyDict, PyDict},
7-
AsPyPointer,
87
};
98

109
fn get_np_locals(py: Python<'_>) -> &'_ PyDict {
@@ -102,53 +101,6 @@ fn as_slice() {
102101
assert!(not_contiguous.as_slice().is_err())
103102
}
104103

105-
#[test]
106-
fn to_pyarray_vec() {
107-
let gil = pyo3::Python::acquire_gil();
108-
109-
let a = vec![1, 2, 3];
110-
let arr = a.to_pyarray(gil.python());
111-
println!("arr.shape = {:?}", arr.shape());
112-
assert_eq!(arr.shape(), [3]);
113-
assert_eq!(arr.as_slice().unwrap(), &[1, 2, 3])
114-
}
115-
116-
#[test]
117-
fn to_pyarray_array() {
118-
let gil = pyo3::Python::acquire_gil();
119-
120-
let a = Array3::<f64>::zeros((3, 4, 2));
121-
let shape = a.shape().iter().cloned().collect::<Vec<_>>();
122-
let strides = a.strides().iter().map(|d| d * 8).collect::<Vec<_>>();
123-
println!("a.shape = {:?}", a.shape());
124-
println!("a.strides = {:?}", a.strides());
125-
let pa = a.to_pyarray(gil.python());
126-
println!("pa.shape = {:?}", pa.shape());
127-
println!("pa.strides = {:?}", pa.strides());
128-
assert_eq!(pa.shape(), shape.as_slice());
129-
assert_eq!(pa.strides(), strides.as_slice());
130-
}
131-
132-
#[test]
133-
fn iter_to_pyarray() {
134-
let gil = pyo3::Python::acquire_gil();
135-
let arr = PyArray::from_iter(gil.python(), (0..10).map(|x| x * x));
136-
assert_eq!(
137-
arr.as_slice().unwrap(),
138-
&[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
139-
);
140-
}
141-
142-
#[test]
143-
fn long_iter_to_pyarray() {
144-
let gil = pyo3::Python::acquire_gil();
145-
let arr = PyArray::from_iter(gil.python(), (0u32..512).map(|x| x));
146-
let slice = arr.as_slice().unwrap();
147-
for (i, &elem) in slice.iter().enumerate() {
148-
assert_eq!(i as u32, elem);
149-
}
150-
}
151-
152104
#[test]
153105
fn is_instance() {
154106
let gil = pyo3::Python::acquire_gil();
@@ -253,42 +205,6 @@ fn from_eval_fail_by_dim() {
253205
.print_and_set_sys_last_vars(gil.python());
254206
}
255207

256-
macro_rules! small_array_test {
257-
($($t: ident)+) => {
258-
#[test]
259-
fn from_small_array() {
260-
let gil = pyo3::Python::acquire_gil();
261-
$({
262-
let array: [$t; 2] = [$t::min_value(), $t::max_value()];
263-
let pyarray = array.to_pyarray(gil.python());
264-
assert_eq!(
265-
pyarray.as_slice().unwrap(),
266-
&[$t::min_value(), $t::max_value()]
267-
);
268-
})+
269-
}
270-
};
271-
}
272-
273-
small_array_test!(i8 u8 i16 u16 i32 u32 i64 u64 usize);
274-
275-
#[test]
276-
fn array_usize_dtype() {
277-
let gil = pyo3::Python::acquire_gil();
278-
let py = gil.python();
279-
280-
let a: Vec<usize> = vec![1, 2, 3];
281-
let x = a.into_pyarray(py);
282-
let x_repr = format!("{:?}", x);
283-
284-
let x_repr_expected = if cfg!(target_pointer_width = "64") {
285-
"array([1, 2, 3], dtype=uint64)"
286-
} else {
287-
"array([1, 2, 3], dtype=uint32)"
288-
};
289-
assert_eq!(x_repr, x_repr_expected);
290-
}
291-
292208
#[test]
293209
fn array_cast() {
294210
let gil = pyo3::Python::acquire_gil();
@@ -297,57 +213,3 @@ fn array_cast() {
297213
let arr_i32: &PyArray2<i32> = arr_f64.cast(false).unwrap();
298214
assert_eq!(arr_i32.as_array(), array![[1, 2, 3], [1, 2, 3]]);
299215
}
300-
301-
#[test]
302-
fn into_pyarray_vec() {
303-
let gil = pyo3::Python::acquire_gil();
304-
let a = vec![1, 2, 3];
305-
let arr = a.into_pyarray(gil.python());
306-
assert_eq!(arr.as_slice().unwrap(), &[1, 2, 3])
307-
}
308-
309-
#[test]
310-
fn into_pyarray_array() {
311-
let gil = pyo3::Python::acquire_gil();
312-
let arr = Array3::<f64>::zeros((3, 4, 2));
313-
let shape = arr.shape().iter().cloned().collect::<Vec<_>>();
314-
let strides = arr.strides().iter().map(|d| d * 8).collect::<Vec<_>>();
315-
let py_arr = arr.into_pyarray(gil.python());
316-
assert_eq!(py_arr.shape(), shape.as_slice());
317-
assert_eq!(py_arr.strides(), strides.as_slice());
318-
}
319-
320-
#[test]
321-
fn into_pyarray_cant_resize() {
322-
let gil = pyo3::Python::acquire_gil();
323-
let a = vec![1, 2, 3];
324-
let arr = a.into_pyarray(gil.python());
325-
assert!(arr.resize(100).is_err())
326-
}
327-
328-
// TODO: Replace it by pyo3::py_run when https://github.com/PyO3/pyo3/pull/512 is released.
329-
macro_rules! py_run {
330-
($py:expr, $val:expr, $code:expr) => {{
331-
let d = pyo3::types::PyDict::new($py);
332-
d.set_item(stringify!($val), &$val).unwrap();
333-
$py.run($code, None, Some(d))
334-
.map_err(|e| {
335-
e.print($py);
336-
$py.run("import sys; sys.stderr.flush()", None, None)
337-
.unwrap();
338-
})
339-
.expect($code)
340-
}};
341-
}
342-
343-
#[test]
344-
fn into_obj_vec_to_pyarray() {
345-
let gil = pyo3::Python::acquire_gil();
346-
let py = gil.python();
347-
let dict = PyDict::new(py);
348-
let string = pyo3::types::PyString::new(py, "Hello python :)");
349-
let a = vec![dict.as_ptr(), string.as_ptr()];
350-
let arr = a.into_pyarray(py);
351-
py_run!(py, arr, "assert arr[0] == {}");
352-
py_run!(py, arr, "assert arr[1] == 'Hello python :)'");
353-
}

0 commit comments

Comments
 (0)