diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b91442d1a..0e198f699 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -57,8 +57,6 @@ jobs: - uses: codecov/test-results-action@v1 - # See https://github.com/PyO3/pyo3/discussions/2781 - # tests intermittently segfault with pypy and cpython 3.7 when using `coverage run ...`, hence separate job test-python: name: test ${{ matrix.python-version }} strategy: @@ -71,6 +69,8 @@ jobs: - '3.12' - '3.13' - '3.13t' + - '3.14' + - '3.14t' - 'pypy3.9' - 'pypy3.10' @@ -412,15 +412,15 @@ jobs: - os: linux manylinux: auto target: armv7 - interpreter: 3.9 3.10 3.11 3.12 3.13 + interpreter: 3.9 3.10 3.11 3.12 3.13 3.14 - os: linux manylinux: auto target: ppc64le - interpreter: 3.9 3.10 3.11 3.12 3.13 + interpreter: 3.9 3.10 3.11 3.12 3.13 3.14 - os: linux manylinux: auto target: s390x - interpreter: 3.9 3.10 3.11 3.12 3.13 + interpreter: 3.9 3.10 3.11 3.12 3.13 3.14 - os: linux manylinux: auto target: x86_64 @@ -456,10 +456,10 @@ jobs: - os: windows target: i686 python-architecture: x86 - interpreter: 3.9 3.10 3.11 3.12 3.13 + interpreter: 3.9 3.10 3.11 3.12 3.13 3.14 - os: windows target: aarch64 - interpreter: 3.11 3.12 3.13 + interpreter: 3.11 3.12 3.13 3.14 exclude: # See above; disabled for now. @@ -483,7 +483,7 @@ jobs: with: target: ${{ matrix.target }} manylinux: ${{ matrix.manylinux }} - args: --release --out dist --interpreter ${{ matrix.interpreter || '3.9 3.10 3.11 3.12 3.13 pypy3.9 pypy3.10 pypy3.11' }} + args: --release --out dist --interpreter ${{ matrix.interpreter || '3.9 3.10 3.11 3.12 3.13 3.14 pypy3.9 pypy3.10 pypy3.11' }} rust-toolchain: stable docker-options: -e CI @@ -504,7 +504,7 @@ jobs: fail-fast: false matrix: os: [linux, windows, macos] - interpreter: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.13t'] + interpreter: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.13t', '3.14', '3.14t'] include: # standard runners with override for macos arm - os: linux diff --git a/Cargo.lock b/Cargo.lock index a9d9e0504..0bb0011b6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -281,9 +281,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jiter" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef8253adcbb6206a43e9a619fe6d42133b21c2eaf21e4686cf7c2f1338a627c" +checksum = "1bcfb1e43bda3ba59889499ff494c5f5b6b10864b74aa0bd4593ce4d16838aa6" dependencies = [ "ahash", "bitvec", @@ -435,11 +435,10 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.24.2" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5203598f366b11a02b13aa20cab591229ff0a89fd121a308a5df751d5fc9219" +checksum = "f239d656363bcee73afef85277f1b281e8ac6212a1d42aa90e55b90ed43c47a4" dependencies = [ - "cfg-if", "indoc", "libc", "memoffset", @@ -454,9 +453,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.24.2" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99636d423fa2ca130fa5acde3059308006d46f98caac629418e53f7ebb1e9999" +checksum = "755ea671a1c34044fa165247aaf6f419ca39caa6003aee791a0df2713d8f1b6d" dependencies = [ "once_cell", "python3-dll-a", @@ -465,9 +464,9 @@ dependencies = [ [[package]] name = "pyo3-ffi" -version = "0.24.2" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78f9cf92ba9c409279bc3305b5409d90db2d2c22392d443a87df3a1adad59e33" +checksum = "fc95a2e67091e44791d4ea300ff744be5293f394f1bafd9f78c080814d35956e" dependencies = [ "libc", "pyo3-build-config", @@ -475,9 +474,9 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.24.2" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b999cb1a6ce21f9a6b147dcf1be9ffedf02e0043aec74dc390f3007047cecd9" +checksum = "a179641d1b93920829a62f15e87c0ed791b6c8db2271ba0fd7c2686090510214" dependencies = [ "proc-macro2", "pyo3-macros-backend", @@ -487,9 +486,9 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.24.2" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "822ece1c7e1012745607d5cf0bcb2874769f0f7cb34c4cde03b9358eb9ef911a" +checksum = "9dff85ebcaab8c441b0e3f7ae40a6963ecea8a9f5e74f647e33fcf5ec9a1e89e" dependencies = [ "heck", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index 72f3e484a..b810cf369 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.24", features = ["generate-import-lib", "num-bigint", "py-clone"] } +pyo3 = { version = "0.25", features = ["generate-import-lib", "num-bigint", "py-clone"] } regex = "1.11.1" strum = { version = "0.26.3", features = ["derive"] } strum_macros = "0.26.4" @@ -44,7 +44,7 @@ base64 = "0.22.1" num-bigint = "0.4.6" num-traits = "0.2.19" uuid = "1.16.0" -jiter = { version = "0.9.1", features = ["python"] } +jiter = { version = "0.10.0", features = ["python"] } hex = "0.4.3" [lib] @@ -72,12 +72,12 @@ debug = true strip = false [dev-dependencies] -pyo3 = { version = "0.24", features = ["auto-initialize"] } +pyo3 = { version = "0.25", 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.24" } +pyo3-build-config = { version = "0.25" } [lints.clippy] dbg_macro = "warn" diff --git a/pyproject.toml b/pyproject.toml index d09c62a10..57e3f24de 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,7 @@ classifiers = [ 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: 3.12', 'Programming Language :: Python :: 3.13', + 'Programming Language :: Python :: 3.14', 'Programming Language :: Rust', 'Framework :: Pydantic', 'Intended Audience :: Developers', @@ -34,7 +35,9 @@ classifiers = [ 'Operating System :: MacOS', 'Typing :: Typed', ] -dependencies = ['typing-extensions>=4.6.0,!=4.7.0'] +dependencies = [ + 'typing-extensions>=4.13.0', +] dynamic = ['description', 'license', 'readme', 'version'] [project.urls] @@ -65,10 +68,10 @@ testing = [ 'numpy; python_version < "3.13" and implementation_name == "cpython" and platform_machine == "x86_64"', 'exceptiongroup; python_version < "3.11"', 'tzdata', - 'typing_extensions', + 'typing-inspection>=0.4.1', ] linting = [{ include-group = "dev" }, 'griffe', 'pyright', 'ruff', 'mypy'] -wasm = [{ include-group = "dev" }, 'typing_extensions', 'ruff'] +wasm = [{ include-group = "dev" }, 'ruff'] codspeed = [ # codspeed is only run on CI, with latest version of CPython 'pytest-codspeed; python_version == "3.13" and implementation_name == "cpython"', diff --git a/src/py_gc.rs b/src/py_gc.rs index 8af285afb..c4f83f5b0 100644 --- a/src/py_gc.rs +++ b/src/py_gc.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use ahash::AHashMap; use enum_dispatch::enum_dispatch; -use pyo3::{AsPyPointer, Py, PyTraverseError, PyVisit}; +use pyo3::{Py, PyTraverseError, PyVisit}; /// Trait implemented by types which can be traversed by the Python GC. #[enum_dispatch] @@ -10,10 +10,7 @@ pub trait PyGcTraverse { fn py_gc_traverse(&self, visit: &PyVisit<'_>) -> Result<(), PyTraverseError>; } -impl PyGcTraverse for Py -where - Py: AsPyPointer, -{ +impl PyGcTraverse for Py { fn py_gc_traverse(&self, visit: &PyVisit<'_>) -> Result<(), PyTraverseError> { visit.call(self) } diff --git a/src/serializers/filter.rs b/src/serializers/filter.rs index 65ec4062d..7f893726a 100644 --- a/src/serializers/filter.rs +++ b/src/serializers/filter.rs @@ -320,7 +320,7 @@ where /// detect both ellipsis and `True` to be compatible with pydantic V1 fn is_ellipsis_like(v: &Bound<'_, PyAny>) -> bool { - v.is(&v.py().Ellipsis()) + v.is(v.py().Ellipsis()) || match v.downcast::() { Ok(b) => b.is_true(), Err(_) => false, diff --git a/src/tools.rs b/src/tools.rs index 96146d30c..f001eeb84 100644 --- a/src/tools.rs +++ b/src/tools.rs @@ -8,7 +8,7 @@ use pyo3::types::{PyDict, PyString}; use pyo3::{intern, FromPyObject}; use crate::input::Int; -use jiter::{cached_py_string, pystring_fast_new, StringCacheMode}; +use jiter::{cached_py_string, StringCacheMode}; pub trait SchemaDict<'py> { fn get_as(&self, key: &Bound<'py, PyString>) -> PyResult> @@ -148,11 +148,10 @@ pub fn extract_int(v: &Bound<'_, PyAny>) -> Option { pub(crate) fn new_py_string<'py>(py: Python<'py>, s: &str, cache_str: StringCacheMode) -> Bound<'py, PyString> { // we could use `bytecount::num_chars(s.as_bytes()) == s.len()` as orjson does, but it doesn't appear to be faster - let ascii_only = false; if matches!(cache_str, StringCacheMode::All) { - cached_py_string(py, s, ascii_only) + cached_py_string(py, s) } else { - pystring_fast_new(py, s, ascii_only) + PyString::new(py, s) } } diff --git a/src/validators/dataclass.rs b/src/validators/dataclass.rs index c74d789ec..9cfb9dbae 100644 --- a/src/validators/dataclass.rs +++ b/src/validators/dataclass.rs @@ -401,7 +401,7 @@ impl Validator for DataclassArgsValidator { let data_dict = dict.copy()?; if let Err(err) = data_dict.del_item(field_name) { // KeyError is fine here as the field might not be in the dict - if !err.get_type(py).is(&PyType::new::(py)) { + if !err.get_type(py).is(PyType::new::(py)) { return Err(err.into()); } } diff --git a/src/validators/enum_.rs b/src/validators/enum_.rs index 0e34cb182..60f24d9d6 100644 --- a/src/validators/enum_.rs +++ b/src/validators/enum_.rs @@ -138,7 +138,7 @@ impl Validator for EnumValidator { // https://github.com/python/cpython/blob/v3.12.2/Lib/enum.py#L1148 if enum_value.is_instance(class)? { return Ok(enum_value.into()); - } else if !enum_value.is(&py.None()) { + } else if !enum_value.is(py.None()) { let type_error = PyTypeError::new_err(format!( "error in {}._missing_: returned {} instead of None or a valid member", class diff --git a/src/validators/model_fields.rs b/src/validators/model_fields.rs index 10d13d7b8..d3af284fa 100644 --- a/src/validators/model_fields.rs +++ b/src/validators/model_fields.rs @@ -409,7 +409,7 @@ impl Validator for ModelFieldsValidator { let data_dict = dict.copy()?; if let Err(err) = data_dict.del_item(field_name) { // KeyError is fine here as the field might not be in the dict - if !err.get_type(py).is(&PyType::new::(py)) { + if !err.get_type(py).is(PyType::new::(py)) { return Err(err.into()); } } diff --git a/tests/emscripten_runner.js b/tests/emscripten_runner.js index ab1583da3..c527f86f8 100644 --- a/tests/emscripten_runner.js +++ b/tests/emscripten_runner.js @@ -106,6 +106,7 @@ await micropip.install([ 'tzdata', 'file:${wheel_path}', 'typing-extensions', + 'typing-inspection', ]) importlib.invalidate_caches() diff --git a/tests/test_garbage_collection.py b/tests/test_garbage_collection.py index c129c0e34..3b5bb3c4f 100644 --- a/tests/test_garbage_collection.py +++ b/tests/test_garbage_collection.py @@ -1,4 +1,5 @@ import platform +import sys from collections.abc import Iterable from typing import Any from weakref import WeakValueDictionary @@ -20,7 +21,7 @@ ) -@pytest.mark.xfail(is_free_threaded, reason='GC leaks on free-threaded') +@pytest.mark.xfail(is_free_threaded and sys.version_info < (3, 14), reason='GC leaks on free-threaded (<3.14)') @pytest.mark.xfail( condition=platform.python_implementation() == 'PyPy', reason='https://foss.heptapod.net/pypy/pypy/-/issues/3899' ) @@ -48,7 +49,7 @@ class MyModel(BaseModel): assert_gc(lambda: len(cache) == 0) -@pytest.mark.xfail(is_free_threaded, reason='GC leaks on free-threaded') +@pytest.mark.xfail(is_free_threaded and sys.version_info < (3, 14), reason='GC leaks on free-threaded (<3.14)') @pytest.mark.xfail( condition=platform.python_implementation() == 'PyPy', reason='https://foss.heptapod.net/pypy/pypy/-/issues/3899' ) diff --git a/tests/test_misc.py b/tests/test_misc.py index 50162c24b..722362fa6 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -1,9 +1,14 @@ import copy import pickle -import re import pytest -from typing_extensions import get_args +from typing_extensions import ( # noqa: UP035 (https://github.com/astral-sh/ruff/pull/18476) + get_args, + get_origin, + get_type_hints, +) +from typing_inspection import typing_objects +from typing_inspection.introspection import UNKNOWN, AnnotationSource, inspect_annotation from pydantic_core import CoreConfig, CoreSchema, CoreSchemaType, PydanticUndefined, core_schema from pydantic_core._pydantic_core import ( @@ -159,13 +164,26 @@ class MyModel: def test_core_schema_type_literal(): - def get_type_value(schema): - type_ = schema.__annotations__['type'] - m = re.search(r"Literal\['(.+?)']", type_.__forward_arg__) - assert m, f'Unknown schema type: {type_}' - return m.group(1) + def get_type_value(schema_typeddict) -> str: + annotation = get_type_hints(schema_typeddict, include_extras=True)['type'] + inspected_ann = inspect_annotation(annotation, annotation_source=AnnotationSource.TYPED_DICT) + annotation = inspected_ann.type + assert annotation is not UNKNOWN + assert typing_objects.is_literal(get_origin(annotation)), ( + f"The 'type' key of core schemas must be a Literal form, got {get_origin(annotation)}" + ) + args = get_args(annotation) + assert len(args) == 1, ( + f"The 'type' key of core schemas must be a Literal form with a single element, got {len(args)} elements" + ) + type_ = args[0] + assert isinstance(type_, str), ( + f"The 'type' key of core schemas must be a Literal form with a single string element, got element of type {type(type_)}" + ) + + return type_ - schema_types = tuple(get_type_value(x) for x in CoreSchema.__args__) + schema_types = (get_type_value(x) for x in CoreSchema.__args__) schema_types = tuple(dict.fromkeys(schema_types)) # remove duplicates while preserving order if get_args(CoreSchemaType) != schema_types: literal = ''.join(f'\n {e!r},' for e in schema_types) diff --git a/tests/test_schema_functions.py b/tests/test_schema_functions.py index a9cb358ff..c8a24b307 100644 --- a/tests/test_schema_functions.py +++ b/tests/test_schema_functions.py @@ -1,10 +1,11 @@ import dataclasses -import re from datetime import date from enum import Enum from typing import Any import pytest +from typing_extensions import get_args, get_type_hints # noqa: UP035 (https://github.com/astral-sh/ruff/pull/18476) +from typing_inspection.introspection import UNKNOWN, AnnotationSource, inspect_annotation from pydantic_core import SchemaError, SchemaSerializer, SchemaValidator, ValidationError, core_schema @@ -332,10 +333,14 @@ def test_schema_functions(function, args_kwargs, expected_schema): def test_all_schema_functions_used(): - all_types = { - re.sub(r".+'(.+?)'.+", r'\1', s.__annotations__['type'].__forward_arg__) - for s in core_schema.CoreSchema.__args__ - } + all_types: set[str] = set() + for schema_typeddict in core_schema.CoreSchema.__args__: + annotation = get_type_hints(schema_typeddict, include_extras=True)['type'] + inspected_ann = inspect_annotation(annotation, annotation_source=AnnotationSource.TYPED_DICT) + annotation = inspected_ann.type + assert annotation is not UNKNOWN + all_types.add(get_args(annotation)[0]) + types_used = {args['type'] for _, _, args in all_schema_functions if 'type' in args} # isn't a CoreSchema type diff --git a/tests/test_validation_context.py b/tests/test_validation_context.py index 5d71f5b55..fd5ae75c2 100644 --- a/tests/test_validation_context.py +++ b/tests/test_validation_context.py @@ -72,11 +72,10 @@ def f(input_value, validator, info): assert v.validate_python('foobar', None, {}) == 'foobar' - # internal error!, use generic bit of error message to match both cpython and pypy - with pytest.raises(TypeError, match='is not iterable'): + with pytest.raises(TypeError): v.validate_test('foobar') - with pytest.raises(TypeError, match='is not iterable'): + with pytest.raises(TypeError): v.isinstance_test('foobar') with pytest.raises(ValidationError, match=r'Value error, wrong \[type=value_error,'): @@ -84,7 +83,7 @@ def f(input_value, validator, info): assert v.isinstance_test('foobar', None, {}) is True - with pytest.raises(TypeError, match='is not iterable'): + with pytest.raises(TypeError): v.isinstance_test('foobar') assert v.isinstance_test('foobar', None, {'error'}) is False diff --git a/tests/validators/test_dataclasses.py b/tests/validators/test_dataclasses.py index da4105a55..4b5b4afa6 100644 --- a/tests/validators/test_dataclasses.py +++ b/tests/validators/test_dataclasses.py @@ -1516,7 +1516,7 @@ def test_dataclass_wrap_json(): assert v.validate_json('{"a": "hello", "b": true}', strict=True) == FooDataclass(a='hello', b=True) -@pytest.mark.xfail(is_free_threaded, reason='GC leaks on free-threaded') +@pytest.mark.xfail(is_free_threaded and sys.version_info < (3, 14), reason='GC leaks on free-threaded (<3.14)') @pytest.mark.xfail( condition=platform.python_implementation() == 'PyPy', reason='https://foss.heptapod.net/pypy/pypy/-/issues/3899' ) diff --git a/tests/validators/test_model_init.py b/tests/validators/test_model_init.py index ccc427800..c15f8970d 100644 --- a/tests/validators/test_model_init.py +++ b/tests/validators/test_model_init.py @@ -1,4 +1,5 @@ import platform +import sys import weakref import pytest @@ -411,7 +412,7 @@ def __init__(self, **kwargs): assert calls == ["{'a': '1'}", "{'a': '1', 'x': 4}"] -@pytest.mark.xfail(is_free_threaded, reason='GC leaks on free-threaded') +@pytest.mark.xfail(is_free_threaded and sys.version_info < (3, 14), reason='GC leaks on free-threaded (<3.14)') @pytest.mark.xfail( condition=platform.python_implementation() == 'PyPy', reason='https://foss.heptapod.net/pypy/pypy/-/issues/3899' ) diff --git a/tests/validators/test_with_default.py b/tests/validators/test_with_default.py index ca9b5802d..44c5887a2 100644 --- a/tests/validators/test_with_default.py +++ b/tests/validators/test_with_default.py @@ -636,7 +636,7 @@ def val_func(v: Any, handler: core_schema.ValidatorFunctionWrapHandler) -> Any: validator.validate_python('') -@pytest.mark.xfail(is_free_threaded, reason='GC leaks on free-threaded') +@pytest.mark.xfail(is_free_threaded and sys.version_info < (3, 14), reason='GC leaks on free-threaded (<3.14)') @pytest.mark.xfail( condition=platform.python_implementation() == 'PyPy', reason='https://foss.heptapod.net/pypy/pypy/-/issues/3899' ) diff --git a/uv.lock b/uv.lock index 717abdced..de11e849a 100644 --- a/uv.lock +++ b/uv.lock @@ -3,7 +3,8 @@ revision = 2 requires-python = ">=3.9" resolution-markers = [ "python_full_version == '3.13.*' and implementation_name == 'cpython'", - "(python_full_version >= '3.12' and implementation_name != 'cpython') or (python_full_version == '3.12.*' and implementation_name == 'cpython') or (python_full_version >= '3.14' and implementation_name == 'cpython')", + "python_full_version == '3.14.*' and implementation_name == 'cpython'", + "(python_full_version >= '3.12' and implementation_name != 'cpython') or (python_full_version == '3.12.*' and implementation_name == 'cpython') or (python_full_version >= '3.15' and implementation_name == 'cpython')", "python_full_version == '3.11.*'", "python_full_version == '3.10.*'", "python_full_version < '3.10'", @@ -442,7 +443,7 @@ name = "numpy" version = "2.2.2" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "(python_full_version >= '3.12' and implementation_name != 'cpython') or (python_full_version == '3.12.*' and implementation_name == 'cpython') or (python_full_version >= '3.14' and implementation_name == 'cpython')", + "(python_full_version >= '3.12' and implementation_name != 'cpython') or (python_full_version == '3.12.*' and implementation_name == 'cpython') or (python_full_version >= '3.15' and implementation_name == 'cpython')", "python_full_version == '3.11.*'", "python_full_version == '3.10.*'", ] @@ -494,10 +495,10 @@ version = "2.2.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy", version = "2.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "numpy", version = "2.2.2", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.10' and python_full_version < '3.13') or (python_full_version >= '3.10' and implementation_name != 'cpython') or (python_full_version >= '3.14' and implementation_name == 'cpython')" }, - { name = "python-dateutil", marker = "python_full_version != '3.13.*' or implementation_name != 'cpython'" }, - { name = "pytz", marker = "python_full_version != '3.13.*' or implementation_name != 'cpython'" }, - { name = "tzdata", marker = "python_full_version != '3.13.*' or implementation_name != 'cpython'" }, + { name = "numpy", version = "2.2.2", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.10' and python_full_version < '3.13') or (python_full_version >= '3.10' and implementation_name != 'cpython') or (python_full_version >= '3.15' and implementation_name == 'cpython')" }, + { name = "python-dateutil", marker = "python_full_version < '3.13' or python_full_version >= '3.15' or implementation_name != 'cpython'" }, + { name = "pytz", marker = "python_full_version < '3.13' or python_full_version >= '3.15' or implementation_name != 'cpython'" }, + { name = "tzdata", marker = "python_full_version < '3.13' or python_full_version >= '3.15' or implementation_name != 'cpython'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/9c/d6/9f8431bacc2e19dca897724cd097b1bb224a6ad5433784a44b587c7c13af/pandas-2.2.3.tar.gz", hash = "sha256:4f18ba62b61d7e192368b84517265a99b4d7ee8912f8708660fb4a366cc82667", size = 4399213, upload-time = "2024-09-20T13:10:04.827Z" } wheels = [ @@ -592,7 +593,7 @@ all = [ { name = "pytest-timeout" }, { name = "python-dateutil" }, { name = "ruff" }, - { name = "typing-extensions" }, + { name = "typing-inspection" }, { name = "tzdata" }, ] codspeed = [ @@ -626,17 +627,16 @@ testing = [ { name = "pytest-speed" }, { name = "pytest-timeout" }, { name = "python-dateutil" }, - { name = "typing-extensions" }, + { name = "typing-inspection" }, { name = "tzdata" }, ] wasm = [ { name = "maturin" }, { name = "ruff" }, - { name = "typing-extensions" }, ] [package.metadata] -requires-dist = [{ name = "typing-extensions", specifier = ">=4.6.0,!=4.7.0" }] +requires-dist = [{ name = "typing-extensions", specifier = ">=4.13.0" }] [package.metadata.requires-dev] all = [ @@ -660,7 +660,7 @@ all = [ { name = "pytest-timeout" }, { name = "python-dateutil" }, { name = "ruff" }, - { name = "typing-extensions" }, + { name = "typing-inspection", specifier = ">=0.4.1" }, { name = "tzdata" }, ] codspeed = [{ name = "pytest-codspeed", marker = "python_full_version == '3.13.*' and implementation_name == 'cpython'" }] @@ -689,13 +689,12 @@ testing = [ { name = "pytest-speed" }, { name = "pytest-timeout" }, { name = "python-dateutil" }, - { name = "typing-extensions" }, + { name = "typing-inspection", specifier = ">=0.4.1" }, { name = "tzdata" }, ] wasm = [ { name = "maturin" }, { name = "ruff" }, - { name = "typing-extensions" }, ] [[package]] @@ -957,11 +956,23 @@ wheels = [ [[package]] name = "typing-extensions" -version = "4.12.2" +version = "4.14.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d1/bc/51647cd02527e87d05cb083ccc402f93e441606ff1f01739a62c8ad09ba5/typing_extensions-4.14.0.tar.gz", hash = "sha256:8676b788e32f02ab42d9e7c61324048ae4c6d844a399eebace3d4979d75ceef4", size = 107423, upload-time = "2025-06-02T14:52:11.399Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/e0/552843e0d356fbb5256d21449fa957fa4eff3bbc135a74a691ee70c7c5da/typing_extensions-4.14.0-py3-none-any.whl", hash = "sha256:a1514509136dd0b477638fc68d6a91497af5076466ad0fa6c338e44e359944af", size = 43839, upload-time = "2025-06-02T14:52:10.026Z" }, +] + +[[package]] +name = "typing-inspection" +version = "0.4.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321, upload-time = "2024-06-07T18:52:15.995Z" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726, upload-time = "2025-05-21T18:55:23.885Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438, upload-time = "2024-06-07T18:52:13.582Z" }, + { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" }, ] [[package]]