Skip to content

Commit

Permalink
remove uses of IntoPy (#1578)
Browse files Browse the repository at this point in the history
  • Loading branch information
davidhewitt authored Dec 17, 2024
1 parent bd91c18 commit 39435c2
Show file tree
Hide file tree
Showing 55 changed files with 405 additions and 411 deletions.
50 changes: 15 additions & 35 deletions src/argument_markers.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use pyo3::basic::CompareOp;
use pyo3::exceptions::PyNotImplementedError;
use pyo3::prelude::*;
use pyo3::sync::GILOnceCell;
Expand All @@ -13,45 +12,26 @@ pub struct ArgsKwargs {
pub(crate) kwargs: Option<Py<PyDict>>,
}

impl ArgsKwargs {
fn eq(&self, py: Python, other: &Self) -> PyResult<bool> {
if self.args.bind(py).eq(other.args.bind(py))? {
match (&self.kwargs, &other.kwargs) {
(Some(d1), Some(d2)) => d1.bind(py).eq(d2.bind(py)),
(None, None) => Ok(true),
_ => Ok(false),
}
} else {
Ok(false)
}
}
}

#[pymethods]
impl ArgsKwargs {
#[new]
#[pyo3(signature = (args, kwargs = None))]
fn py_new(py: Python, args: &Bound<'_, PyTuple>, kwargs: Option<&Bound<'_, PyDict>>) -> Self {
fn py_new(args: Bound<'_, PyTuple>, kwargs: Option<Bound<'_, PyDict>>) -> Self {
Self {
args: args.into_py(py),
kwargs: match kwargs {
Some(d) if !d.is_empty() => Some(d.to_owned().unbind()),
_ => None,
},
args: args.unbind(),
kwargs: kwargs.filter(|d| !d.is_empty()).map(Bound::unbind),
}
}

fn __richcmp__(&self, other: &Self, op: CompareOp, py: Python<'_>) -> PyObject {
match op {
CompareOp::Eq => match self.eq(py, other) {
Ok(b) => b.into_py(py),
Err(e) => e.into_py(py),
},
CompareOp::Ne => match self.eq(py, other) {
Ok(b) => (!b).into_py(py),
Err(e) => e.into_py(py),
},
_ => py.NotImplemented(),
fn __eq__(&self, py: Python, other: &Self) -> PyResult<bool> {
if !self.args.bind(py).eq(&other.args)? {
return Ok(false);
}

match (&self.kwargs, &other.kwargs) {
(Some(d1), Some(d2)) => d1.bind(py).eq(d2),
(None, None) => Ok(true),
_ => Ok(false),
}
}

Expand Down Expand Up @@ -82,16 +62,16 @@ impl PydanticUndefinedType {
#[staticmethod]
pub fn new(py: Python) -> Py<Self> {
UNDEFINED_CELL
.get_or_init(py, || PydanticUndefinedType {}.into_py(py).extract(py).unwrap())
.clone()
.get_or_init(py, || Py::new(py, PydanticUndefinedType {}).unwrap())
.clone_ref(py)
}

fn __repr__(&self) -> &'static str {
"PydanticUndefined"
}

fn __copy__(&self, py: Python) -> Py<Self> {
UNDEFINED_CELL.get(py).unwrap().clone()
UNDEFINED_CELL.get(py).unwrap().clone_ref(py)
}

#[pyo3(signature = (_memo, /))]
Expand Down
11 changes: 9 additions & 2 deletions src/build_tools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use pyo3::prelude::*;
use pyo3::types::{PyDict, PyList, PyString};
use pyo3::{intern, FromPyObject, PyErrArguments};

use crate::errors::ValError;
use crate::errors::{PyLineError, ValError};
use crate::input::InputType;
use crate::tools::SchemaDict;
use crate::ValidationError;
Expand Down Expand Up @@ -85,7 +85,14 @@ impl SchemaError {
pub fn from_val_error(py: Python, error: ValError) -> PyErr {
match error {
ValError::LineErrors(raw_errors) => {
let line_errors = raw_errors.into_iter().map(|e| e.into_py(py)).collect();
let line_errors = match raw_errors
.into_iter()
.map(|e| PyLineError::from_val_line_error(py, e))
.collect::<PyResult<_>>()
{
Ok(errors) => errors,
Err(err) => return err,
};
let validation_error =
ValidationError::new(line_errors, "Schema".to_object(py), InputType::Python, false);
let schema_error = SchemaError(SchemaErrorEnum::ValidationError(validation_error));
Expand Down
10 changes: 9 additions & 1 deletion src/errors/line_error.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::convert::Infallible;

use pyo3::exceptions::PyTypeError;
use pyo3::prelude::*;
use pyo3::DowncastError;
Expand Down Expand Up @@ -61,6 +63,12 @@ impl From<Vec<ValLineError>> for ValError {
}
}

impl From<Infallible> for ValError {
fn from(infallible: Infallible) -> Self {
match infallible {}
}
}

impl ValError {
pub fn new(error_type: ErrorType, input: impl ToErrorValue) -> ValError {
Self::LineErrors(vec![ValLineError::new(error_type, input)])
Expand Down Expand Up @@ -156,7 +164,7 @@ impl ValLineError {
}

#[cfg_attr(debug_assertions, derive(Debug))]
#[derive(Clone)]
#[derive(Clone, IntoPyObject)]
pub enum InputValue {
Python(PyObject),
Json(JsonValue<'static>),
Expand Down
2 changes: 1 addition & 1 deletion src/errors/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ mod value_exception;
pub use self::line_error::{InputValue, ToErrorValue, ValError, ValLineError, ValResult};
pub use self::location::LocItem;
pub use self::types::{list_all_errors, ErrorType, ErrorTypeDefaults, Number};
pub use self::validation_exception::ValidationError;
pub use self::validation_exception::{PyLineError, ValidationError};
pub use self::value_exception::{PydanticCustomError, PydanticKnownError, PydanticOmit, PydanticUseDefault};

pub fn py_err_string(py: Python, err: PyErr) -> String {
Expand Down
11 changes: 3 additions & 8 deletions src/errors/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ use std::borrow::Cow;
use std::fmt;

use pyo3::exceptions::{PyKeyError, PyTypeError};
use pyo3::prelude::*;
use pyo3::sync::GILOnceCell;
use pyo3::types::{PyDict, PyList};
use pyo3::{prelude::*, IntoPyObjectExt};

use ahash::AHashMap;
use num_bigint::BigInt;
Expand Down Expand Up @@ -766,7 +766,7 @@ impl ErrorType {
}
}

#[derive(Clone, Debug)]
#[derive(Clone, Debug, IntoPyObject, IntoPyObjectRef)]
pub enum Number {
Int(i64),
BigInt(BigInt),
Expand Down Expand Up @@ -826,11 +826,6 @@ impl fmt::Display for Number {
}
impl ToPyObject for Number {
fn to_object(&self, py: Python<'_>) -> PyObject {
match self {
Self::Int(i) => i.into_py(py),
Self::BigInt(i) => i.clone().into_py(py),
Self::Float(f) => f.into_py(py),
Self::String(s) => s.into_py(py),
}
self.into_py_any(py).unwrap()
}
}
80 changes: 45 additions & 35 deletions src/errors/validation_exception.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use pyo3::ffi::{self, c_str};
use pyo3::intern;
use pyo3::prelude::*;
use pyo3::sync::GILOnceCell;
use pyo3::types::{PyDict, PyList, PyString, PyType};
use pyo3::types::{PyDict, PyList, PyString, PyTuple, PyType};
use serde::ser::{Error, SerializeMap, SerializeSeq};
use serde::{Serialize, Serializer};

Expand Down Expand Up @@ -57,12 +57,19 @@ impl ValidationError {
) -> PyErr {
match error {
ValError::LineErrors(raw_errors) => {
let line_errors: Vec<PyLineError> = match outer_location {
let line_errors = match outer_location {
Some(outer_location) => raw_errors
.into_iter()
.map(|e| e.with_outer_location(outer_location.clone()).into_py(py))
.map(|e| PyLineError::from_val_line_error(py, e.with_outer_location(outer_location.clone())))
.collect(),
None => raw_errors
.into_iter()
.map(|e| PyLineError::from_val_line_error(py, e))
.collect(),
None => raw_errors.into_iter().map(|e| e.into_py(py)).collect(),
};
let line_errors = match line_errors {
Ok(errors) => errors,
Err(err) => return err,
};
let validation_error = Self::new(line_errors, title, input_type, hide_input);
match Py::new(py, validation_error) {
Expand Down Expand Up @@ -117,15 +124,17 @@ impl ValidationError {
context: _,
} = &line_error.error_type
{
let note: PyObject = if let Location::Empty = &line_error.location {
"Pydantic: cause of loc: root".into_py(py)
let note = if let Location::Empty = &line_error.location {
PyString::new(py, "Pydantic: cause of loc: root")
} else {
format!(
"Pydantic: cause of loc: {}",
// Location formats with a newline at the end, hence the trim()
line_error.location.to_string().trim()
PyString::new(
py,
&format!(
"Pydantic: cause of loc: {}",
// Location formats with a newline at the end, hence the trim()
line_error.location.to_string().trim()
),
)
.into_py(py)
};

// Notes only support 3.11 upwards:
Expand All @@ -144,7 +153,7 @@ impl ValidationError {
{
use pyo3::exceptions::PyUserWarning;

let wrapped = PyUserWarning::new_err((note,));
let wrapped = PyUserWarning::new_err((note.unbind(),));
wrapped.set_cause(py, Some(PyErr::from_value(err.clone_ref(py).into_bound(py))));
user_py_errs.push(wrapped);
}
Expand All @@ -159,7 +168,7 @@ impl ValidationError {
#[cfg(Py_3_11)]
let cause = {
use pyo3::exceptions::PyBaseExceptionGroup;
Some(PyBaseExceptionGroup::new_err((title, user_py_errs)).into_py(py))
Some(PyBaseExceptionGroup::new_err((title, user_py_errs)).into_value(py))
};

// Pre 3.11 ExceptionGroup support, use the python backport instead:
Expand All @@ -170,7 +179,7 @@ impl ValidationError {
match py.import("exceptiongroup") {
Ok(py_mod) => match py_mod.getattr("ExceptionGroup") {
Ok(group_cls) => match group_cls.call1((title, user_py_errs)) {
Ok(group_instance) => Some(group_instance.into_py(py)),
Ok(group_instance) => Some(group_instance),
Err(_) => None,
},
Err(_) => None,
Expand Down Expand Up @@ -308,10 +317,13 @@ impl ValidationError {
return py.None();
}
e.as_dict(py, url_prefix, include_context, self.input_type, include_input)
.unwrap_or_else(|err| {
iteration_error = Some(err);
py.None()
})
.map_or_else(
|err| {
iteration_error = Some(err);
py.None()
},
Into::into,
)
}),
)?;
if let Some(err) = iteration_error {
Expand Down Expand Up @@ -379,7 +391,7 @@ impl ValidationError {
self.__repr__(py)
}

fn __reduce__<'py>(slf: &Bound<'py, Self>) -> PyResult<(Bound<'py, PyAny>, PyObject)> {
fn __reduce__<'py>(slf: &Bound<'py, Self>) -> PyResult<(Bound<'py, PyAny>, Bound<'py, PyTuple>)> {
let py = slf.py();
let callable = slf.getattr("from_exception_data")?;
let borrow = slf.try_borrow()?;
Expand All @@ -389,7 +401,7 @@ impl ValidationError {
borrow.input_type.into_pyobject(py)?,
borrow.hide_input,
)
.into_py(slf.py());
.into_pyobject(slf.py())?;
Ok((callable, args))
}
}
Expand Down Expand Up @@ -418,16 +430,6 @@ pub struct PyLineError {
input_value: PyObject,
}

impl IntoPy<PyLineError> for ValLineError {
fn into_py(self, py: Python<'_>) -> PyLineError {
PyLineError {
error_type: self.error_type,
location: self.location,
input_value: self.input_value.to_object(py),
}
}
}

impl From<PyLineError> for ValLineError {
/// Used to extract line errors from a validation error for wrap functions
fn from(other: PyLineError) -> ValLineError {
Expand Down Expand Up @@ -464,7 +466,7 @@ impl TryFrom<&Bound<'_, PyAny>> for PyLineError {
let location = Location::try_from(dict.get_item("loc")?.as_ref())?;

let input_value = match dict.get_item("input")? {
Some(i) => i.into_py(py),
Some(i) => i.unbind(),
None => py.None(),
};

Expand All @@ -477,18 +479,26 @@ impl TryFrom<&Bound<'_, PyAny>> for PyLineError {
}

impl PyLineError {
pub fn from_val_line_error(py: Python, error: ValLineError) -> PyResult<Self> {
Ok(Self {
error_type: error.error_type,
location: error.location,
input_value: error.input_value.into_pyobject(py)?.unbind(),
})
}

fn get_error_url(&self, url_prefix: &str) -> String {
format!("{url_prefix}{}", self.error_type.type_string())
}

pub fn as_dict(
pub fn as_dict<'py>(
&self,
py: Python,
py: Python<'py>,
url_prefix: Option<&str>,
include_context: bool,
input_type: InputType,
include_input: bool,
) -> PyResult<PyObject> {
) -> PyResult<Bound<'py, PyDict>> {
let dict = PyDict::new(py);
dict.set_item("type", self.error_type.type_string())?;
dict.set_item("loc", self.location.to_object(py))?;
Expand All @@ -511,7 +521,7 @@ impl PyLineError {
}
}
}
Ok(dict.into_py(py))
Ok(dict)
}

fn pretty(
Expand Down
Loading

0 comments on commit 39435c2

Please sign in to comment.