From e6c767ee6dd382380e6b6d4e6ee14ebc0f097fff Mon Sep 17 00:00:00 2001 From: David Hewitt Date: Thu, 6 Feb 2025 20:04:42 +0000 Subject: [PATCH 1/3] support free-threaded Python 3.13t --- .github/workflows/ci.yml | 2 -- src/lib.rs | 51 +++++++++++++++++----------------------- 2 files changed, 22 insertions(+), 31 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ed52c387f..b18b1cc02 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -107,8 +107,6 @@ jobs: HYPOTHESIS_PROFILE: slow # TODO: remove --inline-snapshot=disable after https://github.com/15r10nk/inline-snapshot/issues/192 PYTEST_ADDOPTS: ${{ endsWith(matrix.python-version, 't') && '--parallel-threads=2 --inline-snapshot=disable' || '' }} - # TODO: add `gil_used = false` to the PyO3 `#[pymodule]` when test suite is ok - PYTHON_GIL: ${{ endsWith(matrix.python-version, 't') && '0' || '1' }} test-os: name: test on ${{ matrix.os }} diff --git a/src/lib.rs b/src/lib.rs index 7689f3988..2404ebdfb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -106,33 +106,26 @@ pub fn build_info() -> String { ) } -#[pymodule] -fn _pydantic_core(py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> { - m.add("__version__", get_pydantic_core_version())?; - m.add("build_profile", env!("PROFILE"))?; - m.add("build_info", build_info())?; - m.add("_recursion_limit", recursion_guard::RECURSION_GUARD_LIMIT)?; - m.add("PydanticUndefined", PydanticUndefinedType::new(py))?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_function(wrap_pyfunction!(to_json, m)?)?; - m.add_function(wrap_pyfunction!(from_json, m)?)?; - m.add_function(wrap_pyfunction!(to_jsonable_python, m)?)?; - m.add_function(wrap_pyfunction!(list_all_errors, m)?)?; - m.add_function(wrap_pyfunction!(validate_core_schema, m)?)?; - Ok(()) +#[pymodule(gil_used = false)] +mod _pydantic_core { + #[allow(clippy::wildcard_imports)] + use super::*; + + #[pymodule_export] + use crate::{ + from_json, list_all_errors, to_json, to_jsonable_python, validate_core_schema, ArgsKwargs, PyMultiHostUrl, + PySome, PyUrl, PydanticCustomError, PydanticKnownError, PydanticOmit, PydanticSerializationError, + PydanticSerializationUnexpectedValue, PydanticUndefinedType, PydanticUseDefault, SchemaError, SchemaSerializer, + SchemaValidator, TzInfo, ValidationError, + }; + + #[pymodule_init] + fn module_init(m: &Bound<'_, PyModule>) -> PyResult<()> { + m.add("__version__", get_pydantic_core_version())?; + m.add("build_profile", env!("PROFILE"))?; + m.add("build_info", build_info())?; + m.add("_recursion_limit", recursion_guard::RECURSION_GUARD_LIMIT)?; + m.add("PydanticUndefined", PydanticUndefinedType::new(m.py()))?; + Ok(()) + } } From aa03bfc665f46d794c996753d6899144fac9a055 Mon Sep 17 00:00:00 2001 From: David Hewitt Date: Thu, 6 Feb 2025 20:08:15 +0000 Subject: [PATCH 2/3] include 3.13t in PGO jobs --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b18b1cc02..74200993d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -503,7 +503,7 @@ jobs: fail-fast: false matrix: os: [linux, windows, macos] - interpreter: ['3.9', '3.10', '3.11', '3.12', '3.13'] + interpreter: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.13t'] include: # standard runners with override for macos arm - os: linux From a3e3911159f4c66d3f15e0163348d73455109373 Mon Sep 17 00:00:00 2001 From: David Hewitt Date: Thu, 6 Feb 2025 20:44:10 +0000 Subject: [PATCH 3/3] snipe off some `unsafe` code --- src/validators/decimal.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/validators/decimal.rs b/src/validators/decimal.rs index 4f56f4bfd..6c2e55806 100644 --- a/src/validators/decimal.rs +++ b/src/validators/decimal.rs @@ -182,11 +182,7 @@ impl Validator for DecimalValidator { if let Some(multiple_of) = &self.multiple_of { // fraction = (decimal / multiple_of) % 1 - let fraction = unsafe { - let division = decimal.div(multiple_of)?; - let one = 1u8.into_pyobject(py)?; - Bound::from_owned_ptr_or_err(py, pyo3::ffi::PyNumber_Remainder(division.as_ptr(), one.as_ptr()))? - }; + let fraction = (decimal.div(multiple_of)?).rem(1)?; let zero = 0u8.into_pyobject(py)?; if !fraction.eq(&zero)? { return Err(ValError::new(