feat: FromPyFromStr and ToStrToPy macros YAY
This commit is contained in:
@@ -4,8 +4,11 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
license = { workspace = true }
|
||||
|
||||
[features]
|
||||
macros = ["dep:python-utils-macros"]
|
||||
|
||||
[dependencies]
|
||||
derive_more = { workspace = true }
|
||||
pyo3 = { workspace = true }
|
||||
python-utils-macros = { path = "../python-utils-macros" }
|
||||
python-utils-macros = { optional = true, path = "../python-utils-macros" }
|
||||
snafu = { workspace = true }
|
||||
|
||||
73
python-utils/src/from_pyobject_via_parse.rs
Normal file
73
python-utils/src/from_pyobject_via_parse.rs
Normal file
@@ -0,0 +1,73 @@
|
||||
use std::{
|
||||
fmt::{Debug, Display},
|
||||
str::FromStr,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use pyo3::{
|
||||
exceptions::{PyException, PyValueError},
|
||||
Borrowed, FromPyObject, PyAny, PyErr,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, derive_more::FromStr)]
|
||||
pub struct FromPyObjectViaParse<T>(pub T);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ExtractPyObjectViaParseError<ParseError> {
|
||||
/// couldn't extract the object as a string
|
||||
ExtractStringError { source: Arc<PyErr> },
|
||||
|
||||
/// couldn't parse the string as an instance of this Rust type
|
||||
ParseError { source: ParseError },
|
||||
}
|
||||
|
||||
impl<ParseError: Display> Display for ExtractPyObjectViaParseError<ParseError> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
ExtractPyObjectViaParseError::ExtractStringError { source } => write!(f, "{}", source),
|
||||
ExtractPyObjectViaParseError::ParseError { source } => write!(f, "{}", source),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<ParseError> std::error::Error for ExtractPyObjectViaParseError<ParseError> where
|
||||
ExtractPyObjectViaParseError<ParseError>: Debug + Display
|
||||
{
|
||||
}
|
||||
|
||||
impl<ParseError> From<ExtractPyObjectViaParseError<ParseError>> for PyErr
|
||||
where
|
||||
ExtractPyObjectViaParseError<ParseError>: Display,
|
||||
{
|
||||
fn from(error: ExtractPyObjectViaParseError<ParseError>) -> Self {
|
||||
match &error {
|
||||
ExtractPyObjectViaParseError::ExtractStringError { .. } => {
|
||||
PyException::new_err(error.to_string())
|
||||
}
|
||||
ExtractPyObjectViaParseError::ParseError { .. } => {
|
||||
PyValueError::new_err(error.to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'py, T> FromPyObject<'a, 'py> for FromPyObjectViaParse<T>
|
||||
where
|
||||
T: FromStr,
|
||||
PyErr: From<ExtractPyObjectViaParseError<<T as FromStr>::Err>>,
|
||||
{
|
||||
type Error = ExtractPyObjectViaParseError<<T as FromStr>::Err>;
|
||||
|
||||
fn extract(obj: Borrowed<'a, 'py, PyAny>) -> Result<Self, Self::Error> {
|
||||
let s = obj
|
||||
.extract::<&str>()
|
||||
.map_err(Arc::new)
|
||||
.map_err(|e| ExtractPyObjectViaParseError::ExtractStringError { source: e })?;
|
||||
|
||||
let t = s
|
||||
.parse()
|
||||
.map_err(|e| ExtractPyObjectViaParseError::ParseError { source: e })?;
|
||||
|
||||
Ok(FromPyObjectViaParse(t))
|
||||
}
|
||||
}
|
||||
20
python-utils/src/into_pyobject_via_display.rs
Normal file
20
python-utils/src/into_pyobject_via_display.rs
Normal file
@@ -0,0 +1,20 @@
|
||||
use std::{convert::Infallible, fmt::Display};
|
||||
|
||||
use pyo3::{types::PyString, Bound, IntoPyObject, Python};
|
||||
|
||||
#[derive(Debug, Clone, derive_more::Display)]
|
||||
pub struct IntoPyObjectViaDisplay<T>(pub T);
|
||||
|
||||
impl<'py, T> IntoPyObject<'py> for IntoPyObjectViaDisplay<T>
|
||||
where
|
||||
T: Display,
|
||||
{
|
||||
type Target = PyString;
|
||||
type Output = Bound<'py, Self::Target>;
|
||||
type Error = Infallible;
|
||||
|
||||
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
|
||||
let s = self.to_string();
|
||||
s.into_pyobject(py)
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,18 @@
|
||||
use std::{convert::Infallible, fmt::Display, str::FromStr, sync::Arc};
|
||||
|
||||
use pyo3::{
|
||||
exceptions::{PyException, PyTypeError, PyValueError},
|
||||
exceptions::{PyException, PyTypeError},
|
||||
prelude::*,
|
||||
types::PyString,
|
||||
};
|
||||
use snafu::{ResultExt, Snafu};
|
||||
|
||||
pub use python_utils_macros::PyFromStr;
|
||||
#[cfg(feature = "macros")]
|
||||
pub use python_utils_macros::{FromPyFromStr, ToStrToPy};
|
||||
|
||||
pub mod from_pyobject_via_parse;
|
||||
pub mod into_pyobject_via_display;
|
||||
pub mod none;
|
||||
|
||||
pub use from_pyobject_via_parse::{ExtractPyObjectViaParseError, FromPyObjectViaParse};
|
||||
pub use into_pyobject_via_display::IntoPyObjectViaDisplay;
|
||||
pub use none::IsNone;
|
||||
|
||||
/// Create a GIL-independent reference
|
||||
@@ -83,70 +86,3 @@ pub fn validate_type_by_name(
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, derive_more::Display)]
|
||||
pub struct IntoPyObjectViaDisplay<T>(pub T);
|
||||
|
||||
impl<'py, T> IntoPyObject<'py> for IntoPyObjectViaDisplay<T>
|
||||
where
|
||||
T: Display,
|
||||
{
|
||||
type Target = PyString;
|
||||
type Output = Bound<'py, Self::Target>;
|
||||
type Error = Infallible;
|
||||
|
||||
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
|
||||
let s = self.to_string();
|
||||
s.into_pyobject(py)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, derive_more::FromStr)]
|
||||
pub struct FromPyObjectViaParse<T>(pub T);
|
||||
|
||||
#[derive(Debug, Clone, Snafu)]
|
||||
pub enum ExtractPyObjectViaParseError<ParseError>
|
||||
where
|
||||
ParseError: 'static + snafu::Error,
|
||||
{
|
||||
/// couldn't extract the object as a string
|
||||
ExtractStringError { source: Arc<PyErr> },
|
||||
|
||||
/// couldn't parse the string as an instance of this Rust type
|
||||
ParseError { source: ParseError },
|
||||
}
|
||||
|
||||
impl<E> From<ExtractPyObjectViaParseError<E>> for PyErr
|
||||
where
|
||||
E: 'static + snafu::Error,
|
||||
{
|
||||
fn from(error: ExtractPyObjectViaParseError<E>) -> Self {
|
||||
match &error {
|
||||
ExtractPyObjectViaParseError::ExtractStringError { .. } => {
|
||||
PyException::new_err(error.to_string())
|
||||
}
|
||||
ExtractPyObjectViaParseError::ParseError { .. } => {
|
||||
PyValueError::new_err(error.to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'py, T> FromPyObject<'a, 'py> for FromPyObjectViaParse<T>
|
||||
where
|
||||
T: FromStr,
|
||||
<T as FromStr>::Err: 'static + snafu::Error,
|
||||
PyErr: From<ExtractPyObjectViaParseError<<T as FromStr>::Err>>,
|
||||
{
|
||||
type Error = ExtractPyObjectViaParseError<<T as FromStr>::Err>;
|
||||
|
||||
fn extract(obj: Borrowed<'a, 'py, PyAny>) -> Result<Self, Self::Error> {
|
||||
let s = obj
|
||||
.extract::<&str>()
|
||||
.map_err(Arc::new)
|
||||
.context(ExtractStringSnafu)?;
|
||||
let t = T::from_str(s).context(ParseSnafu)?;
|
||||
|
||||
Ok(FromPyObjectViaParse(t))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user