From 145bb66fb79a33721ce3085f6f8eee91dd404a3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Fri, 10 Oct 2025 10:32:02 +0200 Subject: [PATCH] chore: add support for python 3.14, remove 3.9 --- .github/workflows/tests.yaml | 3 +- .pre-commit-config.yaml | 2 +- doc/changelog.rst | 11 + doc/tutorial.rst | 4 +- pyproject.toml | 4 +- scim2_models/attributes.py | 13 +- scim2_models/base.py | 6 +- scim2_models/messages/bulk.py | 23 +- scim2_models/messages/error.py | 7 +- scim2_models/messages/list_response.py | 11 +- scim2_models/messages/message.py | 9 +- scim2_models/messages/patch_op.py | 10 +- scim2_models/messages/search_request.py | 31 +- scim2_models/reference.py | 2 +- scim2_models/resources/enterprise_user.py | 19 +- scim2_models/resources/group.py | 14 +- scim2_models/resources/resource.py | 51 ++- scim2_models/resources/resource_type.py | 17 +- scim2_models/resources/schema.py | 38 +- .../resources/service_provider_config.py | 55 ++- scim2_models/resources/user.py | 136 +++--- scim2_models/scim_object.py | 7 +- scim2_models/urn.py | 9 +- scim2_models/utils.py | 7 +- tests/test_dynamic_resources.py | 5 +- tests/test_dynamic_schemas.py | 5 +- tests/test_list_response.py | 13 +- tests/test_model_attributes.py | 13 +- tests/test_model_serialization.py | 27 +- tests/test_model_validation.py | 25 +- tests/test_models.py | 3 +- tests/test_patch_op_extensions.py | 3 +- tests/test_patch_op_validation.py | 3 +- tests/test_reference.py | 5 +- tests/test_resource_extension.py | 14 +- tests/test_resource_type.py | 7 +- uv.lock | 418 +++--------------- 37 files changed, 349 insertions(+), 681 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index d655711..9a1e55b 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -18,11 +18,11 @@ jobs: fail-fast: false matrix: python: + - '3.14' - '3.13' - '3.12' - '3.11' - '3.10' - - '3.9' steps: - uses: actions/checkout@v4 - name: Install uv @@ -55,6 +55,7 @@ jobs: fail-fast: false matrix: python: + - '3.14' - '3.13' - '3.12' - '3.11' diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 791a645..b672b96 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,7 +3,7 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit rev: 'v0.14.0' hooks: - - id: ruff + - id: ruff-check args: [--fix, --exit-non-zero-on-fix] - id: ruff-format - repo: https://github.com/pre-commit/pre-commit-hooks diff --git a/doc/changelog.rst b/doc/changelog.rst index de075ab..3e073d9 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -1,6 +1,17 @@ Changelog ========= +[0.5.1] - Unreleased +-------------------- + +Added +^^^^^ +- Support for Python 3.14. + +Removed +^^^^^^^ +- Support for Python 3.9. + [0.5.0] - 2025-08-18 -------------------- diff --git a/doc/tutorial.rst b/doc/tutorial.rst index af4319e..bde98ff 100644 --- a/doc/tutorial.rst +++ b/doc/tutorial.rst @@ -30,8 +30,8 @@ Python models have generally the same name than in the SCIM specifications, they >>> user = User.model_validate(payload) >>> user.user_name 'bjensen@example.com' - >>> user.meta.created - datetime.datetime(2010, 1, 23, 4, 56, 22, tzinfo=TzInfo(UTC)) + >>> user.meta.created # doctest: +ELLIPSIS + datetime.datetime(2010, 1, 23, 4, 56, 22, tzinfo=...) Model serialization diff --git a/pyproject.toml b/pyproject.toml index b0b8b18..5602f40 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,7 +25,7 @@ classifiers = [ "Operating System :: OS Independent", ] -requires-python = ">= 3.9" +requires-python = ">= 3.10" dependencies = [ "pydantic[email]>=2.7.0" ] @@ -128,11 +128,11 @@ warn_required_dynamic_aliases = true requires = ["tox>=4.19"] env_list = [ "style", - "py39", "py310", "py311", "py312", "py313", + "py314", "minversions", "doc", "coverage", diff --git a/scim2_models/attributes.py b/scim2_models/attributes.py index 9f70a1e..c842687 100644 --- a/scim2_models/attributes.py +++ b/scim2_models/attributes.py @@ -1,7 +1,6 @@ from inspect import isclass from typing import Annotated from typing import Any -from typing import Optional from typing import get_origin from pydantic import Field @@ -16,7 +15,7 @@ class ComplexAttribute(BaseModel): """A complex attribute as defined in :rfc:`RFC7643 §2.3.8 <7643#section-2.3.8>`.""" - _attribute_urn: Optional[str] = None + _attribute_urn: str | None = None def get_attribute_urn(self, field_name: str) -> str: """Build the full URN of the attribute. @@ -30,20 +29,20 @@ def get_attribute_urn(self, field_name: str) -> str: class MultiValuedComplexAttribute(ComplexAttribute): - type: Optional[str] = None + type: str | None = None """A label indicating the attribute's function.""" - primary: Optional[bool] = None + primary: bool | None = None """A Boolean value indicating the 'primary' or preferred attribute value for this attribute.""" - display: Annotated[Optional[str], Mutability.immutable] = None + display: Annotated[str | None, Mutability.immutable] = None """A human-readable name, primarily used for display purposes.""" - value: Optional[Any] = None + value: Any | None = None """The value of an entitlement.""" - ref: Optional[Reference[Any]] = Field(None, serialization_alias="$ref") + ref: Reference[Any] | None = Field(None, serialization_alias="$ref") """The reference URI of a target resource, if the attribute is a reference.""" diff --git a/scim2_models/base.py b/scim2_models/base.py index 53c5d98..75f62d2 100644 --- a/scim2_models/base.py +++ b/scim2_models/base.py @@ -96,7 +96,7 @@ def annotation_type_filter(item: Any) -> bool: return field_annotation @classmethod - def get_field_root_type(cls, attribute_name: str) -> Optional[type]: + def get_field_root_type(cls, attribute_name: str) -> type | None: """Extract the root type from a model field. This method unwraps complex type annotations to find the underlying @@ -244,7 +244,7 @@ def normalize_dict_keys( return result def normalize_value( - val: Any, model_class: Optional[type["BaseModel"]] = None + val: Any, model_class: type["BaseModel"] | None = None ) -> Any: """Normalize input value based on model class.""" if not isinstance(val, dict): @@ -504,7 +504,7 @@ def model_serializer_exclude_none( def model_validate( cls, *args: Any, - scim_ctx: Optional[Context] = Context.DEFAULT, + scim_ctx: Context | None = Context.DEFAULT, original: Optional["BaseModel"] = None, **kwargs: Any, ) -> Self: diff --git a/scim2_models/messages/bulk.py b/scim2_models/messages/bulk.py index f36ccfc..cf68a86 100644 --- a/scim2_models/messages/bulk.py +++ b/scim2_models/messages/bulk.py @@ -1,7 +1,6 @@ from enum import Enum from typing import Annotated from typing import Any -from typing import Optional from pydantic import Field from pydantic import PlainSerializer @@ -19,30 +18,30 @@ class Method(str, Enum): patch = "PATCH" delete = "DELETE" - method: Optional[Method] = None + method: Method | None = None """The HTTP method of the current operation.""" - bulk_id: Optional[str] = None + bulk_id: str | None = None """The transient identifier of a newly created resource, unique within a bulk request and created by the client.""" - version: Optional[str] = None + version: str | None = None """The current resource version.""" - path: Optional[str] = None + path: str | None = None """The resource's relative path to the SCIM service provider's root.""" - data: Optional[Any] = None + data: Any | None = None """The resource data as it would appear for a single SCIM POST, PUT, or PATCH operation.""" - location: Optional[str] = None + location: str | None = None """The resource endpoint URL.""" - response: Optional[Any] = None + response: Any | None = None """The HTTP response body for the specified request operation.""" - status: Annotated[Optional[int], PlainSerializer(_int_to_str)] = None + status: Annotated[int | None, PlainSerializer(_int_to_str)] = None """The HTTP response status code for the requested operation.""" @@ -58,12 +57,12 @@ class BulkRequest(Message): "urn:ietf:params:scim:api:messages:2.0:BulkRequest" ] - fail_on_errors: Optional[int] = None + fail_on_errors: int | None = None """An integer specifying the number of errors that the service provider will accept before the operation is terminated and an error response is returned.""" - operations: Optional[list[BulkOperation]] = Field( + operations: list[BulkOperation] | None = Field( None, serialization_alias="Operations" ) """Defines operations within a bulk job.""" @@ -81,7 +80,7 @@ class BulkResponse(Message): "urn:ietf:params:scim:api:messages:2.0:BulkResponse" ] - operations: Optional[list[BulkOperation]] = Field( + operations: list[BulkOperation] | None = Field( None, serialization_alias="Operations" ) """Defines operations within a bulk job.""" diff --git a/scim2_models/messages/error.py b/scim2_models/messages/error.py index bb72e68..7ed465e 100644 --- a/scim2_models/messages/error.py +++ b/scim2_models/messages/error.py @@ -1,5 +1,4 @@ from typing import Annotated -from typing import Optional from pydantic import PlainSerializer @@ -15,14 +14,14 @@ class Error(Message): "urn:ietf:params:scim:api:messages:2.0:Error" ] - status: Annotated[Optional[int], PlainSerializer(_int_to_str)] = None + status: Annotated[int | None, PlainSerializer(_int_to_str)] = None """The HTTP status code (see Section 6 of [RFC7231]) expressed as a JSON string.""" - scim_type: Optional[str] = None + scim_type: str | None = None """A SCIM detail error keyword.""" - detail: Optional[str] = None + detail: str | None = None """A detailed human-readable message.""" @classmethod diff --git a/scim2_models/messages/list_response.py b/scim2_models/messages/list_response.py index 84dda9c..402773e 100644 --- a/scim2_models/messages/list_response.py +++ b/scim2_models/messages/list_response.py @@ -1,7 +1,6 @@ from typing import Annotated from typing import Any from typing import Generic -from typing import Optional from pydantic import Field from pydantic import ValidationInfo @@ -22,19 +21,17 @@ class ListResponse(Message, Generic[AnyResource], metaclass=_GenericMessageMetac "urn:ietf:params:scim:api:messages:2.0:ListResponse" ] - total_results: Optional[int] = None + total_results: int | None = None """The total number of results returned by the list or query operation.""" - start_index: Optional[int] = None + start_index: int | None = None """The 1-based index of the first result in the current set of list results.""" - items_per_page: Optional[int] = None + items_per_page: int | None = None """The number of resources returned in a list response page.""" - resources: Optional[list[AnyResource]] = Field( - None, serialization_alias="Resources" - ) + resources: list[AnyResource] | None = Field(None, serialization_alias="Resources") """A multi-valued list of complex objects containing the requested resources.""" diff --git a/scim2_models/messages/message.py b/scim2_models/messages/message.py index 93ee31c..f22f274 100644 --- a/scim2_models/messages/message.py +++ b/scim2_models/messages/message.py @@ -1,7 +1,6 @@ +from collections.abc import Callable from typing import Annotated from typing import Any -from typing import Callable -from typing import Optional from typing import Union from typing import get_args from typing import get_origin @@ -23,14 +22,14 @@ class Message(ScimObject): def _create_schema_discriminator( resource_types_schemas: list[str], -) -> Callable[[Any], Optional[str]]: +) -> Callable[[Any], str | None]: """Create a schema discriminator function for the given resource schemas. :param resource_types_schemas: List of valid resource schemas :return: Discriminator function for Pydantic """ - def get_schema_from_payload(payload: Any) -> Optional[str]: + def get_schema_from_payload(payload: Any) -> str | None: """Extract schema from SCIM payload for discrimination. :param payload: SCIM payload dict or object @@ -89,7 +88,7 @@ def _create_tagged_resource_union(resource_union: Any) -> Any: for resource_type in resource_types ] # Dynamic union construction from tuple - MyPy can't validate this at compile time - union = Union[tuple(tagged_resources)] # type: ignore + union = Union[tuple(tagged_resources)] # type: ignore # noqa: UP007 return Annotated[union, discriminator] diff --git a/scim2_models/messages/patch_op.py b/scim2_models/messages/patch_op.py index 026c1fe..b5a7876 100644 --- a/scim2_models/messages/patch_op.py +++ b/scim2_models/messages/patch_op.py @@ -3,9 +3,7 @@ from typing import Annotated from typing import Any from typing import Generic -from typing import Optional from typing import TypeVar -from typing import Union from pydantic import Field from pydantic import ValidationInfo @@ -48,7 +46,7 @@ class Op(str, Enum): despite :rfc:`RFC7644 §3.5.2 <7644#section-3.5.2>`, op is case-insensitive. """ - path: Optional[str] = None + path: str | None = None """The "path" attribute value is a String containing an attribute path describing the target of the operation.""" @@ -113,7 +111,7 @@ def validate_operation_requirements(self, info: ValidationInfo) -> Self: return self - value: Optional[Any] = None + value: Any | None = None @field_validator("op", mode="before") @classmethod @@ -165,7 +163,7 @@ def __new__(cls, *args: Any, **kwargs: Any) -> Self: return super().__new__(cls) def __class_getitem__( - cls, typevar_values: Union[type[Resource[Any]], tuple[type[Resource[Any]], ...]] + cls, typevar_values: type[Resource[Any]] | tuple[type[Resource[Any]], ...] ) -> Any: """Validate type parameter when creating parameterized type. @@ -211,7 +209,7 @@ def __class_getitem__( "urn:ietf:params:scim:api:messages:2.0:PatchOp" ] - operations: Annotated[Optional[list[PatchOperation]], Required.true] = Field( + operations: Annotated[list[PatchOperation] | None, Required.true] = Field( None, serialization_alias="Operations", min_length=1 ) """The body of an HTTP PATCH request MUST contain the attribute diff --git a/scim2_models/messages/search_request.py b/scim2_models/messages/search_request.py index 2133098..ccadaaf 100644 --- a/scim2_models/messages/search_request.py +++ b/scim2_models/messages/search_request.py @@ -1,6 +1,5 @@ from enum import Enum from typing import Annotated -from typing import Optional from pydantic import field_validator from pydantic import model_validator @@ -21,14 +20,14 @@ class SearchRequest(Message): "urn:ietf:params:scim:api:messages:2.0:SearchRequest" ] - attributes: Optional[list[str]] = None + attributes: list[str] | None = None """A multi-valued list of strings indicating the names of resource attributes to return in the response, overriding the set of attributes that would be returned by default.""" @field_validator("attributes") @classmethod - def validate_attributes_syntax(cls, v: Optional[list[str]]) -> Optional[list[str]]: + def validate_attributes_syntax(cls, v: list[str] | None) -> list[str] | None: """Validate syntax of attribute paths.""" if v is None: return v @@ -39,15 +38,15 @@ def validate_attributes_syntax(cls, v: Optional[list[str]]) -> Optional[list[str return v - excluded_attributes: Optional[list[str]] = None + excluded_attributes: list[str] | None = None """A multi-valued list of strings indicating the names of resource attributes to be removed from the default set of attributes to return.""" @field_validator("excluded_attributes") @classmethod def validate_excluded_attributes_syntax( - cls, v: Optional[list[str]] - ) -> Optional[list[str]]: + cls, v: list[str] | None + ) -> list[str] | None: """Validate syntax of excluded attribute paths.""" if v is None: return v @@ -58,16 +57,16 @@ def validate_excluded_attributes_syntax( return v - filter: Optional[str] = None + filter: str | None = None """The filter string used to request a subset of resources.""" - sort_by: Optional[str] = None + sort_by: str | None = None """A string indicating the attribute whose value SHALL be used to order the returned responses.""" @field_validator("sort_by") @classmethod - def validate_sort_by_syntax(cls, v: Optional[str]) -> Optional[str]: + def validate_sort_by_syntax(cls, v: str | None) -> str | None: """Validate syntax of sort_by attribute path. :param v: The sort_by attribute path to validate @@ -86,29 +85,29 @@ class SortOrder(str, Enum): ascending = "ascending" descending = "descending" - sort_order: Optional[SortOrder] = None + sort_order: SortOrder | None = None """A string indicating the order in which the "sortBy" parameter is applied.""" - start_index: Optional[int] = None + start_index: int | None = None """An integer indicating the 1-based index of the first query result.""" @field_validator("start_index") @classmethod - def start_index_floor(cls, value: Optional[int]) -> Optional[int]: + def start_index_floor(cls, value: int | None) -> int | None: """According to :rfc:`RFC7644 §3.4.2 <7644#section-3.4.2.4>, start_index values less than 1 are interpreted as 1. A value less than 1 SHALL be interpreted as 1. """ return None if value is None else max(1, value) - count: Optional[int] = None + count: int | None = None """An integer indicating the desired maximum number of query results per page.""" @field_validator("count") @classmethod - def count_floor(cls, value: Optional[int]) -> Optional[int]: + def count_floor(cls, value: int | None) -> int | None: """According to :rfc:`RFC7644 §3.4.2 <7644#section-3.4.2.4>, count values less than 0 are interpreted as 0. A negative value SHALL be interpreted as 0. @@ -125,12 +124,12 @@ def attributes_validator(self) -> "SearchRequest": return self @property - def start_index_0(self) -> Optional[int]: + def start_index_0(self) -> int | None: """The 0 indexed start index.""" return self.start_index - 1 if self.start_index is not None else None @property - def stop_index_0(self) -> Optional[int]: + def stop_index_0(self) -> int | None: """The 0 indexed stop index.""" return ( self.start_index_0 + self.count diff --git a/scim2_models/reference.py b/scim2_models/reference.py index 2321e57..3b8171e 100644 --- a/scim2_models/reference.py +++ b/scim2_models/reference.py @@ -1,13 +1,13 @@ from collections import UserString from typing import Any from typing import Generic +from typing import NewType from typing import TypeVar from typing import get_args from typing import get_origin from pydantic import GetCoreSchemaHandler from pydantic_core import core_schema -from typing_extensions import NewType from .utils import UNION_TYPES diff --git a/scim2_models/resources/enterprise_user.py b/scim2_models/resources/enterprise_user.py index 64fbe3e..9b47afa 100644 --- a/scim2_models/resources/enterprise_user.py +++ b/scim2_models/resources/enterprise_user.py @@ -1,6 +1,5 @@ from typing import Annotated from typing import Literal -from typing import Optional from pydantic import Field @@ -12,16 +11,16 @@ class Manager(ComplexAttribute): - value: Annotated[Optional[str], Required.true] = None + value: Annotated[str | None, Required.true] = None """The id of the SCIM resource representing the User's manager.""" - ref: Annotated[Optional[Reference[Literal["User"]]], Required.true] = Field( + ref: Annotated[Reference[Literal["User"]] | None, Required.true] = Field( None, serialization_alias="$ref", ) """The URI of the SCIM resource representing the User's manager.""" - display_name: Annotated[Optional[str], Mutability.read_only] = None + display_name: Annotated[str | None, Mutability.read_only] = None """The displayName of the User's manager.""" @@ -30,24 +29,24 @@ class EnterpriseUser(Extension): "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User" ] - employee_number: Optional[str] = None + employee_number: str | None = None """Numeric or alphanumeric identifier assigned to a person, typically based on order of hire or association with an organization.""" - cost_center: Optional[str] = None + cost_center: str | None = None """"Identifies the name of a cost center.""" - organization: Optional[str] = None + organization: str | None = None """Identifies the name of an organization.""" - division: Optional[str] = None + division: str | None = None """Identifies the name of a division.""" - department: Optional[str] = None + department: str | None = None """Numeric or alphanumeric identifier assigned to a person, typically based on order of hire or association with an organization.""" - manager: Optional[Manager] = None + manager: Manager | None = None """The User's manager. A complex type that optionally allows service providers to represent diff --git a/scim2_models/resources/group.py b/scim2_models/resources/group.py index 639cd60..aef5cc9 100644 --- a/scim2_models/resources/group.py +++ b/scim2_models/resources/group.py @@ -2,8 +2,6 @@ from typing import Any from typing import ClassVar from typing import Literal -from typing import Optional -from typing import Union from pydantic import Field @@ -15,22 +13,22 @@ class GroupMember(ComplexAttribute): - value: Annotated[Optional[str], Mutability.immutable] = None + value: Annotated[str | None, Mutability.immutable] = None """Identifier of the member of this Group.""" ref: Annotated[ - Optional[Reference[Union[Literal["User"], Literal["Group"]]]], + Reference[Literal["User"] | Literal["Group"]] | None, Mutability.immutable, ] = Field(None, serialization_alias="$ref") """The reference URI of a target resource, if the attribute is a reference.""" - type: Annotated[Optional[str], Mutability.immutable] = Field( + type: Annotated[str | None, Mutability.immutable] = Field( None, examples=["User", "Group"] ) """A label indicating the attribute's function, e.g., "work" or "home".""" - display: Annotated[Optional[str], Mutability.read_only] = None + display: Annotated[str | None, Mutability.read_only] = None class Group(Resource[Any]): @@ -38,10 +36,10 @@ class Group(Resource[Any]): "urn:ietf:params:scim:schemas:core:2.0:Group" ] - display_name: Optional[str] = None + display_name: str | None = None """A human-readable name for the Group.""" - members: Optional[list[GroupMember]] = None + members: list[GroupMember] | None = None """A list of members of the Group.""" Members: ClassVar[type[ComplexAttribute]] = GroupMember diff --git a/scim2_models/resources/resource.py b/scim2_models/resources/resource.py index 60a5ae1..90b295c 100644 --- a/scim2_models/resources/resource.py +++ b/scim2_models/resources/resource.py @@ -3,7 +3,6 @@ from typing import Annotated from typing import Any from typing import Generic -from typing import Optional from typing import TypeVar from typing import Union from typing import cast @@ -42,20 +41,20 @@ class Meta(ComplexAttribute): This attribute SHALL be ignored when provided by clients. "meta" contains the following sub-attributes: """ - resource_type: Optional[str] = None + resource_type: str | None = None """The name of the resource type of the resource. This attribute has a mutability of "readOnly" and "caseExact" as "true". """ - created: Optional[datetime] = None + created: datetime | None = None """The "DateTime" that the resource was added to the service provider. This attribute MUST be a DateTime. """ - last_modified: Optional[datetime] = None + last_modified: datetime | None = None """The most recent DateTime that the details of this resource were updated at the service provider. @@ -63,14 +62,14 @@ class Meta(ComplexAttribute): the value MUST be the same as the value of "created". """ - location: Optional[str] = None + location: str | None = None """The URI of the resource being returned. This value MUST be the same as the "Content-Location" HTTP response header (see Section 3.1.4.2 of [RFC7231]). """ - version: Optional[str] = None + version: str | None = None """The version of the resource being returned. This value must be the same as the entity-tag (ETag) HTTP response @@ -108,7 +107,7 @@ def from_schema(cls, schema: "Schema") -> type["Extension"]: def _extension_serializer( value: Any, handler: SerializerFunctionWrapHandler, info: SerializationInfo -) -> Optional[dict[str, Any]]: +) -> dict[str, Any] | None: """Exclude the Resource attributes from the extension dump. For instance, attributes 'meta', 'id' or 'schemas' should not be @@ -128,7 +127,7 @@ class Resource(ScimObject, Generic[AnyExtension]): # https://www.rfc-editor.org/rfc/rfc7643#section-3.1 id: Annotated[ - Optional[str], Mutability.read_only, Returned.always, Uniqueness.global_ + str | None, Mutability.read_only, Returned.always, Uniqueness.global_ ] = None """A unique identifier for a SCIM resource as defined by the service provider. @@ -138,12 +137,12 @@ class Resource(ScimObject, Generic[AnyExtension]): """ external_id: Annotated[ - Optional[str], Mutability.read_write, Returned.default, CaseExact.true + str | None, Mutability.read_write, Returned.default, CaseExact.true ] = None """A String that is an identifier for the resource as defined by the provisioning client.""" - meta: Annotated[Optional[Meta], Mutability.read_only, Returned.default] = None + meta: Annotated[Meta | None, Mutability.read_only, Returned.default] = None """A complex attribute containing resource metadata.""" @classmethod @@ -188,7 +187,7 @@ def __class_getitem__(cls, item: Any) -> type["Resource[Any]"]: new_annotations = { extension.__name__: Annotated[ - Optional[extension], + extension | None, WrapSerializer(_extension_serializer), ] for extension in valid_extensions @@ -207,11 +206,11 @@ def __class_getitem__(cls, item: Any) -> type["Resource[Any]"]: return new_class - def __getitem__(self, item: Any) -> Optional[Extension]: + def __getitem__(self, item: Any) -> Extension | None: if not isinstance(item, type) or not issubclass(item, Extension): raise KeyError(f"{item} is not a valid extension type") - return cast(Optional[Extension], getattr(self, item.__name__)) + return cast(Extension | None, getattr(self, item.__name__)) def __setitem__(self, item: Any, value: "Extension") -> None: if not isinstance(item, type) or not issubclass(item, Extension): @@ -231,7 +230,7 @@ def get_extension_models(cls) -> dict[str, type[Extension]]: @classmethod def get_extension_model( cls, name_or_schema: Union[str, "Schema"] - ) -> Optional[type[Extension]]: + ) -> type[Extension] | None: """Return an extension by its name or schema.""" for schema, extension in cls.get_extension_models().items(): if schema == name_or_schema or extension.__name__ == name_or_schema: @@ -243,9 +242,9 @@ def get_by_schema( resource_types: list[type["Resource[Any]"]], schema: str, with_extensions: bool = True, - ) -> Optional[Union[type["Resource[Any]"], type["Extension"]]]: + ) -> type["Resource[Any]"] | type["Extension"] | None: """Given a resource type list and a schema, find the matching resource type.""" - by_schema: dict[str, Union[type[Resource[Any]], type[Extension]]] = { + by_schema: dict[str, type[Resource[Any]] | type[Extension]] = { resource_type.model_fields["schemas"].default[0].lower(): resource_type for resource_type in (resource_types or []) } @@ -265,7 +264,7 @@ def get_by_payload( resource_types: list[type["Resource[Any]"]], payload: dict[str, Any], **kwargs: Any, - ) -> Optional[type]: + ) -> type | None: """Given a resource type list and a payload, find the matching resource type.""" if not payload or not payload.get("schemas"): return None @@ -298,9 +297,9 @@ def from_schema(cls, schema: "Schema") -> type["Resource[Any]"]: def _prepare_model_dump( self, - scim_ctx: Optional[Context] = Context.DEFAULT, - attributes: Optional[list[str]] = None, - excluded_attributes: Optional[list[str]] = None, + scim_ctx: Context | None = Context.DEFAULT, + attributes: list[str] | None = None, + excluded_attributes: list[str] | None = None, **kwargs: Any, ) -> dict[str, Any]: kwargs = super()._prepare_model_dump(scim_ctx, **kwargs) @@ -323,9 +322,9 @@ def _prepare_model_dump( def model_dump( self, *args: Any, - scim_ctx: Optional[Context] = Context.DEFAULT, - attributes: Optional[list[str]] = None, - excluded_attributes: Optional[list[str]] = None, + scim_ctx: Context | None = Context.DEFAULT, + attributes: list[str] | None = None, + excluded_attributes: list[str] | None = None, **kwargs: Any, ) -> dict[str, Any]: """Create a model representation that can be included in SCIM messages by using Pydantic :code:`BaseModel.model_dump`. @@ -349,9 +348,9 @@ def model_dump( def model_dump_json( self, *args: Any, - scim_ctx: Optional[Context] = Context.DEFAULT, - attributes: Optional[list[str]] = None, - excluded_attributes: Optional[list[str]] = None, + scim_ctx: Context | None = Context.DEFAULT, + attributes: list[str] | None = None, + excluded_attributes: list[str] | None = None, **kwargs: Any, ) -> str: """Create a JSON model representation that can be included in SCIM messages by using Pydantic :code:`BaseModel.model_dump_json`. diff --git a/scim2_models/resources/resource_type.py b/scim2_models/resources/resource_type.py index c230c8a..0b6f521 100644 --- a/scim2_models/resources/resource_type.py +++ b/scim2_models/resources/resource_type.py @@ -1,6 +1,5 @@ from typing import Annotated from typing import Any -from typing import Optional from pydantic import Field from typing_extensions import Self @@ -17,14 +16,14 @@ class SchemaExtension(ComplexAttribute): schema_: Annotated[ - Optional[Reference[URIReference]], + Reference[URIReference] | None, Mutability.read_only, Required.true, CaseExact.true, ] = Field(None, alias="schema") """The URI of a schema extension.""" - required: Annotated[Optional[bool], Mutability.read_only, Required.true] = None + required: Annotated[bool | None, Mutability.read_only, Required.true] = None """A Boolean value that specifies whether or not the schema extension is required for the resource type. @@ -40,33 +39,33 @@ class ResourceType(Resource[Any]): "urn:ietf:params:scim:schemas:core:2.0:ResourceType" ] - name: Annotated[Optional[str], Mutability.read_only, Required.true] = None + name: Annotated[str | None, Mutability.read_only, Required.true] = None """The resource type name. When applicable, service providers MUST specify the name, e.g., 'User'. """ - description: Annotated[Optional[str], Mutability.read_only] = None + description: Annotated[str | None, Mutability.read_only] = None """The resource type's human-readable description. When applicable, service providers MUST specify the description. """ - id: Annotated[Optional[str], Mutability.read_only, Returned.default] = None + id: Annotated[str | None, Mutability.read_only, Returned.default] = None """The resource type's server unique id. This is often the same value as the "name" attribute. """ endpoint: Annotated[ - Optional[Reference[URIReference]], Mutability.read_only, Required.true + Reference[URIReference] | None, Mutability.read_only, Required.true ] = None """The resource type's HTTP-addressable endpoint relative to the Base URL, e.g., '/Users'.""" schema_: Annotated[ - Optional[Reference[URIReference]], + Reference[URIReference] | None, Mutability.read_only, Required.true, CaseExact.true, @@ -74,7 +73,7 @@ class ResourceType(Resource[Any]): """The resource type's primary/base schema URI.""" schema_extensions: Annotated[ - Optional[list[SchemaExtension]], Mutability.read_only, Required.true + list[SchemaExtension] | None, Mutability.read_only, Required.true ] = None """A list of URIs of the resource type's schema extensions.""" diff --git a/scim2_models/resources/schema.py b/scim2_models/resources/schema.py index 499a895..0f3c710 100644 --- a/scim2_models/resources/schema.py +++ b/scim2_models/resources/schema.py @@ -97,7 +97,7 @@ class Type(str, Enum): def _to_python( self, - reference_types: Optional[list[str]] = None, + reference_types: list[str] | None = None, ) -> type: if self.value == self.reference and reference_types is not None: if reference_types == ["external"]: @@ -107,7 +107,7 @@ def _to_python( return Reference[URIReference] types = tuple(Literal[t] for t in reference_types) - return Reference[Union[types]] # type: ignore + return Reference[Union[types]] # type: ignore # noqa: UP007 attr_types = { self.string: str, @@ -118,7 +118,7 @@ def _to_python( self.binary: Base64Bytes, self.complex: ComplexAttribute, } - return attr_types[self.value] + return attr_types[self] @classmethod def from_python(cls, pytype: type) -> "Attribute.Type": @@ -141,21 +141,21 @@ def from_python(cls, pytype: type) -> "Attribute.Type": } return attr_types.get(pytype, cls.string) - name: Annotated[ - Optional[str], Mutability.read_only, Required.true, CaseExact.true - ] = None + name: Annotated[str | None, Mutability.read_only, Required.true, CaseExact.true] = ( + None + ) """The attribute's name.""" - type: Annotated[Optional[Type], Mutability.read_only, Required.true] = Field( + type: Annotated[Type | None, Mutability.read_only, Required.true] = Field( None, examples=[item.value for item in Type] ) """The attribute's data type.""" - multi_valued: Annotated[Optional[bool], Mutability.read_only, Required.true] = None + multi_valued: Annotated[bool | None, Mutability.read_only, Required.true] = None """A Boolean value indicating the attribute's plurality.""" description: Annotated[ - Optional[str], Mutability.read_only, Required.false, CaseExact.true + str | None, Mutability.read_only, Required.false, CaseExact.true ] = None """The attribute's human-readable description.""" @@ -164,7 +164,7 @@ def from_python(cls, pytype: type) -> "Attribute.Type": required.""" canonical_values: Annotated[ - Optional[list[str]], Mutability.read_only, CaseExact.true + list[str] | None, Mutability.read_only, CaseExact.true ] = None """A collection of suggested canonical values that MAY be used (e.g., "work" and "home").""" @@ -195,17 +195,17 @@ def from_python(cls, pytype: type) -> "Attribute.Type": uniqueness of attribute values.""" reference_types: Annotated[ - Optional[list[str]], Mutability.read_only, Required.false, CaseExact.true + list[str] | None, Mutability.read_only, Required.false, CaseExact.true ] = None """A multi-valued array of JSON strings that indicate the SCIM resource types that may be referenced.""" # for python 3.9 and 3.10 compatibility, this should be 'list' and not 'List' - sub_attributes: Annotated[Optional[List["Attribute"]], Mutability.read_only] = None # noqa: UP006 + sub_attributes: Annotated[List["Attribute"] | None, Mutability.read_only] = None # noqa: UP006 """When an attribute is of type "complex", "subAttributes" defines a set of sub-attributes.""" - def _to_python(self) -> Optional[tuple[Any, Any]]: + def _to_python(self) -> tuple[Any, Any] | None: """Build tuple suited to be passed to pydantic 'create_model'.""" if not self.name or not self.type: return None @@ -219,7 +219,7 @@ def _to_python(self) -> Optional[tuple[Any, Any]]: attr_type = list[attr_type] # type: ignore annotation = Annotated[ - Optional[attr_type], # type: ignore + attr_type | None, # type: ignore self.required, self.case_exact, self.mutability, @@ -256,19 +256,19 @@ class Schema(Resource[Any]): "urn:ietf:params:scim:schemas:core:2.0:Schema" ] - id: Annotated[Optional[str], Mutability.read_only, Required.true] = None + id: Annotated[str | None, Mutability.read_only, Required.true] = None """The unique URI of the schema.""" name: Annotated[ - Optional[str], Mutability.read_only, Returned.default, Required.true + str | None, Mutability.read_only, Returned.default, Required.true ] = None """The schema's human-readable name.""" - description: Annotated[Optional[str], Mutability.read_only, Returned.default] = None + description: Annotated[str | None, Mutability.read_only, Returned.default] = None """The schema's human-readable description.""" attributes: Annotated[ - Optional[list[Attribute]], Mutability.read_only, Required.true + list[Attribute] | None, Mutability.read_only, Required.true ] = None """A complex type that defines service provider attributes and their qualities via the following set of sub-attributes.""" @@ -279,7 +279,7 @@ def urn_id(cls, value: str) -> str: """Ensure that schema ids are URI, as defined in RFC7643 §7.""" return str(Url(value)) - def get_attribute(self, attribute_name: str) -> Optional[Attribute]: + def get_attribute(self, attribute_name: str) -> Attribute | None: """Find an attribute by its name.""" for attribute in self.attributes or []: if attribute.name == attribute_name: diff --git a/scim2_models/resources/service_provider_config.py b/scim2_models/resources/service_provider_config.py index 9911bdd..59f1952 100644 --- a/scim2_models/resources/service_provider_config.py +++ b/scim2_models/resources/service_provider_config.py @@ -1,7 +1,6 @@ from enum import Enum from typing import Annotated from typing import Any -from typing import Optional from pydantic import Field @@ -16,43 +15,41 @@ class Patch(ComplexAttribute): - supported: Annotated[Optional[bool], Mutability.read_only, Required.true] = None + supported: Annotated[bool | None, Mutability.read_only, Required.true] = None """A Boolean value specifying whether or not the operation is supported.""" class Bulk(ComplexAttribute): - supported: Annotated[Optional[bool], Mutability.read_only, Required.true] = None + supported: Annotated[bool | None, Mutability.read_only, Required.true] = None """A Boolean value specifying whether or not the operation is supported.""" - max_operations: Annotated[Optional[int], Mutability.read_only, Required.true] = None + max_operations: Annotated[int | None, Mutability.read_only, Required.true] = None """An integer value specifying the maximum number of operations.""" - max_payload_size: Annotated[Optional[int], Mutability.read_only, Required.true] = ( - None - ) + max_payload_size: Annotated[int | None, Mutability.read_only, Required.true] = None """An integer value specifying the maximum payload size in bytes.""" class Filter(ComplexAttribute): - supported: Annotated[Optional[bool], Mutability.read_only, Required.true] = None + supported: Annotated[bool | None, Mutability.read_only, Required.true] = None """A Boolean value specifying whether or not the operation is supported.""" - max_results: Annotated[Optional[int], Mutability.read_only, Required.true] = None + max_results: Annotated[int | None, Mutability.read_only, Required.true] = None """An integer value specifying the maximum number of resources returned in a response.""" class ChangePassword(ComplexAttribute): - supported: Annotated[Optional[bool], Mutability.read_only, Required.true] = None + supported: Annotated[bool | None, Mutability.read_only, Required.true] = None """A Boolean value specifying whether or not the operation is supported.""" class Sort(ComplexAttribute): - supported: Annotated[Optional[bool], Mutability.read_only, Required.true] = None + supported: Annotated[bool | None, Mutability.read_only, Required.true] = None """A Boolean value specifying whether or not the operation is supported.""" class ETag(ComplexAttribute): - supported: Annotated[Optional[bool], Mutability.read_only, Required.true] = None + supported: Annotated[bool | None, Mutability.read_only, Required.true] = None """A Boolean value specifying whether or not the operation is supported.""" @@ -64,31 +61,31 @@ class Type(str, Enum): httpbasic = "httpbasic" httpdigest = "httpdigest" - type: Annotated[Optional[Type], Mutability.read_only, Required.true] = Field( + type: Annotated[Type | None, Mutability.read_only, Required.true] = Field( None, examples=["oauth", "oauth2", "oauthbearertoken", "httpbasic", "httpdigest"], ) """The authentication scheme.""" - name: Annotated[Optional[str], Mutability.read_only, Required.true] = None + name: Annotated[str | None, Mutability.read_only, Required.true] = None """The common authentication scheme name, e.g., HTTP Basic.""" - description: Annotated[Optional[str], Mutability.read_only, Required.true] = None + description: Annotated[str | None, Mutability.read_only, Required.true] = None """A description of the authentication scheme.""" - spec_uri: Annotated[ - Optional[Reference[ExternalReference]], Mutability.read_only - ] = None + spec_uri: Annotated[Reference[ExternalReference] | None, Mutability.read_only] = ( + None + ) """An HTTP-addressable URL pointing to the authentication scheme's specification.""" documentation_uri: Annotated[ - Optional[Reference[ExternalReference]], Mutability.read_only + Reference[ExternalReference] | None, Mutability.read_only ] = None """An HTTP-addressable URL pointing to the authentication scheme's usage documentation.""" - primary: Annotated[Optional[bool], Mutability.read_only] = None + primary: Annotated[bool | None, Mutability.read_only] = None """A Boolean value indicating the 'primary' or preferred attribute value for this attribute, e.g., the preferred mailing address or primary email address.""" @@ -100,7 +97,7 @@ class ServiceProviderConfig(Resource[Any]): ] id: Annotated[ - Optional[str], Mutability.read_only, Returned.default, Uniqueness.global_ + str | None, Mutability.read_only, Returned.default, Uniqueness.global_ ] = None """A unique identifier for a SCIM resource as defined by the service provider.""" @@ -110,34 +107,34 @@ class ServiceProviderConfig(Resource[Any]): # provider configuration resource documentation_uri: Annotated[ - Optional[Reference[ExternalReference]], Mutability.read_only + Reference[ExternalReference] | None, Mutability.read_only ] = None """An HTTP-addressable URL pointing to the service provider's human- consumable help documentation.""" - patch: Annotated[Optional[Patch], Mutability.read_only, Required.true] = None + patch: Annotated[Patch | None, Mutability.read_only, Required.true] = None """A complex type that specifies PATCH configuration options.""" - bulk: Annotated[Optional[Bulk], Mutability.read_only, Required.true] = None + bulk: Annotated[Bulk | None, Mutability.read_only, Required.true] = None """A complex type that specifies bulk configuration options.""" - filter: Annotated[Optional[Filter], Mutability.read_only, Required.true] = None + filter: Annotated[Filter | None, Mutability.read_only, Required.true] = None """A complex type that specifies FILTER options.""" change_password: Annotated[ - Optional[ChangePassword], Mutability.read_only, Required.true + ChangePassword | None, Mutability.read_only, Required.true ] = None """A complex type that specifies configuration options related to changing a password.""" - sort: Annotated[Optional[Sort], Mutability.read_only, Required.true] = None + sort: Annotated[Sort | None, Mutability.read_only, Required.true] = None """A complex type that specifies sort result options.""" - etag: Annotated[Optional[ETag], Mutability.read_only, Required.true] = None + etag: Annotated[ETag | None, Mutability.read_only, Required.true] = None """A complex type that specifies ETag configuration options.""" authentication_schemes: Annotated[ - Optional[list[AuthenticationScheme]], Mutability.read_only, Required.true + list[AuthenticationScheme] | None, Mutability.read_only, Required.true ] = None """A complex type that specifies supported authentication scheme properties.""" diff --git a/scim2_models/resources/user.py b/scim2_models/resources/user.py index deefb89..c14ca2a 100644 --- a/scim2_models/resources/user.py +++ b/scim2_models/resources/user.py @@ -2,8 +2,6 @@ from typing import Annotated from typing import ClassVar from typing import Literal -from typing import Optional -from typing import Union from pydantic import EmailStr from pydantic import Field @@ -22,27 +20,27 @@ class Name(ComplexAttribute): - formatted: Optional[str] = None + formatted: str | None = None """The full name, including all middle names, titles, and suffixes as appropriate, formatted for display (e.g., 'Ms. Barbara J Jensen, III').""" - family_name: Optional[str] = None + family_name: str | None = None """The family name of the User, or last name in most Western languages (e.g., 'Jensen' given the full name 'Ms. Barbara J Jensen, III').""" - given_name: Optional[str] = None + given_name: str | None = None """The given name of the User, or first name in most Western languages (e.g., 'Barbara' given the full name 'Ms. Barbara J Jensen, III').""" - middle_name: Optional[str] = None + middle_name: str | None = None """The middle name(s) of the User (e.g., 'Jane' given the full name 'Ms. Barbara J Jensen, III').""" - honorific_prefix: Optional[str] = None + honorific_prefix: str | None = None """The honorific prefix(es) of the User, or title in most Western languages (e.g., 'Ms.' given the full name 'Ms. Barbara J Jensen, III').""" - honorific_suffix: Optional[str] = None + honorific_suffix: str | None = None """The honorific suffix(es) of the User, or suffix in most Western languages (e.g., 'III' given the full name 'Ms. Barbara J Jensen, III').""" @@ -53,16 +51,16 @@ class Type(str, Enum): home = "home" other = "other" - value: Optional[EmailStr] = None + value: EmailStr | None = None """Email addresses for the user.""" - display: Optional[str] = None + display: str | None = None """A human-readable name, primarily used for display purposes.""" - type: Optional[Type] = Field(None, examples=["work", "home", "other"]) + type: Type | None = Field(None, examples=["work", "home", "other"]) """A label indicating the attribute's function, e.g., 'work' or 'home'.""" - primary: Optional[bool] = None + primary: bool | None = None """A Boolean value indicating the 'primary' or preferred attribute value for this attribute, e.g., the preferred mailing address or primary email address.""" @@ -77,19 +75,19 @@ class Type(str, Enum): pager = "pager" other = "other" - value: Optional[str] = None + value: str | None = None """Phone number of the User.""" - display: Optional[str] = None + display: str | None = None """A human-readable name, primarily used for display purposes.""" - type: Optional[Type] = Field( + type: Type | None = Field( None, examples=["work", "home", "mobile", "fax", "pager", "other"] ) """A label indicating the attribute's function, e.g., 'work', 'home', 'mobile'.""" - primary: Optional[bool] = None + primary: bool | None = None """A Boolean value indicating the 'primary' or preferred attribute value for this attribute, e.g., the preferred phone number or primary phone number.""" @@ -106,19 +104,19 @@ class Type(str, Enum): qq = "qq" yahoo = "yahoo" - value: Optional[str] = None + value: str | None = None """Instant messaging address for the User.""" - display: Optional[str] = None + display: str | None = None """A human-readable name, primarily used for display purposes.""" - type: Optional[Type] = Field( + type: Type | None = Field( None, examples=["aim", "gtalk", "icq", "xmpp", "msn", "skype", "qq", "yahoo"] ) """A label indicating the attribute's function, e.g., 'aim', 'gtalk', 'xmpp'.""" - primary: Optional[bool] = None + primary: bool | None = None """A Boolean value indicating the 'primary' or preferred attribute value for this attribute, e.g., the preferred messenger or primary messenger.""" @@ -128,17 +126,17 @@ class Type(str, Enum): photo = "photo" thumbnail = "thumbnail" - value: Annotated[Optional[Reference[ExternalReference]], CaseExact.true] = None + value: Annotated[Reference[ExternalReference] | None, CaseExact.true] = None """URL of a photo of the User.""" - display: Optional[str] = None + display: str | None = None """A human-readable name, primarily used for display purposes.""" - type: Optional[Type] = Field(None, examples=["photo", "thumbnail"]) + type: Type | None = Field(None, examples=["photo", "thumbnail"]) """A label indicating the attribute's function, i.e., 'photo' or 'thumbnail'.""" - primary: Optional[bool] = None + primary: bool | None = None """A Boolean value indicating the 'primary' or preferred attribute value for this attribute, e.g., the preferred photo or thumbnail.""" @@ -149,67 +147,67 @@ class Type(str, Enum): home = "home" other = "other" - formatted: Optional[str] = None + formatted: str | None = None """The full mailing address, formatted for display or use with a mailing label.""" - street_address: Optional[str] = None + street_address: str | None = None """The full street address component, which may include house number, street name, P.O. box, and multi-line extended street address information. """ - locality: Optional[str] = None + locality: str | None = None """The city or locality component.""" - region: Optional[str] = None + region: str | None = None """The state or region component.""" - postal_code: Optional[str] = None + postal_code: str | None = None """The zip code or postal code component.""" - country: Optional[str] = None + country: str | None = None """The country name component.""" - type: Optional[Type] = Field(None, examples=["work", "home", "other"]) + type: Type | None = Field(None, examples=["work", "home", "other"]) """A label indicating the attribute's function, e.g., 'work' or 'home'.""" - primary: Optional[bool] = None + primary: bool | None = None """A Boolean value indicating the 'primary' or preferred attribute value for this attribute, e.g., the preferred photo or thumbnail.""" class Entitlement(ComplexAttribute): - value: Optional[str] = None + value: str | None = None """The value of an entitlement.""" - display: Optional[str] = None + display: str | None = None """A human-readable name, primarily used for display purposes.""" - type: Optional[str] = None + type: str | None = None """A label indicating the attribute's function.""" - primary: Optional[bool] = None + primary: bool | None = None """A Boolean value indicating the 'primary' or preferred attribute value for this attribute.""" class GroupMembership(ComplexAttribute): - value: Annotated[Optional[str], Mutability.read_only] = None + value: Annotated[str | None, Mutability.read_only] = None """The identifier of the User's group.""" ref: Annotated[ - Optional[Reference[Union[Literal["User"], Literal["Group"]]]], + Reference[Literal["User"] | Literal["Group"]] | None, Mutability.read_only, ] = Field(None, serialization_alias="$ref") """The reference URI of a target resource, if the attribute is a reference.""" - display: Annotated[Optional[str], Mutability.read_only] = None + display: Annotated[str | None, Mutability.read_only] = None """A human-readable name, primarily used for display purposes.""" - type: Annotated[Optional[str], Mutability.read_only] = Field( + type: Annotated[str | None, Mutability.read_only] = Field( None, examples=["direct", "indirect"] ) """A label indicating the attribute's function, e.g., 'direct' or @@ -217,31 +215,31 @@ class GroupMembership(ComplexAttribute): class Role(ComplexAttribute): - value: Optional[str] = None + value: str | None = None """The value of a role.""" - display: Optional[str] = None + display: str | None = None """A human-readable name, primarily used for display purposes.""" - type: Optional[str] = None + type: str | None = None """A label indicating the attribute's function.""" - primary: Optional[bool] = None + primary: bool | None = None """A Boolean value indicating the 'primary' or preferred attribute value for this attribute.""" class X509Certificate(ComplexAttribute): - value: Annotated[Optional[Base64Bytes], CaseExact.true] = None + value: Annotated[Base64Bytes | None, CaseExact.true] = None """The value of an X.509 certificate.""" - display: Optional[str] = None + display: str | None = None """A human-readable name, primarily used for display purposes.""" - type: Optional[str] = None + type: str | None = None """A label indicating the attribute's function.""" - primary: Optional[bool] = None + primary: bool | None = None """A Boolean value indicating the 'primary' or preferred attribute value for this attribute.""" @@ -251,101 +249,101 @@ class User(Resource[AnyExtension]): "urn:ietf:params:scim:schemas:core:2.0:User" ] - user_name: Annotated[Optional[str], Uniqueness.server, Required.true] = None + user_name: Annotated[str | None, Uniqueness.server, Required.true] = None """Unique identifier for the User, typically used by the user to directly authenticate to the service provider.""" - name: Optional[Name] = None + name: Name | None = None """The components of the user's real name.""" Name: ClassVar[type[ComplexAttribute]] = Name - display_name: Optional[str] = None + display_name: str | None = None """The name of the User, suitable for display to end-users.""" - nick_name: Optional[str] = None + nick_name: str | None = None """The casual way to address the user in real life, e.g., 'Bob' or 'Bobby' instead of 'Robert'.""" - profile_url: Optional[Reference[ExternalReference]] = None + profile_url: Reference[ExternalReference] | None = None """A fully qualified URL pointing to a page representing the User's online profile.""" - title: Optional[str] = None + title: str | None = None """The user's title, such as "Vice President".""" - user_type: Optional[str] = None + user_type: str | None = None """Used to identify the relationship between the organization and the user. Typical values used might be 'Contractor', 'Employee', 'Intern', 'Temp', 'External', and 'Unknown', but any value may be used. """ - preferred_language: Optional[str] = None + preferred_language: str | None = None """Indicates the User's preferred written or spoken language. Generally used for selecting a localized user interface; e.g., 'en_US' specifies the language English and country US. """ - locale: Optional[str] = None + locale: str | None = None """Used to indicate the User's default location for purposes of localizing items such as currency, date time format, or numerical representations.""" - timezone: Optional[str] = None + timezone: str | None = None """The User's time zone in the 'Olson' time zone database format, e.g., 'America/Los_Angeles'.""" - active: Optional[bool] = None + active: bool | None = None """A Boolean value indicating the User's administrative status.""" - password: Annotated[Optional[str], Mutability.write_only, Returned.never] = None + password: Annotated[str | None, Mutability.write_only, Returned.never] = None """The User's cleartext password.""" - emails: Optional[list[Email]] = None + emails: list[Email] | None = None """Email addresses for the user.""" Emails: ClassVar[type[ComplexAttribute]] = Email - phone_numbers: Optional[list[PhoneNumber]] = None + phone_numbers: list[PhoneNumber] | None = None """Phone numbers for the User.""" PhoneNumbers: ClassVar[type[ComplexAttribute]] = PhoneNumber - ims: Optional[list[Im]] = None + ims: list[Im] | None = None """Instant messaging addresses for the User.""" Ims: ClassVar[type[ComplexAttribute]] = Im - photos: Optional[list[Photo]] = None + photos: list[Photo] | None = None """URLs of photos of the User.""" Photos: ClassVar[type[ComplexAttribute]] = Photo - addresses: Optional[list[Address]] = None + addresses: list[Address] | None = None """A physical mailing address for this User.""" Addresses: ClassVar[type[ComplexAttribute]] = Address - groups: Annotated[Optional[list[GroupMembership]], Mutability.read_only] = None + groups: Annotated[list[GroupMembership] | None, Mutability.read_only] = None """A list of groups to which the user belongs, either through direct membership, through nested groups, or dynamically calculated.""" Groups: ClassVar[type[ComplexAttribute]] = GroupMembership - entitlements: Optional[list[Entitlement]] = None + entitlements: list[Entitlement] | None = None """A list of entitlements for the User that represent a thing the User has.""" Entitlements: ClassVar[type[ComplexAttribute]] = Entitlement - roles: Optional[list[Role]] = None + roles: list[Role] | None = None """A list of roles for the User that collectively represent who the User is, e.g., 'Student', 'Faculty'.""" Roles: ClassVar[type[ComplexAttribute]] = Role - x509_certificates: Optional[list[X509Certificate]] = None + x509_certificates: list[X509Certificate] | None = None """A list of certificates issued to the User.""" X509Certificates: ClassVar[type[ComplexAttribute]] = X509Certificate diff --git a/scim2_models/scim_object.py b/scim2_models/scim_object.py index 1002518..3453e58 100644 --- a/scim2_models/scim_object.py +++ b/scim2_models/scim_object.py @@ -3,7 +3,6 @@ from typing import TYPE_CHECKING from typing import Annotated from typing import Any -from typing import Optional from .annotations import Required from .base import BaseModel @@ -22,7 +21,7 @@ class ScimObject(BaseModel): def _prepare_model_dump( self, - scim_ctx: Optional[Context] = Context.DEFAULT, + scim_ctx: Context | None = Context.DEFAULT, **kwargs: Any, ) -> dict[str, Any]: kwargs.setdefault("context", {}).setdefault("scim", scim_ctx) @@ -36,7 +35,7 @@ def _prepare_model_dump( def model_dump( self, *args: Any, - scim_ctx: Optional[Context] = Context.DEFAULT, + scim_ctx: Context | None = Context.DEFAULT, **kwargs: Any, ) -> dict[str, Any]: """Create a model representation that can be included in SCIM messages by using Pydantic :code:`BaseModel.model_dump`. @@ -53,7 +52,7 @@ def model_dump( def model_dump_json( self, *args: Any, - scim_ctx: Optional[Context] = Context.DEFAULT, + scim_ctx: Context | None = Context.DEFAULT, **kwargs: Any, ) -> str: """Create a JSON model representation that can be included in SCIM messages by using Pydantic :code:`BaseModel.model_dump_json`. diff --git a/scim2_models/urn.py b/scim2_models/urn.py index c64fe9c..5a2756e 100644 --- a/scim2_models/urn.py +++ b/scim2_models/urn.py @@ -1,6 +1,5 @@ from typing import TYPE_CHECKING from typing import Any -from typing import Optional from typing import Union from .base import BaseModel @@ -24,7 +23,7 @@ def _get_or_create_extension_instance( return extension_instance -def _normalize_path(model: Optional[type["BaseModel"]], path: str) -> tuple[str, str]: +def _normalize_path(model: type["BaseModel"] | None, path: str) -> tuple[str, str]: """Resolve a path to (schema_urn, attribute_path).""" from .resources.resource import Resource @@ -76,7 +75,7 @@ def _validate_model_attribute(model: type["BaseModel"], attribute_base: str) -> def _validate_attribute_urn( attribute_name: str, resource: type["Resource[Any]"] -) -> Optional[str]: +) -> str | None: """Validate that an attribute urn is valid or not. :param attribute_name: The attribute urn to check. @@ -84,7 +83,7 @@ def _validate_attribute_urn( """ from .resources.resource import Resource - schema: Optional[Any] + schema: Any | None schema, attribute_base = _normalize_path(resource, attribute_name) validated_resource = Resource.get_by_schema([resource], schema) @@ -101,7 +100,7 @@ def _validate_attribute_urn( def _resolve_path_to_target( resource: "Resource[Any]", path: str -) -> tuple[Optional[Union["Resource[Any]", "Extension"]], str]: +) -> tuple[Union["Resource[Any]", "Extension"] | None, str]: """Resolve a path to a target and an attribute_path. The target can be the resource itself, or an extension object. diff --git a/scim2_models/utils.py b/scim2_models/utils.py index 2242eda..f66aa1a 100644 --- a/scim2_models/utils.py +++ b/scim2_models/utils.py @@ -3,7 +3,6 @@ from typing import TYPE_CHECKING from typing import Annotated from typing import Literal -from typing import Optional from typing import Union from pydantic import EncodedBytes @@ -23,7 +22,7 @@ UNION_TYPES = [Union] -def _int_to_str(status: Optional[int]) -> Optional[str]: +def _int_to_str(status: int | None) -> str | None: return None if status is None else str(status) @@ -158,7 +157,7 @@ def _validate_scim_urn_syntax(path: str) -> bool: return True -def _extract_field_name(path: str) -> Optional[str]: +def _extract_field_name(path: str) -> str | None: """Extract the field name from a path. For now, only handle simple paths (no filters, no complex expressions). @@ -181,7 +180,7 @@ def _extract_field_name(path: str) -> Optional[str]: return path -def _find_field_name(model_class: type["BaseModel"], attr_name: str) -> Optional[str]: +def _find_field_name(model_class: type["BaseModel"], attr_name: str) -> str | None: """Find the actual field name in a resource class from an attribute name. :param resource_class: The resource class to search in diff --git a/tests/test_dynamic_resources.py b/tests/test_dynamic_resources.py index 745c91c..13fa488 100644 --- a/tests/test_dynamic_resources.py +++ b/tests/test_dynamic_resources.py @@ -1,6 +1,5 @@ import datetime from typing import Literal -from typing import Union from scim2_models.annotations import CaseExact from scim2_models.annotations import Mutability @@ -72,7 +71,7 @@ def test_make_group_model_from_schema(load_sample): # Members.ref assert ( Members.get_field_root_type("ref") - == Reference[Union[Literal["User"], Literal["Group"]]] + == Reference[Literal["User"] | Literal["Group"]] ) assert not Members.get_field_multiplicity("ref") assert ( @@ -864,7 +863,7 @@ def test_make_user_model_from_schema(load_sample): # group.ref assert ( Groups.get_field_root_type("ref") - == Reference[Union[Literal["User"], Literal["Group"]]] + == Reference[Literal["User"] | Literal["Group"]] ) assert not Groups.get_field_multiplicity("ref") assert ( diff --git a/tests/test_dynamic_schemas.py b/tests/test_dynamic_schemas.py index 1f70399..d699eba 100644 --- a/tests/test_dynamic_schemas.py +++ b/tests/test_dynamic_schemas.py @@ -1,6 +1,5 @@ import operator from typing import Annotated -from typing import Optional import pytest @@ -121,10 +120,10 @@ class Foo(Resource): "urn:ietf:params:scim:schemas:core:2.0:Foo" ] - foo: Optional[str] = None + foo: str | None = None class Bar(Foo): - bar: Optional[str] = None + bar: str | None = None schema = Bar.to_schema() assert schema.model_dump() == { diff --git a/tests/test_list_response.py b/tests/test_list_response.py index dfa0d5e..e516fa6 100644 --- a/tests/test_list_response.py +++ b/tests/test_list_response.py @@ -1,5 +1,4 @@ from typing import Annotated -from typing import Union import pytest from pydantic import ValidationError @@ -101,7 +100,7 @@ def test_mixed_types(load_sample): "schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"], "Resources": [user_payload, group_payload], } - response = ListResponse[Union[User, Group]].model_validate(payload) + response = ListResponse[User | Group].model_validate(payload) user, group = response.resources assert isinstance(user, User) assert isinstance(group, Group) @@ -124,10 +123,10 @@ def test_mixed_types_type_missing(load_sample): "Resources": [user_payload, group_payload], } - ListResponse[Union[User, Group]].model_validate(payload) + ListResponse[User | Group].model_validate(payload) with pytest.raises(ValidationError): - ListResponse[Union[User, Foobar]].model_validate(payload) + ListResponse[User | Foobar].model_validate(payload) with pytest.raises(ValidationError): ListResponse[User].model_validate(payload) @@ -144,7 +143,7 @@ def test_missing_resource_payload(load_sample): } with pytest.raises(ValidationError): - ListResponse[Union[User, Group]].model_validate(payload, strict=True) + ListResponse[User | Group].model_validate(payload, strict=True) # TODO: This should raise a ValidationError ListResponse[User].model_validate(payload, strict=True) @@ -161,7 +160,7 @@ def test_missing_resource_schema(load_sample): } with pytest.raises(ValidationError): - ListResponse[Union[User, Group]].model_validate(payload, strict=True) + ListResponse[User | Group].model_validate(payload, strict=True) # TODO: This should raise a ValidationError ListResponse[User].model_validate(payload, strict=True) @@ -216,7 +215,7 @@ def test_list_response_schema_ordering(): } ], } - ListResponse[Union[User[EnterpriseUser], Group]].model_validate(payload) + ListResponse[User[EnterpriseUser] | Group].model_validate(payload) def test_total_results_required(): diff --git a/tests/test_model_attributes.py b/tests/test_model_attributes.py index bdbc02a..fde21fd 100644 --- a/tests/test_model_attributes.py +++ b/tests/test_model_attributes.py @@ -1,6 +1,5 @@ import uuid from typing import Annotated -from typing import Optional from scim2_models.annotations import Required from scim2_models.annotations import Returned @@ -35,10 +34,10 @@ def test_guess_root_type(): class ReturnedModel(BaseModel): - always: Annotated[Optional[str], Returned.always] = None - never: Annotated[Optional[str], Returned.never] = None - default: Annotated[Optional[str], Returned.default] = None - request: Annotated[Optional[str], Returned.request] = None + always: Annotated[str | None, Returned.always] = None + never: Annotated[str | None, Returned.never] = None + default: Annotated[str | None, Returned.default] = None + request: Annotated[str | None, Returned.request] = None class Baz(ComplexAttribute): @@ -50,7 +49,7 @@ class Foo(Resource): sub: Annotated[ReturnedModel, Returned.default] bar: str snake_case: str - baz: Optional[Baz] = None + baz: Baz | None = None class Bar(Resource): @@ -58,7 +57,7 @@ class Bar(Resource): sub: Annotated[ReturnedModel, Returned.default] bar: str snake_case: str - baz: Optional[Baz] = None + baz: Baz | None = None class MyExtension(Extension): diff --git a/tests/test_model_serialization.py b/tests/test_model_serialization.py index ef1a0e5..f888485 100644 --- a/tests/test_model_serialization.py +++ b/tests/test_model_serialization.py @@ -1,5 +1,4 @@ from typing import Annotated -from typing import Optional import pytest @@ -12,30 +11,30 @@ class SubRetModel(ComplexAttribute): - always_returned: Annotated[Optional[str], Returned.always] = None - never_returned: Annotated[Optional[str], Returned.never] = None - default_returned: Annotated[Optional[str], Returned.default] = None - request_returned: Annotated[Optional[str], Returned.request] = None + always_returned: Annotated[str | None, Returned.always] = None + never_returned: Annotated[str | None, Returned.never] = None + default_returned: Annotated[str | None, Returned.default] = None + request_returned: Annotated[str | None, Returned.request] = None class SupRetResource(Resource): schemas: Annotated[list[str], Required.true] = ["org:example:SupRetResource"] - always_returned: Annotated[Optional[str], Returned.always] = None - never_returned: Annotated[Optional[str], Returned.never] = None - default_returned: Annotated[Optional[str], Returned.default] = None - request_returned: Annotated[Optional[str], Returned.request] = None + always_returned: Annotated[str | None, Returned.always] = None + never_returned: Annotated[str | None, Returned.never] = None + default_returned: Annotated[str | None, Returned.default] = None + request_returned: Annotated[str | None, Returned.request] = None - sub: Optional[SubRetModel] = None + sub: SubRetModel | None = None class MutResource(Resource): schemas: Annotated[list[str], Required.true] = ["org:example:MutResource"] - read_only: Annotated[Optional[str], Mutability.read_only] = None - read_write: Annotated[Optional[str], Mutability.read_write] = None - immutable: Annotated[Optional[str], Mutability.immutable] = None - write_only: Annotated[Optional[str], Mutability.write_only] = None + read_only: Annotated[str | None, Mutability.read_only] = None + read_write: Annotated[str | None, Mutability.read_write] = None + immutable: Annotated[str | None, Mutability.immutable] = None + write_only: Annotated[str | None, Mutability.write_only] = None @pytest.fixture diff --git a/tests/test_model_validation.py b/tests/test_model_validation.py index 2e522a8..7973656 100644 --- a/tests/test_model_validation.py +++ b/tests/test_model_validation.py @@ -1,5 +1,4 @@ from typing import Annotated -from typing import Optional import pytest from pydantic import ValidationError @@ -15,26 +14,26 @@ class RetResource(Resource): schemas: Annotated[list[str], Required.true] = ["org:example:RetResource"] - always_returned: Annotated[Optional[str], Returned.always] = None - never_returned: Annotated[Optional[str], Returned.never] = None - default_returned: Annotated[Optional[str], Returned.default] = None - request_returned: Annotated[Optional[str], Returned.request] = None + always_returned: Annotated[str | None, Returned.always] = None + never_returned: Annotated[str | None, Returned.never] = None + default_returned: Annotated[str | None, Returned.default] = None + request_returned: Annotated[str | None, Returned.request] = None class MutResource(Resource): schemas: Annotated[list[str], Required.true] = ["org:example:MutResource"] - read_only: Annotated[Optional[str], Mutability.read_only] = None - read_write: Annotated[Optional[str], Mutability.read_write] = None - immutable: Annotated[Optional[str], Mutability.immutable] = None - write_only: Annotated[Optional[str], Mutability.write_only] = None + read_only: Annotated[str | None, Mutability.read_only] = None + read_write: Annotated[str | None, Mutability.read_write] = None + immutable: Annotated[str | None, Mutability.immutable] = None + write_only: Annotated[str | None, Mutability.write_only] = None class ReqResource(Resource): schemas: Annotated[list[str], Required.true] = ["org:example:ReqResource"] - required: Annotated[Optional[str], Required.true] = None - optional: Annotated[Optional[str], Required.false] = None + required: Annotated[str | None, Required.true] = None + optional: Annotated[str | None, Required.false] = None def test_validate_default_mutability(): @@ -208,11 +207,11 @@ def test_validate_replacement_request_mutability_sub_attributes(): """ class Sub(ComplexAttribute): - immutable: Annotated[Optional[str], Mutability.immutable] = None + immutable: Annotated[str | None, Mutability.immutable] = None class Super(Resource): schemas: Annotated[list[str], Required.true] = ["org:example:Super"] - sub: Optional[Sub] = None + sub: Sub | None = None original = Super(sub=Sub(immutable="y")) assert Super.model_validate( diff --git a/tests/test_models.py b/tests/test_models.py index fc79b28..7d6465a 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -1,5 +1,4 @@ import os -from typing import Union from scim2_models import BulkRequest from scim2_models import BulkResponse @@ -26,7 +25,7 @@ def test_parse_and_serialize_examples(load_sample): "resource_type": ResourceType, "service_provider_configuration": ServiceProviderConfig, "list_response": ListResponse[ - Union[User[EnterpriseUser], Group, Schema, ResourceType] + User[EnterpriseUser] | Group | Schema | ResourceType ], "patch_op": PatchOp[User], "bulk_request": BulkRequest, diff --git a/tests/test_patch_op_extensions.py b/tests/test_patch_op_extensions.py index 7c0b558..0e3dcae 100644 --- a/tests/test_patch_op_extensions.py +++ b/tests/test_patch_op_extensions.py @@ -1,5 +1,4 @@ from typing import TypeVar -from typing import Union import pytest from pydantic import Field @@ -247,7 +246,7 @@ def test_generic_patchop_rejects_union(): with pytest.raises( TypeError, match="PatchOp type parameter must be a concrete Resource subclass" ): - PatchOp[Union[User, Group]] + PatchOp[User | Group] def test_generic_patchop_with_single_type(): diff --git a/tests/test_patch_op_validation.py b/tests/test_patch_op_validation.py index 92c08a4..8ff3a3c 100644 --- a/tests/test_patch_op_validation.py +++ b/tests/test_patch_op_validation.py @@ -1,5 +1,4 @@ from typing import TypeVar -from typing import Union import pytest from pydantic import ValidationError @@ -40,7 +39,7 @@ def test_patch_op_union_types_not_supported(): with pytest.raises( TypeError, match="PatchOp type parameter must be a concrete Resource subclass" ): - PatchOp[Union[User, Group]] + PatchOp[User | Group] def test_validate_patchop_case_insensitivity(): diff --git a/tests/test_reference.py b/tests/test_reference.py index db6d92a..1a94711 100644 --- a/tests/test_reference.py +++ b/tests/test_reference.py @@ -1,7 +1,6 @@ """Test Reference constructor functionality.""" from typing import Annotated -from typing import Optional import pytest @@ -16,8 +15,8 @@ class ReferenceTestModel(BaseModel): """Test model with Reference fields.""" schemas: Annotated[list[str], Required.true] = ["urn:example:test"] - uri_ref: Optional[Reference[URIReference]] = None - ext_ref: Optional[Reference[ExternalReference]] = None + uri_ref: Reference[URIReference] | None = None + ext_ref: Reference[ExternalReference] | None = None def test_reference_uri_string_assignment(): diff --git a/tests/test_resource_extension.py b/tests/test_resource_extension.py index ce7bfca..ec948db 100644 --- a/tests/test_resource_extension.py +++ b/tests/test_resource_extension.py @@ -1,7 +1,5 @@ import datetime from typing import Annotated -from typing import Optional -from typing import Union import pytest @@ -205,13 +203,13 @@ def test_invalid_setitem(): class SuperHero(Extension): schemas: Annotated[list[str], Required.true] = ["example:extensions:SuperHero"] - superpower: Optional[str] = None + superpower: str | None = None """The superhero superpower.""" def test_multiple_extensions_union(): """Test that multiple extensions can be used by using Union.""" - user_model = User[Union[EnterpriseUser, SuperHero]] + user_model = User[EnterpriseUser | SuperHero] instance = user_model() instance[SuperHero] = SuperHero(superpower="flight") assert instance[SuperHero].superpower == "flight" @@ -283,11 +281,11 @@ def test_get_extension_model(): ) assert ( - User[Union[EnterpriseUser, SuperHero]].get_extension_model("EnterpriseUser") + User[EnterpriseUser | SuperHero].get_extension_model("EnterpriseUser") == EnterpriseUser ) assert ( - User[Union[EnterpriseUser, SuperHero]].get_extension_model( + User[EnterpriseUser | SuperHero].get_extension_model( "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User" ) == EnterpriseUser @@ -324,8 +322,6 @@ def test_class_getitem(): def test_model_attribute_to_scim_attribute_error(): """Test error case where get_field_root_type returns None.""" - from typing import Optional - from pydantic import Field from scim2_models.base import BaseModel @@ -333,7 +329,7 @@ def test_model_attribute_to_scim_attribute_error(): # Create a model with a field that has no clear root type class TestModel(BaseModel): - problematic_field: Optional[str] = Field(default=None) + problematic_field: str | None = Field(default=None) # Mock get_field_root_type to return None original_method = TestModel.get_field_root_type diff --git a/tests/test_resource_type.py b/tests/test_resource_type.py index 1332bf0..172239f 100644 --- a/tests/test_resource_type.py +++ b/tests/test_resource_type.py @@ -1,5 +1,4 @@ from typing import Annotated -from typing import Union from scim2_models import EnterpriseUser from scim2_models import Extension @@ -74,11 +73,11 @@ class TestExtension(Extension): "urn:ietf:params:scim:schemas:extension:Test:1.0:User" ] - test: Union[str, None] = None - test2: Union[list[str], None] = None + test: str | None = None + test2: list[str] | None = None enterprise_user_rt = ResourceType.from_resource( - User[Union[EnterpriseUser, TestExtension]] + User[EnterpriseUser | TestExtension] ) assert enterprise_user_rt.id == "User" assert enterprise_user_rt.name == "User" diff --git a/uv.lock b/uv.lock index 1f46e8c..51acc60 100644 --- a/uv.lock +++ b/uv.lock @@ -1,32 +1,15 @@ version = 1 revision = 3 -requires-python = ">=3.9" +requires-python = ">=3.10" resolution-markers = [ "python_full_version >= '3.11'", - "python_full_version == '3.10.*'", - "python_full_version < '3.10'", -] - -[[package]] -name = "alabaster" -version = "0.7.16" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -sdist = { url = "https://files.pythonhosted.org/packages/c9/3e/13dd8e5ed9094e734ac430b5d0eb4f2bb001708a8b7856cbf8e084e001ba/alabaster-0.7.16.tar.gz", hash = "sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65", size = 23776, upload-time = "2024-01-10T00:56:10.189Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/32/34/d4e1c02d3bee589efb5dfa17f88ea08bdb3e3eac12bc475462aec52ed223/alabaster-0.7.16-py3-none-any.whl", hash = "sha256:b46733c07dce03ae4e150330b975c75737fa60f0a7c591b6c8bf4928a28e2c92", size = 13511, upload-time = "2024-01-10T00:56:08.388Z" }, + "python_full_version < '3.11'", ] [[package]] name = "alabaster" version = "1.0.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.11'", - "python_full_version == '3.10.*'", -] sdist = { url = "https://files.pythonhosted.org/packages/a6/f8/d9c74d0daf3f742840fd818d69cfae176fa332022fd44e3469487d5a9420/alabaster-1.0.0.tar.gz", hash = "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e", size = 24210, upload-time = "2024-07-26T18:15:03.762Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/7e/b3/6b4067be973ae96ba0d615946e314c5ae35f9f993eca561b356540bb0c2b/alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b", size = 13929, upload-time = "2024-07-26T18:15:02.05Z" }, @@ -48,8 +31,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pydantic" }, { name = "pydantic-settings" }, - { name = "sphinx", version = "7.4.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, + { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, ] wheels = [ @@ -153,17 +135,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/72/2a/aff5dd112b2f14bcc3462c312dce5445806bfc8ab3a7328555da95330e4b/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d716a916938e03231e86e43782ca7878fb602a125a91e7acb8b5112e2e96ac16", size = 152224, upload-time = "2025-08-09T07:56:51.369Z" }, { url = "https://files.pythonhosted.org/packages/b7/8c/9839225320046ed279c6e839d51f028342eb77c91c89b8ef2549f951f3ec/charset_normalizer-3.4.3-cp314-cp314-win32.whl", hash = "sha256:c6dbd0ccdda3a2ba7c2ecd9d77b37f3b5831687d8dc1b6ca5f56a4880cc7b7ce", size = 100086, upload-time = "2025-08-09T07:56:52.722Z" }, { url = "https://files.pythonhosted.org/packages/ee/7a/36fbcf646e41f710ce0a563c1c9a343c6edf9be80786edeb15b6f62e17db/charset_normalizer-3.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:73dc19b562516fc9bcf6e5d6e596df0b4eb98d87e4f79f3ae71840e6ed21361c", size = 107400, upload-time = "2025-08-09T07:56:55.172Z" }, - { url = "https://files.pythonhosted.org/packages/c2/ca/9a0983dd5c8e9733565cf3db4df2b0a2e9a82659fd8aa2a868ac6e4a991f/charset_normalizer-3.4.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:70bfc5f2c318afece2f5838ea5e4c3febada0be750fcf4775641052bbba14d05", size = 207520, upload-time = "2025-08-09T07:57:11.026Z" }, - { url = "https://files.pythonhosted.org/packages/39/c6/99271dc37243a4f925b09090493fb96c9333d7992c6187f5cfe5312008d2/charset_normalizer-3.4.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:23b6b24d74478dc833444cbd927c338349d6ae852ba53a0d02a2de1fce45b96e", size = 147307, upload-time = "2025-08-09T07:57:12.4Z" }, - { url = "https://files.pythonhosted.org/packages/e4/69/132eab043356bba06eb333cc2cc60c6340857d0a2e4ca6dc2b51312886b3/charset_normalizer-3.4.3-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:34a7f768e3f985abdb42841e20e17b330ad3aaf4bb7e7aeeb73db2e70f077b99", size = 160448, upload-time = "2025-08-09T07:57:13.712Z" }, - { url = "https://files.pythonhosted.org/packages/04/9a/914d294daa4809c57667b77470533e65def9c0be1ef8b4c1183a99170e9d/charset_normalizer-3.4.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fb731e5deb0c7ef82d698b0f4c5bb724633ee2a489401594c5c88b02e6cb15f7", size = 157758, upload-time = "2025-08-09T07:57:14.979Z" }, - { url = "https://files.pythonhosted.org/packages/b0/a8/6f5bcf1bcf63cb45625f7c5cadca026121ff8a6c8a3256d8d8cd59302663/charset_normalizer-3.4.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:257f26fed7d7ff59921b78244f3cd93ed2af1800ff048c33f624c87475819dd7", size = 152487, upload-time = "2025-08-09T07:57:16.332Z" }, - { url = "https://files.pythonhosted.org/packages/c4/72/d3d0e9592f4e504f9dea08b8db270821c909558c353dc3b457ed2509f2fb/charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1ef99f0456d3d46a50945c98de1774da86f8e992ab5c77865ea8b8195341fc19", size = 150054, upload-time = "2025-08-09T07:57:17.576Z" }, - { url = "https://files.pythonhosted.org/packages/20/30/5f64fe3981677fe63fa987b80e6c01042eb5ff653ff7cec1b7bd9268e54e/charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:2c322db9c8c89009a990ef07c3bcc9f011a3269bc06782f916cd3d9eed7c9312", size = 161703, upload-time = "2025-08-09T07:57:20.012Z" }, - { url = "https://files.pythonhosted.org/packages/e1/ef/dd08b2cac9284fd59e70f7d97382c33a3d0a926e45b15fc21b3308324ffd/charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:511729f456829ef86ac41ca78c63a5cb55240ed23b4b737faca0eb1abb1c41bc", size = 159096, upload-time = "2025-08-09T07:57:21.329Z" }, - { url = "https://files.pythonhosted.org/packages/45/8c/dcef87cfc2b3f002a6478f38906f9040302c68aebe21468090e39cde1445/charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:88ab34806dea0671532d3f82d82b85e8fc23d7b2dd12fa837978dad9bb392a34", size = 153852, upload-time = "2025-08-09T07:57:22.608Z" }, - { url = "https://files.pythonhosted.org/packages/63/86/9cbd533bd37883d467fcd1bd491b3547a3532d0fbb46de2b99feeebf185e/charset_normalizer-3.4.3-cp39-cp39-win32.whl", hash = "sha256:16a8770207946ac75703458e2c743631c79c59c5890c80011d536248f8eaa432", size = 99840, upload-time = "2025-08-09T07:57:23.883Z" }, - { url = "https://files.pythonhosted.org/packages/ce/d6/7e805c8e5c46ff9729c49950acc4ee0aeb55efb8b3a56687658ad10c3216/charset_normalizer-3.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:d22dbedd33326a4a5190dd4fe9e9e693ef12160c77382d9e87919bce54f3d4ca", size = 107438, upload-time = "2025-08-09T07:57:25.287Z" }, { url = "https://files.pythonhosted.org/packages/8a/1f/f041989e93b001bc4e44bb1669ccdcf54d3f00e628229a85b08d330615c5/charset_normalizer-3.4.3-py3-none-any.whl", hash = "sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a", size = 53175, upload-time = "2025-08-09T07:57:26.864Z" }, ] @@ -272,18 +243,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b2/dc/101f3fa3a45146db0cb03f5b4376e24c0aac818309da23e2de0c75295a91/coverage-7.10.7-cp314-cp314t-win32.whl", hash = "sha256:67f8c5cbcd3deb7a60b3345dffc89a961a484ed0af1f6f73de91705cc6e31235", size = 221784, upload-time = "2025-09-21T20:03:24.769Z" }, { url = "https://files.pythonhosted.org/packages/4c/a1/74c51803fc70a8a40d7346660379e144be772bab4ac7bb6e6b905152345c/coverage-7.10.7-cp314-cp314t-win_amd64.whl", hash = "sha256:e1ed71194ef6dea7ed2d5cb5f7243d4bcd334bfb63e59878519be558078f848d", size = 222905, upload-time = "2025-09-21T20:03:26.93Z" }, { url = "https://files.pythonhosted.org/packages/12/65/f116a6d2127df30bcafbceef0302d8a64ba87488bf6f73a6d8eebf060873/coverage-7.10.7-cp314-cp314t-win_arm64.whl", hash = "sha256:7fe650342addd8524ca63d77b2362b02345e5f1a093266787d210c70a50b471a", size = 220922, upload-time = "2025-09-21T20:03:28.672Z" }, - { url = "https://files.pythonhosted.org/packages/a3/ad/d1c25053764b4c42eb294aae92ab617d2e4f803397f9c7c8295caa77a260/coverage-7.10.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fff7b9c3f19957020cac546c70025331113d2e61537f6e2441bc7657913de7d3", size = 217978, upload-time = "2025-09-21T20:03:30.362Z" }, - { url = "https://files.pythonhosted.org/packages/52/2f/b9f9daa39b80ece0b9548bbb723381e29bc664822d9a12c2135f8922c22b/coverage-7.10.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bc91b314cef27742da486d6839b677b3f2793dfe52b51bbbb7cf736d5c29281c", size = 218370, upload-time = "2025-09-21T20:03:32.147Z" }, - { url = "https://files.pythonhosted.org/packages/dd/6e/30d006c3b469e58449650642383dddf1c8fb63d44fdf92994bfd46570695/coverage-7.10.7-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:567f5c155eda8df1d3d439d40a45a6a5f029b429b06648235f1e7e51b522b396", size = 244802, upload-time = "2025-09-21T20:03:33.919Z" }, - { url = "https://files.pythonhosted.org/packages/b0/49/8a070782ce7e6b94ff6a0b6d7c65ba6bc3091d92a92cef4cd4eb0767965c/coverage-7.10.7-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2af88deffcc8a4d5974cf2d502251bc3b2db8461f0b66d80a449c33757aa9f40", size = 246625, upload-time = "2025-09-21T20:03:36.09Z" }, - { url = "https://files.pythonhosted.org/packages/6a/92/1c1c5a9e8677ce56d42b97bdaca337b2d4d9ebe703d8c174ede52dbabd5f/coverage-7.10.7-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c7315339eae3b24c2d2fa1ed7d7a38654cba34a13ef19fbcb9425da46d3dc594", size = 248399, upload-time = "2025-09-21T20:03:38.342Z" }, - { url = "https://files.pythonhosted.org/packages/c0/54/b140edee7257e815de7426d5d9846b58505dffc29795fff2dfb7f8a1c5a0/coverage-7.10.7-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:912e6ebc7a6e4adfdbb1aec371ad04c68854cd3bf3608b3514e7ff9062931d8a", size = 245142, upload-time = "2025-09-21T20:03:40.591Z" }, - { url = "https://files.pythonhosted.org/packages/e4/9e/6d6b8295940b118e8b7083b29226c71f6154f7ff41e9ca431f03de2eac0d/coverage-7.10.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:f49a05acd3dfe1ce9715b657e28d138578bc40126760efb962322c56e9ca344b", size = 246284, upload-time = "2025-09-21T20:03:42.355Z" }, - { url = "https://files.pythonhosted.org/packages/db/e5/5e957ca747d43dbe4d9714358375c7546cb3cb533007b6813fc20fce37ad/coverage-7.10.7-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:cce2109b6219f22ece99db7644b9622f54a4e915dad65660ec435e89a3ea7cc3", size = 244353, upload-time = "2025-09-21T20:03:44.218Z" }, - { url = "https://files.pythonhosted.org/packages/9a/45/540fc5cc92536a1b783b7ef99450bd55a4b3af234aae35a18a339973ce30/coverage-7.10.7-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:f3c887f96407cea3916294046fc7dab611c2552beadbed4ea901cbc6a40cc7a0", size = 244430, upload-time = "2025-09-21T20:03:46.065Z" }, - { url = "https://files.pythonhosted.org/packages/75/0b/8287b2e5b38c8fe15d7e3398849bb58d382aedc0864ea0fa1820e8630491/coverage-7.10.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:635adb9a4507c9fd2ed65f39693fa31c9a3ee3a8e6dc64df033e8fdf52a7003f", size = 245311, upload-time = "2025-09-21T20:03:48.19Z" }, - { url = "https://files.pythonhosted.org/packages/0c/1d/29724999984740f0c86d03e6420b942439bf5bd7f54d4382cae386a9d1e9/coverage-7.10.7-cp39-cp39-win32.whl", hash = "sha256:5a02d5a850e2979b0a014c412573953995174743a3f7fa4ea5a6e9a3c5617431", size = 220500, upload-time = "2025-09-21T20:03:50.024Z" }, - { url = "https://files.pythonhosted.org/packages/43/11/4b1e6b129943f905ca54c339f343877b55b365ae2558806c1be4f7476ed5/coverage-7.10.7-cp39-cp39-win_amd64.whl", hash = "sha256:c134869d5ffe34547d14e174c866fd8fe2254918cc0a95e99052903bc1543e07", size = 221408, upload-time = "2025-09-21T20:03:51.803Z" }, { url = "https://files.pythonhosted.org/packages/ec/16/114df1c291c22cac3b0c127a73e0af5c12ed7bbb6558d310429a0ae24023/coverage-7.10.7-py3-none-any.whl", hash = "sha256:f7941f6f2fe6dd6807a1208737b8a0cbcf1cc6d7b07d24998ad2d63590868260", size = 209952, upload-time = "2025-09-21T20:03:53.918Z" }, ] @@ -301,26 +260,10 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" }, ] -[[package]] -name = "dnspython" -version = "2.7.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -sdist = { url = "https://files.pythonhosted.org/packages/b5/4a/263763cb2ba3816dd94b08ad3a33d5fdae34ecb856678773cc40a3605829/dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1", size = 345197, upload-time = "2024-10-05T20:14:59.362Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/68/1b/e0a87d256e40e8c888847551b20a017a6b98139178505dc7ffb96f04e954/dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86", size = 313632, upload-time = "2024-10-05T20:14:57.687Z" }, -] - [[package]] name = "dnspython" version = "2.8.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.11'", - "python_full_version == '3.10.*'", -] sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/57666417c0f90f08bcafa776861060426765fdb422eb10212086fb811d26/dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f", size = 368251, upload-time = "2025-09-07T18:58:00.022Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094, upload-time = "2025-09-07T18:57:58.071Z" }, @@ -340,8 +283,7 @@ name = "email-validator" version = "2.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "dnspython", version = "2.7.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "dnspython", version = "2.8.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "dnspython" }, { name = "idna" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f5/22/900cb125c76b7aaa450ce02fd727f452243f2e91a61af068b40adba60ea9/email_validator-2.3.0.tar.gz", hash = "sha256:9fc05c37f2f6cf439ff414f8fc46d917929974a82244c20eb10231ba60c54426", size = 51238, upload-time = "2025-08-26T13:09:06.831Z" } @@ -361,26 +303,10 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/36/f4/c6e662dade71f56cd2f3735141b265c3c79293c109549c1e6933b0651ffc/exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10", size = 16674, upload-time = "2025-05-10T17:42:49.33Z" }, ] -[[package]] -name = "filelock" -version = "3.19.1" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -sdist = { url = "https://files.pythonhosted.org/packages/40/bb/0ab3e58d22305b6f5440629d20683af28959bf793d98d11950e305c1c326/filelock-3.19.1.tar.gz", hash = "sha256:66eda1888b0171c998b35be2bcc0f6d75c388a7ce20c3f3f37aa8e96c2dddf58", size = 17687, upload-time = "2025-08-14T16:56:03.016Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/42/14/42b2651a2f46b022ccd948bca9f2d5af0fd8929c4eec235b8d6d844fbe67/filelock-3.19.1-py3-none-any.whl", hash = "sha256:d38e30481def20772f5baf097c122c3babc4fcdb7e14e57049eb9d88c6dc017d", size = 15988, upload-time = "2025-08-14T16:56:01.633Z" }, -] - [[package]] name = "filelock" version = "3.20.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.11'", - "python_full_version == '3.10.*'", -] sdist = { url = "https://files.pythonhosted.org/packages/58/46/0028a82567109b5ef6e4d2a1f04a583fb513e6cf9527fcdd09afd817deeb/filelock-3.20.0.tar.gz", hash = "sha256:711e943b4ec6be42e1d4e6690b48dc175c822967466bb31c0c293f34334c13f4", size = 18922, upload-time = "2025-10-08T18:03:50.056Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/76/91/7216b27286936c16f5b4d0c530087e4a54eead683e6b0b73dd0c64844af6/filelock-3.20.0-py3-none-any.whl", hash = "sha256:339b4732ffda5cd79b13f4e2711a31b0365ce445d95d243bb996273d072546a2", size = 16054, upload-time = "2025-10-08T18:03:48.35Z" }, @@ -404,18 +330,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ff/62/85c4c919272577931d407be5ba5d71c20f0b616d31a0befe0ae45bb79abd/imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b", size = 8769, upload-time = "2022-07-01T12:21:02.467Z" }, ] -[[package]] -name = "importlib-metadata" -version = "8.7.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "zipp", marker = "python_full_version < '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/76/66/650a33bd90f786193e4de4b3ad86ea60b53c89b669a5c7be931fac31cdb0/importlib_metadata-8.7.0.tar.gz", hash = "sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000", size = 56641, upload-time = "2025-04-27T15:29:01.736Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/20/b0/36bd937216ec521246249be3bf9855081de4c5e06a0c9b4219dbeda50373/importlib_metadata-8.7.0-py3-none-any.whl", hash = "sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd", size = 27656, upload-time = "2025-04-27T15:29:00.214Z" }, -] - [[package]] name = "iniconfig" version = "2.1.0" @@ -532,44 +446,14 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" }, { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" }, { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, - { url = "https://files.pythonhosted.org/packages/56/23/0d8c13a44bde9154821586520840643467aee574d8ce79a17da539ee7fed/markupsafe-3.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15d939a21d546304880945ca1ecb8a039db6b4dc49b2c5a400387cdae6a62e26", size = 11623, upload-time = "2025-09-27T18:37:29.296Z" }, - { url = "https://files.pythonhosted.org/packages/fd/23/07a2cb9a8045d5f3f0890a8c3bc0859d7a47bfd9a560b563899bec7b72ed/markupsafe-3.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f71a396b3bf33ecaa1626c255855702aca4d3d9fea5e051b41ac59a9c1c41edc", size = 12049, upload-time = "2025-09-27T18:37:30.234Z" }, - { url = "https://files.pythonhosted.org/packages/bc/e4/6be85eb81503f8e11b61c0b6369b6e077dcf0a74adbd9ebf6b349937b4e9/markupsafe-3.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f4b68347f8c5eab4a13419215bdfd7f8c9b19f2b25520968adfad23eb0ce60c", size = 21923, upload-time = "2025-09-27T18:37:31.177Z" }, - { url = "https://files.pythonhosted.org/packages/6f/bc/4dc914ead3fe6ddaef035341fee0fc956949bbd27335b611829292b89ee2/markupsafe-3.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e8fc20152abba6b83724d7ff268c249fa196d8259ff481f3b1476383f8f24e42", size = 20543, upload-time = "2025-09-27T18:37:32.168Z" }, - { url = "https://files.pythonhosted.org/packages/89/6e/5fe81fbcfba4aef4093d5f856e5c774ec2057946052d18d168219b7bd9f9/markupsafe-3.0.3-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:949b8d66bc381ee8b007cd945914c721d9aba8e27f71959d750a46f7c282b20b", size = 20585, upload-time = "2025-09-27T18:37:33.166Z" }, - { url = "https://files.pythonhosted.org/packages/f6/f6/e0e5a3d3ae9c4020f696cd055f940ef86b64fe88de26f3a0308b9d3d048c/markupsafe-3.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3537e01efc9d4dccdf77221fb1cb3b8e1a38d5428920e0657ce299b20324d758", size = 21387, upload-time = "2025-09-27T18:37:34.185Z" }, - { url = "https://files.pythonhosted.org/packages/c8/25/651753ef4dea08ea790f4fbb65146a9a44a014986996ca40102e237aa49a/markupsafe-3.0.3-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:591ae9f2a647529ca990bc681daebdd52c8791ff06c2bfa05b65163e28102ef2", size = 20133, upload-time = "2025-09-27T18:37:35.138Z" }, - { url = "https://files.pythonhosted.org/packages/dc/0a/c3cf2b4fef5f0426e8a6d7fce3cb966a17817c568ce59d76b92a233fdbec/markupsafe-3.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a320721ab5a1aba0a233739394eb907f8c8da5c98c9181d1161e77a0c8e36f2d", size = 20588, upload-time = "2025-09-27T18:37:36.096Z" }, - { url = "https://files.pythonhosted.org/packages/cd/1b/a7782984844bd519ad4ffdbebbba2671ec5d0ebbeac34736c15fb86399e8/markupsafe-3.0.3-cp39-cp39-win32.whl", hash = "sha256:df2449253ef108a379b8b5d6b43f4b1a8e81a061d6537becd5582fba5f9196d7", size = 14566, upload-time = "2025-09-27T18:37:37.09Z" }, - { url = "https://files.pythonhosted.org/packages/18/1f/8d9c20e1c9440e215a44be5ab64359e207fcb4f675543f1cf9a2a7f648d0/markupsafe-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:7c3fb7d25180895632e5d3148dbdc29ea38ccb7fd210aa27acbd1201a1902c6e", size = 15053, upload-time = "2025-09-27T18:37:38.054Z" }, - { url = "https://files.pythonhosted.org/packages/4e/d3/fe08482b5cd995033556d45041a4f4e76e7f0521112a9c9991d40d39825f/markupsafe-3.0.3-cp39-cp39-win_arm64.whl", hash = "sha256:38664109c14ffc9e7437e86b4dceb442b0096dfe3541d7864d9cbe1da4cf36c8", size = 13928, upload-time = "2025-09-27T18:37:39.037Z" }, -] - -[[package]] -name = "mdit-py-plugins" -version = "0.4.2" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -dependencies = [ - { name = "markdown-it-py", marker = "python_full_version < '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/19/03/a2ecab526543b152300717cf232bb4bb8605b6edb946c845016fa9c9c9fd/mdit_py_plugins-0.4.2.tar.gz", hash = "sha256:5f2cd1fdb606ddf152d37ec30e46101a60512bc0e5fa1a7002c36647b09e26b5", size = 43542, upload-time = "2024-09-09T20:27:49.564Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/f7/7782a043553ee469c1ff49cfa1cdace2d6bf99a1f333cf38676b3ddf30da/mdit_py_plugins-0.4.2-py3-none-any.whl", hash = "sha256:0c673c3f889399a33b95e88d2f0d111b4447bdfea7f237dab2d488f459835636", size = 55316, upload-time = "2024-09-09T20:27:48.397Z" }, ] [[package]] name = "mdit-py-plugins" version = "0.5.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.11'", - "python_full_version == '3.10.*'", -] dependencies = [ - { name = "markdown-it-py", marker = "python_full_version >= '3.10'" }, + { name = "markdown-it-py" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b2/fd/a756d36c0bfba5f6e39a1cdbdbfdd448dc02692467d83816dff4592a1ebc/mdit_py_plugins-0.5.0.tar.gz", hash = "sha256:f4918cb50119f50446560513a8e311d574ff6aaed72606ddae6d35716fe809c6", size = 44655, upload-time = "2025-08-11T07:25:49.083Z" } wheels = [ @@ -627,12 +511,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5b/11/040983fad5132d85914c874a2836252bbc57832065548885b5bb5b0d4359/mypy-1.18.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d924eef3795cc89fecf6bedc6ed32b33ac13e8321344f6ddbf8ee89f706c05cb", size = 13326683, upload-time = "2025-09-19T00:09:55.572Z" }, { url = "https://files.pythonhosted.org/packages/e9/ba/89b2901dd77414dd7a8c8729985832a5735053be15b744c18e4586e506ef/mypy-1.18.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:20c02215a080e3a2be3aa50506c67242df1c151eaba0dcbc1e4e557922a26075", size = 13514749, upload-time = "2025-09-19T00:10:44.827Z" }, { url = "https://files.pythonhosted.org/packages/25/bc/cc98767cffd6b2928ba680f3e5bc969c4152bf7c2d83f92f5a504b92b0eb/mypy-1.18.2-cp314-cp314-win_amd64.whl", hash = "sha256:749b5f83198f1ca64345603118a6f01a4e99ad4bf9d103ddc5a3200cc4614adf", size = 9982959, upload-time = "2025-09-19T00:10:37.344Z" }, - { url = "https://files.pythonhosted.org/packages/3f/a6/490ff491d8ecddf8ab91762d4f67635040202f76a44171420bcbe38ceee5/mypy-1.18.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:25a9c8fb67b00599f839cf472713f54249a62efd53a54b565eb61956a7e3296b", size = 12807230, upload-time = "2025-09-19T00:09:49.471Z" }, - { url = "https://files.pythonhosted.org/packages/eb/2e/60076fc829645d167ece9e80db9e8375648d210dab44cc98beb5b322a826/mypy-1.18.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c2b9c7e284ee20e7598d6f42e13ca40b4928e6957ed6813d1ab6348aa3f47133", size = 11895666, upload-time = "2025-09-19T00:10:53.678Z" }, - { url = "https://files.pythonhosted.org/packages/97/4a/1e2880a2a5dda4dc8d9ecd1a7e7606bc0b0e14813637eeda40c38624e037/mypy-1.18.2-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d6985ed057513e344e43a26cc1cd815c7a94602fb6a3130a34798625bc2f07b6", size = 12499608, upload-time = "2025-09-19T00:09:36.204Z" }, - { url = "https://files.pythonhosted.org/packages/00/81/a117f1b73a3015b076b20246b1f341c34a578ebd9662848c6b80ad5c4138/mypy-1.18.2-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22f27105f1525ec024b5c630c0b9f36d5c1cc4d447d61fe51ff4bd60633f47ac", size = 13244551, upload-time = "2025-09-19T00:10:17.531Z" }, - { url = "https://files.pythonhosted.org/packages/9b/61/b9f48e1714ce87c7bf0358eb93f60663740ebb08f9ea886ffc670cea7933/mypy-1.18.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:030c52d0ea8144e721e49b1f68391e39553d7451f0c3f8a7565b59e19fcb608b", size = 13491552, upload-time = "2025-09-19T00:10:13.753Z" }, - { url = "https://files.pythonhosted.org/packages/c9/66/b2c0af3b684fa80d1b27501a8bdd3d2daa467ea3992a8aa612f5ca17c2db/mypy-1.18.2-cp39-cp39-win_amd64.whl", hash = "sha256:aa5e07ac1a60a253445797e42b8b2963c9675563a94f11291ab40718b016a7a0", size = 9765635, upload-time = "2025-09-19T00:10:30.993Z" }, { url = "https://files.pythonhosted.org/packages/87/e3/be76d87158ebafa0309946c4a73831974d4d6ab4f4ef40c3b53a385a66fd/mypy-1.18.2-py3-none-any.whl", hash = "sha256:22a1748707dd62b58d2ae53562ffc4d7f8bcc727e8ac7cbc69c053ddc874d47e", size = 2352367, upload-time = "2025-09-19T00:10:15.489Z" }, ] @@ -645,41 +523,17 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, ] -[[package]] -name = "myst-parser" -version = "3.0.1" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -dependencies = [ - { name = "docutils", marker = "python_full_version < '3.10'" }, - { name = "jinja2", marker = "python_full_version < '3.10'" }, - { name = "markdown-it-py", marker = "python_full_version < '3.10'" }, - { name = "mdit-py-plugins", version = "0.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "pyyaml", marker = "python_full_version < '3.10'" }, - { name = "sphinx", version = "7.4.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/49/64/e2f13dac02f599980798c01156393b781aec983b52a6e4057ee58f07c43a/myst_parser-3.0.1.tar.gz", hash = "sha256:88f0cb406cb363b077d176b51c476f62d60604d68a8dcdf4832e080441301a87", size = 92392, upload-time = "2024-04-28T20:22:42.116Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/de/21aa8394f16add8f7427f0a1326ccd2b3a2a8a3245c9252bc5ac034c6155/myst_parser-3.0.1-py3-none-any.whl", hash = "sha256:6457aaa33a5d474aca678b8ead9b3dc298e89c68e67012e73146ea6fd54babf1", size = 83163, upload-time = "2024-04-28T20:22:39.985Z" }, -] - [[package]] name = "myst-parser" version = "4.0.1" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.11'", - "python_full_version == '3.10.*'", -] dependencies = [ - { name = "docutils", marker = "python_full_version >= '3.10'" }, - { name = "jinja2", marker = "python_full_version >= '3.10'" }, - { name = "markdown-it-py", marker = "python_full_version >= '3.10'" }, - { name = "mdit-py-plugins", version = "0.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "pyyaml", marker = "python_full_version >= '3.10'" }, - { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, + { name = "docutils" }, + { name = "jinja2" }, + { name = "markdown-it-py" }, + { name = "mdit-py-plugins" }, + { name = "pyyaml" }, + { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/66/a5/9626ba4f73555b3735ad86247a8077d4603aa8628537687c839ab08bfe44/myst_parser-4.0.1.tar.gz", hash = "sha256:5cfea715e4f3574138aecbf7d54132296bfd72bb614d31168f48c477a830a7c4", size = 93985, upload-time = "2025-02-12T10:53:03.833Z" } @@ -705,26 +559,10 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" }, ] -[[package]] -name = "platformdirs" -version = "4.4.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -sdist = { url = "https://files.pythonhosted.org/packages/23/e8/21db9c9987b0e728855bd57bff6984f67952bea55d6f75e055c46b5383e8/platformdirs-4.4.0.tar.gz", hash = "sha256:ca753cf4d81dc309bc67b0ea38fd15dc97bc30ce419a7f58d13eb3bf14c4febf", size = 21634, upload-time = "2025-08-26T14:32:04.268Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/40/4b/2028861e724d3bd36227adfa20d3fd24c3fc6d52032f4a93c133be5d17ce/platformdirs-4.4.0-py3-none-any.whl", hash = "sha256:abd01743f24e5287cd7a5db3752faf1a2d65353f38ec26d98e25a6db65958c85", size = 18654, upload-time = "2025-08-26T14:32:02.735Z" }, -] - [[package]] name = "platformdirs" version = "4.5.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.11'", - "python_full_version == '3.10.*'", -] sdist = { url = "https://files.pythonhosted.org/packages/61/33/9611380c2bdb1225fdef633e2a9610622310fed35ab11dac9620972ee088/platformdirs-4.5.0.tar.gz", hash = "sha256:70ddccdd7c99fc5942e9fc25636a8b34d04c24b335100223152c2803e4063312", size = 21632, upload-time = "2025-10-08T17:44:48.791Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/73/cb/ac7874b3e5d58441674fb70742e6c374b28b0c7cb988d37d991cde47166c/platformdirs-4.5.0-py3-none-any.whl", hash = "sha256:e578a81bb873cbb89a41fcc904c7ef523cc18284b7e3b3ccf06aca1403b7ebd3", size = 18651, upload-time = "2025-10-08T17:44:47.223Z" }, @@ -869,19 +707,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e7/7e/8ac10ccb047dc0221aa2530ec3c7c05ab4656d4d4bd984ee85da7f3d5525/pydantic_core-2.41.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f9b9c968cfe5cd576fdd7361f47f27adeb120517e637d1b189eea1c3ece573f4", size = 1875124, upload-time = "2025-10-06T21:11:47.591Z" }, { url = "https://files.pythonhosted.org/packages/c3/e4/7d9791efeb9c7d97e7268f8d20e0da24d03438a7fa7163ab58f1073ba968/pydantic_core-2.41.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1ebc7ab67b856384aba09ed74e3e977dded40e693de18a4f197c67d0d4e6d8e", size = 2043075, upload-time = "2025-10-06T21:11:49.542Z" }, { url = "https://files.pythonhosted.org/packages/2d/c3/3f6e6b2342ac11ac8cd5cb56e24c7b14afa27c010e82a765ffa5f771884a/pydantic_core-2.41.1-cp314-cp314t-win_amd64.whl", hash = "sha256:8ae0dc57b62a762985bc7fbf636be3412394acc0ddb4ade07fe104230f1b9762", size = 1995341, upload-time = "2025-10-06T21:11:51.497Z" }, - { url = "https://files.pythonhosted.org/packages/aa/d2/90421a4749f15aa4f06dd1d25a6419b91b181ae7994a4e7c4ed0a6415057/pydantic_core-2.41.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:10ce489cf09a4956a1549af839b983edc59b0f60e1b068c21b10154e58f54f80", size = 2114974, upload-time = "2025-10-06T21:11:53.549Z" }, - { url = "https://files.pythonhosted.org/packages/39/6a/3b5c2ba43da5380f252b35f7e74851e1379f4935c8bccbbda05992b5fe4d/pydantic_core-2.41.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ff548c908caffd9455fd1342366bcf8a1ec8a3fca42f35c7fc60883d6a901074", size = 1940064, upload-time = "2025-10-06T21:11:55.268Z" }, - { url = "https://files.pythonhosted.org/packages/81/a9/050595183529316cf95d0f97662a4fe782dbea5f31dba0cf366015b67fad/pydantic_core-2.41.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d43bf082025082bda13be89a5f876cc2386b7727c7b322be2d2b706a45cea8e", size = 1976637, upload-time = "2025-10-06T21:11:57.024Z" }, - { url = "https://files.pythonhosted.org/packages/46/a8/846a8e466edd841c67f11f0ae738ca5c5d87968f6d8630bc449e2e6e11f2/pydantic_core-2.41.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:666aee751faf1c6864b2db795775dd67b61fdcf646abefa309ed1da039a97209", size = 2069274, upload-time = "2025-10-06T21:11:59.129Z" }, - { url = "https://files.pythonhosted.org/packages/4c/dc/19d01747082daf3667f952b6deee73e9e63338caa9c61442558cbdf8c876/pydantic_core-2.41.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b83aaeff0d7bde852c32e856f3ee410842ebc08bc55c510771d87dcd1c01e1ed", size = 2255302, upload-time = "2025-10-07T10:49:36.917Z" }, - { url = "https://files.pythonhosted.org/packages/fa/99/0d4f031aeddf2cf03a5eb8eafde50147259067716c32174551b786aa72e1/pydantic_core-2.41.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:055c7931b0329cb8acde20cdde6d9c2cbc2a02a0a8e54a792cddd91e2ea92c65", size = 2386549, upload-time = "2025-10-07T10:49:39.385Z" }, - { url = "https://files.pythonhosted.org/packages/09/7f/027061a060718733a6c016e7d4acc864c8bb69f0092d9b3da7e3888b102f/pydantic_core-2.41.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:530bbb1347e3e5ca13a91ac087c4971d7da09630ef8febd27a20a10800c2d06d", size = 2079817, upload-time = "2025-10-07T10:49:41.409Z" }, - { url = "https://files.pythonhosted.org/packages/3a/5e/791c16d5e2a0b394c2c236f7d2556dbc381f8666bc12db7d35dc051c67e3/pydantic_core-2.41.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:65a0ea16cfea7bfa9e43604c8bd726e63a3788b61c384c37664b55209fcb1d74", size = 2196276, upload-time = "2025-10-07T10:49:43.367Z" }, - { url = "https://files.pythonhosted.org/packages/a3/99/2c7010145da82fdd30955c1c0e1e75723ca7aef32b52f2565383fd2347d2/pydantic_core-2.41.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:8fa93fadff794c6d15c345c560513b160197342275c6d104cc879f932b978afc", size = 2157417, upload-time = "2025-10-07T10:49:45.176Z" }, - { url = "https://files.pythonhosted.org/packages/c6/df/b8f2ac7fa15479e989d0c2ea88e5e28eeb923096b2462804b9113bce51b5/pydantic_core-2.41.1-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:c8a1af9ac51969a494c6a82b563abae6859dc082d3b999e8fa7ba5ee1b05e8e8", size = 2333884, upload-time = "2025-10-07T10:49:46.896Z" }, - { url = "https://files.pythonhosted.org/packages/60/e8/06387d852bf67402fb0129b3297aa0c358aa9647e59f795c0965a7bedefe/pydantic_core-2.41.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:30edab28829703f876897c9471a857e43d847b8799c3c9e2fbce644724b50aa4", size = 2330735, upload-time = "2025-10-07T10:49:48.79Z" }, - { url = "https://files.pythonhosted.org/packages/07/41/8964006fd8897df13cb0eec374bda053d1936cbc81315acdd755d85c99d5/pydantic_core-2.41.1-cp39-cp39-win32.whl", hash = "sha256:84d0ff869f98be2e93efdf1ae31e5a15f0926d22af8677d51676e373abbfe57a", size = 1992855, upload-time = "2025-10-07T10:49:50.806Z" }, - { url = "https://files.pythonhosted.org/packages/d3/c9/0f68c22ba0cac693326a7de73f04c7543886e0b240e2320f8ced861f0c3d/pydantic_core-2.41.1-cp39-cp39-win_amd64.whl", hash = "sha256:b5674314987cdde5a5511b029fa5fb1556b3d147a367e01dd583b19cfa8e35df", size = 2030219, upload-time = "2025-10-07T10:49:52.712Z" }, { url = "https://files.pythonhosted.org/packages/16/89/d0afad37ba25f5801735af1472e650b86baad9fe807a42076508e4824a2a/pydantic_core-2.41.1-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:68f2251559b8efa99041bb63571ec7cdd2d715ba74cc82b3bc9eff824ebc8bf0", size = 2124001, upload-time = "2025-10-07T10:49:54.369Z" }, { url = "https://files.pythonhosted.org/packages/8e/c4/08609134b34520568ddebb084d9ed0a2a3f5f52b45739e6e22cb3a7112eb/pydantic_core-2.41.1-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:c7bc140c596097cb53b30546ca257dbe3f19282283190b1b5142928e5d5d3a20", size = 1941841, upload-time = "2025-10-07T10:49:56.248Z" }, { url = "https://files.pythonhosted.org/packages/2a/43/94a4877094e5fe19a3f37e7e817772263e2c573c94f1e3fa2b1eee56ef3b/pydantic_core-2.41.1-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2896510fce8f4725ec518f8b9d7f015a00db249d2fd40788f442af303480063d", size = 1961129, upload-time = "2025-10-07T10:49:58.298Z" }, @@ -943,33 +768,13 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e6/3d/8888e7ca0c6b093b52aa5c6693b0022e66d5958adcc685ed7a6a8ae615e8/pygments_styles-0.2.0-py3-none-any.whl", hash = "sha256:40fb7f1d34ce2b2792aecabc8d3877ca364eb04bb3b7f7747cfc9a7f0569bae9", size = 34200, upload-time = "2025-09-26T08:39:02.262Z" }, ] -[[package]] -name = "pyproject-api" -version = "1.9.1" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -dependencies = [ - { name = "packaging", marker = "python_full_version < '3.10'" }, - { name = "tomli", marker = "python_full_version < '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/19/fd/437901c891f58a7b9096511750247535e891d2d5a5a6eefbc9386a2b41d5/pyproject_api-1.9.1.tar.gz", hash = "sha256:43c9918f49daab37e302038fc1aed54a8c7a91a9fa935d00b9a485f37e0f5335", size = 22710, upload-time = "2025-05-12T14:41:58.025Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/e6/c293c06695d4a3ab0260ef124a74ebadba5f4c511ce3a4259e976902c00b/pyproject_api-1.9.1-py3-none-any.whl", hash = "sha256:7d6238d92f8962773dd75b5f0c4a6a27cce092a14b623b811dba656f3b628948", size = 13158, upload-time = "2025-05-12T14:41:56.217Z" }, -] - [[package]] name = "pyproject-api" version = "1.10.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.11'", - "python_full_version == '3.10.*'", -] dependencies = [ - { name = "packaging", marker = "python_full_version >= '3.10'" }, - { name = "tomli", marker = "python_full_version == '3.10.*'" }, + { name = "packaging" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/45/7b/c0e1333b61d41c69e59e5366e727b18c4992688caf0de1be10b3e5265f6b/pyproject_api-1.10.0.tar.gz", hash = "sha256:40c6f2d82eebdc4afee61c773ed208c04c19db4c4a60d97f8d7be3ebc0bbb330", size = 22785, upload-time = "2025-10-09T19:12:27.21Z" } wheels = [ @@ -1079,15 +884,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, - { url = "https://files.pythonhosted.org/packages/9f/62/67fc8e68a75f738c9200422bf65693fb79a4cd0dc5b23310e5202e978090/pyyaml-6.0.3-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da", size = 184450, upload-time = "2025-09-25T21:33:00.618Z" }, - { url = "https://files.pythonhosted.org/packages/ae/92/861f152ce87c452b11b9d0977952259aa7df792d71c1053365cc7b09cc08/pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917", size = 174319, upload-time = "2025-09-25T21:33:02.086Z" }, - { url = "https://files.pythonhosted.org/packages/d0/cd/f0cfc8c74f8a030017a2b9c771b7f47e5dd702c3e28e5b2071374bda2948/pyyaml-6.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9", size = 737631, upload-time = "2025-09-25T21:33:03.25Z" }, - { url = "https://files.pythonhosted.org/packages/ef/b2/18f2bd28cd2055a79a46c9b0895c0b3d987ce40ee471cecf58a1a0199805/pyyaml-6.0.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5", size = 836795, upload-time = "2025-09-25T21:33:05.014Z" }, - { url = "https://files.pythonhosted.org/packages/73/b9/793686b2d54b531203c160ef12bec60228a0109c79bae6c1277961026770/pyyaml-6.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a", size = 750767, upload-time = "2025-09-25T21:33:06.398Z" }, - { url = "https://files.pythonhosted.org/packages/a9/86/a137b39a611def2ed78b0e66ce2fe13ee701a07c07aebe55c340ed2a050e/pyyaml-6.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926", size = 727982, upload-time = "2025-09-25T21:33:08.708Z" }, - { url = "https://files.pythonhosted.org/packages/dd/62/71c27c94f457cf4418ef8ccc71735324c549f7e3ea9d34aba50874563561/pyyaml-6.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7", size = 755677, upload-time = "2025-09-25T21:33:09.876Z" }, - { url = "https://files.pythonhosted.org/packages/29/3d/6f5e0d58bd924fb0d06c3a6bad00effbdae2de5adb5cda5648006ffbd8d3/pyyaml-6.0.3-cp39-cp39-win32.whl", hash = "sha256:1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0", size = 142592, upload-time = "2025-09-25T21:33:10.983Z" }, - { url = "https://files.pythonhosted.org/packages/f0/0c/25113e0b5e103d7f1490c0e947e303fe4a696c10b501dea7a9f49d4e876c/pyyaml-6.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007", size = 158777, upload-time = "2025-09-25T21:33:15.55Z" }, ] [[package]] @@ -1128,16 +924,13 @@ dev = [ { name = "prek" }, { name = "pytest" }, { name = "pytest-cov" }, - { name = "tox-uv", version = "1.28.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "tox-uv", version = "1.29.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "tox-uv" }, ] doc = [ { name = "autodoc-pydantic" }, - { name = "myst-parser", version = "3.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "myst-parser", version = "4.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "myst-parser" }, { name = "shibuya" }, - { name = "sphinx", version = "7.4.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, + { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "sphinx-issues" }, { name = "sphinx-paramlinks" }, @@ -1180,8 +973,7 @@ version = "2025.9.25" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pygments-styles" }, - { name = "sphinx", version = "7.4.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, + { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/00/f3/36435b8e126b0a2cd7efa346cb366f25769094425fa0b145ab6991d20829/shibuya-2025.9.25.tar.gz", hash = "sha256:03131beb0f8e31cf4f501a4b744cd9c3f387cf23696259476d141b9ca976156b", size = 81798, upload-time = "2025-09-25T02:54:18.744Z" } @@ -1198,63 +990,31 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c8/78/3565d011c61f5a43488987ee32b6f3f656e7f107ac2782dd57bdd7d91d9a/snowballstemmer-3.0.1-py3-none-any.whl", hash = "sha256:6cd7b3897da8d6c9ffb968a6781fa6532dce9c3618a4b127d920dab764a19064", size = 103274, upload-time = "2025-05-09T16:34:50.371Z" }, ] -[[package]] -name = "sphinx" -version = "7.4.7" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -dependencies = [ - { name = "alabaster", version = "0.7.16", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "babel", marker = "python_full_version < '3.10'" }, - { name = "colorama", marker = "python_full_version < '3.10' and sys_platform == 'win32'" }, - { name = "docutils", marker = "python_full_version < '3.10'" }, - { name = "imagesize", marker = "python_full_version < '3.10'" }, - { name = "importlib-metadata", marker = "python_full_version < '3.10'" }, - { name = "jinja2", marker = "python_full_version < '3.10'" }, - { name = "packaging", marker = "python_full_version < '3.10'" }, - { name = "pygments", marker = "python_full_version < '3.10'" }, - { name = "requests", marker = "python_full_version < '3.10'" }, - { name = "snowballstemmer", marker = "python_full_version < '3.10'" }, - { name = "sphinxcontrib-applehelp", marker = "python_full_version < '3.10'" }, - { name = "sphinxcontrib-devhelp", marker = "python_full_version < '3.10'" }, - { name = "sphinxcontrib-htmlhelp", marker = "python_full_version < '3.10'" }, - { name = "sphinxcontrib-jsmath", marker = "python_full_version < '3.10'" }, - { name = "sphinxcontrib-qthelp", marker = "python_full_version < '3.10'" }, - { name = "sphinxcontrib-serializinghtml", marker = "python_full_version < '3.10'" }, - { name = "tomli", marker = "python_full_version < '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5b/be/50e50cb4f2eff47df05673d361095cafd95521d2a22521b920c67a372dcb/sphinx-7.4.7.tar.gz", hash = "sha256:242f92a7ea7e6c5b406fdc2615413890ba9f699114a9c09192d7dfead2ee9cfe", size = 8067911, upload-time = "2024-07-20T14:46:56.059Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/ef/153f6803c5d5f8917dbb7f7fcf6d34a871ede3296fa89c2c703f5f8a6c8e/sphinx-7.4.7-py3-none-any.whl", hash = "sha256:c2419e2135d11f1951cd994d6eb18a1835bd8fdd8429f9ca375dc1f3281bd239", size = 3401624, upload-time = "2024-07-20T14:46:52.142Z" }, -] - [[package]] name = "sphinx" version = "8.1.3" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version == '3.10.*'", + "python_full_version < '3.11'", ] dependencies = [ - { name = "alabaster", version = "1.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, - { name = "babel", marker = "python_full_version == '3.10.*'" }, - { name = "colorama", marker = "python_full_version == '3.10.*' and sys_platform == 'win32'" }, - { name = "docutils", marker = "python_full_version == '3.10.*'" }, - { name = "imagesize", marker = "python_full_version == '3.10.*'" }, - { name = "jinja2", marker = "python_full_version == '3.10.*'" }, - { name = "packaging", marker = "python_full_version == '3.10.*'" }, - { name = "pygments", marker = "python_full_version == '3.10.*'" }, - { name = "requests", marker = "python_full_version == '3.10.*'" }, - { name = "snowballstemmer", marker = "python_full_version == '3.10.*'" }, - { name = "sphinxcontrib-applehelp", marker = "python_full_version == '3.10.*'" }, - { name = "sphinxcontrib-devhelp", marker = "python_full_version == '3.10.*'" }, - { name = "sphinxcontrib-htmlhelp", marker = "python_full_version == '3.10.*'" }, - { name = "sphinxcontrib-jsmath", marker = "python_full_version == '3.10.*'" }, - { name = "sphinxcontrib-qthelp", marker = "python_full_version == '3.10.*'" }, - { name = "sphinxcontrib-serializinghtml", marker = "python_full_version == '3.10.*'" }, - { name = "tomli", marker = "python_full_version == '3.10.*'" }, + { name = "alabaster", marker = "python_full_version < '3.11'" }, + { name = "babel", marker = "python_full_version < '3.11'" }, + { name = "colorama", marker = "python_full_version < '3.11' and sys_platform == 'win32'" }, + { name = "docutils", marker = "python_full_version < '3.11'" }, + { name = "imagesize", marker = "python_full_version < '3.11'" }, + { name = "jinja2", marker = "python_full_version < '3.11'" }, + { name = "packaging", marker = "python_full_version < '3.11'" }, + { name = "pygments", marker = "python_full_version < '3.11'" }, + { name = "requests", marker = "python_full_version < '3.11'" }, + { name = "snowballstemmer", marker = "python_full_version < '3.11'" }, + { name = "sphinxcontrib-applehelp", marker = "python_full_version < '3.11'" }, + { name = "sphinxcontrib-devhelp", marker = "python_full_version < '3.11'" }, + { name = "sphinxcontrib-htmlhelp", marker = "python_full_version < '3.11'" }, + { name = "sphinxcontrib-jsmath", marker = "python_full_version < '3.11'" }, + { name = "sphinxcontrib-qthelp", marker = "python_full_version < '3.11'" }, + { name = "sphinxcontrib-serializinghtml", marker = "python_full_version < '3.11'" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/be0b61178fe2cdcb67e2a92fc9ebb488e3c51c4f74a36a7824c0adf23425/sphinx-8.1.3.tar.gz", hash = "sha256:43c1911eecb0d3e161ad78611bc905d1ad0e523e4ddc202a58a821773dc4c927", size = 8184611, upload-time = "2024-10-13T20:27:13.93Z" } wheels = [ @@ -1269,7 +1029,7 @@ resolution-markers = [ "python_full_version >= '3.11'", ] dependencies = [ - { name = "alabaster", version = "1.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "alabaster", marker = "python_full_version >= '3.11'" }, { name = "babel", marker = "python_full_version >= '3.11'" }, { name = "colorama", marker = "python_full_version >= '3.11' and sys_platform == 'win32'" }, { name = "docutils", marker = "python_full_version >= '3.11'" }, @@ -1297,8 +1057,7 @@ name = "sphinx-issues" version = "5.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "sphinx", version = "7.4.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, + { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/3a/62/b55f1c482ce20acee71185dbebf0497a48d23b325b48925d95d5ce0e4666/sphinx_issues-5.0.1.tar.gz", hash = "sha256:6da131d4545af00be4b48ec7c4086ea82c1371a05116bbe5779f57cff34bf16a", size = 14370, upload-time = "2025-04-10T13:41:41.945Z" } @@ -1312,8 +1071,7 @@ version = "0.6.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "docutils" }, - { name = "sphinx", version = "7.4.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, + { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ae/21/62d3a58ff7bd02bbb9245a63d1f0d2e0455522a11a78951d16088569fca8/sphinx-paramlinks-0.6.0.tar.gz", hash = "sha256:746a0816860aa3fff5d8d746efcbec4deead421f152687411db1d613d29f915e", size = 12363, upload-time = "2023-08-11T16:09:28.604Z" } @@ -1325,8 +1083,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "docutils" }, { name = "setuptools" }, - { name = "sphinx", version = "7.4.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, + { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "wheel" }, ] @@ -1438,89 +1195,37 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/77/b8/0135fadc89e73be292b473cb820b4f5a08197779206b33191e801feeae40/tomli-2.3.0-py3-none-any.whl", hash = "sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b", size = 14408, upload-time = "2025-10-08T22:01:46.04Z" }, ] -[[package]] -name = "tox" -version = "4.30.3" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -dependencies = [ - { name = "cachetools", marker = "python_full_version < '3.10'" }, - { name = "chardet", marker = "python_full_version < '3.10'" }, - { name = "colorama", marker = "python_full_version < '3.10'" }, - { name = "filelock", version = "3.19.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "packaging", marker = "python_full_version < '3.10'" }, - { name = "platformdirs", version = "4.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "pluggy", marker = "python_full_version < '3.10'" }, - { name = "pyproject-api", version = "1.9.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "tomli", marker = "python_full_version < '3.10'" }, - { name = "typing-extensions", marker = "python_full_version < '3.10'" }, - { name = "virtualenv", marker = "python_full_version < '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/51/b2/cee55172e5e10ce030b087cd3ac06641e47d08a3dc8d76c17b157dba7558/tox-4.30.3.tar.gz", hash = "sha256:f3dd0735f1cd4e8fbea5a3661b77f517456b5f0031a6256432533900e34b90bf", size = 202799, upload-time = "2025-10-02T16:24:39.974Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/e4/8bb9ce952820df4165eb34610af347665d6cb436898a234db9d84d093ce6/tox-4.30.3-py3-none-any.whl", hash = "sha256:a9f17b4b2d0f74fe0d76207236925a119095011e5c2e661a133115a8061178c9", size = 175512, upload-time = "2025-10-02T16:24:38.209Z" }, -] - [[package]] name = "tox" version = "4.31.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.11'", - "python_full_version == '3.10.*'", -] dependencies = [ - { name = "cachetools", marker = "python_full_version >= '3.10'" }, - { name = "chardet", marker = "python_full_version >= '3.10'" }, - { name = "colorama", marker = "python_full_version >= '3.10'" }, - { name = "filelock", version = "3.20.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "packaging", marker = "python_full_version >= '3.10'" }, - { name = "platformdirs", version = "4.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "pluggy", marker = "python_full_version >= '3.10'" }, - { name = "pyproject-api", version = "1.10.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "tomli", marker = "python_full_version == '3.10.*'" }, - { name = "typing-extensions", marker = "python_full_version == '3.10.*'" }, - { name = "virtualenv", marker = "python_full_version >= '3.10'" }, + { name = "cachetools" }, + { name = "chardet" }, + { name = "colorama" }, + { name = "filelock" }, + { name = "packaging" }, + { name = "platformdirs" }, + { name = "pluggy" }, + { name = "pyproject-api" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, + { name = "virtualenv" }, ] sdist = { url = "https://files.pythonhosted.org/packages/be/b9/1750ebb6e8e2d198a17822b7b851dea33e61dcc9c25f55a3e3636f67389a/tox-4.31.0.tar.gz", hash = "sha256:266381ffef35615ec0d40ae4969a9e43b506017597c0413d6545a603cc8c7561", size = 203294, upload-time = "2025-10-09T18:53:53.619Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/3e/84/1691aae773dccff72c866ad19af7adb12d4fb8b439c8bfb36ffc429c8c27/tox-4.31.0-py3-none-any.whl", hash = "sha256:328f392e6567e46cb0f9b625679456744dde940287dd1b39117627dc4b21d5da", size = 175917, upload-time = "2025-10-09T18:53:51.494Z" }, ] -[[package]] -name = "tox-uv" -version = "1.28.1" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.10'", -] -dependencies = [ - { name = "packaging", marker = "python_full_version < '3.10'" }, - { name = "tomli", marker = "python_full_version < '3.10'" }, - { name = "tox", version = "4.30.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "typing-extensions", marker = "python_full_version < '3.10'" }, - { name = "uv", marker = "python_full_version < '3.10'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f2/23/5c7f9bb50f25b4e9096a3b38e4b67604d3030388fdb6e645e54226b30cb0/tox_uv-1.28.1.tar.gz", hash = "sha256:fb01a34f49496e51e198196ee73a2be19ecd9cdbdc2508d86b981314c3d1b058", size = 23518, upload-time = "2025-10-09T16:13:45.286Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f1/54/46abc86d4cf2844d34dbd8e7bd0e4ed226ed6fb6a9a9481a85d4daff28ca/tox_uv-1.28.1-py3-none-any.whl", hash = "sha256:29f64076c57bda643b0c25dcb925011a35bfa57b0a94d3aaf550607d31e9f30a", size = 17363, upload-time = "2025-10-09T16:13:43.793Z" }, -] - [[package]] name = "tox-uv" version = "1.29.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.11'", - "python_full_version == '3.10.*'", -] dependencies = [ - { name = "packaging", marker = "python_full_version >= '3.10'" }, - { name = "tomli", marker = "python_full_version == '3.10.*'" }, - { name = "tox", version = "4.31.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "uv", marker = "python_full_version >= '3.10'" }, + { name = "packaging" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, + { name = "tox" }, + { name = "uv" }, ] sdist = { url = "https://files.pythonhosted.org/packages/4f/90/06752775b8cfadba8856190f5beae9f552547e0f287e0246677972107375/tox_uv-1.29.0.tar.gz", hash = "sha256:30fa9e6ad507df49d3c6a2f88894256bcf90f18e240a00764da6ecab1db24895", size = 23427, upload-time = "2025-10-09T20:40:27.384Z" } wheels = [ @@ -1589,10 +1294,8 @@ version = "20.35.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "distlib" }, - { name = "filelock", version = "3.19.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "filelock", version = "3.20.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "platformdirs", version = "4.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, - { name = "platformdirs", version = "4.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "filelock" }, + { name = "platformdirs" }, { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b4/55/a15050669ab087762c2c63010ef54643032ac1b32b5e15cc4ba75897806b/virtualenv-20.35.1.tar.gz", hash = "sha256:041dac43b6899858a91838b616599e80000e545dee01a21172a6a46746472cb2", size = 6005687, upload-time = "2025-10-09T22:21:16.139Z" } @@ -1608,12 +1311,3 @@ sdist = { url = "https://files.pythonhosted.org/packages/8a/98/2d9906746cdc6a6ef wheels = [ { url = "https://files.pythonhosted.org/packages/0b/2c/87f3254fd8ffd29e4c02732eee68a83a1d3c346ae39bc6822dcbcb697f2b/wheel-0.45.1-py3-none-any.whl", hash = "sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248", size = 72494, upload-time = "2024-11-23T00:18:21.207Z" }, ] - -[[package]] -name = "zipp" -version = "3.23.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547, upload-time = "2025-06-08T17:06:39.4Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276, upload-time = "2025-06-08T17:06:38.034Z" }, -]