diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index f6bc7c3..c676a96 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -12,8 +12,7 @@ permissions: env: MINIMUM_PYTHON_VERSION: "3.9" - UV_VERSION: "0.4.18" - UV_CACHE_DIR: /tmp/.uv-cache + UV_VERSION: "0.5.1" # If new code is pushed to a PR branch, then cancel in progress workflows for that PR. Ensures that # we don't waste CI time, and returns results quicker https://github.com/jonhoo/rust-ci-conf/pull/5 @@ -40,16 +39,10 @@ jobs: # ----- setup uv and load cache ----- #---------------------------------------------- - name: Set up uv - run: curl -LsSf https://astral.sh/uv/${{ env.UV_VERSION }}/install.sh | sh - - - name: Restore uv cache - uses: actions/cache@v4 + uses: astral-sh/setup-uv@v3 with: - path: /tmp/.uv-cache - key: uv-${{ runner.os }}-${{ hashFiles('uv.lock') }} - restore-keys: | - uv-${{ runner.os }}-${{ hashFiles('uv.lock') }} - uv-${{ runner.os }} + version: ${{ env.UV_VERSION }} + enable-cache: true - name: Load cached venv id: cached-venv @@ -65,8 +58,6 @@ jobs: - name: check formatting run: make check-fmt - - name: Minimize uv cache - run: uv cache prune --ci lint: runs-on: ubuntu-latest name: ubuntu / 3.9 / lint @@ -84,16 +75,10 @@ jobs: # ----- setup uv and load cache ----- #---------------------------------------------- - name: Set up uv - run: curl -LsSf https://astral.sh/uv/${{ env.UV_VERSION }}/install.sh | sh - - - name: Restore uv cache - uses: actions/cache@v4 + uses: astral-sh/setup-uv@v3 with: - path: /tmp/.uv-cache - key: uv-${{ runner.os }}-${{ hashFiles('uv.lock') }} - restore-keys: | - uv-${{ runner.os }}-${{ hashFiles('uv.lock') }} - uv-${{ runner.os }} + version: ${{ env.UV_VERSION }} + enable-cache: true - name: Load cached venv id: cached-venv @@ -101,15 +86,14 @@ jobs: with: path: .venv key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('**/pyproject.toml') }}-${{ hashFiles('**/uv.lock') }} + - name: Install dependencies if: steps.cached-venv.outputs.cache-hit != 'true' run: make install-dev + - name: lint code run: make lint - - name: Minimize uv cache - run: uv cache prune --ci - type-check: runs-on: ubuntu-latest name: ubuntu / 3.9 / type-check @@ -127,16 +111,10 @@ jobs: # ----- setup uv and load cache ----- #---------------------------------------------- - name: Set up uv - run: curl -LsSf https://astral.sh/uv/${{ env.UV_VERSION }}/install.sh | sh - - - name: Restore uv cache - uses: actions/cache@v4 + uses: astral-sh/setup-uv@v3 with: - path: /tmp/.uv-cache - key: uv-${{ runner.os }}-${{ hashFiles('uv.lock') }} - restore-keys: | - uv-${{ runner.os }}-${{ hashFiles('uv.lock') }} - uv-${{ runner.os }} + version: ${{ env.UV_VERSION }} + enable-cache: true - name: Load cached venv id: cached-venv @@ -144,15 +122,14 @@ jobs: with: path: .venv key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('**/pyproject.toml') }}-${{ hashFiles('**/uv.lock') }} + - name: Install dependencies if: steps.cached-venv.outputs.cache-hit != 'true' run: make install-dev + - name: type-check code run: make type-check - - name: Minimize uv cache - run: uv cache prune --ci - # https://github.com/marketplace/actions/alls-green#why used for branch protection checks check-check: if: always() diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index db3ad6b..9350650 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,8 +17,7 @@ permissions: env: MINIMUM_PYTHON_VERSION: "3.9" - UV_VERSION: "0.4.18" - UV_CACHE_DIR: /tmp/.uv-cache + UV_VERSION: "0.5.1" jobs: build: @@ -48,16 +47,10 @@ jobs: # ----- setup uv and load cache ----- #---------------------------------------------- - name: Set up uv - run: curl -LsSf https://astral.sh/uv/${{ env.UV_VERSION }}/install.sh | sh - - - name: Restore uv cache - uses: actions/cache@v4 + uses: astral-sh/setup-uv@v3 with: - path: /tmp/.uv-cache - key: uv-${{ runner.os }}-${{ hashFiles('uv.lock') }} - restore-keys: | - uv-${{ runner.os }}-${{ hashFiles('uv.lock') }} - uv-${{ runner.os }} + version: ${{ env.UV_VERSION }} + enable-cache: true #---------------------------------------------- # ----- build distribution ----- @@ -73,9 +66,6 @@ jobs: name: pypi_files path: dist - - name: Minimize uv cache - run: uv cache prune --ci - test-build: # This action runs the test suite on the built artifact in the `build` action. # The default is to run this in ubuntu, macos and windows diff --git a/.github/workflows/scheduled.yml b/.github/workflows/scheduled.yml index d4f3ec2..ab75168 100644 --- a/.github/workflows/scheduled.yml +++ b/.github/workflows/scheduled.yml @@ -18,51 +18,75 @@ concurrency: name: rolling env: - UV_VERSION: "0.4.18" - UV_CACHE_DIR: /tmp/.uv-cache + UV_VERSION: "0.5.1" jobs: + # https://twitter.com/mycoliza/status/1571295690063753218 + nightly: + runs-on: ubuntu-latest + name: ubuntu / 3.14-dev + steps: + - uses: actions/checkout@v4 + with: + submodules: true + + - name: Set up uv + uses: astral-sh/setup-uv@v3 + with: + version: ${{ env.UV_VERSION }} + enable-cache: true + + - name: Install python + uses: actions/setup-python@v5 + with: + python-version: "3.14-dev" + + - run: python --version + + - name: uv lock + if: hashFiles('uv.lock') == '' + run: uv lock + + - name: uv sync --dev + run: uv sync --dev + + - name: make test + run: make test + # https://twitter.com/alcuadrado/status/1571291687837732873 update: # This action checks that updating the dependencies of this crate to the latest available that - # satisfy the versions in Cargo.toml does not break this crate. This is important as consumers + # satisfy the versions in pyproject.toml does not break this crate. This is important as consumers # of this crate will generally use the latest available crates. This is subject to the standard # Cargo semver rules (i.e cargo does not update to a new major version unless explicitly told # to). runs-on: ubuntu-latest name: ubuntu / 3.12 / updates work - # There's no point running this if no Cargo.lock was checked in in the first place, since we'd + # There's no point running this if no uv.lock was checked in in the first place, since we'd # just redo what happened in the regular test job. Unfortunately, hashFiles only works in if on # steps, so we repeat it. steps: - uses: actions/checkout@v4 with: submodules: true + - name: Set up uv if: hashFiles('uv.lock') != '' - run: curl -LsSf https://astral.sh/uv/${{ env.UV_VERSION }}/install.sh | sh + uses: astral-sh/setup-uv@v3 + with: + version: ${{ env.UV_VERSION }} + enable-cache: true + - name: Install 3.12 if: hashFiles('uv.lock') != '' uses: actions/setup-python@v5 with: python-version: "3.12" - - name: Restore uv cache - uses: actions/cache@v4 - with: - path: /tmp/.uv-cache - key: uv-${{ runner.os }}-${{ hashFiles('uv.lock') }} - restore-keys: | - uv-${{ runner.os }}-${{ hashFiles('uv.lock') }} - uv-${{ runner.os }} - - name: uv sync --dev --upgrade if: hashFiles('uv.lock') != '' run: uv sync --dev --upgrade + - name: make test if: hashFiles('uv.lock') != '' run: make test - - - name: Minimize uv cache - if: hashFiles('uv.lock') != '' - run: uv cache prune --ci diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b276d4f..840760e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,8 +16,7 @@ permissions: env: MINIMUM_PYTHON_VERSION: "3.9" - UV_VERSION: "0.4.18" - UV_CACHE_DIR: /tmp/.uv-cache + UV_VERSION: "0.5.1" jobs: coverage: @@ -49,7 +48,10 @@ jobs: submodules: true - name: Set up uv - run: curl -LsSf https://astral.sh/uv/${{ env.UV_VERSION }}/install.sh | sh + uses: astral-sh/setup-uv@v3 + with: + version: ${{ env.UV_VERSION }} + enable-cache: true - name: Set up Python ${{ matrix.python-version }} id: setup-python @@ -57,15 +59,6 @@ jobs: with: python-version: ${{ matrix.python-version }} - - name: Restore uv cache - uses: actions/cache@v4 - with: - path: /tmp/.uv-cache - key: uv-${{ runner.os }}-${{ hashFiles('uv.lock') }} - restore-keys: | - uv-${{ runner.os }}-${{ hashFiles('uv.lock') }} - uv-${{ runner.os }} - - name: Load cached venv id: cached-venv uses: actions/cache@v4 @@ -80,11 +73,8 @@ jobs: - name: Run tests for coverage run: make test-w-coverage cov_report=xml - - name: Minimize uv cache - run: uv cache prune --ci - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} # directory: ./coverage @@ -116,7 +106,10 @@ jobs: submodules: true - name: Set up uv - run: curl -LsSf https://astral.sh/uv/${{ env.UV_VERSION }}/install.sh | sh + uses: astral-sh/setup-uv@v3 + with: + version: ${{ env.UV_VERSION }} + enable-cache: true - name: Set up Python ${{ env.MINIMUM_PYTHON_VERSION }} id: setup-python @@ -124,15 +117,6 @@ jobs: with: python-version: ${{ env.MINIMUM_PYTHON_VERSION }} - - name: Restore uv cache - uses: actions/cache@v4 - with: - path: /tmp/.uv-cache - key: uv-${{ runner.os }}-${{ hashFiles('uv.lock') }} - restore-keys: | - uv-${{ runner.os }}-${{ hashFiles('uv.lock') }} - uv-${{ runner.os }} - - name: Load cached venv id: cached-venv uses: actions/cache@v4 @@ -149,9 +133,6 @@ jobs: - name: make doc-tests run: make doc-tests cov_report=xml - - name: Minimize uv cache - run: uv cache prune --ci - - name: Upload coverage to Codecov uses: codecov/codecov-action@v4 with: @@ -181,8 +162,12 @@ jobs: - uses: actions/checkout@v4 with: submodules: true + - name: Set up uv - run: curl -LsSf https://astral.sh/uv/${{ env.UV_VERSION }}/install.sh | sh + uses: astral-sh/setup-uv@v3 + with: + version: ${{ env.UV_VERSION }} + enable-cache: true - name: Set up Python ${{ env.MINIMUM_PYTHON_VERSION }} id: setup-python @@ -190,24 +175,12 @@ jobs: with: python-version: ${{ env.MINIMUM_PYTHON_VERSION }} - - name: Restore uv cache - uses: actions/cache@v4 - with: - path: /tmp/.uv-cache - key: uv-${{ runner.os }}-${{ hashFiles('uv.lock') }} - restore-keys: | - uv-${{ runner.os }}-${{ hashFiles('uv.lock') }} - uv-${{ runner.os }} - - name: install lowest direct dependencies run: uv sync --resolution lowest-direct --all-extras --dev - name: make test run: make test - - name: Minimize uv cache - run: uv cache prune --ci - # https://github.com/marketplace/actions/alls-green#why used for branch protection checks test-check: if: always() diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d58c332..a84b1f6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,34 +1,27 @@ # See https://pre-commit.com for more information # See https://pre-commit.com/hooks.html for more hooks repos: - - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 - hooks: - - id: check-yaml - stages: [commit] - - id: check-json - stages: [commit] - - id: check-toml - stages: [commit] - - id: check-merge-conflict - stages: [commit] - - id: check-case-conflict - stages: [commit] - - id: detect-private-key - stages: [commit] - # - id: end-of-file-fixer - - id: check-added-large-files - stages: [commit] - - repo: https://github.com/astral-sh/ruff-pre-commit - # Ruff version. - rev: v0.7.0 - hooks: - # Run the linter. - - id: ruff - # Run the formatter. - - id: ruff-format - - repo: https://github.com/crate-ci/committed - rev: v1.0.20 - hooks: - - id: committed - stages: [commit-msg] + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: check-yaml + - id: check-json + - id: check-toml + - id: check-merge-conflict + - id: check-case-conflict + - id: detect-private-key + # - id: end-of-file-fixer + - id: check-added-large-files + - repo: https://github.com/astral-sh/ruff-pre-commit + # Ruff version. + rev: v0.7.4 + hooks: + # Run the linter. + - id: ruff + # Run the formatter. + - id: ruff-format + - repo: https://github.com/crate-ci/committed + rev: v1.0.20 + hooks: + - id: committed + stages: [commit-msg] diff --git a/Makefile b/Makefile index dec88b1..0748af1 100644 --- a/Makefile +++ b/Makefile @@ -150,8 +150,8 @@ publish: prepare-release: update-changelog tests/requirements-testing.lock # we use lock extension so that dependabot doesn't pick up changes in this file -tests/requirements-testing.lock: pyproject.toml tests/requirements-testing.in - uv pip compile $^ --output-file $@ +tests/requirements-testing.lock: pyproject.toml + uv export --dev --format requirements-txt --no-hashes --no-emit-project --output-file $@ .PHONY: update-changelog update-changelog: CHANGELOG.md diff --git a/mypy.ini b/mypy.ini index 18a6155..ea4d3cc 100644 --- a/mypy.ini +++ b/mypy.ini @@ -4,5 +4,5 @@ namespace_packages = True explicit_package_bases = True show_error_codes = True ignore_missing_imports = True -python_version = 3.8 +python_version = 3.9 ; plugins = adt.mypy_plugin diff --git a/pyproject.toml b/pyproject.toml index c0b12ef..33a33fa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,21 +38,16 @@ classifiers = [ "Topic :: Utilities", ] -[project.optional-dependencies] +[dependency-groups] dev = [ + "mypy>=1.12.1", "pytest>=8.3.3", + "pytest-cov>=5.0.0", + "ruff>=0.7.0", + "syrupy>=4.7.2", ] + [build-system] requires = ["hatchling"] build-backend = "hatchling.build" - -[tool.uv] -dev-dependencies = [ - "bump-my-version>=0.28.0", - "mypy>=1.12.1", - "pytest-cov>=5.0.0", - "pytest>=8.3.3", - "ruff>=0.7.0", - "syrupy>=4.7.2", -] diff --git a/ruff.toml b/ruff.toml index 4221071..b55b803 100644 --- a/ruff.toml +++ b/ruff.toml @@ -1,5 +1,7 @@ line-length = 97 +target-version = "py39" + [lint] select = [ "A", # flake8-builtins diff --git a/src/parallel_corpus/graph.py b/src/parallel_corpus/graph.py index 0ccfb2f..081b50f 100644 --- a/src/parallel_corpus/graph.py +++ b/src/parallel_corpus/graph.py @@ -1,10 +1,12 @@ """Parallel corpus as a graph.""" +import copy import itertools import logging import re +from collections.abc import Iterable from dataclasses import dataclass -from typing import Dict, Iterable, List, Optional, TypedDict, TypeVar +from typing import Optional, TypedDict, TypeVar import parallel_corpus.shared.ranges import parallel_corpus.shared.str_map @@ -32,24 +34,24 @@ class Edge: # a copy of the identifier used in the edges object of the graph id: str # these are ids to source and target tokens - ids: List[str] + ids: list[str] # labels on this edge - labels: List[str] + labels: list[str] # is this manually or automatically aligned manual: bool comment: Optional[str] = None -Edges = Dict[str, Edge] +Edges = dict[str, Edge] @dataclass -class Graph(SourceTarget[List[Token]]): # noqa: D101 +class Graph(SourceTarget[list[Token]]): # noqa: D101 edges: Edges comment: Optional[str] = None def copy_with_updated_side_and_edges( # noqa: D102 - self, side: Side, new_tokens: List[Token], edges: Edges + self, side: Side, new_tokens: list[Token], edges: Edges ) -> "Graph": source = self.source if side == Side.target else new_tokens target = new_tokens if side == Side.target else self.target @@ -64,8 +66,8 @@ def next_id(g: Graph) -> int: def edge( - ids: List[str], - labels: List[str], + ids: list[str], + labels: list[str], *, comment: Optional[str] = None, manual: bool = False, @@ -81,7 +83,7 @@ def edge( ) -def edge_record(es: Iterable[Edge]) -> Dict[str, Edge]: +def edge_record(es: Iterable[Edge]) -> dict[str, Edge]: return {e.id: e for e in es} @@ -95,7 +97,7 @@ def init_with_source_and_target(source: str, target: str, *, manual: bool = Fals ) -def init_from(tokens: List[str], *, manual: bool = False) -> Graph: +def init_from(tokens: list[str], *, manual: bool = False) -> Graph: return align( Graph( source=text_token.identify(tokens, "s"), @@ -108,7 +110,7 @@ def init_from(tokens: List[str], *, manual: bool = False) -> Graph: def init_from_source_and_target( - source: List[str], target: List[str], *, manual: bool = False + source: list[str], target: list[str], *, manual: bool = False ) -> Graph: source_tokens = text_token.identify(source, "s") target_tokens = text_token.identify(target, "t") @@ -128,12 +130,12 @@ def init_from_source_and_target( class TextLabels(TypedDict): text: str - labels: List[str] + labels: list[str] -def from_unaligned(st: SourceTarget[List[TextLabels]]) -> Graph: +def from_unaligned(st: SourceTarget[list[TextLabels]]) -> Graph: """Initialize a graph from unaligned tokens.""" - edges: Dict[str, Edge] = {} + edges: dict[str, Edge] = {} def proto_token_to_token(tok: TextLabels, i: int, prefix: str) -> Token: id_ = f"{prefix}{i}" @@ -141,7 +143,7 @@ def proto_token_to_token(tok: TextLabels, i: int, prefix: str) -> Token: edges[id_] = e return Token(tok["text"], id_) - def proto_tokens_to_tokens(toks: List[TextLabels], side: Side) -> List[Token]: + def proto_tokens_to_tokens(toks: list[TextLabels], side: Side) -> list[Token]: return [ proto_token_to_token(tok, i, "s" if side == Side.source else "t") for i, tok in enumerate(toks) @@ -206,7 +208,7 @@ def align(g: Graph) -> Graph: c.a is not None and c.b is not None and c.a.id is not None and c.b.id is not None ): uf.union(c.a.id, c.b.id) - proto_edges: Dict[str, Edge] = {k: e for k, e in g.edges.items() if e.manual} + proto_edges: dict[str, Edge] = {k: e for k, e in g.edges.items() if e.manual} first: UniqueCheck[str] = UniqueCheck() def update_edges(tokens, _side) -> None: # noqa: ANN001 @@ -231,31 +233,52 @@ def rearrange(g: Graph, begin: int, end: int, dest: int) -> Graph: return align(unaligned_rearrange(g, begin, end, dest)) -def target_text(g: SourceTarget[List[text_token.Text]]) -> str: +def target_text(g: SourceTarget[list[text_token.Text]]) -> str: return text_token.text(g.target) +def connect_isolated_tokens_based_on_index(g: Graph) -> Graph: + g_new = copy.deepcopy(g) + isolated_source_edges = [ + e for e in g_new.edges.values() if len(e.ids) == 1 and e.ids[0].startswith("s") + ] + isolated_target_edges = [ + e for e in g_new.edges.values() if len(e.ids) == 1 and e.ids[0].startswith("t") + ] + for s_edge in isolated_source_edges: + needle = s_edge.ids[0].replace("s", "t") + t_edge = next(filter(lambda t: t.ids[0] == needle, isolated_target_edges), None) + if t_edge: + del g_new.edges[s_edge.id] + del g_new.edges[t_edge.id] + + new_edge = merge_edges(s_edge, t_edge) + g_new.edges[new_edge.id] = new_edge + + return g_new + + @dataclass class CharIdPair: char: str id: Optional[str] = None -def to_char_ids(token: Token) -> List[CharIdPair]: +def to_char_ids(token: Token) -> list[CharIdPair]: return parallel_corpus.shared.str_map.str_map( token.text, lambda char, _i: CharIdPair(char=char, id=None if char == " " else token.id), ) -def edge_map(g: Graph) -> Dict[str, Edge]: +def edge_map(g: Graph) -> dict[str, Edge]: """Map from token ids to edges. Args: g (Graph): the Graph to build the edge map from. Returns: - Dict[str, Edge]: a map from token ids to edges + dict[str, Edge]: a map from token ids to edges """ edges = {} for e in g.edges.values(): @@ -331,7 +354,7 @@ def get_side_text(g: Graph, side: Side) -> str: return text_token.text(g.get_side(side)) -def get_side_texts(g: Graph, side: Side) -> List[str]: +def get_side_texts(g: Graph, side: Side) -> list[str]: return text_token.texts(g.get_side(side)) diff --git a/src/parallel_corpus/shared/__init__.py b/src/parallel_corpus/shared/__init__.py index 196f7e7..71d74bd 100644 --- a/src/parallel_corpus/shared/__init__.py +++ b/src/parallel_corpus/shared/__init__.py @@ -1,7 +1,7 @@ """Utilities.""" import re -from typing import List, TypeVar +from typing import TypeVar from . import diffs @@ -17,8 +17,8 @@ def end_with_space(s: str) -> str: return f"{s} " if (ENDING_WHITESPACE.fullmatch(s[-1]) is None) else s -def uniq(xs: List[str]) -> List[str]: - used = set() +def uniq(xs: list[str]) -> list[str]: + used: set[str] = set() return [x for x in xs if x not in used and (used.add(x) or True)] # type: ignore [func-returns-value] diff --git a/src/parallel_corpus/shared/dicts.py b/src/parallel_corpus/shared/dicts.py index 7041264..048eaa6 100644 --- a/src/parallel_corpus/shared/dicts.py +++ b/src/parallel_corpus/shared/dicts.py @@ -1,6 +1,6 @@ -"""Dicts.""" +"""dicts.""" -from typing import TYPE_CHECKING, Callable, Dict, List, TypeVar +from typing import TYPE_CHECKING, Callable, TypeVar if TYPE_CHECKING: from _typeshed import SupportsRichComparison @@ -14,15 +14,15 @@ V = TypeVar("V") -def modify(x: Dict[K, V], k: K, default: V, f: Callable[[V], V]) -> V: # noqa: D103 +def modify(x: dict[K, V], k: K, default: V, f: Callable[[V], V]) -> V: # noqa: D103 x[k] = f(x.get(k) or default) return x[k] -def traverse(x: Dict[K, A], k: Callable[[A, K], B], *, sort_keys: bool = False) -> List[B]: # noqa: D103 +def traverse(x: dict[K, A], k: Callable[[A, K], B], *, sort_keys: bool = False) -> list[B]: # noqa: D103 ks = sorted(x.keys()) if sort_keys else x.keys() return [k(x[i], i) for i in ks] -def filter_dict(x: Dict[K, A], k: Callable[[A, K], bool]) -> Dict[K, A]: # noqa: D103 +def filter_dict(x: dict[K, A], k: Callable[[A, K], bool]) -> dict[K, A]: # noqa: D103 return {id_: a for id_, a in x.items() if k(a, id_)} diff --git a/src/parallel_corpus/shared/diffs.py b/src/parallel_corpus/shared/diffs.py index 233e29c..8af4b76 100644 --- a/src/parallel_corpus/shared/diffs.py +++ b/src/parallel_corpus/shared/diffs.py @@ -1,8 +1,9 @@ """Diffs.""" import enum +from collections.abc import Generator from itertools import starmap -from typing import Any, Callable, Dict, Generator, Generic, List, Optional, Tuple, TypeVar, Union +from typing import Any, Callable, Generic, Optional, TypeVar, Union import diff_match_patch as dmp_module from typing_extensions import Self @@ -46,8 +47,8 @@ def deleted(cls, a: A) -> Self: # noqa: D102 def inserted(cls, b: B) -> Self: # noqa: D102 return cls(ChangeType.INSERTED, b=b) - def model_dump(self) -> Dict[str, Union[int, A, B]]: # noqa: D102 - out: Dict[str, Union[int, A, B]] = { + def model_dump(self) -> dict[str, Union[int, A, B]]: # noqa: D102 + out: dict[str, Union[int, A, B]] = { "change": int(self.change), } if self.a is not None: @@ -94,17 +95,17 @@ def char_stream() -> Generator[str, None, None]: def hdiff( # noqa: D103 - xs: List[A], - ys: List[B], + xs: list[A], + ys: list[B], a_cmp: Callable[[A], str] = str, b_cmp: Callable[[B], str] = str, -) -> List[Change[A, B]]: - to: Dict[str, str] = {} - a_from: Dict[str, List[A]] = {} - b_from: Dict[str, List[B]] = {} +) -> list[Change[A, B]]: + to: dict[str, str] = {} + a_from: dict[str, list[A]] = {} + b_from: dict[str, list[B]] = {} chars = char_stream() - def assign(c: C, c_cmp: Callable[[C], str], c_from: Dict[str, List[C]]) -> str: + def assign(c: C, c_cmp: Callable[[C], str], c_from: dict[str, list[C]]) -> str: s = c_cmp(c) u = to.get(s) if u is None: @@ -147,7 +148,7 @@ def map_change(change: int, cs): # noqa: ANN001, ANN202 return out -def token_diff(s1: str, s2: str) -> List[Tuple[int, str]]: # noqa: D103 +def token_diff(s1: str, s2: str) -> list[tuple[int, str]]: # noqa: D103 d = dmp.diff_main(s1, s2) dmp.diff_cleanupSemantic(d) return d diff --git a/src/parallel_corpus/shared/functional.py b/src/parallel_corpus/shared/functional.py index 062bcbd..13867a7 100644 --- a/src/parallel_corpus/shared/functional.py +++ b/src/parallel_corpus/shared/functional.py @@ -1,6 +1,7 @@ """Functional utilities.""" -from typing import Callable, Sequence, TypeVar +from collections.abc import Sequence +from typing import Callable, TypeVar A = TypeVar("A") diff --git a/src/parallel_corpus/shared/ids.py b/src/parallel_corpus/shared/ids.py index f1b2510..bcd5701 100644 --- a/src/parallel_corpus/shared/ids.py +++ b/src/parallel_corpus/shared/ids.py @@ -1,7 +1,7 @@ """Ids.""" import re -from typing import Iterable +from collections.abc import Iterable DIGITS = re.compile(r"\d+") diff --git a/src/parallel_corpus/shared/lists.py b/src/parallel_corpus/shared/lists.py index a0e25e9..85fa629 100644 --- a/src/parallel_corpus/shared/lists.py +++ b/src/parallel_corpus/shared/lists.py @@ -1,12 +1,12 @@ -"""List.""" +"""list.""" import copy -from typing import List, Tuple, TypeVar +from typing import TypeVar A = TypeVar("A") -def rearrange(xs: List[A], begin: int, end: int, dest: int) -> List[A]: +def rearrange(xs: list[A], begin: int, end: int, dest: int) -> list[A]: """Move a slice of the items and puts back them at some destination. rearrange([0, 1, 2, 3], 1, 2, 0) // => [1, 2, 0, 3] @@ -23,14 +23,14 @@ def rearrange(xs: List[A], begin: int, end: int, dest: int) -> List[A]: return pre + mid + post -def splice(xs: List[A], start: int, count: int, *insert) -> Tuple[List[A], List[A]]: # noqa: ANN002, D103 +def splice(xs: list[A], start: int, count: int, *insert) -> tuple[list[A], list[A]]: # noqa: ANN002, D103 ys = copy.deepcopy(xs) zs = ys[start : (start + count)] ys[start : (start + count)] = insert return ys, zs -def split_at_3(xs: List[A], start: int, end: int) -> Tuple[List[A], List[A], List[A]]: +def split_at_3(xs: list[A], start: int, end: int) -> tuple[list[A], list[A], list[A]]: """Split an array into three pieces. splitAt3('0123456'.split(''), 2, 4).map(xs => xs.join('')) // => ['01', '23', '456'] @@ -43,5 +43,5 @@ def split_at_3(xs: List[A], start: int, end: int) -> Tuple[List[A], List[A], Lis return a, b, c -def split_at(xs: List[A], index: int) -> Tuple[List[A], List[A]]: # noqa: D103 +def split_at(xs: list[A], index: int) -> tuple[list[A], list[A]]: # noqa: D103 return xs[:index], xs[index:] diff --git a/src/parallel_corpus/shared/str_map.py b/src/parallel_corpus/shared/str_map.py index 784fabd..fe469fa 100644 --- a/src/parallel_corpus/shared/str_map.py +++ b/src/parallel_corpus/shared/str_map.py @@ -1,9 +1,9 @@ """str_map.""" -from typing import Callable, List, TypeVar +from typing import Callable, TypeVar A = TypeVar("A") -def str_map(s: str, f: Callable[[str, int], A]) -> List[A]: # noqa: D103 +def str_map(s: str, f: Callable[[str, int], A]) -> list[A]: # noqa: D103 return [f(s[i], i) for i in range(len(s))] diff --git a/src/parallel_corpus/shared/union_find.py b/src/parallel_corpus/shared/union_find.py index 6cf01e1..7a32a87 100644 --- a/src/parallel_corpus/shared/union_find.py +++ b/src/parallel_corpus/shared/union_find.py @@ -4,7 +4,7 @@ import functools import json from dataclasses import dataclass -from typing import Callable, Dict, Generic, List, Optional, Tuple, TypeVar +from typing import Callable, Generic, Optional, TypeVar from typing_extensions import Self @@ -23,13 +23,13 @@ def union(self, x: A, y: A) -> A: """Make these belong to the same group.""" @abc.abstractmethod - def unions(self, xs: List[A]) -> None: + def unions(self, xs: list[A]) -> None: """Make these belong to the same group.""" class UnionFind(UnionFindOperations[int]): # noqa: D101 - def __init__(self, *, rev: Optional[List[int]] = None) -> None: # noqa: D107 - self._rev: List[int] = rev or [] + def __init__(self, *, rev: Optional[list[Optional[int]]] = None) -> None: # noqa: D107 + self._rev: list[Optional[int]] = rev or [] def find(self, x: int) -> int: # noqa: D102 while x >= len(self._rev): @@ -47,14 +47,14 @@ def union(self, x: int, y: int) -> int: # noqa: D102 self._rev[find_y] = find_x return find_x - def unions(self, xs: List[int]) -> None: # noqa: D102 + def unions(self, xs: list[int]) -> None: # noqa: D102 functools.reduce(self.union, xs, xs[0]) @dataclass class Renumber(Generic[A]): # noqa: D101 - bw: Dict[str, int] - fw: Dict[int, A] + bw: dict[str, int] + fw: dict[int, A] i = 0 serialize: Callable[[A], str] @@ -76,7 +76,7 @@ def init(cls, serialize: Callable[[A], str] = json.dumps) -> Self: # noqa: D102 def renumber( serialize: Callable[[A], str] = json.dumps, -) -> Tuple[Callable[[int], Optional[A]], Callable[[A], int]]: +) -> tuple[Callable[[int], Optional[A]], Callable[[A], int]]: """Assign unique numbers to each distinct element. const {un, num} = Renumber() @@ -111,7 +111,7 @@ def find(self, x: A) -> Optional[A]: # noqa: D102 def union(self, x: A, y: A) -> Optional[A]: # noqa: D102 return self._renum.un(self._uf.union(self._renum.num(x), self._renum.num(y))) - def unions(self, xs: List[A]) -> None: # noqa: D102 + def unions(self, xs: list[A]) -> None: # noqa: D102 num_xs_0 = self._renum.num(xs[0]) for x in xs[1:]: self._uf.union(num_xs_0, self._renum.num(x)) diff --git a/src/parallel_corpus/shared/unique_check.py b/src/parallel_corpus/shared/unique_check.py index 71e81e4..47d8ccc 100644 --- a/src/parallel_corpus/shared/unique_check.py +++ b/src/parallel_corpus/shared/unique_check.py @@ -1,6 +1,6 @@ """UniqueCheck.""" -from typing import Dict, Generic, TypeVar +from typing import Generic, TypeVar S = TypeVar("S") @@ -55,7 +55,7 @@ class Count(Generic[S]): """ def __init__(self) -> None: # noqa: D107 - self.m: Dict[S, int] = {} + self.m: dict[S, int] = {} def get(self, s: S) -> int: # noqa: D102 return self.m.get(s) or 0 diff --git a/src/parallel_corpus/text_token.py b/src/parallel_corpus/text_token.py index 9e10cb5..bc6bc6e 100644 --- a/src/parallel_corpus/text_token.py +++ b/src/parallel_corpus/text_token.py @@ -1,8 +1,9 @@ """Token.""" import re +from collections.abc import Sequence from dataclasses import dataclass -from typing import List, Sequence, TypedDict +from typing import TypedDict from parallel_corpus import shared @@ -33,7 +34,7 @@ def text(ts: Sequence[Text]) -> str: return "".join(texts(ts)) -def texts(ts: Sequence[Text]) -> List[str]: +def texts(ts: Sequence[Text]) -> list[str]: """Return text from the given tokens as list. >>> texts(identify(tokenize('apa bepa cepa '), '#')) @@ -42,7 +43,7 @@ def texts(ts: Sequence[Text]) -> List[str]: return [t.text for t in ts] -def tokenize(s: str) -> List[str]: +def tokenize(s: str) -> list[str]: """Tokenizes text on whitespace, prefers to have trailing whitespace.""" return list( map( @@ -52,7 +53,7 @@ def tokenize(s: str) -> List[str]: ) -def identify(toks: List[str], prefix: str) -> List[Token]: # noqa: D103 +def identify(toks: list[str], prefix: str) -> list[Token]: # noqa: D103 return [Token(text=text, id=f"{prefix}{i}") for i, text in enumerate(toks)] @@ -61,7 +62,7 @@ class TokenAt(TypedDict): # noqa: D101 offset: int -def token_at(tokens: List[str], character_offset: int) -> TokenAt: +def token_at(tokens: list[str], character_offset: int) -> TokenAt: """Return token at the given offset. >>> abc = ['012', '3456', '789'] diff --git a/tests/requirements-testing.in b/tests/requirements-testing.in deleted file mode 100644 index af4a43e..0000000 --- a/tests/requirements-testing.in +++ /dev/null @@ -1,2 +0,0 @@ -pytest -syrupy diff --git a/tests/requirements-testing.lock b/tests/requirements-testing.lock index 8ae81dd..199e9be 100644 --- a/tests/requirements-testing.lock +++ b/tests/requirements-testing.lock @@ -1,22 +1,37 @@ # This file was autogenerated by uv via the following command: -# uv pip compile pyproject.toml tests/requirements-testing.in --output-file tests/requirements-testing.lock +# uv export --dev --format requirements-txt --no-hashes --no-emit-project --output-file tests/requirements-testing.lock +annotated-types==0.7.0 +bracex==2.5.post1 +bump-my-version==0.28.0 +click==8.1.7 +colorama==0.4.6 ; sys_platform == 'win32' or platform_system == 'Windows' +coverage==7.6.4 diff-match-patch==20241021 - # via parallel-corpus (pyproject.toml) +exceptiongroup==1.2.2 ; python_full_version < '3.11' iniconfig==2.0.0 - # via pytest +markdown-it-py==3.0.0 +mdurl==0.1.2 more-itertools==10.5.0 - # via parallel-corpus (pyproject.toml) +mypy==1.12.1 +mypy-extensions==1.0.0 packaging==24.1 - # via pytest pluggy==1.5.0 - # via pytest +prompt-toolkit==3.0.36 +pydantic==2.9.2 +pydantic-core==2.23.4 +pydantic-settings==2.6.0 +pygments==2.18.0 pytest==8.3.3 - # via - # -r tests/requirements-testing.in - # syrupy +pytest-cov==5.0.0 +python-dotenv==1.0.1 +questionary==2.0.1 +rich==13.9.2 +rich-click==1.8.3 +ruff==0.7.0 strenum==0.4.15 - # via parallel-corpus (pyproject.toml) syrupy==4.7.2 - # via -r tests/requirements-testing.in +tomli==2.0.2 ; python_full_version <= '3.11' +tomlkit==0.13.2 typing-extensions==4.12.2 - # via parallel-corpus (pyproject.toml) +wcmatch==10.0 +wcwidth==0.2.13 diff --git a/tests/test_graph.py b/tests/test_graph.py index 900b8c0..5ebf4c8 100644 --- a/tests/test_graph.py +++ b/tests/test_graph.py @@ -1,5 +1,3 @@ -from typing import List - import pytest from parallel_corpus import graph, text_token @@ -172,11 +170,11 @@ def test_graph_align() -> None: assert len(g_aligned.edges) == 2 -def show(g: graph.Graph) -> List[str]: +def show(g: graph.Graph) -> list[str]: return [t.text for t in g.target] -def show_source(g: graph.Graph) -> List[str]: +def show_source(g: graph.Graph) -> list[str]: return [s.text for s in g.source] @@ -305,3 +303,13 @@ def test_unaligned_rearrange() -> None: # target_text(unaligned_rearrange(init(), 1, 2, 0)) // => + + +def test_connecting_token_based_on_index() -> None: + original_text = "Den 24 maj: JfS 404: pä ansökan af handlanden E. G. Petersson i Mönstcräs. Den 25,maj: M 383: pá ansökan as" # noqa: E501 + generated_text = "Den 24 maj: № 404: på ansökan af handlanden E. G. Petersson i Mönsterås. Den 25 maj: № 383: på ansökan af" # noqa: E501 + + g = graph.init_with_source_and_target(original_text, generated_text) + print(f"{g=}") + g_new = graph.connect_isolated_tokens_based_on_index(g) + assert "e-s3-t3" in g_new.edges diff --git a/tests/test_token.py b/tests/test_token.py index 2479ffa..6e46bd2 100644 --- a/tests/test_token.py +++ b/tests/test_token.py @@ -1,5 +1,3 @@ -from typing import List - import pytest from parallel_corpus.text_token import Token, identify, tokenize @@ -23,7 +21,7 @@ def test_can_create_token() -> None: (" apa bepa cepa ", [" apa ", "bepa ", "cepa "]), ], ) -def test_tokenize(text: str, expected: List[str], snapshot) -> None: +def test_tokenize(text: str, expected: list[str], snapshot) -> None: actual = tokenize(text) assert actual == expected diff --git a/uv.lock b/uv.lock index 55566aa..f2d2c1d 100644 --- a/uv.lock +++ b/uv.lock @@ -5,55 +5,6 @@ resolution-markers = [ "python_full_version >= '3.13'", ] -[[package]] -name = "annotated-types" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 }, -] - -[[package]] -name = "bracex" -version = "2.5.post1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/6c/57418c4404cd22fe6275b8301ca2b46a8cdaa8157938017a9ae0b3edf363/bracex-2.5.post1.tar.gz", hash = "sha256:12c50952415bfa773d2d9ccb8e79651b8cdb1f31a42f6091b804f6ba2b4a66b6", size = 26641 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4b/02/8db98cdc1a58e0abd6716d5e63244658e6e63513c65f469f34b6f1053fd0/bracex-2.5.post1-py3-none-any.whl", hash = "sha256:13e5732fec27828d6af308628285ad358047cec36801598368cb28bc631dbaf6", size = 11558 }, -] - -[[package]] -name = "bump-my-version" -version = "0.28.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "questionary" }, - { name = "rich" }, - { name = "rich-click" }, - { name = "tomlkit" }, - { name = "wcmatch" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d4/25/9b361ff2d42733578ee2b5564cf8b7dc389a187b6b6184c2c19d090e3084/bump_my_version-0.28.0.tar.gz", hash = "sha256:ff3cb51bb15509ae8ebb8e8efa3eaa7c02209677f45457c8b007ef2f5bef7179", size = 983361 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5f/f8/3d46566ab1caaac211ef678160d8174cb8e88ab4bd22439cecc6351ddecd/bump_my_version-0.28.0-py3-none-any.whl", hash = "sha256:cc84ace477022a4cc8c401ef5c035f2f752df45488be90ccb764a47f7de0e395", size = 52201 }, -] - -[[package]] -name = "click" -version = "8.1.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "platform_system == 'Windows'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/96/d3/f04c7bfcf5c1862a2a5b845c6b2b360488cf47af55dfa79c98f6a6bf98b5/click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de", size = 336121 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", size = 97941 }, -] - [[package]] name = "colorama" version = "0.4.6" @@ -164,27 +115,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, ] -[[package]] -name = "markdown-it-py" -version = "3.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mdurl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 }, -] - -[[package]] -name = "mdurl" -version = "0.1.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 }, -] - [[package]] name = "more-itertools" version = "10.5.0" @@ -262,14 +192,8 @@ dependencies = [ { name = "typing-extensions" }, ] -[package.optional-dependencies] -dev = [ - { name = "pytest" }, -] - [package.dev-dependencies] dev = [ - { name = "bump-my-version" }, { name = "mypy" }, { name = "pytest" }, { name = "pytest-cov" }, @@ -281,14 +205,12 @@ dev = [ requires-dist = [ { name = "diff-match-patch", specifier = ">=20230430" }, { name = "more-itertools", specifier = ">=10.2.0" }, - { name = "pytest", marker = "extra == 'dev'", specifier = ">=8.3.3" }, { name = "strenum", specifier = ">=0.4.15" }, { name = "typing-extensions", specifier = ">=4.11.0" }, ] [package.metadata.requires-dev] dev = [ - { name = "bump-my-version", specifier = ">=0.28.0" }, { name = "mypy", specifier = ">=1.12.1" }, { name = "pytest", specifier = ">=8.3.3" }, { name = "pytest-cov", specifier = ">=5.0.0" }, @@ -305,141 +227,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 }, ] -[[package]] -name = "prompt-toolkit" -version = "3.0.36" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "wcwidth" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fb/93/180be2342f89f16543ec4eb3f25083b5b84eba5378f68efff05409fb39a9/prompt_toolkit-3.0.36.tar.gz", hash = "sha256:3e163f254bef5a03b146397d7c1963bd3e2812f0964bb9a24e6ec761fd28db63", size = 423863 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/37/791f1a6edd13c61cac85282368aa68cb0f3f164440fdf60032f2cc6ca34e/prompt_toolkit-3.0.36-py3-none-any.whl", hash = "sha256:aa64ad242a462c5ff0363a7b9cfe696c20d55d9fc60c11fd8e632d064804d305", size = 386414 }, -] - -[[package]] -name = "pydantic" -version = "2.9.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "annotated-types" }, - { name = "pydantic-core" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a9/b7/d9e3f12af310e1120c21603644a1cd86f59060e040ec5c3a80b8f05fae30/pydantic-2.9.2.tar.gz", hash = "sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f", size = 769917 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/df/e4/ba44652d562cbf0bf320e0f3810206149c8a4e99cdbf66da82e97ab53a15/pydantic-2.9.2-py3-none-any.whl", hash = "sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12", size = 434928 }, -] - -[[package]] -name = "pydantic-core" -version = "2.23.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e2/aa/6b6a9b9f8537b872f552ddd46dd3da230367754b6f707b8e1e963f515ea3/pydantic_core-2.23.4.tar.gz", hash = "sha256:2584f7cf844ac4d970fba483a717dbe10c1c1c96a969bf65d61ffe94df1b2863", size = 402156 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5c/8b/d3ae387f66277bd8104096d6ec0a145f4baa2966ebb2cad746c0920c9526/pydantic_core-2.23.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:b10bd51f823d891193d4717448fab065733958bdb6a6b351967bd349d48d5c9b", size = 1867835 }, - { url = "https://files.pythonhosted.org/packages/46/76/f68272e4c3a7df8777798282c5e47d508274917f29992d84e1898f8908c7/pydantic_core-2.23.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4fc714bdbfb534f94034efaa6eadd74e5b93c8fa6315565a222f7b6f42ca1166", size = 1776689 }, - { url = "https://files.pythonhosted.org/packages/cc/69/5f945b4416f42ea3f3bc9d2aaec66c76084a6ff4ff27555bf9415ab43189/pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63e46b3169866bd62849936de036f901a9356e36376079b05efa83caeaa02ceb", size = 1800748 }, - { url = "https://files.pythonhosted.org/packages/50/ab/891a7b0054bcc297fb02d44d05c50e68154e31788f2d9d41d0b72c89fdf7/pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed1a53de42fbe34853ba90513cea21673481cd81ed1be739f7f2efb931b24916", size = 1806469 }, - { url = "https://files.pythonhosted.org/packages/31/7c/6e3fa122075d78f277a8431c4c608f061881b76c2b7faca01d317ee39b5d/pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cfdd16ab5e59fc31b5e906d1a3f666571abc367598e3e02c83403acabc092e07", size = 2002246 }, - { url = "https://files.pythonhosted.org/packages/ad/6f/22d5692b7ab63fc4acbc74de6ff61d185804a83160adba5e6cc6068e1128/pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255a8ef062cbf6674450e668482456abac99a5583bbafb73f9ad469540a3a232", size = 2659404 }, - { url = "https://files.pythonhosted.org/packages/11/ac/1e647dc1121c028b691028fa61a4e7477e6aeb5132628fde41dd34c1671f/pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a7cd62e831afe623fbb7aabbb4fe583212115b3ef38a9f6b71869ba644624a2", size = 2053940 }, - { url = "https://files.pythonhosted.org/packages/91/75/984740c17f12c3ce18b5a2fcc4bdceb785cce7df1511a4ce89bca17c7e2d/pydantic_core-2.23.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f09e2ff1f17c2b51f2bc76d1cc33da96298f0a036a137f5440ab3ec5360b624f", size = 1921437 }, - { url = "https://files.pythonhosted.org/packages/a0/74/13c5f606b64d93f0721e7768cd3e8b2102164866c207b8cd6f90bb15d24f/pydantic_core-2.23.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e38e63e6f3d1cec5a27e0afe90a085af8b6806ee208b33030e65b6516353f1a3", size = 1966129 }, - { url = "https://files.pythonhosted.org/packages/18/03/9c4aa5919457c7b57a016c1ab513b1a926ed9b2bb7915bf8e506bf65c34b/pydantic_core-2.23.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0dbd8dbed2085ed23b5c04afa29d8fd2771674223135dc9bc937f3c09284d071", size = 2110908 }, - { url = "https://files.pythonhosted.org/packages/92/2c/053d33f029c5dc65e5cf44ff03ceeefb7cce908f8f3cca9265e7f9b540c8/pydantic_core-2.23.4-cp310-none-win32.whl", hash = "sha256:6531b7ca5f951d663c339002e91aaebda765ec7d61b7d1e3991051906ddde119", size = 1735278 }, - { url = "https://files.pythonhosted.org/packages/de/81/7dfe464eca78d76d31dd661b04b5f2036ec72ea8848dd87ab7375e185c23/pydantic_core-2.23.4-cp310-none-win_amd64.whl", hash = "sha256:7c9129eb40958b3d4500fa2467e6a83356b3b61bfff1b414c7361d9220f9ae8f", size = 1917453 }, - { url = "https://files.pythonhosted.org/packages/5d/30/890a583cd3f2be27ecf32b479d5d615710bb926d92da03e3f7838ff3e58b/pydantic_core-2.23.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:77733e3892bb0a7fa797826361ce8a9184d25c8dffaec60b7ffe928153680ba8", size = 1865160 }, - { url = "https://files.pythonhosted.org/packages/1d/9a/b634442e1253bc6889c87afe8bb59447f106ee042140bd57680b3b113ec7/pydantic_core-2.23.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b84d168f6c48fabd1f2027a3d1bdfe62f92cade1fb273a5d68e621da0e44e6d", size = 1776777 }, - { url = "https://files.pythonhosted.org/packages/75/9a/7816295124a6b08c24c96f9ce73085032d8bcbaf7e5a781cd41aa910c891/pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df49e7a0861a8c36d089c1ed57d308623d60416dab2647a4a17fe050ba85de0e", size = 1799244 }, - { url = "https://files.pythonhosted.org/packages/a9/8f/89c1405176903e567c5f99ec53387449e62f1121894aa9fc2c4fdc51a59b/pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ff02b6d461a6de369f07ec15e465a88895f3223eb75073ffea56b84d9331f607", size = 1805307 }, - { url = "https://files.pythonhosted.org/packages/d5/a5/1a194447d0da1ef492e3470680c66048fef56fc1f1a25cafbea4bc1d1c48/pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:996a38a83508c54c78a5f41456b0103c30508fed9abcad0a59b876d7398f25fd", size = 2000663 }, - { url = "https://files.pythonhosted.org/packages/13/a5/1df8541651de4455e7d587cf556201b4f7997191e110bca3b589218745a5/pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d97683ddee4723ae8c95d1eddac7c192e8c552da0c73a925a89fa8649bf13eea", size = 2655941 }, - { url = "https://files.pythonhosted.org/packages/44/31/a3899b5ce02c4316865e390107f145089876dff7e1dfc770a231d836aed8/pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:216f9b2d7713eb98cb83c80b9c794de1f6b7e3145eef40400c62e86cee5f4e1e", size = 2052105 }, - { url = "https://files.pythonhosted.org/packages/1b/aa/98e190f8745d5ec831f6d5449344c48c0627ac5fed4e5340a44b74878f8e/pydantic_core-2.23.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6f783e0ec4803c787bcea93e13e9932edab72068f68ecffdf86a99fd5918878b", size = 1919967 }, - { url = "https://files.pythonhosted.org/packages/ae/35/b6e00b6abb2acfee3e8f85558c02a0822e9a8b2f2d812ea8b9079b118ba0/pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d0776dea117cf5272382634bd2a5c1b6eb16767c223c6a5317cd3e2a757c61a0", size = 1964291 }, - { url = "https://files.pythonhosted.org/packages/13/46/7bee6d32b69191cd649bbbd2361af79c472d72cb29bb2024f0b6e350ba06/pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d5f7a395a8cf1621939692dba2a6b6a830efa6b3cee787d82c7de1ad2930de64", size = 2109666 }, - { url = "https://files.pythonhosted.org/packages/39/ef/7b34f1b122a81b68ed0a7d0e564da9ccdc9a2924c8d6c6b5b11fa3a56970/pydantic_core-2.23.4-cp311-none-win32.whl", hash = "sha256:74b9127ffea03643e998e0c5ad9bd3811d3dac8c676e47db17b0ee7c3c3bf35f", size = 1732940 }, - { url = "https://files.pythonhosted.org/packages/2f/76/37b7e76c645843ff46c1d73e046207311ef298d3f7b2f7d8f6ac60113071/pydantic_core-2.23.4-cp311-none-win_amd64.whl", hash = "sha256:98d134c954828488b153d88ba1f34e14259284f256180ce659e8d83e9c05eaa3", size = 1916804 }, - { url = "https://files.pythonhosted.org/packages/74/7b/8e315f80666194b354966ec84b7d567da77ad927ed6323db4006cf915f3f/pydantic_core-2.23.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f3e0da4ebaef65158d4dfd7d3678aad692f7666877df0002b8a522cdf088f231", size = 1856459 }, - { url = "https://files.pythonhosted.org/packages/14/de/866bdce10ed808323d437612aca1ec9971b981e1c52e5e42ad9b8e17a6f6/pydantic_core-2.23.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f69a8e0b033b747bb3e36a44e7732f0c99f7edd5cea723d45bc0d6e95377ffee", size = 1770007 }, - { url = "https://files.pythonhosted.org/packages/dc/69/8edd5c3cd48bb833a3f7ef9b81d7666ccddd3c9a635225214e044b6e8281/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:723314c1d51722ab28bfcd5240d858512ffd3116449c557a1336cbe3919beb87", size = 1790245 }, - { url = "https://files.pythonhosted.org/packages/80/33/9c24334e3af796ce80d2274940aae38dd4e5676298b4398eff103a79e02d/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb2802e667b7051a1bebbfe93684841cc9351004e2badbd6411bf357ab8d5ac8", size = 1801260 }, - { url = "https://files.pythonhosted.org/packages/a5/6f/e9567fd90104b79b101ca9d120219644d3314962caa7948dd8b965e9f83e/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d18ca8148bebe1b0a382a27a8ee60350091a6ddaf475fa05ef50dc35b5df6327", size = 1996872 }, - { url = "https://files.pythonhosted.org/packages/2d/ad/b5f0fe9e6cfee915dd144edbd10b6e9c9c9c9d7a56b69256d124b8ac682e/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33e3d65a85a2a4a0dc3b092b938a4062b1a05f3a9abde65ea93b233bca0e03f2", size = 2661617 }, - { url = "https://files.pythonhosted.org/packages/06/c8/7d4b708f8d05a5cbfda3243aad468052c6e99de7d0937c9146c24d9f12e9/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:128585782e5bfa515c590ccee4b727fb76925dd04a98864182b22e89a4e6ed36", size = 2071831 }, - { url = "https://files.pythonhosted.org/packages/89/4d/3079d00c47f22c9a9a8220db088b309ad6e600a73d7a69473e3a8e5e3ea3/pydantic_core-2.23.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:68665f4c17edcceecc112dfed5dbe6f92261fb9d6054b47d01bf6371a6196126", size = 1917453 }, - { url = "https://files.pythonhosted.org/packages/e9/88/9df5b7ce880a4703fcc2d76c8c2d8eb9f861f79d0c56f4b8f5f2607ccec8/pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:20152074317d9bed6b7a95ade3b7d6054845d70584216160860425f4fbd5ee9e", size = 1968793 }, - { url = "https://files.pythonhosted.org/packages/e3/b9/41f7efe80f6ce2ed3ee3c2dcfe10ab7adc1172f778cc9659509a79518c43/pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24", size = 2116872 }, - { url = "https://files.pythonhosted.org/packages/63/08/b59b7a92e03dd25554b0436554bf23e7c29abae7cce4b1c459cd92746811/pydantic_core-2.23.4-cp312-none-win32.whl", hash = "sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84", size = 1738535 }, - { url = "https://files.pythonhosted.org/packages/88/8d/479293e4d39ab409747926eec4329de5b7129beaedc3786eca070605d07f/pydantic_core-2.23.4-cp312-none-win_amd64.whl", hash = "sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9", size = 1917992 }, - { url = "https://files.pythonhosted.org/packages/ad/ef/16ee2df472bf0e419b6bc68c05bf0145c49247a1095e85cee1463c6a44a1/pydantic_core-2.23.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7530e201d10d7d14abce4fb54cfe5b94a0aefc87da539d0346a484ead376c3cc", size = 1856143 }, - { url = "https://files.pythonhosted.org/packages/da/fa/bc3dbb83605669a34a93308e297ab22be82dfb9dcf88c6cf4b4f264e0a42/pydantic_core-2.23.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:df933278128ea1cd77772673c73954e53a1c95a4fdf41eef97c2b779271bd0bd", size = 1770063 }, - { url = "https://files.pythonhosted.org/packages/4e/48/e813f3bbd257a712303ebdf55c8dc46f9589ec74b384c9f652597df3288d/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05", size = 1790013 }, - { url = "https://files.pythonhosted.org/packages/b4/e0/56eda3a37929a1d297fcab1966db8c339023bcca0b64c5a84896db3fcc5c/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c6dcb030aefb668a2b7009c85b27f90e51e6a3b4d5c9bc4c57631292015b0d", size = 1801077 }, - { url = "https://files.pythonhosted.org/packages/04/be/5e49376769bfbf82486da6c5c1683b891809365c20d7c7e52792ce4c71f3/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:696dd8d674d6ce621ab9d45b205df149399e4bb9aa34102c970b721554828510", size = 1996782 }, - { url = "https://files.pythonhosted.org/packages/bc/24/e3ee6c04f1d58cc15f37bcc62f32c7478ff55142b7b3e6d42ea374ea427c/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2971bb5ffe72cc0f555c13e19b23c85b654dd2a8f7ab493c262071377bfce9f6", size = 2661375 }, - { url = "https://files.pythonhosted.org/packages/c1/f8/11a9006de4e89d016b8de74ebb1db727dc100608bb1e6bbe9d56a3cbbcce/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8394d940e5d400d04cad4f75c0598665cbb81aecefaca82ca85bd28264af7f9b", size = 2071635 }, - { url = "https://files.pythonhosted.org/packages/7c/45/bdce5779b59f468bdf262a5bc9eecbae87f271c51aef628d8c073b4b4b4c/pydantic_core-2.23.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0dff76e0602ca7d4cdaacc1ac4c005e0ce0dcfe095d5b5259163a80d3a10d327", size = 1916994 }, - { url = "https://files.pythonhosted.org/packages/d8/fa/c648308fe711ee1f88192cad6026ab4f925396d1293e8356de7e55be89b5/pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7d32706badfe136888bdea71c0def994644e09fff0bfe47441deaed8e96fdbc6", size = 1968877 }, - { url = "https://files.pythonhosted.org/packages/16/16/b805c74b35607d24d37103007f899abc4880923b04929547ae68d478b7f4/pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f", size = 2116814 }, - { url = "https://files.pythonhosted.org/packages/d1/58/5305e723d9fcdf1c5a655e6a4cc2a07128bf644ff4b1d98daf7a9dbf57da/pydantic_core-2.23.4-cp313-none-win32.whl", hash = "sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769", size = 1738360 }, - { url = "https://files.pythonhosted.org/packages/a5/ae/e14b0ff8b3f48e02394d8acd911376b7b66e164535687ef7dc24ea03072f/pydantic_core-2.23.4-cp313-none-win_amd64.whl", hash = "sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5", size = 1919411 }, - { url = "https://files.pythonhosted.org/packages/7a/04/2580b2deaae37b3e30fc30c54298be938b973990b23612d6b61c7bdd01c7/pydantic_core-2.23.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a4fa4fc04dff799089689f4fd502ce7d59de529fc2f40a2c8836886c03e0175a", size = 1868200 }, - { url = "https://files.pythonhosted.org/packages/39/6e/e311bd0751505350f0cdcee3077841eb1f9253c5a1ddbad048cd9fbf7c6e/pydantic_core-2.23.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0a7df63886be5e270da67e0966cf4afbae86069501d35c8c1b3b6c168f42cb36", size = 1749316 }, - { url = "https://files.pythonhosted.org/packages/d0/b4/95b5eb47c6dc8692508c3ca04a1f8d6f0884c9dacb34cf3357595cbe73be/pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcedcd19a557e182628afa1d553c3895a9f825b936415d0dbd3cd0bbcfd29b4b", size = 1800880 }, - { url = "https://files.pythonhosted.org/packages/da/79/41c4f817acd7f42d94cd1e16526c062a7b089f66faed4bd30852314d9a66/pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f54b118ce5de9ac21c363d9b3caa6c800341e8c47a508787e5868c6b79c9323", size = 1807077 }, - { url = "https://files.pythonhosted.org/packages/fb/53/d13d1eb0a97d5c06cf7a225935d471e9c241afd389a333f40c703f214973/pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86d2f57d3e1379a9525c5ab067b27dbb8a0642fb5d454e17a9ac434f9ce523e3", size = 2002859 }, - { url = "https://files.pythonhosted.org/packages/53/7d/6b8a1eff453774b46cac8c849e99455b27167971a003212f668e94bc4c9c/pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:de6d1d1b9e5101508cb37ab0d972357cac5235f5c6533d1071964c47139257df", size = 2661437 }, - { url = "https://files.pythonhosted.org/packages/6c/ea/8820f57f0b46e6148ee42d8216b15e8fe3b360944284bbc705bf34fac888/pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1278e0d324f6908e872730c9102b0112477a7f7cf88b308e4fc36ce1bdb6d58c", size = 2054404 }, - { url = "https://files.pythonhosted.org/packages/0f/36/d4ae869e473c3c7868e1cd1e2a1b9e13bce5cd1a7d287f6ac755a0b1575e/pydantic_core-2.23.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9a6b5099eeec78827553827f4c6b8615978bb4b6a88e5d9b93eddf8bb6790f55", size = 1921680 }, - { url = "https://files.pythonhosted.org/packages/0d/f8/eed5c65b80c4ac4494117e2101973b45fc655774ef647d17dde40a70f7d2/pydantic_core-2.23.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e55541f756f9b3ee346b840103f32779c695a19826a4c442b7954550a0972040", size = 1966093 }, - { url = "https://files.pythonhosted.org/packages/e8/c8/1d42ce51d65e571ab53d466cae83434325a126811df7ce4861d9d97bee4b/pydantic_core-2.23.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a5c7ba8ffb6d6f8f2ab08743be203654bb1aaa8c9dcb09f82ddd34eadb695605", size = 2111437 }, - { url = "https://files.pythonhosted.org/packages/aa/c9/7fea9d13383c2ec6865919e09cffe44ab77e911eb281b53a4deaafd4c8e8/pydantic_core-2.23.4-cp39-none-win32.whl", hash = "sha256:37b0fe330e4a58d3c58b24d91d1eb102aeec675a3db4c292ec3928ecd892a9a6", size = 1735049 }, - { url = "https://files.pythonhosted.org/packages/98/95/dd7045c4caa2b73d0bf3b989d66b23cfbb7a0ef14ce99db15677a000a953/pydantic_core-2.23.4-cp39-none-win_amd64.whl", hash = "sha256:1498bec4c05c9c787bde9125cfdcc63a41004ff167f495063191b863399b1a29", size = 1920180 }, - { url = "https://files.pythonhosted.org/packages/13/a9/5d582eb3204464284611f636b55c0a7410d748ff338756323cb1ce721b96/pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f455ee30a9d61d3e1a15abd5068827773d6e4dc513e795f380cdd59932c782d5", size = 1857135 }, - { url = "https://files.pythonhosted.org/packages/2c/57/faf36290933fe16717f97829eabfb1868182ac495f99cf0eda9f59687c9d/pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1e90d2e3bd2c3863d48525d297cd143fe541be8bbf6f579504b9712cb6b643ec", size = 1740583 }, - { url = "https://files.pythonhosted.org/packages/91/7c/d99e3513dc191c4fec363aef1bf4c8af9125d8fa53af7cb97e8babef4e40/pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e203fdf807ac7e12ab59ca2bfcabb38c7cf0b33c41efeb00f8e5da1d86af480", size = 1793637 }, - { url = "https://files.pythonhosted.org/packages/29/18/812222b6d18c2d13eebbb0f7cdc170a408d9ced65794fdb86147c77e1982/pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e08277a400de01bc72436a0ccd02bdf596631411f592ad985dcee21445bd0068", size = 1941963 }, - { url = "https://files.pythonhosted.org/packages/0f/36/c1f3642ac3f05e6bb4aec3ffc399fa3f84895d259cf5f0ce3054b7735c29/pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f220b0eea5965dec25480b6333c788fb72ce5f9129e8759ef876a1d805d00801", size = 1915332 }, - { url = "https://files.pythonhosted.org/packages/f7/ca/9c0854829311fb446020ebb540ee22509731abad886d2859c855dd29b904/pydantic_core-2.23.4-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d06b0c8da4f16d1d1e352134427cb194a0a6e19ad5db9161bf32b2113409e728", size = 1957926 }, - { url = "https://files.pythonhosted.org/packages/c0/1c/7836b67c42d0cd4441fcd9fafbf6a027ad4b79b6559f80cf11f89fd83648/pydantic_core-2.23.4-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ba1a0996f6c2773bd83e63f18914c1de3c9dd26d55f4ac302a7efe93fb8e7433", size = 2100342 }, - { url = "https://files.pythonhosted.org/packages/a9/f9/b6bcaf874f410564a78908739c80861a171788ef4d4f76f5009656672dfe/pydantic_core-2.23.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:9a5bce9d23aac8f0cf0836ecfc033896aa8443b501c58d0602dbfd5bd5b37753", size = 1920344 }, - { url = "https://files.pythonhosted.org/packages/32/fd/ac9cdfaaa7cf2d32590b807d900612b39acb25e5527c3c7e482f0553025b/pydantic_core-2.23.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:78ddaaa81421a29574a682b3179d4cf9e6d405a09b99d93ddcf7e5239c742e21", size = 1857850 }, - { url = "https://files.pythonhosted.org/packages/08/fe/038f4b2bcae325ea643c8ad353191187a4c92a9c3b913b139289a6f2ef04/pydantic_core-2.23.4-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:883a91b5dd7d26492ff2f04f40fbb652de40fcc0afe07e8129e8ae779c2110eb", size = 1740265 }, - { url = "https://files.pythonhosted.org/packages/51/14/b215c9c3cbd1edaaea23014d4b3304260823f712d3fdee52549b19b25d62/pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88ad334a15b32a791ea935af224b9de1bf99bcd62fabf745d5f3442199d86d59", size = 1793912 }, - { url = "https://files.pythonhosted.org/packages/62/de/2c3ad79b63ba564878cbce325be725929ba50089cd5156f89ea5155cb9b3/pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:233710f069d251feb12a56da21e14cca67994eab08362207785cf8c598e74577", size = 1942870 }, - { url = "https://files.pythonhosted.org/packages/cb/55/c222af19e4644c741b3f3fe4fd8bbb6b4cdca87d8a49258b61cf7826b19e/pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:19442362866a753485ba5e4be408964644dd6a09123d9416c54cd49171f50744", size = 1915610 }, - { url = "https://files.pythonhosted.org/packages/c4/7a/9a8760692a6f76bb54bcd43f245ff3d8b603db695899bbc624099c00af80/pydantic_core-2.23.4-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:624e278a7d29b6445e4e813af92af37820fafb6dcc55c012c834f9e26f9aaaef", size = 1958403 }, - { url = "https://files.pythonhosted.org/packages/4c/91/9b03166feb914bb5698e2f6499e07c2617e2eebf69f9374d0358d7eb2009/pydantic_core-2.23.4-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f5ef8f42bec47f21d07668a043f077d507e5bf4e668d5c6dfe6aaba89de1a5b8", size = 2101154 }, - { url = "https://files.pythonhosted.org/packages/1d/d9/1d7ecb98318da4cb96986daaf0e20d66f1651d0aeb9e2d4435b916ce031d/pydantic_core-2.23.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:aea443fffa9fbe3af1a9ba721a87f926fe548d32cab71d188a6ede77d0ff244e", size = 1920855 }, -] - -[[package]] -name = "pydantic-settings" -version = "2.6.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pydantic" }, - { name = "python-dotenv" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/6c/66/5f1a9da10675bfb3b9da52f5b689c77e0a5612263fcce510cfac3e99a168/pydantic_settings-2.6.0.tar.gz", hash = "sha256:44a1804abffac9e6a30372bb45f6cafab945ef5af25e66b1c634c01dd39e0188", size = 75232 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/34/19/26bb6bdb9fdad5f0dfce538780814084fb667b4bc37fcb28459c14b8d3b5/pydantic_settings-2.6.0-py3-none-any.whl", hash = "sha256:4a819166f119b74d7f8c765196b165f95cc7487ce58ea27dec8a5a26be0970e0", size = 28578 }, -] - -[[package]] -name = "pygments" -version = "2.18.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/62/8336eff65bcbc8e4cb5d05b55faf041285951b6e80f33e2bff2024788f31/pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199", size = 4891905 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f7/3f/01c8b82017c199075f8f788d0d906b9ffbbc5a47dc9918a945e13d5a2bda/pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a", size = 1205513 }, -] - [[package]] name = "pytest" version = "8.3.3" @@ -470,55 +257,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/78/3a/af5b4fa5961d9a1e6237b530eb87dd04aea6eb83da09d2a4073d81b54ccf/pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652", size = 21990 }, ] -[[package]] -name = "python-dotenv" -version = "1.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bc/57/e84d88dfe0aec03b7a2d4327012c1627ab5f03652216c63d49846d7a6c58/python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", size = 39115 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/3e/b68c118422ec867fa7ab88444e1274aa40681c606d59ac27de5a5588f082/python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a", size = 19863 }, -] - -[[package]] -name = "questionary" -version = "2.0.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "prompt-toolkit" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/84/d0/d73525aeba800df7030ac187d09c59dc40df1c878b4fab8669bdc805535d/questionary-2.0.1.tar.gz", hash = "sha256:bcce898bf3dbb446ff62830c86c5c6fb9a22a54146f0f5597d3da43b10d8fc8b", size = 24726 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0b/e7/2dd8f59d1d328773505f78b85405ddb1cfe74126425d076ce72e65540b8b/questionary-2.0.1-py3-none-any.whl", hash = "sha256:8ab9a01d0b91b68444dff7f6652c1e754105533f083cbe27597c8110ecc230a2", size = 34248 }, -] - -[[package]] -name = "rich" -version = "13.9.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markdown-it-py" }, - { name = "pygments" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/aa/9e/1784d15b057b0075e5136445aaea92d23955aad2c93eaede673718a40d95/rich-13.9.2.tar.gz", hash = "sha256:51a2c62057461aaf7152b4d611168f93a9fc73068f8ded2790f29fe2b5366d0c", size = 222843 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/67/91/5474b84e505a6ccc295b2d322d90ff6aa0746745717839ee0c5fb4fdcceb/rich-13.9.2-py3-none-any.whl", hash = "sha256:8c82a3d3f8dcfe9e734771313e606b39d8247bb6b826e196f4914b333b743cf1", size = 242117 }, -] - -[[package]] -name = "rich-click" -version = "1.8.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "rich" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/3a/a9/a1f1af87e83832d794342fbc09c96cc7cd6798b8dfb8adfbe6ccbef8d70c/rich_click-1.8.3.tar.gz", hash = "sha256:6d75bdfa7aa9ed2c467789a0688bc6da23fbe3a143e19aa6ad3f8bac113d2ab3", size = 38209 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/ea/5a0c5a8e6532e971983d1b0fc99268eb66a10f489da35d9022ce01044191/rich_click-1.8.3-py3-none-any.whl", hash = "sha256:636d9c040d31c5eee242201b5bf4f2d358bfae4db14bb22ec1cafa717cfd02cd", size = 35032 }, -] - [[package]] name = "ruff" version = "0.7.0" @@ -574,15 +312,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cf/db/ce8eda256fa131af12e0a76d481711abe4681b6923c27efb9a255c9e4594/tomli-2.0.2-py3-none-any.whl", hash = "sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38", size = 13237 }, ] -[[package]] -name = "tomlkit" -version = "0.13.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b1/09/a439bec5888f00a54b8b9f05fa94d7f901d6735ef4e55dcec9bc37b5d8fa/tomlkit-0.13.2.tar.gz", hash = "sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79", size = 192885 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/b6/a447b5e4ec71e13871be01ba81f5dfc9d0af7e473da256ff46bc0e24026f/tomlkit-0.13.2-py3-none-any.whl", hash = "sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde", size = 37955 }, -] - [[package]] name = "typing-extensions" version = "4.12.2" @@ -591,24 +320,3 @@ sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec3 wheels = [ { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 }, ] - -[[package]] -name = "wcmatch" -version = "10.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "bracex" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/41/ab/b3a52228538ccb983653c446c1656eddf1d5303b9cb8b9aef6a91299f862/wcmatch-10.0.tar.gz", hash = "sha256:e72f0de09bba6a04e0de70937b0cf06e55f36f37b3deb422dfaf854b867b840a", size = 115578 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/df/4ee467ab39cc1de4b852c212c1ed3becfec2e486a51ac1ce0091f85f38d7/wcmatch-10.0-py3-none-any.whl", hash = "sha256:0dd927072d03c0a6527a20d2e6ad5ba8d0380e60870c383bc533b71744df7b7a", size = 39347 }, -] - -[[package]] -name = "wcwidth" -version = "0.2.13" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6c/63/53559446a878410fc5a5974feb13d31d78d752eb18aeba59c7fef1af7598/wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5", size = 101301 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", size = 34166 }, -]