diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d2fc6c3..75971dc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,7 +39,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] + python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13'] env: UV_PYTHON: ${{ matrix.python-version }} diff --git a/pydantic_extra_types/color.py b/pydantic_extra_types/color.py index 5f1e3a5..92995e5 100644 --- a/pydantic_extra_types/color.py +++ b/pydantic_extra_types/color.py @@ -12,16 +12,16 @@ import math import re from colorsys import hls_to_rgb, rgb_to_hls -from typing import Any, Callable, Literal, Union, cast +from typing import Any, Callable, Literal, Tuple, Union, cast from pydantic import GetJsonSchemaHandler from pydantic._internal import _repr from pydantic.json_schema import JsonSchemaValue from pydantic_core import CoreSchema, PydanticCustomError, core_schema -ColorTuple = Union[tuple[int, int, int], tuple[int, int, int, float]] +ColorTuple = Union[Tuple[int, int, int], Tuple[int, int, int, float]] ColorType = Union[ColorTuple, str, 'Color'] -HslColorTuple = Union[tuple[float, float, float], tuple[float, float, float, float]] +HslColorTuple = Union[Tuple[float, float, float], Tuple[float, float, float, float]] class RGBA: @@ -115,7 +115,7 @@ def as_named(self, *, fallback: bool = False) -> str: """ if self._rgba.alpha is not None: return self.as_hex() - rgb = cast(tuple[int, int, int], self.as_rgb_tuple()) + rgb = cast('tuple[int, int, int]', self.as_rgb_tuple()) if rgb in COLORS_BY_VALUE: return COLORS_BY_VALUE[rgb] diff --git a/pydantic_extra_types/coordinate.py b/pydantic_extra_types/coordinate.py index 04717b9..cfd14fe 100644 --- a/pydantic_extra_types/coordinate.py +++ b/pydantic_extra_types/coordinate.py @@ -3,8 +3,10 @@ [`Coordinate`][pydantic_extra_types.coordinate.Coordinate] data types. """ +from __future__ import annotations + from dataclasses import dataclass -from typing import Any, ClassVar +from typing import Any, ClassVar, Tuple from pydantic import GetCoreSchemaHandler from pydantic._internal import _repr @@ -89,7 +91,7 @@ class Location(BaseModel): ``` """ - _NULL_ISLAND: ClassVar[tuple[float, float]] = (0.0, 0.0) + _NULL_ISLAND: ClassVar[Tuple[float, float]] = (0.0, 0.0) latitude: Latitude longitude: Longitude @@ -100,7 +102,7 @@ def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaH core_schema.no_info_wrap_validator_function(cls._parse_str, core_schema.str_schema()), core_schema.no_info_wrap_validator_function( cls._parse_tuple, - handler.generate_schema(tuple[float, float]), + handler.generate_schema(Tuple[float, float]), ), handler(source), ] diff --git a/pydantic_extra_types/domain.py b/pydantic_extra_types/domain.py index 9dfef55..1e44ebb 100644 --- a/pydantic_extra_types/domain.py +++ b/pydantic_extra_types/domain.py @@ -5,7 +5,6 @@ from __future__ import annotations import re -from collections.abc import Mapping from typing import Any from pydantic import GetCoreSchemaHandler @@ -54,5 +53,5 @@ def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHa @classmethod def __get_pydantic_json_schema__( cls, schema: core_schema.CoreSchema, handler: GetCoreSchemaHandler - ) -> Mapping[str, Any]: + ) -> dict[str, Any]: return handler(schema) diff --git a/pydantic_extra_types/pendulum_dt.py b/pydantic_extra_types/pendulum_dt.py index 9b7b00b..797bb8e 100644 --- a/pydantic_extra_types/pendulum_dt.py +++ b/pydantic_extra_types/pendulum_dt.py @@ -2,6 +2,8 @@ CoreSchema implementation. This allows Pydantic to validate the DateTime object. """ +from __future__ import annotations + try: from pendulum import Date as _Date from pendulum import DateTime as _DateTime @@ -63,7 +65,7 @@ def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaH return core_schema.no_info_wrap_validator_function(cls._validate, core_schema.datetime_schema()) @classmethod - def _validate(cls, value: Any, handler: core_schema.ValidatorFunctionWrapHandler) -> 'DateTime': + def _validate(cls, value: Any, handler: core_schema.ValidatorFunctionWrapHandler) -> DateTime: """Validate the datetime object and return it. Args: @@ -128,7 +130,7 @@ def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaH return core_schema.no_info_wrap_validator_function(cls._validate, core_schema.date_schema()) @classmethod - def _validate(cls, value: Any, handler: core_schema.ValidatorFunctionWrapHandler) -> 'Date': + def _validate(cls, value: Any, handler: core_schema.ValidatorFunctionWrapHandler) -> Date: """Validate the date object and return it. Args: @@ -187,7 +189,7 @@ def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaH return core_schema.no_info_wrap_validator_function(cls._validate, core_schema.timedelta_schema()) @classmethod - def _validate(cls, value: Any, handler: core_schema.ValidatorFunctionWrapHandler) -> 'Duration': + def _validate(cls, value: Any, handler: core_schema.ValidatorFunctionWrapHandler) -> Duration: """Validate the Duration object and return it. Args: diff --git a/pydantic_extra_types/phone_numbers.py b/pydantic_extra_types/phone_numbers.py index e405d8c..ca1ccb9 100644 --- a/pydantic_extra_types/phone_numbers.py +++ b/pydantic_extra_types/phone_numbers.py @@ -9,7 +9,7 @@ from collections.abc import Sequence from dataclasses import dataclass from functools import partial -from typing import Any, ClassVar, Optional +from typing import Any, ClassVar from pydantic import GetCoreSchemaHandler, GetJsonSchemaHandler from pydantic_core import PydanticCustomError, core_schema @@ -107,9 +107,9 @@ class SomeModel(BaseModel): us_number: USNumberType """ - default_region: Optional[str] = None + default_region: str | None = None number_format: str = 'RFC3966' - supported_regions: Optional[Sequence[str]] = None + supported_regions: Sequence[str] | None = None def __post_init__(self) -> None: if self.default_region and self.default_region not in phonenumbers.SUPPORTED_REGIONS: @@ -131,7 +131,7 @@ def __post_init__(self) -> None: def _parse( region: str | None, number_format: str, - supported_regions: Optional[Sequence[str]], + supported_regions: Sequence[str] | None, phone_number: Any, ) -> str: if not phone_number: diff --git a/pydantic_extra_types/routing_number.py b/pydantic_extra_types/routing_number.py index 912e3e8..fa9438d 100644 --- a/pydantic_extra_types/routing_number.py +++ b/pydantic_extra_types/routing_number.py @@ -2,6 +2,8 @@ [`ABARoutingNumber`][pydantic_extra_types.routing_number.ABARoutingNumber] data type. """ +from __future__ import annotations + from typing import Any, ClassVar from pydantic import GetCoreSchemaHandler @@ -54,7 +56,7 @@ def __get_pydantic_core_schema__( ) @classmethod - def _validate(cls, __input_value: str, _: core_schema.ValidationInfo) -> 'ABARoutingNumber': + def _validate(cls, __input_value: str, _: core_schema.ValidationInfo) -> ABARoutingNumber: return cls(__input_value) @classmethod diff --git a/pydantic_extra_types/semver.py b/pydantic_extra_types/semver.py index 2b58864..f53b80f 100644 --- a/pydantic_extra_types/semver.py +++ b/pydantic_extra_types/semver.py @@ -4,12 +4,13 @@ """ import warnings -from typing import Annotated, Any, Callable +from typing import Any, Callable from pydantic import GetJsonSchemaHandler from pydantic.json_schema import JsonSchemaValue from pydantic_core import core_schema from semver import Version +from typing_extensions import Annotated warnings.warn( 'Use from pydantic_extra_types.semver import SemanticVersion instead. Will be removed in 3.0.0.', DeprecationWarning diff --git a/pydantic_extra_types/timezone_name.py b/pydantic_extra_types/timezone_name.py index b33b6e6..773a612 100644 --- a/pydantic_extra_types/timezone_name.py +++ b/pydantic_extra_types/timezone_name.py @@ -57,7 +57,7 @@ def get_timezones() -> set[str]: class TimeZoneNameSettings(type): def __new__(cls, name: str, bases: tuple[type, ...], dct: dict[str, Any], **kwargs: Any) -> type[TimeZoneName]: dct['strict'] = kwargs.pop('strict', True) - return cast(type[TimeZoneName], super().__new__(cls, name, bases, dct)) + return cast('type[TimeZoneName]', super().__new__(cls, name, bases, dct)) def __init__(cls, name: str, bases: tuple[type, ...], dct: dict[str, Any], **kwargs: Any) -> None: super().__init__(name, bases, dct) diff --git a/pyproject.toml b/pyproject.toml index 8192da1..3b55e38 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -92,7 +92,7 @@ keep-runtime-typing = true [tool.ruff] line-length = 120 -target-version = "py39" +target-version = 'py38' [tool.ruff.lint] extend-select = [ diff --git a/tests/test_json_schema.py b/tests/test_json_schema.py index 96773bc..abe419e 100644 --- a/tests/test_json_schema.py +++ b/tests/test_json_schema.py @@ -3,12 +3,7 @@ import pycountry import pytest from pydantic import BaseModel - -try: - from typing import Annotated -except ImportError: - # Python 3.8 - from typing import Annotated +from typing_extensions import Annotated import pydantic_extra_types from pydantic_extra_types import epoch diff --git a/tests/test_phone_numbers_validator.py b/tests/test_phone_numbers_validator.py index e882da8..81f682c 100644 --- a/tests/test_phone_numbers_validator.py +++ b/tests/test_phone_numbers_validator.py @@ -1,16 +1,10 @@ from typing import Any, Optional, Union -try: - from typing import Annotated -except ImportError: - # Python 3.8 - from typing import Annotated - - import phonenumbers import pytest from phonenumbers import PhoneNumber from pydantic import BaseModel, TypeAdapter, ValidationError +from typing_extensions import Annotated from pydantic_extra_types.phone_numbers import PhoneNumberValidator diff --git a/uv.lock b/uv.lock index d8ad2db..765a14c 100644 --- a/uv.lock +++ b/uv.lock @@ -477,7 +477,7 @@ wheels = [ [[package]] name = "pydantic-extra-types" -version = "2.10.0" +version = "2.10.1" source = { editable = "." } dependencies = [ { name = "pydantic" },