90 lines
3.1 KiB
Rust
90 lines
3.1 KiB
Rust
use pyo3::{
|
|
exceptions::{PyException, PyTypeError},
|
|
types::{PyAnyMethods as _, PyStringMethods, PyTypeMethods as _},
|
|
Borrowed, Bound, Py, PyAny, PyErr,
|
|
};
|
|
use snafu::{ResultExt, Snafu};
|
|
|
|
#[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
|
|
pub fn detach<T>(borrowed: Borrowed<'_, '_, T>) -> Py<T> {
|
|
let py = borrowed.py();
|
|
borrowed.as_unbound().clone_ref(py)
|
|
}
|
|
/// Create a GIL-independent reference
|
|
pub fn detach_bound<T>(bound: &Bound<T>) -> Py<T> {
|
|
detach(bound.as_borrowed())
|
|
}
|
|
|
|
#[derive(Debug, Snafu)]
|
|
pub enum TypeByNameValidationError {
|
|
/// error getting the type name of this object
|
|
GetTypeNameError { source: PyErr },
|
|
/// error extracting the (successfully retrieved) type name as an [`&str`]
|
|
ExtractTypeNameError { source: PyErr },
|
|
|
|
/// error getting the fully qualified type name of this object
|
|
GetFullyQualifiedTypeNameError { source: PyErr },
|
|
/// error extracting the (successfully retrieved) fully qualified type name as an [`&str`]
|
|
ExtractFullyQualifiedTypeNameError { source: PyErr },
|
|
|
|
/// expected an instance of {expected} but got an instance of {actual}
|
|
UnexpectedType { expected: String, actual: String },
|
|
}
|
|
|
|
impl From<TypeByNameValidationError> for PyErr {
|
|
fn from(error: TypeByNameValidationError) -> Self {
|
|
match &error {
|
|
TypeByNameValidationError::GetTypeNameError { .. } => {
|
|
PyException::new_err(error.to_string())
|
|
}
|
|
TypeByNameValidationError::ExtractTypeNameError { .. } => {
|
|
PyException::new_err(error.to_string())
|
|
}
|
|
TypeByNameValidationError::GetFullyQualifiedTypeNameError { .. } => {
|
|
PyException::new_err(error.to_string())
|
|
}
|
|
TypeByNameValidationError::ExtractFullyQualifiedTypeNameError { .. } => {
|
|
PyException::new_err(error.to_string())
|
|
}
|
|
TypeByNameValidationError::UnexpectedType { .. } => {
|
|
PyTypeError::new_err(error.to_string())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn validate_type_by_name(
|
|
bound: &Bound<PyAny>,
|
|
expected_type_name: &str,
|
|
) -> Result<(), TypeByNameValidationError> {
|
|
let py_type = bound.get_type();
|
|
let type_name = py_type.name().context(GetTypeNameSnafu)?;
|
|
let type_name = type_name.to_str().context(ExtractTypeNameSnafu)?;
|
|
|
|
if type_name != expected_type_name {
|
|
let fully_qualified_type_name = py_type
|
|
.fully_qualified_name()
|
|
.context(GetFullyQualifiedTypeNameSnafu)?;
|
|
let fully_qualified_type_name = fully_qualified_type_name
|
|
.to_str()
|
|
.context(ExtractFullyQualifiedTypeNameSnafu)?;
|
|
return Err(TypeByNameValidationError::UnexpectedType {
|
|
expected: expected_type_name.to_owned(),
|
|
actual: fully_qualified_type_name.to_owned(),
|
|
});
|
|
}
|
|
|
|
Ok(())
|
|
}
|