diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 1a9a3fdf..b022f834 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,3 +5,5 @@ updates: schedule: interval: "weekly" target-branch: develop + cooldown: + default-days: 28 diff --git a/.github/workflows/lint_and_test.yml b/.github/workflows/lint_and_test.yml index 9b8d89cb..028b95f3 100644 --- a/.github/workflows/lint_and_test.yml +++ b/.github/workflows/lint_and_test.yml @@ -28,7 +28,7 @@ jobs: persist-credentials: false - name: Set up Python 3.11 - uses: actions/setup-python@v6 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 with: python-version: "3.11" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9c97b7ad..7349e515 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,7 +18,7 @@ default_stages: repos: - repo: 'https://github.com/pre-commit/pre-commit-hooks' - rev: v5.0.0 + rev: v6.0.0 hooks: - id: check-merge-conflict - id: debug-statements @@ -35,24 +35,24 @@ repos: args: ['-e'] # remove default --in-place argument and emit error - repo: 'https://github.com/astral-sh/ruff-pre-commit' - rev: v0.14.0 + rev: v0.14.14 hooks: - id: ruff args: ['--fix-only'] - repo: 'https://github.com/python-jsonschema/check-jsonschema' - rev: 0.33.0 + rev: 0.36.1 hooks: - id: check-dependabot - id: check-github-workflows - repo: 'https://github.com/rhysd/actionlint' - rev: v1.7.7 + rev: v1.7.10 hooks: - id: actionlint - repo: 'https://github.com/woodruffw/zizmor-pre-commit' - rev: v1.8.0 + rev: v1.22.0 hooks: - id: zizmor diff --git a/benchmarks/benchmarks/bench_nexus.py b/benchmarks/benchmarks/bench_nexus.py index ed4e56ea..59c1bae7 100644 --- a/benchmarks/benchmarks/bench_nexus.py +++ b/benchmarks/benchmarks/bench_nexus.py @@ -12,7 +12,7 @@ from itertools import pairwise from pathlib import Path from textwrap import dedent -from typing import Any, Callable, DefaultDict, Dict, Iterable, List, Mapping, Optional, Sequence, Set, TypeVar, Union +from typing import Any, Callable, DefaultDict, Dict, Iterable, List, Mapping, Sequence, Set, TypeVar from zipfile import ZIP_BZIP2, ZipFile import plotly @@ -39,7 +39,7 @@ class BenchmarkMeasure: pyperf: pyperf.Benchmark -def pyperf_bench_to_measure(data: Union[str, bytes]) -> BenchmarkMeasure: +def pyperf_bench_to_measure(data: str | bytes) -> BenchmarkMeasure: pybench_data = json.loads(data)["pybench_data"] return BenchmarkMeasure( base=pybench_data["base"], @@ -243,10 +243,10 @@ def add_arguments(cls, parser: ArgumentParser) -> None: def __init__( self, namespace: Namespace, - include: Optional[Sequence[str]] = None, - exclude: Optional[Sequence[str]] = None, - env_include: Optional[Sequence[str]] = None, - env_exclude: Optional[Sequence[str]] = None, + include: Sequence[str] | None = None, + exclude: Sequence[str] | None = None, + env_include: Sequence[str] | None = None, + env_exclude: Sequence[str] | None = None, ): self.include = include self.exclude = exclude @@ -328,7 +328,7 @@ def load_directors( env_description: self._submit_python(executor, env_description, env_spec_printer) for env_description in self.filtered_envs() } - for hub_description, env_spec_printer in zip(hub_descriptions, env_spec_printers) + for hub_description, env_spec_printer in zip(hub_descriptions, env_spec_printers, strict=False) } return { hub_description: { @@ -354,7 +354,7 @@ class CaseState: accessor: BenchAccessor checker: BenchChecker local_ids_with_warnings: Sequence[str] - max_tries: Optional[int] + max_tries: int | None tries_count: int = 0 @property @@ -388,12 +388,12 @@ def add_arguments(cls, parser: ArgumentParser) -> None: def __init__( self, namespace: Namespace, - include: Optional[Sequence[str]] = None, - exclude: Optional[Sequence[str]] = None, - env_include: Optional[Sequence[str]] = None, - env_exclude: Optional[Sequence[str]] = None, + include: Sequence[str] | None = None, + exclude: Sequence[str] | None = None, + env_include: Sequence[str] | None = None, + env_exclude: Sequence[str] | None = None, series: int = 2, - max_tries: Optional[int] = None, + max_tries: int | None = None, ): super().__init__( namespace=namespace, @@ -551,11 +551,11 @@ def add_arguments(cls, parser: ArgumentParser) -> None: def __init__( self, namespace: Namespace, - include: Optional[Sequence[str]] = None, - exclude: Optional[Sequence[str]] = None, - env_include: Optional[Sequence[str]] = None, - env_exclude: Optional[Sequence[str]] = None, - output: Optional[str] = None, + include: Sequence[str] | None = None, + exclude: Sequence[str] | None = None, + env_include: Sequence[str] | None = None, + env_exclude: Sequence[str] | None = None, + output: str | None = None, ): super().__init__( namespace=namespace, diff --git a/benchmarks/benchmarks/gh_issues/bench_adaptix.py b/benchmarks/benchmarks/gh_issues/bench_adaptix.py index b7758771..31ac82dc 100644 --- a/benchmarks/benchmarks/gh_issues/bench_adaptix.py +++ b/benchmarks/benchmarks/gh_issues/bench_adaptix.py @@ -1,6 +1,6 @@ from dataclasses import dataclass from datetime import datetime -from typing import List, Optional +from typing import List from adaptix import DebugTrail, Retort, name_mapping from benchmarks.gh_issues.common import ( @@ -19,7 +19,7 @@ class SimpleUser: id: int node_id: str avatar_url: str - gravatar_id: Optional[str] + gravatar_id: str | None url: str html_url: str followers_url: str @@ -33,9 +33,9 @@ class SimpleUser: received_events_url: str type: str site_admin: bool - name: Optional[str] = None - email: Optional[str] = None - starred_at: Optional[datetime] = None + name: str | None = None + email: str | None = None + starred_at: datetime | None = None @dataclass @@ -44,7 +44,7 @@ class Label: node_id: str url: str name: str - description: Optional[str] + description: str | None color: str default: bool @@ -65,11 +65,11 @@ class Reactions: @dataclass class PullRequest: - diff_url: Optional[str] - html_url: Optional[str] - patch_url: Optional[str] - url: Optional[str] - merged_at: Optional[datetime] = None + diff_url: str | None + html_url: str | None + patch_url: str | None + url: str | None + merged_at: datetime | None = None @dataclass @@ -84,25 +84,25 @@ class Issue: html_url: str number: int state: IssueState - state_reason: Optional[StateReason] + state_reason: StateReason | None title: str - user: Optional[SimpleUser] + user: SimpleUser | None labels: List[Label] - assignee: Optional[SimpleUser] - assignees: Optional[List[SimpleUser]] + assignee: SimpleUser | None + assignees: List[SimpleUser] | None locked: bool - active_lock_reason: Optional[str] + active_lock_reason: str | None comments: int - closed_at: Optional[datetime] - created_at: Optional[datetime] - updated_at: Optional[datetime] + closed_at: datetime | None + created_at: datetime | None + updated_at: datetime | None author_association: AuthorAssociation - reactions: Optional[Reactions] = None - pull_request: Optional[PullRequest] = None - body_html: Optional[str] = None - body_text: Optional[str] = None - timeline_url: Optional[str] = None - body: Optional[str] = None + reactions: Reactions | None = None + pull_request: PullRequest | None = None + body_html: str | None = None + body_text: str | None = None + timeline_url: str | None = None + body: str | None = None @dataclass diff --git a/benchmarks/benchmarks/gh_issues/bench_asdict.py b/benchmarks/benchmarks/gh_issues/bench_asdict.py index de4620f9..572452ae 100644 --- a/benchmarks/benchmarks/gh_issues/bench_asdict.py +++ b/benchmarks/benchmarks/gh_issues/bench_asdict.py @@ -1,6 +1,6 @@ from dataclasses import asdict, dataclass from datetime import datetime -from typing import List, Optional +from typing import List from benchmarks.gh_issues.common import AuthorAssociation, IssueState, StateReason, create_response from benchmarks.pybench.bench_api import benchmark_plan @@ -12,7 +12,7 @@ class SimpleUser: id: int node_id: str avatar_url: str - gravatar_id: Optional[str] + gravatar_id: str | None url: str html_url: str followers_url: str @@ -26,9 +26,9 @@ class SimpleUser: received_events_url: str type: str site_admin: bool - name: Optional[str] = None - email: Optional[str] = None - starred_at: Optional[datetime] = None + name: str | None = None + email: str | None = None + starred_at: datetime | None = None @dataclass @@ -37,7 +37,7 @@ class Label: node_id: str url: str name: str - description: Optional[str] + description: str | None color: str default: bool @@ -58,11 +58,11 @@ class Reactions: @dataclass class PullRequest: - diff_url: Optional[str] - html_url: Optional[str] - patch_url: Optional[str] - url: Optional[str] - merged_at: Optional[datetime] = None + diff_url: str | None + html_url: str | None + patch_url: str | None + url: str | None + merged_at: datetime | None = None @dataclass @@ -77,25 +77,25 @@ class Issue: html_url: str number: int state: IssueState - state_reason: Optional[StateReason] + state_reason: StateReason | None title: str - user: Optional[SimpleUser] + user: SimpleUser | None labels: List[Label] - assignee: Optional[SimpleUser] - assignees: Optional[List[SimpleUser]] + assignee: SimpleUser | None + assignees: List[SimpleUser] | None locked: bool - active_lock_reason: Optional[str] + active_lock_reason: str | None comments: int - closed_at: Optional[datetime] - created_at: Optional[datetime] - updated_at: Optional[datetime] + closed_at: datetime | None + created_at: datetime | None + updated_at: datetime | None author_association: AuthorAssociation - reactions: Optional[Reactions] = None - pull_request: Optional[PullRequest] = None - body_html: Optional[str] = None - body_text: Optional[str] = None - timeline_url: Optional[str] = None - body: Optional[str] = None + reactions: Reactions | None = None + pull_request: PullRequest | None = None + body_html: str | None = None + body_text: str | None = None + timeline_url: str | None = None + body: str | None = None @dataclass diff --git a/benchmarks/benchmarks/gh_issues/bench_cattrs.py b/benchmarks/benchmarks/gh_issues/bench_cattrs.py index 3f8a6f0e..a911f193 100644 --- a/benchmarks/benchmarks/gh_issues/bench_cattrs.py +++ b/benchmarks/benchmarks/gh_issues/bench_cattrs.py @@ -1,5 +1,5 @@ from datetime import datetime -from typing import List, Optional +from typing import List from attr import define from cattr import Converter @@ -21,7 +21,7 @@ class SimpleUser: id: int node_id: str avatar_url: str - gravatar_id: Optional[str] + gravatar_id: str | None url: str html_url: str followers_url: str @@ -35,9 +35,9 @@ class SimpleUser: received_events_url: str type: str site_admin: bool - name: Optional[str] = None - email: Optional[str] = None - starred_at: Optional[datetime] = None + name: str | None = None + email: str | None = None + starred_at: datetime | None = None @define @@ -46,7 +46,7 @@ class Label: node_id: str url: str name: str - description: Optional[str] + description: str | None color: str default: bool @@ -67,11 +67,11 @@ class Reactions: @define class PullRequest: - diff_url: Optional[str] - html_url: Optional[str] - patch_url: Optional[str] - url: Optional[str] - merged_at: Optional[datetime] = None + diff_url: str | None + html_url: str | None + patch_url: str | None + url: str | None + merged_at: datetime | None = None @define @@ -86,25 +86,25 @@ class Issue: html_url: str number: int state: IssueState - state_reason: Optional[StateReason] + state_reason: StateReason | None title: str - user: Optional[SimpleUser] + user: SimpleUser | None labels: List[Label] - assignee: Optional[SimpleUser] - assignees: Optional[List[SimpleUser]] + assignee: SimpleUser | None + assignees: List[SimpleUser] | None locked: bool - active_lock_reason: Optional[str] + active_lock_reason: str | None comments: int - closed_at: Optional[datetime] - created_at: Optional[datetime] - updated_at: Optional[datetime] + closed_at: datetime | None + created_at: datetime | None + updated_at: datetime | None author_association: AuthorAssociation - reactions: Optional[Reactions] = None - pull_request: Optional[PullRequest] = None - body_html: Optional[str] = None - body_text: Optional[str] = None - timeline_url: Optional[str] = None - body: Optional[str] = None + reactions: Reactions | None = None + pull_request: PullRequest | None = None + body_html: str | None = None + body_text: str | None = None + timeline_url: str | None = None + body: str | None = None @define diff --git a/benchmarks/benchmarks/gh_issues/bench_dataclass_factory.py b/benchmarks/benchmarks/gh_issues/bench_dataclass_factory.py index 6833ba1d..05a5bddb 100644 --- a/benchmarks/benchmarks/gh_issues/bench_dataclass_factory.py +++ b/benchmarks/benchmarks/gh_issues/bench_dataclass_factory.py @@ -1,6 +1,6 @@ from dataclasses import dataclass from datetime import datetime -from typing import List, Optional +from typing import List from dataclass_factory import Factory, Schema from tests_helpers import requires @@ -22,7 +22,7 @@ class SimpleUser: id: int node_id: str avatar_url: str - gravatar_id: Optional[str] + gravatar_id: str | None url: str html_url: str followers_url: str @@ -36,9 +36,9 @@ class SimpleUser: received_events_url: str type: str site_admin: bool - name: Optional[str] = None - email: Optional[str] = None - starred_at: Optional[datetime] = None + name: str | None = None + email: str | None = None + starred_at: datetime | None = None @dataclass @@ -47,7 +47,7 @@ class Label: node_id: str url: str name: str - description: Optional[str] + description: str | None color: str default: bool @@ -68,11 +68,11 @@ class Reactions: @dataclass class PullRequest: - diff_url: Optional[str] - html_url: Optional[str] - patch_url: Optional[str] - url: Optional[str] - merged_at: Optional[datetime] = None + diff_url: str | None + html_url: str | None + patch_url: str | None + url: str | None + merged_at: datetime | None = None @dataclass @@ -87,25 +87,25 @@ class Issue: html_url: str number: int state: IssueState - state_reason: Optional[StateReason] + state_reason: StateReason | None title: str - user: Optional[SimpleUser] + user: SimpleUser | None labels: List[Label] - assignee: Optional[SimpleUser] - assignees: Optional[List[SimpleUser]] + assignee: SimpleUser | None + assignees: List[SimpleUser] | None locked: bool - active_lock_reason: Optional[str] + active_lock_reason: str | None comments: int - closed_at: Optional[datetime] - created_at: Optional[datetime] - updated_at: Optional[datetime] + closed_at: datetime | None + created_at: datetime | None + updated_at: datetime | None author_association: AuthorAssociation - reactions: Optional[Reactions] = None - pull_request: Optional[PullRequest] = None - body_html: Optional[str] = None - body_text: Optional[str] = None - timeline_url: Optional[str] = None - body: Optional[str] = None + reactions: Reactions | None = None + pull_request: PullRequest | None = None + body_html: str | None = None + body_text: str | None = None + timeline_url: str | None = None + body: str | None = None @dataclass diff --git a/benchmarks/benchmarks/gh_issues/bench_marshmallow.py b/benchmarks/benchmarks/gh_issues/bench_marshmallow.py index d29f80c1..4fb7cabf 100644 --- a/benchmarks/benchmarks/gh_issues/bench_marshmallow.py +++ b/benchmarks/benchmarks/gh_issues/bench_marshmallow.py @@ -1,6 +1,6 @@ from dataclasses import dataclass from datetime import datetime -from typing import List, Optional +from typing import List from marshmallow import Schema, fields, post_dump, post_load @@ -20,7 +20,7 @@ class SimpleUser: id: int node_id: str avatar_url: str - gravatar_id: Optional[str] + gravatar_id: str | None url: str html_url: str followers_url: str @@ -34,9 +34,9 @@ class SimpleUser: received_events_url: str type: str site_admin: bool - name: Optional[str] = None - email: Optional[str] = None - starred_at: Optional[datetime] = None + name: str | None = None + email: str | None = None + starred_at: datetime | None = None @dataclass @@ -45,7 +45,7 @@ class Label: node_id: str url: str name: str - description: Optional[str] + description: str | None color: str default: bool @@ -66,11 +66,11 @@ class Reactions: @dataclass class PullRequest: - diff_url: Optional[str] - html_url: Optional[str] - patch_url: Optional[str] - url: Optional[str] - merged_at: Optional[datetime] = None + diff_url: str | None + html_url: str | None + patch_url: str | None + url: str | None + merged_at: datetime | None = None @dataclass @@ -85,25 +85,25 @@ class Issue: html_url: str number: int state: IssueState - state_reason: Optional[StateReason] + state_reason: StateReason | None title: str - user: Optional[SimpleUser] + user: SimpleUser | None labels: List[Label] - assignee: Optional[SimpleUser] - assignees: Optional[List[SimpleUser]] + assignee: SimpleUser | None + assignees: List[SimpleUser] | None locked: bool - active_lock_reason: Optional[str] + active_lock_reason: str | None comments: int - closed_at: Optional[datetime] - created_at: Optional[datetime] - updated_at: Optional[datetime] + closed_at: datetime | None + created_at: datetime | None + updated_at: datetime | None author_association: AuthorAssociation - reactions: Optional[Reactions] = None - pull_request: Optional[PullRequest] = None - body_html: Optional[str] = None - body_text: Optional[str] = None - timeline_url: Optional[str] = None - body: Optional[str] = None + reactions: Reactions | None = None + pull_request: PullRequest | None = None + body_html: str | None = None + body_text: str | None = None + timeline_url: str | None = None + body: str | None = None @dataclass diff --git a/benchmarks/benchmarks/gh_issues/bench_mashumaro.py b/benchmarks/benchmarks/gh_issues/bench_mashumaro.py index bf85d360..71c1b3c2 100644 --- a/benchmarks/benchmarks/gh_issues/bench_mashumaro.py +++ b/benchmarks/benchmarks/gh_issues/bench_mashumaro.py @@ -1,6 +1,6 @@ from dataclasses import dataclass from datetime import datetime -from typing import List, Optional +from typing import List from mashumaro import DataClassDictMixin from mashumaro.config import BaseConfig @@ -21,7 +21,7 @@ class SimpleUser(DataClassDictMixin): id: int node_id: str avatar_url: str - gravatar_id: Optional[str] + gravatar_id: str | None url: str html_url: str followers_url: str @@ -35,9 +35,9 @@ class SimpleUser(DataClassDictMixin): received_events_url: str type: str site_admin: bool - name: Optional[str] = None - email: Optional[str] = None - starred_at: Optional[datetime] = None + name: str | None = None + email: str | None = None + starred_at: datetime | None = None class Config: omit_default = True @@ -49,7 +49,7 @@ class Label(DataClassDictMixin): node_id: str url: str name: str - description: Optional[str] + description: str | None color: str default: bool @@ -77,11 +77,11 @@ class Config(BaseConfig): @dataclass class PullRequest(DataClassDictMixin): - diff_url: Optional[str] - html_url: Optional[str] - patch_url: Optional[str] - url: Optional[str] - merged_at: Optional[datetime] = None + diff_url: str | None + html_url: str | None + patch_url: str | None + url: str | None + merged_at: datetime | None = None class Config(BaseConfig): omit_default = True @@ -99,25 +99,25 @@ class Issue(DataClassDictMixin): html_url: str number: int state: IssueState - state_reason: Optional[StateReason] + state_reason: StateReason | None title: str - user: Optional[SimpleUser] + user: SimpleUser | None labels: List[Label] - assignee: Optional[SimpleUser] - assignees: Optional[List[SimpleUser]] + assignee: SimpleUser | None + assignees: List[SimpleUser] | None locked: bool - active_lock_reason: Optional[str] + active_lock_reason: str | None comments: int - closed_at: Optional[datetime] - created_at: Optional[datetime] - updated_at: Optional[datetime] + closed_at: datetime | None + created_at: datetime | None + updated_at: datetime | None author_association: AuthorAssociation - reactions: Optional[Reactions] = None - pull_request: Optional[PullRequest] = None - body_html: Optional[str] = None - body_text: Optional[str] = None - timeline_url: Optional[str] = None - body: Optional[str] = None + reactions: Reactions | None = None + pull_request: PullRequest | None = None + body_html: str | None = None + body_text: str | None = None + timeline_url: str | None = None + body: str | None = None class Config(BaseConfig): omit_default = True @@ -134,7 +134,7 @@ class SimpleUserLC(DataClassDictMixin): id: int node_id: str avatar_url: str - gravatar_id: Optional[str] + gravatar_id: str | None url: str html_url: str followers_url: str @@ -148,9 +148,9 @@ class SimpleUserLC(DataClassDictMixin): received_events_url: str type: str site_admin: bool - name: Optional[str] = None - email: Optional[str] = None - starred_at: Optional[datetime] = None + name: str | None = None + email: str | None = None + starred_at: datetime | None = None class Config: omit_default = True @@ -163,7 +163,7 @@ class LabelLC(DataClassDictMixin): node_id: str url: str name: str - description: Optional[str] + description: str | None color: str default: bool @@ -195,11 +195,11 @@ class Config(BaseConfig): @dataclass class PullRequestLC(DataClassDictMixin): - diff_url: Optional[str] - html_url: Optional[str] - patch_url: Optional[str] - url: Optional[str] - merged_at: Optional[datetime] = None + diff_url: str | None + html_url: str | None + patch_url: str | None + url: str | None + merged_at: datetime | None = None class Config: omit_default = True @@ -218,25 +218,25 @@ class IssueLC(DataClassDictMixin): html_url: str number: int state: IssueState - state_reason: Optional[StateReason] + state_reason: StateReason | None title: str - user: Optional[SimpleUserLC] + user: SimpleUserLC | None labels: List[LabelLC] - assignee: Optional[SimpleUserLC] - assignees: Optional[List[SimpleUserLC]] + assignee: SimpleUserLC | None + assignees: List[SimpleUserLC] | None locked: bool - active_lock_reason: Optional[str] + active_lock_reason: str | None comments: int - closed_at: Optional[datetime] - created_at: Optional[datetime] - updated_at: Optional[datetime] + closed_at: datetime | None + created_at: datetime | None + updated_at: datetime | None author_association: AuthorAssociation - reactions: Optional[ReactionsLC] = None - pull_request: Optional[PullRequestLC] = None - body_html: Optional[str] = None - body_text: Optional[str] = None - timeline_url: Optional[str] = None - body: Optional[str] = None + reactions: ReactionsLC | None = None + pull_request: PullRequestLC | None = None + body_html: str | None = None + body_text: str | None = None + timeline_url: str | None = None + body: str | None = None class Config: omit_default = True diff --git a/benchmarks/benchmarks/gh_issues/bench_msgspec.py b/benchmarks/benchmarks/gh_issues/bench_msgspec.py index 2543d440..baddd3bc 100644 --- a/benchmarks/benchmarks/gh_issues/bench_msgspec.py +++ b/benchmarks/benchmarks/gh_issues/bench_msgspec.py @@ -1,6 +1,6 @@ from datetime import datetime from functools import partial -from typing import List, Optional +from typing import List import msgspec import pytest @@ -22,7 +22,7 @@ class SimpleUser(msgspec.Struct, omit_defaults=True): id: int node_id: str avatar_url: str - gravatar_id: Optional[str] + gravatar_id: str | None url: str html_url: str followers_url: str @@ -36,9 +36,9 @@ class SimpleUser(msgspec.Struct, omit_defaults=True): received_events_url: str type: str site_admin: bool - name: Optional[str] = None - email: Optional[str] = None - starred_at: Optional[datetime] = None + name: str | None = None + email: str | None = None + starred_at: datetime | None = None class Label(msgspec.Struct): @@ -46,7 +46,7 @@ class Label(msgspec.Struct): node_id: str url: str name: str - description: Optional[str] + description: str | None color: str default: bool @@ -65,11 +65,11 @@ class Reactions(msgspec.Struct, rename=reactions_rename): class PullRequest(msgspec.Struct, omit_defaults=True): - diff_url: Optional[str] - html_url: Optional[str] - patch_url: Optional[str] - url: Optional[str] - merged_at: Optional[datetime] = None + diff_url: str | None + html_url: str | None + patch_url: str | None + url: str | None + merged_at: datetime | None = None class Issue(msgspec.Struct, omit_defaults=True): @@ -83,25 +83,25 @@ class Issue(msgspec.Struct, omit_defaults=True): html_url: str number: int state: IssueState - state_reason: Optional[StateReason] + state_reason: StateReason | None title: str - user: Optional[SimpleUser] + user: SimpleUser | None labels: List[Label] - assignee: Optional[SimpleUser] - assignees: Optional[List[SimpleUser]] + assignee: SimpleUser | None + assignees: List[SimpleUser] | None locked: bool - active_lock_reason: Optional[str] + active_lock_reason: str | None comments: int - closed_at: Optional[datetime] - created_at: Optional[datetime] - updated_at: Optional[datetime] + closed_at: datetime | None + created_at: datetime | None + updated_at: datetime | None author_association: AuthorAssociation - reactions: Optional[Reactions] = None - pull_request: Optional[PullRequest] = None - body_html: Optional[str] = None - body_text: Optional[str] = None - timeline_url: Optional[str] = None - body: Optional[str] = None + reactions: Reactions | None = None + pull_request: PullRequest | None = None + body_html: str | None = None + body_text: str | None = None + timeline_url: str | None = None + body: str | None = None class GetRepoIssuesResponse(msgspec.Struct): @@ -113,7 +113,7 @@ class SimpleUserNoGC(msgspec.Struct, omit_defaults=True, gc=False): id: int node_id: str avatar_url: str - gravatar_id: Optional[str] + gravatar_id: str | None url: str html_url: str followers_url: str @@ -127,9 +127,9 @@ class SimpleUserNoGC(msgspec.Struct, omit_defaults=True, gc=False): received_events_url: str type: str site_admin: bool - name: Optional[str] = None - email: Optional[str] = None - starred_at: Optional[datetime] = None + name: str | None = None + email: str | None = None + starred_at: datetime | None = None class LabelNoGC(msgspec.Struct, gc=False): @@ -137,7 +137,7 @@ class LabelNoGC(msgspec.Struct, gc=False): node_id: str url: str name: str - description: Optional[str] + description: str | None color: str default: bool @@ -156,11 +156,11 @@ class ReactionsNoGC(msgspec.Struct, rename=reactions_rename, gc=False): class PullRequestNoGC(msgspec.Struct, omit_defaults=True, gc=False): - diff_url: Optional[str] - html_url: Optional[str] - patch_url: Optional[str] - url: Optional[str] - merged_at: Optional[datetime] = None + diff_url: str | None + html_url: str | None + patch_url: str | None + url: str | None + merged_at: datetime | None = None class IssueNoGC(msgspec.Struct, omit_defaults=True, gc=False): @@ -174,25 +174,25 @@ class IssueNoGC(msgspec.Struct, omit_defaults=True, gc=False): html_url: str number: int state: IssueState - state_reason: Optional[StateReason] + state_reason: StateReason | None title: str - user: Optional[SimpleUserNoGC] + user: SimpleUserNoGC | None labels: List[LabelNoGC] - assignee: Optional[SimpleUserNoGC] - assignees: Optional[List[SimpleUserNoGC]] + assignee: SimpleUserNoGC | None + assignees: List[SimpleUserNoGC] | None locked: bool - active_lock_reason: Optional[str] + active_lock_reason: str | None comments: int - closed_at: Optional[datetime] - created_at: Optional[datetime] - updated_at: Optional[datetime] + closed_at: datetime | None + created_at: datetime | None + updated_at: datetime | None author_association: AuthorAssociation - reactions: Optional[ReactionsNoGC] = None - pull_request: Optional[PullRequestNoGC] = None - body_html: Optional[str] = None - body_text: Optional[str] = None - timeline_url: Optional[str] = None - body: Optional[str] = None + reactions: ReactionsNoGC | None = None + pull_request: PullRequestNoGC | None = None + body_html: str | None = None + body_text: str | None = None + timeline_url: str | None = None + body: str | None = None class GetRepoIssuesResponseNoGC(msgspec.Struct, gc=False): diff --git a/benchmarks/benchmarks/gh_issues/bench_pydantic.py b/benchmarks/benchmarks/gh_issues/bench_pydantic.py index beb3b98d..557c7ef8 100644 --- a/benchmarks/benchmarks/gh_issues/bench_pydantic.py +++ b/benchmarks/benchmarks/gh_issues/bench_pydantic.py @@ -1,5 +1,5 @@ from datetime import datetime -from typing import List, Optional +from typing import List from pydantic import BaseModel, Field @@ -18,7 +18,7 @@ class SimpleUser(BaseModel): id: int node_id: str avatar_url: str - gravatar_id: Optional[str] + gravatar_id: str | None url: str html_url: str followers_url: str @@ -32,9 +32,9 @@ class SimpleUser(BaseModel): received_events_url: str type: str site_admin: bool - name: Optional[str] = None - email: Optional[str] = None - starred_at: Optional[datetime] = None + name: str | None = None + email: str | None = None + starred_at: datetime | None = None class Label(BaseModel): @@ -42,7 +42,7 @@ class Label(BaseModel): node_id: str url: str name: str - description: Optional[str] + description: str | None color: str default: bool @@ -65,11 +65,11 @@ class Reactions(BaseModel): class PullRequest(BaseModel): - diff_url: Optional[str] - html_url: Optional[str] - patch_url: Optional[str] - url: Optional[str] - merged_at: Optional[datetime] = None + diff_url: str | None + html_url: str | None + patch_url: str | None + url: str | None + merged_at: datetime | None = None class Issue(BaseModel): @@ -83,25 +83,25 @@ class Issue(BaseModel): html_url: str number: int state: IssueState - state_reason: Optional[StateReason] + state_reason: StateReason | None title: str - user: Optional[SimpleUser] + user: SimpleUser | None labels: List[Label] - assignee: Optional[SimpleUser] - assignees: Optional[List[SimpleUser]] + assignee: SimpleUser | None + assignees: List[SimpleUser] | None locked: bool - active_lock_reason: Optional[str] + active_lock_reason: str | None comments: int - closed_at: Optional[datetime] - created_at: Optional[datetime] - updated_at: Optional[datetime] + closed_at: datetime | None + created_at: datetime | None + updated_at: datetime | None author_association: AuthorAssociation - reactions: Optional[Reactions] = None - pull_request: Optional[PullRequest] = None - body_html: Optional[str] = None - body_text: Optional[str] = None - timeline_url: Optional[str] = None - body: Optional[str] = None + reactions: Reactions | None = None + pull_request: PullRequest | None = None + body_html: str | None = None + body_text: str | None = None + timeline_url: str | None = None + body: str | None = None class GetRepoIssuesResponse(BaseModel): diff --git a/benchmarks/benchmarks/pybench/director_api.py b/benchmarks/benchmarks/pybench/director_api.py index 4677c60f..1dfbf48f 100644 --- a/benchmarks/benchmarks/pybench/director_api.py +++ b/benchmarks/benchmarks/pybench/director_api.py @@ -1,4 +1,3 @@ -# pylint: disable=import-error,no-name-in-module # ruff: noqa: T201, S603 import importlib.metadata import inspect @@ -7,13 +6,13 @@ import subprocess import sys from argparse import ArgumentParser, Namespace -from collections.abc import Iterable, Mapping, Sequence +from collections.abc import Callable, Iterable, Mapping, Sequence from copy import copy from dataclasses import dataclass from functools import cached_property from pathlib import Path from tempfile import TemporaryDirectory -from typing import Any, Callable, Literal, Optional, TypeVar, Union +from typing import Any, Literal, TypeVar import pyperf from pyperf._cli import format_checks @@ -41,18 +40,18 @@ @dataclass(frozen=True) class CheckParams: - stdev_rel_threshold: Optional[float] = None - ignore_pyperf_warnings: Optional[bool] = None + stdev_rel_threshold: float | None = None + ignore_pyperf_warnings: bool | None = None @dataclass(frozen=True) class BenchSchema: - entry_point: Union[Callable, str] + entry_point: Callable | str base: str tags: Iterable[str] kwargs: Mapping[str, Any] used_distributions: Sequence[str] - skip_if: Optional[Callable[[EnvSpec], bool]] = None + skip_if: Callable[[EnvSpec], bool] | None = None check_params: Callable[[EnvSpec], CheckParams] = lambda env_spec: CheckParams() @@ -73,9 +72,9 @@ def add_arguments(cls, parser: ArgumentParser) -> None: def create( self, - storage_type: Optional[Literal["fs", "sqlite"]] = None, - sqlite_db: Optional[Path] = None, - fs_data_dir: Optional[Path] = None, + storage_type: Literal["fs", "sqlite"] | None = None, + sqlite_db: Path | None = None, + fs_data_dir: Path | None = None, ) -> BenchStorage: if storage_type is None or storage_type == "sqlite": return SqliteBenchStorage( @@ -116,7 +115,7 @@ def __init__( def add_arguments(self, parser: ArgumentParser) -> None: parser.add_argument("--env-spec", action="extend", nargs="+", required=False, metavar="KEY=VALUE") - def override_state(self, env_spec: Optional[Iterable[str]]): + def override_state(self, env_spec: Iterable[str] | None): if env_spec is not None: update_data = {} for item in env_spec: @@ -175,7 +174,7 @@ def schemas(self) -> Sequence[BenchSchema]: if schema.skip_if is None or not schema.skip_if(self.env_spec) ] - def get_case_result(self, schema: BenchSchema) -> Optional[BenchCaseResult]: + def get_case_result(self, schema: BenchSchema) -> BenchCaseResult | None: return self._storage.get_case_result(self.get_id(schema)) def get_existing_case_result(self, schema: BenchSchema) -> BenchCaseResult: @@ -214,7 +213,7 @@ def _process_pyperf_warnings( if not line.startswith("Use") ] - def get_warnings(self, schema: BenchSchema) -> Optional[Sequence[str]]: + def get_warnings(self, schema: BenchSchema) -> Sequence[str] | None: data = self.accessor.get_case_result(schema) if data is None: return None @@ -279,8 +278,8 @@ def add_arguments(self, parser: ArgumentParser) -> None: def run_benchmarks( self, *, - include: Optional[Sequence[str]] = None, - exclude: Optional[Sequence[str]] = None, + include: Sequence[str] | None = None, + exclude: Sequence[str] | None = None, missing: bool = False, unstable: bool = False, ) -> None: @@ -430,7 +429,7 @@ def add(self, *schemas: BenchSchema) -> None: def add_iter(self, schemas: Iterable[BenchSchema]) -> None: self.schemas.extend(schemas) - def cli(self, args: Optional[Sequence[str]] = None): + def cli(self, args: Sequence[str] | None = None): accessor = self.make_accessor() self._validate_schemas(accessor) diff --git a/benchmarks/benchmarks/pybench/parametrization.py b/benchmarks/benchmarks/pybench/parametrization.py index af7fab40..5e6eacca 100644 --- a/benchmarks/benchmarks/pybench/parametrization.py +++ b/benchmarks/benchmarks/pybench/parametrization.py @@ -1,12 +1,12 @@ import itertools from collections.abc import Iterable, Iterator, Mapping -from typing import Any, Optional, TypeVar +from typing import Any, TypeVar P = TypeVar("P", bound="Parametrizer") class Parametrizer: - def __init__(self, *, product: Optional[Mapping[str, Iterable[Any]]] = None) -> None: + def __init__(self, *, product: Mapping[str, Iterable[Any]] | None = None) -> None: self._product: dict[str, Iterable[Any]] = {} if product is None else dict(product) def product(self: P, variants: Mapping[str, Iterable[Any]]) -> P: @@ -15,10 +15,10 @@ def product(self: P, variants: Mapping[str, Iterable[Any]]) -> P: def __iter__(self) -> Iterator[dict[str, Any]]: for case_values in itertools.product(*self._product.values()): - yield dict(zip(self._product.keys(), case_values)) + yield dict(zip(self._product.keys(), case_values, strict=False)) -def bool_tag_spec(key: str, tag: Optional[str] = None) -> Mapping[str, Mapping[Any, Optional[str]]]: +def bool_tag_spec(key: str, tag: str | None = None) -> Mapping[str, Mapping[Any, str | None]]: if tag is None: tag = key return { @@ -29,7 +29,7 @@ def bool_tag_spec(key: str, tag: Optional[str] = None) -> Mapping[str, Mapping[A } -def tags_from_case(spec: Mapping[str, Mapping[Any, Optional[str]]], case: Mapping[str, Any]) -> Iterable[str]: +def tags_from_case(spec: Mapping[str, Mapping[Any, str | None]], case: Mapping[str, Any]) -> Iterable[str]: for key, value in case.items(): result = spec[key][value] if result is not None: diff --git a/benchmarks/benchmarks/pybench/storage.py b/benchmarks/benchmarks/pybench/storage.py index d13dbd38..142b9e9c 100644 --- a/benchmarks/benchmarks/pybench/storage.py +++ b/benchmarks/benchmarks/pybench/storage.py @@ -5,7 +5,7 @@ from contextlib import AbstractContextManager from datetime import datetime, timezone from pathlib import Path -from typing import Any, Optional, TypedDict +from typing import Any, TypedDict from pyperf._formatter import format_timedelta @@ -35,7 +35,7 @@ def write_case_result(self, result: BenchCaseResult, stats: BenchCaseResultStats ... @abstractmethod - def get_case_result(self, case_id: str) -> Optional[BenchCaseResult]: + def get_case_result(self, case_id: str) -> BenchCaseResult | None: ... @@ -43,7 +43,7 @@ class UninitedBenchStorage(BenchStorage): def write_case_result(self, result: BenchCaseResult, stats: BenchCaseResultStats) -> None: raise NotImplementedError - def get_case_result(self, case_id: str) -> Optional[BenchCaseResult]: + def get_case_result(self, case_id: str) -> BenchCaseResult | None: raise NotImplementedError @@ -59,7 +59,7 @@ def write_case_result(self, result: BenchCaseResult, stats: BenchCaseResultStats result_file.parent.mkdir(parents=True, exist_ok=True) result_file.write_text(json.dumps(result)) - def get_case_result(self, case_id: str) -> Optional[BenchCaseResult]: + def get_case_result(self, case_id: str) -> BenchCaseResult | None: try: result_text = self._get_result_file(case_id).read_text() except FileNotFoundError: @@ -196,7 +196,7 @@ def write_case_result(self, result: BenchCaseResult, stats: BenchCaseResultStats ) connection.commit() - def get_case_result(self, case_id: str) -> Optional[BenchCaseResult]: + def get_case_result(self, case_id: str) -> BenchCaseResult | None: with self._connect() as connection: result = connection.execute( self.GET_BENCH_RESULT_QUERY, diff --git a/benchmarks/benchmarks/pybench/utils.py b/benchmarks/benchmarks/pybench/utils.py index 54c8bb5b..3125972e 100644 --- a/benchmarks/benchmarks/pybench/utils.py +++ b/benchmarks/benchmarks/pybench/utils.py @@ -1,5 +1,6 @@ +from collections.abc import Callable from importlib import import_module -from typing import Any, Callable +from typing import Any def load_by_object_ref(object_ref: str) -> Any: diff --git a/benchmarks/benchmarks/simple_structures/hub_loading.py b/benchmarks/benchmarks/simple_structures/hub_loading.py index 9eef43c6..cf74df47 100644 --- a/benchmarks/benchmarks/simple_structures/hub_loading.py +++ b/benchmarks/benchmarks/simple_structures/hub_loading.py @@ -1,5 +1,4 @@ import sys -from pathlib import Path from adaptix import DebugTrail from benchmarks.pybench.director_api import BenchmarkDirector, BenchSchema, CheckParams diff --git a/docs/custom_ext/macros.py b/docs/custom_ext/macros.py index acff2619..db7d9c21 100644 --- a/docs/custom_ext/macros.py +++ b/docs/custom_ext/macros.py @@ -1,9 +1,9 @@ -import tomllib from abc import ABC, abstractmethod from collections.abc import Iterable from pathlib import Path from textwrap import dedent, indent +import tomllib from docutils.statemachine import StringList from sphinx.util import docutils from sphinx.util.docutils import SphinxDirective diff --git a/docs/examples/benchmarks/gh_issues_models.py b/docs/examples/benchmarks/gh_issues_models.py index 7bf90dc3..4107c4b2 100644 --- a/docs/examples/benchmarks/gh_issues_models.py +++ b/docs/examples/benchmarks/gh_issues_models.py @@ -1,7 +1,6 @@ from dataclasses import dataclass from datetime import datetime from enum import Enum -from typing import Optional class IssueState(str, Enum): @@ -32,7 +31,7 @@ class SimpleUser: id: int node_id: str avatar_url: str - gravatar_id: Optional[str] + gravatar_id: str | None url: str html_url: str followers_url: str @@ -46,9 +45,9 @@ class SimpleUser: received_events_url: str type: str site_admin: bool - name: Optional[str] = None - email: Optional[str] = None - starred_at: Optional[datetime] = None + name: str | None = None + email: str | None = None + starred_at: datetime | None = None @dataclass @@ -57,7 +56,7 @@ class Label: node_id: str url: str name: str - description: Optional[str] + description: str | None color: str default: bool @@ -78,11 +77,11 @@ class Reactions: @dataclass class PullRequest: - diff_url: Optional[str] - html_url: Optional[str] - patch_url: Optional[str] - url: Optional[str] - merged_at: Optional[datetime] = None + diff_url: str | None + html_url: str | None + patch_url: str | None + url: str | None + merged_at: datetime | None = None @dataclass @@ -97,25 +96,25 @@ class Issue: html_url: str number: int state: IssueState - state_reason: Optional[StateReason] + state_reason: StateReason | None title: str - user: Optional[SimpleUser] + user: SimpleUser | None labels: list[Label] - assignee: Optional[SimpleUser] - assignees: Optional[list[SimpleUser]] + assignee: SimpleUser | None + assignees: list[SimpleUser] | None locked: bool - active_lock_reason: Optional[str] + active_lock_reason: str | None comments: int - closed_at: Optional[datetime] - created_at: Optional[datetime] - updated_at: Optional[datetime] + closed_at: datetime | None + created_at: datetime | None + updated_at: datetime | None author_association: AuthorAssociation - reactions: Optional[Reactions] = None - pull_request: Optional[PullRequest] = None - body_html: Optional[str] = None - body_text: Optional[str] = None - timeline_url: Optional[str] = None - body: Optional[str] = None + reactions: Reactions | None = None + pull_request: PullRequest | None = None + body_html: str | None = None + body_text: str | None = None + timeline_url: str | None = None + body: str | None = None @dataclass diff --git a/docs/examples/common/dealing_with_type_checking/chat.py b/docs/examples/common/dealing_with_type_checking/chat.py index 1ee9b348..c5d6800a 100644 --- a/docs/examples/common/dealing_with_type_checking/chat.py +++ b/docs/examples/common/dealing_with_type_checking/chat.py @@ -1,4 +1,4 @@ -# ruff: noqa: UP006 +# ruff: noqa: UP006, UP035 from dataclasses import dataclass from typing import TYPE_CHECKING, List diff --git a/docs/examples/common/dealing_with_type_checking/main.py b/docs/examples/common/dealing_with_type_checking/main.py index 01f0defa..4814fe66 100644 --- a/docs/examples/common/dealing_with_type_checking/main.py +++ b/docs/examples/common/dealing_with_type_checking/main.py @@ -1,4 +1,4 @@ -# ruff: noqa: UP006 +# ruff: noqa: UP006, UP035 from typing import List, get_type_hints from adaptix.type_tools import exec_type_checking diff --git a/docs/examples/conversion/extended_usage/global_allow_unlinked_optional.py b/docs/examples/conversion/extended_usage/global_allow_unlinked_optional.py index ff92a130..f25d3fa7 100644 --- a/docs/examples/conversion/extended_usage/global_allow_unlinked_optional.py +++ b/docs/examples/conversion/extended_usage/global_allow_unlinked_optional.py @@ -1,5 +1,4 @@ from dataclasses import dataclass, field -from typing import Optional from adaptix.conversion import allow_unlinked_optional, get_converter @@ -16,7 +15,7 @@ class BookDTO: title: str price: int author: str - collection_id: Optional[int] = None + collection_id: int | None = None bookmarks_ids: list[str] = field(default_factory=list) diff --git a/docs/examples/conversion/extended_usage/link_constant.py b/docs/examples/conversion/extended_usage/link_constant.py index 1c8b36f0..1f4b122f 100644 --- a/docs/examples/conversion/extended_usage/link_constant.py +++ b/docs/examples/conversion/extended_usage/link_constant.py @@ -1,5 +1,4 @@ from dataclasses import dataclass -from typing import Optional from adaptix import P from adaptix.conversion import get_converter, link_constant @@ -17,7 +16,7 @@ class BookDTO: title: str price: int author: str - collection_id: Optional[int] + collection_id: int | None bookmarks_ids: list[str] diff --git a/docs/examples/conversion/extended_usage/using_default_value_for_fields.py b/docs/examples/conversion/extended_usage/using_default_value_for_fields.py index 43eeb768..4742be11 100644 --- a/docs/examples/conversion/extended_usage/using_default_value_for_fields.py +++ b/docs/examples/conversion/extended_usage/using_default_value_for_fields.py @@ -1,5 +1,4 @@ from dataclasses import dataclass -from typing import Optional from adaptix import P from adaptix.conversion import allow_unlinked_optional, get_converter @@ -17,7 +16,7 @@ class BookDTO: title: str price: int author: str - collection_id: Optional[int] = None + collection_id: int | None = None convert_book_to_dto = get_converter( diff --git a/docs/examples/loading-and-dumping/extended_usage/detecting_absense_of_a_field/custom_sentinel.py b/docs/examples/loading-and-dumping/extended_usage/detecting_absense_of_a_field/custom_sentinel.py index f712196a..20a87165 100644 --- a/docs/examples/loading-and-dumping/extended_usage/detecting_absense_of_a_field/custom_sentinel.py +++ b/docs/examples/loading-and-dumping/extended_usage/detecting_absense_of_a_field/custom_sentinel.py @@ -1,6 +1,5 @@ from dataclasses import dataclass from enum import Enum -from typing import Optional, Union from adaptix import Retort, as_sentinel, name_mapping from adaptix.load_error import AggregateLoadError, TypeLoadError @@ -13,8 +12,8 @@ class MySentinel(Enum): @dataclass class PatchBook: id: int - title: Union[str, MySentinel] = MySentinel.VALUE - sub_title: Union[Optional[str], MySentinel] = MySentinel.VALUE + title: str | MySentinel = MySentinel.VALUE + sub_title: str | None | MySentinel = MySentinel.VALUE retort = Retort( diff --git a/docs/examples/loading-and-dumping/extended_usage/detecting_absense_of_a_field/none_as_sentinel.py b/docs/examples/loading-and-dumping/extended_usage/detecting_absense_of_a_field/none_as_sentinel.py index 5e37d7aa..21fd3f70 100644 --- a/docs/examples/loading-and-dumping/extended_usage/detecting_absense_of_a_field/none_as_sentinel.py +++ b/docs/examples/loading-and-dumping/extended_usage/detecting_absense_of_a_field/none_as_sentinel.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from typing import Optional, Union +from typing import Union from adaptix import P, Retort, as_sentinel, name_mapping from adaptix.load_error import AggregateLoadError, TypeLoadError @@ -8,8 +8,8 @@ @dataclass class PatchBook: id: int - title: Optional[str] = None - sub_title: Optional[str] = None + title: str | None = None + sub_title: str | None = None retort = Retort( diff --git a/docs/examples/loading-and-dumping/extended_usage/detecting_absense_of_a_field/omitted.py b/docs/examples/loading-and-dumping/extended_usage/detecting_absense_of_a_field/omitted.py index 8c22cde5..1d4e5fcf 100644 --- a/docs/examples/loading-and-dumping/extended_usage/detecting_absense_of_a_field/omitted.py +++ b/docs/examples/loading-and-dumping/extended_usage/detecting_absense_of_a_field/omitted.py @@ -1,5 +1,4 @@ from dataclasses import dataclass -from typing import Optional from adaptix import Omittable, Omitted, Retort, name_mapping from adaptix.load_error import AggregateLoadError, TypeLoadError @@ -9,7 +8,7 @@ class PatchBook: id: int title: Omittable[str] = Omitted() - sub_title: Omittable[Optional[str]] = Omitted() + sub_title: Omittable[str | None] = Omitted() retort = Retort( diff --git a/docs/examples/loading-and-dumping/extended_usage/generic_classes_simple.py b/docs/examples/loading-and-dumping/extended_usage/generic_classes_simple.py index c8595dc8..3ce3e124 100644 --- a/docs/examples/loading-and-dumping/extended_usage/generic_classes_simple.py +++ b/docs/examples/loading-and-dumping/extended_usage/generic_classes_simple.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from typing import Generic, Optional, TypeVar +from typing import Generic, TypeVar from adaptix import Retort @@ -8,8 +8,8 @@ @dataclass class MinMax(Generic[T]): - min: Optional[T] = None - max: Optional[T] = None + min: T | None = None + max: T | None = None retort = Retort() diff --git a/docs/examples/loading-and-dumping/extended_usage/omit_default.py b/docs/examples/loading-and-dumping/extended_usage/omit_default.py index 850a04c0..8385097c 100644 --- a/docs/examples/loading-and-dumping/extended_usage/omit_default.py +++ b/docs/examples/loading-and-dumping/extended_usage/omit_default.py @@ -1,5 +1,4 @@ from dataclasses import dataclass, field -from typing import Optional from adaptix import Retort, name_mapping @@ -7,7 +6,7 @@ @dataclass class Book: title: str - sub_title: Optional[str] = None + sub_title: str | None = None authors: list[str] = field(default_factory=list) diff --git a/docs/examples/loading-and-dumping/extended_usage/omit_default_selective.py b/docs/examples/loading-and-dumping/extended_usage/omit_default_selective.py index 01d7fbc5..6a4d0a40 100644 --- a/docs/examples/loading-and-dumping/extended_usage/omit_default_selective.py +++ b/docs/examples/loading-and-dumping/extended_usage/omit_default_selective.py @@ -1,5 +1,4 @@ from dataclasses import dataclass, field -from typing import Optional from adaptix import Retort, name_mapping @@ -7,7 +6,7 @@ @dataclass class Book: title: str - sub_title: Optional[str] = None + sub_title: str | None = None authors: list[str] = field(default_factory=list) diff --git a/docs/examples/loading-and-dumping/extended_usage/recursive_data_types.py b/docs/examples/loading-and-dumping/extended_usage/recursive_data_types.py index 5c53917a..3233c883 100644 --- a/docs/examples/loading-and-dumping/extended_usage/recursive_data_types.py +++ b/docs/examples/loading-and-dumping/extended_usage/recursive_data_types.py @@ -1,4 +1,4 @@ -# ruff: noqa: UP006 +# ruff: noqa: UP006, UP035 from dataclasses import dataclass from typing import List diff --git a/docs/examples/loading-and-dumping/specific_types_behavior/union_case_overlapping.py b/docs/examples/loading-and-dumping/specific_types_behavior/union_case_overlapping.py index ec9d4910..676f0c91 100644 --- a/docs/examples/loading-and-dumping/specific_types_behavior/union_case_overlapping.py +++ b/docs/examples/loading-and-dumping/specific_types_behavior/union_case_overlapping.py @@ -1,5 +1,4 @@ from dataclasses import dataclass -from typing import Union from adaptix import Retort @@ -17,4 +16,4 @@ class Dog: retort = Retort() -retort.load({"name": "Tardar Sauce", "breed": "mixed"}, Union[Cat, Dog]) +retort.load({"name": "Tardar Sauce", "breed": "mixed"}, Cat | Dog) diff --git a/docs/examples/loading-and-dumping/specific_types_behavior/union_model_supersets.py b/docs/examples/loading-and-dumping/specific_types_behavior/union_model_supersets.py index 3a3ab9ac..eb6a471d 100644 --- a/docs/examples/loading-and-dumping/specific_types_behavior/union_model_supersets.py +++ b/docs/examples/loading-and-dumping/specific_types_behavior/union_model_supersets.py @@ -1,5 +1,4 @@ from dataclasses import dataclass -from typing import Union from adaptix import Retort @@ -18,4 +17,4 @@ class Bike(Vehicle): data = {"speed": 10, "wheel_count": 3} assert retort.load(data, Bike) == Bike(speed=10, wheel_count=3) assert retort.load(data, Vehicle) == Vehicle(speed=10) -retort.load(data, Union[Bike, Vehicle]) # result is undefined +retort.load(data, Bike | Vehicle) # result is undefined diff --git a/docs/examples/loading-and-dumping/specific_types_behavior/union_with_designator.py b/docs/examples/loading-and-dumping/specific_types_behavior/union_with_designator.py index 5d8b3da8..5483737c 100644 --- a/docs/examples/loading-and-dumping/specific_types_behavior/union_with_designator.py +++ b/docs/examples/loading-and-dumping/specific_types_behavior/union_with_designator.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from typing import Literal, Union +from typing import Literal from adaptix import Retort @@ -22,6 +22,6 @@ class Dog: retort = Retort() data = {"name": "Tardar Sauce", "breed": "mixed", "kind": "cat"} -cat = retort.load(data, Union[Cat, Dog]) +cat = retort.load(data, Cat | Dog) assert cat == Cat(name="Tardar Sauce", breed="mixed") assert retort.dump(cat) == data diff --git a/docs/examples/reference/integrations/sqlalchemy_json/preamble.py b/docs/examples/reference/integrations/sqlalchemy_json/preamble.py index ffd48dbb..da9684ca 100644 --- a/docs/examples/reference/integrations/sqlalchemy_json/preamble.py +++ b/docs/examples/reference/integrations/sqlalchemy_json/preamble.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from typing import Literal, Union +from typing import Literal from adaptix import Retort from adaptix.integrations.sqlalchemy import AdaptixJSON @@ -22,7 +22,7 @@ class UserChanged: tag: Literal["user_changed"] = "user_changed" -AnyAuditLog = Union[UserCreated, UserChanged] +AnyAuditLog = UserCreated | UserChanged class Base(DeclarativeBase): diff --git a/docs/examples/why_not_pydantic/instantiating_penalty_models.py b/docs/examples/why_not_pydantic/instantiating_penalty_models.py index 35caf57e..a805e0ba 100644 --- a/docs/examples/why_not_pydantic/instantiating_penalty_models.py +++ b/docs/examples/why_not_pydantic/instantiating_penalty_models.py @@ -1,6 +1,5 @@ from dataclasses import dataclass from datetime import datetime -from typing import Optional from pydantic import BaseModel, PositiveInt @@ -8,7 +7,7 @@ class UserPydantic(BaseModel): id: int name: str = "John Doe" - signup_ts: Optional[datetime] + signup_ts: datetime | None tastes: dict[str, PositiveInt] @@ -16,5 +15,5 @@ class UserPydantic(BaseModel): class UserDataclass: id: int name: str = "John Doe" - signup_ts: Optional[datetime] + signup_ts: datetime | None tastes: dict[str, PositiveInt] diff --git a/docs/examples/why_not_pydantic/underdone_class_mapping_default.py b/docs/examples/why_not_pydantic/underdone_class_mapping_default.py index 2b6a6db5..ba69a6dc 100644 --- a/docs/examples/why_not_pydantic/underdone_class_mapping_default.py +++ b/docs/examples/why_not_pydantic/underdone_class_mapping_default.py @@ -1,6 +1,5 @@ # mypy: disable-error-code="call-arg" from dataclasses import dataclass -from typing import Optional from pydantic import BaseModel @@ -13,7 +12,7 @@ class Book: class BookDTO(BaseModel): title: str - writer: Optional[str] = None # alias is forgotten! + writer: str | None = None # alias is forgotten! book = Book(title="Fahrenheit 451", author="Ray Bradbury") diff --git a/examples/api_division/models.py b/examples/api_division/models.py index a82f7c7b..c0883076 100644 --- a/examples/api_division/models.py +++ b/examples/api_division/models.py @@ -1,7 +1,7 @@ from dataclasses import dataclass from decimal import Decimal from enum import Enum, IntEnum -from typing import Literal, Optional, Union +from typing import Literal from phonenumbers import PhoneNumber @@ -33,7 +33,7 @@ class NotifyPhone: type: Literal["phone"] = "phone" -NotifyTarget = Union[NotifyEmail, NotifyPhone] +NotifyTarget = NotifyEmail | NotifyPhone @dataclass(frozen=True) @@ -48,5 +48,5 @@ class Receipt: type: ReceiptType items: list[RecItem] taxation: Taxation - notify: Optional[list[NotifyTarget]] + notify: list[NotifyTarget] | None version: Literal["1"] = "1" diff --git a/examples/api_division/money.py b/examples/api_division/money.py index 13852797..83e10271 100644 --- a/examples/api_division/money.py +++ b/examples/api_division/money.py @@ -1,6 +1,5 @@ from decimal import Decimal from functools import total_ordering -from typing import Union class TooPreciseAmountError(Exception): @@ -38,5 +37,5 @@ def from_decimal_rubles(cls, rubles_: Decimal): return cls(int(kopek)) -def rubles(value: Union[int, str, Decimal]) -> Money: +def rubles(value: int | str | Decimal) -> Money: return Money.from_decimal_rubles(Decimal(value)) diff --git a/examples/api_division/test_example.py b/examples/api_division/test_example.py index 63112dc3..e9396ea2 100644 --- a/examples/api_division/test_example.py +++ b/examples/api_division/test_example.py @@ -1,6 +1,6 @@ from copy import deepcopy from decimal import Decimal -from typing import Any, List, Optional, Union +from typing import Any import phonenumbers from tests_helpers import raises_exc, with_trail @@ -20,7 +20,7 @@ from .retort import inner_receipt_retort, outer_receipt_retort -def change(data, path: List[Union[str, int]], new_value: Any): +def change(data, path: list[str | int], new_value: Any): new_data = deepcopy(data) target = new_data @@ -105,7 +105,7 @@ def test_outer_loading_bad_phone(): [ with_trail( UnionLoadError( - f"while loading {Optional[list[NotifyTarget]]}", + f"while loading {list[NotifyTarget] | None}", [ TypeLoadError(None, [{"type": "phone", "value": "+1-541-754-3010"}]), AggregateLoadError( diff --git a/examples/real_world_app/db_models.py b/examples/real_world_app/db_models.py index 29853400..afa81b82 100644 --- a/examples/real_world_app/db_models.py +++ b/examples/real_world_app/db_models.py @@ -1,5 +1,4 @@ from dataclasses import dataclass -from typing import Optional from sqlalchemy import ForeignKey from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column @@ -21,8 +20,8 @@ class SignupMeta: @dataclass class UserMetadata: - signup: Optional[SignupMeta] - imported_from: Optional[str] + signup: SignupMeta | None + imported_from: str | None _db_retort = Retort() diff --git a/examples/simple_api_processing/models.py b/examples/simple_api_processing/models.py index e7d632d5..7414f9c8 100644 --- a/examples/simple_api_processing/models.py +++ b/examples/simple_api_processing/models.py @@ -1,6 +1,5 @@ from dataclasses import dataclass, field from datetime import datetime -from typing import Optional @dataclass @@ -19,8 +18,8 @@ class Forecast: clouds: int dew_point: float - sunrise: Optional[datetime] = None - sunset: Optional[datetime] = None + sunrise: datetime | None = None + sunset: datetime | None = None @dataclass @@ -39,7 +38,7 @@ class ForecastPack: timezone: str timezone_offset: int - current: Optional[Forecast] = None + current: Forecast | None = None minutely: list[Forecast] = field(default_factory=list) hourly: list[Forecast] = field(default_factory=list) daily: list[Forecast] = field(default_factory=list) diff --git a/pyproject.toml b/pyproject.toml index db53f827..a58bb9ee 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -123,9 +123,6 @@ output-format = "concise" [tool.ruff.lint.isort] combine-as-imports = true -extra-standard-library = [ - "tomllib", # because requires-python = '>=3.9' -] [tool.ruff.lint] @@ -150,12 +147,6 @@ ignore = [ 'FIX002', 'RUF012', - # Turn on full drop support of 3.9 - 'UP045', - 'UP007', - 'B905', - 'UP035', - 'PYI019', # turn on after 3.11 # Rules emitting false alerts @@ -205,17 +196,21 @@ ignore = [ 'PLR2004', 'N806', 'FA102', - 'UP006', # turn on after 3.9 - 'UP035', # turn on after 3.9 - 'UP044', # turn on after 3.9 - 'UP045', # turn on after 3.9 - 'UP049', + 'E501', 'PLC0105', 'PLC0415', 'PYI061', 'PLW1641', 'FURB157', + + # Test must keep old type hints + 'UP006', + 'UP007', + 'UP035', + 'UP044', + 'UP045', + 'UP049', ] "tests/*/local_helpers.py" = ['S101', 'PLR2004', 'PLC0105', 'N806', 'FA102'] "tests/*/data_*.py" = ['F821'] @@ -229,7 +224,7 @@ ignore = [ ] "examples/*" = [ - 'UP035', 'UP006', # turn on after 3.9 + 'UP035', 'PLW1641', 'S101' ] diff --git a/requirements/dev.txt b/requirements/dev.txt index b4088086..c37b5cb5 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -112,6 +112,8 @@ jsonschema-rs==0.40.0 ; implementation_name != 'pypy' # via -r requirements/raw/_test_base.txt jsonschema-specifications==2025.4.1 # via jsonschema +librt==0.7.8 ; platform_python_implementation != 'PyPy' + # via mypy lxml==5.4.0 # via astpath mando==0.7.1 @@ -136,7 +138,7 @@ msgspec==0.20.0 ; implementation_name != 'pypy' # via # -r requirements/raw/bench.txt # -r requirements/raw/test_extra_new.txt -mypy==1.15.0 +mypy==1.19.1 # via -r requirements/raw/lint.txt mypy-extensions==1.1.0 # via mypy @@ -155,6 +157,8 @@ packaging==25.0 # sphinx # tox # tox-uv +pathspec==1.0.4 + # via mypy pbr==6.1.1 # via sphinxcontrib-apidoc phonenumberslite==9.0.5 @@ -221,7 +225,7 @@ rpds-py==0.25.1 # via # jsonschema # referencing -ruff==0.14.0 +ruff==0.14.14 # via -r requirements/raw/lint.txt schematics==2.1.1 # via -r requirements/raw/bench.txt @@ -307,7 +311,7 @@ typing-extensions==4.15.0 # typing-inspection typing-inspection==0.4.2 # via pydantic -typos==1.39.0 +typos==1.42.3 # via -r requirements/raw/lint.txt urllib3==2.4.0 # via requests diff --git a/requirements/lint.txt b/requirements/lint.txt index 01756780..14c6bda9 100644 --- a/requirements/lint.txt +++ b/requirements/lint.txt @@ -93,6 +93,8 @@ jsonschema-rs==0.40.0 ; implementation_name != 'pypy' # via -r requirements/raw/_test_base.txt jsonschema-specifications==2025.4.1 # via jsonschema +librt==0.7.8 ; platform_python_implementation != 'PyPy' + # via mypy lxml==5.4.0 # via astpath mando==0.7.1 @@ -117,7 +119,7 @@ msgspec==0.20.0 ; implementation_name != 'pypy' # via # -r requirements/raw/bench.txt # -r requirements/raw/test_extra_new.txt -mypy==1.15.0 +mypy==1.19.1 # via -r requirements/raw/lint.txt mypy-extensions==1.1.0 # via mypy @@ -133,6 +135,8 @@ packaging==25.0 # plotly # pytest # sphinx +pathspec==1.0.4 + # via mypy pbr==6.1.1 # via sphinxcontrib-apidoc phonenumberslite==9.0.5 @@ -189,7 +193,7 @@ rpds-py==0.25.1 # via # jsonschema # referencing -ruff==0.14.0 +ruff==0.14.14 # via -r requirements/raw/lint.txt schematics==2.1.1 # via -r requirements/raw/bench.txt @@ -267,7 +271,7 @@ typing-extensions==4.15.0 # typing-inspection typing-inspection==0.4.2 # via pydantic -typos==1.39.0 +typos==1.42.3 # via -r requirements/raw/lint.txt urllib3==2.4.0 # via requests diff --git a/requirements/raw/lint.txt b/requirements/raw/lint.txt index 91879677..638561ef 100644 --- a/requirements/raw/lint.txt +++ b/requirements/raw/lint.txt @@ -4,18 +4,18 @@ prek==0.2.5 -mypy[faster-cache]==1.15.0 +mypy[faster-cache]==1.19.1 vulture==2.10 -ruff==0.14.0 +ruff==0.14.14 radon==6.0.1 dlint==0.14.1 astpath[xpath]==0.9.1 -typos==1.39.0 +typos==1.42.3 # flake8-docstrings # pycodestyle # darglint diff --git a/scripts/invoke_tasks.py b/scripts/invoke_tasks.py index db76c668..cba04842 100644 --- a/scripts/invoke_tasks.py +++ b/scripts/invoke_tasks.py @@ -2,12 +2,11 @@ # ruff: noqa: FBT002 import shlex from pathlib import Path -from typing import Union from invoke import Context, task -def q(value: Union[Path, str]) -> str: +def q(value: Path | str) -> str: return shlex.quote(str(value)) diff --git a/src/adaptix/_internal/code_tools/cascade_namespace.py b/src/adaptix/_internal/code_tools/cascade_namespace.py index 3fbf2e49..a054030c 100644 --- a/src/adaptix/_internal/code_tools/cascade_namespace.py +++ b/src/adaptix/_internal/code_tools/cascade_namespace.py @@ -1,6 +1,5 @@ from abc import ABC, abstractmethod from collections.abc import Mapping, Set -from typing import Optional from .utils import NAME_TO_BUILTIN @@ -28,9 +27,9 @@ class BuiltinCascadeNamespace(CascadeNamespace): def __init__( self, - constants: Optional[Mapping[str, object]] = None, - outer_constants: Optional[Mapping[str, object]] = None, - occupied: Optional[Set[str]] = None, + constants: Mapping[str, object] | None = None, + outer_constants: Mapping[str, object] | None = None, + occupied: Set[str] | None = None, *, allow_builtins: bool = False, ): diff --git a/src/adaptix/_internal/code_tools/compiler.py b/src/adaptix/_internal/code_tools/compiler.py index b4283f90..44f63dcf 100644 --- a/src/adaptix/_internal/code_tools/compiler.py +++ b/src/adaptix/_internal/code_tools/compiler.py @@ -1,8 +1,9 @@ import linecache from abc import ABC, abstractmethod from collections import defaultdict +from collections.abc import Callable from threading import Lock -from typing import Any, Callable +from typing import Any from .code_builder import CodeBuilder diff --git a/src/adaptix/_internal/code_tools/utils.py b/src/adaptix/_internal/code_tools/utils.py index 3e78194d..b1fd27cb 100644 --- a/src/adaptix/_internal/code_tools/utils.py +++ b/src/adaptix/_internal/code_tools/utils.py @@ -1,7 +1,7 @@ import builtins import math from enum import Enum -from typing import Any, Optional +from typing import Any BUILTIN_TO_NAME = { (getattr(builtins, name), type(getattr(builtins, name))): name @@ -15,7 +15,7 @@ class _CannotBeRenderedError(Exception): pass -def get_literal_expr(obj: object) -> Optional[str]: +def get_literal_expr(obj: object) -> str | None: if type(obj) in (int, str, bytes, bytearray): return repr(obj) if type(obj) is float: @@ -52,7 +52,7 @@ def _try_sort(iterable): return iterable -def _get_complex_literal_expr(obj: object) -> Optional[str]: # noqa: PLR0911, C901 +def _get_complex_literal_expr(obj: object) -> str | None: # noqa: PLR0911, C901 if type(obj) is list: return _parenthesize("[]", obj) @@ -99,7 +99,7 @@ def _get_complex_literal_expr(obj: object) -> Optional[str]: # noqa: PLR0911, C } -def get_literal_from_factory(obj: object) -> Optional[str]: +def get_literal_from_factory(obj: object) -> str | None: try: return _CLS_TO_FACTORY_LITERAL.get(obj) except TypeError: diff --git a/src/adaptix/_internal/common.py b/src/adaptix/_internal/common.py index ee3be802..eabf10a9 100644 --- a/src/adaptix/_internal/common.py +++ b/src/adaptix/_internal/common.py @@ -1,4 +1,5 @@ -from typing import TYPE_CHECKING, Any, Callable, TypeVar, Union +from collections.abc import Callable +from typing import TYPE_CHECKING, Any, TypeVar K_contra = TypeVar("K_contra", contravariant=True) V_co = TypeVar("V_co", covariant=True) @@ -14,7 +15,7 @@ VarTuple = tuple[T, ...] -Catchable = Union[type[BaseException], VarTuple[type[BaseException]]] +Catchable = type[BaseException] | VarTuple[type[BaseException]] # https://github.com/python/typing/issues/684#issuecomment-548203158 if TYPE_CHECKING: diff --git a/src/adaptix/_internal/conversion/broaching/code_generator.py b/src/adaptix/_internal/conversion/broaching/code_generator.py index 69354f19..e87f0726 100644 --- a/src/adaptix/_internal/conversion/broaching/code_generator.py +++ b/src/adaptix/_internal/conversion/broaching/code_generator.py @@ -5,7 +5,6 @@ from collections import defaultdict from collections.abc import Mapping from inspect import Signature -from typing import Union from ...code_tools.ast_templater import ast_substitute from ...code_tools.cascade_namespace import BuiltinCascadeNamespace, CascadeNamespace @@ -25,12 +24,12 @@ UnpackMapping, ) -BroachingPlan = Union[ - ParameterElement, - ConstantElement, - FunctionElement["BroachingPlan"], - AccessorElement["BroachingPlan"], -] +BroachingPlan = ( + ParameterElement + | ConstantElement + | FunctionElement["BroachingPlan"] + | AccessorElement["BroachingPlan"] +) class GenState: diff --git a/src/adaptix/_internal/conversion/broaching/definitions.py b/src/adaptix/_internal/conversion/broaching/definitions.py index 443033e7..948fe0a3 100644 --- a/src/adaptix/_internal/conversion/broaching/definitions.py +++ b/src/adaptix/_internal/conversion/broaching/definitions.py @@ -1,5 +1,6 @@ +from collections.abc import Callable from dataclasses import dataclass -from typing import Any, Callable, Generic, TypeVar, Union +from typing import Any, Generic, TypeVar from adaptix._internal.common import VarTuple from adaptix._internal.model_tools.definitions import Accessor @@ -43,12 +44,12 @@ class UnpackMapping(Generic[PlanT]): element: PlanT -FuncCallArg = Union[ - PositionalArg[PlanT], - KeywordArg[PlanT], - UnpackIterable[PlanT], - UnpackMapping[PlanT], -] +FuncCallArg = ( + PositionalArg[PlanT] + | KeywordArg[PlanT] + | UnpackIterable[PlanT] + | UnpackMapping[PlanT] +) @dataclass(frozen=True) diff --git a/src/adaptix/_internal/conversion/coercer_provider.py b/src/adaptix/_internal/conversion/coercer_provider.py index 488855a0..d3ec63cf 100644 --- a/src/adaptix/_internal/conversion/coercer_provider.py +++ b/src/adaptix/_internal/conversion/coercer_provider.py @@ -1,8 +1,9 @@ import collections.abc from abc import ABC, abstractmethod from collections import deque +from collections.abc import Callable from dataclasses import replace -from typing import Any, Callable, ForwardRef, Union, final +from typing import Any, ForwardRef, Union, final from ..common import Coercer, OneArgCoercer, TypeHint from ..morphing.utils import try_normalize_type diff --git a/src/adaptix/_internal/conversion/converter_provider.py b/src/adaptix/_internal/conversion/converter_provider.py index 4cdfa9f1..0a186aa1 100644 --- a/src/adaptix/_internal/conversion/converter_provider.py +++ b/src/adaptix/_internal/conversion/converter_provider.py @@ -1,8 +1,8 @@ import itertools -from collections.abc import Mapping, Sequence +from collections.abc import Callable, Mapping, Sequence from functools import update_wrapper from inspect import Parameter, Signature -from typing import Any, Callable, Optional +from typing import Any from ..code_tools.cascade_namespace import BuiltinCascadeNamespace, CascadeNamespace from ..code_tools.code_builder import CodeBuilder @@ -82,7 +82,7 @@ def _register_mangled(self, namespace: CascadeNamespace, base: str, obj: object) def _produce_code( self, signature: Signature, - stub_function: Optional[Callable], + stub_function: Callable | None, closure_name: str, coercer: Coercer, ) -> tuple[str, Mapping[str, object]]: diff --git a/src/adaptix/_internal/conversion/facade/func.py b/src/adaptix/_internal/conversion/facade/func.py index cf86df3d..0c25e219 100644 --- a/src/adaptix/_internal/conversion/facade/func.py +++ b/src/adaptix/_internal/conversion/facade/func.py @@ -1,5 +1,5 @@ -from collections.abc import Iterable -from typing import Any, Callable, Optional, TypeVar, overload +from collections.abc import Callable, Iterable +from typing import Any, TypeVar, overload from ...common import TypeHint from ...provider.essential import Provider @@ -29,7 +29,7 @@ def get_converter( dst: type[DstT], *, recipe: Iterable[Provider] = (), - name: Optional[str] = None, + name: str | None = None, ) -> Callable[[SrcT], DstT]: ... @@ -40,12 +40,12 @@ def get_converter( dst: TypeHint, *, recipe: Iterable[Provider] = (), - name: Optional[str] = None, + name: str | None = None, ) -> Callable[[Any], Any]: ... -def get_converter(src: TypeHint, dst: TypeHint, *, recipe: Iterable[Provider] = (), name: Optional[str] = None): +def get_converter(src: TypeHint, dst: TypeHint, *, recipe: Iterable[Provider] = (), name: str | None = None): """Factory producing basic converter. :param src: A type of converter input data. @@ -67,7 +67,7 @@ def impl_converter(*, recipe: Iterable[Provider] = ()) -> Callable[[CallableT], ... -def impl_converter(stub_function: Optional[Callable] = None, *, recipe: Iterable[Provider] = ()): +def impl_converter(stub_function: Callable | None = None, *, recipe: Iterable[Provider] = ()): """Decorator producing converter with signature of stub function. :param stub_function: A function that signature is used to generate converter. diff --git a/src/adaptix/_internal/conversion/facade/provider.py b/src/adaptix/_internal/conversion/facade/provider.py index df2fd107..c1ed2d56 100644 --- a/src/adaptix/_internal/conversion/facade/provider.py +++ b/src/adaptix/_internal/conversion/facade/provider.py @@ -1,4 +1,5 @@ -from typing import Any, Callable, Optional, overload +from collections.abc import Callable +from typing import Any, overload from ...common import OneArgCoercer from ...model_tools.definitions import DefaultFactory, DefaultValue @@ -11,7 +12,7 @@ from ..request_filtering import FromCtxParam -def link(src: Pred, dst: Pred, *, coercer: Optional[OneArgCoercer] = None) -> Provider: +def link(src: Pred, dst: Pred, *, coercer: OneArgCoercer | None = None) -> Provider: """Basic provider to define custom linking between fields. :param src: Predicate specifying source point of linking. See :ref:`predicate-system` for details. diff --git a/src/adaptix/_internal/conversion/facade/retort.py b/src/adaptix/_internal/conversion/facade/retort.py index 3a8e4765..47be6d49 100644 --- a/src/adaptix/_internal/conversion/facade/retort.py +++ b/src/adaptix/_internal/conversion/facade/retort.py @@ -1,8 +1,8 @@ import inspect -from collections.abc import Iterable +from collections.abc import Callable, Iterable from functools import partial from inspect import Parameter, Signature -from typing import Any, Callable, Optional, TypeVar, overload +from typing import Any, TypeVar, overload from ...common import Converter, TypeHint from ...provider.essential import Provider @@ -64,12 +64,12 @@ class FilledConversionRetort(OperatingRetort): class AdornedConversionRetort(OperatingRetort): def _calculate_derived(self) -> None: super()._calculate_derived() - self._simple_converter_cache: dict[tuple[TypeHint, TypeHint, Optional[str]], Converter] = {} + self._simple_converter_cache: dict[tuple[TypeHint, TypeHint, str | None], Converter] = {} def replace( self: AR, *, - error_renderer: Omittable[Optional[ErrorRenderer]] = Omitted(), + error_renderer: Omittable[ErrorRenderer | None] = Omitted(), ) -> AR: with self._clone() as clone: if not isinstance(error_renderer, Omitted): @@ -87,8 +87,8 @@ def extend(self: AR, *, recipe: Iterable[Provider]) -> AR: def _produce_converter( self, signature: Signature, - stub_function: Optional[Callable], - function_name: Optional[str], + stub_function: Callable | None, + function_name: str | None, ) -> Callable[..., Any]: return self._facade_provide( ConverterRequest( @@ -99,7 +99,7 @@ def _produce_converter( error_message=f"Cannot produce converter for {signature!r}", ) - def _make_simple_converter(self, src: TypeHint, dst: TypeHint, name: Optional[str]) -> Converter: + def _make_simple_converter(self, src: TypeHint, dst: TypeHint, name: str | None) -> Converter: return self._produce_converter( signature=Signature( parameters=[Parameter("src", kind=Parameter.POSITIONAL_ONLY, annotation=src)], @@ -125,7 +125,7 @@ def get_converter( src: TypeHint, dst: TypeHint, *, - name: Optional[str] = None, + name: str | None = None, recipe: Iterable[Provider] = (), ) -> Callable[[Any], Any]: ... @@ -135,7 +135,7 @@ def get_converter( src: TypeHint, dst: TypeHint, *, - name: Optional[str] = None, + name: str | None = None, recipe: Iterable[Provider] = (), ): """Method producing basic converter. @@ -164,7 +164,7 @@ def impl_converter(self, func_stub: CallableT, /) -> CallableT: def impl_converter(self, *, recipe: Iterable[Provider] = ()) -> Callable[[CallableT], CallableT]: ... - def impl_converter(self, stub_function: Optional[Callable] = None, *, recipe: Iterable[Provider] = ()): + def impl_converter(self, stub_function: Callable | None = None, *, recipe: Iterable[Provider] = ()): """Decorator producing converter with signature of stub function. :param stub_function: A function that signature is used to generate converter. diff --git a/src/adaptix/_internal/conversion/linking_provider.py b/src/adaptix/_internal/conversion/linking_provider.py index 5d716d91..a45b4bc5 100644 --- a/src/adaptix/_internal/conversion/linking_provider.py +++ b/src/adaptix/_internal/conversion/linking_provider.py @@ -1,6 +1,6 @@ import itertools -from collections.abc import Iterable, Mapping -from typing import Callable, Optional, TypeVar, Union +from collections.abc import Callable, Iterable, Mapping +from typing import TypeVar from ..common import Coercer, OneArgCoercer, VarTuple from ..model_tools.definitions import DefaultFactory, DefaultValue, InputField, InputShape, Param, ParamKind @@ -40,12 +40,12 @@ def _iterate_sources(self, request: LinkingRequest) -> Iterable[LinkingSource]: class MatchingLinkingProvider(LinkingProvider): - def __init__(self, src_lsc: LocStackChecker, dst_lsc: LocStackChecker, coercer: Optional[OneArgCoercer]): + def __init__(self, src_lsc: LocStackChecker, dst_lsc: LocStackChecker, coercer: OneArgCoercer | None): self._src_lsc = src_lsc self._dst_lsc = dst_lsc self._one_arg_coercer = coercer - def _get_coercer(self) -> Optional[Coercer]: + def _get_coercer(self) -> Coercer | None: one_arg_coercer = self._one_arg_coercer if one_arg_coercer is None: return None @@ -62,7 +62,7 @@ def _provide_linking(self, mediator: Mediator, request: LinkingRequest) -> Linki class ConstantLinkingProvider(LinkingProvider): - def __init__(self, dst_lsc: LocStackChecker, default: Union[DefaultValue, DefaultFactory]): + def __init__(self, dst_lsc: LocStackChecker, default: DefaultValue | DefaultFactory): self._dst_lsc = dst_lsc self._default = default diff --git a/src/adaptix/_internal/conversion/model_coercer_provider.py b/src/adaptix/_internal/conversion/model_coercer_provider.py index 5ad0ef95..f041f7d5 100644 --- a/src/adaptix/_internal/conversion/model_coercer_provider.py +++ b/src/adaptix/_internal/conversion/model_coercer_provider.py @@ -1,7 +1,6 @@ import sys -from collections.abc import Iterable, Mapping, Sequence +from collections.abc import Callable, Iterable, Mapping, Sequence from inspect import Parameter, Signature -from typing import Callable, Optional from ..code_tools.compiler import BasicClosureCompiler, ClosureCompiler from ..code_tools.name_sanitizer import BuiltinNameSanitizer, NameSanitizer @@ -157,13 +156,13 @@ def _fetch_linkings( request: CoercerRequest, dst_shape: InputShape, src_shape: OutputShape, - ) -> Iterable[tuple[InputField, Optional[LinkingResult]]]: + ) -> Iterable[tuple[InputField, LinkingResult | None]]: sources = tuple( request.src.append_with(output_field_to_loc(src_field)) for src_field in src_shape.fields ) - def fetch_field_linking(dst_field: InputField) -> tuple[InputField, Optional[LinkingResult]]: + def fetch_field_linking(dst_field: InputField) -> tuple[InputField, LinkingResult | None]: destination = request.dst.append_with(input_field_to_loc(dst_field)) try: linking = mediator.provide( @@ -195,7 +194,7 @@ def fetch_field_linking(dst_field: InputField) -> tuple[InputField, Optional[Lin return mandatory_apply_by_iterable( fetch_field_linking, - zip(dst_shape.fields), + zip(dst_shape.fields, strict=False), lambda: "Cannot create coercer for models. Linkings for some fields are not found", ) @@ -288,7 +287,7 @@ def _generate_sub_plan( mediator: Mediator, request: CoercerRequest, field_linkings: Iterable[tuple[InputField, LinkingResult]], - parent_func: Optional[Callable], + parent_func: Callable | None, ) -> Mapping[InputField, BroachingPlan]: def generate_sub_plan(input_field: InputField, linking_result: LinkingResult): if isinstance(linking_result.linking, ConstantLinking): @@ -340,7 +339,7 @@ def generate_sub_plan(input_field: InputField, linking_result: LinkingResult): return { dst_field: sub_plan - for (dst_field, linking), sub_plan in zip(field_linkings, field_sub_plans) + for (dst_field, linking), sub_plan in zip(field_linkings, field_sub_plans, strict=True) } def _make_broaching_plan( @@ -375,7 +374,7 @@ def _make_broaching_plan( def _make_constructor_call( self, dst_shape: InputShape, - field_to_linking: Mapping[InputField, Optional[LinkingResult]], + field_to_linking: Mapping[InputField, LinkingResult | None], field_to_sub_plan: Mapping[InputField, BroachingPlan], ) -> BroachingPlan: args: list[FuncCallArg[BroachingPlan]] = [] diff --git a/src/adaptix/_internal/conversion/request_cls.py b/src/adaptix/_internal/conversion/request_cls.py index a1fa1f60..5c494f30 100644 --- a/src/adaptix/_internal/conversion/request_cls.py +++ b/src/adaptix/_internal/conversion/request_cls.py @@ -1,6 +1,7 @@ +from collections.abc import Callable from dataclasses import dataclass, field, replace from inspect import Signature -from typing import Callable, Optional, TypeVar, Union +from typing import TypeVar from ..common import Coercer, VarTuple from ..model_tools.definitions import DefaultFactory, DefaultValue, InputField, ParamKind @@ -13,12 +14,12 @@ @dataclass(frozen=True) class ConverterRequest(Request): signature: Signature - function_name: Optional[str] - stub_function: Optional[Callable] + function_name: str | None + stub_function: Callable | None -ConversionSourceItem = Union[FieldLoc, OutputFieldLoc, GenericParamLoc] -ConversionDestItem = Union[TypeHintLoc, InputFieldLoc, InputFuncFieldLoc, GenericParamLoc] +ConversionSourceItem = FieldLoc | OutputFieldLoc | GenericParamLoc +ConversionDestItem = TypeHintLoc | InputFieldLoc | InputFuncFieldLoc | GenericParamLoc @dataclass(frozen=True) @@ -36,12 +37,12 @@ def __post_init__(self): @dataclass(frozen=True) class FieldLinking: source: LinkingSource - coercer: Optional[Coercer] + coercer: Coercer | None @dataclass(frozen=True) class ConstantLinking: - constant: Union[DefaultValue, DefaultFactory] + constant: DefaultValue | DefaultFactory @dataclass(frozen=True) @@ -63,7 +64,7 @@ class ParamSpec: @dataclass(frozen=True) class LinkingResult: - linking: Union[FieldLinking, ConstantLinking, ModelLinking, FunctionLinking] + linking: FieldLinking | ConstantLinking | ModelLinking | FunctionLinking @dataclass(frozen=True) diff --git a/src/adaptix/_internal/datastructures.py b/src/adaptix/_internal/datastructures.py index 47389734..8bf3ada0 100644 --- a/src/adaptix/_internal/datastructures.py +++ b/src/adaptix/_internal/datastructures.py @@ -1,5 +1,6 @@ from collections import defaultdict from collections.abc import ( + Callable, Collection, Hashable, Iterable, @@ -13,7 +14,7 @@ ValuesView, ) from itertools import islice -from typing import Callable, Generic, Optional, Protocol, TypeVar, Union, runtime_checkable +from typing import Generic, Protocol, TypeVar, runtime_checkable from .common import VarTuple from .utils import MappingHashWrapper @@ -72,7 +73,7 @@ class ClassDispatcher(Generic[K_co, V]): """ __slots__ = ("_mapping",) - def __init__(self, mapping: Optional[Mapping[type[K_co], V]] = None): + def __init__(self, mapping: Mapping[type[K_co], V] | None = None): self._mapping: dict[type[K_co], V] = {} if mapping is None else dict(mapping) def dispatch(self, key: type[K_co]) -> V: @@ -174,7 +175,7 @@ def has(self, *classes: type[H]) -> bool: def get_or_raise( self, key: type[D], - exception_factory: Callable[[], Union[BaseException, type[BaseException]]], + exception_factory: Callable[[], BaseException | type[BaseException]], ) -> D: try: return self._mapping[key] # type: ignore[index,return-value] diff --git a/src/adaptix/_internal/integrations/msgspec/native.py b/src/adaptix/_internal/integrations/msgspec/native.py index f6b2e146..54bfe81b 100644 --- a/src/adaptix/_internal/integrations/msgspec/native.py +++ b/src/adaptix/_internal/integrations/msgspec/native.py @@ -1,6 +1,6 @@ -from collections.abc import Iterable +from collections.abc import Callable, Iterable from contextlib import suppress -from typing import Any, Callable, Optional, TypedDict +from typing import Any, TypedDict from ...common import Dumper, Loader from ...morphing.load_error import LoadError @@ -68,8 +68,8 @@ def native_msgspec_dumper_with_params(data): def native_msgspec( *preds: Pred, - convert: Optional[ConvertParams] = None, - to_builtins: Optional[ToBuiltinsParams] = None, + convert: ConvertParams | None = None, + to_builtins: ToBuiltinsParams | None = None, ) -> Provider: """Provider that represents value via msgspec. You can use this function to validate or serialize msgspec structs via msgspec itself. diff --git a/src/adaptix/_internal/integrations/pydantic/native.py b/src/adaptix/_internal/integrations/pydantic/native.py index 3297d64e..1671fdb2 100644 --- a/src/adaptix/_internal/integrations/pydantic/native.py +++ b/src/adaptix/_internal/integrations/pydantic/native.py @@ -1,5 +1,6 @@ +from collections.abc import Callable from contextlib import suppress -from typing import Any, Callable, Literal, Optional, TypedDict, TypeVar, Union +from typing import Any, Literal, Optional, TypedDict, TypeVar from ...common import Dumper, Loader from ...morphing.load_error import LoadError @@ -15,15 +16,15 @@ class ValidatePythonParams(TypedDict, total=False): - strict: Optional[bool] - from_attributes: Optional[bool] - context: Optional[Any] - self_instance: Optional[Any] - allow_partial: Union[bool, Literal["off", "on", "trailing-strings"]] + strict: bool | None + from_attributes: bool | None + context: Any | None + self_instance: Any | None + allow_partial: bool | Literal["off", "on", "trailing-strings"] class ToPythonParams(TypedDict, total=False): - mode: Optional[str] + mode: str | None include: Optional["IncEx"] exclude: Optional["IncEx"] by_alias: bool @@ -31,10 +32,10 @@ class ToPythonParams(TypedDict, total=False): exclude_defaults: bool exclude_none: bool round_trip: bool - warnings: Union[bool, Literal["none", "warn", "error"]] - fallback: Optional[Callable[[Any], Any]] + warnings: bool | Literal["none", "warn", "error"] + fallback: Callable[[Any], Any] | None serialize_as_any: bool - context: Optional[Any] + context: Any | None T = TypeVar("T") @@ -86,8 +87,8 @@ def native_pydantic_dumper(data): def native_pydantic( *preds: Pred, config: Optional["ConfigDict"] = None, - validate_python: Optional[ValidatePythonParams] = None, - to_python: Optional[ToPythonParams] = None, + validate_python: ValidatePythonParams | None = None, + to_python: ToPythonParams | None = None, ) -> Provider: """Provider that represents value via pydantic. You can use this function to validate or serialize pydantic models via pydantic itself. diff --git a/src/adaptix/_internal/integrations/sqlalchemy/orm.py b/src/adaptix/_internal/integrations/sqlalchemy/orm.py index c16462d0..6de4a068 100644 --- a/src/adaptix/_internal/integrations/sqlalchemy/orm.py +++ b/src/adaptix/_internal/integrations/sqlalchemy/orm.py @@ -1,4 +1,4 @@ -from typing import Any, Optional, Union +from typing import Any from sqlalchemy import JSON, Dialect, TypeDecorator, null from sqlalchemy.dialects import postgresql @@ -21,7 +21,7 @@ def __init__( retort: AdornedRetort, tp: TypeHint, *, - impl: Optional[TypeEngine] = None, + impl: TypeEngine | None = None, ): super().__init__() self.retort = retort @@ -37,7 +37,7 @@ def load_dialect_impl(self, dialect: Dialect) -> TypeEngine[Any]: return self._custom_impl return to_instance(self._load_default_dialect_impl(dialect)) - def _load_default_dialect_impl(self, dialect: Dialect) -> Union[TypeEngine[Any], type[TypeEngine[Any]]]: + def _load_default_dialect_impl(self, dialect: Dialect) -> TypeEngine[Any] | type[TypeEngine[Any]]: if isinstance(dialect, PGDialect): return postgresql.JSONB return JSON diff --git a/src/adaptix/_internal/model_tools/definitions.py b/src/adaptix/_internal/model_tools/definitions.py index 7a7871ca..aa0d05d5 100644 --- a/src/adaptix/_internal/model_tools/definitions.py +++ b/src/adaptix/_internal/model_tools/definitions.py @@ -1,9 +1,9 @@ from abc import ABC, abstractmethod -from collections.abc import Hashable, Mapping +from collections.abc import Callable, Hashable, Mapping from dataclasses import dataclass, field from enum import Enum from itertools import pairwise -from typing import Any, Callable, Generic, Optional, TypeVar, Union +from typing import Any, Generic, TypeVar from ..common import Catchable, TypeHint, VarTuple from ..feature_requirement import DistributionRequirement, DistributionVersionRequirement @@ -39,7 +39,12 @@ class DefaultFactoryWithSelf(Generic[S, T]): factory: Callable[[S], T] -Default = Union[NoDefault, DefaultValue[Any], DefaultFactory[Any], DefaultFactoryWithSelf[Any, Any]] +Default = ( + NoDefault + | DefaultValue[Any] + | DefaultFactory[Any] + | DefaultFactoryWithSelf[Any, Any] +) class Accessor(Hashable, ABC): @@ -50,7 +55,7 @@ def getter(self) -> Callable[[Any], Any]: @property @abstractmethod - def access_error(self) -> Optional[Catchable]: + def access_error(self) -> Catchable | None: ... @property @@ -60,7 +65,7 @@ def trail_element(self) -> TrailElement: class DescriptorAccessor(Accessor, ABC): - def __init__(self, attr_name: str, access_error: Optional[Catchable]): + def __init__(self, attr_name: str, access_error: Catchable | None): self._attr_name = attr_name self._access_error = access_error @@ -69,7 +74,7 @@ def getter(self, obj): return getattr(obj, self._attr_name) @property - def access_error(self) -> Optional[Catchable]: + def access_error(self) -> Catchable | None: return self._access_error @property @@ -93,7 +98,7 @@ def __repr__(self): class ItemAccessor(Accessor): - def __init__(self, key: Union[int, str], access_error: Optional[Catchable], path_element: TrailElement): + def __init__(self, key: int | str, access_error: Catchable | None, path_element: TrailElement): self.key = key self._access_error = access_error self._path_element = path_element @@ -103,7 +108,7 @@ def getter(self, obj): return obj[self.key] @property - def access_error(self) -> Optional[Catchable]: + def access_error(self) -> Catchable | None: return self._access_error @property @@ -139,7 +144,7 @@ def create_attr_accessor(attr_name: str, *, is_required: bool) -> DescriptorAcce ) -def create_key_accessor(key: Union[str, int], access_error: Optional[Catchable]) -> ItemAccessor: +def create_key_accessor(key: str | int, access_error: Catchable | None) -> ItemAccessor: return ItemAccessor( key=key, access_error=access_error, @@ -255,7 +260,7 @@ class InputShape(BaseShape, Generic[T]): """ fields: VarTuple[InputField] params: VarTuple[Param] - kwargs: Optional[ParamKwargs] + kwargs: ParamKwargs | None constructor: Callable[..., T] fields_dict: Mapping[str, InputField] = field(init=False, hash=False, repr=False, compare=False) @@ -313,8 +318,8 @@ class OutputShape(BaseShape): fields_dict: Mapping[str, OutputField] = field(init=False, hash=False, repr=False, compare=False) -Inp = TypeVar("Inp", bound=Optional[InputShape]) -Out = TypeVar("Out", bound=Optional[OutputShape]) +Inp = TypeVar("Inp", bound=InputShape | None) +Out = TypeVar("Out", bound=OutputShape | None) @dataclass(frozen=True) diff --git a/src/adaptix/_internal/model_tools/introspection/callable.py b/src/adaptix/_internal/model_tools/introspection/callable.py index c9b8c6d2..145c9635 100644 --- a/src/adaptix/_internal/model_tools/introspection/callable.py +++ b/src/adaptix/_internal/model_tools/introspection/callable.py @@ -2,7 +2,7 @@ import typing from inspect import Parameter, Signature from types import MappingProxyType -from typing import Any, Optional +from typing import Any from ...common import VarTuple from ...feature_requirement import HAS_PY_312 @@ -32,8 +32,8 @@ def _is_empty(value): def _unpack_typed_dict_kwargs( - param_kwargs: Optional[ParamKwargs], -) -> tuple[VarTuple[InputField], VarTuple[Param], Optional[ParamKwargs]]: + param_kwargs: ParamKwargs | None, +) -> tuple[VarTuple[InputField], VarTuple[Param], ParamKwargs | None]: if not HAS_PY_312 or param_kwargs is None: return (), (), param_kwargs diff --git a/src/adaptix/_internal/model_tools/introspection/sqlalchemy.py b/src/adaptix/_internal/model_tools/introspection/sqlalchemy.py index 1dfe9414..7ec3d083 100644 --- a/src/adaptix/_internal/model_tools/introspection/sqlalchemy.py +++ b/src/adaptix/_internal/model_tools/introspection/sqlalchemy.py @@ -1,6 +1,6 @@ import inspect from collections.abc import Mapping -from typing import Any, Generic, Optional, TypeVar +from typing import Any, Generic, TypeVar from ...common import TypeHint @@ -78,7 +78,7 @@ def _get_type_for_column(column: "ColumnElement", type_hints: Mapping[str, TypeH return _unwrap_mapped_annotation(type_hints[column.name]) except KeyError: if column.nullable: - return Optional[column.type.python_type] + return column.type.python_type | None return column.type.python_type @@ -88,10 +88,10 @@ def _get_type_for_relationship(relationship: "RelationshipProperty", type_hints: except KeyError: if relationship.uselist: return list[relationship.entity.class_] # type: ignore[name-defined] - return Optional[relationship.entity.class_] + return relationship.entity.class_ | None -def _get_default(column_default: "Optional[DefaultGenerator]"): +def _get_default(column_default: "DefaultGenerator | None"): if isinstance(column_default, CallableColumnDefault): if _is_context_sensitive(column_default): return NoDefault() @@ -101,7 +101,7 @@ def _get_default(column_default: "Optional[DefaultGenerator]"): return NoDefault() -def _is_input_required_for_column(column: "ColumnElement", autoincrement_column: "Optional[Column[int]]"): +def _is_input_required_for_column(column: "ColumnElement", autoincrement_column: "Column[int] | None"): return not ( # columns constrained by FK are not required since they can be specified by instances column.default is not None diff --git a/src/adaptix/_internal/model_tools/introspection/typed_dict.py b/src/adaptix/_internal/model_tools/introspection/typed_dict.py index d9b4cb9c..57e5c5dd 100644 --- a/src/adaptix/_internal/model_tools/introspection/typed_dict.py +++ b/src/adaptix/_internal/model_tools/introspection/typed_dict.py @@ -64,7 +64,7 @@ def get_typed_dict_shape(tp) -> FullShape: norm_types = [normalize_type(tp) for _, tp in type_hints] required_keys = _fetch_required_keys( - [(field_name, field_tp) for (field_name, _), field_tp in zip(type_hints, norm_types)], + [(field_name, field_tp) for (field_name, _), field_tp in zip(type_hints, norm_types, strict=True)], tp.__required_keys__, ) requirement_determinant = _make_requirement_determinant(required_keys) diff --git a/src/adaptix/_internal/morphing/concrete_provider.py b/src/adaptix/_internal/morphing/concrete_provider.py index c2395b35..bf232791 100644 --- a/src/adaptix/_internal/morphing/concrete_provider.py +++ b/src/adaptix/_internal/morphing/concrete_provider.py @@ -7,7 +7,7 @@ from decimal import Decimal, InvalidOperation from fractions import Fraction from io import BytesIO -from typing import Generic, Optional, TypeVar, Union +from typing import Generic, TypeVar from zoneinfo import ZoneInfo, ZoneInfoNotFoundError from ..common import Dumper, Loader @@ -32,7 +32,7 @@ class IsoFormatProvider(MorphingProvider): datetime: JSONSchemaBuiltinFormat.DATE_TIME, } - def __init__(self, cls: type[Union[date, time]]): + def __init__(self, cls: type[date | time]): self._cls = cls self._loc_stack_checker = create_loc_stack_checker(cls) @@ -105,7 +105,7 @@ def provide_json_schema(self, mediator: Mediator, request: JSONSchemaRequest) -> @for_predicate(datetime) class DatetimeTimestampProvider(MorphingProvider): - def __init__(self, tz: Optional[timezone]): + def __init__(self, tz: timezone | None): self._tz = tz def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: @@ -118,7 +118,7 @@ def datetime_timestamp_loader(data): try: return datetime.fromtimestamp(data, tz=tz) except TypeError: - raise TypeLoadError(Union[int, float], data) + raise TypeLoadError(int | float, data) except ValueError: raise ValueLoadError("Unexpected value", data) except OverflowError: @@ -164,11 +164,11 @@ def date_timestamp_loader(data): # of datetime.date.fromtimestamp module works differently with a None arg. # See https://github.com/python/cpython/issues/120268 for more details. if data is None: - raise TypeLoadError(Union[int, float], data) + raise TypeLoadError(int | float, data) return date.fromtimestamp(data) # noqa: DTZ012 except TypeError: - raise TypeLoadError(Union[int, float], data) + raise TypeLoadError(int | float, data) except ValueError: raise ValueLoadError("Unexpected value", data) except OverflowError: @@ -181,7 +181,7 @@ def pydate_timestamp_loader(data): try: return date.fromtimestamp(data) # noqa: DTZ012 except TypeError: - raise TypeLoadError(Union[int, float], data) + raise TypeLoadError(int | float, data) except OverflowError: raise ValueLoadError( "Timestamp is out of the range of supported values", @@ -220,7 +220,7 @@ def _make_loader(self): def timedelta_loader(data): if type(data) not in ok_types: - raise TypeLoadError(Union[int, float, Decimal], data) + raise TypeLoadError(int | float | Decimal, data) return timedelta(seconds=int(data), microseconds=int(data % 1 * 10 ** 6)) return timedelta_loader @@ -437,7 +437,7 @@ def int_lax_coercion_loader(data): raise ValueLoadError("Bad string format", data) raise ValueLoadError(e_str, data) except TypeError: - raise TypeLoadError(Union[int, float, str], data) + raise TypeLoadError(int | float | str, data) INT_PROVIDER = ScalarProvider( @@ -452,7 +452,7 @@ def int_lax_coercion_loader(data): def float_strict_coercion_loader(data): if type(data) in (float, int): return float(data) - raise TypeLoadError(Union[float, int], data) + raise TypeLoadError(int | float, data) def float_lax_coercion_loader(data): @@ -464,7 +464,7 @@ def float_lax_coercion_loader(data): raise ValueLoadError("Bad string format", data) raise ValueLoadError(e_str, data) except TypeError: - raise TypeLoadError(Union[int, float, str], data) + raise TypeLoadError(int | float | str, data) FLOAT_PROVIDER = ScalarProvider( @@ -514,7 +514,7 @@ def decimal_strict_coercion_loader(data): raise ValueLoadError("Bad string format", data) if type(data) is Decimal: return data - raise TypeLoadError(Union[str, Decimal], data) + raise TypeLoadError(str | Decimal, data) def decimal_lax_coercion_loader(data): @@ -523,7 +523,7 @@ def decimal_lax_coercion_loader(data): except InvalidOperation: raise ValueLoadError("Bad string format", data) except TypeError: - raise TypeLoadError(Union[str, Decimal], data) + raise TypeLoadError(str | Decimal, data) except ValueError as e: raise ValueLoadError(str(e), data) @@ -543,14 +543,14 @@ def fraction_strict_coercion_loader(data): return Fraction(data) except ValueError: raise ValueLoadError("Bad string format", data) - raise TypeLoadError(Union[str, Fraction], data) + raise TypeLoadError(str | Fraction, data) def fraction_lax_coercion_loader(data): try: return Fraction(data) except TypeError: - raise TypeLoadError(Union[str, Fraction], data) + raise TypeLoadError(str | Fraction, data) except ValueError as e: str_e = str(e) if str_e.startswith("Invalid literal"): @@ -573,14 +573,14 @@ def complex_strict_coercion_loader(data): return complex(data) except ValueError: raise ValueLoadError("Bad string format", data) - raise TypeLoadError(Union[str, complex], data) + raise TypeLoadError(str | complex, data) def complex_lax_coercion_loader(data): try: return complex(data) except TypeError: - raise TypeLoadError(Union[str, complex], data) + raise TypeLoadError(str | complex, data) except ValueError: raise ValueLoadError("Bad string format", data) diff --git a/src/adaptix/_internal/morphing/constant_length_tuple_provider.py b/src/adaptix/_internal/morphing/constant_length_tuple_provider.py index 27a26afe..4dba3a1b 100644 --- a/src/adaptix/_internal/morphing/constant_length_tuple_provider.py +++ b/src/adaptix/_internal/morphing/constant_length_tuple_provider.py @@ -113,7 +113,7 @@ def dt_all_loader(data): idx = 0 errors = [] has_unexpected_error = False - for loader, field in zip(loaders, data): + for loader, field in zip(loaders, data, strict=True): try: yield loader(field) except LoadError as e: @@ -153,7 +153,7 @@ def dt_first_loader(data): raise NoRequiredItemsLoadError(loaders_len, data) idx = 0 - for loader, field in zip(loaders, data): + for loader, field in zip(loaders, data, strict=True): try: yield loader(field) except Exception as e: @@ -180,7 +180,7 @@ def dt_disable_non_sc_loader(data): return tuple( loader(field) - for loader, field in zip(loaders, data) + for loader, field in zip(loaders, data, strict=True) ) return dt_disable_non_sc_loader @@ -207,7 +207,7 @@ def dt_disable_sc_loader(data): return tuple( loader(field) - for loader, field in zip(loaders, data) + for loader, field in zip(loaders, data, strict=True) ) return dt_disable_sc_loader @@ -262,7 +262,7 @@ def dt_all_dumper(data): idx = 0 errors = [] - for dumper, field in zip(dumpers, data): + for dumper, field in zip(dumpers, data, strict=True): try: yield dumper(field) except Exception as e: @@ -294,7 +294,7 @@ def dt_first_dumper(data): raise NoRequiredItemsLoadError(dumpers_len, data) idx = 0 - for dumper, field in zip(dumpers, data): + for dumper, field in zip(dumpers, data, strict=True): try: yield dumper(field) except Exception as e: @@ -327,7 +327,7 @@ def tuple_dumper(data): return tuple( dumper(field) - for dumper, field in zip(dumpers, data) + for dumper, field in zip(dumpers, data, strict=True) ) return tuple_dumper diff --git a/src/adaptix/_internal/morphing/dict_provider.py b/src/adaptix/_internal/morphing/dict_provider.py index 5fd4c4bd..45ccaac7 100644 --- a/src/adaptix/_internal/morphing/dict_provider.py +++ b/src/adaptix/_internal/morphing/dict_provider.py @@ -1,8 +1,7 @@ import collections.abc from collections import defaultdict -from collections.abc import Mapping +from collections.abc import Callable, Mapping from dataclasses import replace -from typing import Callable, Optional from ..common import Dumper, Loader from ..compat import CompatExceptionGroup @@ -250,7 +249,7 @@ def dict_dumper_dt_all(data: Mapping): class DefaultDictProvider(LoaderProvider, DumperProvider): _DICT_PROVIDER = DictProvider() - def __init__(self, default_factory: Optional[Callable] = None): + def __init__(self, default_factory: Callable | None = None): self.default_factory = default_factory def _extract_key_value(self, request: LocatedRequest) -> tuple[BaseNormType, BaseNormType]: diff --git a/src/adaptix/_internal/morphing/enum_provider.py b/src/adaptix/_internal/morphing/enum_provider.py index 86c22b94..da0c7098 100644 --- a/src/adaptix/_internal/morphing/enum_provider.py +++ b/src/adaptix/_internal/morphing/enum_provider.py @@ -5,7 +5,7 @@ from enum import Enum, EnumMeta, Flag from functools import reduce from operator import or_ -from typing import Any, Optional, TypeVar, Union, final +from typing import Any, TypeVar, final from ..common import Dumper, Loader, TypeHint from ..morphing.provider_template import DumperProvider, LoaderProvider @@ -51,8 +51,8 @@ def generate_for_loading(self, cases: Iterable[EnumT]) -> Mapping[str, EnumT]: class ByNameEnumMappingGenerator(BaseEnumMappingGenerator): def __init__( self, - name_style: Optional[NameStyle] = None, - map: Optional[Mapping[Union[str, Enum], str]] = None, # noqa: A002 + name_style: NameStyle | None = None, + map: Mapping[str | Enum, str] | None = None, # noqa: A002 ): self._name_style = name_style self._map = map if map is not None else {} @@ -225,7 +225,7 @@ def enum_exact_loader_v2m(data): return enum_exact_loader_v2m - def _get_exact_value_to_member(self, enum: type[Enum]) -> Optional[Mapping[Any, Any]]: + def _get_exact_value_to_member(self, enum: type[Enum]) -> Mapping[Any, Any] | None: try: value_to_member = {member.value: member for member in enum} except TypeError: @@ -340,7 +340,7 @@ def _make_loader(self, enum, *, strict_coercion: bool): zero_case = enum(0) # treat str and Iterable[str] as different types - expected_type = Union[str, Iterable[str]] if allow_single_value else Iterable[str] + expected_type = str | Iterable[str] if allow_single_value else Iterable[str] def flag_loader(data) -> Flag: data_type = type(data) diff --git a/src/adaptix/_internal/morphing/facade/func.py b/src/adaptix/_internal/morphing/facade/func.py index 224d634d..9e711469 100644 --- a/src/adaptix/_internal/morphing/facade/func.py +++ b/src/adaptix/_internal/morphing/facade/func.py @@ -1,6 +1,6 @@ from collections.abc import Container, Iterable, Mapping, Sequence from dataclasses import fields -from typing import Any, Optional, TypeVar, overload +from typing import Any, TypeVar, overload from ...common import TypeHint from ...definitions import Direction @@ -42,11 +42,11 @@ def dump(data: T, tp: type[T], /) -> Any: @overload -def dump(data: Any, tp: Optional[TypeHint] = None, /) -> Any: +def dump(data: Any, tp: TypeHint | None = None, /) -> Any: ... -def dump(data: Any, tp: Optional[TypeHint] = None, /) -> Any: +def dump(data: Any, tp: TypeHint | None = None, /) -> Any: return _default_retort.dump(data, tp) diff --git a/src/adaptix/_internal/morphing/facade/provider.py b/src/adaptix/_internal/morphing/facade/provider.py index e7a8b6ae..634389e3 100644 --- a/src/adaptix/_internal/morphing/facade/provider.py +++ b/src/adaptix/_internal/morphing/facade/provider.py @@ -1,10 +1,10 @@ from __future__ import annotations -from collections.abc import Iterable, Mapping +from collections.abc import Callable, Iterable, Mapping from datetime import timezone from enum import Enum, EnumMeta from types import MappingProxyType -from typing import Any, Callable, Optional, TypeVar, Union +from typing import Any, TypeVar from ...common import Catchable, Dumper, Loader, TypeHint, VarTuple from ...model_tools.definitions import Default, DescriptorAccessor, NoDefault, OutputField @@ -62,7 +62,7 @@ T = TypeVar("T") -def make_chain(chain: Optional[Chain], provider: Provider) -> Provider: +def make_chain(chain: Chain | None, provider: Provider) -> Provider: if chain is None: return provider @@ -72,7 +72,7 @@ def make_chain(chain: Optional[Chain], provider: Provider) -> Provider: def loader( pred: Pred, func: Loader, - chain: Optional[Chain] = None, + chain: Chain | None = None, *, json_schema: JSONSchemaOverride = EraseJSONSchema(), ) -> Provider: @@ -113,7 +113,7 @@ def loader( def dumper( pred: Pred, func: Dumper, - chain: Optional[Chain] = None, + chain: Chain | None = None, *, json_schema: JSONSchemaOverride = EraseJSONSchema(), ) -> Provider: @@ -228,7 +228,7 @@ def _name_mapping_convert_map(name_map: Omittable[NameMap]) -> VarTuple[Provider return tuple(result) -def _name_mapping_convert_preds(value: Omittable[Union[Iterable[Pred], Pred]]) -> Omittable[LocStackChecker]: +def _name_mapping_convert_preds(value: Omittable[Iterable[Pred] | Pred]) -> Omittable[LocStackChecker]: if isinstance(value, Omitted): return value if isinstance(value, Iterable) and not isinstance(value, str): @@ -237,14 +237,14 @@ def _name_mapping_convert_preds(value: Omittable[Union[Iterable[Pred], Pred]]) - def _name_mapping_convert_omit_default( - value: Omittable[Union[Iterable[Pred], Pred, bool]], + value: Omittable[Iterable[Pred] | Pred | bool], ) -> Omittable[LocStackChecker]: if isinstance(value, bool): return AnyLocStackChecker() if value else ~AnyLocStackChecker() return _name_mapping_convert_preds(value) -def _name_mapping_extra(value: Union[str, Iterable[str], T]) -> Union[str, Iterable[str], T]: +def _name_mapping_extra(value: str | Iterable[str] | T) -> str | Iterable[str] | T: if isinstance(value, str): return value if isinstance(value, Iterable): @@ -256,20 +256,20 @@ def name_mapping( pred: Omittable[Pred] = Omitted(), *, # filtering which fields are presented - skip: Omittable[Union[Iterable[Pred], Pred]] = Omitted(), - only: Omittable[Union[Iterable[Pred], Pred]] = Omitted(), + skip: Omittable[Iterable[Pred] | Pred] = Omitted(), + only: Omittable[Iterable[Pred] | Pred] = Omitted(), # mutating names of presented fields map: Omittable[NameMap] = Omitted(), # noqa: A002 as_list: Omittable[bool] = Omitted(), trim_trailing_underscore: Omittable[bool] = Omitted(), - name_style: Omittable[Optional[NameStyle]] = Omitted(), + name_style: Omittable[NameStyle | None] = Omitted(), # filtering of dumped data - omit_default: Omittable[Union[Iterable[Pred], Pred, bool]] = Omitted(), + omit_default: Omittable[Iterable[Pred] | Pred | bool] = Omitted(), # policy for data that does not map to fields extra_in: Omittable[ExtraIn] = Omitted(), extra_out: Omittable[ExtraOut] = Omitted(), # chaining with next matching provider - chain: Optional[Chain] = Chain.FIRST, + chain: Chain | None = Chain.FIRST, ) -> Provider: """A name mapping decides which fields will be presented to the outside world and how they will look. @@ -324,16 +324,13 @@ def name_mapping( ) -NameOrProp = Union[str, property] - - def with_property( pred: Pred, - prop: NameOrProp, + prop: str | property, tp: Omittable[TypeHint] = Omitted(), /, *, default: Default = NoDefault(), - access_error: Optional[Catchable] = None, + access_error: Catchable | None = None, metadata: Mapping[Any, Any] = MappingProxyType({}), ) -> Provider: """Provider registering property for a model for dumping. @@ -368,7 +365,7 @@ def with_property( ) -def _ensure_attr_name(prop: NameOrProp) -> str: +def _ensure_attr_name(prop: str | property) -> str: if isinstance(prop, str): return prop @@ -379,13 +376,13 @@ def _ensure_attr_name(prop: NameOrProp) -> str: return fget.__name__ -EnumPred = Union[TypeHint, str, EnumMeta, LocStackPattern] +EnumPred = TypeHint | str | EnumMeta | LocStackPattern def enum_by_name( *preds: EnumPred, - name_style: Optional[NameStyle] = None, - map: Optional[Mapping[Union[str, Enum], str]] = None, # noqa: A002 + name_style: NameStyle | None = None, + map: Mapping[str | Enum, str] | None = None, # noqa: A002 ) -> Provider: """Provider that represents enum members to the outside world by their name. @@ -454,8 +451,8 @@ def flag_by_member_names( allow_single_value: bool = False, allow_duplicates: bool = True, allow_compound: bool = True, - name_style: Optional[NameStyle] = None, - map: Optional[Mapping[Union[str, Enum], str]] = None, # noqa: A002 + name_style: NameStyle | None = None, + map: Mapping[str | Enum, str] | None = None, # noqa: A002 ) -> Provider: """Provider that represents flag members to the outside world by list of their names. @@ -496,7 +493,7 @@ def flag_by_member_names( def validator( pred: Pred, func: Callable[[Any], bool], - error: Union[str, Callable[[Any], LoadError], None] = None, + error: str | Callable[[Any], LoadError] | None = None, chain: Chain = Chain.LAST, ) -> Provider: exception_factory = ( @@ -523,7 +520,7 @@ def default_dict(pred: Pred, default_factory: Callable) -> Provider: return bound(pred, DefaultDictProvider(default_factory)) -def datetime_by_timestamp(pred: Pred = P.ANY, *, tz: Optional[timezone] = timezone.utc) -> Provider: +def datetime_by_timestamp(pred: Pred = P.ANY, *, tz: timezone | None = timezone.utc) -> Provider: """Provider that can load/dump datetime object from/to UNIX timestamp. :param pred: Predicate specifying where the provider should be used. diff --git a/src/adaptix/_internal/morphing/facade/retort.py b/src/adaptix/_internal/morphing/facade/retort.py index 273badb7..ad6a2e29 100644 --- a/src/adaptix/_internal/morphing/facade/retort.py +++ b/src/adaptix/_internal/morphing/facade/retort.py @@ -15,7 +15,7 @@ from ipaddress import IPv4Address, IPv4Interface, IPv4Network, IPv6Address, IPv6Interface, IPv6Network from itertools import chain from pathlib import Path, PosixPath, PurePath, PurePosixPath, PureWindowsPath, WindowsPath -from typing import Any, Optional, TypeVar, overload +from typing import Any, TypeVar, overload from uuid import UUID from ...common import Dumper, Loader, TypeHint, VarTuple @@ -230,7 +230,7 @@ def __init__( recipe: Iterable[Provider] = (), strict_coercion: bool = True, debug_trail: DebugTrail = DebugTrail.ALL, - error_renderer: Optional[ErrorRenderer] = default_error_renderer, + error_renderer: ErrorRenderer | None = default_error_renderer, ): self._strict_coercion = strict_coercion self._debug_trail = debug_trail @@ -246,7 +246,7 @@ def replace( *, strict_coercion: Omittable[bool] = Omitted(), debug_trail: Omittable[DebugTrail] = Omitted(), - error_renderer: Omittable[Optional[ErrorRenderer]] = Omitted(), + error_renderer: Omittable[ErrorRenderer | None] = Omitted(), ) -> AR: with self._clone() as clone: if not isinstance(strict_coercion, Omitted): @@ -339,10 +339,10 @@ def dump(self, data: T, tp: type[T], /) -> Any: ... @overload - def dump(self, data: Any, tp: Optional[TypeHint] = None, /) -> Any: + def dump(self, data: Any, tp: TypeHint | None = None, /) -> Any: ... - def dump(self, data: Any, tp: Optional[TypeHint] = None, /) -> Any: + def dump(self, data: Any, tp: TypeHint | None = None, /) -> Any: if tp is None: tp = type(data) if is_generic_class(tp): diff --git a/src/adaptix/_internal/morphing/generic_provider.py b/src/adaptix/_internal/morphing/generic_provider.py index f9928d82..80d57fab 100644 --- a/src/adaptix/_internal/morphing/generic_provider.py +++ b/src/adaptix/_internal/morphing/generic_provider.py @@ -3,7 +3,7 @@ from enum import Enum from os import PathLike from pathlib import Path -from typing import Any, ForwardRef, Literal, Optional, TypeVar +from typing import Any, ForwardRef, Literal, TypeVar from ..common import Dumper, Loader, TypeHint from ..provider.essential import CannotProvide, Mediator @@ -151,7 +151,7 @@ def _fetch_enum_dumpers( requests, lambda: "Cannot create dumper for literal. Dumpers for enums cannot be created", ) - return dict(zip(enum_classes, dumpers)) + return dict(zip(enum_classes, dumpers, strict=True)) def _fetch_bytes_dumper( self, @@ -343,7 +343,7 @@ def literal_dumper_with_bytes(data): def _make_dumper( self, enum_dumpers_wrapper: MappingHashWrapper[Mapping[type[Enum], Dumper[Enum]]], - bytes_dumper: Optional[Dumper[bytes]], + bytes_dumper: Dumper[bytes] | None, ): enum_dumpers = enum_dumpers_wrapper.mapping diff --git a/src/adaptix/_internal/morphing/iterable_provider.py b/src/adaptix/_internal/morphing/iterable_provider.py index 5c1dcd44..52b3351f 100644 --- a/src/adaptix/_internal/morphing/iterable_provider.py +++ b/src/adaptix/_internal/morphing/iterable_provider.py @@ -1,7 +1,7 @@ # ruff: noqa: SIM113 import collections.abc -from collections.abc import Iterable, Mapping -from typing import Callable, TypeVar +from collections.abc import Callable, Iterable, Mapping +from typing import TypeVar from ..common import Dumper, Loader, TypeHint from ..compat import CompatExceptionGroup diff --git a/src/adaptix/_internal/morphing/json_schema/definitions.py b/src/adaptix/_internal/morphing/json_schema/definitions.py index 881bc04f..e3e2dd02 100644 --- a/src/adaptix/_internal/morphing/json_schema/definitions.py +++ b/src/adaptix/_internal/morphing/json_schema/definitions.py @@ -1,5 +1,5 @@ from dataclasses import dataclass, field -from typing import Generic, Optional, TypeVar, Union +from typing import Generic, TypeAlias, TypeVar from ...provider.loc_stack_filtering import LocStack from ...type_tools.fwd_ref import FwdRef @@ -12,7 +12,7 @@ @dataclass(frozen=True) class LocalRefSource(Generic[JSONSchemaT]): - value: Optional[str] + value: str | None json_schema: JSONSchemaT = field(hash=False) loc_stack: LocStack = field(repr=False) @@ -22,13 +22,13 @@ class RemoteRef: value: str -Boolable = Union[T, bool] +Boolable: TypeAlias = T | bool @dataclass(repr=False) class JSONSchema( BaseJSONSchema[ - Union[LocalRefSource[FwdRef["JSONSchema"]], RemoteRef], + LocalRefSource[FwdRef["JSONSchema"]] | RemoteRef, Boolable[FwdRef["JSONSchema"]], ], ): diff --git a/src/adaptix/_internal/morphing/json_schema/mangling.py b/src/adaptix/_internal/morphing/json_schema/mangling.py index c182bb97..d89a48d8 100644 --- a/src/adaptix/_internal/morphing/json_schema/mangling.py +++ b/src/adaptix/_internal/morphing/json_schema/mangling.py @@ -1,7 +1,6 @@ from collections import defaultdict from collections.abc import Container, Mapping, Sequence from itertools import count -from typing import Optional from .resolver import LocalRefSourceGroup, RefMangler @@ -45,7 +44,7 @@ def mangle_refs( for sources_group in sources_groups } - def _generate_name(self, sources_group: LocalRefSourceGroup) -> Optional[str]: + def _generate_name(self, sources_group: LocalRefSourceGroup) -> str | None: if len(sources_group.sources) > 1: tps = {source.loc_stack.last.type for source in sources_group.sources} if len(tps) > 1: diff --git a/src/adaptix/_internal/morphing/json_schema/patch.py b/src/adaptix/_internal/morphing/json_schema/patch.py index babe924c..cb9783d1 100644 --- a/src/adaptix/_internal/morphing/json_schema/patch.py +++ b/src/adaptix/_internal/morphing/json_schema/patch.py @@ -1,7 +1,7 @@ -from collections.abc import Iterable +from collections.abc import Callable, Iterable from copy import copy, deepcopy from dataclasses import fields, replace -from typing import Any, Callable, TypeVar +from typing import Any, TypeVar from ...provider.provider_wrapper import Chain from ...utils import Omitted diff --git a/src/adaptix/_internal/morphing/json_schema/providers.py b/src/adaptix/_internal/morphing/json_schema/providers.py index e1a52bd1..1daa9064 100644 --- a/src/adaptix/_internal/morphing/json_schema/providers.py +++ b/src/adaptix/_internal/morphing/json_schema/providers.py @@ -1,5 +1,3 @@ -from typing import Union - from ...provider.essential import CannotProvide, Mediator from ...provider.located_request import LocatedRequestMethodsProvider from ...provider.methods_provider import method_handler @@ -56,7 +54,7 @@ class EraseJSONSchema(metaclass=SingletonMeta): pass -JSONSchemaOverride = Union[JSONSchema, KeepJSONSchema, EraseJSONSchema, JSONSchemaPatch] +JSONSchemaOverride = JSONSchema | KeepJSONSchema | EraseJSONSchema | JSONSchemaPatch class JSONSchemaOverrideProvider(JSONSchemaProvider): diff --git a/src/adaptix/_internal/morphing/json_schema/resolver.py b/src/adaptix/_internal/morphing/json_schema/resolver.py index ba1f2d5d..b1440d3f 100644 --- a/src/adaptix/_internal/morphing/json_schema/resolver.py +++ b/src/adaptix/_internal/morphing/json_schema/resolver.py @@ -1,7 +1,7 @@ from abc import ABC, abstractmethod from collections import defaultdict from collections.abc import Container, Mapping, Sequence -from typing import Optional, TypeVar +from typing import TypeVar from ...datastructures import OrderedUniqueGrouper from ...provider.loc_stack_filtering import LocStack @@ -161,7 +161,7 @@ def _validate_pining_conflict( self, common_ref: str, sources_groups: Sequence[LocalRefSourceGroup], - ) -> tuple[Sequence[LocalRefSourceGroup], Optional[LocalRefSourceGroup]]: + ) -> tuple[Sequence[LocalRefSourceGroup], LocalRefSourceGroup | None]: pinned_groups = [ source_group for source_group in sources_groups diff --git a/src/adaptix/_internal/morphing/json_schema/schema_model.py b/src/adaptix/_internal/morphing/json_schema/schema_model.py index 6dca580a..550bcb46 100644 --- a/src/adaptix/_internal/morphing/json_schema/schema_model.py +++ b/src/adaptix/_internal/morphing/json_schema/schema_model.py @@ -1,13 +1,13 @@ from collections.abc import Mapping, Sequence from dataclasses import dataclass, field from enum import Enum -from typing import Any, Generic, TypeVar, Union +from typing import Any, Generic, TypeVar from ...utils import Omittable, Omitted T = TypeVar("T") -JSONNumeric = Union[int, float] +JSONNumeric = int | float JSONObject = Mapping[str, T] # Recursive normalized types are not supported now. @@ -102,11 +102,11 @@ class _JSONSchemaSubschemas(Generic[JSONSchemaT]): @dataclass class _JSONSchemaValidation(Generic[JSONSchemaT]): # common - type: Omittable[Union[JSONSchemaType, Sequence[JSONSchemaType]]] = Omitted() + type: Omittable[JSONSchemaType | Sequence[JSONSchemaType]] = Omitted() enum: Omittable[Sequence[JSONValue]] = Omitted() const: Omittable[JSONValue] = Omitted() - format: Omittable[Union[JSONSchemaBuiltinFormat, str]] = Omitted() + format: Omittable[JSONSchemaBuiltinFormat | str] = Omitted() # numeric multiple_of: Omittable[JSONNumeric] = Omitted() diff --git a/src/adaptix/_internal/morphing/json_schema/schema_tools.py b/src/adaptix/_internal/morphing/json_schema/schema_tools.py index f9058ef8..ae7fdb43 100644 --- a/src/adaptix/_internal/morphing/json_schema/schema_tools.py +++ b/src/adaptix/_internal/morphing/json_schema/schema_tools.py @@ -1,7 +1,7 @@ -from collections.abc import Iterable, Mapping, Sequence +from collections.abc import Callable, Iterable, Mapping, Sequence from dataclasses import fields from textwrap import dedent, indent -from typing import Any, Callable, Optional, TypeVar, Union +from typing import Any, TypeVar from adaptix import TypeHint @@ -10,8 +10,8 @@ from .schema_model import JSONNumeric, JSONObject, JSONSchemaBuiltinFormat, JSONSchemaT, JSONSchemaType, JSONValue, RefT _non_generic_fields_types = [ - Omittable[Union[JSONSchemaType, Sequence[JSONSchemaType]]], # type: ignore[misc] - Omittable[Union[JSONSchemaBuiltinFormat, str]], # type: ignore[misc] + Omittable[JSONSchemaType | Sequence[JSONSchemaType]], # type: ignore[misc] + Omittable[JSONSchemaBuiltinFormat | str], # type: ignore[misc] Omittable[JSONNumeric], # type: ignore[misc] Omittable[int], # type: ignore[misc] Omittable[str], # type: ignore[misc] @@ -62,7 +62,7 @@ def _generate_json_schema_traverser( function_name: str, file_name: str, - templates: Mapping[TypeHint, Optional[str]], + templates: Mapping[TypeHint, str | None], cls: type[JSONSchemaT], ) -> Callable[[JSONSchemaT], Iterable[JSONSchemaT]]: result = [] @@ -134,7 +134,7 @@ def {function_name}(obj, /): def _generate_json_schema_replacer( function_name: str, file_name: str, - templates: Mapping[TypeHint, Optional[str]], + templates: Mapping[TypeHint, str | None], source_cls: type[JSONSchemaSourceT], target_cls: type[JSONSchemaTargetT], context: type[ContextT], @@ -214,10 +214,10 @@ def _sequence_hasher(item_hasher_template: str) -> str: _approx_hash_templates = { - Omittable[Union[JSONSchemaType, Sequence[JSONSchemaType]]]: ( # type: ignore[misc] + Omittable[JSONSchemaType | Sequence[JSONSchemaType]]: ( # type: ignore[misc] f"{_sequence_hasher('hash(__value__)')} if isinstance(__value__, Sequence) else hash(__value__)" ), - Omittable[Union[JSONSchemaBuiltinFormat, str]]: "hash(__value__)", # type: ignore[misc] + Omittable[JSONSchemaBuiltinFormat | str]: "hash(__value__)", # type: ignore[misc] Omittable[JSONNumeric]: "hash(__value__)", # type: ignore[misc] Omittable[int]: "hash(__value__)", # type: ignore[misc] Omittable[str]: "hash(__value__)", # type: ignore[misc] @@ -256,7 +256,7 @@ def _sequence_hasher(item_hasher_template: str) -> str: def _generate_json_schema_hasher( function_name: str, file_name: str, - templates: Mapping[TypeHint, Optional[str]], + templates: Mapping[TypeHint, str | None], source_cls: type[JSONSchemaSourceT], ) -> Callable[[JSONSchemaSourceT], int]: result = [] diff --git a/src/adaptix/_internal/morphing/load_error.py b/src/adaptix/_internal/morphing/load_error.py index 70f39697..7da598bb 100644 --- a/src/adaptix/_internal/morphing/load_error.py +++ b/src/adaptix/_internal/morphing/load_error.py @@ -2,7 +2,7 @@ from collections.abc import Iterable from dataclasses import dataclass from functools import partial -from typing import Any, Optional, Union +from typing import Any from ..common import TypeHint, VarTuple from ..compat import CompatExceptionGroup @@ -70,7 +70,7 @@ class UnionLoadError(LoadExceptionGroup): @custom_exception @dataclass(eq=False) class MsgLoadError(LoadError): - msg: Optional[str] + msg: str | None input_value: Any @@ -160,6 +160,6 @@ class DuplicatedValuesLoadError(LoadError): @custom_exception @dataclass(eq=False) class OutOfRangeLoadError(LoadError): - min_value: Optional[Union[int, float]] - max_value: Optional[Union[int, float]] + min_value: int | float | None + max_value: int | float | None input_value: Any diff --git a/src/adaptix/_internal/morphing/model/basic_gen.py b/src/adaptix/_internal/morphing/model/basic_gen.py index c14c7141..2bbc2aba 100644 --- a/src/adaptix/_internal/morphing/model/basic_gen.py +++ b/src/adaptix/_internal/morphing/model/basic_gen.py @@ -1,8 +1,8 @@ import itertools from abc import ABC, abstractmethod -from collections.abc import Collection, Container, Iterable, Mapping, Set +from collections.abc import Callable, Collection, Container, Iterable, Mapping, Set from dataclasses import dataclass -from typing import Any, Callable, TypeVar, Union +from typing import Any, TypeVar from ...code_tools.code_builder import CodeBuilder from ...code_tools.compiler import ClosureCompiler @@ -154,7 +154,7 @@ def get_extra_targets_at_crown(name_layout: BaseNameLayout) -> Collection[str]: def get_optional_fields_at_list_crown( - fields_map: Mapping[str, Union[InputField, OutputField]], + fields_map: Mapping[str, InputField | OutputField], crown: BaseCrown, ) -> Collection[str]: if isinstance(crown, BaseDictCrown): @@ -178,7 +178,7 @@ def get_optional_fields_at_list_crown( raise TypeError -def get_wild_extra_targets(shape: BaseShape, extra_move: Union[InpExtraMove, OutExtraMove]) -> Collection[str]: +def get_wild_extra_targets(shape: BaseShape, extra_move: InpExtraMove | OutExtraMove) -> Collection[str]: if not isinstance(extra_move, ExtraTargets): return [] diff --git a/src/adaptix/_internal/morphing/model/crown_definitions.py b/src/adaptix/_internal/morphing/model/crown_definitions.py index 3a814b13..11e622dc 100644 --- a/src/adaptix/_internal/morphing/model/crown_definitions.py +++ b/src/adaptix/_internal/morphing/model/crown_definitions.py @@ -1,6 +1,6 @@ -from collections.abc import Mapping, Sequence +from collections.abc import Callable, Mapping, Sequence from dataclasses import dataclass -from typing import Any, Callable, Generic, TypeVar, Union +from typing import Any, Generic, TypeVar from ...common import VarTuple from ...model_tools.definitions import BaseShape, DefaultFactory, DefaultValue, InputShape, OutputShape @@ -9,7 +9,7 @@ T = TypeVar("T") -CrownPathElem = Union[str, int] +CrownPathElem = str | int CrownPath = VarTuple[CrownPathElem] # subset of struct_path.Trail @@ -56,14 +56,14 @@ class BaseFieldCrown: id: str -BranchBaseCrown = Union[BaseDictCrown, BaseListCrown] -LeafBaseCrown = Union[BaseFieldCrown, BaseNoneCrown] -BaseCrown = Union[BranchBaseCrown, LeafBaseCrown] +BranchBaseCrown = BaseDictCrown | BaseListCrown +LeafBaseCrown = BaseFieldCrown | BaseNoneCrown +BaseCrown = BranchBaseCrown | LeafBaseCrown # -------- Input Crown -------- # -DictExtraPolicy = Union[ExtraSkip, ExtraForbid, ExtraCollect] -ListExtraPolicy = Union[ExtraSkip, ExtraForbid] +DictExtraPolicy = ExtraSkip | ExtraForbid | ExtraCollect +ListExtraPolicy = ExtraSkip | ExtraForbid @dataclass(frozen=True) @@ -89,9 +89,9 @@ class InpFieldCrown(BaseFieldCrown): pass -BranchInpCrown = Union[InpDictCrown, InpListCrown] -LeafInpCrown = Union[InpFieldCrown, InpNoneCrown] -InpCrown = Union[BranchInpCrown, LeafInpCrown] +BranchInpCrown = InpDictCrown | InpListCrown +LeafInpCrown = InpFieldCrown | InpNoneCrown +InpCrown = BranchInpCrown | LeafInpCrown # -------- Output Crown -------- # @@ -123,7 +123,7 @@ class OutListCrown(BaseListCrown["OutCrown"]): pass -Placeholder = Union[DefaultValue, DefaultFactory] +Placeholder = DefaultValue | DefaultFactory @dataclass(frozen=True) @@ -136,9 +136,9 @@ class OutFieldCrown(BaseFieldCrown): pass -BranchOutCrown = Union[OutDictCrown, OutListCrown] -LeafOutCrown = Union[OutFieldCrown, OutNoneCrown] -OutCrown = Union[BranchOutCrown, LeafOutCrown] +BranchOutCrown = OutDictCrown | OutListCrown +LeafOutCrown = OutFieldCrown | OutNoneCrown +OutCrown = BranchOutCrown | LeafOutCrown # -------- Name Layout -------- # @@ -166,9 +166,9 @@ class ExtraExtract(Generic[T]): func: Extractor[T] -InpExtraMove = Union[None, ExtraTargets, ExtraKwargs, ExtraSaturate[T]] -OutExtraMove = Union[None, ExtraTargets, ExtraExtract[T]] -BaseExtraMove = Union[InpExtraMove, OutExtraMove] +InpExtraMove = None | ExtraTargets | ExtraKwargs | ExtraSaturate[T] +OutExtraMove = None | ExtraTargets | ExtraExtract[T] +BaseExtraMove = InpExtraMove | OutExtraMove @dataclass(frozen=True) diff --git a/src/adaptix/_internal/morphing/model/dumper_gen.py b/src/adaptix/_internal/morphing/model/dumper_gen.py index 3d716281..9e259478 100644 --- a/src/adaptix/_internal/morphing/model/dumper_gen.py +++ b/src/adaptix/_internal/morphing/model/dumper_gen.py @@ -1,7 +1,7 @@ import contextlib -from collections.abc import Iterable, Mapping +from collections.abc import Callable, Iterable, Mapping from dataclasses import replace -from typing import Any, Callable, NamedTuple, Optional +from typing import Any, NamedTuple from ...code_tools.cascade_namespace import BuiltinCascadeNamespace, CascadeNamespace from ...code_tools.code_block_tree import ( @@ -71,10 +71,10 @@ def __init__(self, namespace: CascadeNamespace, debug_trail: DebugTrail, error_h self.trail_element_to_name_idx: dict[TrailElement, int] = {} self.error_handler_name = error_handler_name - self.error_handlers: dict[Optional[OutputField], Callable[[Statement], Statement]] = {} - self.field_to_idx: dict[Optional[OutputField], int] = {} + self.error_handlers: dict[OutputField | None, Callable[[Statement], Statement]] = {} + self.field_to_idx: dict[OutputField | None, int] = {} - def register_field_idx(self, field: Optional[OutputField]) -> int: + def register_field_idx(self, field: OutputField | None) -> int: if field in self.field_to_idx: return self.field_to_idx[field] idx = len(self.field_to_idx) @@ -103,7 +103,7 @@ def add_key(self, key: CrownPathElem): yield self._path = past - def suffix(self, basis: str, key: Optional[CrownPathElem] = None) -> str: + def suffix(self, basis: str, key: CrownPathElem | None = None) -> str: path = self._path if key is None else (*self._path, key) if not path: return basis @@ -153,7 +153,7 @@ def write_lines(self, writer: TextSliceWriter) -> None: class ErrorHandling(Statement): - def __init__(self, state: GenState, field: Optional[OutputField]): + def __init__(self, state: GenState, field: OutputField | None): self._state = state self._field = field @@ -209,9 +209,9 @@ class OutVarStatement(NamedTuple): class DictFragment(NamedTuple): - before: Optional[Statement] = None - item: Optional[DictItem] = None - after: Optional[Statement] = None + before: Statement | None = None + item: DictItem | None = None + after: Statement | None = None class BuiltinModelDumperGen(ModelDumperGen): @@ -483,7 +483,7 @@ def _process_dict_non_field( self, state: GenState, key: str, - sieve: Optional[Sieve], + sieve: Sieve | None, sub_crown: OutCrown, ) -> DictFragment: out_stmt = self._get_crown_out_stmt(state, key, sub_crown) @@ -546,7 +546,7 @@ def _get_none_crown_out_stmt(self, state: GenState, crown: OutNoneCrown) -> OutV ), ) - def _get_extra_extraction(self, state: GenState) -> Optional[OutVarStatement]: + def _get_extra_extraction(self, state: GenState) -> OutVarStatement | None: if isinstance(self._name_layout.extra_move, ExtraTargets): return self._get_extra_target_extraction(state, self._name_layout.extra_move) if isinstance(self._name_layout.extra_move, ExtraExtract): @@ -633,7 +633,7 @@ def _get_extra_extract_extraction(self, state: GenState, extra_move: ExtraExtrac var=var, ) - def _get_error_collector(self, state: GenState, field: Optional[OutputField]) -> Statement: + def _get_error_collector(self, state: GenState, field: OutputField | None) -> Statement: if field is None: return RawStatement("errors.append(e)") diff --git a/src/adaptix/_internal/morphing/model/dumper_provider.py b/src/adaptix/_internal/morphing/model/dumper_provider.py index 9711b71f..ebb1d820 100644 --- a/src/adaptix/_internal/morphing/model/dumper_provider.py +++ b/src/adaptix/_internal/morphing/model/dumper_provider.py @@ -226,7 +226,7 @@ def _fetch_field_dumpers( ], lambda: "Cannot create dumper for model. Dumpers for some fields cannot be created", ) - return {field.id: dumper for field, dumper in zip(shape.fields, dumpers)} + return {field.id: dumper for field, dumper in zip(shape.fields, dumpers, strict=True)} def _validate_params(self, shape: OutputShape, name_layout: OutputNameLayout) -> None: optional_fields_at_list_crown = get_optional_fields_at_list_crown( diff --git a/src/adaptix/_internal/morphing/model/loader_gen.py b/src/adaptix/_internal/morphing/model/loader_gen.py index 6bf78c77..7acca8e5 100644 --- a/src/adaptix/_internal/morphing/model/loader_gen.py +++ b/src/adaptix/_internal/morphing/model/loader_gen.py @@ -2,7 +2,7 @@ from collections.abc import Mapping, Set from contextlib import AbstractContextManager, contextmanager, nullcontext from dataclasses import dataclass, replace -from typing import Any, Optional +from typing import Any from ...code_tools.cascade_namespace import BuiltinCascadeNamespace, CascadeNamespace from ...code_tools.code_builder import CodeBuilder @@ -120,7 +120,7 @@ def __init__( self.field_id_to_path: dict[str, CrownPath] = {} self._last_path_idx = 0 - self._parent_path: Optional[CrownPath] = None + self._parent_path: CrownPath | None = None self._crown_stack: list[InpCrown] = [root_crown] self.type_checked_type_paths: set[CrownPath] = set() @@ -383,7 +383,7 @@ def _gen_raise_bad_type_error( self, state: GenState, bad_type_load_error: str, - namer: Optional[Namer] = None, + namer: Namer | None = None, ) -> None: if namer is None: namer = state @@ -407,7 +407,7 @@ def _gen_assignment_from_parent_data( state: GenState, *, assign_to: str, - on_lookup_error: Optional[str] = None, + on_lookup_error: str | None = None, ): last_path_el = state.path[-1] if isinstance(last_path_el, str): diff --git a/src/adaptix/_internal/morphing/model/loader_provider.py b/src/adaptix/_internal/morphing/model/loader_provider.py index c3875775..5fdd94cc 100644 --- a/src/adaptix/_internal/morphing/model/loader_provider.py +++ b/src/adaptix/_internal/morphing/model/loader_provider.py @@ -154,7 +154,7 @@ def _fetch_field_json_schemas( ], lambda: "Cannot create JSON Schema for model. JSON Schemas for some fields cannot be created", ) - return {field.id: json_schema for field, json_schema in zip(shape.fields, json_schemas)} + return {field.id: json_schema for field, json_schema in zip(shape.fields, json_schemas, strict=True)} def _fetch_field_json_schemas_of_default( self, @@ -180,7 +180,10 @@ def _fetch_field_json_schemas_of_default( ], lambda: "Cannot create JSON Schema for model. Dumpers for some field defaults cannot be created", ) - return {field.id: dumper(default) for (field, default), dumper in zip(fields_and_defaults, dumpers)} + return { + field.id: dumper(default) + for (field, default), dumper in zip(fields_and_defaults, dumpers, strict=True) + } def _fetch_model_identity( self, @@ -260,7 +263,7 @@ def _fetch_field_loaders( ], lambda: "Cannot create loader for model. Loaders for some fields cannot be created", ) - return {field.id: loader for field, loader in zip(shape.fields, loaders)} + return {field.id: loader for field, loader in zip(shape.fields, loaders, strict=True)} def _validate_params( self, diff --git a/src/adaptix/_internal/morphing/name_layout/base.py b/src/adaptix/_internal/morphing/name_layout/base.py index f3d49216..eff8dcfd 100644 --- a/src/adaptix/_internal/morphing/name_layout/base.py +++ b/src/adaptix/_internal/morphing/name_layout/base.py @@ -1,6 +1,6 @@ from abc import ABC, abstractmethod from collections.abc import Iterable, Mapping -from typing import TypeVar, Union +from typing import TypeVar from ...common import VarTuple from ...provider.essential import Mediator @@ -23,10 +23,10 @@ T = TypeVar("T") -ExtraIn = Union[ExtraSkip, str, Iterable[str], ExtraForbid, ExtraKwargs, Saturator] -ExtraOut = Union[ExtraSkip, str, Iterable[str], Extractor] +ExtraIn = ExtraSkip | str | Iterable[str] | ExtraForbid | ExtraKwargs | Saturator +ExtraOut = ExtraSkip | str | Iterable[str] | Extractor -Key = Union[str, int] +Key = str | int KeyPath = VarTuple[Key] PathsTo = Mapping[KeyPath, T] diff --git a/src/adaptix/_internal/morphing/name_layout/component.py b/src/adaptix/_internal/morphing/name_layout/component.py index 803722fa..f6407b99 100644 --- a/src/adaptix/_internal/morphing/name_layout/component.py +++ b/src/adaptix/_internal/morphing/name_layout/component.py @@ -1,7 +1,7 @@ from collections import defaultdict -from collections.abc import Iterable, Mapping, Sequence +from collections.abc import Callable, Iterable, Mapping, Sequence from dataclasses import dataclass -from typing import Callable, Optional, TypeVar, Union +from typing import TypeVar from ...common import VarTuple from ...model_tools.definitions import ( @@ -68,7 +68,7 @@ class StructureSchema(Schema): map: VarTuple[Provider] trim_trailing_underscore: bool - name_style: Optional[NameStyle] + name_style: NameStyle | None as_list: bool @@ -79,18 +79,18 @@ class StructureOverlay(Overlay[StructureSchema]): map: Omittable[VarTuple[Provider]] trim_trailing_underscore: Omittable[bool] - name_style: Omittable[Optional[NameStyle]] + name_style: Omittable[NameStyle | None] as_list: Omittable[bool] def _merge_map(self, old: VarTuple[Provider], new: VarTuple[Provider]) -> VarTuple[Provider]: return new + old -AnyField = Union[InputField, OutputField] +AnyField = InputField | OutputField LeafCr = TypeVar("LeafCr", bound=LeafBaseCrown) FieldCr = TypeVar("FieldCr", bound=BaseFieldCrown) F = TypeVar("F", bound=BaseField) -FieldAndPath = tuple[F, Optional[KeyPath]] +FieldAndPath = tuple[F, KeyPath | None] def apply_lsc( @@ -104,7 +104,7 @@ def apply_lsc( class NameMappingRetort(OperatingRetort): - def provide_name_mapping(self, request: NameMappingRequest) -> Optional[KeyPath]: + def provide_name_mapping(self, request: NameMappingRequest) -> KeyPath | None: return self._provide_from_recipe(request) @@ -128,7 +128,7 @@ def _map_fields( mediator: Mediator, request: BaseNameLayoutRequest, schema: StructureSchema, - extra_move: Union[InpExtraMove, OutExtraMove], + extra_move: InpExtraMove | OutExtraMove, ) -> Iterable[FieldAndPath]: extra_targets = extra_move.fields if isinstance(extra_move, ExtraTargets) else () retort = self._create_name_mapping_retort(schema) @@ -270,8 +270,8 @@ def _make_paths_to_leaves( fields_to_paths: Iterable[FieldAndPath], field_crown: Callable[[str], FieldCr], gaps_filler: Callable[[KeyPath], LeafCr], - ) -> PathsTo[Union[FieldCr, LeafCr]]: - paths_to_leaves: dict[KeyPath, Union[FieldCr, LeafCr]] = { + ) -> PathsTo[FieldCr | LeafCr]: + paths_to_leaves: dict[KeyPath, FieldCr | LeafCr] = { path: field_crown(field.id) for field, path in fields_to_paths if path is not None @@ -404,7 +404,7 @@ class ExtraMoveAndPoliciesOverlay(Overlay[ExtraMoveAndPoliciesSchema]): class BuiltinExtraMoveAndPoliciesMaker(ExtraMoveMaker, ExtraPoliciesMaker): - def _create_extra_targets(self, extra: Union[str, Sequence[str]]) -> ExtraTargets: + def _create_extra_targets(self, extra: str | Sequence[str]) -> ExtraTargets: if isinstance(extra, str): return ExtraTargets((extra,)) return ExtraTargets(tuple(extra)) diff --git a/src/adaptix/_internal/morphing/name_layout/crown_builder.py b/src/adaptix/_internal/morphing/name_layout/crown_builder.py index 397d6c59..2c7b6b7d 100644 --- a/src/adaptix/_internal/morphing/name_layout/crown_builder.py +++ b/src/adaptix/_internal/morphing/name_layout/crown_builder.py @@ -3,7 +3,7 @@ from collections.abc import Mapping, Sequence from dataclasses import dataclass from itertools import groupby -from typing import Generic, TypeVar, Union, cast +from typing import Generic, TypeVar, cast from ..model.crown_definitions import ( BaseDictCrown, @@ -41,17 +41,17 @@ def __init__(self, paths_to_leaves: PathsTo[LeafCr]): self._paths_to_leaves = paths_to_leaves self._paths_to_order = {path: i for i, path in enumerate(paths_to_leaves)} - def build_empty_crown(self, *, as_list: bool) -> Union[DictCr, ListCr]: + def build_empty_crown(self, *, as_list: bool) -> DictCr | ListCr: if as_list: return self._make_list_crown(current_path=(), paths_with_leaves=[]) return self._make_dict_crown(current_path=(), paths_with_leaves=[]) - def build_crown(self) -> Union[DictCr, ListCr]: + def build_crown(self) -> DictCr | ListCr: paths_with_leaves = [PathWithLeaf(path, leaf) for path, leaf in self._paths_to_leaves.items()] paths_with_leaves.sort(key=lambda x: x.path) - return cast(Union[DictCr, ListCr], self._build_crown(paths_with_leaves, 0)) + return cast(DictCr | ListCr, self._build_crown(paths_with_leaves, 0)) - def _build_crown(self, paths_with_leaves: PathedLeaves[LeafCr], path_offset: int) -> Union[LeafCr, DictCr, ListCr]: + def _build_crown(self, paths_with_leaves: PathedLeaves[LeafCr], path_offset: int) -> LeafCr | DictCr | ListCr: if not paths_with_leaves: raise ValueError @@ -72,7 +72,7 @@ def _get_dict_crown_map( self, current_path: KeyPath, paths_with_leaves: PathedLeaves[LeafCr], - ) -> Mapping[str, Union[LeafCr, DictCr, ListCr]]: + ) -> Mapping[str, LeafCr | DictCr | ListCr]: dict_crown_map = { key: self._build_crown(list(path_group), len(current_path) + 1) for key, path_group in groupby(paths_with_leaves, lambda x: x.path[len(current_path)]) @@ -91,7 +91,7 @@ def _get_list_crown_map( self, current_path: KeyPath, paths_with_leaves: PathedLeaves[LeafCr], - ) -> Sequence[Union[LeafCr, DictCr, ListCr]]: + ) -> Sequence[LeafCr | DictCr | ListCr]: grouped_paths = [ list(grouped_paths) for key, grouped_paths in groupby(paths_with_leaves, lambda x: x.path[len(current_path)]) diff --git a/src/adaptix/_internal/morphing/name_layout/name_mapping.py b/src/adaptix/_internal/morphing/name_layout/name_mapping.py index 9c76368a..db7b61de 100644 --- a/src/adaptix/_internal/morphing/name_layout/name_mapping.py +++ b/src/adaptix/_internal/morphing/name_layout/name_mapping.py @@ -1,9 +1,8 @@ from __future__ import annotations from abc import ABC, abstractmethod -from collections.abc import Iterable, Mapping +from collections.abc import Callable, Iterable, Mapping from dataclasses import dataclass -from typing import Callable, Optional, Union from ...common import EllipsisType from ...model_tools.definitions import BaseField, BaseShape, OutputField, is_valid_field_id @@ -13,30 +12,28 @@ from ...provider.methods_provider import MethodsProvider, method_handler from .base import Key, KeyPath -RawKey = Union[Key, EllipsisType] +RawKey = Key | EllipsisType RawPath = Iterable[RawKey] -MapResult = Union[RawKey, RawPath, None] -NameMap = Union[ - Mapping[str, MapResult], - Iterable[ - Union[ - Mapping[str, MapResult], - tuple[Pred, MapResult], - tuple[Pred, Callable[[BaseShape, BaseField], MapResult]], - Provider, - ] - ], -] +MapResult = RawKey | RawPath | None +NameMap = ( + Mapping[str, MapResult] + | Iterable[ + Mapping[str, MapResult] + | tuple[Pred, MapResult] + | tuple[Pred, Callable[[BaseShape, BaseField], MapResult]] + | Provider + ] +) @dataclass(frozen=True) -class NameMappingRequest(LocatedRequest[Optional[KeyPath]]): +class NameMappingRequest(LocatedRequest[KeyPath | None]): shape: BaseShape field: BaseField generated_key: Key -def resolve_map_result(generated_key: Key, map_result: MapResult) -> Optional[KeyPath]: +def resolve_map_result(generated_key: Key, map_result: MapResult) -> KeyPath | None: if map_result is None: return None if isinstance(map_result, (str, int)): @@ -49,7 +46,7 @@ def resolve_map_result(generated_key: Key, map_result: MapResult) -> Optional[Ke class NameMappingProvider(MethodsProvider, ABC): @abstractmethod @method_handler - def provide_name_mapping(self, mediator: Mediator, request: NameMappingRequest) -> Optional[KeyPath]: + def provide_name_mapping(self, mediator: Mediator, request: NameMappingRequest) -> KeyPath | None: ... @@ -66,7 +63,7 @@ def _validate(self) -> None: f" Keys {invalid_keys!r} does not meet this condition.", ) - def provide_name_mapping(self, mediator: Mediator, request: NameMappingRequest) -> Optional[KeyPath]: + def provide_name_mapping(self, mediator: Mediator, request: NameMappingRequest) -> KeyPath | None: try: map_result = self._name_map[request.field.id] except KeyError: @@ -78,7 +75,7 @@ class ConstNameMappingProvider(NameMappingProvider): def __init__(self, result: MapResult): self._result = result - def provide_name_mapping(self, mediator: Mediator, request: NameMappingRequest) -> Optional[KeyPath]: + def provide_name_mapping(self, mediator: Mediator, request: NameMappingRequest) -> KeyPath | None: return resolve_map_result(request.generated_key, self._result) @@ -86,13 +83,13 @@ class FuncNameMappingProvider(NameMappingProvider): def __init__(self, func: Callable[[BaseShape, BaseField], MapResult]): self._func = func - def provide_name_mapping(self, mediator: Mediator, request: NameMappingRequest) -> Optional[KeyPath]: + def provide_name_mapping(self, mediator: Mediator, request: NameMappingRequest) -> KeyPath | None: result = self._func(request.shape, request.field) return resolve_map_result(request.generated_key, result) class SkipPrivateFieldsNameMappingProvider(NameMappingProvider): - def provide_name_mapping(self, mediator: Mediator, request: NameMappingRequest) -> Optional[KeyPath]: + def provide_name_mapping(self, mediator: Mediator, request: NameMappingRequest) -> KeyPath | None: if not isinstance(request.field, OutputField): raise CannotProvide if request.field.id.startswith("_"): diff --git a/src/adaptix/_internal/morphing/union_provider.py b/src/adaptix/_internal/morphing/union_provider.py index b8a71547..b0c1443b 100644 --- a/src/adaptix/_internal/morphing/union_provider.py +++ b/src/adaptix/_internal/morphing/union_provider.py @@ -1,6 +1,6 @@ import collections.abc from collections.abc import Iterable, Sequence -from typing import Any, Literal, Optional, Union +from typing import Any, Literal, Union from ..common import Dumper, Loader, TypeHint from ..compat import CompatExceptionGroup @@ -87,7 +87,7 @@ def provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader: return mediator.cached_call(self._produce_loader_dt_all, norm.source, tuple(loaders)) raise ValueError - def _parse_single_optional_loader(self, loaders: Sequence[Loader]) -> Optional[Loader]: + def _parse_single_optional_loader(self, loaders: Sequence[Loader]) -> Loader | None: try: [first, second] = loaders except ValueError: @@ -233,9 +233,9 @@ def _get_class_for_dumping(self, norm: BaseNormType) -> type: return NoneType return strip_tags(norm).origin - def _parse_single_optional_dumper(self, norm: BaseNormType, dumpers: Iterable[Dumper]) -> Optional[Dumper]: + def _parse_single_optional_dumper(self, norm: BaseNormType, dumpers: Iterable[Dumper]) -> Dumper | None: try: - [(first_norm, first_dumper), (second_norm, second_dumper)] = zip(norm.args, dumpers) + [(first_norm, first_dumper), (second_norm, second_dumper)] = zip(norm.args, dumpers, strict=True) except ValueError: return None if first_norm.origin is None and first_dumper == as_is_stub: @@ -246,8 +246,8 @@ def _parse_single_optional_dumper(self, norm: BaseNormType, dumpers: Iterable[Du def _extract_literal(self, args: Iterable[TypeHint], dumpers: Iterable[Dumper]): non_literals: list[tuple[BaseNormType, Dumper]] = [] - literal: Optional[tuple[BaseNormType, Dumper]] = None - for arg, dumper in zip(args, dumpers): + literal: tuple[BaseNormType, Dumper] | None = None + for arg, dumper in zip(args, dumpers, strict=True): norm = try_normalize_type(arg) if norm.origin == Literal: literal = (norm, dumper) diff --git a/src/adaptix/_internal/name_style.py b/src/adaptix/_internal/name_style.py index ca12b648..de01b107 100644 --- a/src/adaptix/_internal/name_style.py +++ b/src/adaptix/_internal/name_style.py @@ -1,8 +1,8 @@ import re +from collections.abc import Callable from dataclasses import dataclass from enum import Enum from functools import partial -from typing import Callable class NameStyle(Enum): diff --git a/src/adaptix/_internal/provider/essential.py b/src/adaptix/_internal/provider/essential.py index dfc97a00..10a75751 100644 --- a/src/adaptix/_internal/provider/essential.py +++ b/src/adaptix/_internal/provider/essential.py @@ -1,8 +1,8 @@ import typing from abc import ABC, abstractmethod -from collections.abc import Iterable, Sequence +from collections.abc import Callable, Iterable, Sequence from dataclasses import dataclass -from typing import TYPE_CHECKING, Any, Callable, Generic, Optional, TypeVar, final +from typing import TYPE_CHECKING, Any, Generic, TypeVar, final from ..common import VarTuple from ..compat import CompatExceptionGroup @@ -31,7 +31,7 @@ def __init__( *, is_terminal: bool = False, is_demonstrative: bool = False, - parent_notes_gen: Optional[Callable[[], Sequence[str]]] = None, + parent_notes_gen: Callable[[], Sequence[str]] | None = None, ): self.message = message self.is_terminal = is_terminal @@ -46,7 +46,7 @@ def __repr__(self): @with_module("adaptix") -class AggregateCannotProvide(CompatExceptionGroup[CannotProvide], CannotProvide): # type: ignore[misc] +class AggregateCannotProvide(CompatExceptionGroup[CannotProvide], CannotProvide): # type: ignore[override] def __init__( self, message: str, @@ -54,7 +54,7 @@ def __init__( *, is_terminal: bool = False, is_demonstrative: bool = False, - parent_notes_gen: Optional[Callable[[], Sequence[str]]] = None, + parent_notes_gen: Callable[[], Sequence[str]] | None = None, ): # Parameter `message` is saved by `__new__` of CompatExceptionGroup self.is_terminal = is_terminal @@ -69,7 +69,7 @@ def __new__( *, is_terminal: bool = False, is_demonstrative: bool = False, - parent_notes_gen: Optional[Callable[[], Sequence[str]]] = None, + parent_notes_gen: Callable[[], Sequence[str]] | None = None, ): return super().__new__(cls, message, exceptions) @@ -103,7 +103,7 @@ def make( *, is_terminal: bool = False, is_demonstrative: bool = False, - parent_notes_gen: Optional[Callable[[], Sequence[str]]] = None, + parent_notes_gen: Callable[[], Sequence[str]] | None = None, ) -> CannotProvide: if exceptions: return AggregateCannotProvide( @@ -141,7 +141,7 @@ def provide(self, request: Request[T]) -> T: def delegating_provide( self, request: Request[T], - error_describer: Optional[Callable[[CannotProvide], str]] = None, + error_describer: Callable[[CannotProvide], str] | None = None, ) -> T: try: return self.provide(request) @@ -157,7 +157,7 @@ def delegating_provide( def mandatory_provide( self, request: Request[T], - error_describer: Optional[Callable[[CannotProvide], str]] = None, + error_describer: Callable[[CannotProvide], str] | None = None, ) -> T: try: return self.provide(request) @@ -173,7 +173,7 @@ def mandatory_provide( def mandatory_provide_by_iterable( self, requests: Iterable[Request[T]], - error_describer: Optional[Callable[[], str]] = None, + error_describer: Callable[[], str] | None = None, ) -> Sequence[T]: results = [] exceptions = [] @@ -197,7 +197,7 @@ def mandatory_provide_by_iterable( def mandatory_apply_by_iterable( func: Callable[..., T], args_iterable: Iterable[VarTuple[Any]], - error_describer: Optional[Callable[[], str]] = None, + error_describer: Callable[[], str] | None = None, ) -> Iterable[T]: results = [] exceptions = [] diff --git a/src/adaptix/_internal/provider/fields.py b/src/adaptix/_internal/provider/fields.py index 30ee21ef..7fb857d2 100644 --- a/src/adaptix/_internal/provider/fields.py +++ b/src/adaptix/_internal/provider/fields.py @@ -1,4 +1,3 @@ -from typing import Union from ..model_tools.definitions import BaseField, InputField, OutputField from .location import InputFieldLoc, OutputFieldLoc @@ -24,7 +23,7 @@ def output_field_to_loc(field: OutputField) -> OutputFieldLoc: ) -def field_to_loc(field: BaseField) -> Union[InputFieldLoc, OutputFieldLoc]: +def field_to_loc(field: BaseField) -> InputFieldLoc | OutputFieldLoc: if isinstance(field, InputField): return input_field_to_loc(field) if isinstance(field, OutputField): diff --git a/src/adaptix/_internal/provider/loc_stack_filtering.py b/src/adaptix/_internal/provider/loc_stack_filtering.py index 0df26db6..9950925d 100644 --- a/src/adaptix/_internal/provider/loc_stack_filtering.py +++ b/src/adaptix/_internal/provider/loc_stack_filtering.py @@ -8,7 +8,7 @@ from functools import reduce from inspect import isabstract, isgenerator from re import Pattern -from typing import Any, ClassVar, Optional, TypeVar, Union, final +from typing import Any, ClassVar, TypeVar, Union, final from ..common import TypeHint, VarTuple from ..datastructures import ImmutableStack @@ -213,7 +213,7 @@ def check_loc_stack(self, mediator: DirectMediator, loc_stack: LocStack) -> bool Pred = Union[str, re.Pattern, type, TypeHint, LocStackChecker, "LocStackPattern"] -def _create_non_type_hint_loc_stack_checker(pred: Pred) -> Optional[LocStackChecker]: +def _create_non_type_hint_loc_stack_checker(pred: Pred) -> LocStackChecker | None: if isinstance(pred, str): if pred.isidentifier(): return ExactFieldNameLSC(pred) # this is only an optimization @@ -295,44 +295,44 @@ def __getattr__(self: Pat, item: str) -> Pat: raise AttributeError return self[item] - def __getitem__(self: Pat, item: Union[Pred, VarTuple[Pred]]) -> Pat: + def __getitem__(self: Pat, item: Pred | VarTuple[Pred]) -> Pat: if isinstance(item, tuple) or isgenerator(item): return self._extend_stack( [OrLocStackChecker([self._ensure_loc_stack_checker_from_pred(el) for el in item])], ) return self._extend_stack([self._ensure_loc_stack_checker_from_pred(item)]) - def _ensure_loc_stack_checker(self: Pat, other: Union[Pat, LocStackChecker]) -> LocStackChecker: + def _ensure_loc_stack_checker(self: Pat, other: Pat | LocStackChecker) -> LocStackChecker: if isinstance(other, LocStackChecker): return other return other.build_loc_stack_checker() - def __or__(self: Pat, other: Union[Pat, LocStackChecker]) -> Pat: + def __or__(self: Pat, other: Pat | LocStackChecker) -> Pat: return self._from_lsc( self.build_loc_stack_checker() | self._ensure_loc_stack_checker(other), ) - def __ror__(self: Pat, other: Union[Pat, LocStackChecker]) -> Pat: + def __ror__(self: Pat, other: Pat | LocStackChecker) -> Pat: return self._from_lsc( self._ensure_loc_stack_checker(other) | self.build_loc_stack_checker(), ) - def __and__(self: Pat, other: Union[Pat, LocStackChecker]) -> Pat: + def __and__(self: Pat, other: Pat | LocStackChecker) -> Pat: return self._from_lsc( self.build_loc_stack_checker() & self._ensure_loc_stack_checker(other), ) - def __rand__(self: Pat, other: Union[Pat, LocStackChecker]) -> Pat: + def __rand__(self: Pat, other: Pat | LocStackChecker) -> Pat: return self._from_lsc( self._ensure_loc_stack_checker(other) & self.build_loc_stack_checker(), ) - def __xor__(self: Pat, other: Union[Pat, LocStackChecker]) -> Pat: + def __xor__(self: Pat, other: Pat | LocStackChecker) -> Pat: return self._from_lsc( self.build_loc_stack_checker() ^ self._ensure_loc_stack_checker(other), ) - def __rxor__(self: Pat, other: Union[Pat, LocStackChecker]) -> Pat: + def __rxor__(self: Pat, other: Pat | LocStackChecker) -> Pat: return self._from_lsc( self._ensure_loc_stack_checker(other) ^ self.build_loc_stack_checker(), ) diff --git a/src/adaptix/_internal/provider/loc_stack_tools.py b/src/adaptix/_internal/provider/loc_stack_tools.py index 27d389d3..5a89ae17 100644 --- a/src/adaptix/_internal/provider/loc_stack_tools.py +++ b/src/adaptix/_internal/provider/loc_stack_tools.py @@ -1,5 +1,5 @@ +from collections.abc import Callable from itertools import pairwise -from typing import Callable from ..common import TypeHint from ..type_tools.type_rendering import TypeHintRenderer diff --git a/src/adaptix/_internal/provider/location.py b/src/adaptix/_internal/provider/location.py index 710878e9..c4288b09 100644 --- a/src/adaptix/_internal/provider/location.py +++ b/src/adaptix/_internal/provider/location.py @@ -1,6 +1,6 @@ -from collections.abc import Container, Mapping +from collections.abc import Callable, Container, Mapping from dataclasses import dataclass, field -from typing import Any, Callable, TypeVar, Union +from typing import Any, TypeVar from ..common import TypeHint from ..model_tools.definitions import Accessor, Default @@ -12,7 +12,7 @@ class _BaseLoc: def cast_or_raise( self, tp: type[T], - exception_factory: Callable[[], Union[BaseException, type[BaseException]]], + exception_factory: Callable[[], BaseException | type[BaseException]], ) -> T: if type(self) in _CAST_SOURCES[tp]: return self # type: ignore[return-value] @@ -97,4 +97,4 @@ class GenericParamLoc(_GenericParamLoc): GenericParamLoc: {GenericParamLoc}, } -AnyLoc = Union[TypeHintLoc, FieldLoc, InputFieldLoc, InputFuncFieldLoc, OutputFieldLoc, GenericParamLoc] +AnyLoc = TypeHintLoc | FieldLoc | InputFieldLoc | InputFuncFieldLoc | OutputFieldLoc | GenericParamLoc diff --git a/src/adaptix/_internal/provider/methods_provider.py b/src/adaptix/_internal/provider/methods_provider.py index 24f0cb46..281c4558 100644 --- a/src/adaptix/_internal/provider/methods_provider.py +++ b/src/adaptix/_internal/provider/methods_provider.py @@ -1,6 +1,6 @@ import inspect -from collections.abc import Iterable, Mapping, Sequence -from typing import Any, Callable, ClassVar, TypeVar, final +from collections.abc import Callable, Iterable, Mapping, Sequence +from typing import Any, ClassVar, TypeVar, final from ..type_tools import get_all_type_hints, is_subclass_soft, normalize_type, strip_tags from .essential import Mediator, Provider, Request, RequestChecker, RequestHandlerRegisterRecord diff --git a/src/adaptix/_internal/provider/overlay_schema.py b/src/adaptix/_internal/provider/overlay_schema.py index 20c71778..3a213187 100644 --- a/src/adaptix/_internal/provider/overlay_schema.py +++ b/src/adaptix/_internal/provider/overlay_schema.py @@ -1,6 +1,6 @@ -from collections.abc import Iterable, Mapping +from collections.abc import Callable, Iterable, Mapping from dataclasses import dataclass, fields -from typing import Any, Callable, ClassVar, Generic, Optional, TypeVar +from typing import Any, ClassVar, Generic, TypeVar from ..datastructures import ClassMap from ..type_tools import strip_alias @@ -26,7 +26,7 @@ class Schema: @dataclass(frozen=True) class Overlay(Generic[Sc]): _schema_cls: ClassVar[type[Schema]] # ClassVar cannot contain TypeVar - _mergers: ClassVar[Optional[Mapping[str, Merger]]] + _mergers: ClassVar[Mapping[str, Merger] | None] def __init_subclass__(cls, *args, **kwargs): for base in cls.__orig_bases__: @@ -109,7 +109,7 @@ def provide_schema(overlay: type[Overlay[Sc]], mediator: Mediator, loc_stack: Lo class OverlayProvider(MethodsProvider): - def __init__(self, overlays: Iterable[Overlay], chain: Optional[Chain]): + def __init__(self, overlays: Iterable[Overlay], chain: Chain | None): self._chain = chain self._overlays = ClassMap(*overlays) diff --git a/src/adaptix/_internal/provider/shape_provider.py b/src/adaptix/_internal/provider/shape_provider.py index 8ad7a3d0..969fea3f 100644 --- a/src/adaptix/_internal/provider/shape_provider.py +++ b/src/adaptix/_internal/provider/shape_provider.py @@ -1,7 +1,7 @@ import inspect from collections.abc import Container, Iterable from dataclasses import dataclass, replace -from typing import Any, Generic, Optional, TypeVar, Union, cast +from typing import Any, Generic, TypeVar, cast from ..common import TypeHint from ..model_tools.definitions import ( @@ -137,7 +137,7 @@ def _infer_property_type(self, tp: TypeHint, attr_name: str) -> TypeHint: return signature.return_annotation -ShapeT = TypeVar("ShapeT", bound=Union[InputShape, OutputShape]) +ShapeT = TypeVar("ShapeT", bound=InputShape | OutputShape) class ShapeGenericResolver(Generic[ShapeT]): @@ -160,7 +160,7 @@ def provide(self) -> ShapeT: ), ) - def _get_members(self, tp) -> MembersStorage[str, Optional[ShapeT]]: + def _get_members(self, tp) -> MembersStorage[str, ShapeT | None]: try: shape = self._mediator.delegating_provide( replace( diff --git a/src/adaptix/_internal/retort/builtin_mediator.py b/src/adaptix/_internal/retort/builtin_mediator.py index 4152c1c8..4b8cb2b2 100644 --- a/src/adaptix/_internal/retort/builtin_mediator.py +++ b/src/adaptix/_internal/retort/builtin_mediator.py @@ -1,6 +1,6 @@ from abc import ABC, abstractmethod -from collections.abc import Mapping -from typing import Any, Callable, Generic, TypeVar +from collections.abc import Callable, Mapping +from typing import Any, Generic, TypeVar from ..provider.essential import CannotProvide, Mediator, Request diff --git a/src/adaptix/_internal/retort/operating_retort.py b/src/adaptix/_internal/retort/operating_retort.py index 69a98018..15d1509d 100644 --- a/src/adaptix/_internal/retort/operating_retort.py +++ b/src/adaptix/_internal/retort/operating_retort.py @@ -1,5 +1,5 @@ -from collections.abc import Iterable, Sequence -from typing import Any, Callable, Generic, Optional, TypeVar +from collections.abc import Callable, Iterable, Sequence +from typing import Any, Generic, TypeVar from ..common import TypeHint from ..conversion.request_cls import CoercerRequest, LinkingRequest @@ -41,7 +41,7 @@ class LocatedRequestCallableRecursionResolver(RecursionResolver[LocatedRequest, def __init__(self) -> None: self._tp_to_stub: dict[TypeHint, FuncWrapper] = {} - def track_request(self, request: LocatedRequest) -> Optional[Any]: + def track_request(self, request: LocatedRequest) -> Any | None: last_loc_type = request.last_loc.type if sum(loc.type == last_loc_type for loc in request.loc_stack) == 1: return None @@ -142,7 +142,7 @@ def _create_error_representor(self, request_cls: type[RequestT]) -> ErrorReprese return BaseRequestErrorRepresentor(f"Cannot satisfy {request_cls}") - def _create_recursion_resolver(self, request_cls: type[RequestT]) -> Optional[RecursionResolver[RequestT, Any]]: + def _create_recursion_resolver(self, request_cls: type[RequestT]) -> RecursionResolver[RequestT, Any] | None: if issubclass(request_cls, (LoaderRequest, DumperRequest)): return LocatedRequestCallableRecursionResolver() # type: ignore[return-value] return None diff --git a/src/adaptix/_internal/retort/request_bus.py b/src/adaptix/_internal/retort/request_bus.py index 26df7c3c..3f908d6d 100644 --- a/src/adaptix/_internal/retort/request_bus.py +++ b/src/adaptix/_internal/retort/request_bus.py @@ -1,6 +1,6 @@ from abc import ABC, abstractmethod -from collections.abc import Iterable -from typing import Any, Callable, Generic, Optional, TypeVar +from collections.abc import Callable, Iterable +from typing import Any, Generic, TypeVar from ..provider.essential import ( AggregateCannotProvide, @@ -114,7 +114,7 @@ def _attach_sub_exceptions_notes(self, exc: E, sub_exceptions: Iterable[CannotPr class RecursionResolver(ABC, Generic[RequestT, ResponseT]): @abstractmethod - def track_request(self, request: RequestT) -> Optional[ResponseT]: + def track_request(self, request: RequestT) -> ResponseT | None: ... @abstractmethod diff --git a/src/adaptix/_internal/retort/routers.py b/src/adaptix/_internal/retort/routers.py index 454213a0..8444932a 100644 --- a/src/adaptix/_internal/retort/routers.py +++ b/src/adaptix/_internal/retort/routers.py @@ -1,6 +1,6 @@ from collections.abc import Sequence from itertools import islice -from typing import Optional, TypeVar, Union +from typing import TypeVar from ..common import TypeHint from ..provider.essential import DirectMediator, Request, RequestChecker, RequestHandler @@ -38,13 +38,13 @@ def get_max_offset(self) -> int: OriginToHandler = dict[TypeHint, RequestHandler] -LRRoutingItem = Union[CheckerAndHandler, OriginToHandler] +LRRoutingItem = CheckerAndHandler | OriginToHandler class LocatedRequestRouter(RequestRouter[LocatedRequest]): __slots__ = ("_items", ) - def __init__(self, items: Sequence[Union[CheckerAndHandler, OriginToHandler]]): + def __init__(self, items: Sequence[CheckerAndHandler | OriginToHandler]): self._items = items def find_handler( @@ -79,7 +79,7 @@ class ExactOriginCombiner: def __init__(self) -> None: self._combo: OriginToHandler = {} - def _stop_combo(self, checker_and_handler: Optional[CheckerAndHandler]) -> Sequence[LRRoutingItem]: + def _stop_combo(self, checker_and_handler: CheckerAndHandler | None) -> Sequence[LRRoutingItem]: result: list[LRRoutingItem] = [] if self._combo: if len(self._combo) == 1: @@ -111,7 +111,7 @@ def finalize(self) -> Sequence[LRRoutingItem]: def create_router_for_located_request( checkers_and_handlers: Sequence[CheckerAndHandler], ) -> RequestRouter[LocatedRequest]: - items: list[Union[CheckerAndHandler, OriginToHandler]] = [] + items: list[CheckerAndHandler | OriginToHandler] = [] combiner = ExactOriginCombiner() for checkers_and_handler in checkers_and_handlers: diff --git a/src/adaptix/_internal/retort/searching_retort.py b/src/adaptix/_internal/retort/searching_retort.py index c9177f04..bef898ea 100644 --- a/src/adaptix/_internal/retort/searching_retort.py +++ b/src/adaptix/_internal/retort/searching_retort.py @@ -1,7 +1,7 @@ from abc import ABC, abstractmethod from collections import defaultdict -from collections.abc import Iterable, Mapping, Sequence -from typing import Any, Callable, Optional, TypeVar +from collections.abc import Callable, Iterable, Mapping, Sequence +from typing import Any, TypeVar from ..compat import CompatBaseExceptionGroup from ..provider.essential import ( @@ -24,7 +24,7 @@ @with_module("adaptix") class ProviderNotFoundError(Exception): - def __init__(self, message: str, description: Optional[str] = None): + def __init__(self, message: str, description: str | None = None): self.message = message self.description = description @@ -48,7 +48,7 @@ def __init__( self, *, recipe: Iterable[Provider] = (), - error_renderer: Optional[ErrorRenderer] = default_error_renderer, + error_renderer: ErrorRenderer | None = default_error_renderer, ): self._error_renderer = error_renderer super().__init__(recipe=recipe) @@ -106,12 +106,12 @@ def _get_facade_error(self, e: CannotProvide, error_message: str) -> Exception: exception.__cause__ = cause return exception - def _get_exception_cause(self, exc: CannotProvide) -> Optional[CannotProvide]: + def _get_exception_cause(self, exc: CannotProvide) -> CannotProvide | None: if isinstance(exc, AggregateCannotProvide): return self._extract_demonstrative_exc(exc) return exc if exc.is_demonstrative else None - def _extract_demonstrative_exc(self, exc: AggregateCannotProvide) -> Optional[CannotProvide]: + def _extract_demonstrative_exc(self, exc: AggregateCannotProvide) -> CannotProvide | None: demonstrative_exc_list: list[CannotProvide] = [] for sub_exc in exc.exceptions: if isinstance(sub_exc, AggregateCannotProvide): @@ -160,7 +160,7 @@ def _create_error_representor(self, request_cls: type[RequestT]) -> ErrorReprese ... @abstractmethod - def _create_recursion_resolver(self, request_cls: type[RequestT]) -> Optional[RecursionResolver[RequestT, Any]]: + def _create_recursion_resolver(self, request_cls: type[RequestT]) -> RecursionResolver[RequestT, Any] | None: ... def _create_request_bus( diff --git a/src/adaptix/_internal/special_cases_optimization.py b/src/adaptix/_internal/special_cases_optimization.py index aa0eba68..030c4a5b 100644 --- a/src/adaptix/_internal/special_cases_optimization.py +++ b/src/adaptix/_internal/special_cases_optimization.py @@ -1,4 +1,4 @@ -from typing import Optional, TypeVar, Union +from typing import TypeVar from .model_tools.definitions import DefaultFactory, DefaultFactoryWithSelf, DefaultValue from .morphing.model.crown_definitions import Sieve @@ -12,10 +12,10 @@ _DEFAULT_CLAUSE_ATTR_NAME = "_adaptix_default_clause" -def with_default_clause(default: Union[DefaultValue, DefaultFactory, DefaultFactoryWithSelf], sieve: S) -> S: +def with_default_clause(default: DefaultValue | DefaultFactory | DefaultFactoryWithSelf, sieve: S) -> S: setattr(sieve, _DEFAULT_CLAUSE_ATTR_NAME, default) return sieve -def get_default_clause(sieve: Sieve) -> Optional[Union[DefaultValue, DefaultFactory, DefaultFactoryWithSelf]]: +def get_default_clause(sieve: Sieve) -> DefaultValue | DefaultFactory | DefaultFactoryWithSelf | None: return getattr(sieve, _DEFAULT_CLAUSE_ATTR_NAME, None) diff --git a/src/adaptix/_internal/struct_trail.py b/src/adaptix/_internal/struct_trail.py index f98d33d2..a7770098 100644 --- a/src/adaptix/_internal/struct_trail.py +++ b/src/adaptix/_internal/struct_trail.py @@ -1,7 +1,7 @@ from collections import deque from collections.abc import Reversible, Sequence from dataclasses import dataclass -from typing import Any, TypeVar, Union +from typing import Any, TypeVar from .feature_requirement import HAS_NATIVE_EXC_GROUP @@ -30,7 +30,7 @@ def __repr__(self): # By default, you must subscribe a source to get the next object, # except with TrailElementMarker children that define custom way to extract values. # For example, Attr means that the next value must be gotten by attribute access -TrailElement = Union[str, int, Any, TrailElementMarker] +TrailElement = str | int | Any | TrailElementMarker Trail = Sequence[TrailElement] T = TypeVar("T") diff --git a/src/adaptix/_internal/tree_renderer.py b/src/adaptix/_internal/tree_renderer.py index a08e7e53..54330283 100644 --- a/src/adaptix/_internal/tree_renderer.py +++ b/src/adaptix/_internal/tree_renderer.py @@ -1,6 +1,6 @@ -from collections.abc import Iterable, Sequence +from collections.abc import Callable, Iterable, Sequence from dataclasses import dataclass -from typing import Callable, Generic, TypeVar +from typing import Generic, TypeVar @dataclass diff --git a/src/adaptix/_internal/type_tools/basic_utils.py b/src/adaptix/_internal/type_tools/basic_utils.py index 87432d5e..2f0b9c04 100644 --- a/src/adaptix/_internal/type_tools/basic_utils.py +++ b/src/adaptix/_internal/type_tools/basic_utils.py @@ -51,7 +51,7 @@ def is_protocol(tp): def create_union(args: tuple): - return Union[args] + return Union[args] # noqa: UP007 def is_parametrized(tp: TypeHint) -> bool: @@ -104,7 +104,7 @@ def is_generic_class(cls: type) -> bool: return ( cls in BUILTIN_ORIGIN_TO_TYPEVARS or ( - issubclass(cls, Generic) # type: ignore[arg-type] + issubclass(cls, Generic) and bool(cls.__parameters__) # type: ignore[attr-defined] ) ) @@ -115,8 +115,8 @@ def get_type_vars_of_parametrized(tp: TypeHint) -> VarTuple[TypeVar]: if not params: return () if isinstance(tp, type): - if isinstance(tp, types.GenericAlias): - return params + if isinstance(tp, types.GenericAlias): # type: ignore[unreachable] + return params # type: ignore[unreachable] return () if strip_alias(tp) != tp and get_generic_args(tp) == (): return () diff --git a/src/adaptix/_internal/type_tools/generic_resolver.py b/src/adaptix/_internal/type_tools/generic_resolver.py index b2cbe15d..926fcf61 100644 --- a/src/adaptix/_internal/type_tools/generic_resolver.py +++ b/src/adaptix/_internal/type_tools/generic_resolver.py @@ -1,8 +1,8 @@ import typing -from collections.abc import Collection, Hashable, Mapping +from collections.abc import Callable, Collection, Hashable, Mapping from dataclasses import dataclass, replace from itertools import chain -from typing import Callable, Generic, TypeVar +from typing import Generic, TypeVar from ..common import TypeHint from ..feature_requirement import HAS_TV_TUPLE, HAS_UNPACK diff --git a/src/adaptix/_internal/type_tools/normalize_type.py b/src/adaptix/_internal/type_tools/normalize_type.py index 45881b3b..817b9910 100644 --- a/src/adaptix/_internal/type_tools/normalize_type.py +++ b/src/adaptix/_internal/type_tools/normalize_type.py @@ -5,7 +5,7 @@ import typing from abc import ABC, abstractmethod from collections import abc as c_abc, defaultdict -from collections.abc import Hashable, Iterable, Sequence +from collections.abc import Callable, Hashable, Iterable, Sequence from copy import copy from dataclasses import InitVar, dataclass from enum import Enum, EnumMeta @@ -13,7 +13,6 @@ from typing import ( Annotated, Any, - Callable, ClassVar, Final, ForwardRef, @@ -137,7 +136,7 @@ def _type_and_value_iter(args): return [(type(arg), arg) for arg in args] -LiteralArg = Union[str, int, bytes, Enum] +LiteralArg = str | int | bytes | Enum class _LiteralNormType(_BasicNormType): @@ -214,7 +213,7 @@ class Constraints: value: VarTuple[BaseNormType] -TypeVarLimit = Union[Bound, Constraints] +TypeVarLimit = Bound | Constraints class _BaseNormTypeVarLike(BaseNormType): @@ -257,7 +256,7 @@ def __eq__(self, other): class NormTV(_BaseNormTypeVarLike): __slots__ = (*_BaseNormTypeVarLike.__slots__, "_limit", "_variance", "_default") - def __init__(self, var: Any, limit: TypeVarLimit, *, source: TypeHint, default: Optional[BaseNormType]): + def __init__(self, var: Any, limit: TypeVarLimit, *, source: TypeHint, default: BaseNormType | None): super().__init__(var, source=source) self._limit = limit @@ -279,26 +278,26 @@ def limit(self) -> TypeVarLimit: return self._limit @property - def default(self) -> Optional[BaseNormType]: + def default(self) -> BaseNormType | None: return self._default class NormTVTuple(_BaseNormTypeVarLike): __slots__ = (*_BaseNormTypeVarLike.__slots__, "_default") - def __init__(self, var: Any, *, source: TypeHint, default: Optional[tuple[BaseNormType, ...]]): + def __init__(self, var: Any, *, source: TypeHint, default: tuple[BaseNormType, ...] | None): super().__init__(var, source=source) self._default = default @property - def default(self) -> Optional[tuple[BaseNormType, ...]]: + def default(self) -> tuple[BaseNormType, ...] | None: return self._default class NormParamSpec(_BaseNormTypeVarLike): __slots__ = (*_BaseNormTypeVarLike.__slots__, "_limit", "_default") - def __init__(self, var: Any, limit: TypeVarLimit, *, source: TypeHint, default: Optional[tuple[BaseNormType, ...]]): + def __init__(self, var: Any, limit: TypeVarLimit, *, source: TypeHint, default: tuple[BaseNormType, ...] | None): super().__init__(var, source=source) self._default = default self._limit = limit @@ -308,7 +307,7 @@ def limit(self) -> TypeVarLimit: return self._limit @property - def default(self) -> Optional[tuple[BaseNormType, ...]]: + def default(self) -> tuple[BaseNormType, ...] | None: return self._default @@ -354,7 +353,7 @@ def origin(self) -> Any: return typing.ParamSpecKwargs -AnyNormTypeVarLike = Union[NormTV, NormTVTuple, NormParamSpec] +AnyNormTypeVarLike = NormTV | NormTVTuple | NormParamSpec class NormTypeAlias(BaseNormType): @@ -467,7 +466,7 @@ def _replace_source_with_union(norm: BaseNormType, sources: list) -> BaseNormTyp ) -NormAspect = Callable[["TypeNormalizer", Any, Any, tuple], Optional[BaseNormType]] +NormAspect = Callable[["TypeNormalizer", Any, Any, tuple], BaseNormType | None] class AspectStorage(list[str]): @@ -479,7 +478,7 @@ def add(self, *, condition: object = True) -> Callable[[NormAspect], NormAspect] def add(self, func: NormAspect) -> NormAspect: ... - def add(self, func: Optional[NormAspect] = None, *, condition: object = True) -> Any: + def add(self, func: NormAspect | None = None, *, condition: object = True) -> Any: if func is None: return partial(self.add, condition=condition) @@ -502,7 +501,7 @@ class NotSubscribedError(ValueError): class TypeNormalizer: def __init__(self, implicit_params_getter: ImplicitParamsGetter): self.implicit_params_getter = implicit_params_getter - self._namespace: Optional[dict[str, Any]] = None + self._namespace: dict[str, Any] | None = None def _with_namespace(self: TN, namespace: dict[str, Any]) -> TN: self_copy = copy(self) diff --git a/src/adaptix/_internal/utils.py b/src/adaptix/_internal/utils.py index f8a0ab66..bc8324eb 100644 --- a/src/adaptix/_internal/utils.py +++ b/src/adaptix/_internal/utils.py @@ -1,10 +1,10 @@ import sys import warnings from abc import ABC, abstractmethod -from collections.abc import Collection, Generator, Iterable, Iterator, Mapping +from collections.abc import Callable, Collection, Generator, Iterable, Iterator, Mapping from contextlib import contextmanager from copy import copy -from typing import Any, Callable, Generic, Protocol, TypeVar, Union, final, overload +from typing import Any, Generic, Protocol, TypeAlias, TypeVar, final, overload from .feature_requirement import HAS_NATIVE_EXC_GROUP, HAS_PY_311 @@ -87,7 +87,7 @@ def __bool__(self): T = TypeVar("T") -Omittable = Union[T, Omitted] +Omittable: TypeAlias = T | Omitted ComparableSeqT = TypeVar("ComparableSeqT", bound="ComparableSequence") diff --git a/tests/tests_helpers/tests_helpers/morphing.py b/tests/tests_helpers/tests_helpers/morphing.py index c93955cf..0f74c4b2 100644 --- a/tests/tests_helpers/tests_helpers/morphing.py +++ b/tests/tests_helpers/tests_helpers/morphing.py @@ -163,7 +163,7 @@ def _assert_json_schema_errors( ) -> None: errors_list = list(errors) assert len(errors_list) == len(templates) - for error, template in zip(errors_list, templates): + for error, template in zip(errors_list, templates, strict=False): assert path_getter(error) == template.path asserter_getter(template)(error) diff --git a/tests/unit/type_tools/test_type_rendering.py b/tests/unit/type_tools/test_type_rendering.py index 8423497f..f00c1aea 100644 --- a/tests/unit/type_tools/test_type_rendering.py +++ b/tests/unit/type_tools/test_type_rendering.py @@ -1,6 +1,7 @@ import collections import typing -from typing import Annotated, Callable, Generic, List, Optional, ParamSpec, TypeVar, Union +from collections.abc import Callable +from typing import Annotated, Generic, List, Optional, ParamSpec, TypeVar, Union import pytest from tests_helpers import cond_list