File vortex.diff of Package mingw-python-pydantic-core

diff --git a/Cargo.toml b/Cargo.toml
index a7e86ab..01586c4 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -27,7 +27,7 @@ rust-version = "1.75"
 [dependencies]
 # TODO it would be very nice to remove the "py-clone" feature as it can panic,
 # but needs a bit of work to make sure it's not used in the codebase
-pyo3 = { version = "0.26", features = ["generate-import-lib", "num-bigint", "py-clone"] }
+pyo3 = { version = "0.27", features = ["generate-import-lib", "num-bigint", "py-clone"] }
 regex = "1.12.2"
 strum = { version = "0.27", features = ["derive"] }
 strum_macros = "0.27"
@@ -44,7 +44,7 @@ base64 = "0.22.1"
 num-bigint = "0.4.6"
 num-traits = "0.2.19"
 uuid = "1.18.1"
-jiter = { version = "0.11.1", features = ["python"] }
+jiter = { version = "0.12.0", features = ["python"] }
 hex = "0.4.3"
 percent-encoding = "2.3.2"
 
@@ -69,12 +69,12 @@ debug = true
 strip = false
 
 [dev-dependencies]
-pyo3 = { version = "0.26", features = ["auto-initialize"] }
+pyo3 = { version = "0.27", features = ["auto-initialize"] }
 
 [build-dependencies]
 version_check = "0.9.5"
 # used where logic has to be version/distribution specific, e.g. pypy
-pyo3-build-config = { version = "0.26" }
+pyo3-build-config = { version = "0.27" }
 
 [lints.clippy]
 dbg_macro = "warn"
diff --git a/src/build_tools.rs b/src/build_tools.rs
index 2ccb827..1644c2b 100644
--- a/src/build_tools.rs
+++ b/src/build_tools.rs
@@ -14,6 +14,7 @@ use crate::input::InputType;
 use crate::tools::SchemaDict;
 use crate::ValidationError;
 
+/*
 pub fn schema_or_config<'py, T>(
     schema: &Bound<'py, PyDict>,
     config: Option<&Bound<'py, PyDict>>,
@@ -31,7 +32,28 @@ where
         },
     }
 }
+*/
 
+pub fn schema_or_config<'py, T>(
+    schema: &Bound<'py, PyDict>,
+    config: Option<&Bound<'py, PyDict>>,
+    schema_key: &Bound<'py, PyString>,
+    config_key: &Bound<'py, PyString>,
+) -> PyResult<Option<T>>
+where
+    T: for<'a> FromPyObject<'a, 'py>,
+    for<'a> <T as FromPyObject<'a, 'py>>::Error: Into<PyErr>,
+{
+    match schema.get_as(schema_key)? {
+        Some(v) => Ok(Some(v)),
+        None => match config {
+            Some(config) => config.get_as(config_key),
+            None => Ok(None),
+        },
+    }
+}
+
+/*
 pub fn schema_or_config_same<'py, T>(
     schema: &Bound<'py, PyDict>,
     config: Option<&Bound<'py, PyDict>>,
@@ -42,6 +64,20 @@ where
 {
     schema_or_config(schema, config, key, key)
 }
+*/
+
+pub fn schema_or_config_same<'py, T>(
+    schema: &Bound<'py, PyDict>,
+    config: Option<&Bound<'py, PyDict>>,
+    key: &Bound<'py, PyString>,
+) -> PyResult<Option<T>>
+where
+    T: for<'a> FromPyObject<'a, 'py>,
+    for<'a> <T as FromPyObject<'a, 'py>>::Error: Into<PyErr>,
+{
+    schema_or_config(schema, config, key, key)
+}
+
 
 pub fn is_strict(schema: &Bound<'_, PyDict>, config: Option<&Bound<'_, PyDict>>) -> PyResult<bool> {
     let py = schema.py();
@@ -185,6 +221,7 @@ pub enum ExtraBehavior {
     Ignore,
 }
 
+/*
 impl ExtraBehavior {
     pub fn from_schema_or_config(
         py: Python,
@@ -206,6 +243,29 @@ impl ExtraBehavior {
         Ok(res)
     }
 }
+*/
+
+impl ExtraBehavior {
+    pub fn from_schema_or_config<'py>(
+        py: Python<'py>,
+        schema: &Bound<'py, PyDict>,
+        config: Option<&Bound<'py, PyDict>>,
+        default: Self,
+    ) -> PyResult<Self> {
+        let extra_behavior: Option<String> = schema_or_config(
+            schema,
+            config,
+            intern!(py, "extra_behavior"),
+            intern!(py, "extra_fields_behavior"),
+        )?;
+
+        Ok(match extra_behavior.as_deref() {
+            Some(s) => Self::from_str(s)?,
+            None => default,
+        })
+    }
+}
+
 
 impl FromStr for ExtraBehavior {
     type Err = PyErr;
diff --git a/src/common/prebuilt.rs b/src/common/prebuilt.rs
index e66e2c3..141c7c8 100644
--- a/src/common/prebuilt.rs
+++ b/src/common/prebuilt.rs
@@ -1,9 +1,10 @@
 use pyo3::intern;
+use pyo3::exceptions::PyKeyError;
 use pyo3::prelude::*;
 use pyo3::types::{PyAny, PyDict, PyType};
 
-use crate::tools::SchemaDict;
 
+/*
 pub fn get_prebuilt<T>(
     type_: &str,
     schema: &Bound<'_, PyDict>,
@@ -42,3 +43,47 @@ pub fn get_prebuilt<T>(
     let prebuilt: Bound<'_, PyAny> = class_dict.get_item(prebuilt_attr_name)?;
     extractor(prebuilt)
 }
+*/
+
+pub fn get_prebuilt<'py, T>(
+    type_: &str,
+    schema: &Bound<'py, PyDict>,
+    prebuilt_attr_name: &str,
+    extractor: impl FnOnce(Bound<'py, PyAny>) -> PyResult<Option<T>>,
+) -> PyResult<Option<T>> {
+    let py = schema.py();
+
+    // we can only use prebuilt validators/serializers from models and Pydantic dataclasses.
+    // However, we don't want to use a prebuilt structure from dataclasses if we have a `generic_origin`
+    // as this means the dataclass was parametrized (so a generic alias instance), and `cls` in the
+    // core schema is still the (unparametrized) class, meaning we would fetch the wrong validator/serializer.
+    if !matches!(type_, "model" | "dataclass")
+        || (type_ == "dataclass" && schema.contains(intern!(py, "generic_origin"))?)
+    {
+        return Ok(None);
+    }
+
+    // Avoid SchemaDict::get_as_req::<Bound<PyType>>() here; extract as PyAny then downcast.
+    let cls_any = schema
+        .get_item(intern!(py, "cls"))?
+        .ok_or_else(|| PyKeyError::new_err("cls"))?;
+    let class: Bound<'py, PyType> = cls_any.downcast::<PyType>()?.to_owned();
+
+    // Note: we NEED to use the __dict__ here (and perform get_item calls rather than getattr)
+    // because we don't want to fetch prebuilt validators from parent classes.
+    // We don't downcast here because __dict__ on a class is a readonly mappingproxy,
+    // so we can just leave it as is and do get_item checks.
+    let class_dict = class.getattr(intern!(py, "__dict__"))?;
+
+    let is_complete: bool = class_dict
+        .get_item(intern!(py, "__pydantic_complete__"))
+        .is_ok_and(|b| b.extract().unwrap_or(false));
+
+    if !is_complete {
+        return Ok(None);
+    }
+
+    // Retrieve the prebuilt validator / serializer if available
+    let prebuilt: Bound<'py, PyAny> = class_dict.get_item(prebuilt_attr_name)?;
+    extractor(prebuilt)
+}
diff --git a/src/errors/types.rs b/src/errors/types.rs
index 1b821e2..ee4341c 100644
--- a/src/errors/types.rs
+++ b/src/errors/types.rs
@@ -42,6 +42,7 @@ pub fn list_all_errors(py: Python<'_>) -> PyResult<Bound<'_, PyList>> {
     PyList::new(py, errors)
 }
 
+/*
 fn field_from_context<'py, T: FromPyObject<'py>>(
     context: Option<&Bound<'py, PyDict>>,
     field_name: &str,
@@ -55,7 +56,37 @@ fn field_from_context<'py, T: FromPyObject<'py>>(
         .extract::<T>()
         .map_err(|_| py_error_type!(PyTypeError; "{}: '{}' context value must be a {}", enum_name, field_name, type_name_fn()))
 }
+*/
 
+fn field_from_context<'py, T>(
+    context: Option<&Bound<'py, PyDict>>,
+    field_name: &str,
+    enum_name: &str,
+    type_name_fn: fn() -> &'static str,
+) -> PyResult<T>
+where
+    T: for<'a> FromPyObject<'a, 'py>,
+    for<'a> <T as FromPyObject<'a, 'py>>::Error: Into<PyErr>,
+{
+    context
+        .ok_or_else(|| py_error_type!(PyTypeError; "{}: '{}' required in context", enum_name, field_name))?
+        .get_item(field_name)?
+        .ok_or_else(|| py_error_type!(PyTypeError; "{}: '{}' required in context", enum_name, field_name))?
+        .extract::<T>()
+        .map_err(Into::into)
+        .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<Owned = T> + ?Sized + 'static>(
     context: Option<&Bound<'py, PyDict>>,
     field_name: &str,
@@ -67,6 +98,25 @@ fn cow_field_from_context<'py, T: FromPyObject<'py>, B: ToOwned<Owned = T> + ?Si
     })?;
     Ok(Cow::Owned(res))
 }
+*/
+
+fn cow_field_from_context<'py, T, B>(
+    context: Option<&Bound<'py, PyDict>>,
+    field_name: &str,
+    enum_name: &str,
+    _type_name_fn: fn() -> &'static str,
+) -> PyResult<Cow<'static, B>>
+where
+    T: for<'a> FromPyObject<'a, 'py>,
+    for<'a> <T as FromPyObject<'a, 'py>>::Error: Into<PyErr>,
+    B: ToOwned<Owned = T> + ?Sized + 'static,
+{
+    let res: T = field_from_context(context, field_name, enum_name, || {
+        type_name::<T>().split("::").last().unwrap()
+    })?;
+    Ok(Cow::Owned(res))
+}
+
 
 macro_rules! basic_error_default {
     (
@@ -799,6 +849,7 @@ impl From<Int> for Number {
     }
 }
 
+/*
 impl FromPyObject<'_> for Number {
     fn extract_bound(obj: &Bound<'_, PyAny>) -> PyResult<Self> {
         if let Some(int) = extract_i64(obj) {
@@ -812,6 +863,30 @@ impl FromPyObject<'_> for Number {
         }
     }
 }
+*/
+
+use pyo3::Borrowed;
+
+impl<'py> FromPyObject<'_, 'py> for Number {
+    type Error = PyErr;
+
+    fn extract(obj: Borrowed<'_, 'py, PyAny>) -> Result<Self, Self::Error> {
+        // Keep your existing logic by working with a Bound<PyAny>
+        let obj: &Bound<'py, PyAny> = &*obj;
+
+        if let Some(int) = extract_i64(obj) {
+            Ok(Number::Int(int))
+        } else if let Ok(float) = obj.extract::<f64>() {
+            Ok(Number::Float(float))
+        } else if let Ok(string) = obj.extract::<String>() {
+            Ok(Number::String(string))
+        } else {
+            py_err!(PyTypeError; "Expected int or float or String, got {}", obj.get_type())
+        }
+    }
+}
+
+
 
 impl fmt::Display for Number {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
diff --git a/src/errors/validation_exception.rs b/src/errors/validation_exception.rs
index 5216acc..f750905 100644
--- a/src/errors/validation_exception.rs
+++ b/src/errors/validation_exception.rs
@@ -441,6 +441,7 @@ impl From<PyLineError> for ValLineError {
     }
 }
 
+/*
 impl TryFrom<&Bound<'_, PyAny>> for PyLineError {
     type Error = PyErr;
 
@@ -477,6 +478,49 @@ impl TryFrom<&Bound<'_, PyAny>> for PyLineError {
         })
     }
 }
+*/
+
+impl<'py> TryFrom<&Bound<'py, PyAny>> for PyLineError {
+    type Error = PyErr;
+
+    fn try_from(value: &Bound<'py, PyAny>) -> PyResult<Self> {
+        let dict = value.downcast::<PyDict>()?;
+        let py = value.py();
+
+        let type_raw = dict
+            .get_item(intern!(py, "type"))?
+            .ok_or_else(|| PyKeyError::new_err("type"))?;
+
+        let error_type = if let Ok(type_str) = type_raw.downcast::<PyString>() {
+            let context: Option<Bound<'py, PyDict>> = match dict.get_item(intern!(py, "ctx"))? {
+                Some(ctx_any) => Some(ctx_any.downcast::<PyDict>()?.to_owned()),
+                None => None,
+            };
+
+            ErrorType::new(py, type_str.to_str()?, context)?
+        } else if let Ok(custom_error) = type_raw.extract::<PydanticCustomError>() {
+            ErrorType::new_custom_error(py, custom_error)
+        } else {
+            return Err(PyTypeError::new_err(
+                "`type` should be a `str` or `PydanticCustomError`",
+            ));
+        };
+
+        let location = Location::try_from(dict.get_item("loc")?.as_ref())?;
+
+        let input_value = match dict.get_item("input")? {
+            Some(i) => i.unbind(),
+            None => py.None(),
+        };
+
+        Ok(Self {
+            error_type,
+            location,
+            input_value,
+        })
+    }
+}
+
 
 impl PyLineError {
     pub fn from_val_line_error(py: Python, error: ValLineError) -> PyResult<Self> {
diff --git a/src/input/return_enums.rs b/src/input/return_enums.rs
index 526d2c9..bfef47d 100644
--- a/src/input/return_enums.rs
+++ b/src/input/return_enums.rs
@@ -706,6 +706,7 @@ impl Rem for &Int {
     }
 }
 
+/*
 impl FromPyObject<'_> for Int {
     fn extract_bound(obj: &Bound<'_, PyAny>) -> PyResult<Self> {
         match extract_int(obj) {
@@ -714,6 +715,23 @@ impl FromPyObject<'_> for Int {
         }
     }
 }
+*/
+
+use pyo3::Borrowed;
+
+impl<'py> FromPyObject<'_, 'py> for Int {
+    type Error = PyErr;
+
+    fn extract(obj: Borrowed<'_, 'py, PyAny>) -> Result<Self, Self::Error> {
+        let obj: &Bound<'py, PyAny> = &*obj;
+
+        match extract_int(obj) {
+            Some(i) => Ok(i),
+            None => py_err!(PyTypeError; "Expected int, got {}", obj.get_type()),
+        }
+    }
+}
+
 
 #[derive(Clone)]
 pub enum EitherComplex<'py> {
diff --git a/src/serializers/computed_fields.rs b/src/serializers/computed_fields.rs
index 890d4a8..f1997c5 100644
--- a/src/serializers/computed_fields.rs
+++ b/src/serializers/computed_fields.rs
@@ -1,5 +1,6 @@
 use std::sync::Arc;
 
+use pyo3::exceptions::PyKeyError;
 use pyo3::prelude::*;
 use pyo3::types::{PyDict, PyList, PyString};
 use pyo3::{intern, PyTraverseError, PyVisit};
@@ -21,6 +22,8 @@ use super::errors::py_err_se_err;
 pub(super) struct ComputedFields(Vec<ComputedField>);
 
 impl ComputedFields {
+
+    /*
     pub fn new(
         schema: &Bound<'_, PyDict>,
         config: Option<&Bound<'_, PyDict>>,
@@ -37,6 +40,30 @@ impl ComputedFields {
             Ok(None)
         }
     }
+    */
+
+    pub fn new<'py>(
+        schema: &Bound<'py, PyDict>,
+        config: Option<&Bound<'py, PyDict>>,
+        definitions: &mut DefinitionsBuilder<Arc<CombinedSerializer>>,
+    ) -> PyResult<Option<Self>> {
+        let py = schema.py();
+
+        let computed_fields_any: Option<Bound<'py, PyAny>> =
+            schema.get_item(intern!(py, "computed_fields"))?;
+
+        let Some(computed_fields_any) = computed_fields_any else {
+            return Ok(None);
+        };
+
+        let computed_fields_list: &Bound<'py, PyList> = computed_fields_any.downcast::<PyList>()?;
+        let computed_fields = computed_fields_list
+            .iter()
+            .map(|field| ComputedField::new(&field, config, definitions))
+            .collect::<PyResult<Vec<_>>>()?;
+
+        Ok(Some(Self(computed_fields)))
+    }
 
     pub fn len(&self) -> usize {
         self.0.len()
@@ -162,6 +189,7 @@ struct ComputedField {
     serialize_by_alias: Option<bool>,
 }
 
+/*
 impl ComputedField {
     pub fn new(
         schema: &Bound<'_, PyAny>,
@@ -187,6 +215,60 @@ impl ComputedField {
         })
     }
 }
+*/
+
+impl ComputedField {
+    pub fn new<'py>(
+        schema: &Bound<'py, PyAny>,
+        config: Option<&Bound<'py, PyDict>>,
+        definitions: &mut DefinitionsBuilder<Arc<CombinedSerializer>>,
+    ) -> PyResult<Self> {
+        let py = schema.py();
+        let schema: &Bound<'py, PyDict> = schema.downcast::<PyDict>()?;
+
+        // property_name: required str
+        let property_name_any = schema
+            .get_item(intern!(py, "property_name"))?
+            .ok_or_else(|| PyKeyError::new_err("property_name"))?;
+        let property_name: &Bound<'py, PyString> = property_name_any.downcast::<PyString>()?;
+
+        // return_schema: required dict (or whatever CombinedSerializer::build expects; keep as PyAny if it accepts that)
+        let return_schema_any = schema
+            .get_item(intern!(py, "return_schema"))?
+            .ok_or_else(|| PyKeyError::new_err("return_schema"))?;
+
+        let return_schema: &Bound<'_, PyDict> = return_schema_any.downcast::<PyDict>()?;
+
+        let serializer = CombinedSerializer::build(return_schema, config, definitions)
+            .map_err(|e| py_schema_error_type!("Computed field `{}`:\n  {}", property_name, e))?;
+
+        // alias: optional str; default to property_name
+        let alias: Bound<'py, PyString> = match schema.get_item(intern!(py, "alias"))? {
+            Some(alias_any) => alias_any.downcast::<PyString>()?.to_owned(),
+            None => property_name.to_owned(),
+        };
+
+        let serialize_by_alias: Option<bool> = match config {
+            Some(c) => match c.get_item(intern!(py, "serialize_by_alias"))? {
+                Some(v) => Some(v.extract::<bool>().unwrap_or(false)),
+                None => None,
+            },
+            None => None,
+        };
+
+
+        Ok(Self {
+            property_name: property_name.to_str()?.to_owned(),
+            property_name_py: property_name.to_owned().into(),
+            serializer,
+            alias: alias.to_str()?.to_owned(),
+            alias_py: alias.into(),
+            serialize_by_alias,
+        })
+    }
+}
+
+
 
 impl_py_gc_traverse!(ComputedField { serializer });
 
diff --git a/src/serializers/config.rs b/src/serializers/config.rs
index 69d03ea..954e892 100644
--- a/src/serializers/config.rs
+++ b/src/serializers/config.rs
@@ -92,6 +92,7 @@ macro_rules! serialization_mode {
             }
         }
 
+        /*
         impl FromConfig for $name {
             fn from_config(config: Option<&Bound<'_, PyDict>>) -> PyResult<Self> {
                 let Some(config_dict) = config else {
@@ -101,6 +102,24 @@ macro_rules! serialization_mode {
                 raw_mode.map_or_else(|| Ok(Self::default()), |raw| Self::from_str(raw.to_str()?))
             }
         }
+        */
+
+        impl FromConfig for $name {
+            fn from_config(config: Option<&Bound<'_, PyDict>>) -> PyResult<Self> {
+                let Some(config_dict) = config else {
+                    return Ok(Self::default());
+                };
+                let py = config_dict.py();
+
+                let raw_mode: Option<String> = match config_dict.get_item(intern!(py, $config_key))? {
+                    Some(v) => Some(v.extract::<String>()?),
+                    None => None,
+                };
+
+                raw_mode.map_or_else(|| Ok(Self::default()), |raw| Self::from_str(&raw))
+            }
+        }
+
 
     };
 }
@@ -347,8 +366,21 @@ pub fn utf8_py_error(py: Python, err: Utf8Error, data: &[u8]) -> PyErr {
     }
 }
 
+/*
 impl FromPyObject<'_> for InfNanMode {
     fn extract_bound(ob: &Bound<'_, PyAny>) -> PyResult<Self> {
         Self::from_str(ob.downcast::<PyString>()?.to_str()?)
     }
 }
+*/
+
+use pyo3::Borrowed;
+
+impl<'py> FromPyObject<'_, 'py> for InfNanMode {
+    type Error = PyErr;
+
+    fn extract(ob: Borrowed<'_, 'py, PyAny>) -> Result<Self, Self::Error> {
+        let ob: &Bound<'py, PyAny> = &*ob;
+        Self::from_str(ob.downcast::<PyString>()?.to_str()?)
+    }
+}
diff --git a/src/serializers/extra.rs b/src/serializers/extra.rs
index 2e43954..e57f74f 100644
--- a/src/serializers/extra.rs
+++ b/src/serializers/extra.rs
@@ -403,6 +403,7 @@ pub enum WarningsMode {
     Error,
 }
 
+/*
 impl<'py> FromPyObject<'py> for WarningsMode {
     fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<WarningsMode> {
         if let Ok(bool_mode) = ob.downcast::<PyBool>() {
@@ -423,6 +424,35 @@ impl<'py> FromPyObject<'py> for WarningsMode {
         }
     }
 }
+*/
+
+use pyo3::Borrowed;
+
+impl<'py> FromPyObject<'_, 'py> for WarningsMode {
+    type Error = PyErr;
+
+    fn extract(ob: Borrowed<'_, 'py, PyAny>) -> Result<Self, Self::Error> {
+        let ob: &Bound<'py, PyAny> = &*ob;
+
+        if let Ok(bool_mode) = ob.downcast::<PyBool>() {
+            Ok(bool_mode.is_true().into())
+        } else if let Ok(str_mode) = ob.extract::<&str>() {
+            match str_mode {
+                "none" => Ok(Self::None),
+                "warn" => Ok(Self::Warn),
+                "error" => Ok(Self::Error),
+                _ => Err(PyValueError::new_err(
+                    "Invalid warnings parameter, should be `'none'`, `'warn'`, `'error'` or a `bool`",
+                )),
+            }
+        } else {
+            Err(PyTypeError::new_err(
+                "Invalid warnings parameter, should be `'none'`, `'warn'`, `'error'` or a `bool`",
+            ))
+        }
+    }
+}
+
 
 impl From<bool> for WarningsMode {
     fn from(mode: bool) -> Self {
diff --git a/src/serializers/filter.rs b/src/serializers/filter.rs
index 444033a..5659038 100644
--- a/src/serializers/filter.rs
+++ b/src/serializers/filter.rs
@@ -61,6 +61,7 @@ fn map_negative_indices<'py>(
 type NextFilters<'py> = Option<(Option<Bound<'py, PyAny>>, Option<Bound<'py, PyAny>>)>;
 
 impl SchemaFilter<usize> {
+    /*
     pub fn from_schema(schema: &Bound<'_, PyDict>) -> PyResult<Self> {
         let py = schema.py();
         match schema.get_as::<Bound<'_, PyDict>>(intern!(py, "serialization"))? {
@@ -72,6 +73,23 @@ impl SchemaFilter<usize> {
             None => Ok(SchemaFilter::default()),
         }
     }
+    */
+
+    pub fn from_schema<'py>(schema: &Bound<'py, PyDict>) -> PyResult<Self> {
+        let py = schema.py();
+
+        let ser_any: Option<Bound<'py, PyAny>> = schema.get_item(intern!(py, "serialization"))?;
+        match ser_any {
+            Some(ser_any) => {
+                let ser: &Bound<'py, PyDict> = ser_any.downcast::<PyDict>()?;
+
+                let include = Self::build_set_ints(ser.get_item(intern!(py, "include"))?)?;
+                let exclude = Self::build_set_ints(ser.get_item(intern!(py, "exclude"))?)?;
+                Ok(Self { include, exclude })
+            }
+            None => Ok(SchemaFilter::default()),
+        }
+    }
 
     fn build_set_ints(v: Option<Bound<'_, PyAny>>) -> PyResult<Option<AHashSet<usize>>> {
         match v {
diff --git a/src/serializers/infer.rs b/src/serializers/infer.rs
index 1f6f468..d1e71d1 100644
--- a/src/serializers/infer.rs
+++ b/src/serializers/infer.rs
@@ -618,7 +618,11 @@ pub(crate) fn call_pydantic_serializer<'py, T, E: From<PyErr>>(
 ) -> Result<T, E> {
     let py = value.py();
     let py_serializer = value.getattr(intern!(py, "__pydantic_serializer__"))?;
-    let extracted_serializer: PyRef<SchemaSerializer> = py_serializer.extract()?;
+    //let extracted_serializer: PyRef<SchemaSerializer> = py_serializer.extract()?;
+
+    let extracted_serializer: PyRef<'_, SchemaSerializer> = py_serializer
+        .extract::<PyRef<'_, SchemaSerializer>>()
+        .map_err(|e| e.into())?;
     let mut state = SerializationState {
         warnings: state.warnings.clone(),
         rec_guard: state.rec_guard.clone(),
diff --git a/src/serializers/shared.rs b/src/serializers/shared.rs
index f8a0201..505dd60 100644
--- a/src/serializers/shared.rs
+++ b/src/serializers/shared.rs
@@ -4,7 +4,7 @@ use std::fmt::Debug;
 use std::io::{self, Write};
 use std::sync::Arc;
 
-use pyo3::exceptions::PyTypeError;
+use pyo3::exceptions::{PyKeyError, PyTypeError};
 use pyo3::sync::PyOnceLock;
 use pyo3::types::{PyDict, PyString};
 use pyo3::{intern, PyTraverseError, PyVisit};
@@ -174,9 +174,21 @@ impl CombinedSerializer {
         let py = schema.py();
         let type_key = intern!(py, "type");
 
-        if let Some(ser_schema) = schema.get_as::<Bound<'_, PyDict>>(intern!(py, "serialization"))? {
-            let op_ser_type: Option<Bound<'_, PyString>> = ser_schema.get_as(type_key)?;
-            match op_ser_type.as_ref().map(|py_str| py_str.to_str()).transpose()? {
+        let ser_schema: Option<Bound<'_, PyDict>> = match schema.get_item(intern!(py, "serialization"))? {
+            Some(v) => Some(v.downcast::<PyDict>()?.to_owned()),
+            None => None,
+        };
+
+        if let Some(ser_schema) = ser_schema.as_ref() {
+        //if let Some(ser_schema) = schema.get_as::<Bound<'_, PyDict>>(intern!(py, "serialization"))? {
+            let op_ser_type: Option<String> = match ser_schema.get_item(type_key)? {
+                Some(v) => Some(v.extract::<String>()?),
+                None => None,
+            };
+
+            match op_ser_type.as_deref() {
+            //let op_ser_type: Option<Bound<'_, PyString>> = ser_schema.get_as(type_key)?;
+            //match op_ser_type.as_ref().map(|py_str| py_str.to_str()).transpose()? {
                 Some("function-plain") => {
                     // `function-plain` is a special case, not included in `find_serializer` since it means
                     // something different in `schema.type`
@@ -210,24 +222,29 @@ impl CombinedSerializer {
                 Some(ser_type) => {
                     // otherwise if `schema.serialization.type` is defined, use that with `find_serializer`
                     // instead of `schema.type`. In this case it's an error if a serializer isn't found.
-                    return Self::find_serializer(ser_type, &ser_schema, config, definitions);
+                    //return Self::find_serializer(ser_type, &ser_schema, config, definitions);
+                    return Self::find_serializer(ser_type, ser_schema, config, definitions);
                 }
             };
         }
 
-        let type_: Bound<'_, PyString> = schema.get_as_req(type_key)?;
-        let type_ = type_.to_str()?;
+        //let type_: Bound<'_, PyString> = schema.get_as_req(type_key)?;
+        //let type_ = type_.to_str()?;
+        let type_: String = match schema.get_item(type_key)? {
+            Some(v) => v.extract::<String>()?,
+            None => return Err(PyKeyError::new_err("type")),
+        };
 
         if use_prebuilt {
             // if we have a SchemaValidator on the type already, use it
             if let Ok(Some(prebuilt_serializer)) =
-                super::prebuilt::PrebuiltSerializer::try_get_from_schema(type_, schema)
+                super::prebuilt::PrebuiltSerializer::try_get_from_schema(&type_, schema)
             {
                 return Ok(Arc::new(prebuilt_serializer));
             }
         }
 
-        Self::find_serializer(type_, schema, config, definitions)
+        Self::find_serializer(&type_, schema, config, definitions)
     }
 
     /// Main recursive way to call serializers, supports possible recursive type inference by
diff --git a/src/tools.rs b/src/tools.rs
index 8ce929c..10f18c0 100644
--- a/src/tools.rs
+++ b/src/tools.rs
@@ -11,6 +11,7 @@ use crate::input::Int;
 use crate::PydanticUndefinedType;
 use jiter::{cached_py_string, StringCacheMode};
 
+/*
 pub trait SchemaDict<'py> {
     fn get_as<T>(&self, key: &Bound<'py, PyString>) -> PyResult<Option<T>>
     where
@@ -20,7 +21,21 @@ pub trait SchemaDict<'py> {
     where
         T: FromPyObject<'py>;
 }
+*/
 
+pub trait SchemaDict<'py> {
+    fn get_as<T>(&self, key: &Bound<'py, PyString>) -> PyResult<Option<T>>
+    where
+        T: for<'a> FromPyObject<'a, 'py>,
+        for<'a> <T as FromPyObject<'a, 'py>>::Error: Into<PyErr>;
+
+    fn get_as_req<T>(&self, key: &Bound<'py, PyString>) -> PyResult<T>
+    where
+        T: for<'a> FromPyObject<'a, 'py>,
+        for<'a> <T as FromPyObject<'a, 'py>>::Error: Into<PyErr>;
+}
+
+/*
 impl<'py> SchemaDict<'py> for Bound<'py, PyDict> {
     fn get_as<T>(&self, key: &Bound<'py, PyString>) -> PyResult<Option<T>>
     where
@@ -42,7 +57,33 @@ impl<'py> SchemaDict<'py> for Bound<'py, PyDict> {
         }
     }
 }
+*/
+
+impl<'py> SchemaDict<'py> for Bound<'py, PyDict> {
+    fn get_as<T>(&self, key: &Bound<'py, PyString>) -> PyResult<Option<T>>
+    where
+        T: for<'a> FromPyObject<'a, 'py>,
+        for<'a> <T as FromPyObject<'a, 'py>>::Error: Into<PyErr>,
+    {
+        match self.get_item(key)? {
+            Some(t) => t.extract().map(Some).map_err(Into::into),
+            None => Ok(None),
+        }
+    }
+
+    fn get_as_req<T>(&self, key: &Bound<'py, PyString>) -> PyResult<T>
+    where
+        T: for<'a> FromPyObject<'a, 'py>,
+        for<'a> <T as FromPyObject<'a, 'py>>::Error: Into<PyErr>,
+    {
+        match self.get_item(key)? {
+            Some(t) => t.extract().map_err(Into::into),
+            None => py_err!(PyKeyError; "{}", key),
+        }
+    }
+}
 
+/*
 impl<'py> SchemaDict<'py> for Option<&Bound<'py, PyDict>> {
     fn get_as<T>(&self, key: &Bound<'py, PyString>) -> PyResult<Option<T>>
     where
@@ -65,6 +106,33 @@ impl<'py> SchemaDict<'py> for Option<&Bound<'py, PyDict>> {
         }
     }
 }
+*/
+
+impl<'py> SchemaDict<'py> for Option<&Bound<'py, PyDict>> {
+    fn get_as<T>(&self, key: &Bound<'py, PyString>) -> PyResult<Option<T>>
+    where
+        T: for<'a> FromPyObject<'a, 'py>,
+        for<'a> <T as FromPyObject<'a, 'py>>::Error: Into<PyErr>,
+    {
+        match self {
+            Some(d) => d.get_as(key),
+            None => Ok(None),
+        }
+    }
+
+    #[cfg_attr(has_coverage_attribute, coverage(off))]
+    fn get_as_req<T>(&self, key: &Bound<'py, PyString>) -> PyResult<T>
+    where
+        T: for<'a> FromPyObject<'a, 'py>,
+        for<'a> <T as FromPyObject<'a, 'py>>::Error: Into<PyErr>,
+    {
+        match self {
+            Some(d) => d.get_as_req(key),
+            None => py_err!(PyKeyError; "{}", key),
+        }
+    }
+}
+
 
 macro_rules! py_error_type {
     ($error_type:ty; $msg:expr) => {
diff --git a/src/url.rs b/src/url.rs
index 6963e65..ae1e885 100644
--- a/src/url.rs
+++ b/src/url.rs
@@ -602,6 +602,7 @@ impl UrlHostParts {
     }
 }
 
+/*
 impl FromPyObject<'_> for UrlHostParts {
     fn extract_bound(ob: &Bound<'_, PyAny>) -> PyResult<Self> {
         let py = ob.py();
@@ -614,6 +615,28 @@ impl FromPyObject<'_> for UrlHostParts {
         })
     }
 }
+*/
+
+use pyo3::Borrowed;
+
+impl<'py> FromPyObject<'_, 'py> for UrlHostParts {
+    type Error = PyErr;
+
+    fn extract(ob: Borrowed<'_, 'py, PyAny>) -> Result<Self, Self::Error> {
+        let ob: &Bound<'py, PyAny> = &*ob;
+
+        let py = ob.py();
+        let dict = ob.downcast::<PyDict>()?;
+
+        Ok(UrlHostParts {
+            username: dict.get_as(intern!(py, "username"))?,
+            password: dict.get_as(intern!(py, "password"))?,
+            host: dict.get_as(intern!(py, "host"))?,
+            port: dict.get_as(intern!(py, "port"))?,
+        })
+    }
+}
+
 
 fn host_to_dict<'a>(py: Python<'a>, lib_url: &Url) -> PyResult<Bound<'a, PyDict>> {
     let dict = PyDict::new(py);
diff --git a/src/validators/uuid.rs b/src/validators/uuid.rs
index 25b80c5..9fc67a8 100644
--- a/src/validators/uuid.rs
+++ b/src/validators/uuid.rs
@@ -28,7 +28,7 @@ const UUID_IS_SAFE: &str = "is_safe";
 static UUID_TYPE: PyOnceLock<Py<PyType>> = PyOnceLock::new();
 
 fn import_type(py: Python, module: &str, attr: &str) -> PyResult<Py<PyType>> {
-    py.import(module)?.getattr(attr)?.extract()
+    py.import(module)?.getattr(attr)?.extract().map_err(Into::into)
 }
 
 fn get_uuid_type(py: Python<'_>) -> PyResult<&Bound<'_, PyType>> {
openSUSE Build Service is sponsored by