mirror of
https://github.com/Cian-H/read_aconity_layers.git
synced 2025-12-24 03:01:56 +00:00
Updated package to use most recent maturin version
Significant rewrite to allow this module to work with the most recetn version of maturin. Required dependency removal for ndarray-csv and rewrite of tests. Should future-proof for migratiosn to python3.13 in software using this library.
This commit is contained in:
70
src/lib.rs
70
src/lib.rs
@@ -1,7 +1,7 @@
|
||||
use numpy::{IntoPyArray, PyArray2};
|
||||
use ndarray::{ArrayBase, Ix2, OwnedRepr};
|
||||
use numpy::{PyArray2, ToPyArray};
|
||||
use pyo3::exceptions;
|
||||
use pyo3::prelude::{pymodule, PyErr, PyModule, PyResult, Python};
|
||||
use pyo3::types::{PyList, PyString};
|
||||
use pyo3::prelude::*;
|
||||
use std::path::Path;
|
||||
|
||||
pub mod rust_fn;
|
||||
@@ -16,9 +16,7 @@ impl From<rust_fn::ReadError> for PyErr {
|
||||
PyErr::new::<exceptions::PyRuntimeError, _>(format!("{}", e))
|
||||
}
|
||||
rust_fn::ReadError::Io(e) => PyErr::new::<exceptions::PyIOError, _>(format!("{}", e)),
|
||||
rust_fn::ReadError::NdarrayCSV(e) => {
|
||||
PyErr::new::<exceptions::PyIOError, _>(format!("{}", e))
|
||||
}
|
||||
rust_fn::ReadError::CSV(e) => PyErr::new::<exceptions::PyIOError, _>(format!("{}", e)),
|
||||
rust_fn::ReadError::ParseFloatError(e) => {
|
||||
PyErr::new::<exceptions::PyRuntimeError, _>(format!("{}", e))
|
||||
}
|
||||
@@ -27,31 +25,41 @@ impl From<rust_fn::ReadError> for PyErr {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn read_layers<'py>(_py: Python<'py>, folder: &'py str) -> PyResult<Bound<'py, PyArray2<f64>>>
|
||||
where
|
||||
ArrayBase<OwnedRepr<f64>, Ix2>: ToPyArray<Item = f64, Dim = Ix2>,
|
||||
{
|
||||
let rs_result = rust_fn::read_layers(folder)?;
|
||||
let py_result = rs_result.to_pyarray_bound(_py);
|
||||
Ok(py_result)
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn read_selected_layers<'py>(
|
||||
_py: Python<'py>,
|
||||
file_list: Vec<String>,
|
||||
) -> PyResult<Bound<'py, PyArray2<f64>>> {
|
||||
let path_list = file_list
|
||||
.iter()
|
||||
.map(|x| Path::new(x).to_path_buf())
|
||||
.collect();
|
||||
let rs_result = rust_fn::read_selected_layers(path_list)?;
|
||||
let py_result = rs_result.to_pyarray_bound(_py);
|
||||
Ok(py_result)
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn read_layer<'py>(_py: Python<'py>, file: String) -> PyResult<Bound<'py, PyArray2<f64>>> {
|
||||
let rs_result = rust_fn::read_layer(&file)?;
|
||||
let py_result = rs_result.to_pyarray_bound(_py);
|
||||
Ok(py_result)
|
||||
}
|
||||
|
||||
#[pymodule]
|
||||
fn read_aconity_layers(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
||||
#[pyfn(m)]
|
||||
fn read_layers<'py>(py: Python<'py>, folder: &PyString) -> PyResult<&'py PyArray2<f64>> {
|
||||
Ok(rust_fn::read_layers(folder.to_str().unwrap())?.into_pyarray(py))
|
||||
}
|
||||
|
||||
#[pyfn(m)]
|
||||
fn read_selected_layers<'py>(
|
||||
py: Python<'py>,
|
||||
file_list: &PyList,
|
||||
) -> PyResult<&'py PyArray2<f64>> {
|
||||
Ok(rust_fn::read_selected_layers(
|
||||
file_list
|
||||
.iter()
|
||||
.map(|x| Path::new(&(*x).str().unwrap().to_string()).to_path_buf())
|
||||
.collect(),
|
||||
)?
|
||||
.into_pyarray(py))
|
||||
}
|
||||
|
||||
#[pyfn(m)]
|
||||
fn read_layer<'py>(py: Python<'py>, file: &PyString) -> PyResult<&'py PyArray2<f64>> {
|
||||
Ok(rust_fn::read_layer(file.to_str().unwrap())?.into_pyarray(py))
|
||||
}
|
||||
|
||||
fn read_aconity_layers(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||
m.add_function(wrap_pyfunction!(read_layers, m)?)?;
|
||||
m.add_function(wrap_pyfunction!(read_selected_layers, m)?)?;
|
||||
m.add_function(wrap_pyfunction!(read_layer, m)?)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ use csv::ReaderBuilder;
|
||||
use glob::glob;
|
||||
use indicatif::ProgressBar;
|
||||
use ndarray::{concatenate, Array2, ArrayView2, Axis, Slice};
|
||||
use ndarray_csv::Array2Reader;
|
||||
use rayon::prelude::*;
|
||||
use std::fs::File;
|
||||
use std::path::{Path, PathBuf};
|
||||
@@ -19,8 +18,8 @@ pub enum ReadError {
|
||||
#[error("IO error: {0}")]
|
||||
Io(#[from] std::io::Error),
|
||||
|
||||
#[error("NdarrayCSV error: {0}")]
|
||||
NdarrayCSV(#[from] ndarray_csv::ReadError),
|
||||
#[error("CSV error: {0}")]
|
||||
CSV(#[from] csv::Error),
|
||||
|
||||
#[error("Float parse error: {0}")]
|
||||
ParseFloatError(#[from] std::num::ParseFloatError),
|
||||
@@ -158,14 +157,28 @@ pub fn read_layer(file: &str) -> Result<Array2<f64>> {
|
||||
pub fn read_file(filepath: PathBuf) -> Result<(Array2<f64>, f64, usize)> {
|
||||
let z: f64 = get_z(&filepath)?;
|
||||
let file = File::open(filepath)?;
|
||||
let mut rdr = ReaderBuilder::new()
|
||||
.has_headers(false)
|
||||
.delimiter(b' ')
|
||||
.from_reader(file);
|
||||
let array_read: Array2<f64> = rdr.deserialize_array2_dynamic()?;
|
||||
let z_len: usize = array_read.shape()[0];
|
||||
let mut rdr = ReaderBuilder::new().has_headers(false).from_reader(file);
|
||||
let data = rdr
|
||||
.records()
|
||||
.into_iter()
|
||||
.collect::<std::result::Result<Vec<csv::StringRecord>, _>>()?
|
||||
.iter()
|
||||
.map(|x| {
|
||||
x.iter()
|
||||
.map(|y| y.parse::<f64>().map_err(|e| ReadError::ParseFloatError(e)))
|
||||
.collect::<Result<Vec<f64>>>()
|
||||
})
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
let length = data.len();
|
||||
let width = data[0].len(); // WARNING: assumes fixed width columns!
|
||||
let mut arr: Array2<f64> = Array2::zeros((length, width));
|
||||
for (data_row, mut arr_row) in data.iter().zip(arr.axis_iter_mut(Axis(0))) {
|
||||
for (data_i, arr_i) in data_row.iter().zip(arr_row.iter_mut()) {
|
||||
*arr_i = *data_i
|
||||
}
|
||||
}
|
||||
|
||||
Ok((array_read, z, z_len))
|
||||
Ok((arr, z, length))
|
||||
}
|
||||
|
||||
pub fn get_z(filepath: &Path) -> Result<f64> {
|
||||
@@ -220,13 +233,16 @@ mod tests {
|
||||
}
|
||||
impl<'a> Arbitrary<'a> for ExampleData {
|
||||
fn arbitrary(u: &mut Unstructured<'a>) -> ArbResult<Self> {
|
||||
// NOTE: We need to add 1 here, it len == 0 the test will fail
|
||||
// NOTE: We need to add 1 here, if len == 0 the test will fail
|
||||
let len = 1 + u
|
||||
.arbitrary_len::<(isize, isize, isize, isize)>()?
|
||||
.min(usize::MAX - 1);
|
||||
let ar =
|
||||
Array2::from_shape_simple_fn((4, len), || isize::arbitrary(u).unwrap_or_default());
|
||||
let z = f64::arbitrary(u)?.abs() / Z_SCALING;
|
||||
// This is a clunky way to account for truncation of floats when writing filepath
|
||||
let z = format!("{:.32}", f64::arbitrary(u)?.abs() / Z_SCALING)
|
||||
.parse()
|
||||
.map_err(|_| arbitrary::Error::IncorrectFormat)?;
|
||||
|
||||
Ok(ExampleData { z, ar })
|
||||
}
|
||||
@@ -291,8 +307,10 @@ mod tests {
|
||||
fn proptest_read_file() {
|
||||
fn prop(u: &mut Unstructured<'_>) -> ArbResult<()> {
|
||||
let data = ExampleData::arbitrary(u)?;
|
||||
let (_tmpdir, tmpfpath) = create_test_pcd(data.z, &data.ar).unwrap();
|
||||
let (ar_out, z_out, _) = rust_fn::read_file(tmpfpath).unwrap();
|
||||
let (_tmpdir, tmpfpath) = create_test_pcd(data.z, &data.ar)
|
||||
.map_err(|_e| arbitrary::Error::IncorrectFormat)?;
|
||||
let (ar_out, z_out, _) =
|
||||
rust_fn::read_file(tmpfpath).map_err(|_e| arbitrary::Error::IncorrectFormat)?;
|
||||
let actual_result = ReadResult {
|
||||
z: z_out,
|
||||
ar: ar_out,
|
||||
|
||||
Reference in New Issue
Block a user