From 4438770a52ec1eb88e95743bc3aba1b67f0f63b0 Mon Sep 17 00:00:00 2001 From: Kai Zhang Date: Wed, 1 May 2024 20:08:31 +0800 Subject: [PATCH] upgrade pyo3 --- anndata/Cargo.toml | 10 ++-- pyanndata/Cargo.toml | 18 +++---- pyanndata/src/anndata.rs | 2 +- pyanndata/src/anndata/backed.rs | 78 ++++++++++++++-------------- pyanndata/src/anndata/dataset.rs | 80 ++++++++++++++--------------- pyanndata/src/anndata/memory.rs | 62 +++++++++++----------- pyanndata/src/container.rs | 12 ++--- pyanndata/src/container/traits.rs | 18 +++---- pyanndata/src/data.rs | 25 +++++---- pyanndata/src/data/array.rs | 85 ++++++++++++++++--------------- pyanndata/src/data/instance.rs | 35 ++++++------- pyanndata/src/data/slice.rs | 16 +++--- python/Cargo.toml | 4 +- 13 files changed, 220 insertions(+), 225 deletions(-) diff --git a/anndata/Cargo.toml b/anndata/Cargo.toml index aa88fe3..96746aa 100644 --- a/anndata/Cargo.toml +++ b/anndata/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "anndata" -version = "0.3.2" +version = "0.3.3" edition = "2021" rust-version = "1.70" authors = ["Kai Zhang "] @@ -14,16 +14,16 @@ homepage = "https://github.com/kaizhang/anndata-rs" anyhow = "1.0" flate2 = "1.0" log = "0.4" -indexmap = { version = "2.0", features = ["rayon"] } +indexmap = { version = "2.2", features = ["rayon"] } itertools = "0.12" ndarray = { version = "0.15" } nalgebra-sparse = "0.9" num = "0.4" -polars = { version = "0.37", features = ["lazy", "decompress-fast", "ndarray", "dtype-full"] } +polars = { version = "0.39", features = ["lazy", "decompress-fast", "ndarray", "dtype-full"] } parking_lot = "0.12" replace_with = "0.1" -smallvec = "1.11" -rayon = "1.8" +smallvec = "1.13" +rayon = "1.10" permutation = "0.4" [dev-dependencies] diff --git a/pyanndata/Cargo.toml b/pyanndata/Cargo.toml index 82efb34..e4c0304 100644 --- a/pyanndata/Cargo.toml +++ b/pyanndata/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pyanndata" -version = "0.3.2" +version = "0.3.3" edition = "2021" rust-version = "1.70" authors = ["Kai Zhang "] @@ -12,27 +12,27 @@ homepage = "https://github.com/kaizhang/anndata-rs" keywords = ["data"] [dependencies] -anndata = "0.3.2" +anndata = "0.3.3" anndata-hdf5 = "0.2" anyhow = "1.0" downcast-rs = "1.2" -numpy = "0.20.0" +numpy = "0.21.0" ndarray = "0.15" nalgebra-sparse = "0.9" hdf5 = "0.8" -polars = { version = "0.37", features = ["ndarray"] } -polars-core = "0.37" -polars-arrow = "0.37" -pyo3-polars = "0.11.3" +polars = { version = "0.39", features = ["ndarray"] } +polars-core = "0.39" +polars-arrow = "0.39" +pyo3-polars = "0.13" thiserror = "1.0" rand = "0.8" flate2 = "1.0" paste = "1.0" parking_lot = "0.12" -rayon = "1.8" +rayon = "1.10" [dependencies.pyo3] -version = "0.20.2" +version = "0.21.2" features = ["extension-module", "multiple-pymethods", "anyhow"] [lib] diff --git a/pyanndata/src/anndata.rs b/pyanndata/src/anndata.rs index b78b6c8..ace5066 100644 --- a/pyanndata/src/anndata.rs +++ b/pyanndata/src/anndata.rs @@ -34,7 +34,7 @@ use anyhow::Result; pub fn read<'py>(py: Python<'py>, filename: PathBuf, backed: Option<&str>, backend: Option<&str>) -> Result { let adata = match backed { Some(m) => AnnData::new_from(filename, m, backend).unwrap().into_py(py), - None => PyModule::import(py, "anndata")? + None => PyModule::import_bound(py, "anndata")? .getattr("read_h5ad")? .call1((filename,))? .to_object(py), diff --git a/pyanndata/src/anndata/backed.rs b/pyanndata/src/anndata/backed.rs index 206a9b2..c18fc38 100644 --- a/pyanndata/src/anndata/backed.rs +++ b/pyanndata/src/anndata/backed.rs @@ -91,7 +91,7 @@ impl AnnData { } } - fn select_obs(&self, ix: &PyAny) -> PyResult { + fn select_obs(&self, ix: &Bound<'_, PyAny>) -> PyResult { let from_iter = ix.iter().and_then(|iter| iter.map(|x| x.unwrap().extract::()).collect::>>() ).map(|names| { @@ -109,7 +109,7 @@ impl AnnData { } } - fn select_var(&self, ix: &PyAny) -> PyResult { + fn select_var(&self, ix: &Bound<'_, PyAny>) -> PyResult { let from_iter = ix.iter().and_then(|iter| iter.map(|x| x.unwrap().extract::()).collect::>>() ).map(|names| { @@ -145,8 +145,8 @@ impl AnnData { pub fn new( filename: PathBuf, X: Option, - obs: Option<&PyAny>, - var: Option<&PyAny>, + obs: Option>, + var: Option>, obsm: Option>, varm: Option>, uns: Option>, @@ -218,12 +218,12 @@ impl AnnData { self.0.obs_names().into_vec() } #[setter(obs_names)] - pub fn set_obs_names(&self, names: &PyAny) -> Result<()> { + pub fn set_obs_names(&self, names: Bound<'_, PyAny>) -> Result<()> { self.0.set_obs_names(names) } #[pyo3(text_signature = "($self, names)")] - fn obs_ix(&self, names: &PyAny) -> Result> { self.0.obs_ix(names) } + fn obs_ix(&self, names: Bound<'_, PyAny>) -> Result> { self.0.obs_ix(names) } /// Names of variables. /// @@ -235,12 +235,12 @@ impl AnnData { self.0.var_names().into_vec() } #[setter(var_names)] - pub fn set_var_names(&self, names: &PyAny) -> Result<()> { + pub fn set_var_names(&self, names: Bound<'_, PyAny>) -> Result<()> { self.0.set_var_names(names) } #[pyo3(text_signature = "($self, names)")] - fn var_ix(&self, names: &PyAny) -> Result> { self.0.var_ix(names) } + fn var_ix(&self, names: Bound<'_, PyAny>) -> Result> { self.0.var_ix(names) } /// Data matrix of shape n_obs × n_vars. /// @@ -266,7 +266,7 @@ impl AnnData { self.0.get_obs() } #[setter(obs)] - fn set_obs(&self, obs: Option<&PyAny>) -> Result<()> { + fn set_obs(&self, obs: Option>) -> Result<()> { self.0.set_obs(obs) } @@ -280,7 +280,7 @@ impl AnnData { self.0.get_var() } #[setter(var)] - fn set_var(&self, var: Option<&PyAny>) -> Result<()> { + fn set_var(&self, var: Option>) -> Result<()> { self.0.set_var(var) } @@ -370,8 +370,8 @@ impl AnnData { pub fn subset( &self, py: Python<'_>, - obs_indices: Option<&PyAny>, - var_indices: Option<&PyAny>, + obs_indices: Option<&Bound<'_, PyAny>>, + var_indices: Option<&Bound<'_, PyAny>>, out: Option, inplace: bool, backend: Option<&str>, @@ -504,11 +504,11 @@ impl AnnData { trait AnnDataTrait: Send + Downcast { fn shape(&self) -> (usize, usize); fn obs_names(&self) -> DataFrameIndex; - fn set_obs_names(&self, names: &PyAny) -> Result<()>; - fn obs_ix(&self, index: &PyAny) -> Result>; + fn set_obs_names(&self, names: Bound<'_, PyAny>) -> Result<()>; + fn obs_ix(&self, index: Bound<'_, PyAny>) -> Result>; fn var_names(&self) -> DataFrameIndex; - fn set_var_names(&self, names: &PyAny) -> Result<()>; - fn var_ix(&self, index: &PyAny) -> Result>; + fn set_var_names(&self, names: Bound<'_, PyAny>) -> Result<()>; + fn var_ix(&self, index: Bound<'_, PyAny>) -> Result>; fn get_x(&self) -> Option; fn get_obs(&self) -> Option; @@ -521,8 +521,8 @@ trait AnnDataTrait: Send + Downcast { fn get_layers(&self) -> Option; fn set_x(&self, data: Option) -> Result<()>; - fn set_obs(&self, obs: Option<&PyAny>) -> Result<()>; - fn set_var(&self, var: Option<&PyAny>) -> Result<()>; + fn set_obs(&self, obs: Option>) -> Result<()>; + fn set_var(&self, var: Option>) -> Result<()>; fn set_uns(&self, uns: Option>) -> Result<()>; fn set_obsm(&self, obsm: Option>) -> Result<()>; fn set_obsp(&self, obsp: Option>) -> Result<()>; @@ -582,13 +582,12 @@ impl AnnDataTrait for InnerAnnData { self.adata.inner().obs_names() } - fn obs_ix(&self, index: &PyAny) -> Result> { - self.adata.inner().obs_ix( - index.iter()?.map(|x| x.unwrap().extract::<&str>().unwrap()) - ) + fn obs_ix(&self, index: Bound<'_, PyAny>) -> Result> { + let bounds: Vec<_> = index.iter()?.map(|x| x.unwrap()).collect(); + self.adata.inner().obs_ix(bounds.iter().map(|x| x.extract::<&str>().unwrap())) } - fn set_obs_names(&self, names: &PyAny) -> Result<()> { + fn set_obs_names(&self, names: Bound<'_, PyAny>) -> Result<()> { let obs_names: Result = names.iter()?.map(|x| Ok(x?.extract::()?)).collect(); self.adata.inner().set_obs_names(obs_names?) @@ -598,13 +597,12 @@ impl AnnDataTrait for InnerAnnData { self.adata.inner().var_names() } - fn var_ix(&self, index: &PyAny) -> Result> { - self.adata.inner().var_ix( - index.iter()?.map(|x| x.unwrap().extract::<&str>().unwrap()) - ) + fn var_ix(&self, index: Bound<'_, PyAny>) -> Result> { + let bounds: Vec<_> = index.iter()?.map(|x| x.unwrap()).collect(); + self.adata.inner().var_ix(bounds.iter().map(|x| x.extract::<&str>().unwrap())) } - fn set_var_names(&self, names: &PyAny) -> Result<()> { + fn set_var_names(&self, names: Bound<'_, PyAny>) -> Result<()> { let var_names: Result = names.iter()?.map(|x| Ok(x?.extract::()?)).collect(); self.adata.inner().set_var_names(var_names?) @@ -702,34 +700,34 @@ impl AnnDataTrait for InnerAnnData { } Ok(()) } - fn set_obs(&self, obs: Option<&PyAny>) -> Result<()> { + fn set_obs(&self, obs: Option>) -> Result<()> { let inner = self.adata.inner(); if let Some(x) = obs { let py = x.py(); - let ob = if isinstance_of_pandas(py, x)? { - py.import("polars")?.call_method1("from_pandas", (x, )) + let ob = if isinstance_of_pandas(&x)? { + py.import_bound("polars")?.call_method1("from_pandas", (x, ))? } else if x.is_instance_of::() { - py.import("polars")?.call_method1("from_dict", (x, )) + py.import_bound("polars")?.call_method1("from_dict", (x, ))? } else { - Ok(x) - }?; + x + }; inner.set_obs(ob.extract::()?.0)?; } else { inner.del_obs()?; } Ok(()) } - fn set_var(&self, var: Option<&PyAny>) -> Result<()> { + fn set_var(&self, var: Option>) -> Result<()> { let inner = self.adata.inner(); if let Some(x) = var { let py = x.py(); - let ob = if isinstance_of_pandas(py, x)? { - py.import("polars")?.call_method1("from_pandas", (x, )) + let ob = if isinstance_of_pandas(&x)? { + py.import_bound("polars")?.call_method1("from_pandas", (x, ))? } else if x.is_instance_of::() { - py.import("polars")?.call_method1("from_dict", (x, )) + py.import_bound("polars")?.call_method1("from_dict", (x, ))? } else { - Ok(x) - }?; + x + }; inner.set_var(ob.extract::()?.0)?; } else { inner.del_var()?; diff --git a/pyanndata/src/anndata/dataset.rs b/pyanndata/src/anndata/dataset.rs index 9505c6e..56e876f 100644 --- a/pyanndata/src/anndata/dataset.rs +++ b/pyanndata/src/anndata/dataset.rs @@ -71,7 +71,7 @@ impl AnnDataSet { self.0.downcast_ref::>>().expect("downcast to AnnDataSet failed").inner() } - fn select_obs(&self, ix: &PyAny) -> PyResult { + fn select_obs(&self, ix: &Bound<'_, PyAny>) -> PyResult { let from_iter = ix.iter().and_then(|iter| iter.map(|x| x.unwrap().extract::()).collect::>>() ).map(|names| { @@ -89,7 +89,7 @@ impl AnnDataSet { } } - fn select_var(&self, ix: &PyAny) -> PyResult { + fn select_var(&self, ix: &Bound<'_, PyAny>) -> PyResult { let from_iter = ix.iter().and_then(|iter| iter.map(|x| x.unwrap().extract::()).collect::>>() ).map(|names| { @@ -111,7 +111,7 @@ impl AnnDataSet { #[derive(FromPyObject)] pub enum AnnDataFile<'py> { Path(PathBuf), - Data(&'py PyCell), + Data(Bound<'py, AnnData>), } #[pymethods] @@ -181,12 +181,12 @@ impl AnnDataSet { self.0.obs_names().into_vec() } #[setter(obs_names)] - pub fn set_obs_names(&self, names: &PyAny) -> Result<()> { + pub fn set_obs_names(&self, names: Bound<'_, PyAny>) -> Result<()> { self.0.set_obs_names(names) } #[pyo3(text_signature = "($self, names)")] - fn obs_ix(&self, names: &PyAny) -> Result> { self.0.obs_ix(names) } + fn obs_ix(&self, names: &Bound<'_, PyAny>) -> Result> { self.0.obs_ix(names) } /// Names of variables. /// @@ -198,12 +198,12 @@ impl AnnDataSet { self.0.var_names().into_vec() } #[setter(var_names)] - pub fn set_var_names(&self, names: &PyAny) -> Result<()> { + pub fn set_var_names(&self, names: Bound<'_, PyAny>) -> Result<()> { self.0.set_var_names(names) } #[pyo3(text_signature = "($self, names)")] - fn var_ix(&self, names: &PyAny) -> Result> { self.0.var_ix(names) } + fn var_ix(&self, names: Bound<'_, PyAny>) -> Result> { self.0.var_ix(names) } /// Data matrix of shape n_obs × n_vars. /// @@ -225,7 +225,7 @@ impl AnnDataSet { self.0.get_obs() } #[setter(obs)] - fn set_obs(&self, obs: Option<&PyAny>) -> Result<()> { + fn set_obs(&self, obs: Option>) -> Result<()> { self.0.set_obs(obs) } @@ -239,7 +239,7 @@ impl AnnDataSet { self.0.get_var() } #[setter(var)] - fn set_var(&self, var: Option<&PyAny>) -> Result<()> { + fn set_var(&self, var: Option>) -> Result<()> { self.0.set_var(var) } @@ -327,8 +327,8 @@ impl AnnDataSet { )] pub fn subset( &self, - obs_indices: Option<&PyAny>, - var_indices: Option<&PyAny>, + obs_indices: Option<&Bound<'_, PyAny>>, + var_indices: Option<&Bound<'_, PyAny>>, out: Option, backend: Option<&str>, ) -> Result<(AnnDataSet, Option>)> { @@ -363,8 +363,8 @@ impl AnnDataSet { pub fn to_adata( &self, py: Python<'_>, - obs_indices: Option<&PyAny>, - var_indices: Option<&PyAny>, + obs_indices: Option<&Bound<'_, PyAny>>, + var_indices: Option<&Bound<'_, PyAny>>, copy_x: bool, file: Option, backend: Option<&str>, @@ -442,11 +442,11 @@ pub struct StackedAnnData(pub Slot); trait AnnDataSetTrait: Send + Downcast { fn shape(&self) -> (usize, usize); fn obs_names(&self) -> DataFrameIndex; - fn set_obs_names(&self, names: &PyAny) -> Result<()>; - fn obs_ix(&self, index: &PyAny) -> Result>; + fn set_obs_names(&self, names: Bound<'_, PyAny>) -> Result<()>; + fn obs_ix(&self, index: &Bound<'_, PyAny>) -> Result>; fn var_names(&self) -> DataFrameIndex; - fn set_var_names(&self, names: &PyAny) -> Result<()>; - fn var_ix(&self, index: &PyAny) -> Result>; + fn set_var_names(&self, names: Bound<'_, PyAny>) -> Result<()>; + fn var_ix(&self, index: Bound<'_, PyAny>) -> Result>; fn get_x(&self) -> Option; fn get_obs(&self) -> Option; @@ -457,8 +457,8 @@ trait AnnDataSetTrait: Send + Downcast { fn get_varm(&self) -> Option; fn get_varp(&self) -> Option; - fn set_obs(&self, obs: Option<&PyAny>) -> Result<()>; - fn set_var(&self, var: Option<&PyAny>) -> Result<()>; + fn set_obs(&self, obs: Option>) -> Result<()>; + fn set_var(&self, var: Option>) -> Result<()>; fn set_uns(&self, uns: Option>) -> Result<()>; fn set_obsm(&self, obsm: Option>) -> Result<()>; fn set_obsp(&self, obsp: Option>) -> Result<()>; @@ -504,32 +504,30 @@ impl AnnDataSetTrait for Slot> { self.inner().obs_names() } - fn set_obs_names(&self, names: &PyAny) -> Result<()> { + fn set_obs_names(&self, names: Bound<'_, PyAny>) -> Result<()> { let obs_names: Result = names.iter()?.map(|x| Ok(x?.extract::()?)).collect(); self.inner().set_obs_names(obs_names?) } - fn obs_ix(&self, index: &PyAny) -> Result> { - self.inner().obs_ix( - index.iter()?.map(|x| x.unwrap().extract::<&str>().unwrap()) - ) + fn obs_ix(&self, index: &Bound<'_, PyAny>) -> Result> { + let bounds: Vec<_> = index.iter()?.map(|x| x.unwrap()).collect(); + self.inner().obs_ix(bounds.iter().map(|x| x.extract::<&str>().unwrap())) } fn var_names(&self) -> DataFrameIndex { self.inner().var_names() } - fn set_var_names(&self, names: &PyAny) -> Result<()> { + fn set_var_names(&self, names: Bound<'_, PyAny>) -> Result<()> { let var_names: Result = names.iter()?.map(|x| Ok(x?.extract::()?)).collect(); self.inner().set_var_names(var_names?) } - fn var_ix(&self, index: &PyAny) -> Result> { - self.inner().var_ix( - index.iter()?.map(|x| x.unwrap().extract::<&str>().unwrap()) - ) + fn var_ix(&self, index: Bound<'_, PyAny>) -> Result> { + let bounds: Vec<_> = index.iter()?.map(|x| x.unwrap()).collect(); + self.inner().var_ix(bounds.iter().map(|x| x.extract::<&str>().unwrap())) } fn get_x(&self) -> Option { @@ -599,34 +597,34 @@ impl AnnDataSetTrait for Slot> { } } - fn set_obs(&self, obs: Option<&PyAny>) -> Result<()> { + fn set_obs(&self, obs: Option>) -> Result<()> { let inner = self.inner(); if let Some(x) = obs { let py = x.py(); - let ob = if isinstance_of_pandas(py, x)? { - py.import("polars")?.call_method1("from_pandas", (x, )) + let ob = if isinstance_of_pandas(&x)? { + py.import_bound("polars")?.call_method1("from_pandas", (x, ))? } else if x.is_instance_of::() { - py.import("polars")?.call_method1("from_dict", (x, )) + py.import_bound("polars")?.call_method1("from_dict", (x, ))? } else { - Ok(x) - }?; + x + }; inner.set_obs(ob.extract::()?.0)?; } else { inner.del_obs()?; } Ok(()) } - fn set_var(&self, var: Option<&PyAny>) -> Result<()> { + fn set_var(&self, var: Option>) -> Result<()> { let inner = self.inner(); if let Some(x) = var { let py = x.py(); - let ob = if isinstance_of_pandas(py, x)? { - py.import("polars")?.call_method1("from_pandas", (x, )) + let ob = if isinstance_of_pandas(&x)? { + py.import_bound("polars")?.call_method1("from_pandas", (x, ))? } else if x.is_instance_of::() { - py.import("polars")?.call_method1("from_dict", (x, )) + py.import_bound("polars")?.call_method1("from_dict", (x, ))? } else { - Ok(x) - }?; + x + }; inner.set_var(ob.extract::()?.0)?; } else { inner.del_var()?; diff --git a/pyanndata/src/anndata/memory.rs b/pyanndata/src/anndata/memory.rs index e40d7c0..4a10011 100644 --- a/pyanndata/src/anndata/memory.rs +++ b/pyanndata/src/anndata/memory.rs @@ -11,31 +11,29 @@ use anndata::{AnnDataOp, AxisArraysOp, ArrayData, Data, ReadArrayData, ReadData, use anndata::data::{DataFrameIndex, SelectInfoElem, ArrayChunk, Shape}; use anyhow::{Result, bail}; -pub struct PyAnnData<'py>(&'py PyAny); +pub struct PyAnnData<'py>(Bound<'py, PyAny>); impl<'py> Deref for PyAnnData<'py> { - type Target = PyAny; + type Target = Bound<'py, PyAny>; fn deref(&self) -> &Self::Target { - self.0 + &self.0 } } impl<'py> FromPyObject<'py> for PyAnnData<'py> { - fn extract(obj: &'py PyAny) -> PyResult { - Python::with_gil(|py| { - if isinstance_of_pyanndata(py, obj)? { - Ok(PyAnnData(obj)) - } else { - Err(PyTypeError::new_err("Not a Python AnnData object")) - } - }) + fn extract_bound(obj: &Bound<'py, PyAny>) -> PyResult { + if isinstance_of_pyanndata(obj)? { + Ok(PyAnnData(obj.clone())) + } else { + Err(PyTypeError::new_err("Not a Python AnnData object")) + } } } impl ToPyObject for PyAnnData<'_> { fn to_object(&self, py: Python<'_>) -> PyObject { - self.0.into_py(py) + self.0.as_ref().into_py(py) } } @@ -48,7 +46,7 @@ impl IntoPy for PyAnnData<'_> { impl<'py> PyAnnData<'py> { pub fn new(py: Python<'py>) -> PyResult { - PyModule::import(py, "anndata")? + PyModule::import_bound(py, "anndata")? .call_method0("AnnData")? .extract() } @@ -195,12 +193,12 @@ impl<'py> AnnDataOp for PyAnnData<'py> { } fn set_obs_names(&self, index: DataFrameIndex) -> Result<()> { - if self.getattr("obs")?.getattr("empty")?.is_true()? { + if self.getattr("obs")?.getattr("empty")?.downcast().unwrap().is_true() { let py = self.py(); - let df = py.import("pandas")?.call_method( + let df = py.import_bound("pandas")?.call_method( "DataFrame", (), - Some(&[("index", index.into_vec())].into_py_dict(py)), + Some(&[("index", index.into_vec())].into_py_dict_bound(py)), )?; self.setattr("obs", df)?; } else { @@ -209,12 +207,12 @@ impl<'py> AnnDataOp for PyAnnData<'py> { Ok(()) } fn set_var_names(&self, index: DataFrameIndex) -> Result<()> { - if self.getattr("var")?.getattr("empty")?.is_true()? { + if self.getattr("var")?.getattr("empty")?.downcast().unwrap().is_true() { let py = self.py(); - let df = py.import("pandas")?.call_method( + let df = py.import_bound("pandas")?.call_method( "DataFrame", (), - Some(&[("index", index.into_vec())].into_py_dict(py)), + Some(&[("index", index.into_vec())].into_py_dict_bound(py)), )?; self.setattr("var", df)?; } else { @@ -227,17 +225,15 @@ impl<'py> AnnDataOp for PyAnnData<'py> { fn var_ix<'a, I: IntoIterator>(&self, _names: I) -> Result> {todo!()} fn read_obs(&self) -> Result { - let py = self.py(); - let df: PyDataFrame = py - .import("polars")? + let df: PyDataFrame = self.py() + .import_bound("polars")? .call_method1("from_pandas", (self.0.getattr("obs")?,))? .extract()?; Ok(df.into()) } fn read_var(&self) -> Result { - let py = self.py(); - let df: PyDataFrame = py - .import("polars")? + let df: PyDataFrame = self.py() + .import_bound("polars")? .call_method1("from_pandas", (self.0.getattr("var")?,))? .extract()?; Ok(df.into()) @@ -247,7 +243,7 @@ impl<'py> AnnDataOp for PyAnnData<'py> { let py = self.py(); let index = self.getattr("obs")?.getattr("index")?; let df = if obs.is_empty() { - py.import("pandas")? + py.import_bound("pandas")? .call_method1("DataFrame", (py.None(), index))? .into_py(py) } else { @@ -263,7 +259,7 @@ impl<'py> AnnDataOp for PyAnnData<'py> { let py = self.py(); let index = self.getattr("var")?.getattr("index")?; let df = if var.is_empty() { - py.import("pandas")? + py.import_bound("pandas")? .call_method1("DataFrame", (py.None(), index))? .into_py(py) } else { @@ -326,7 +322,7 @@ impl<'py> AnnDataOp for PyAnnData<'py> { } fn del_uns(&self) -> Result<()> { - self.0.setattr("uns", pyo3::types::PyDict::new(self.py()))?; + self.0.setattr("uns", pyo3::types::PyDict::new_bound(self.py()))?; Ok(()) } @@ -413,7 +409,7 @@ where } } -pub struct ElemCollection<'a>(&'a PyAny); +pub struct ElemCollection<'a>(Bound<'a, PyAny>); impl ElemCollectionOp for ElemCollection<'_> { fn keys(&self) -> Vec { @@ -439,7 +435,7 @@ impl ElemCollectionOp for ElemCollection<'_> { { let py = self.0.py(); let d = PyData::from(data.into()).into_py(py); - let new_d = if isinstance_of_polars(py, d.as_ref(py))? { + let new_d = if isinstance_of_polars(d.bind(py))? { d.call_method0(py, "to_pandas")? } else { d @@ -455,7 +451,7 @@ impl ElemCollectionOp for ElemCollection<'_> { } pub struct AxisArrays<'a> { - arrays: &'a PyAny, + arrays: Bound<'a, PyAny>, adata: &'a PyAnnData<'a>, axis: u8, } @@ -488,7 +484,7 @@ impl<'py> AxisArraysOp for AxisArrays<'py> { self.adata.set_n_vars(shape[1])?; } let d = PyArrayData::from(data.into()).into_py(py); - let new_d = if isinstance_of_polars(py, d.as_ref(py))? { + let new_d = if isinstance_of_polars(d.bind(py))? { d.call_method0(py, "to_pandas")? } else { d @@ -525,7 +521,7 @@ impl<'py> AxisArraysOp for AxisArrays<'py> { } -pub struct ArrayElem<'a>(&'a PyAny); +pub struct ArrayElem<'a>(Bound<'a, PyAny>); impl ArrayElemOp for ArrayElem<'_> { type ArrayIter = PyArrayIterator diff --git a/pyanndata/src/container.rs b/pyanndata/src/container.rs index c92ff57..1b5878c 100644 --- a/pyanndata/src/container.rs +++ b/pyanndata/src/container.rs @@ -34,8 +34,8 @@ impl PyElem { self.0.is_scalar() } - fn __getitem__<'py>(&self, py: Python<'py>, subscript: &'py PyAny) -> Result { - self.0.get(py, subscript) + fn __getitem__<'py>(&self, subscript: &Bound<'py, PyAny>) -> Result { + self.0.get(subscript) } fn __repr__(&self) -> String { @@ -81,7 +81,7 @@ impl PyArrayElem { self.0.shape() } - fn __getitem__(&self, subscript: &PyAny) -> Result { + fn __getitem__(&self, subscript: &Bound<'_, PyAny>) -> Result { self.0.get(subscript) } @@ -149,12 +149,12 @@ impl From for PyDataFrameElem { #[pymethods] impl PyDataFrameElem { - fn __getitem__(&self, subscript: &PyAny) -> Result { + fn __getitem__(&self, subscript: &Bound<'_, PyAny>) -> Result { self.0.get(subscript) } - fn __setitem__(&self, key: &str, data: &PyAny) -> Result<()> { - let data: PySeries = data.py().import("polars")?.call_method1("Series", (data, ))?.extract()?; + fn __setitem__(&self, key: &str, data: &Bound<'_, PyAny>) -> Result<()> { + let data: PySeries = data.py().import_bound("polars")?.call_method1("Series", (data, ))?.extract()?; self.0.set(key, data.into()) } diff --git a/pyanndata/src/container/traits.rs b/pyanndata/src/container/traits.rs index f4727f3..728edee 100644 --- a/pyanndata/src/container/traits.rs +++ b/pyanndata/src/container/traits.rs @@ -25,7 +25,7 @@ pub trait ElemTrait: Send { fn enable_cache(&self); fn disable_cache(&self); fn is_scalar(&self) -> bool; - fn get<'py>(&self, py: Python<'py>, subscript: &'py PyAny) -> Result; + fn get<'py>(&self, subscript: &Bound<'py, PyAny>) -> Result; fn show(&self) -> String; } @@ -45,8 +45,8 @@ impl ElemTrait for Elem { } } - fn get<'py>(&self, py: Python<'py>, slice: &'py PyAny) -> Result { - if is_none_slice(py, slice)? { + fn get<'py>(&self, slice: &Bound<'py, PyAny>) -> Result { + if is_none_slice(slice)? { Ok(self.inner().data::()?.into()) } else { bail!("Please use None slice to retrieve data.") @@ -62,7 +62,7 @@ pub trait ArrayElemTrait: Send { fn enable_cache(&self); fn disable_cache(&self); fn show(&self) -> String; - fn get(&self, subscript: &PyAny) -> Result; + fn get(&self, subscript: &Bound<'_, PyAny>) -> Result; fn shape(&self) -> Vec; fn chunk( &self, @@ -82,7 +82,7 @@ impl ArrayElemTrait for ArrayElem { self.lock().as_mut().map(|x| x.disable_cache()); } - fn get(&self, subscript: &PyAny) -> Result { + fn get(&self, subscript: &Bound<'_, PyAny>) -> Result { let slice = to_select_info(subscript, self.inner().shape())?; self.inner() .select::(slice.as_ref()) @@ -129,7 +129,7 @@ impl ArrayElemTrait for StackedArrayElem { self.deref().disable_cache(); } - fn get(&self, subscript: &PyAny) -> Result { + fn get(&self, subscript: &Bound<'_, PyAny>) -> Result { let slice = to_select_info(subscript, self.deref().shape().as_ref().unwrap())?; self.select::(slice.as_ref()) .map(|x| x.unwrap().into()) @@ -168,14 +168,14 @@ impl ArrayElemTrait for StackedArrayElem { } pub trait DataFrameElemTrait: Send { - fn get(&self, subscript: &PyAny) -> Result; + fn get(&self, subscript: &Bound<'_, PyAny>) -> Result; fn set(&self, key: &str, data: Series) -> Result<()>; fn contains(&self, key: &str) -> bool; fn show(&self) -> String; } impl DataFrameElemTrait for DataFrameElem { - fn get(&self, subscript: &PyAny) -> Result { + fn get(&self, subscript: &Bound<'_, PyAny>) -> Result { let py = subscript.py(); if let Ok(key) = subscript.extract::<&str>() { Ok(PySeries(self.inner().column(key)?.clone()).into_py(py)) @@ -207,7 +207,7 @@ impl DataFrameElemTrait for DataFrameElem { } impl DataFrameElemTrait for StackedDataFrame { - fn get(&self, subscript: &PyAny) -> Result { + fn get(&self, subscript: &Bound<'_, PyAny>) -> Result { let py = subscript.py(); if let Ok(key) = subscript.extract::<&str>() { Ok(PySeries(self.column(key)?.clone()).into_py(py)) diff --git a/pyanndata/src/data.rs b/pyanndata/src/data.rs index 4a09374..31b4fb9 100644 --- a/pyanndata/src/data.rs +++ b/pyanndata/src/data.rs @@ -11,7 +11,7 @@ use pyo3::{prelude::*, types::PyDict}; use anndata::data::{Data, ArrayData, DynArray, DynCsrMatrix, DynCscMatrix, DynScalar, Mapping, DynCsrNonCanonical}; pub(crate) trait FromPython<'source>: Sized { - fn from_python(ob: &'source PyAny) -> PyResult; + fn from_python(ob: &Bound<'source, PyAny>) -> PyResult; } pub(crate) trait IntoPython { @@ -41,22 +41,21 @@ impl Into for PyArrayData { } impl<'py> FromPyObject<'py> for PyArrayData { - fn extract(ob: &'py PyAny) -> PyResult { - let py = ob.py(); - if isinstance_of_arr(py, ob)? { + fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { + if isinstance_of_arr(ob)? { Ok(ArrayData::from(DynArray::from_python(ob)?).into()) - } else if isinstance_of_csr(py, ob)? { + } else if isinstance_of_csr(ob)? { if ob.getattr("has_canonical_format")?.extract()? { Ok(ArrayData::from(DynCsrMatrix::from_python(ob)?).into()) } else { Ok(ArrayData::from(DynCsrNonCanonical::from_python(ob)?).into()) } - } else if isinstance_of_csc(py, ob)? { + } else if isinstance_of_csc(ob)? { Ok(ArrayData::from(DynCscMatrix::from_python(ob)?).into()) - } else if isinstance_of_pandas(py, ob)? { - let ob = py.import("polars")?.call_method1("from_pandas", (ob, ))?; + } else if isinstance_of_pandas(ob)? { + let ob = ob.py().import_bound("polars")?.call_method1("from_pandas", (ob, ))?; Ok(ArrayData::from(ob.extract::()?.0).into()) - } else if isinstance_of_polars(py, ob)? { + } else if isinstance_of_polars(ob)? { Ok(ArrayData::from(ob.extract::()?.0).into()) } else { Err(PyErr::new::( @@ -93,7 +92,7 @@ impl Into for PyData { } impl<'py> FromPyObject<'py> for PyData { - fn extract(ob: &'py PyAny) -> PyResult { + fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { let data = if let Ok(s) = DynScalar::from_python(ob) { PyData(Data::Scalar(s)) } else if ob.is_instance_of::() { @@ -118,7 +117,7 @@ impl IntoPy for PyData { } impl FromPython<'_> for DynScalar { - fn from_python(ob: &PyAny) -> PyResult { + fn from_python(ob: &Bound<'_, PyAny>) -> PyResult { if ob.is_instance_of::() { ob.extract::().map(Into::into) } else if ob.is_instance_of::() { @@ -136,7 +135,7 @@ impl FromPython<'_> for DynScalar { } impl FromPython<'_> for Mapping { - fn from_python(ob: &PyAny) -> PyResult { + fn from_python(ob: &Bound<'_, PyAny>) -> PyResult { let data: HashMap = ob.extract()?; let mapping = data.into_iter() .map(|(k, v)| (k, v.0)) @@ -167,7 +166,7 @@ impl IntoPython for DynScalar { impl IntoPython for Mapping { fn into_python(self, py: Python<'_>) -> PyResult { - let dict = PyDict::new(py); + let dict = PyDict::new_bound(py); let data: HashMap = self.into(); data.into_iter().try_for_each(|(k, v)| { dict.set_item(k, PyData(v).into_py(py)) diff --git a/pyanndata/src/data/array.rs b/pyanndata/src/data/array.rs index 23a3a0c..53272a9 100644 --- a/pyanndata/src/data/array.rs +++ b/pyanndata/src/data/array.rs @@ -4,7 +4,7 @@ use ndarray::ArrayD; use nalgebra_sparse::{CsrMatrix, CscMatrix}; use pyo3::{exceptions::PyTypeError, prelude::*}; use anndata::data::{DynArray, DynCsrMatrix, DynCscMatrix, DynCsrNonCanonical, CsrNonCanonical}; -use numpy::{PyReadonlyArrayDyn, IntoPyArray}; +use numpy::{PyReadonlyArrayDyn, IntoPyArray, PyArrayMethods}; macro_rules! proc_py_numeric { ($dtype:expr, $data:expr, $ty_anno:tt) => { @@ -59,9 +59,10 @@ macro_rules! proc_py_numeric { } impl FromPython<'_> for DynArray { - fn from_python(ob: &PyAny) -> PyResult { + fn from_python(ob: &Bound<'_, PyAny>) -> PyResult { let py = ob.py(); - let dtype = ob.getattr("dtype")?.getattr("char")?.extract::<&str>()?; + let dtype = ob.getattr("dtype")?.getattr("char")?; + let dtype = dtype.extract::<&str>()?; let arr = if dtype == "U" || dtype == "S" { ob.getattr("astype")?.call1(("object",))? .extract::>()? @@ -74,7 +75,8 @@ impl FromPython<'_> for DynArray { .map(|x| x.extract::(py).unwrap()) .into() } else { - let ty = ob.getattr("dtype")?.getattr("name")?.extract::<&str>()?; + let ty = ob.getattr("dtype")?.getattr("name")?; + let ty = ty.extract::<&str>()?; proc_py_numeric!(ty, ob.extract::>()?.to_owned_array(), ArrayD) }; Ok(arr) @@ -82,8 +84,8 @@ impl FromPython<'_> for DynArray { } impl FromPython<'_> for DynCsrMatrix { - fn from_python(ob: &PyAny) -> PyResult { - fn extract_csr_indicies(indicies: &PyAny) -> PyResult> { + fn from_python(ob: &Bound<'_, PyAny>) -> PyResult { + fn extract_csr_indicies(indicies: Bound<'_, PyAny>) -> PyResult> { let res = match indicies .getattr("dtype")? .getattr("name")? @@ -106,14 +108,15 @@ impl FromPython<'_> for DynCsrMatrix { Ok(res) } - if !isinstance_of_csr(ob.py(), ob)? { + if !isinstance_of_csr(ob)? { return Err(PyTypeError::new_err("not a csr matrix")) } let shape: Vec = ob.getattr("shape")?.extract()?; let indices = extract_csr_indicies(ob.getattr("indices")?)?; let indptr = extract_csr_indicies(ob.getattr("indptr")?)?; - let ty = ob.getattr("data")?.getattr("dtype")?.getattr("name")?.extract::<&str>()?; + let ty = ob.getattr("data")?.getattr("dtype")?.getattr("name")?; + let ty = ty.extract::<&str>()?; let csr = proc_py_numeric!( ty, @@ -131,8 +134,8 @@ impl FromPython<'_> for DynCsrMatrix { } impl FromPython<'_> for DynCsrNonCanonical { - fn from_python(ob: &PyAny) -> PyResult { - fn extract_csr_indicies(indicies: &PyAny) -> PyResult> { + fn from_python(ob: &Bound<'_, PyAny>) -> PyResult { + fn extract_csr_indicies(indicies: Bound<'_, PyAny>) -> PyResult> { let res = match indicies .getattr("dtype")? .getattr("name")? @@ -155,14 +158,15 @@ impl FromPython<'_> for DynCsrNonCanonical { Ok(res) } - if !isinstance_of_csr(ob.py(), ob)? { + if !isinstance_of_csr(ob)? { return Err(PyTypeError::new_err("not a csr matrix")) } let shape: Vec = ob.getattr("shape")?.extract()?; let indices = extract_csr_indicies(ob.getattr("indices")?)?; let indptr = extract_csr_indicies(ob.getattr("indptr")?)?; - let ty = ob.getattr("data")?.getattr("dtype")?.getattr("name")?.extract::<&str>()?; + let ty = ob.getattr("data")?.getattr("dtype")?.getattr("name")?; + let ty = ty.extract::<&str>()?; let csr = proc_py_numeric!( ty, @@ -180,8 +184,8 @@ impl FromPython<'_> for DynCsrNonCanonical { } impl FromPython<'_> for DynCscMatrix { - fn from_python(ob: &PyAny) -> PyResult { - fn extract_csc_indicies(indicies: &PyAny) -> PyResult> { + fn from_python(ob: &Bound<'_, PyAny>) -> PyResult { + fn extract_csc_indicies(indicies: Bound<'_, PyAny>) -> PyResult> { let res = match indicies .getattr("dtype")? .getattr("name")? @@ -204,14 +208,15 @@ impl FromPython<'_> for DynCscMatrix { Ok(res) } - if !isinstance_of_csc(ob.py(), ob)? { + if !isinstance_of_csc(ob)? { return Err(PyTypeError::new_err("not a csc matrix")) } let shape: Vec = ob.getattr("shape")?.extract()?; let indices = extract_csc_indicies(ob.getattr("indices")?)?; let indptr = extract_csc_indicies(ob.getattr("indptr")?)?; - let ty = ob.getattr("data")?.getattr("dtype")?.getattr("name")?.extract::<&str>()?; + let ty = ob.getattr("data")?.getattr("dtype")?.getattr("name")?; + let ty = ty.extract::<&str>()?; let csc = proc_py_numeric!( ty, @@ -231,18 +236,18 @@ impl FromPython<'_> for DynCscMatrix { impl IntoPython for DynArray { fn into_python(self, py: Python<'_>) -> PyResult { let res = match self { - DynArray::I8(arr) => arr.into_pyarray(py).to_object(py), - DynArray::I16(arr) => arr.into_pyarray(py).to_object(py), - DynArray::I32(arr) => arr.into_pyarray(py).to_object(py), - DynArray::I64(arr) => arr.into_pyarray(py).to_object(py), - DynArray::U8(arr) => arr.into_pyarray(py).to_object(py), - DynArray::U16(arr) => arr.into_pyarray(py).to_object(py), - DynArray::U32(arr) => arr.into_pyarray(py).to_object(py), - DynArray::U64(arr) => arr.into_pyarray(py).to_object(py), - DynArray::Usize(arr) => arr.into_pyarray(py).to_object(py), - DynArray::F32(arr) => arr.into_pyarray(py).to_object(py), - DynArray::F64(arr) => arr.into_pyarray(py).to_object(py), - DynArray::Bool(arr) => arr.into_pyarray(py).to_object(py), + DynArray::I8(arr) => arr.into_pyarray_bound(py).to_object(py), + DynArray::I16(arr) => arr.into_pyarray_bound(py).to_object(py), + DynArray::I32(arr) => arr.into_pyarray_bound(py).to_object(py), + DynArray::I64(arr) => arr.into_pyarray_bound(py).to_object(py), + DynArray::U8(arr) => arr.into_pyarray_bound(py).to_object(py), + DynArray::U16(arr) => arr.into_pyarray_bound(py).to_object(py), + DynArray::U32(arr) => arr.into_pyarray_bound(py).to_object(py), + DynArray::U64(arr) => arr.into_pyarray_bound(py).to_object(py), + DynArray::Usize(arr) => arr.into_pyarray_bound(py).to_object(py), + DynArray::F32(arr) => arr.into_pyarray_bound(py).to_object(py), + DynArray::F64(arr) => arr.into_pyarray_bound(py).to_object(py), + DynArray::Bool(arr) => arr.into_pyarray_bound(py).to_object(py), DynArray::String(_) => todo!(), DynArray::Categorical(_) => todo!(), }; @@ -256,14 +261,14 @@ impl IntoPython for DynCsrMatrix { let n = csr.nrows(); let m = csr.ncols(); let (indptr, indices, data) = csr.disassemble(); - let scipy = PyModule::import(py, "scipy.sparse")?; + let scipy = PyModule::import_bound(py, "scipy.sparse")?; Ok(scipy .getattr("csr_matrix")? .call1(( ( - data.into_pyarray(py), - indices.into_pyarray(py), - indptr.into_pyarray(py), + data.into_pyarray_bound(py), + indices.into_pyarray_bound(py), + indptr.into_pyarray_bound(py), ), (n, m), ))? @@ -294,14 +299,14 @@ impl IntoPython for DynCsrNonCanonical { let n = csr.nrows(); let m = csr.ncols(); let (indptr, indices, data) = csr.disassemble(); - let scipy = PyModule::import(py, "scipy.sparse")?; + let scipy = PyModule::import_bound(py, "scipy.sparse")?; Ok(scipy .getattr("csr_matrix")? .call1(( ( - data.into_pyarray(py), - indices.into_pyarray(py), - indptr.into_pyarray(py), + data.into_pyarray_bound(py), + indices.into_pyarray_bound(py), + indptr.into_pyarray_bound(py), ), (n, m), ))? @@ -333,14 +338,14 @@ impl IntoPython for DynCscMatrix { let n = csc.nrows(); let m = csc.ncols(); let (indptr, indices, data) = csc.disassemble(); - let scipy = PyModule::import(py, "scipy.sparse")?; + let scipy = PyModule::import_bound(py, "scipy.sparse")?; Ok(scipy .getattr("csc_matrix")? .call1(( ( - data.into_pyarray(py), - indices.into_pyarray(py), - indptr.into_pyarray(py), + data.into_pyarray_bound(py), + indices.into_pyarray_bound(py), + indptr.into_pyarray_bound(py), ), (n, m), ))? diff --git a/pyanndata/src/data/instance.rs b/pyanndata/src/data/instance.rs index 6b00b30..8182799 100644 --- a/pyanndata/src/data/instance.rs +++ b/pyanndata/src/data/instance.rs @@ -1,67 +1,68 @@ -use pyo3::{prelude::*, types::PyType, PyResult, Python}; +use pyo3::{prelude::*, types::PyType, PyResult}; -pub fn isinstance_of_csr<'py>(py: Python<'py>, obj: &'py PyAny) -> PyResult { +pub fn isinstance_of_csr<'py>(obj: &Bound<'py, PyAny>) -> PyResult { obj.is_instance( - py.import("scipy.sparse")? + obj.py().import_bound("scipy.sparse")? .getattr("csr_matrix")? .downcast::() .unwrap(), ) } -pub fn isinstance_of_csc<'py>(py: Python<'py>, obj: &'py PyAny) -> PyResult { +pub fn isinstance_of_csc<'py>(obj: &Bound<'py, PyAny>) -> PyResult { obj.is_instance( - py.import("scipy.sparse")? + obj.py().import_bound("scipy.sparse")? .getattr("csc_matrix")? .downcast::() .unwrap(), ) } -pub fn isinstance_of_arr<'py>(py: Python<'py>, obj: &'py PyAny) -> PyResult { +pub fn isinstance_of_arr<'py>(obj: &Bound<'py, PyAny>) -> PyResult { obj.is_instance( - py.import("numpy")? + obj.py().import_bound("numpy")? .getattr("ndarray")? .downcast::() .unwrap(), ) } -pub fn isinstance_of_pyanndata<'py>(py: Python<'py>, obj: &'py PyAny) -> PyResult { +pub fn isinstance_of_pyanndata<'py>(obj: &Bound<'py, PyAny>) -> PyResult { obj.is_instance( - py.import("anndata")? + obj.py().import_bound("anndata")? .getattr("AnnData")? .downcast::() .unwrap(), ) } -pub fn isinstance_of_pandas<'py>(py: Python<'py>, obj: &'py PyAny) -> PyResult { +pub fn isinstance_of_pandas<'py>(obj: &Bound<'py, PyAny>) -> PyResult { obj.is_instance( - py.import("pandas")? + obj.py().import_bound("pandas")? .getattr("DataFrame")? .downcast::() .unwrap(), ) } -pub fn isinstance_of_polars<'py>(py: Python<'py>, obj: &'py PyAny) -> PyResult { +pub fn isinstance_of_polars<'py>(obj: &Bound<'py, PyAny>) -> PyResult { obj.is_instance( - py.import("polars")? + obj.py().import_bound("polars")? .getattr("DataFrame")? .downcast::() .unwrap(), ) } -pub fn is_none_slice<'py>(py: Python<'py>, obj: &'py PyAny) -> PyResult { +pub fn is_none_slice<'py>(obj: &Bound<'py, PyAny>) -> PyResult { + let py = obj.py(); Ok( obj.is_none() || - obj.is_ellipsis() || - (is_slice(obj) && obj.eq(py.eval("slice(None, None, None)", None, None)?)?) + obj.is(&py.Ellipsis()) || + (is_slice(obj) && obj.eq(py.eval_bound("slice(None, None, None)", None, None)?)?) ) } -fn is_slice<'py>(obj: &'py PyAny) -> bool { +fn is_slice<'py>(obj: &Bound<'py, PyAny>) -> bool { obj.is_instance_of::() } \ No newline at end of file diff --git a/pyanndata/src/data/slice.rs b/pyanndata/src/data/slice.rs index 9e3d1c4..eac3df0 100644 --- a/pyanndata/src/data/slice.rs +++ b/pyanndata/src/data/slice.rs @@ -3,22 +3,20 @@ use crate::data::instance::*; use pyo3::prelude::*; use anndata::data::{Shape, SelectInfo, SelectInfoElem}; -pub fn to_select_info(ob: &PyAny, shape: &Shape) -> PyResult { - let py = ob.py(); +pub fn to_select_info(ob: &Bound<'_, PyAny>, shape: &Shape) -> PyResult { let ndim = shape.ndim(); - if is_none_slice(py, ob)? { + if is_none_slice(ob)? { Ok(std::iter::repeat(SelectInfoElem::full()).take(ndim).collect()) } else if ob.is_instance_of::() { ob.iter()?.zip(shape.as_ref()) - .map(|(x, len)| to_select_elem(x?, *len)) + .map(|(x, len)| to_select_elem(&x?, *len)) .collect() } else { todo!() } } -pub fn to_select_elem(ob: &PyAny, length: usize) -> PyResult { - let py = ob.py(); +pub fn to_select_elem(ob: &Bound<'_, PyAny>, length: usize) -> PyResult { let select = if let Ok(slice) = ob.downcast::() { let s = slice.indices(length as i64)?; ndarray::Slice { @@ -26,14 +24,14 @@ pub fn to_select_elem(ob: &PyAny, length: usize) -> PyResult { end: Some(s.stop), step: s.step, }.into() - } else if is_none_slice(py, ob)? { + } else if is_none_slice(ob)? { SelectInfoElem::full() } else if ob.is_instance_of::() { ob.extract::()?.into() - } else if isinstance_of_arr(py, ob)? && ob.getattr("dtype")?.getattr("name")?.extract::<&str>()? == "bool" { + } else if isinstance_of_arr(ob)? && ob.getattr("dtype")?.getattr("name")?.extract::<&str>()? == "bool" { let arr = ob .extract::>()?; - if arr.len() == length { + if arr.len()? == length { boolean_mask_to_indices(arr.as_array().into_iter().map(|x| *x)).into() } else { panic!("boolean mask dimension mismatched") diff --git a/python/Cargo.toml b/python/Cargo.toml index 8965140..3f65295 100644 --- a/python/Cargo.toml +++ b/python/Cargo.toml @@ -11,10 +11,10 @@ keywords = ["data"] [dependencies] pyanndata = { path = "../pyanndata" } -pyo3-log = "0.9" +pyo3-log = "0.10" [dependencies.pyo3] -version = "0.20.2" +version = "0.21.2" features = ["extension-module", "multiple-pymethods"] [lib]