Lest this is an XY question: I want to pass a 2-dimensional ndarray::Array2 of a custom structure to Python.
If this doesn't make sense I'll try to write a minimally expressive example -- won't be minimally functional, because my problem is that it won't compile.
This, hopefully, distills down my 600-line file with one little ol' problem down to something intelligible. My problem is that when I try to call from_array on a ndarray of an arbitrary object, I get the error the trait `numpy::Element` is not implemented for `SomethingArbitrary`
So -- is there a way take my ndarray::Array2 of some weird type and convert it into a numpy::PyArray2 of the same type? I'm probably going to end up converting to a vector, and then to a PyArray2, but that seems very messy.
use pyo3::prelude::*;
use pyo3::exceptions::*;
use numpy::{PyArray2};
use ndarray::{Array2};
struct SomethingArbitrary {
this: u16,
that: bool,
}
...
let r: Array2::<SomethingArbitrary> = make_array_of_something_arbitrary();
pyo3::Python::with_gill(|py| {
PyArray::from_array(py, r)
})
pyo3::Python::with_gil(|py| {
let result = self.correct(r);
result.to_pyarray(py).to_object(py)
})
It compiles just fine! Everything's wonderful! Except that when I try to run the containing function from Python I get a seg fault! I'm feeling kinda cheated here, because I didn't call any unsafe code in this chain!
Cargo.toml. Note that with the versions mentioned, you need to run cargo update --package ndarray:0.15.3 --precise 0.14.0 to get this to work. But if you go with the latest of everything the problem still happens.
[package]
name = "pyo3_numpy"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
crate-type = ["cdylib"]
[dependencies]
# Need to run `cargo update --package ndarray:0.15.3 --precise 0.14.0
ndarray = "0.14"
numpy = "0.14"
pyo3 = "0.14"
If anyone runs into this: a workaround that's almost nice is to just make a vector of vectors of the object (or one vector if it's 1D, or n if it's N-D). Python sees it as a list (of lists, of lists, depending on how many dimensions). You can put that directly into a call tonumpy.array.
So instead of your Python code saying thingie = get_thingie(), it says thingie = numpy.array(get_thingie()). Which isn't too far off, and will still work if, in the future, the problem gets fixed and you change your library code to return an ndarray.