Skip to content

Commit 28ec322

Browse files
authored
Merge pull request #315 from PyO3/optimize-type-error
Delay formatting type errors to improve performance of failed extractions.
2 parents 2c99dfa + 9720102 commit 28ec322

File tree

4 files changed

+61
-21
lines changed

4 files changed

+61
-21
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
- The `inner`, `dot` and `einsum` functions can also return a scalar instead of a zero-dimensional array to match NumPy's types ([#285](https://github.com/PyO3/rust-numpy/pull/285))
99
- The `PyArray::resize` function supports n-dimensional contiguous arrays. ([#312](https://github.com/PyO3/rust-numpy/pull/312))
1010
- Deprecate `PyArray::from_exact_iter` after optimizing `PyArray::from_iter`. ([#292](https://github.com/PyO3/rust-numpy/pull/292))
11+
- Remove `DimensionalityError` and `TypeError` from the public API as they never used directly. ([#315](https://github.com/PyO3/rust-numpy/pull/315))
1112
- Fix returning invalid slices from `PyArray::{strides,shape}` for rank zero arrays. ([#303](https://github.com/PyO3/rust-numpy/pull/303))
1213

1314
- v0.16.2

benches/array.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,29 @@ use test::{black_box, Bencher};
66
use std::ops::Range;
77

88
use numpy::{PyArray1, PyArray2, PyArray3};
9-
use pyo3::{Python, ToPyObject};
9+
use pyo3::{PyAny, Python, ToPyObject};
10+
11+
#[bench]
12+
fn extract_success(bencher: &mut Bencher) {
13+
Python::with_gil(|py| {
14+
let any: &PyAny = PyArray2::<f64>::zeros(py, (10, 10), false);
15+
16+
bencher.iter(|| {
17+
black_box(any).extract::<&PyArray2<f64>>().unwrap();
18+
});
19+
});
20+
}
21+
22+
#[bench]
23+
fn extract_failure(bencher: &mut Bencher) {
24+
Python::with_gil(|py| {
25+
let any: &PyAny = PyArray2::<i32>::zeros(py, (10, 10), false);
26+
27+
bencher.iter(|| {
28+
black_box(any).extract::<&PyArray2<f64>>().unwrap_err();
29+
});
30+
});
31+
}
1032

1133
struct Iter(Range<usize>);
1234

src/error.rs

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use std::error::Error;
44
use std::fmt;
55

6-
use pyo3::{exceptions::PyTypeError, PyErr, PyErrArguments, PyObject, Python, ToPyObject};
6+
use pyo3::{exceptions::PyTypeError, Py, PyErr, PyErrArguments, PyObject, Python, ToPyObject};
77

88
use crate::dtype::PyArrayDescr;
99

@@ -59,32 +59,51 @@ impl_pyerr!(DimensionalityError);
5959

6060
/// Represents that types of the given arrays do not match.
6161
#[derive(Debug)]
62-
pub struct TypeError {
63-
from: String,
64-
to: String,
62+
pub struct TypeError<'a> {
63+
from: &'a PyArrayDescr,
64+
to: &'a PyArrayDescr,
6565
}
6666

67-
impl TypeError {
68-
pub(crate) fn new(from: &PyArrayDescr, to: &PyArrayDescr) -> Self {
69-
let dtype_to_str = |dtype: &PyArrayDescr| {
70-
dtype
71-
.str()
72-
.map_or_else(|_| "(unknown)".into(), |s| s.to_string_lossy().into_owned())
73-
};
74-
Self {
75-
from: dtype_to_str(from),
76-
to: dtype_to_str(to),
77-
}
67+
impl<'a> TypeError<'a> {
68+
pub(crate) fn new(from: &'a PyArrayDescr, to: &'a PyArrayDescr) -> Self {
69+
Self { from, to }
7870
}
7971
}
8072

81-
impl fmt::Display for TypeError {
73+
impl fmt::Display for TypeError<'_> {
8274
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
8375
write!(f, "type mismatch:\n from={}, to={}", self.from, self.to)
8476
}
8577
}
8678

87-
impl_pyerr!(TypeError);
79+
impl Error for TypeError<'_> {}
80+
81+
struct TypeErrorArguments {
82+
from: Py<PyArrayDescr>,
83+
to: Py<PyArrayDescr>,
84+
}
85+
86+
impl PyErrArguments for TypeErrorArguments {
87+
fn arguments(self, py: Python) -> PyObject {
88+
let err = TypeError {
89+
from: self.from.as_ref(py),
90+
to: self.to.as_ref(py),
91+
};
92+
93+
err.to_string().to_object(py)
94+
}
95+
}
96+
97+
impl From<TypeError<'_>> for PyErr {
98+
fn from(err: TypeError<'_>) -> PyErr {
99+
let args = TypeErrorArguments {
100+
from: err.from.into(),
101+
to: err.to.into(),
102+
};
103+
104+
PyTypeError::new_err(args)
105+
}
106+
}
88107

89108
/// Represents that given `Vec` cannot be treated as an array.
90109
#[derive(Debug)]

src/lib.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,7 @@ pub use crate::borrow::{
6161
};
6262
pub use crate::convert::{IntoPyArray, NpyIndex, ToNpyDims, ToPyArray};
6363
pub use crate::dtype::{dtype, Complex32, Complex64, Element, PyArrayDescr};
64-
pub use crate::error::{
65-
BorrowError, DimensionalityError, FromVecError, NotContiguousError, TypeError,
66-
};
64+
pub use crate::error::{BorrowError, FromVecError, NotContiguousError};
6765
pub use crate::npyffi::{PY_ARRAY_API, PY_UFUNC_API};
6866
#[allow(deprecated)]
6967
pub use crate::npyiter::{

0 commit comments

Comments
 (0)