Skip to content

Commit ce46756

Browse files
authored
support free-threaded Python 3.13t (#1628)
1 parent db63fec commit ce46756

File tree

3 files changed

+24
-37
lines changed

3 files changed

+24
-37
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,6 @@ jobs:
107107
HYPOTHESIS_PROFILE: slow
108108
# TODO: remove --inline-snapshot=disable after https://github.com/15r10nk/inline-snapshot/issues/192
109109
PYTEST_ADDOPTS: ${{ endsWith(matrix.python-version, 't') && '--parallel-threads=2 --inline-snapshot=disable' || '' }}
110-
# TODO: add `gil_used = false` to the PyO3 `#[pymodule]` when test suite is ok
111-
PYTHON_GIL: ${{ endsWith(matrix.python-version, 't') && '0' || '1' }}
112110

113111
test-os:
114112
name: test on ${{ matrix.os }}
@@ -505,7 +503,7 @@ jobs:
505503
fail-fast: false
506504
matrix:
507505
os: [linux, windows, macos]
508-
interpreter: ['3.9', '3.10', '3.11', '3.12', '3.13']
506+
interpreter: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.13t']
509507
include:
510508
# standard runners with override for macos arm
511509
- os: linux

src/lib.rs

Lines changed: 22 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -106,33 +106,26 @@ pub fn build_info() -> String {
106106
)
107107
}
108108

109-
#[pymodule]
110-
fn _pydantic_core(py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
111-
m.add("__version__", get_pydantic_core_version())?;
112-
m.add("build_profile", env!("PROFILE"))?;
113-
m.add("build_info", build_info())?;
114-
m.add("_recursion_limit", recursion_guard::RECURSION_GUARD_LIMIT)?;
115-
m.add("PydanticUndefined", PydanticUndefinedType::new(py))?;
116-
m.add_class::<PydanticUndefinedType>()?;
117-
m.add_class::<PySome>()?;
118-
m.add_class::<SchemaValidator>()?;
119-
m.add_class::<ValidationError>()?;
120-
m.add_class::<SchemaError>()?;
121-
m.add_class::<PydanticCustomError>()?;
122-
m.add_class::<PydanticKnownError>()?;
123-
m.add_class::<PydanticOmit>()?;
124-
m.add_class::<PydanticUseDefault>()?;
125-
m.add_class::<PydanticSerializationError>()?;
126-
m.add_class::<PydanticSerializationUnexpectedValue>()?;
127-
m.add_class::<PyUrl>()?;
128-
m.add_class::<PyMultiHostUrl>()?;
129-
m.add_class::<ArgsKwargs>()?;
130-
m.add_class::<SchemaSerializer>()?;
131-
m.add_class::<TzInfo>()?;
132-
m.add_function(wrap_pyfunction!(to_json, m)?)?;
133-
m.add_function(wrap_pyfunction!(from_json, m)?)?;
134-
m.add_function(wrap_pyfunction!(to_jsonable_python, m)?)?;
135-
m.add_function(wrap_pyfunction!(list_all_errors, m)?)?;
136-
m.add_function(wrap_pyfunction!(validate_core_schema, m)?)?;
137-
Ok(())
109+
#[pymodule(gil_used = false)]
110+
mod _pydantic_core {
111+
#[allow(clippy::wildcard_imports)]
112+
use super::*;
113+
114+
#[pymodule_export]
115+
use crate::{
116+
from_json, list_all_errors, to_json, to_jsonable_python, validate_core_schema, ArgsKwargs, PyMultiHostUrl,
117+
PySome, PyUrl, PydanticCustomError, PydanticKnownError, PydanticOmit, PydanticSerializationError,
118+
PydanticSerializationUnexpectedValue, PydanticUndefinedType, PydanticUseDefault, SchemaError, SchemaSerializer,
119+
SchemaValidator, TzInfo, ValidationError,
120+
};
121+
122+
#[pymodule_init]
123+
fn module_init(m: &Bound<'_, PyModule>) -> PyResult<()> {
124+
m.add("__version__", get_pydantic_core_version())?;
125+
m.add("build_profile", env!("PROFILE"))?;
126+
m.add("build_info", build_info())?;
127+
m.add("_recursion_limit", recursion_guard::RECURSION_GUARD_LIMIT)?;
128+
m.add("PydanticUndefined", PydanticUndefinedType::new(m.py()))?;
129+
Ok(())
130+
}
138131
}

src/validators/decimal.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -182,11 +182,7 @@ impl Validator for DecimalValidator {
182182

183183
if let Some(multiple_of) = &self.multiple_of {
184184
// fraction = (decimal / multiple_of) % 1
185-
let fraction = unsafe {
186-
let division = decimal.div(multiple_of)?;
187-
let one = 1u8.into_pyobject(py)?;
188-
Bound::from_owned_ptr_or_err(py, pyo3::ffi::PyNumber_Remainder(division.as_ptr(), one.as_ptr()))?
189-
};
185+
let fraction = (decimal.div(multiple_of)?).rem(1)?;
190186
let zero = 0u8.into_pyobject(py)?;
191187
if !fraction.eq(&zero)? {
192188
return Err(ValError::new(

0 commit comments

Comments
 (0)