chore(arbitrary-value): update to pyo3 0.27

This commit is contained in:
2026-01-07 01:19:34 -05:00
parent 10bceb55b8
commit 36bfa89548
2 changed files with 95 additions and 16 deletions

View File

@@ -3,11 +3,13 @@ use chrono_tz::Tz;
use ijson::{IArray, INumber, IObject, IString, IValue}; use ijson::{IArray, INumber, IObject, IString, IValue};
#[cfg(feature = "pyo3")] #[cfg(feature = "pyo3")]
use pyo3::{ use pyo3::{
exceptions::{PyTypeError, PyValueError}, exceptions::{PyException, PyTypeError, PyValueError},
prelude::*, prelude::*,
types::{PyList, PyNone}, types::{PyList, PyNone},
}; };
use snafu::Snafu; use snafu::{ResultExt, Snafu};
use crate::finite_f64::NotFinite;
use super::{finite_f64::FiniteF64, map::Map, map_key::MapKey}; use super::{finite_f64::FiniteF64, map::Map, map_key::MapKey};
@@ -73,22 +75,64 @@ impl From<Arbitrary> for IValue {
} }
#[cfg(feature = "pyo3")] #[cfg(feature = "pyo3")]
impl<'py> FromPyObject<'py> for Arbitrary { #[derive(Debug, Snafu)]
fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self> { pub enum ExtractArbitraryError {
/// error getting the qualified type name when trying to report
/// that an instance of this type cannot be extracted as an [`Arbitrary`]
GetTypeNameError { source: PyErr },
/// error extracting the (successfully retrieved) fully qualified type name as a [`String`]
ExtractTypeNameError { source: PyErr },
/// the float trying to be extracted is not finite, which isn't supported
FloatNotFinite { source: NotFinite },
/// can't extract an arbitrary from a {type_name}
UnsupportedType { type_name: String },
}
#[cfg(feature = "pyo3")]
impl From<ExtractArbitraryError> for PyErr {
fn from(error: ExtractArbitraryError) -> Self {
match &error {
ExtractArbitraryError::GetTypeNameError { .. } => {
PyException::new_err(error.to_string())
}
ExtractArbitraryError::ExtractTypeNameError { .. } => {
PyException::new_err(error.to_string())
}
ExtractArbitraryError::FloatNotFinite { .. } => {
PyValueError::new_err(error.to_string())
}
ExtractArbitraryError::UnsupportedType { .. } => {
PyTypeError::new_err(error.to_string())
}
}
}
}
#[cfg(feature = "pyo3")]
impl<'a, 'py> FromPyObject<'a, 'py> for Arbitrary {
type Error = ExtractArbitraryError;
fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result<Self, Self::Error> {
if let Ok(map_key) = ob.extract::<MapKey>() { if let Ok(map_key) = ob.extract::<MapKey>() {
Ok(map_key.into()) Ok(map_key.into())
} else if let Ok(map) = ob.extract() { } else if let Ok(map) = ob.extract() {
Ok(Self::Map(map)) Ok(Self::Map(map))
} else if let Ok(f) = ob.extract::<f64>() { } else if let Ok(f) = ob.extract::<f64>() {
let f = FiniteF64::try_from(f).map_err(|err| PyValueError::new_err(err.to_string()))?; let f = FiniteF64::try_from(f).context(FloatNotFiniteSnafu)?;
Ok(Self::Float(f)) Ok(Self::Float(f))
} else if let Ok(vec) = ob.extract() { } else if let Ok(vec) = ob.extract() {
Ok(Self::Array(vec)) Ok(Self::Array(vec))
} else { } else {
let type_name = ob.get_type().fully_qualified_name()?; let type_name = ob
Err(PyTypeError::new_err(format!( .get_type()
"can't extract an arbitrary from a {type_name}" .fully_qualified_name()
))) .context(GetTypeNameSnafu)?
.extract()
.context(ExtractTypeNameSnafu)?;
Err(ExtractArbitraryError::UnsupportedType { type_name })
} }
} }
} }

View File

@@ -10,6 +10,7 @@ use pyo3::{
prelude::*, prelude::*,
types::{PyNone, PyTuple}, types::{PyNone, PyTuple},
}; };
use snafu::{ResultExt, Snafu};
use super::arbitrary::{Arbitrary, MapKeyFromArbitraryError}; use super::arbitrary::{Arbitrary, MapKeyFromArbitraryError};
@@ -43,9 +44,40 @@ impl Display for MapKey {
} }
#[cfg(feature = "pyo3")] #[cfg(feature = "pyo3")]
impl<'py> FromPyObject<'py> for MapKey { #[derive(Debug, Snafu)]
fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self> { pub enum ExtractMapKeyError {
if let Ok(_none) = ob.downcast::<PyNone>() { /// error getting the qualified type name when trying to report
/// that an instance of this type cannot be extracted as an [`Arbitrary`]
GetTypeNameError { source: PyErr },
/// error extracting the (successfully retrieved) fully qualified type name as a [`String`]
ExtractTypeNameError { source: PyErr },
/// can't extract a map key from a {type_name}
UnsupportedType { type_name: String },
}
#[cfg(feature = "pyo3")]
impl From<ExtractMapKeyError> for PyErr {
fn from(error: ExtractMapKeyError) -> Self {
use pyo3::exceptions::PyException;
match &error {
ExtractMapKeyError::GetTypeNameError { .. } => PyException::new_err(error.to_string()),
ExtractMapKeyError::ExtractTypeNameError { .. } => {
PyException::new_err(error.to_string())
}
ExtractMapKeyError::UnsupportedType { .. } => PyTypeError::new_err(error.to_string()),
}
}
}
#[cfg(feature = "pyo3")]
impl<'a, 'py> FromPyObject<'a, 'py> for MapKey {
type Error = ExtractMapKeyError;
fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result<Self, Self::Error> {
if let Ok(_none) = ob.cast::<PyNone>() {
Ok(Self::Null) Ok(Self::Null)
} else if let Ok(b) = ob.extract() { } else if let Ok(b) = ob.extract() {
Ok(Self::Bool(b)) Ok(Self::Bool(b))
@@ -56,10 +88,13 @@ impl<'py> FromPyObject<'py> for MapKey {
} else if let Ok(tuple) = ob.extract() { } else if let Ok(tuple) = ob.extract() {
Ok(Self::Tuple(tuple)) Ok(Self::Tuple(tuple))
} else { } else {
let type_name = ob.get_type().fully_qualified_name()?; let type_name = ob
Err(PyTypeError::new_err(format!( .get_type()
"can't extract a map key from a {type_name}" .fully_qualified_name()
))) .context(GetTypeNameSnafu)?
.extract()
.context(ExtractTypeNameSnafu)?;
Err(ExtractMapKeyError::UnsupportedType { type_name })
} }
} }
} }