diff --git a/Cargo.lock b/Cargo.lock index 20ca83a39..2427073b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -288,8 +288,7 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jiter" version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed1be5dfeadf968b30fa03a012a2f161de8be6df2d91bd8085c62cfb5efca65a" +source = "git+https://github.com/pydantic/jiter.git?branch=dh/pyo3-0.27#747950a735f0ae44f77cda4ea01f5c772ecea59e" dependencies = [ "ahash", "bitvec", @@ -458,8 +457,7 @@ dependencies = [ [[package]] name = "pyo3" version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ba0117f4212101ee6544044dae45abe1083d30ce7b29c4b5cbdfa2354e07383" +source = "git+https://github.com/pyo3/pyo3.git#da618c7c90b1f55c66c14353c9f014c9ae7c52df" dependencies = [ "indoc", "libc", @@ -476,8 +474,7 @@ dependencies = [ [[package]] name = "pyo3-build-config" version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fc6ddaf24947d12a9aa31ac65431fb1b851b8f4365426e182901eabfb87df5f" +source = "git+https://github.com/pyo3/pyo3.git#da618c7c90b1f55c66c14353c9f014c9ae7c52df" dependencies = [ "python3-dll-a", "target-lexicon", @@ -486,8 +483,7 @@ dependencies = [ [[package]] name = "pyo3-ffi" version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "025474d3928738efb38ac36d4744a74a400c901c7596199e20e45d98eb194105" +source = "git+https://github.com/pyo3/pyo3.git#da618c7c90b1f55c66c14353c9f014c9ae7c52df" dependencies = [ "libc", "pyo3-build-config", @@ -496,8 +492,7 @@ dependencies = [ [[package]] name = "pyo3-macros" version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e64eb489f22fe1c95911b77c44cc41e7c19f3082fc81cce90f657cdc42ffded" +source = "git+https://github.com/pyo3/pyo3.git#da618c7c90b1f55c66c14353c9f014c9ae7c52df" dependencies = [ "proc-macro2", "pyo3-macros-backend", @@ -508,8 +503,7 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "100246c0ecf400b475341b8455a9213344569af29a3c841d29270e53102e0fcf" +source = "git+https://github.com/pyo3/pyo3.git#da618c7c90b1f55c66c14353c9f014c9ae7c52df" dependencies = [ "heck", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index a2455c7aa..73936ab66 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -105,3 +105,8 @@ too_many_lines = "allow" unnecessary_wraps = "allow" unused_self = "allow" used_underscore_binding = "allow" + +[patch.crates-io] +pyo3 = { git = "https://github.com/pyo3/pyo3.git" } +pyo3-build-config = { git = "https://github.com/pyo3/pyo3.git" } +jiter = { git = "https://github.com/pydantic/jiter.git", branch = "dh/pyo3-0.27" } diff --git a/src/build_tools.rs b/src/build_tools.rs index 2abcbd9ca..a5fa284ed 100644 --- a/src/build_tools.rs +++ b/src/build_tools.rs @@ -5,7 +5,7 @@ use std::str::FromStr; use pyo3::exceptions::PyException; use pyo3::prelude::*; use pyo3::types::{PyDict, PyList, PyString}; -use pyo3::{intern, FromPyObject, PyErrArguments}; +use pyo3::{intern, PyErrArguments}; use crate::errors::{PyLineError, ValError}; use crate::input::InputType; @@ -19,7 +19,7 @@ pub fn schema_or_config<'py, T>( config_key: &Bound<'py, PyString>, ) -> PyResult> where - T: FromPyObject<'py>, + T: FromPyObjectOwned<'py>, { match schema.get_as(schema_key)? { Some(v) => Ok(Some(v)), @@ -36,7 +36,7 @@ pub fn schema_or_config_same<'py, T>( key: &Bound<'py, PyString>, ) -> PyResult> where - T: FromPyObject<'py>, + T: FromPyObjectOwned<'py>, { schema_or_config(schema, config, key, key) } diff --git a/src/errors/types.rs b/src/errors/types.rs index 3dc18565a..fde9164cd 100644 --- a/src/errors/types.rs +++ b/src/errors/types.rs @@ -42,7 +42,7 @@ pub fn list_all_errors(py: Python<'_>) -> PyResult> { PyList::new(py, errors) } -fn field_from_context<'py, T: FromPyObject<'py>>( +fn field_from_context<'py, T: FromPyObjectOwned<'py>>( context: Option<&Bound<'py, PyDict>>, field_name: &str, enum_name: &str, @@ -56,7 +56,7 @@ fn field_from_context<'py, T: FromPyObject<'py>>( .map_err(|_| py_error_type!(PyTypeError; "{}: '{}' context value must be a {}", enum_name, field_name, type_name_fn())) } -fn cow_field_from_context<'py, T: FromPyObject<'py>, B: ToOwned + ?Sized + 'static>( +fn cow_field_from_context<'py, T: FromPyObjectOwned<'py>, B: ToOwned + ?Sized + 'static>( context: Option<&Bound<'py, PyDict>>, field_name: &str, enum_name: &str, @@ -805,9 +805,11 @@ impl From for Number { } } -impl FromPyObject<'_> for Number { - fn extract_bound(obj: &Bound<'_, PyAny>) -> PyResult { - if let Some(int) = extract_i64(obj) { +impl FromPyObject<'_, '_> for Number { + type Error = PyErr; + + fn extract(obj: Borrowed<'_, '_, PyAny>) -> PyResult { + if let Some(int) = extract_i64(&obj) { Ok(Number::Int(int)) } else if let Ok(float) = obj.extract::() { Ok(Number::Float(float)) diff --git a/src/input/return_enums.rs b/src/input/return_enums.rs index 526d2c970..6a22c2286 100644 --- a/src/input/return_enums.rs +++ b/src/input/return_enums.rs @@ -706,9 +706,11 @@ impl Rem for &Int { } } -impl FromPyObject<'_> for Int { - fn extract_bound(obj: &Bound<'_, PyAny>) -> PyResult { - match extract_int(obj) { +impl FromPyObject<'_, '_> for Int { + type Error = PyErr; + + fn extract(obj: Borrowed<'_, '_, PyAny>) -> PyResult { + match extract_int(&obj) { Some(i) => Ok(i), None => py_err!(PyTypeError; "Expected int, got {}", obj.get_type()), } diff --git a/src/serializers/config.rs b/src/serializers/config.rs index 0779e2964..7bccd12d6 100644 --- a/src/serializers/config.rs +++ b/src/serializers/config.rs @@ -347,8 +347,9 @@ pub fn utf8_py_error(py: Python, err: Utf8Error, data: &[u8]) -> PyErr { } } -impl FromPyObject<'_> for InfNanMode { - fn extract_bound(ob: &Bound<'_, PyAny>) -> PyResult { +impl FromPyObject<'_, '_> for InfNanMode { + type Error = PyErr; + fn extract(ob: Borrowed<'_, '_, PyAny>) -> PyResult { Self::from_str(ob.downcast::()?.to_str()?) } } diff --git a/src/serializers/extra.rs b/src/serializers/extra.rs index 2b4b07b2d..7198ef303 100644 --- a/src/serializers/extra.rs +++ b/src/serializers/extra.rs @@ -316,8 +316,10 @@ pub enum WarningsMode { Error, } -impl<'py> FromPyObject<'py> for WarningsMode { - fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { +impl<'py> FromPyObject<'_, 'py> for WarningsMode { + type Error = PyErr; + + fn extract(ob: Borrowed<'_, 'py, PyAny>) -> PyResult { if let Ok(bool_mode) = ob.downcast::() { Ok(bool_mode.is_true().into()) } else if let Ok(str_mode) = ob.extract::<&str>() { diff --git a/src/tools.rs b/src/tools.rs index edf9b6bac..b49fe0158 100644 --- a/src/tools.rs +++ b/src/tools.rs @@ -3,9 +3,9 @@ use core::fmt; use num_bigint::BigInt; use pyo3::exceptions::PyKeyError; +use pyo3::intern; use pyo3::prelude::*; use pyo3::types::{PyDict, PyString}; -use pyo3::{intern, FromPyObject}; use crate::input::Int; use jiter::{cached_py_string, StringCacheMode}; @@ -13,30 +13,30 @@ use jiter::{cached_py_string, StringCacheMode}; pub trait SchemaDict<'py> { fn get_as(&self, key: &Bound<'py, PyString>) -> PyResult> where - T: FromPyObject<'py>; + T: FromPyObjectOwned<'py>; fn get_as_req(&self, key: &Bound<'py, PyString>) -> PyResult where - T: FromPyObject<'py>; + T: FromPyObjectOwned<'py>; } impl<'py> SchemaDict<'py> for Bound<'py, PyDict> { fn get_as(&self, key: &Bound<'py, PyString>) -> PyResult> where - T: FromPyObject<'py>, + T: FromPyObjectOwned<'py>, { match self.get_item(key)? { - Some(t) => t.extract().map(Some), + Some(t) => t.extract().map_err(Into::into).map(Some), None => Ok(None), } } fn get_as_req(&self, key: &Bound<'py, PyString>) -> PyResult where - T: FromPyObject<'py>, + T: FromPyObjectOwned<'py>, { match self.get_item(key)? { - Some(t) => t.extract(), + Some(t) => t.extract().map_err(Into::into), None => py_err!(PyKeyError; "{}", key), } } @@ -45,7 +45,7 @@ impl<'py> SchemaDict<'py> for Bound<'py, PyDict> { impl<'py> SchemaDict<'py> for Option<&Bound<'py, PyDict>> { fn get_as(&self, key: &Bound<'py, PyString>) -> PyResult> where - T: FromPyObject<'py>, + T: FromPyObjectOwned<'py>, { match self { Some(d) => d.get_as(key), @@ -56,7 +56,7 @@ impl<'py> SchemaDict<'py> for Option<&Bound<'py, PyDict>> { #[cfg_attr(has_coverage_attribute, coverage(off))] fn get_as_req(&self, key: &Bound<'py, PyString>) -> PyResult where - T: FromPyObject<'py>, + T: FromPyObjectOwned<'py>, { match self { Some(d) => d.get_as_req(key), diff --git a/src/url.rs b/src/url.rs index c7d484411..b5e0ea796 100644 --- a/src/url.rs +++ b/src/url.rs @@ -46,7 +46,7 @@ impl PyUrl { let schema_obj = SCHEMA_DEFINITION_URL .get_or_init(py, || build_schema_validator(py, "url")) .validate_python(py, url, None, None, None, None, None, false.into(), None, None)?; - schema_obj.extract(py) + schema_obj.extract(py).map_err(Into::into) } #[getter] @@ -226,7 +226,7 @@ impl PyMultiHostUrl { let schema_obj = SCHEMA_DEFINITION_MULTI_HOST_URL .get_or_init(py, || build_schema_validator(py, "multi-host-url")) .validate_python(py, url, None, None, None, None, None, false.into(), None, None)?; - schema_obj.extract(py) + schema_obj.extract(py).map_err(Into::into) } #[getter] @@ -436,8 +436,10 @@ impl UrlHostParts { } } -impl FromPyObject<'_> for UrlHostParts { - fn extract_bound(ob: &Bound<'_, PyAny>) -> PyResult { +impl FromPyObject<'_, '_> for UrlHostParts { + type Error = PyErr; + + fn extract(ob: Borrowed<'_, '_, PyAny>) -> PyResult { let py = ob.py(); let dict = ob.downcast::()?; Ok(UrlHostParts { diff --git a/src/validators/uuid.rs b/src/validators/uuid.rs index 03ff27864..fe230244d 100644 --- a/src/validators/uuid.rs +++ b/src/validators/uuid.rs @@ -26,14 +26,8 @@ const UUID_IS_SAFE: &str = "is_safe"; static UUID_TYPE: PyOnceLock> = PyOnceLock::new(); -fn import_type(py: Python, module: &str, attr: &str) -> PyResult> { - py.import(module)?.getattr(attr)?.extract() -} - fn get_uuid_type(py: Python<'_>) -> PyResult<&Bound<'_, PyType>> { - Ok(UUID_TYPE - .get_or_init(py, || import_type(py, "uuid", "UUID").unwrap()) - .bind(py)) + UUID_TYPE.import(py, "uuid", "UUID") } #[derive(Debug, Clone, Copy)]