Skip to content

Commit

Permalink
resolve remaining deprecation warnings from PyO3 0.23 (#1584)
Browse files Browse the repository at this point in the history
  • Loading branch information
davidhewitt authored Jan 23, 2025
1 parent 261c7ab commit 8758528
Show file tree
Hide file tree
Showing 42 changed files with 214 additions and 230 deletions.
8 changes: 6 additions & 2 deletions src/build_tools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,12 @@ impl SchemaError {
Ok(errors) => errors,
Err(err) => return err,
};
let validation_error =
ValidationError::new(line_errors, "Schema".to_object(py), InputType::Python, false);
let validation_error = ValidationError::new(
line_errors,
PyString::new(py, "Schema").into(),
InputType::Python,
false,
);
let schema_error = SchemaError(SchemaErrorEnum::ValidationError(validation_error));
match Py::new(py, schema_error) {
Ok(err) => PyErr::from_value(err.into_bound(py).into_any()),
Expand Down
2 changes: 1 addition & 1 deletion src/common/union.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub enum Discriminator {
impl Discriminator {
pub fn new(py: Python, raw: &Bound<'_, PyAny>) -> PyResult<Self> {
if raw.is_callable() {
return Ok(Self::Function(raw.to_object(py)));
return Ok(Self::Function(raw.clone().unbind()));
}

let lookup_key = LookupKey::from_py(py, raw, None)?;
Expand Down
9 changes: 0 additions & 9 deletions src/errors/line_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,12 +169,3 @@ pub enum InputValue {
Python(PyObject),
Json(JsonValue<'static>),
}

impl ToPyObject for InputValue {
fn to_object(&self, py: Python) -> PyObject {
match self {
Self::Python(input) => input.clone_ref(py),
Self::Json(input) => input.to_object(py),
}
}
}
28 changes: 12 additions & 16 deletions src/errors/location.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,6 @@ impl From<PathItem> for LocItem {
}
}

impl ToPyObject for LocItem {
fn to_object(&self, py: Python<'_>) -> PyObject {
match self {
Self::S(val) => val.to_object(py),
Self::I(val) => val.to_object(py),
}
}
}

impl Serialize for LocItem {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
Expand Down Expand Up @@ -128,15 +119,20 @@ impl Default for Location {
}
}

static EMPTY_TUPLE: GILOnceCell<PyObject> = GILOnceCell::new();
static EMPTY_TUPLE: GILOnceCell<Py<PyTuple>> = GILOnceCell::new();

impl<'py> IntoPyObject<'py> for &'_ Location {
type Target = PyTuple;
type Output = Bound<'py, PyTuple>;
type Error = PyErr;

impl ToPyObject for Location {
fn to_object(&self, py: Python<'_>) -> PyObject {
fn into_pyobject(self, py: Python<'py>) -> PyResult<Bound<'py, PyTuple>> {
match self {
Self::List(loc) => PyTuple::new(py, loc.iter().rev()).unwrap().to_object(py),
Self::Empty => EMPTY_TUPLE
.get_or_init(py, || PyTuple::empty(py).to_object(py))
.clone_ref(py),
Location::List(loc) => PyTuple::new(py, loc.iter().rev()),
Location::Empty => Ok(EMPTY_TUPLE
.get_or_init(py, || PyTuple::empty(py).unbind())
.bind(py)
.clone()),
}
}
}
Expand Down
9 changes: 2 additions & 7 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 @@ -124,7 +124,7 @@ macro_rules! error_types {
$(
Self::$item { context, $($key,)* } => {
$(
dict.set_item::<&str, Py<PyAny>>(stringify!($key), $key.to_object(py))?;
dict.set_item(stringify!($key), $key)?;
)*
if let Some(ctx) = context {
dict.update(ctx.bind(py).downcast::<PyMapping>()?)?;
Expand Down Expand Up @@ -824,8 +824,3 @@ impl fmt::Display for Number {
}
}
}
impl ToPyObject for Number {
fn to_object(&self, py: Python<'_>) -> PyObject {
self.into_py_any(py).unwrap()
}
}
34 changes: 16 additions & 18 deletions src/errors/validation_exception.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::borrow::Cow;
use std::fmt;
use std::fmt::{Display, Write};
use std::str::from_utf8;
Expand Down Expand Up @@ -72,15 +73,15 @@ impl ValidationError {
Err(err) => return err,
};
let validation_error = Self::new(line_errors, title, input_type, hide_input);
match Py::new(py, validation_error) {
match Bound::new(py, validation_error) {
Ok(err) => {
if validation_error_cause {
// Will return an import error if the backport was needed and not installed:
if let Some(cause_problem) = ValidationError::maybe_add_cause(err.borrow(py), py) {
if let Some(cause_problem) = ValidationError::maybe_add_cause(err.borrow(), py) {
return cause_problem;
}
}
PyErr::from_value(err.into_bound(py).into_any())
PyErr::from_value(err.into_any())
}
Err(err) => err,
}
Expand Down Expand Up @@ -125,16 +126,13 @@ impl ValidationError {
} = &line_error.error_type
{
let note = if let Location::Empty = &line_error.location {
PyString::new(py, "Pydantic: cause of loc: root")
Cow::Borrowed("Pydantic: cause of loc: root")
} else {
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()
),
)
Cow::Owned(format!(
"Pydantic: cause of loc: {}",
// Location formats with a newline at the end, hence the trim()
line_error.location.to_string().trim()
))
};

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

let wrapped = PyUserWarning::new_err((note.unbind(),));
let wrapped = PyUserWarning::new_err((note,));
wrapped.set_cause(py, Some(PyErr::from_value(err.clone_ref(py).into_bound(py))));
user_py_errs.push(wrapped);
}
Expand Down Expand Up @@ -329,7 +327,7 @@ impl ValidationError {
if let Some(err) = iteration_error {
Err(err)
} else {
Ok(list.into())
Ok(list.unbind())
}
}

Expand Down Expand Up @@ -396,12 +394,12 @@ impl ValidationError {
let callable = slf.getattr("from_exception_data")?;
let borrow = slf.try_borrow()?;
let args = (
borrow.title.bind(py),
&borrow.title,
borrow.errors(py, include_url_env(py), true, true)?,
borrow.input_type.into_pyobject(py)?,
borrow.input_type,
borrow.hide_input,
)
.into_pyobject(slf.py())?;
.into_pyobject(py)?;
Ok((callable, args))
}
}
Expand Down Expand Up @@ -501,7 +499,7 @@ impl PyLineError {
) -> 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))?;
dict.set_item("loc", &self.location)?;
dict.set_item("msg", self.error_type.render_message(py, input_type)?)?;
if include_input {
dict.set_item("input", &self.input_value)?;
Expand Down
28 changes: 18 additions & 10 deletions src/input/input_abstract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::fmt;

use pyo3::exceptions::PyValueError;
use pyo3::types::{PyDict, PyList, PyString};
use pyo3::{intern, prelude::*};
use pyo3::{intern, prelude::*, IntoPyObjectExt};

use crate::errors::{ErrorTypeDefaults, InputValue, LocItem, ValError, ValResult};
use crate::lookup_key::{LookupKey, LookupPath};
Expand All @@ -23,15 +23,16 @@ pub enum InputType {

impl<'py> IntoPyObject<'py> for InputType {
type Target = PyString;
type Output = Bound<'py, PyString>;
type Output = Borrowed<'py, 'py, PyString>;
type Error = Infallible;

fn into_pyobject(self, py: Python<'_>) -> Result<Bound<'_, PyString>, Infallible> {
Ok(match self {
Self::Json => intern!(py, "json").clone(),
Self::Python => intern!(py, "python").clone(),
Self::String => intern!(py, "string").clone(),
})
fn into_pyobject(self, py: Python<'py>) -> Result<Borrowed<'py, 'py, PyString>, Infallible> {
let text = match self {
Self::Json => intern!(py, "json"),
Self::Python => intern!(py, "python"),
Self::String => intern!(py, "string"),
};
Ok(text.as_borrowed())
}
}

Expand All @@ -54,7 +55,14 @@ pub type ValMatch<T> = ValResult<ValidationMatch<T>>;
/// the convention is to either implement:
/// * `strict_*` & `lax_*` if they have different behavior
/// * or, `validate_*` and `strict_*` to just call `validate_*` if the behavior for strict and lax is the same
pub trait Input<'py>: fmt::Debug + ToPyObject {
pub trait Input<'py>: fmt::Debug {
fn py_converter(&self) -> impl IntoPyObject<'py> + '_;

#[inline]
fn to_object<'a>(&'a self, py: Python<'py>) -> PyResult<Bound<'py, PyAny>> {
self.py_converter().into_bound_py_any(py)
}

fn as_error_value(&self) -> InputValue;

fn is_none(&self) -> bool {
Expand Down Expand Up @@ -208,7 +216,7 @@ pub trait KeywordArgs<'py> {
type Key<'a>: BorrowInput<'py> + Clone + Into<LocItem>
where
Self: 'a;
type Item<'a>: BorrowInput<'py> + ToPyObject
type Item<'a>: BorrowInput<'py>
where
Self: 'a;
fn len(&self) -> usize;
Expand Down
18 changes: 14 additions & 4 deletions src/input/input_json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ impl From<JsonValue<'_>> for LocItem {
}

impl<'py, 'data> Input<'py> for JsonValue<'data> {
#[inline]
fn py_converter(&self) -> impl IntoPyObject<'py> + '_ {
self
}

fn as_error_value(&self) -> InputValue {
// cloning JsonValue is cheap due to use of Arc
InputValue::Json(self.to_static())
Expand All @@ -58,7 +63,7 @@ impl<'py, 'data> Input<'py> for JsonValue<'data> {
JsonValue::Object(object) => {
let dict = PyDict::new(py);
for (k, v) in LazyIndexMap::iter(object) {
dict.set_item(k, v.to_object(py)).unwrap();
dict.set_item(k, v).unwrap();
}
Some(dict)
}
Expand Down Expand Up @@ -174,7 +179,7 @@ impl<'py, 'data> Input<'py> for JsonValue<'data> {
create_decimal(&PyString::new(py, &f.to_string()), self).map(ValidationMatch::strict)
}
JsonValue::Str(..) | JsonValue::Int(..) | JsonValue::BigInt(..) => {
create_decimal(self.to_object(py).bind(py), self).map(ValidationMatch::strict)
create_decimal(&self.into_pyobject(py)?, self).map(ValidationMatch::strict)
}
_ => Err(ValError::new(ErrorTypeDefaults::DecimalType, self)),
}
Expand Down Expand Up @@ -348,6 +353,11 @@ impl<'py, 'data> Input<'py> for JsonValue<'data> {

/// Required for JSON Object keys so the string can behave like an Input
impl<'py> Input<'py> for str {
#[inline]
fn py_converter(&self) -> impl IntoPyObject<'py> + '_ {
self
}

fn as_error_value(&self) -> InputValue {
// Justification for the clone: this is on the error pathway and we are generally ok
// with errors having a performance penalty
Expand Down Expand Up @@ -414,7 +424,7 @@ impl<'py> Input<'py> for str {
}

fn validate_decimal(&self, _strict: bool, py: Python<'py>) -> ValMatch<Bound<'py, PyAny>> {
create_decimal(self.to_object(py).bind(py), self).map(ValidationMatch::lax)
create_decimal(self.into_pyobject(py)?.as_any(), self).map(ValidationMatch::lax)
}

type Dict<'a> = Never;
Expand Down Expand Up @@ -483,7 +493,7 @@ impl<'py> Input<'py> for str {

fn validate_complex(&self, _strict: bool, py: Python<'py>) -> ValResult<ValidationMatch<EitherComplex<'py>>> {
Ok(ValidationMatch::strict(EitherComplex::Py(string_to_complex(
self.to_object(py).downcast_bound::<PyString>(py)?,
&self.into_pyobject(py)?,
self,
)?)))
}
Expand Down
13 changes: 9 additions & 4 deletions src/input/input_python.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ impl From<Bound<'_, PyAny>> for LocItem {
}

impl<'py> Input<'py> for Bound<'py, PyAny> {
#[inline]
fn py_converter(&self) -> impl IntoPyObject<'py> + '_ {
self
}

fn as_error_value(&self) -> InputValue {
InputValue::Python(self.clone().into())
}
Expand Down Expand Up @@ -472,7 +477,7 @@ impl<'py> Input<'py> for Bound<'py, PyAny> {
}

fn validate_iter(&self) -> ValResult<GenericIterator<'static>> {
if self.iter().is_ok() {
if self.try_iter().is_ok() {
Ok(self.into())
} else {
Err(ValError::new(ErrorTypeDefaults::IterableType, self))
Expand Down Expand Up @@ -851,7 +856,7 @@ impl<'py> ValidatedDict<'py> for GenericPyMapping<'_, 'py> {
Self::Mapping(mapping) => mapping
.call_method0(intern!(mapping.py(), "keys"))
.ok()?
.iter()
.try_iter()
.ok()?
.last()?
.ok(),
Expand Down Expand Up @@ -891,7 +896,7 @@ fn extract_sequence_iterable<'a, 'py>(obj: &'a Bound<'py, PyAny>) -> ValResult<P
|| obj.is_instance_of::<PyDict>()
|| obj.downcast::<PyMapping>().is_ok())
{
if let Ok(iter) = obj.iter() {
if let Ok(iter) = obj.try_iter() {
return Ok(PySequenceIterable::Iterator(iter));
}
}
Expand Down Expand Up @@ -920,7 +925,7 @@ impl<'py> PySequenceIterable<'_, 'py> {
PySequenceIterable::Tuple(iter) => Ok(consumer.consume_iterator(iter.iter().map(Ok))),
PySequenceIterable::Set(iter) => Ok(consumer.consume_iterator(iter.iter().map(Ok))),
PySequenceIterable::FrozenSet(iter) => Ok(consumer.consume_iterator(iter.iter().map(Ok))),
PySequenceIterable::Iterator(iter) => Ok(consumer.consume_iterator(iter.iter()?)),
PySequenceIterable::Iterator(iter) => Ok(consumer.consume_iterator(iter.try_iter()?)),
}
}
}
Expand Down
Loading

0 comments on commit 8758528

Please sign in to comment.