ocr-stringdist 0.0.3__tar.gz → 0.0.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (23) hide show
  1. {ocr_stringdist-0.0.3 → ocr_stringdist-0.0.4}/.gitignore +0 -1
  2. {ocr_stringdist-0.0.3 → ocr_stringdist-0.0.4}/Cargo.lock +2 -2
  3. {ocr_stringdist-0.0.3 → ocr_stringdist-0.0.4}/Cargo.toml +1 -1
  4. ocr_stringdist-0.0.4/Justfile +14 -0
  5. {ocr_stringdist-0.0.3 → ocr_stringdist-0.0.4}/PKG-INFO +21 -2
  6. {ocr_stringdist-0.0.3 → ocr_stringdist-0.0.4}/README.md +19 -0
  7. {ocr_stringdist-0.0.3 → ocr_stringdist-0.0.4}/example.py +10 -1
  8. ocr_stringdist-0.0.4/mypy.ini +137 -0
  9. {ocr_stringdist-0.0.3 → ocr_stringdist-0.0.4}/pyproject.toml +11 -1
  10. {ocr_stringdist-0.0.3 → ocr_stringdist-0.0.4}/python/ocr_stringdist/__init__.py +3 -3
  11. ocr_stringdist-0.0.4/python/ocr_stringdist/matching.py +83 -0
  12. ocr_stringdist-0.0.4/ruff.toml +88 -0
  13. ocr_stringdist-0.0.4/tests/test_matching.py +39 -0
  14. ocr_stringdist-0.0.4/uv.lock +290 -0
  15. ocr_stringdist-0.0.3/Justfile +0 -12
  16. {ocr_stringdist-0.0.3 → ocr_stringdist-0.0.4}/.github/workflows/CI.yml +0 -0
  17. {ocr_stringdist-0.0.3 → ocr_stringdist-0.0.4}/LICENSE +0 -0
  18. {ocr_stringdist-0.0.3 → ocr_stringdist-0.0.4}/python/ocr_stringdist/default_ocr_distances.py +0 -0
  19. {ocr_stringdist-0.0.3 → ocr_stringdist-0.0.4}/python/ocr_stringdist/py.typed +0 -0
  20. {ocr_stringdist-0.0.3 → ocr_stringdist-0.0.4}/src/lib.rs +0 -0
  21. {ocr_stringdist-0.0.3 → ocr_stringdist-0.0.4}/src/rust_stringdist.rs +0 -0
  22. {ocr_stringdist-0.0.3 → ocr_stringdist-0.0.4}/src/weighted_levenshtein.rs +0 -0
  23. {ocr_stringdist-0.0.3 → ocr_stringdist-0.0.4}/tests/test_ocr_stringdist.py +0 -0
@@ -15,7 +15,6 @@ _build/
15
15
  wheelhouse/
16
16
  site/
17
17
  target/
18
- Cargo.lock
19
18
  .venv
20
19
  .vscode
21
20
 
@@ -1,6 +1,6 @@
1
1
  # This file is automatically @generated by Cargo.
2
2
  # It is not intended for manual editing.
3
- version = 4
3
+ version = 3
4
4
 
5
5
  [[package]]
6
6
  name = "ahash"
@@ -67,7 +67,7 @@ dependencies = [
67
67
 
68
68
  [[package]]
69
69
  name = "ocr_stringdist"
70
- version = "0.0.3"
70
+ version = "0.0.4"
71
71
  dependencies = [
72
72
  "ahash",
73
73
  "pyo3",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "ocr_stringdist"
3
- version = "0.0.3"
3
+ version = "0.0.4"
4
4
  edition = "2021"
5
5
  description = "String distances considering OCR errors."
6
6
  authors = ["Niklas von Moers <niklasvmoers@protonmail.com>"]
@@ -0,0 +1,14 @@
1
+ venv:
2
+ rm -rf .venv
3
+ uv venv
4
+ uv sync
5
+
6
+ pytest:
7
+ maturin develop
8
+ uv run pytest
9
+
10
+ test:
11
+ cargo test
12
+
13
+ mypy:
14
+ uv run mypy .
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ocr_stringdist
3
- Version: 0.0.3
3
+ Version: 0.0.4
4
4
  Classifier: Programming Language :: Rust
5
- Classifier: Programming Language :: Python :: Implementation :: PyPy
5
+ Classifier: Programming Language :: Python
6
6
  Classifier: Operating System :: OS Independent
7
7
  License-File: LICENSE
8
8
  Summary: String distances considering OCR errors.
@@ -37,9 +37,12 @@ pip install ocr-stringdist
37
37
  - **Weighted Levenshtein Distance**: An adaptation of the classic Levenshtein algorithm with custom substitution costs for character pairs that are commonly confused in OCR models.
38
38
  - **Pre-defined OCR Distance Map**: A built-in distance map for common OCR confusions (e.g., "0" vs "O", "1" vs "l", "5" vs "S").
39
39
  - **Customizable Cost Maps**: Create your own substitution cost maps for specific OCR systems or domains.
40
+ - **Best Match Finder**: Utility function find_best_candidate to efficiently find the best matching string from a collection of candidates using any specified distance function (including the library's OCR-aware ones). Supports early stopping for performance optimization.
40
41
 
41
42
  ## Usage
42
43
 
44
+ ### Weighted Levenshtein Distance
45
+
43
46
  ```python
44
47
  import ocr_stringdist as osd
45
48
 
@@ -58,6 +61,22 @@ distance = osd.weighted_levenshtein_distance(
58
61
  print(f"Distance with custom map: {distance}")
59
62
  ```
60
63
 
64
+ ### Finding the Best Candidate
65
+
66
+ ```python
67
+ import ocr_stringdist as osd
68
+
69
+ s = "apple"
70
+ candidates = ["apply", "apples", "orange", "appIe"] # 'appIe' has an OCR-like error
71
+
72
+ def ocr_aware_distance(s1: str, s2: str) -> float:
73
+ return osd.weighted_levenshtein_distance(s1, s2, cost_map={("l", "I"): 0.1})
74
+
75
+ best_candidate, best_dist = osd.find_best_candidate(s, candidates, ocr_aware_distance)
76
+ print(f"Best candidate for '{s}' is '{best_candidate}' with distance {best_dist}")
77
+ # Output: Best candidate for 'apple' is 'appIe' with distance 0.1
78
+ ```
79
+
61
80
  ## Acknowledgements
62
81
 
63
82
  This project is inspired by [jellyfish](https://github.com/jamesturk/jellyfish), providing the base implementations of the algorithms used here.
@@ -22,9 +22,12 @@ pip install ocr-stringdist
22
22
  - **Weighted Levenshtein Distance**: An adaptation of the classic Levenshtein algorithm with custom substitution costs for character pairs that are commonly confused in OCR models.
23
23
  - **Pre-defined OCR Distance Map**: A built-in distance map for common OCR confusions (e.g., "0" vs "O", "1" vs "l", "5" vs "S").
24
24
  - **Customizable Cost Maps**: Create your own substitution cost maps for specific OCR systems or domains.
25
+ - **Best Match Finder**: Utility function find_best_candidate to efficiently find the best matching string from a collection of candidates using any specified distance function (including the library's OCR-aware ones). Supports early stopping for performance optimization.
25
26
 
26
27
  ## Usage
27
28
 
29
+ ### Weighted Levenshtein Distance
30
+
28
31
  ```python
29
32
  import ocr_stringdist as osd
30
33
 
@@ -43,6 +46,22 @@ distance = osd.weighted_levenshtein_distance(
43
46
  print(f"Distance with custom map: {distance}")
44
47
  ```
45
48
 
49
+ ### Finding the Best Candidate
50
+
51
+ ```python
52
+ import ocr_stringdist as osd
53
+
54
+ s = "apple"
55
+ candidates = ["apply", "apples", "orange", "appIe"] # 'appIe' has an OCR-like error
56
+
57
+ def ocr_aware_distance(s1: str, s2: str) -> float:
58
+ return osd.weighted_levenshtein_distance(s1, s2, cost_map={("l", "I"): 0.1})
59
+
60
+ best_candidate, best_dist = osd.find_best_candidate(s, candidates, ocr_aware_distance)
61
+ print(f"Best candidate for '{s}' is '{best_candidate}' with distance {best_dist}")
62
+ # Output: Best candidate for 'apple' is 'appIe' with distance 0.1
63
+ ```
64
+
46
65
  ## Acknowledgements
47
66
 
48
67
  This project is inspired by [jellyfish](https://github.com/jamesturk/jellyfish), providing the base implementations of the algorithms used here.
@@ -1,5 +1,5 @@
1
- from ocr_stringdist import weighted_levenshtein_distance
2
1
  from icecream import ic
2
+ from ocr_stringdist import find_best_candidate, weighted_levenshtein_distance
3
3
 
4
4
  ic(
5
5
  weighted_levenshtein_distance(
@@ -39,3 +39,12 @@ ic(weighted_levenshtein_distance("A", "B", {("A", "B"): 0.0}, symmetric=False))
39
39
  ic(weighted_levenshtein_distance("A", "B", {("B", "A"): 0.0}, symmetric=False))
40
40
  ic(weighted_levenshtein_distance("B", "A", {("B", "A"): 0.0}, symmetric=False))
41
41
  ic(weighted_levenshtein_distance("B", "A", {("A", "B"): 0.0}, symmetric=False))
42
+
43
+
44
+ ic(
45
+ find_best_candidate(
46
+ "apple",
47
+ ["apply", "apples", "orange", "appIe"],
48
+ lambda s1, s2: weighted_levenshtein_distance(s1, s2, {("l", "I"): 0.1}),
49
+ )
50
+ )
@@ -0,0 +1,137 @@
1
+ ; Based on https://gist.github.com/CodeByAidan/adb2b9e188256def1fe35b932cba7eb8
2
+ [mypy]
3
+ check_untyped_defs = True
4
+ disallow_any_generics = True
5
+ disallow_any_unimported = True
6
+ disallow_subclassing_any = True
7
+ disallow_untyped_calls = True
8
+ disallow_untyped_decorators = True
9
+ disallow_untyped_defs = True
10
+ ignore_missing_imports = True
11
+ no_implicit_optional = True
12
+ pretty = True
13
+ show_column_numbers = True
14
+ show_error_codes = True
15
+ show_error_context = True
16
+ strict_equality = True
17
+ warn_return_any = True
18
+ warn_unused_ignores = True
19
+
20
+ ; All of this below is just defaults:
21
+ ; -----------------------------------
22
+ ; (if any flags are commented out with a = and nothing after it,
23
+ ; it means there is no default value/custom)
24
+ ; ex. ; mypy_path =
25
+ ; -----------------------------------
26
+ ; (if any flags are commented out with a = and a value after it,
27
+ ; it means that is the default value but it was changed out for
28
+ ; my personal preference in my config above)
29
+ ; ex. ; ignore_missing_imports = False
30
+
31
+ ; == Import discovery ==
32
+ ; mypy_path =
33
+ ; files =
34
+ ; modules =
35
+ ; packages =
36
+ ; exclude =
37
+ namespace_packages = True
38
+ explicit_package_bases = False
39
+ ; ignore_missing_imports = False
40
+ follow_imports = normal
41
+ follow_imports_for_stubs = False
42
+ ; python_executable =
43
+ no_site_packages = False
44
+ no_silence_site_packages = False
45
+
46
+ ; == Platform configuration ==
47
+ ; python_version =
48
+ ; platform =
49
+ ; always_true =
50
+ ; always_false =
51
+
52
+ ; == Disallow dynamic typing ==
53
+ ; disallow_any_unimported = False
54
+ disallow_any_expr = False
55
+ disallow_any_decorated = False
56
+ disallow_any_explicit = False
57
+ ; disallow_any_generics = False
58
+ ; disallow_subclassing_any = False
59
+
60
+ ; == Untyped definitions and calls ==
61
+ ; disallow_untyped_calls = False
62
+ ; untyped_calls_exclude =
63
+ ; disallow_untyped_defs = False
64
+ disallow_incomplete_defs = False
65
+ ; check_untyped_defs = False
66
+ ; disallow_untyped_decorators = False
67
+
68
+ ; == None and Optional handling ==
69
+ implicit_optional = False
70
+ strict_optional = True
71
+
72
+ ; == Configuring warnings ==
73
+ warn_redundant_casts = False
74
+ ; warn_unused_ignores = False
75
+ warn_no_return = True
76
+ ; warn_return_any = False
77
+ warn_unreachable = False
78
+
79
+ ; == Suppressing errors ==
80
+ ignore_errors = False
81
+
82
+ ; == Miscellaneous strictness flags ==
83
+ allow_untyped_globals = False
84
+ allow_redefinition = False
85
+ local_partial_types = False
86
+ ; disable_error_code =
87
+ ; enable_error_code =
88
+ implicit_reexport = True
89
+ strict_concatenate = False
90
+ ; strict_equality = False
91
+ strict = False
92
+
93
+ ; == Configuring error messages ==
94
+ ; show_error_context = False
95
+ ; show_column_numbers = False
96
+ hide_error_codes = False
97
+ ; pretty = False
98
+ color_output = True
99
+ error_summary = True
100
+ show_absolute_path = False
101
+ force_uppercase_builtins = False
102
+ force_union_syntax = False
103
+
104
+ ; == Incremental mode ==
105
+ incremental = True
106
+ cache_dir = .mypy_cache
107
+ sqlite_cache = False
108
+ cache_fine_grained = False
109
+ skip_version_check = False
110
+ skip_cache_mtime_checks = False
111
+
112
+ ; == Advanced options ==
113
+ ; plugins =
114
+ pdb = False
115
+ show_traceback = False
116
+ raise_exceptions = False
117
+ ; custom_typing_module =
118
+ ; custom_typeshed_dir =
119
+ warn_incomplete_stub = False
120
+
121
+ ; == Report generation ==
122
+ ; any_exprs_report =
123
+ ; cobertura_xml_report = ; pip install mypy[reports]
124
+ ; html_report = ; pip install mypy[reports]
125
+ ; xslt_html_report = ; pip install mypy[reports]
126
+ ; linecount_report =
127
+ ; linecoverage_report =
128
+ ; lineprecision_report =
129
+ ; txt_report = ; pip install mypy[reports]
130
+ ; xslt_txt_report = ; pip install mypy[reports]
131
+ ; xml_report = ; pip install mypy[reports]
132
+
133
+ ; == Miscellaneous ==
134
+ ; junit_xml =
135
+ scripts_are_modules = False
136
+ warn_unused_configs = False
137
+ verbosity = 0
@@ -8,7 +8,7 @@ dynamic = ["version"]
8
8
  requires-python = ">=3.9"
9
9
  classifiers = [
10
10
  "Programming Language :: Rust",
11
- "Programming Language :: Python :: Implementation :: PyPy",
11
+ "Programming Language :: Python",
12
12
  "Operating System :: OS Independent",
13
13
  ]
14
14
 
@@ -20,3 +20,13 @@ repository = "https://github.com/NiklasvonM/ocr-stringdist"
20
20
  features = ["pyo3/extension-module", "python"]
21
21
  python-source = "python"
22
22
  module-name = "ocr_stringdist._rust_stringdist"
23
+
24
+ [dependency-groups]
25
+ dev = [
26
+ "icecream>=2.1.4",
27
+ "maturin>=1.8.3",
28
+ "mypy>=1.15.0",
29
+ "pytest>=8.3.5",
30
+ "ruff>=0.11.6",
31
+ "wheel>=0.45.1",
32
+ ]
@@ -1,13 +1,13 @@
1
1
  from typing import Optional
2
2
 
3
3
  from ._rust_stringdist import * # noqa: F403
4
-
5
4
  from .default_ocr_distances import ocr_distance_map
6
-
5
+ from .matching import find_best_candidate
7
6
 
8
7
  __all__ = [
9
8
  "ocr_distance_map",
10
9
  "weighted_levenshtein_distance", # noqa: F405
10
+ "find_best_candidate",
11
11
  ]
12
12
 
13
13
 
@@ -36,6 +36,6 @@ def weighted_levenshtein_distance(
36
36
  """
37
37
  if cost_map is None:
38
38
  cost_map = ocr_distance_map
39
- return _weighted_levenshtein_distance( # noqa: F405
39
+ return _weighted_levenshtein_distance( # type: ignore # noqa: F405
40
40
  s1, s2, cost_map=cost_map, symmetric=symmetric, default_cost=default_cost
41
41
  )
@@ -0,0 +1,83 @@
1
+ from collections.abc import Callable, Iterable
2
+ from typing import Optional
3
+
4
+
5
+ def find_best_candidate(
6
+ s: str,
7
+ candidates: Iterable[str],
8
+ distance_fun: Callable[[str, str], float],
9
+ *,
10
+ minimize: bool = True,
11
+ early_return_value: Optional[float] = None,
12
+ ) -> tuple[str, float]:
13
+ """
14
+ Finds the best matching string from a collection of candidates based on a distance function.
15
+
16
+ Compares a given string against each string in the 'candidates'
17
+ iterable using the provided 'distance_fun'. It identifies the candidate
18
+ that yields the minimum (or maximum, if minimize=False) distance.
19
+
20
+ :param s: The reference string to compare against.
21
+ :type s: str
22
+ :param candidates: An iterable of candidate strings to compare with 's'.
23
+ :type candidates: Iterable[str]
24
+ :param distance_fun: A function that takes two strings (s, candidate) and
25
+ returns a float representing their distance or similarity.
26
+ :type distance_fun: Callable[[str, str], float]
27
+ :param minimize: If True (default), finds the candidate with the minimum
28
+ distance. If False, finds the candidate with the maximum
29
+ distance (useful for similarity scores).
30
+ :type minimize: bool
31
+ :param early_return_value: If provided, the function will return immediately
32
+ if a distance is found that is less than or equal
33
+ to this value (if minimize=True) or greater than
34
+ or equal to this value (if minimize=False).
35
+ If None (default), all candidates are checked.
36
+ :type early_return_value: Optional[float]
37
+ :raises ValueError: If the 'candidates' iterable is empty.
38
+ :return: A tuple containing the best matching candidate string and its
39
+ calculated distance/score.
40
+ :rtype: tuple[str, float]
41
+
42
+ :Example:
43
+
44
+ >>> from ocr_stringdist import weighted_levenshtein_distance as distance
45
+ >>> s = "apple"
46
+ >>> candidates = ["apply", "apples", "orange", "appIe"]
47
+ >>> find_best_match(s, candidates, lambda s1, s2: distance(s1, s2, {("l", "I"): 0.1}))
48
+ ('appIe', 0.1)
49
+ """
50
+ if not candidates:
51
+ raise ValueError("The 'candidates' iterable cannot be empty.")
52
+
53
+ best_candidate: str = ""
54
+
55
+ if minimize:
56
+ best_distance = float("inf")
57
+
58
+ def is_next_best(current: float, best: float) -> bool:
59
+ return current < best
60
+
61
+ def can_return_early(current: float, threshold: float) -> bool:
62
+ return current <= threshold
63
+ else:
64
+ best_distance = -float("inf")
65
+
66
+ def is_next_best(current: float, best: float) -> bool:
67
+ return current > best
68
+
69
+ def can_return_early(current: float, threshold: float) -> bool:
70
+ return current >= threshold
71
+
72
+ for candidate in candidates:
73
+ current_distance = distance_fun(s, candidate)
74
+
75
+ if early_return_value is not None and can_return_early(
76
+ current_distance, early_return_value
77
+ ):
78
+ return candidate, current_distance
79
+ if is_next_best(current_distance, best_distance):
80
+ best_distance = current_distance
81
+ best_candidate = candidate
82
+
83
+ return best_candidate, best_distance
@@ -0,0 +1,88 @@
1
+ # Exclude a variety of commonly ignored directories.
2
+ exclude = [
3
+ ".bzr",
4
+ ".direnv",
5
+ ".eggs",
6
+ ".git",
7
+ ".git-rewrite",
8
+ ".hg",
9
+ ".ipynb_checkpoints",
10
+ ".mypy_cache",
11
+ ".nox",
12
+ ".pants.d",
13
+ ".pyenv",
14
+ ".pytest_cache",
15
+ ".pytype",
16
+ ".ruff_cache",
17
+ ".svn",
18
+ ".tox",
19
+ ".venv",
20
+ ".vscode",
21
+ "__pypackages__",
22
+ "_build",
23
+ "buck-out",
24
+ "build",
25
+ "dist",
26
+ "node_modules",
27
+ "site-packages",
28
+ "venv",
29
+ ]
30
+
31
+ line-length = 100
32
+ indent-width = 4
33
+
34
+ # Assume Python 3.9
35
+ target-version = "py39"
36
+
37
+ [lint]
38
+ select = [
39
+ # pycodestyle
40
+ "E",
41
+ # Pyflakes
42
+ "F",
43
+ # pyupgrade
44
+ "UP",
45
+ # flake8-bugbear
46
+ "B",
47
+ # flake8-simplify
48
+ "SIM",
49
+ # isort
50
+ "I",
51
+ # refurb
52
+ "FURB",
53
+ ]
54
+ ignore = []
55
+
56
+ # Allow fix for all enabled rules (when `--fix`) is provided.
57
+ fixable = ["ALL"]
58
+ unfixable = []
59
+
60
+ # Allow unused variables when underscore-prefixed.
61
+ dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
62
+
63
+ [format]
64
+ # Like Black, use double quotes for strings.
65
+ quote-style = "double"
66
+
67
+ # Like Black, indent with spaces, rather than tabs.
68
+ indent-style = "space"
69
+
70
+ # Like Black, respect magic trailing commas.
71
+ skip-magic-trailing-comma = false
72
+
73
+ # Like Black, automatically detect the appropriate line ending.
74
+ line-ending = "auto"
75
+
76
+ # Enable auto-formatting of code examples in docstrings. Markdown,
77
+ # reStructuredText code/literal blocks and doctests are all supported.
78
+ #
79
+ # This is currently disabled by default, but it is planned for this
80
+ # to be opt-out in the future.
81
+ docstring-code-format = false
82
+
83
+ # Set the line length limit used when formatting code snippets in
84
+ # docstrings.
85
+ #
86
+ # This only has an effect when the `docstring-code-format` setting is
87
+ # enabled.
88
+ docstring-code-line-length = "dynamic"
@@ -0,0 +1,39 @@
1
+ from collections.abc import Iterable
2
+
3
+ import pytest
4
+ from ocr_stringdist import find_best_candidate, weighted_levenshtein_distance
5
+
6
+
7
+ @pytest.mark.parametrize(
8
+ ["s", "candidates", "cost_map", "expected_match", "expected_distance"],
9
+ [
10
+ ("", {"a"}, {}, "a", 1.0),
11
+ ("R0BERT", {"ROBERT", "ALFRED", "Robert"}, {("0", "O"): 0.5}, "ROBERT", 0.5),
12
+ ],
13
+ )
14
+ def test_find_best_candidate(
15
+ s: str,
16
+ candidates: Iterable[str],
17
+ cost_map: dict[tuple[str, str], float],
18
+ expected_match: str,
19
+ expected_distance: float,
20
+ ) -> None:
21
+ actual_match, actual_distance = find_best_candidate(
22
+ s, candidates, lambda s1, s2: weighted_levenshtein_distance(s1, s2, cost_map=cost_map)
23
+ )
24
+ assert actual_match == expected_match
25
+ assert actual_distance == pytest.approx(expected_distance)
26
+
27
+
28
+ def test_find_best_candidate_early_return() -> None:
29
+ # Exact match is present, but a good enough match is found earlier.
30
+ assert find_best_candidate(
31
+ "HANNA", ["ANNA", "HANNA"], weighted_levenshtein_distance, early_return_value=2.0
32
+ ) == ("ANNA", 1.0)
33
+
34
+
35
+ def test_find_best_candidate_maximize() -> None:
36
+ def similarity(s1: str, s2: str) -> float:
37
+ return float(s1 == s2)
38
+
39
+ assert find_best_candidate("one", {"one", "two"}, similarity, minimize=False) == ("one", 1.0)
@@ -0,0 +1,290 @@
1
+ version = 1
2
+ requires-python = ">=3.9"
3
+
4
+ [[package]]
5
+ name = "asttokens"
6
+ version = "3.0.0"
7
+ source = { registry = "https://pypi.org/simple" }
8
+ sdist = { url = "https://files.pythonhosted.org/packages/4a/e7/82da0a03e7ba5141f05cce0d302e6eed121ae055e0456ca228bf693984bc/asttokens-3.0.0.tar.gz", hash = "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7", size = 61978 }
9
+ wheels = [
10
+ { url = "https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2", size = 26918 },
11
+ ]
12
+
13
+ [[package]]
14
+ name = "colorama"
15
+ version = "0.4.6"
16
+ source = { registry = "https://pypi.org/simple" }
17
+ sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 }
18
+ wheels = [
19
+ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 },
20
+ ]
21
+
22
+ [[package]]
23
+ name = "exceptiongroup"
24
+ version = "1.2.2"
25
+ source = { registry = "https://pypi.org/simple" }
26
+ sdist = { url = "https://files.pythonhosted.org/packages/09/35/2495c4ac46b980e4ca1f6ad6db102322ef3ad2410b79fdde159a4b0f3b92/exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc", size = 28883 }
27
+ wheels = [
28
+ { url = "https://files.pythonhosted.org/packages/02/cc/b7e31358aac6ed1ef2bb790a9746ac2c69bcb3c8588b41616914eb106eaf/exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", size = 16453 },
29
+ ]
30
+
31
+ [[package]]
32
+ name = "executing"
33
+ version = "2.2.0"
34
+ source = { registry = "https://pypi.org/simple" }
35
+ sdist = { url = "https://files.pythonhosted.org/packages/91/50/a9d80c47ff289c611ff12e63f7c5d13942c65d68125160cefd768c73e6e4/executing-2.2.0.tar.gz", hash = "sha256:5d108c028108fe2551d1a7b2e8b713341e2cb4fc0aa7dcf966fa4327a5226755", size = 978693 }
36
+ wheels = [
37
+ { url = "https://files.pythonhosted.org/packages/7b/8f/c4d9bafc34ad7ad5d8dc16dd1347ee0e507a52c3adb6bfa8887e1c6a26ba/executing-2.2.0-py2.py3-none-any.whl", hash = "sha256:11387150cad388d62750327a53d3339fad4888b39a6fe233c3afbb54ecffd3aa", size = 26702 },
38
+ ]
39
+
40
+ [[package]]
41
+ name = "icecream"
42
+ version = "2.1.4"
43
+ source = { registry = "https://pypi.org/simple" }
44
+ dependencies = [
45
+ { name = "asttokens" },
46
+ { name = "colorama" },
47
+ { name = "executing" },
48
+ { name = "pygments" },
49
+ ]
50
+ sdist = { url = "https://files.pythonhosted.org/packages/78/5e/9f41831f032b9ce456c919c4989952562fcc2b0eb8c038080c24ce20d6cd/icecream-2.1.4.tar.gz", hash = "sha256:58755e58397d5350a76f25976dee7b607f5febb3c6e1cddfe6b1951896e91573", size = 15872 }
51
+ wheels = [
52
+ { url = "https://files.pythonhosted.org/packages/57/1d/43ef7a6875190e6745ffcd1b12c7aaa7efed082897401e311ee1cd75c8b2/icecream-2.1.4-py3-none-any.whl", hash = "sha256:7bb715f69102cae871b3a361c3b656536db02cfcadac9664c673581cac4df4fd", size = 14782 },
53
+ ]
54
+
55
+ [[package]]
56
+ name = "iniconfig"
57
+ version = "2.1.0"
58
+ source = { registry = "https://pypi.org/simple" }
59
+ sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793 }
60
+ wheels = [
61
+ { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050 },
62
+ ]
63
+
64
+ [[package]]
65
+ name = "maturin"
66
+ version = "1.8.3"
67
+ source = { registry = "https://pypi.org/simple" }
68
+ dependencies = [
69
+ { name = "tomli", marker = "python_full_version < '3.11'" },
70
+ ]
71
+ sdist = { url = "https://files.pythonhosted.org/packages/30/0b/3fd746cf5cfa3c8d7e20ea08c0dbc2c2c765ae051d0fc43d808a38bc9548/maturin-1.8.3.tar.gz", hash = "sha256:304762f86fd53a8031b1bf006d12572a2aa0a5235485031113195cc0152e1e12", size = 199656 }
72
+ wheels = [
73
+ { url = "https://files.pythonhosted.org/packages/78/80/08579d0184ba743345bbd350a3b6419510ff8a4f6e9e671f713160d41fbb/maturin-1.8.3-py3-none-linux_armv6l.whl", hash = "sha256:fa27466b627150123729b2e611f9f9cfade84d24385d72c6877f78c30de30e89", size = 7758366 },
74
+ { url = "https://files.pythonhosted.org/packages/87/1c/00755d28ae277daa828e183c3d118e2923e8b8f0cba4ff708b15d274ac0e/maturin-1.8.3-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:583404d20d7f1d9c8f3c18dcab9014faacabbed6be02da80062c06cd0e279554", size = 15201378 },
75
+ { url = "https://files.pythonhosted.org/packages/58/9f/b8738dc55ba3eb149ad2686d3f9b3c24e44b7baff46cc6baa85e5dc8cf5e/maturin-1.8.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:f9ffdac53dfe0089cf19b597410bc552eb34c856ddb41482b243a695e8b549d3", size = 7934215 },
76
+ { url = "https://files.pythonhosted.org/packages/18/68/300f1a279486d6f63b624a76b81f0fba82545d027127c1ca4d5ded0d1b43/maturin-1.8.3-py3-none-manylinux_2_12_i686.manylinux2010_i686.musllinux_1_1_i686.whl", hash = "sha256:7949a4a17637341f84e88f4cbf0c155998780bbb7a145ed735725b907881c0ae", size = 7791270 },
77
+ { url = "https://files.pythonhosted.org/packages/2e/6d/bf1b8bb9a8b1d9adad242b4089794be318446142975762d04f04ffabae40/maturin-1.8.3-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.musllinux_1_1_x86_64.whl", hash = "sha256:11564fac7486313b7baf3aa4e82c20e1b20364aad3fde2ccbc4c07693c0b7e16", size = 8282824 },
78
+ { url = "https://files.pythonhosted.org/packages/18/e9/c601de8699e546774d3f9e761eab374988f88e4ed7006afbb5ff61bb41c0/maturin-1.8.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:8555d8701cdba6c19c4705a22ce4d2a1814efd792f55dc5873262ff903317540", size = 7595855 },
79
+ { url = "https://files.pythonhosted.org/packages/34/b8/82ae650e6b589289f4219a480f2b220bcf3d9391ae9ea02cc7a58ef59cfc/maturin-1.8.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l.whl", hash = "sha256:5b2a513468c1c9b4d1728d4b6d3d044b7c183985ef819c9ef15e373b70d99c7d", size = 7634888 },
80
+ { url = "https://files.pythonhosted.org/packages/ac/4a/4f898a66cf4697267c447a6f240b6cbcc2dcacd3cab89735bfbd44810be1/maturin-1.8.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.musllinux_1_1_ppc64le.whl", hash = "sha256:2fe8fdff420cfccde127bbc3d8e40835163dcebb6d28c49fffd9aaf1e6ec1090", size = 9810616 },
81
+ { url = "https://files.pythonhosted.org/packages/31/bd/21b0d471e6ade0801f27c33672bca4d563eb1d1e624e534f3bef8a01b1ac/maturin-1.8.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:22cd8b6dc490fee99a62590f914f0c04ddad1dd6dbd5c7e933b3f882b1bd78c2", size = 10923701 },
82
+ { url = "https://files.pythonhosted.org/packages/6c/07/85c32f03ed757c0626e2fc5a9d6454988228be96a756991702a2a757691b/maturin-1.8.3-py3-none-win32.whl", hash = "sha256:2427924546c9d1079b1c0c6c5c1d380e1b8187baba4e6342cca81597a0f3d697", size = 7016502 },
83
+ { url = "https://files.pythonhosted.org/packages/d5/62/f92a130a370dd7aca13c316844b82853647f048cfe1594a81f628ab7101f/maturin-1.8.3-py3-none-win_amd64.whl", hash = "sha256:85f2b882d8235c1c1cb0a38d382ccd5b3ba0674d99cb548d49df9342cc688e36", size = 7953286 },
84
+ { url = "https://files.pythonhosted.org/packages/04/95/8379140838cd95472de843e982d0bf674e8dbf25a899c44e2f76b15704d9/maturin-1.8.3-py3-none-win_arm64.whl", hash = "sha256:33939aabf9a06a8a14ca6c399d32616c7e574fcca8d4ff6dcd984441051f32fb", size = 6687772 },
85
+ ]
86
+
87
+ [[package]]
88
+ name = "mypy"
89
+ version = "1.15.0"
90
+ source = { registry = "https://pypi.org/simple" }
91
+ dependencies = [
92
+ { name = "mypy-extensions" },
93
+ { name = "tomli", marker = "python_full_version < '3.11'" },
94
+ { name = "typing-extensions" },
95
+ ]
96
+ sdist = { url = "https://files.pythonhosted.org/packages/ce/43/d5e49a86afa64bd3839ea0d5b9c7103487007d728e1293f52525d6d5486a/mypy-1.15.0.tar.gz", hash = "sha256:404534629d51d3efea5c800ee7c42b72a6554d6c400e6a79eafe15d11341fd43", size = 3239717 }
97
+ wheels = [
98
+ { url = "https://files.pythonhosted.org/packages/68/f8/65a7ce8d0e09b6329ad0c8d40330d100ea343bd4dd04c4f8ae26462d0a17/mypy-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:979e4e1a006511dacf628e36fadfecbcc0160a8af6ca7dad2f5025529e082c13", size = 10738433 },
99
+ { url = "https://files.pythonhosted.org/packages/b4/95/9c0ecb8eacfe048583706249439ff52105b3f552ea9c4024166c03224270/mypy-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c4bb0e1bd29f7d34efcccd71cf733580191e9a264a2202b0239da95984c5b559", size = 9861472 },
100
+ { url = "https://files.pythonhosted.org/packages/84/09/9ec95e982e282e20c0d5407bc65031dfd0f0f8ecc66b69538296e06fcbee/mypy-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be68172e9fd9ad8fb876c6389f16d1c1b5f100ffa779f77b1fb2176fcc9ab95b", size = 11611424 },
101
+ { url = "https://files.pythonhosted.org/packages/78/13/f7d14e55865036a1e6a0a69580c240f43bc1f37407fe9235c0d4ef25ffb0/mypy-1.15.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c7be1e46525adfa0d97681432ee9fcd61a3964c2446795714699a998d193f1a3", size = 12365450 },
102
+ { url = "https://files.pythonhosted.org/packages/48/e1/301a73852d40c241e915ac6d7bcd7fedd47d519246db2d7b86b9d7e7a0cb/mypy-1.15.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2e2c2e6d3593f6451b18588848e66260ff62ccca522dd231cd4dd59b0160668b", size = 12551765 },
103
+ { url = "https://files.pythonhosted.org/packages/77/ba/c37bc323ae5fe7f3f15a28e06ab012cd0b7552886118943e90b15af31195/mypy-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:6983aae8b2f653e098edb77f893f7b6aca69f6cffb19b2cc7443f23cce5f4828", size = 9274701 },
104
+ { url = "https://files.pythonhosted.org/packages/03/bc/f6339726c627bd7ca1ce0fa56c9ae2d0144604a319e0e339bdadafbbb599/mypy-1.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2922d42e16d6de288022e5ca321cd0618b238cfc5570e0263e5ba0a77dbef56f", size = 10662338 },
105
+ { url = "https://files.pythonhosted.org/packages/e2/90/8dcf506ca1a09b0d17555cc00cd69aee402c203911410136cd716559efe7/mypy-1.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2ee2d57e01a7c35de00f4634ba1bbf015185b219e4dc5909e281016df43f5ee5", size = 9787540 },
106
+ { url = "https://files.pythonhosted.org/packages/05/05/a10f9479681e5da09ef2f9426f650d7b550d4bafbef683b69aad1ba87457/mypy-1.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:973500e0774b85d9689715feeffcc980193086551110fd678ebe1f4342fb7c5e", size = 11538051 },
107
+ { url = "https://files.pythonhosted.org/packages/e9/9a/1f7d18b30edd57441a6411fcbc0c6869448d1a4bacbaee60656ac0fc29c8/mypy-1.15.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a95fb17c13e29d2d5195869262f8125dfdb5c134dc8d9a9d0aecf7525b10c2c", size = 12286751 },
108
+ { url = "https://files.pythonhosted.org/packages/72/af/19ff499b6f1dafcaf56f9881f7a965ac2f474f69f6f618b5175b044299f5/mypy-1.15.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1905f494bfd7d85a23a88c5d97840888a7bd516545fc5aaedff0267e0bb54e2f", size = 12421783 },
109
+ { url = "https://files.pythonhosted.org/packages/96/39/11b57431a1f686c1aed54bf794870efe0f6aeca11aca281a0bd87a5ad42c/mypy-1.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:c9817fa23833ff189db061e6d2eff49b2f3b6ed9856b4a0a73046e41932d744f", size = 9265618 },
110
+ { url = "https://files.pythonhosted.org/packages/98/3a/03c74331c5eb8bd025734e04c9840532226775c47a2c39b56a0c8d4f128d/mypy-1.15.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:aea39e0583d05124836ea645f412e88a5c7d0fd77a6d694b60d9b6b2d9f184fd", size = 10793981 },
111
+ { url = "https://files.pythonhosted.org/packages/f0/1a/41759b18f2cfd568848a37c89030aeb03534411eef981df621d8fad08a1d/mypy-1.15.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2f2147ab812b75e5b5499b01ade1f4a81489a147c01585cda36019102538615f", size = 9749175 },
112
+ { url = "https://files.pythonhosted.org/packages/12/7e/873481abf1ef112c582db832740f4c11b2bfa510e829d6da29b0ab8c3f9c/mypy-1.15.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ce436f4c6d218a070048ed6a44c0bbb10cd2cc5e272b29e7845f6a2f57ee4464", size = 11455675 },
113
+ { url = "https://files.pythonhosted.org/packages/b3/d0/92ae4cde706923a2d3f2d6c39629134063ff64b9dedca9c1388363da072d/mypy-1.15.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8023ff13985661b50a5928fc7a5ca15f3d1affb41e5f0a9952cb68ef090b31ee", size = 12410020 },
114
+ { url = "https://files.pythonhosted.org/packages/46/8b/df49974b337cce35f828ba6fda228152d6db45fed4c86ba56ffe442434fd/mypy-1.15.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1124a18bc11a6a62887e3e137f37f53fbae476dc36c185d549d4f837a2a6a14e", size = 12498582 },
115
+ { url = "https://files.pythonhosted.org/packages/13/50/da5203fcf6c53044a0b699939f31075c45ae8a4cadf538a9069b165c1050/mypy-1.15.0-cp312-cp312-win_amd64.whl", hash = "sha256:171a9ca9a40cd1843abeca0e405bc1940cd9b305eaeea2dda769ba096932bb22", size = 9366614 },
116
+ { url = "https://files.pythonhosted.org/packages/6a/9b/fd2e05d6ffff24d912f150b87db9e364fa8282045c875654ce7e32fffa66/mypy-1.15.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:93faf3fdb04768d44bf28693293f3904bbb555d076b781ad2530214ee53e3445", size = 10788592 },
117
+ { url = "https://files.pythonhosted.org/packages/74/37/b246d711c28a03ead1fd906bbc7106659aed7c089d55fe40dd58db812628/mypy-1.15.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:811aeccadfb730024c5d3e326b2fbe9249bb7413553f15499a4050f7c30e801d", size = 9753611 },
118
+ { url = "https://files.pythonhosted.org/packages/a6/ac/395808a92e10cfdac8003c3de9a2ab6dc7cde6c0d2a4df3df1b815ffd067/mypy-1.15.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:98b7b9b9aedb65fe628c62a6dc57f6d5088ef2dfca37903a7d9ee374d03acca5", size = 11438443 },
119
+ { url = "https://files.pythonhosted.org/packages/d2/8b/801aa06445d2de3895f59e476f38f3f8d610ef5d6908245f07d002676cbf/mypy-1.15.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c43a7682e24b4f576d93072216bf56eeff70d9140241f9edec0c104d0c515036", size = 12402541 },
120
+ { url = "https://files.pythonhosted.org/packages/c7/67/5a4268782eb77344cc613a4cf23540928e41f018a9a1ec4c6882baf20ab8/mypy-1.15.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:baefc32840a9f00babd83251560e0ae1573e2f9d1b067719479bfb0e987c6357", size = 12494348 },
121
+ { url = "https://files.pythonhosted.org/packages/83/3e/57bb447f7bbbfaabf1712d96f9df142624a386d98fb026a761532526057e/mypy-1.15.0-cp313-cp313-win_amd64.whl", hash = "sha256:b9378e2c00146c44793c98b8d5a61039a048e31f429fb0eb546d93f4b000bedf", size = 9373648 },
122
+ { url = "https://files.pythonhosted.org/packages/5a/fa/79cf41a55b682794abe71372151dbbf856e3008f6767057229e6649d294a/mypy-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e601a7fa172c2131bff456bb3ee08a88360760d0d2f8cbd7a75a65497e2df078", size = 10737129 },
123
+ { url = "https://files.pythonhosted.org/packages/d3/33/dd8feb2597d648de29e3da0a8bf4e1afbda472964d2a4a0052203a6f3594/mypy-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:712e962a6357634fef20412699a3655c610110e01cdaa6180acec7fc9f8513ba", size = 9856335 },
124
+ { url = "https://files.pythonhosted.org/packages/e4/b5/74508959c1b06b96674b364ffeb7ae5802646b32929b7701fc6b18447592/mypy-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f95579473af29ab73a10bada2f9722856792a36ec5af5399b653aa28360290a5", size = 11611935 },
125
+ { url = "https://files.pythonhosted.org/packages/6c/53/da61b9d9973efcd6507183fdad96606996191657fe79701b2c818714d573/mypy-1.15.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8f8722560a14cde92fdb1e31597760dc35f9f5524cce17836c0d22841830fd5b", size = 12365827 },
126
+ { url = "https://files.pythonhosted.org/packages/c1/72/965bd9ee89540c79a25778cc080c7e6ef40aa1eeac4d52cec7eae6eb5228/mypy-1.15.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1fbb8da62dc352133d7d7ca90ed2fb0e9d42bb1a32724c287d3c76c58cbaa9c2", size = 12541924 },
127
+ { url = "https://files.pythonhosted.org/packages/46/d0/f41645c2eb263e6c77ada7d76f894c580c9ddb20d77f0c24d34273a4dab2/mypy-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:d10d994b41fb3497719bbf866f227b3489048ea4bbbb5015357db306249f7980", size = 9271176 },
128
+ { url = "https://files.pythonhosted.org/packages/09/4e/a7d65c7322c510de2c409ff3828b03354a7c43f5a8ed458a7a131b41c7b9/mypy-1.15.0-py3-none-any.whl", hash = "sha256:5469affef548bd1895d86d3bf10ce2b44e33d86923c29e4d675b3e323437ea3e", size = 2221777 },
129
+ ]
130
+
131
+ [[package]]
132
+ name = "mypy-extensions"
133
+ version = "1.0.0"
134
+ source = { registry = "https://pypi.org/simple" }
135
+ sdist = { url = "https://files.pythonhosted.org/packages/98/a4/1ab47638b92648243faf97a5aeb6ea83059cc3624972ab6b8d2316078d3f/mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782", size = 4433 }
136
+ wheels = [
137
+ { url = "https://files.pythonhosted.org/packages/2a/e2/5d3f6ada4297caebe1a2add3b126fe800c96f56dbe5d1988a2cbe0b267aa/mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", size = 4695 },
138
+ ]
139
+
140
+ [[package]]
141
+ name = "ocr-stringdist"
142
+ source = { editable = "." }
143
+
144
+ [package.dev-dependencies]
145
+ dev = [
146
+ { name = "icecream" },
147
+ { name = "maturin" },
148
+ { name = "mypy" },
149
+ { name = "pytest" },
150
+ { name = "ruff" },
151
+ { name = "wheel" },
152
+ ]
153
+
154
+ [package.metadata]
155
+
156
+ [package.metadata.requires-dev]
157
+ dev = [
158
+ { name = "icecream", specifier = ">=2.1.4" },
159
+ { name = "maturin", specifier = ">=1.8.3" },
160
+ { name = "mypy", specifier = ">=1.15.0" },
161
+ { name = "pytest", specifier = ">=8.3.5" },
162
+ { name = "ruff", specifier = ">=0.11.6" },
163
+ { name = "wheel", specifier = ">=0.45.1" },
164
+ ]
165
+
166
+ [[package]]
167
+ name = "packaging"
168
+ version = "25.0"
169
+ source = { registry = "https://pypi.org/simple" }
170
+ sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727 }
171
+ wheels = [
172
+ { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469 },
173
+ ]
174
+
175
+ [[package]]
176
+ name = "pluggy"
177
+ version = "1.5.0"
178
+ source = { registry = "https://pypi.org/simple" }
179
+ sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 }
180
+ wheels = [
181
+ { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 },
182
+ ]
183
+
184
+ [[package]]
185
+ name = "pygments"
186
+ version = "2.19.1"
187
+ source = { registry = "https://pypi.org/simple" }
188
+ sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581 }
189
+ wheels = [
190
+ { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293 },
191
+ ]
192
+
193
+ [[package]]
194
+ name = "pytest"
195
+ version = "8.3.5"
196
+ source = { registry = "https://pypi.org/simple" }
197
+ dependencies = [
198
+ { name = "colorama", marker = "sys_platform == 'win32'" },
199
+ { name = "exceptiongroup", marker = "python_full_version < '3.11'" },
200
+ { name = "iniconfig" },
201
+ { name = "packaging" },
202
+ { name = "pluggy" },
203
+ { name = "tomli", marker = "python_full_version < '3.11'" },
204
+ ]
205
+ sdist = { url = "https://files.pythonhosted.org/packages/ae/3c/c9d525a414d506893f0cd8a8d0de7706446213181570cdbd766691164e40/pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845", size = 1450891 }
206
+ wheels = [
207
+ { url = "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", size = 343634 },
208
+ ]
209
+
210
+ [[package]]
211
+ name = "ruff"
212
+ version = "0.11.6"
213
+ source = { registry = "https://pypi.org/simple" }
214
+ sdist = { url = "https://files.pythonhosted.org/packages/d9/11/bcef6784c7e5d200b8a1f5c2ddf53e5da0efec37e6e5a44d163fb97e04ba/ruff-0.11.6.tar.gz", hash = "sha256:bec8bcc3ac228a45ccc811e45f7eb61b950dbf4cf31a67fa89352574b01c7d79", size = 4010053 }
215
+ wheels = [
216
+ { url = "https://files.pythonhosted.org/packages/6e/1f/8848b625100ebcc8740c8bac5b5dd8ba97dd4ee210970e98832092c1635b/ruff-0.11.6-py3-none-linux_armv6l.whl", hash = "sha256:d84dcbe74cf9356d1bdb4a78cf74fd47c740bf7bdeb7529068f69b08272239a1", size = 10248105 },
217
+ { url = "https://files.pythonhosted.org/packages/e0/47/c44036e70c6cc11e6ee24399c2a1e1f1e99be5152bd7dff0190e4b325b76/ruff-0.11.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9bc583628e1096148011a5d51ff3c836f51899e61112e03e5f2b1573a9b726de", size = 11001494 },
218
+ { url = "https://files.pythonhosted.org/packages/ed/5b/170444061650202d84d316e8f112de02d092bff71fafe060d3542f5bc5df/ruff-0.11.6-py3-none-macosx_11_0_arm64.whl", hash = "sha256:f2959049faeb5ba5e3b378709e9d1bf0cab06528b306b9dd6ebd2a312127964a", size = 10352151 },
219
+ { url = "https://files.pythonhosted.org/packages/ff/91/f02839fb3787c678e112c8865f2c3e87cfe1744dcc96ff9fc56cfb97dda2/ruff-0.11.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63c5d4e30d9d0de7fedbfb3e9e20d134b73a30c1e74b596f40f0629d5c28a193", size = 10541951 },
220
+ { url = "https://files.pythonhosted.org/packages/9e/f3/c09933306096ff7a08abede3cc2534d6fcf5529ccd26504c16bf363989b5/ruff-0.11.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:26a4b9a4e1439f7d0a091c6763a100cef8fbdc10d68593df6f3cfa5abdd9246e", size = 10079195 },
221
+ { url = "https://files.pythonhosted.org/packages/e0/0d/a87f8933fccbc0d8c653cfbf44bedda69c9582ba09210a309c066794e2ee/ruff-0.11.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b5edf270223dd622218256569636dc3e708c2cb989242262fe378609eccf1308", size = 11698918 },
222
+ { url = "https://files.pythonhosted.org/packages/52/7d/8eac0bd083ea8a0b55b7e4628428203441ca68cd55e0b67c135a4bc6e309/ruff-0.11.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:f55844e818206a9dd31ff27f91385afb538067e2dc0beb05f82c293ab84f7d55", size = 12319426 },
223
+ { url = "https://files.pythonhosted.org/packages/c2/dc/d0c17d875662d0c86fadcf4ca014ab2001f867621b793d5d7eef01b9dcce/ruff-0.11.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d8f782286c5ff562e4e00344f954b9320026d8e3fae2ba9e6948443fafd9ffc", size = 11791012 },
224
+ { url = "https://files.pythonhosted.org/packages/f9/f3/81a1aea17f1065449a72509fc7ccc3659cf93148b136ff2a8291c4bc3ef1/ruff-0.11.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:01c63ba219514271cee955cd0adc26a4083df1956d57847978383b0e50ffd7d2", size = 13949947 },
225
+ { url = "https://files.pythonhosted.org/packages/61/9f/a3e34de425a668284e7024ee6fd41f452f6fa9d817f1f3495b46e5e3a407/ruff-0.11.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15adac20ef2ca296dd3d8e2bedc6202ea6de81c091a74661c3666e5c4c223ff6", size = 11471753 },
226
+ { url = "https://files.pythonhosted.org/packages/df/c5/4a57a86d12542c0f6e2744f262257b2aa5a3783098ec14e40f3e4b3a354a/ruff-0.11.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:4dd6b09e98144ad7aec026f5588e493c65057d1b387dd937d7787baa531d9bc2", size = 10417121 },
227
+ { url = "https://files.pythonhosted.org/packages/58/3f/a3b4346dff07ef5b862e2ba06d98fcbf71f66f04cf01d375e871382b5e4b/ruff-0.11.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:45b2e1d6c0eed89c248d024ea95074d0e09988d8e7b1dad8d3ab9a67017a5b03", size = 10073829 },
228
+ { url = "https://files.pythonhosted.org/packages/93/cc/7ed02e0b86a649216b845b3ac66ed55d8aa86f5898c5f1691797f408fcb9/ruff-0.11.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:bd40de4115b2ec4850302f1a1d8067f42e70b4990b68838ccb9ccd9f110c5e8b", size = 11076108 },
229
+ { url = "https://files.pythonhosted.org/packages/39/5e/5b09840fef0eff1a6fa1dea6296c07d09c17cb6fb94ed5593aa591b50460/ruff-0.11.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:77cda2dfbac1ab73aef5e514c4cbfc4ec1fbef4b84a44c736cc26f61b3814cd9", size = 11512366 },
230
+ { url = "https://files.pythonhosted.org/packages/6f/4c/1cd5a84a412d3626335ae69f5f9de2bb554eea0faf46deb1f0cb48534042/ruff-0.11.6-py3-none-win32.whl", hash = "sha256:5151a871554be3036cd6e51d0ec6eef56334d74dfe1702de717a995ee3d5b287", size = 10485900 },
231
+ { url = "https://files.pythonhosted.org/packages/42/46/8997872bc44d43df986491c18d4418f1caff03bc47b7f381261d62c23442/ruff-0.11.6-py3-none-win_amd64.whl", hash = "sha256:cce85721d09c51f3b782c331b0abd07e9d7d5f775840379c640606d3159cae0e", size = 11558592 },
232
+ { url = "https://files.pythonhosted.org/packages/d7/6a/65fecd51a9ca19e1477c3879a7fda24f8904174d1275b419422ac00f6eee/ruff-0.11.6-py3-none-win_arm64.whl", hash = "sha256:3567ba0d07fb170b1b48d944715e3294b77f5b7679e8ba258199a250383ccb79", size = 10682766 },
233
+ ]
234
+
235
+ [[package]]
236
+ name = "tomli"
237
+ version = "2.2.1"
238
+ source = { registry = "https://pypi.org/simple" }
239
+ sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175 }
240
+ wheels = [
241
+ { url = "https://files.pythonhosted.org/packages/43/ca/75707e6efa2b37c77dadb324ae7d9571cb424e61ea73fad7c56c2d14527f/tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", size = 131077 },
242
+ { url = "https://files.pythonhosted.org/packages/c7/16/51ae563a8615d472fdbffc43a3f3d46588c264ac4f024f63f01283becfbb/tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", size = 123429 },
243
+ { url = "https://files.pythonhosted.org/packages/f1/dd/4f6cd1e7b160041db83c694abc78e100473c15d54620083dbd5aae7b990e/tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", size = 226067 },
244
+ { url = "https://files.pythonhosted.org/packages/a9/6b/c54ede5dc70d648cc6361eaf429304b02f2871a345bbdd51e993d6cdf550/tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", size = 236030 },
245
+ { url = "https://files.pythonhosted.org/packages/1f/47/999514fa49cfaf7a92c805a86c3c43f4215621855d151b61c602abb38091/tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", size = 240898 },
246
+ { url = "https://files.pythonhosted.org/packages/73/41/0a01279a7ae09ee1573b423318e7934674ce06eb33f50936655071d81a24/tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", size = 229894 },
247
+ { url = "https://files.pythonhosted.org/packages/55/18/5d8bc5b0a0362311ce4d18830a5d28943667599a60d20118074ea1b01bb7/tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", size = 245319 },
248
+ { url = "https://files.pythonhosted.org/packages/92/a3/7ade0576d17f3cdf5ff44d61390d4b3febb8a9fc2b480c75c47ea048c646/tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", size = 238273 },
249
+ { url = "https://files.pythonhosted.org/packages/72/6f/fa64ef058ac1446a1e51110c375339b3ec6be245af9d14c87c4a6412dd32/tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", size = 98310 },
250
+ { url = "https://files.pythonhosted.org/packages/6a/1c/4a2dcde4a51b81be3530565e92eda625d94dafb46dbeb15069df4caffc34/tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", size = 108309 },
251
+ { url = "https://files.pythonhosted.org/packages/52/e1/f8af4c2fcde17500422858155aeb0d7e93477a0d59a98e56cbfe75070fd0/tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", size = 132762 },
252
+ { url = "https://files.pythonhosted.org/packages/03/b8/152c68bb84fc00396b83e7bbddd5ec0bd3dd409db4195e2a9b3e398ad2e3/tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", size = 123453 },
253
+ { url = "https://files.pythonhosted.org/packages/c8/d6/fc9267af9166f79ac528ff7e8c55c8181ded34eb4b0e93daa767b8841573/tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", size = 233486 },
254
+ { url = "https://files.pythonhosted.org/packages/5c/51/51c3f2884d7bab89af25f678447ea7d297b53b5a3b5730a7cb2ef6069f07/tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", size = 242349 },
255
+ { url = "https://files.pythonhosted.org/packages/ab/df/bfa89627d13a5cc22402e441e8a931ef2108403db390ff3345c05253935e/tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", size = 252159 },
256
+ { url = "https://files.pythonhosted.org/packages/9e/6e/fa2b916dced65763a5168c6ccb91066f7639bdc88b48adda990db10c8c0b/tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", size = 237243 },
257
+ { url = "https://files.pythonhosted.org/packages/b4/04/885d3b1f650e1153cbb93a6a9782c58a972b94ea4483ae4ac5cedd5e4a09/tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", size = 259645 },
258
+ { url = "https://files.pythonhosted.org/packages/9c/de/6b432d66e986e501586da298e28ebeefd3edc2c780f3ad73d22566034239/tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", size = 244584 },
259
+ { url = "https://files.pythonhosted.org/packages/1c/9a/47c0449b98e6e7d1be6cbac02f93dd79003234ddc4aaab6ba07a9a7482e2/tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", size = 98875 },
260
+ { url = "https://files.pythonhosted.org/packages/ef/60/9b9638f081c6f1261e2688bd487625cd1e660d0a85bd469e91d8db969734/tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", size = 109418 },
261
+ { url = "https://files.pythonhosted.org/packages/04/90/2ee5f2e0362cb8a0b6499dc44f4d7d48f8fff06d28ba46e6f1eaa61a1388/tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7", size = 132708 },
262
+ { url = "https://files.pythonhosted.org/packages/c0/ec/46b4108816de6b385141f082ba99e315501ccd0a2ea23db4a100dd3990ea/tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", size = 123582 },
263
+ { url = "https://files.pythonhosted.org/packages/a0/bd/b470466d0137b37b68d24556c38a0cc819e8febe392d5b199dcd7f578365/tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", size = 232543 },
264
+ { url = "https://files.pythonhosted.org/packages/d9/e5/82e80ff3b751373f7cead2815bcbe2d51c895b3c990686741a8e56ec42ab/tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", size = 241691 },
265
+ { url = "https://files.pythonhosted.org/packages/05/7e/2a110bc2713557d6a1bfb06af23dd01e7dde52b6ee7dadc589868f9abfac/tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", size = 251170 },
266
+ { url = "https://files.pythonhosted.org/packages/64/7b/22d713946efe00e0adbcdfd6d1aa119ae03fd0b60ebed51ebb3fa9f5a2e5/tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", size = 236530 },
267
+ { url = "https://files.pythonhosted.org/packages/38/31/3a76f67da4b0cf37b742ca76beaf819dca0ebef26d78fc794a576e08accf/tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", size = 258666 },
268
+ { url = "https://files.pythonhosted.org/packages/07/10/5af1293da642aded87e8a988753945d0cf7e00a9452d3911dd3bb354c9e2/tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", size = 243954 },
269
+ { url = "https://files.pythonhosted.org/packages/5b/b9/1ed31d167be802da0fc95020d04cd27b7d7065cc6fbefdd2f9186f60d7bd/tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", size = 98724 },
270
+ { url = "https://files.pythonhosted.org/packages/c7/32/b0963458706accd9afcfeb867c0f9175a741bf7b19cd424230714d722198/tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", size = 109383 },
271
+ { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257 },
272
+ ]
273
+
274
+ [[package]]
275
+ name = "typing-extensions"
276
+ version = "4.13.2"
277
+ source = { registry = "https://pypi.org/simple" }
278
+ sdist = { url = "https://files.pythonhosted.org/packages/f6/37/23083fcd6e35492953e8d2aaaa68b860eb422b34627b13f2ce3eb6106061/typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef", size = 106967 }
279
+ wheels = [
280
+ { url = "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c", size = 45806 },
281
+ ]
282
+
283
+ [[package]]
284
+ name = "wheel"
285
+ version = "0.45.1"
286
+ source = { registry = "https://pypi.org/simple" }
287
+ sdist = { url = "https://files.pythonhosted.org/packages/8a/98/2d9906746cdc6a6ef809ae6338005b3f21bb568bea3165cfc6a243fdc25c/wheel-0.45.1.tar.gz", hash = "sha256:661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729", size = 107545 }
288
+ wheels = [
289
+ { url = "https://files.pythonhosted.org/packages/0b/2c/87f3254fd8ffd29e4c02732eee68a83a1d3c346ae39bc6822dcbcb697f2b/wheel-0.45.1-py3-none-any.whl", hash = "sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248", size = 72494 },
290
+ ]
@@ -1,12 +0,0 @@
1
- pytest:
2
- maturin develop
3
- .venv/bin/pytest
4
-
5
- test: pytest
6
- cargo test
7
-
8
- venv:
9
- rm -rf .venv
10
- python3 -m venv .venv
11
- . .venv/bin/activate
12
- .venv/bin/pip install wheel pytest maturin
File without changes