From 93f2856eeafac4928b82e63412dad30ee5f11f5e Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Fri, 5 Dec 2025 18:24:18 +0400 Subject: [PATCH 01/53] chore: Update release configuration and add GitHub Actions workflows for publishing - Modified `.releaserc.json` to define separate branches for stable and release candidate versions. - Added new GitHub Actions workflows: `publish-stable.yaml` for publishing stable releases to PyPI, `publish.yaml` for publishing release candidates to Test PyPI, and `release-stable.yaml` for automating the release process on the `release` branch. Signed-off-by: Dmitrii Safronov --- .github/workflows/publish-stable.yaml | 33 ++++++++++++++++++++++++++ .github/workflows/publish.yaml | 34 +++++++++++++++++++++++++++ .github/workflows/release-stable.yaml | 34 +++++++++++++++++++++++++++ .releaserc.json | 11 ++++++++- 4 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/publish-stable.yaml create mode 100644 .github/workflows/publish.yaml create mode 100644 .github/workflows/release-stable.yaml diff --git a/.github/workflows/publish-stable.yaml b/.github/workflows/publish-stable.yaml new file mode 100644 index 0000000..9ce902f --- /dev/null +++ b/.github/workflows/publish-stable.yaml @@ -0,0 +1,33 @@ +--- +name: Publish to PyPI (stable) + +"on": + push: + tags: + # Publish final release tags (without -rc suffix). + - "v[0-9]+.[0-9]+.[0-9]+" + workflow_dispatch: + +jobs: + publish: + name: "Publish to PyPI" + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Install uv + uses: astral-sh/setup-uv@v3 + with: + enable-cache: true + + - name: Build package + run: uv build + + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + packages-dir: dist/ diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml new file mode 100644 index 0000000..9498047 --- /dev/null +++ b/.github/workflows/publish.yaml @@ -0,0 +1,34 @@ +--- +name: Publish Release Candidate to Test PyPI + +"on": + push: + tags: + # Publish release candidate tags. + - 'v[0-9]+.[0-9]+.[0-9]+-rc\.[0-9]+' + workflow_dispatch: + +jobs: + publish-rc: + name: "Publish RC to Test PyPI" + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Install uv + uses: astral-sh/setup-uv@v3 + with: + enable-cache: true + + - name: Build package + run: uv build + + - name: Publish to Test PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + packages-dir: dist/ + repository-url: https://test.pypi.org/legacy/ diff --git a/.github/workflows/release-stable.yaml b/.github/workflows/release-stable.yaml new file mode 100644 index 0000000..ef6fd81 --- /dev/null +++ b/.github/workflows/release-stable.yaml @@ -0,0 +1,34 @@ +--- +name: Release (stable) + +"on": + push: + branches: + - release + +jobs: + release: + name: "Release" + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + concurrency: + group: semantic-release + cancel-in-progress: false + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + fetch-depth: 0 + token: ${{ secrets.SEMANTIC_RELEASE_TOKEN || secrets.GITHUB_TOKEN }} + + - name: Semantic release + run: | + docker run --rm \ + --user 1001 \ + -v ${{ github.workspace }}:/workspace \ + -w /workspace \ + -e GITHUB_TOKEN=${{ secrets.SEMANTIC_RELEASE_TOKEN || secrets.GITHUB_TOKEN }} \ + -e CI=true \ + ghcr.io/disafronov/semantic-release:latest diff --git a/.releaserc.json b/.releaserc.json index 677db12..7678cee 100644 --- a/.releaserc.json +++ b/.releaserc.json @@ -1,5 +1,14 @@ { - "branches": ["main"], + "branches": [ + { + "name": "release", + "prerelease": false + }, + { + "name": "main", + "prerelease": "rc" + } + ], "plugins": [ ["@semantic-release/commit-analyzer", { "preset": "conventionalcommits", From 34f9ec64691ce4a2fa77c71e0bb8fcb649690cc0 Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Fri, 5 Dec 2025 18:34:40 +0400 Subject: [PATCH 02/53] ci: Correct regex for release candidate tags in GitHub Actions workflow - Updated the regex pattern in `.github/workflows/publish.yaml` to remove the escape character before the dot in the release candidate tag format, ensuring proper tag matching for release candidates. --- .github/workflows/publish.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 9498047..030403b 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -5,7 +5,7 @@ name: Publish Release Candidate to Test PyPI push: tags: # Publish release candidate tags. - - 'v[0-9]+.[0-9]+.[0-9]+-rc\.[0-9]+' + - 'v[0-9]+.[0-9]+.[0-9]+-rc.[0-9]+' workflow_dispatch: jobs: From c632d8338b68e68fc413efc8e414532bfdd53db8 Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Fri, 5 Dec 2025 18:40:48 +0400 Subject: [PATCH 03/53] chore: Refine release configuration for semantic release - Updated the `.releaserc.json` file to improve the versioning command for release candidates by modifying the regex pattern. - Ensured the configuration maintains compatibility with the existing plugins for commit analysis, release notes generation, and GitHub integration. Signed-off-by: Dmitrii Safronov --- .releaserc.json | 50 ++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/.releaserc.json b/.releaserc.json index 7678cee..910b535 100644 --- a/.releaserc.json +++ b/.releaserc.json @@ -10,30 +10,30 @@ } ], "plugins": [ - ["@semantic-release/commit-analyzer", { - "preset": "conventionalcommits", - "releaseRules": [ - { "type": "feat", "release": "minor" }, - { "type": "fix", "release": "patch" }, - { "type": "perf", "release": "patch" }, - { "type": "revert", "release": "patch" }, - { "type": "refactor", "release": "patch" }, - { "type": "docs", "release": false }, - { "type": "style", "release": false }, - { "type": "test", "release": false }, - { "type": "build", "release": false }, - { "type": "ci", "release": false }, - { "type": "chore", "release": false } - ] - }], - ["@semantic-release/release-notes-generator", { "preset": "conventionalcommits" }], - ["@semantic-release/exec", { - "prepareCmd": "node -e \"const fs=require('fs'),toml=require('@iarna/toml');const f='pyproject.toml';const data=toml.parse(fs.readFileSync(f,'utf8'));data.project.version='${nextRelease.version}';fs.writeFileSync(f,toml.stringify(data))\"" - }], - ["@semantic-release/git", { - "assets": ["pyproject.toml"], - "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" - }], - ["@semantic-release/github", {}] + ["@semantic-release/commit-analyzer", { + "preset": "conventionalcommits", + "releaseRules": [ + { "type": "feat", "release": "minor" }, + { "type": "fix", "release": "patch" }, + { "type": "perf", "release": "patch" }, + { "type": "revert", "release": "patch" }, + { "type": "refactor", "release": "patch" }, + { "type": "docs", "release": false }, + { "type": "style", "release": false }, + { "type": "test", "release": false }, + { "type": "build", "release": false }, + { "type": "ci", "release": false }, + { "type": "chore", "release": false } + ] + }], + ["@semantic-release/release-notes-generator", { "preset": "conventionalcommits" }], + ["@semantic-release/exec", { + "prepareCmd": "node -e \"const fs=require('fs'),toml=require('@iarna/toml');const f='pyproject.toml';const data=toml.parse(fs.readFileSync(f,'utf8'));let version='${nextRelease.version}';version=version.replace(/-rc\\./g,'rc');data.project.version=version;fs.writeFileSync(f,toml.stringify(data))\"" + }], + ["@semantic-release/git", { + "assets": ["pyproject.toml"], + "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" + }], + ["@semantic-release/github", {}] ] } From 1ddedd689f02b92eea54048f8286c91ddbf365c4 Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Fri, 5 Dec 2025 18:45:48 +0400 Subject: [PATCH 04/53] chore: Add version verification step in GitHub Actions workflows - Implemented a new step in both `publish-stable.yaml` and `publish.yaml` to verify that the version in the tag matches the version specified in `pyproject.toml`. - The verification process includes extracting the version from the tag and comparing it with the actual version from the project file, ensuring consistency before publishing. Signed-off-by: Dmitrii Safronov --- .github/workflows/publish-stable.yaml | 17 +++++++++++++++++ .github/workflows/publish.yaml | 17 +++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/.github/workflows/publish-stable.yaml b/.github/workflows/publish-stable.yaml index 9ce902f..86483ba 100644 --- a/.github/workflows/publish-stable.yaml +++ b/.github/workflows/publish-stable.yaml @@ -24,6 +24,23 @@ jobs: with: enable-cache: true + - name: Verify version matches tag + run: | + TAG_NAME="${GITHUB_REF#refs/tags/}" + # Remove 'v' prefix from tag (v1.2.3 -> 1.2.3) + EXPECTED_VERSION=$(echo "$TAG_NAME" | sed 's/^v//') + # Extract version from pyproject.toml using tomli (compatible with Python 3.7+) + uv pip install tomli + ACTUAL_VERSION=$(python3 -c "import tomli; f=open('pyproject.toml','rb'); data=tomli.load(f); print(data['project']['version'])") + if [ "$EXPECTED_VERSION" != "$ACTUAL_VERSION" ]; then + echo "Error: Version mismatch!" + echo "Tag: $TAG_NAME" + echo "Expected version in pyproject.toml: $EXPECTED_VERSION" + echo "Actual version in pyproject.toml: $ACTUAL_VERSION" + exit 1 + fi + echo "Version verification passed: $ACTUAL_VERSION" + - name: Build package run: uv build diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 030403b..d0e7b24 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -24,6 +24,23 @@ jobs: with: enable-cache: true + - name: Verify version matches tag + run: | + TAG_NAME="${GITHUB_REF#refs/tags/}" + # Convert SemVer tag format (v1.2.3-rc.1) to PEP 440 format (1.2.3rc1) + EXPECTED_VERSION=$(echo "$TAG_NAME" | sed 's/^v//' | sed 's/-rc\./rc/') + # Extract version from pyproject.toml using tomli (compatible with Python 3.7+) + uv pip install tomli + ACTUAL_VERSION=$(python3 -c "import tomli; f=open('pyproject.toml','rb'); data=tomli.load(f); print(data['project']['version'])") + if [ "$EXPECTED_VERSION" != "$ACTUAL_VERSION" ]; then + echo "Error: Version mismatch!" + echo "Tag: $TAG_NAME" + echo "Expected version in pyproject.toml: $EXPECTED_VERSION" + echo "Actual version in pyproject.toml: $ACTUAL_VERSION" + exit 1 + fi + echo "Version verification passed: $ACTUAL_VERSION" + - name: Build package run: uv build From 42a45bd6675f11f7b10ae8e10fc25bea386ba6a7 Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Fri, 5 Dec 2025 18:53:59 +0400 Subject: [PATCH 05/53] chore: Remove workflow_dispatch from GitHub Actions for publishing - Eliminated the `workflow_dispatch` trigger from both `publish-stable.yaml` and `publish.yaml` workflows to streamline the publishing process and ensure that releases are only triggered by tag events. Signed-off-by: Dmitrii Safronov --- .github/workflows/publish-stable.yaml | 1 - .github/workflows/publish.yaml | 1 - 2 files changed, 2 deletions(-) diff --git a/.github/workflows/publish-stable.yaml b/.github/workflows/publish-stable.yaml index 86483ba..1276cdc 100644 --- a/.github/workflows/publish-stable.yaml +++ b/.github/workflows/publish-stable.yaml @@ -6,7 +6,6 @@ name: Publish to PyPI (stable) tags: # Publish final release tags (without -rc suffix). - "v[0-9]+.[0-9]+.[0-9]+" - workflow_dispatch: jobs: publish: diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index d0e7b24..d70f7a2 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -6,7 +6,6 @@ name: Publish Release Candidate to Test PyPI tags: # Publish release candidate tags. - 'v[0-9]+.[0-9]+.[0-9]+-rc.[0-9]+' - workflow_dispatch: jobs: publish-rc: From dd295ead70c5e1825e49f02f11a12ff69fc24c01 Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Fri, 5 Dec 2025 18:55:33 +0400 Subject: [PATCH 06/53] chore: Simplify release branch configuration in .releaserc.json - Modified the `.releaserc.json` file to streamline the branch configuration by replacing the object definition for the `release` branch with a string. This change enhances clarity and reduces complexity in the release setup. Signed-off-by: Dmitrii Safronov --- .releaserc.json | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.releaserc.json b/.releaserc.json index 910b535..8694940 100644 --- a/.releaserc.json +++ b/.releaserc.json @@ -1,9 +1,6 @@ { "branches": [ - { - "name": "release", - "prerelease": false - }, + "release", { "name": "main", "prerelease": "rc" From 397f73b9933056a776eeafff2f35e4da58ff80c0 Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Fri, 5 Dec 2025 19:14:55 +0400 Subject: [PATCH 07/53] refactor: Enhance schema validation and nested value handling - Introduced new helper functions `_validate_list_value`, `_set_nested_value`, and `_validate_and_apply_leaf` to improve the validation of list values and the application of schema leaves. - Refactored `_apply_schema_internal` to utilize the new validation and application functions, streamlining the processing of schema leaves. - Added comprehensive unit tests for the new functions to ensure correct behavior and validation logic, including handling of type mismatches and nested structures. Signed-off-by: Dmitrii Safronov --- .../schema_applier.py | 174 ++++++++++----- tests/test_formatter.py | 203 ++++++++++++++++++ 2 files changed, 321 insertions(+), 56 deletions(-) diff --git a/src/logging_objects_with_schema/schema_applier.py b/src/logging_objects_with_schema/schema_applier.py index 6f7387d..c89b8fb 100644 --- a/src/logging_objects_with_schema/schema_applier.py +++ b/src/logging_objects_with_schema/schema_applier.py @@ -6,12 +6,126 @@ from __future__ import annotations +from collections import defaultdict from typing import Any, Dict, List, Mapping, MutableMapping, Tuple from .errors import DataProblem from .schema_loader import CompiledSchema, SchemaLeaf +def _validate_list_value( + value: list, + source: str, + item_expected_type: type | None, +) -> DataProblem | None: + """Validate that a list value matches the expected item type. + + Validates that all elements in the list have the exact type declared by + ``item_expected_type``. Empty lists are always considered valid. + + Args: + value: The list value to validate. + source: The source field name (for error messages). + item_expected_type: Expected type for list elements. Must not be None + for list-typed leaves. + + Returns: + DataProblem if validation fails, None if validation succeeds. + """ + if item_expected_type is None: + return DataProblem( + f"Field '{source}' is declared as list in schema but " + f"has no item type configured", + ) + + if len(value) == 0: + # Empty lists are always valid + return None + + invalid_item_types = { + type(item).__name__ for item in value if type(item) is not item_expected_type + } + + if invalid_item_types: + return DataProblem( + f"Field '{source}' is a list but contains elements " + f"with types {sorted(invalid_item_types)}; " + f"expected all elements to be of type " + f"{item_expected_type.__name__}", + ) + + return None + + +def _set_nested_value( + target: MutableMapping[str, Any], + path: Tuple[str, ...], + value: Any, +) -> None: + """Set a value in a nested dictionary structure following the given path. + + Creates intermediate dictionaries as needed. The last element of the path + is used as the final key for the value. + + Args: + target: The root dictionary to modify. + path: Tuple of keys representing the path to the target location. + value: The value to set at the target location. + """ + current = target + for key in path[:-1]: + child = current.get(key) + if not isinstance(child, dict): + child = {} + current[key] = child + current = child + + current[path[-1]] = value + + +def _validate_and_apply_leaf( + leaf: SchemaLeaf, + value: Any, + source: str, + extra: MutableMapping[str, Any], + problems: List[DataProblem], +) -> None: + """Validate a value against a schema leaf and apply it if valid. + + Performs strict type checking and list validation. If validation passes, + the value is written to the target location in the extra dictionary. + + Args: + leaf: The schema leaf to validate against. + value: The value to validate and apply. + source: The source field name (for error messages). + extra: The target dictionary to write the value to if validation passes. + problems: List to append validation problems to. + """ + # Use strict type checking (type() is) instead of isinstance() to + # prevent bool values from passing validation for int types (since + # bool is a subclass of int). This ensures that the actual + # runtime type matches the schema type exactly. + if type(value) is not leaf.expected_type: + problems.append( + DataProblem( + f"Field '{source}' has type {type(value).__name__}, " + f"expected {leaf.expected_type.__name__}", + ), + ) + return + + # For lists, validate that all elements strictly match the declared + # item_expected_type (homogeneous primitive list). + if leaf.expected_type is list and isinstance(value, list): + list_problem = _validate_list_value(value, source, leaf.item_expected_type) + if list_problem is not None: + problems.append(list_problem) + return + + _set_nested_value(extra, leaf.path, value) + + def _strip_empty(node: Any) -> Any: """Remove empty dictionaries and None values from a nested structure. @@ -95,9 +209,10 @@ def _apply_schema_internal( used_sources = {leaf.source for leaf in compiled.leaves} - source_to_leaves: Dict[str, List[SchemaLeaf]] = {} + # Group leaves by source for efficient processing + source_to_leaves: Dict[str, List[SchemaLeaf]] = defaultdict(list) for leaf in compiled.leaves: - source_to_leaves.setdefault(leaf.source, []).append(leaf) + source_to_leaves[leaf.source].append(leaf) for source, leaves in source_to_leaves.items(): if source not in extra_values: @@ -116,60 +231,7 @@ def _apply_schema_internal( continue for leaf in leaves: - # Use strict type checking (type() is) instead of isinstance() to - # prevent bool values from passing validation for int types (since - # bool is a subclass of int). This ensures that the actual - # runtime type matches the schema type exactly. - if type(value) is not leaf.expected_type: - problems.append( - DataProblem( - f"Field '{source}' has type {type(value).__name__}, " - f"expected {leaf.expected_type.__name__}", - ), - ) - continue - - # For lists, validate that all elements strictly match the declared - # item_expected_type (homogeneous primitive list). - if leaf.expected_type is list and isinstance(value, list): - item_expected_type = leaf.item_expected_type - # item_expected_type should always be set for list leaves by the - # schema compiler, but we guard defensively. - if item_expected_type is None: - problems.append( - DataProblem( - f"Field '{source}' is declared as list in schema but " - f"has no item type configured", - ), - ) - continue - - if len(value) > 0: - invalid_item_types = { - type(item).__name__ - for item in value - if type(item) is not item_expected_type - } - if invalid_item_types: - problems.append( - DataProblem( - f"Field '{source}' is a list but contains elements " - f"with types {sorted(invalid_item_types)}; " - f"expected all elements to be of type " - f"{item_expected_type.__name__}", - ), - ) - continue - - target: MutableMapping[str, Any] = extra - for key in leaf.path[:-1]: - child = target.get(key) - if not isinstance(child, dict): - child = {} - target[key] = child - target = child - - target[leaf.path[-1]] = value + _validate_and_apply_leaf(leaf, value, source, extra, problems) # Report redundant fields for any keys not referenced by schema leaves. for key in extra_values.keys(): diff --git a/tests/test_formatter.py b/tests/test_formatter.py index 612e572..88ae29e 100644 --- a/tests/test_formatter.py +++ b/tests/test_formatter.py @@ -6,10 +6,20 @@ from __future__ import annotations +from logging_objects_with_schema.errors import DataProblem from logging_objects_with_schema.schema_applier import ( _apply_schema_internal as apply_schema_internal, ) +from logging_objects_with_schema.schema_applier import ( + _set_nested_value as set_nested_value, +) from logging_objects_with_schema.schema_applier import _strip_empty as strip_empty +from logging_objects_with_schema.schema_applier import ( + _validate_and_apply_leaf as validate_and_apply_leaf, +) +from logging_objects_with_schema.schema_applier import ( + _validate_list_value as validate_list_value, +) from logging_objects_with_schema.schema_loader import CompiledSchema, SchemaLeaf @@ -623,3 +633,196 @@ def test_apply_schema_strict_type_checking_for_all_primitives() -> None: assert result == {} assert len(problems) == 1 assert "expected int" in problems[0].message + + +# Tests for helper functions + + +def test_validate_list_value_empty_list_returns_none() -> None: + """validate_list_value should return None for empty lists.""" + result = validate_list_value([], "test_field", str) + assert result is None + + +def test_validate_list_value_valid_items_returns_none() -> None: + """validate_list_value should return None for lists with valid items.""" + result = validate_list_value(["a", "b", "c"], "test_field", str) + assert result is None + + result = validate_list_value([1, 2, 3], "test_field", int) + assert result is None + + result = validate_list_value([1.0, 2.5, 3.14], "test_field", float) + assert result is None + + result = validate_list_value([True, False], "test_field", bool) + assert result is None + + +def test_validate_list_value_mixed_types_returns_problem() -> None: + """validate_list_value should return DataProblem for mixed types.""" + result = validate_list_value([1, "two", 3], "test_field", int) + assert isinstance(result, DataProblem) + assert "test_field" in result.message + assert "str" in result.message + assert "expected all elements to be of type int" in result.message + + +def test_validate_list_value_none_item_type_returns_problem() -> None: + """validate_list_value should return DataProblem when item_expected_type is None.""" + result = validate_list_value([1, 2, 3], "test_field", None) + assert isinstance(result, DataProblem) + assert "test_field" in result.message + assert "no item type configured" in result.message + + +def test_validate_list_value_nested_list_returns_problem() -> None: + """validate_list_value should return DataProblem for nested lists.""" + result = validate_list_value([1, [2, 3], 4], "test_field", int) + assert isinstance(result, DataProblem) + assert "list" in result.message.lower() + + +def test_validate_list_value_dict_in_list_returns_problem() -> None: + """validate_list_value should return DataProblem for dicts in list.""" + result = validate_list_value([1, {"key": "value"}, 3], "test_field", int) + assert isinstance(result, DataProblem) + assert "dict" in result.message.lower() + + +def test_set_nested_value_single_level() -> None: + """set_nested_value should set value at single level.""" + target = {} + set_nested_value(target, ("key",), "value") + assert target == {"key": "value"} + + +def test_set_nested_value_two_levels() -> None: + """set_nested_value should create nested structure for two levels.""" + target = {} + set_nested_value(target, ("level1", "level2"), "value") + assert target == {"level1": {"level2": "value"}} + + +def test_set_nested_value_deeply_nested() -> None: + """set_nested_value should create deeply nested structure.""" + target = {} + set_nested_value(target, ("a", "b", "c", "d", "e"), "value") + assert target == {"a": {"b": {"c": {"d": {"e": "value"}}}}} + + +def test_set_nested_value_preserves_existing_structure() -> None: + """set_nested_value should preserve existing dictionary structure.""" + target = {"existing": {"key": "value"}} + set_nested_value(target, ("existing", "new_key"), "new_value") + assert target == {"existing": {"key": "value", "new_key": "new_value"}} + + +def test_set_nested_value_overwrites_existing_value() -> None: + """set_nested_value should overwrite existing value at path.""" + target = {"level1": {"level2": "old_value"}} + set_nested_value(target, ("level1", "level2"), "new_value") + assert target == {"level1": {"level2": "new_value"}} + + +def test_validate_and_apply_leaf_valid_value() -> None: + """validate_and_apply_leaf should apply valid value to target.""" + leaf = SchemaLeaf( + path=("ServicePayload", "RequestID"), + source="request_id", + expected_type=str, + ) + extra = {} + problems = [] + + validate_and_apply_leaf(leaf, "abc-123", "request_id", extra, problems) + + assert problems == [] + assert extra == {"ServicePayload": {"RequestID": "abc-123"}} + + +def test_validate_and_apply_leaf_type_mismatch() -> None: + """validate_and_apply_leaf should add problem for type mismatch.""" + leaf = SchemaLeaf( + path=("ServicePayload", "UserID"), + source="user_id", + expected_type=int, + ) + extra = {} + problems = [] + + validate_and_apply_leaf(leaf, "not-an-int", "user_id", extra, problems) + + assert len(problems) == 1 + assert "expected int" in problems[0].message + assert extra == {} + + +def test_validate_and_apply_leaf_valid_list() -> None: + """validate_and_apply_leaf should apply valid list value.""" + leaf = SchemaLeaf( + path=("ServicePayload", "Tags"), + source="tags", + expected_type=list, + item_expected_type=str, + ) + extra = {} + problems = [] + + validate_and_apply_leaf(leaf, ["tag1", "tag2"], "tags", extra, problems) + + assert problems == [] + assert extra == {"ServicePayload": {"Tags": ["tag1", "tag2"]}} + + +def test_validate_and_apply_leaf_invalid_list() -> None: + """validate_and_apply_leaf should add problem for invalid list.""" + leaf = SchemaLeaf( + path=("ServicePayload", "Values"), + source="values", + expected_type=list, + item_expected_type=int, + ) + extra = {} + problems = [] + + validate_and_apply_leaf(leaf, [1, "two", 3], "values", extra, problems) + + assert len(problems) == 1 + assert "is a list but contains elements" in problems[0].message + assert extra == {} + + +def test_validate_and_apply_leaf_empty_list() -> None: + """validate_and_apply_leaf should accept empty lists.""" + leaf = SchemaLeaf( + path=("ServicePayload", "Tags"), + source="tags", + expected_type=list, + item_expected_type=str, + ) + extra = {} + problems = [] + + validate_and_apply_leaf(leaf, [], "tags", extra, problems) + + assert problems == [] + assert extra == {"ServicePayload": {"Tags": []}} + + +def test_validate_and_apply_leaf_list_without_item_type() -> None: + """validate_and_apply_leaf should add problem when item_expected_type is None.""" + leaf = SchemaLeaf( + path=("ServicePayload", "Items"), + source="items", + expected_type=list, + item_expected_type=None, + ) + extra = {} + problems = [] + + validate_and_apply_leaf(leaf, [1, 2, 3], "items", extra, problems) + + assert len(problems) == 1 + assert "no item type configured" in problems[0].message + assert extra == {} From 790cb095c10222a8960e325707de2317e4c6d40a Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 5 Dec 2025 15:25:45 +0000 Subject: [PATCH 08/53] chore(release): 0.1.1-rc.1 [skip ci] ## [0.1.1-rc.1](https://github.com/disafronov/python-logging-objects-with-schema/compare/v0.1.0...v0.1.1-rc.1) (2025-12-05) --- pyproject.toml | 99 +++++++++++++++++++++++++------------------------- 1 file changed, 50 insertions(+), 49 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 60dad58..b756e83 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,54 +1,55 @@ [build-system] -requires = ["uv_build >= 0.9.11, <0.10.0"] +requires = [ "uv_build >= 0.9.11, <0.10.0" ] build-backend = "uv_build" [project] name = "logging-objects-with-schema" -version = "0.1.0" +version = "0.1.1rc1" description = "Proxy logging wrapper that validates extra fields against a JSON schema." readme = "README.md" requires-python = ">=3.10" -dependencies = [] +dependencies = [ ] license = "Apache-2.0" -license-files = ["LICENSE"] -authors = [ - { name = "Dmitrii Safronov", email = "dhameoelin+logging-objects-with-schema@gmail.com" }, -] +license-files = [ "LICENSE" ] keywords = [ - "logging", - "schema", - "validation", - "structured-logging", - "structured-logs", + "logging", + "schema", + "validation", + "structured-logging", + "structured-logs" ] classifiers = [ - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - "Programming Language :: Python :: 3.13", - "Programming Language :: Python :: 3.14", - "Programming Language :: Python :: 3 :: Only", - "Intended Audience :: Developers", - "Topic :: System :: Logging", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", + "Programming Language :: Python :: 3 :: Only", + "Intended Audience :: Developers", + "Topic :: System :: Logging" ] -[project.optional-dependencies] -dev = [ - "pytest>=7.0.0", - "pytest-cov>=4.0.0", - "black>=23.0.0", - "isort>=5.12.0", - "flake8>=6.0.0", - "flake8-pyproject>=1.2.3", - "mypy>=1.18.1", - "bandit>=1.8.6", - "pre-commit>=3.5.0", + [[project.authors]] + name = "Dmitrii Safronov" + email = "dhameoelin+logging-objects-with-schema@gmail.com" + + [project.optional-dependencies] + dev = [ + "pytest>=7.0.0", + "pytest-cov>=4.0.0", + "black>=23.0.0", + "isort>=5.12.0", + "flake8>=6.0.0", + "flake8-pyproject>=1.2.3", + "mypy>=1.18.1", + "bandit>=1.8.6", + "pre-commit>=3.5.0" ] -[project.urls] -Source = "https://github.com/disafronov/python-logging-objects-with-schema" -Issues = "https://github.com/disafronov/python-logging-objects-with-schema/issues" + [project.urls] + Source = "https://github.com/disafronov/python-logging-objects-with-schema" + Issues = "https://github.com/disafronov/python-logging-objects-with-schema/issues" [tool.isort] profile = "black" @@ -57,27 +58,27 @@ multi_line_output = 3 [tool.black] line-length = 88 -include = '\.pyi?$' -extend-exclude = ''' +include = "\\.pyi?$" +extend-exclude = """ /( - \.eggs - | \.git - | \.hg - | \.mypy_cache - | \.tox - | \.venv + \\.eggs + | \\.git + | \\.hg + | \\.mypy_cache + | \\.tox + | \\.venv | build | dist )/ -''' +""" [tool.flake8] max-line-length = 88 -extend-ignore = ["E203", "W503"] -exclude = [".venv", "__pycache__", ".git", "htmlcov"] +extend-ignore = [ "E203", "W503" ] +exclude = [ ".venv", "__pycache__", ".git", "htmlcov" ] [tool.mypy] -exclude = 'tests/' +exclude = "tests/" warn_return_any = true warn_unused_configs = true disallow_untyped_defs = true @@ -92,5 +93,5 @@ warn_unreachable = true strict_equality = true [tool.bandit] -skips = ["B101", "B601"] -exclude_dirs = [".venv", "__pycache__", ".git", "htmlcov"] +skips = [ "B101", "B601" ] +exclude_dirs = [ ".venv", "__pycache__", ".git", "htmlcov" ] From 3fc25e999bc4fd5821b03cf211be3712dd6a5f30 Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Fri, 5 Dec 2025 19:34:30 +0400 Subject: [PATCH 09/53] ci: Correct quote style for regex pattern in publish.yaml - Updated the regex pattern for release candidate tags in `.github/workflows/publish.yaml` to use double quotes for consistency with YAML standards. Signed-off-by: Dmitrii Safronov --- .github/workflows/publish.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index d70f7a2..ca4efd4 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -5,7 +5,7 @@ name: Publish Release Candidate to Test PyPI push: tags: # Publish release candidate tags. - - 'v[0-9]+.[0-9]+.[0-9]+-rc.[0-9]+' + - "v[0-9]+.[0-9]+.[0-9]+-rc.[0-9]+" jobs: publish-rc: From 97aecf4901e8ea6cc92c80222519d0197062246d Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Fri, 5 Dec 2025 19:39:31 +0400 Subject: [PATCH 10/53] ci: Add virtual environment creation step in GitHub Actions workflows - Introduced a new step to create a virtual environment in both `publish-stable.yaml` and `publish.yaml` workflows, ensuring a consistent environment for the publishing process. Signed-off-by: Dmitrii Safronov --- .github/workflows/publish-stable.yaml | 3 +++ .github/workflows/publish.yaml | 3 +++ 2 files changed, 6 insertions(+) diff --git a/.github/workflows/publish-stable.yaml b/.github/workflows/publish-stable.yaml index 1276cdc..91cd96d 100644 --- a/.github/workflows/publish-stable.yaml +++ b/.github/workflows/publish-stable.yaml @@ -23,6 +23,9 @@ jobs: with: enable-cache: true + - name: Create virtual environment + run: uv venv + - name: Verify version matches tag run: | TAG_NAME="${GITHUB_REF#refs/tags/}" diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index ca4efd4..f035b01 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -23,6 +23,9 @@ jobs: with: enable-cache: true + - name: Create virtual environment + run: uv venv + - name: Verify version matches tag run: | TAG_NAME="${GITHUB_REF#refs/tags/}" From e335c3bdc50ade2825d76b1d9b3fe9a732377bcb Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Fri, 5 Dec 2025 19:46:42 +0400 Subject: [PATCH 11/53] ci: Update version extraction command in GitHub Actions workflows - Modified the version extraction command in both `publish-stable.yaml` and `publish.yaml` to use `uv run python` instead of `python3`, ensuring compatibility with the virtual environment setup. Signed-off-by: Dmitrii Safronov --- .github/workflows/publish-stable.yaml | 2 +- .github/workflows/publish.yaml | 2 +- uv.lock | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/publish-stable.yaml b/.github/workflows/publish-stable.yaml index 91cd96d..0e7e5cd 100644 --- a/.github/workflows/publish-stable.yaml +++ b/.github/workflows/publish-stable.yaml @@ -33,7 +33,7 @@ jobs: EXPECTED_VERSION=$(echo "$TAG_NAME" | sed 's/^v//') # Extract version from pyproject.toml using tomli (compatible with Python 3.7+) uv pip install tomli - ACTUAL_VERSION=$(python3 -c "import tomli; f=open('pyproject.toml','rb'); data=tomli.load(f); print(data['project']['version'])") + ACTUAL_VERSION=$(uv run python -c "import tomli; f=open('pyproject.toml','rb'); data=tomli.load(f); print(data['project']['version'])") if [ "$EXPECTED_VERSION" != "$ACTUAL_VERSION" ]; then echo "Error: Version mismatch!" echo "Tag: $TAG_NAME" diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index f035b01..c463af4 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -33,7 +33,7 @@ jobs: EXPECTED_VERSION=$(echo "$TAG_NAME" | sed 's/^v//' | sed 's/-rc\./rc/') # Extract version from pyproject.toml using tomli (compatible with Python 3.7+) uv pip install tomli - ACTUAL_VERSION=$(python3 -c "import tomli; f=open('pyproject.toml','rb'); data=tomli.load(f); print(data['project']['version'])") + ACTUAL_VERSION=$(uv run python -c "import tomli; f=open('pyproject.toml','rb'); data=tomli.load(f); print(data['project']['version'])") if [ "$EXPECTED_VERSION" != "$ACTUAL_VERSION" ]; then echo "Error: Version mismatch!" echo "Tag: $TAG_NAME" diff --git a/uv.lock b/uv.lock index 88dc452..1a38563 100644 --- a/uv.lock +++ b/uv.lock @@ -348,7 +348,7 @@ wheels = [ [[package]] name = "logging-objects-with-schema" -version = "0.1.0" +version = "0.1.1rc1" source = { editable = "." } [package.optional-dependencies] From e9a354f8159c8534d4437842b2be37d71c336529 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Dec 2025 15:49:57 +0000 Subject: [PATCH 12/53] chore(deps): bump astral-sh/setup-uv from 3 to 7 Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 3 to 7. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/v3...v7) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/lint_and_test.yaml | 2 +- .github/workflows/publish-stable.yaml | 2 +- .github/workflows/publish.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/lint_and_test.yaml b/.github/workflows/lint_and_test.yaml index 9aade7b..08e0a6f 100644 --- a/.github/workflows/lint_and_test.yaml +++ b/.github/workflows/lint_and_test.yaml @@ -20,7 +20,7 @@ jobs: uses: actions/checkout@v6 - name: Install uv - uses: astral-sh/setup-uv@v3 + uses: astral-sh/setup-uv@v7 with: enable-cache: true cache-suffix: ${{ matrix.python-version }} diff --git a/.github/workflows/publish-stable.yaml b/.github/workflows/publish-stable.yaml index 0e7e5cd..ed7521d 100644 --- a/.github/workflows/publish-stable.yaml +++ b/.github/workflows/publish-stable.yaml @@ -19,7 +19,7 @@ jobs: uses: actions/checkout@v6 - name: Install uv - uses: astral-sh/setup-uv@v3 + uses: astral-sh/setup-uv@v7 with: enable-cache: true diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index c463af4..0b88c80 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -19,7 +19,7 @@ jobs: uses: actions/checkout@v6 - name: Install uv - uses: astral-sh/setup-uv@v3 + uses: astral-sh/setup-uv@v7 with: enable-cache: true From 02d21369c8ff2beaf52fae70d9fe498bccae5ca2 Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Fri, 5 Dec 2025 22:33:27 +0400 Subject: [PATCH 13/53] refactor: Update type hints for error classes in errors.py - Changed type hints from List to list for problems parameter in SchemaValidationError and DataValidationError classes to align with Python 3.9+ syntax. - This update enhances code clarity and maintains compatibility with modern Python type hinting standards. Signed-off-by: Dmitrii Safronov --- src/logging_objects_with_schema/errors.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/logging_objects_with_schema/errors.py b/src/logging_objects_with_schema/errors.py index 2922972..515e095 100644 --- a/src/logging_objects_with_schema/errors.py +++ b/src/logging_objects_with_schema/errors.py @@ -3,7 +3,6 @@ from __future__ import annotations from dataclasses import dataclass -from typing import List @dataclass @@ -40,10 +39,10 @@ class SchemaValidationError(Exception): """ def __init__( - self, message: str, problems: List[SchemaProblem] | None = None + self, message: str, problems: list[SchemaProblem] | None = None ) -> None: super().__init__(message) - self.problems: List[SchemaProblem] = problems or [] + self.problems: list[SchemaProblem] = problems or [] @dataclass @@ -80,6 +79,6 @@ class DataValidationError(Exception): ... # Note: valid fields were already logged before this exception """ - def __init__(self, message: str, problems: List[DataProblem] | None = None) -> None: + def __init__(self, message: str, problems: list[DataProblem] | None = None) -> None: super().__init__(message) - self.problems: List[DataProblem] = problems or [] + self.problems: list[DataProblem] = problems or [] From a8af09a6e28c45e5462630e603b9164e5a717ab3 Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Fri, 5 Dec 2025 22:40:10 +0400 Subject: [PATCH 14/53] refactor(schema_loader): add caching to get_builtin_logrecord_attributes Add functools.lru_cache decorator to avoid recreating LogRecord instance and performing introspection on every call. The result is constant at runtime, so caching provides a minor optimization. Signed-off-by: Dmitrii Safronov --- src/logging_objects_with_schema/schema_loader.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/logging_objects_with_schema/schema_loader.py b/src/logging_objects_with_schema/schema_loader.py index a4fcf52..db29b71 100644 --- a/src/logging_objects_with_schema/schema_loader.py +++ b/src/logging_objects_with_schema/schema_loader.py @@ -8,6 +8,7 @@ from __future__ import annotations +import functools import json import logging import os @@ -325,6 +326,7 @@ def _compile_schema_tree( yield child_leaf +@functools.lru_cache(maxsize=1) def get_builtin_logrecord_attributes() -> set[str]: """Get set of standard LogRecord attribute names. From 10fc5c3e0742b4c24d2b08764ec5d96ea1cf507f Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Fri, 5 Dec 2025 22:40:51 +0400 Subject: [PATCH 15/53] refactor(schema_loader): extract path formatting into helper function Add _format_path() utility function to eliminate code duplication in schema validation error messages. Replace all occurrences of '.'.join(path + (key,)) and '.'.join(path) with calls to the new helper function. Signed-off-by: Dmitrii Safronov --- .../schema_loader.py | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/logging_objects_with_schema/schema_loader.py b/src/logging_objects_with_schema/schema_loader.py index db29b71..a6f76b8 100644 --- a/src/logging_objects_with_schema/schema_loader.py +++ b/src/logging_objects_with_schema/schema_loader.py @@ -209,6 +209,21 @@ def _load_raw_schema() -> Tuple[Dict[str, Any], Path]: return data, schema_path +def _format_path(path: tuple[str, ...], key: str | None = None) -> str: + """Format a schema path tuple into a dot-separated string. + + Args: + path: Tuple of keys representing the path in the schema tree. + key: Optional additional key to append to the path. + + Returns: + Dot-separated string representation of the path. + """ + if key is not None: + return ".".join(path + (key,)) + return ".".join(path) + + def _compile_schema_tree( node: MutableMapping[str, Any], path: Tuple[str, ...], @@ -229,7 +244,7 @@ def _compile_schema_tree( problems.append( SchemaProblem( f"Schema nesting depth exceeds maximum allowed depth of " - f"{MAX_SCHEMA_DEPTH} at path {'.'.join(path)}" + f"{MAX_SCHEMA_DEPTH} at path {_format_path(path)}" ), ) return @@ -238,7 +253,7 @@ def _compile_schema_tree( if not isinstance(value, Mapping): problems.append( SchemaProblem( - f"Invalid schema at {'.'.join(path + (key,))}: expected object" + f"Invalid schema at {_format_path(path, key)}: expected object" ), ) continue @@ -259,7 +274,7 @@ def _compile_schema_tree( if type_invalid: problems.append( SchemaProblem( - f"Incomplete leaf at {'.'.join(path + (key,))}: " + f"Incomplete leaf at {_format_path(path, key)}: " f"type cannot be None or empty", ), ) @@ -267,7 +282,7 @@ def _compile_schema_tree( if source_invalid: problems.append( SchemaProblem( - f"Incomplete leaf at {'.'.join(path + (key,))}: " + f"Incomplete leaf at {_format_path(path, key)}: " f"source cannot be None or empty", ), ) @@ -279,7 +294,7 @@ def _compile_schema_tree( if expected_type is None: problems.append( SchemaProblem( - f"Unknown type '{leaf_type}' at {'.'.join(path + (key,))}", + f"Unknown type '{leaf_type}' at {_format_path(path, key)}", ), ) continue @@ -295,7 +310,7 @@ def _compile_schema_tree( if item_type_invalid: problems.append( SchemaProblem( - f"Incomplete leaf at {'.'.join(path + (key,))}: " + f"Incomplete leaf at {_format_path(path, key)}: " f"item_type is required for list type and " f"cannot be None or empty", ), @@ -308,7 +323,7 @@ def _compile_schema_tree( problems.append( SchemaProblem( f"Invalid item_type '{item_type_name}' at " - f"{'.'.join(path + (key,))}: only primitive item types " + f"{_format_path(path, key)}: only primitive item types " f"('str', 'int', 'float', 'bool') are allowed for lists", ), ) From a6533b08fe7efcfe8a111e3c939cbe9d34bec14d Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Fri, 5 Dec 2025 23:00:46 +0400 Subject: [PATCH 16/53] refactor(schema_loader): introduce _is_empty_or_none helper function Add a new utility function, _is_empty_or_none, to check if a value is None or an empty string. This function is utilized in the schema validation process to simplify the validation logic for leaf types and sources, enhancing code readability and maintainability. Signed-off-by: Dmitrii Safronov --- .../schema_loader.py | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/logging_objects_with_schema/schema_loader.py b/src/logging_objects_with_schema/schema_loader.py index a6f76b8..e99a7c0 100644 --- a/src/logging_objects_with_schema/schema_loader.py +++ b/src/logging_objects_with_schema/schema_loader.py @@ -224,6 +224,18 @@ def _format_path(path: tuple[str, ...], key: str | None = None) -> str: return ".".join(path) +def _is_empty_or_none(value: Any) -> bool: + """Check if a value is None or an empty string. + + Args: + value: The value to check. + + Returns: + True if value is None or an empty/whitespace-only string, False otherwise. + """ + return value is None or (isinstance(value, str) and value.strip() == "") + + def _compile_schema_tree( node: MutableMapping[str, Any], path: Tuple[str, ...], @@ -264,12 +276,8 @@ def _compile_schema_tree( if leaf_type is not None or leaf_source is not None: # This is supposed to be a leaf - validate required fields first. - type_invalid = leaf_type is None or ( - isinstance(leaf_type, str) and leaf_type.strip() == "" - ) - source_invalid = leaf_source is None or ( - isinstance(leaf_source, str) and leaf_source.strip() == "" - ) + type_invalid = _is_empty_or_none(leaf_type) + source_invalid = _is_empty_or_none(leaf_source) if type_invalid: problems.append( @@ -304,9 +312,7 @@ def _compile_schema_tree( # to ensure element homogeneity (e.g. list[str], list[int]). if expected_type is list: item_type_name = value_dict.get("item_type") - item_type_invalid = item_type_name is None or ( - isinstance(item_type_name, str) and item_type_name.strip() == "" - ) + item_type_invalid = _is_empty_or_none(item_type_name) if item_type_invalid: problems.append( SchemaProblem( From f52dd783f7adc8b9c3ca37d334aa5f2382ec0923 Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Fri, 5 Dec 2025 23:10:28 +0400 Subject: [PATCH 17/53] refactor(schema_applier): update type hints to Python 3.9+ syntax - Changed type hints from List to list and Tuple to tuple in schema_applier.py to align with modern Python type hinting standards. - This update enhances code clarity and maintains compatibility with Python 3.9 and later. Signed-off-by: Dmitrii Safronov --- .../schema_applier.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/logging_objects_with_schema/schema_applier.py b/src/logging_objects_with_schema/schema_applier.py index c89b8fb..7a76114 100644 --- a/src/logging_objects_with_schema/schema_applier.py +++ b/src/logging_objects_with_schema/schema_applier.py @@ -7,7 +7,7 @@ from __future__ import annotations from collections import defaultdict -from typing import Any, Dict, List, Mapping, MutableMapping, Tuple +from typing import Any, Mapping, MutableMapping from .errors import DataProblem from .schema_loader import CompiledSchema, SchemaLeaf @@ -59,7 +59,7 @@ def _validate_list_value( def _set_nested_value( target: MutableMapping[str, Any], - path: Tuple[str, ...], + path: tuple[str, ...], value: Any, ) -> None: """Set a value in a nested dictionary structure following the given path. @@ -88,7 +88,7 @@ def _validate_and_apply_leaf( value: Any, source: str, extra: MutableMapping[str, Any], - problems: List[DataProblem], + problems: list[DataProblem], ) -> None: """Validate a value against a schema leaf and apply it if valid. @@ -156,7 +156,7 @@ def _strip_empty(node: Any) -> Any: def _apply_schema_internal( compiled: CompiledSchema, extra_values: Mapping[str, Any], -) -> Tuple[Dict[str, Any], List[DataProblem]]: +) -> tuple[dict[str, Any], list[DataProblem]]: """Internal function to build structured ``extra`` from compiled schema. The function applies a :class:`CompiledSchema` to user-provided ``extra`` @@ -202,15 +202,15 @@ def _apply_schema_internal( change between releases without preserving backward compatibility. Returns: - Tuple of (structured_extra, List[DataProblem]). + Tuple of (structured_extra, list[DataProblem]). """ - extra: Dict[str, Any] = {} - problems: List[DataProblem] = [] + extra: dict[str, Any] = {} + problems: list[DataProblem] = [] used_sources = {leaf.source for leaf in compiled.leaves} # Group leaves by source for efficient processing - source_to_leaves: Dict[str, List[SchemaLeaf]] = defaultdict(list) + source_to_leaves: dict[str, list[SchemaLeaf]] = defaultdict(list) for leaf in compiled.leaves: source_to_leaves[leaf.source].append(leaf) From 80ae0cb6e7d6dbbc57baa19c55130e3042eb8b0b Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Fri, 5 Dec 2025 23:26:31 +0400 Subject: [PATCH 18/53] refactor(schema_loader): update type hints to Python 3.9+ syntax - Changed type hints from List and Tuple to list and tuple in schema_loader.py to align with modern Python type hinting standards. - This update enhances code clarity and maintains compatibility with Python 3.9 and later. Signed-off-by: Dmitrii Safronov --- .../schema_loader.py | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/logging_objects_with_schema/schema_loader.py b/src/logging_objects_with_schema/schema_loader.py index e99a7c0..ccdc3de 100644 --- a/src/logging_objects_with_schema/schema_loader.py +++ b/src/logging_objects_with_schema/schema_loader.py @@ -15,7 +15,7 @@ import threading from dataclasses import dataclass from pathlib import Path -from typing import Any, Dict, Iterable, List, Mapping, MutableMapping, Tuple +from typing import Any, Iterable, Mapping, MutableMapping from .errors import SchemaProblem @@ -37,7 +37,7 @@ class SchemaLeaf: ``expected_type`` is ``list``. For non-list leaves this is ``None``. """ - path: Tuple[str, ...] + path: tuple[str, ...] source: str expected_type: type item_expected_type: type | None = None @@ -47,7 +47,7 @@ class SchemaLeaf: class CompiledSchema: """Internal representation of a compiled schema.""" - leaves: List[SchemaLeaf] + leaves: list[SchemaLeaf] @property def is_empty(self) -> bool: @@ -65,10 +65,10 @@ def is_empty(self) -> bool: } # Module-level cache for compiled schemas. -# Key: absolute schema_path, Value: (CompiledSchema, List[SchemaProblem]) +# Key: absolute schema_path, Value: (CompiledSchema, list[SchemaProblem]) # This cache is thread-safe: all read and write operations are protected by # _cache_lock. -_SCHEMA_CACHE: Dict[Path, Tuple[CompiledSchema, List[SchemaProblem]]] = {} +_SCHEMA_CACHE: dict[Path, tuple[CompiledSchema, list[SchemaProblem]]] = {} _cache_lock = threading.RLock() @@ -169,7 +169,7 @@ def _get_schema_path() -> Path: return schema_path -def _load_raw_schema() -> Tuple[Dict[str, Any], Path]: +def _load_raw_schema() -> tuple[dict[str, Any], Path]: """Load raw JSON schema from the application root. This function always attempts to read the schema file and records @@ -238,8 +238,8 @@ def _is_empty_or_none(value: Any) -> bool: def _compile_schema_tree( node: MutableMapping[str, Any], - path: Tuple[str, ...], - problems: List[SchemaProblem], + path: tuple[str, ...], + problems: list[SchemaProblem], ) -> Iterable[SchemaLeaf]: """Recursively compile a schema node into SchemaLeaf objects. @@ -399,7 +399,7 @@ def get_builtin_logrecord_attributes() -> set[str]: def _check_root_conflicts( - schema_dict: Mapping[str, Any], problems: List[SchemaProblem] + schema_dict: Mapping[str, Any], problems: list[SchemaProblem] ) -> None: """Check schema root keys for conflicts with reserved logging fields.""" @@ -414,7 +414,7 @@ def _check_root_conflicts( ) -def _compile_schema_internal() -> Tuple[CompiledSchema, List[SchemaProblem]]: +def _compile_schema_internal() -> tuple[CompiledSchema, list[SchemaProblem]]: """Compile JSON schema into ``CompiledSchema`` and collect all problems. The function loads the raw JSON schema, validates its structure, checks @@ -424,7 +424,7 @@ def _compile_schema_internal() -> Tuple[CompiledSchema, List[SchemaProblem]]: instances. Results are cached process-wide: the cache key is the absolute schema - file path and the value is a tuple ``(CompiledSchema, List[SchemaProblem])``. + file path and the value is a tuple ``(CompiledSchema, list[SchemaProblem])``. Once a schema for a given path has been observed (including the cases when it is missing or invalid), subsequent calls always return the cached result without re-reading or re-compiling the schema. To pick up on-disk changes @@ -442,7 +442,7 @@ def _compile_schema_internal() -> Tuple[CompiledSchema, List[SchemaProblem]]: between releases without preserving backward compatibility. Returns: - Tuple of (CompiledSchema, List[SchemaProblem]). + Tuple of (CompiledSchema, list[SchemaProblem]). """ schema_path = _get_schema_path().resolve() @@ -453,7 +453,7 @@ def _compile_schema_internal() -> Tuple[CompiledSchema, List[SchemaProblem]]: if cached is not None: return cached - problems: List[SchemaProblem] = [] + problems: list[SchemaProblem] = [] try: raw_schema, loaded_path = _load_raw_schema() @@ -472,7 +472,7 @@ def _compile_schema_internal() -> Tuple[CompiledSchema, List[SchemaProblem]]: _check_root_conflicts(raw_schema, problems) - leaves: List[SchemaLeaf] = [] + leaves: list[SchemaLeaf] = [] for key, value in raw_schema.items(): if not isinstance(value, Mapping): problems.append( From d4d08c70819ab5cc81011a7a443e52140aa37056 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 5 Dec 2025 19:28:18 +0000 Subject: [PATCH 19/53] chore(release): 0.1.1-rc.2 [skip ci] ## [0.1.1-rc.2](https://github.com/disafronov/python-logging-objects-with-schema/compare/v0.1.1-rc.1...v0.1.1-rc.2) (2025-12-05) --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index b756e83..a5198f6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "uv_build" [project] name = "logging-objects-with-schema" -version = "0.1.1rc1" +version = "0.1.1rc2" description = "Proxy logging wrapper that validates extra fields against a JSON schema." readme = "README.md" requires-python = ">=3.10" From 6cb5ec02fecafbca5e1566faa6ea549fdfca8953 Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Fri, 5 Dec 2025 23:34:44 +0400 Subject: [PATCH 20/53] refactor(schema_loader): introduce _validate_and_create_leaf function - Added a new function, _validate_and_create_leaf, to encapsulate the validation logic for leaf nodes in the schema. This refactor improves code organization and readability by centralizing the validation process, reducing duplication, and enhancing maintainability. Signed-off-by: Dmitrii Safronov --- .../schema_loader.py | 157 ++++++++++-------- 1 file changed, 91 insertions(+), 66 deletions(-) diff --git a/src/logging_objects_with_schema/schema_loader.py b/src/logging_objects_with_schema/schema_loader.py index ccdc3de..23d1951 100644 --- a/src/logging_objects_with_schema/schema_loader.py +++ b/src/logging_objects_with_schema/schema_loader.py @@ -236,6 +236,94 @@ def _is_empty_or_none(value: Any) -> bool: return value is None or (isinstance(value, str) and value.strip() == "") +def _validate_and_create_leaf( + value_dict: dict[str, Any], + path: tuple[str, ...], + key: str, + problems: list[SchemaProblem], +) -> SchemaLeaf | None: + """Validate a leaf node and create SchemaLeaf if valid. + + Args: + value_dict: Dictionary containing leaf node data. + path: Current path in the schema tree. + key: Current key being processed. + problems: List to collect validation problems. + + Returns: + SchemaLeaf if validation passes, None otherwise. + """ + leaf_type = value_dict.get("type") + leaf_source = value_dict.get("source") + + # This is supposed to be a leaf - validate required fields first. + type_invalid = _is_empty_or_none(leaf_type) + source_invalid = _is_empty_or_none(leaf_source) + + if type_invalid: + problems.append( + SchemaProblem( + f"Incomplete leaf at {_format_path(path, key)}: " + f"type cannot be None or empty", + ), + ) + + if source_invalid: + problems.append( + SchemaProblem( + f"Incomplete leaf at {_format_path(path, key)}: " + f"source cannot be None or empty", + ), + ) + + if type_invalid or source_invalid: + return None + + expected_type = _TYPE_MAP.get(str(leaf_type)) + if expected_type is None: + problems.append( + SchemaProblem( + f"Unknown type '{leaf_type}' at {_format_path(path, key)}", + ), + ) + return None + + item_expected_type: type | None = None + # For list-typed leaves we require an explicit, primitive item_type + # to ensure element homogeneity (e.g. list[str], list[int]). + if expected_type is list: + item_type_name = value_dict.get("item_type") + item_type_invalid = _is_empty_or_none(item_type_name) + if item_type_invalid: + problems.append( + SchemaProblem( + f"Incomplete leaf at {_format_path(path, key)}: " + f"item_type is required for list type and " + f"cannot be None or empty", + ), + ) + return None + + item_expected_type = _TYPE_MAP.get(str(item_type_name)) + # Item type must be a primitive (str, int, float, bool), not list + if item_expected_type is None or item_expected_type is list: + problems.append( + SchemaProblem( + f"Invalid item_type '{item_type_name}' at " + f"{_format_path(path, key)}: only primitive item types " + f"('str', 'int', 'float', 'bool') are allowed for lists", + ), + ) + return None + + return SchemaLeaf( + path=path + (key,), + source=str(leaf_source), + expected_type=expected_type, + item_expected_type=item_expected_type, + ) + + def _compile_schema_tree( node: MutableMapping[str, Any], path: tuple[str, ...], @@ -275,72 +363,9 @@ def _compile_schema_tree( leaf_source = value_dict.get("source") if leaf_type is not None or leaf_source is not None: - # This is supposed to be a leaf - validate required fields first. - type_invalid = _is_empty_or_none(leaf_type) - source_invalid = _is_empty_or_none(leaf_source) - - if type_invalid: - problems.append( - SchemaProblem( - f"Incomplete leaf at {_format_path(path, key)}: " - f"type cannot be None or empty", - ), - ) - - if source_invalid: - problems.append( - SchemaProblem( - f"Incomplete leaf at {_format_path(path, key)}: " - f"source cannot be None or empty", - ), - ) - - if type_invalid or source_invalid: - continue - - expected_type = _TYPE_MAP.get(str(leaf_type)) - if expected_type is None: - problems.append( - SchemaProblem( - f"Unknown type '{leaf_type}' at {_format_path(path, key)}", - ), - ) - continue - - item_expected_type: type | None = None - # For list-typed leaves we require an explicit, primitive item_type - # to ensure element homogeneity (e.g. list[str], list[int]). - if expected_type is list: - item_type_name = value_dict.get("item_type") - item_type_invalid = _is_empty_or_none(item_type_name) - if item_type_invalid: - problems.append( - SchemaProblem( - f"Incomplete leaf at {_format_path(path, key)}: " - f"item_type is required for list type and " - f"cannot be None or empty", - ), - ) - continue - - item_expected_type = _TYPE_MAP.get(str(item_type_name)) - # Item type must be a primitive (str, int, float, bool), not list - if item_expected_type is None or item_expected_type is list: - problems.append( - SchemaProblem( - f"Invalid item_type '{item_type_name}' at " - f"{_format_path(path, key)}: only primitive item types " - f"('str', 'int', 'float', 'bool') are allowed for lists", - ), - ) - continue - - yield SchemaLeaf( - path=path + (key,), - source=str(leaf_source), - expected_type=expected_type, - item_expected_type=item_expected_type, - ) + leaf = _validate_and_create_leaf(value_dict, path, key, problems) + if leaf is not None: + yield leaf else: # This is an inner node; recurse into children. for child_leaf in _compile_schema_tree(value_dict, path + (key,), problems): From 140278006a405b8d3958a6e9be0091ecdcfb1511 Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Fri, 5 Dec 2025 23:38:15 +0400 Subject: [PATCH 21/53] test(schema_loader): add unit tests for schema validation functions - Introduced new unit tests for the _format_path, _is_empty_or_none, and _validate_and_create_leaf functions to ensure correct behavior across various scenarios. - Tests cover formatting paths with and without keys, checking for empty or None values, and validating leaf creation for different types and conditions. - This addition enhances test coverage and helps maintain the reliability of the schema validation logic. Signed-off-by: Dmitrii Safronov --- tests/test_schema_loader.py | 257 ++++++++++++++++++++++++++++++++++++ 1 file changed, 257 insertions(+) diff --git a/tests/test_schema_loader.py b/tests/test_schema_loader.py index f3d3232..4d80e39 100644 --- a/tests/test_schema_loader.py +++ b/tests/test_schema_loader.py @@ -10,13 +10,22 @@ import pytest +from logging_objects_with_schema.errors import SchemaProblem from logging_objects_with_schema.schema_loader import ( SCHEMA_FILE_NAME, CompiledSchema, + SchemaLeaf, ) from logging_objects_with_schema.schema_loader import ( _compile_schema_internal as compile_schema_internal, ) +from logging_objects_with_schema.schema_loader import _format_path as format_path +from logging_objects_with_schema.schema_loader import ( + _is_empty_or_none as is_empty_or_none, +) +from logging_objects_with_schema.schema_loader import ( + _validate_and_create_leaf as validate_and_create_leaf, +) from tests.conftest import _write_schema @@ -521,3 +530,251 @@ def test_invalid_schema_result_is_cached_within_same_process( assert isinstance(compiled2, CompiledSchema) assert compiled2.is_empty assert problems2 + + +def test_format_path_without_key() -> None: + """_format_path should format path tuple without key.""" + assert format_path(("Level1", "Level2")) == "Level1.Level2" + assert format_path(("ServicePayload",)) == "ServicePayload" + assert format_path(()) == "" + + +def test_format_path_with_key() -> None: + """_format_path should format path tuple with additional key.""" + assert format_path(("Level1", "Level2"), "Level3") == "Level1.Level2.Level3" + assert format_path(("ServicePayload",), "RequestID") == "ServicePayload.RequestID" + assert format_path((), "Root") == "Root" + + +def test_is_empty_or_none_with_none() -> None: + """_is_empty_or_none should return True for None.""" + assert is_empty_or_none(None) is True + + +def test_is_empty_or_none_with_empty_string() -> None: + """_is_empty_or_none should return True for empty string.""" + assert is_empty_or_none("") is True + + +def test_is_empty_or_none_with_whitespace_only_string() -> None: + """_is_empty_or_none should return True for whitespace-only strings.""" + assert is_empty_or_none(" ") is True + assert is_empty_or_none("\t\n") is True + assert is_empty_or_none(" \t \n ") is True + + +def test_is_empty_or_none_with_valid_string() -> None: + """_is_empty_or_none should return False for non-empty strings.""" + assert is_empty_or_none("valid") is False + assert is_empty_or_none(" valid ") is False + assert is_empty_or_none("str") is False + + +def test_is_empty_or_none_with_non_string_types() -> None: + """_is_empty_or_none should return False for non-string, non-None types.""" + assert is_empty_or_none(0) is False + assert is_empty_or_none(42) is False + assert is_empty_or_none([]) is False + assert is_empty_or_none({}) is False + assert is_empty_or_none(True) is False + + +def test_validate_and_create_leaf_valid_primitive() -> None: + """_validate_and_create_leaf should create SchemaLeaf for valid primitive type.""" + problems: list[SchemaProblem] = [] + value_dict = {"type": "str", "source": "request_id"} + + leaf = validate_and_create_leaf( + value_dict, ("ServicePayload",), "RequestID", problems + ) + + assert leaf is not None + assert isinstance(leaf, SchemaLeaf) + assert leaf.path == ("ServicePayload", "RequestID") + assert leaf.source == "request_id" + assert leaf.expected_type is str + assert leaf.item_expected_type is None + assert problems == [] + + +def test_validate_and_create_leaf_valid_list_type() -> None: + """_validate_and_create_leaf should create SchemaLeaf for valid list type.""" + problems: list[SchemaProblem] = [] + value_dict = {"type": "list", "source": "tags", "item_type": "str"} + + leaf = validate_and_create_leaf(value_dict, ("ServicePayload",), "Tags", problems) + + assert leaf is not None + assert isinstance(leaf, SchemaLeaf) + assert leaf.path == ("ServicePayload", "Tags") + assert leaf.source == "tags" + assert leaf.expected_type is list + assert leaf.item_expected_type is str + assert problems == [] + + +def test_validate_and_create_leaf_missing_type() -> None: + """_validate_and_create_leaf should return None and add problem for missing type.""" + problems: list[SchemaProblem] = [] + value_dict = {"source": "request_id"} + + leaf = validate_and_create_leaf( + value_dict, ("ServicePayload",), "RequestID", problems + ) + + assert leaf is None + assert len(problems) == 1 + assert "type cannot be None or empty" in problems[0].message + + +def test_validate_and_create_leaf_missing_source() -> None: + """_validate_and_create_leaf should return None for missing source.""" + problems: list[SchemaProblem] = [] + value_dict = {"type": "str"} + + leaf = validate_and_create_leaf( + value_dict, ("ServicePayload",), "RequestID", problems + ) + + assert leaf is None + assert len(problems) == 1 + assert "source cannot be None or empty" in problems[0].message + + +def test_validate_and_create_leaf_empty_type() -> None: + """_validate_and_create_leaf should return None for empty type string.""" + problems: list[SchemaProblem] = [] + value_dict = {"type": "", "source": "request_id"} + + leaf = validate_and_create_leaf( + value_dict, ("ServicePayload",), "RequestID", problems + ) + + assert leaf is None + assert len(problems) == 1 + assert "type cannot be None or empty" in problems[0].message + + +def test_validate_and_create_leaf_whitespace_type() -> None: + """_validate_and_create_leaf should return None for whitespace-only type string.""" + problems: list[SchemaProblem] = [] + value_dict = {"type": " ", "source": "request_id"} + + leaf = validate_and_create_leaf( + value_dict, ("ServicePayload",), "RequestID", problems + ) + + assert leaf is None + assert len(problems) == 1 + assert "type cannot be None or empty" in problems[0].message + + +def test_validate_and_create_leaf_empty_source() -> None: + """_validate_and_create_leaf should return None for empty source string.""" + problems: list[SchemaProblem] = [] + value_dict = {"type": "str", "source": ""} + + leaf = validate_and_create_leaf( + value_dict, ("ServicePayload",), "RequestID", problems + ) + + assert leaf is None + assert len(problems) == 1 + assert "source cannot be None or empty" in problems[0].message + + +def test_validate_and_create_leaf_whitespace_source() -> None: + """_validate_and_create_leaf should return None for whitespace source.""" + problems: list[SchemaProblem] = [] + value_dict = {"type": "str", "source": "\t\n"} + + leaf = validate_and_create_leaf( + value_dict, ("ServicePayload",), "RequestID", problems + ) + + assert leaf is None + assert len(problems) == 1 + assert "source cannot be None or empty" in problems[0].message + + +def test_validate_and_create_leaf_unknown_type() -> None: + """_validate_and_create_leaf should return None for unknown type.""" + problems: list[SchemaProblem] = [] + value_dict = {"type": "unknown_type", "source": "request_id"} + + leaf = validate_and_create_leaf( + value_dict, ("ServicePayload",), "RequestID", problems + ) + + assert leaf is None + assert len(problems) == 1 + assert "Unknown type" in problems[0].message + assert "unknown_type" in problems[0].message + + +def test_validate_and_create_leaf_list_missing_item_type() -> None: + """_validate_and_create_leaf should return None for list type without item_type.""" + problems: list[SchemaProblem] = [] + value_dict = {"type": "list", "source": "tags"} + + leaf = validate_and_create_leaf(value_dict, ("ServicePayload",), "Tags", problems) + + assert leaf is None + assert len(problems) == 1 + assert "item_type is required for list type" in problems[0].message + + +def test_validate_and_create_leaf_list_empty_item_type() -> None: + """_validate_and_create_leaf should return None for empty item_type.""" + problems: list[SchemaProblem] = [] + value_dict = {"type": "list", "source": "tags", "item_type": ""} + + leaf = validate_and_create_leaf(value_dict, ("ServicePayload",), "Tags", problems) + + assert leaf is None + assert len(problems) == 1 + assert "item_type is required for list type" in problems[0].message + + +def test_validate_and_create_leaf_list_invalid_item_type() -> None: + """_validate_and_create_leaf should return None for invalid item_type.""" + problems: list[SchemaProblem] = [] + value_dict = {"type": "list", "source": "tags", "item_type": "list"} + + leaf = validate_and_create_leaf(value_dict, ("ServicePayload",), "Tags", problems) + + assert leaf is None + assert len(problems) == 1 + assert "Invalid item_type" in problems[0].message + assert "only primitive item types" in problems[0].message + + +def test_validate_and_create_leaf_list_unknown_item_type() -> None: + """_validate_and_create_leaf should return None for unknown item_type.""" + problems: list[SchemaProblem] = [] + value_dict = {"type": "list", "source": "tags", "item_type": "unknown"} + + leaf = validate_and_create_leaf(value_dict, ("ServicePayload",), "Tags", problems) + + assert leaf is None + assert len(problems) == 1 + assert "Invalid item_type" in problems[0].message + + +def test_validate_and_create_leaf_all_primitive_types() -> None: + """_validate_and_create_leaf should work with all primitive types.""" + problems: list[SchemaProblem] = [] + + for type_name, expected_type in [ + ("str", str), + ("int", int), + ("float", float), + ("bool", bool), + ]: + value_dict = {"type": type_name, "source": f"{type_name}_value"} + leaf = validate_and_create_leaf(value_dict, ("Payload",), "Value", problems) + + assert leaf is not None + assert leaf.expected_type is expected_type + assert problems == [] + problems.clear() From e9265aee7fb24228100058e198671981db588e47 Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Fri, 5 Dec 2025 23:42:56 +0400 Subject: [PATCH 22/53] test(schema_loader): add tests for schema depth validation and path retrieval - Introduced new unit tests to validate schema depth constraints, ensuring that schemas exceeding MAX_SCHEMA_DEPTH produce appropriate problems, while those at the maximum depth compile correctly. - Added tests for the _get_schema_path function to verify its behavior when the cached file is deleted and when the current working directory changes, ensuring it correctly handles cache invalidation and retrieval. Signed-off-by: Dmitrii Safronov --- tests/test_schema_loader.py | 151 ++++++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) diff --git a/tests/test_schema_loader.py b/tests/test_schema_loader.py index 4d80e39..051aac8 100644 --- a/tests/test_schema_loader.py +++ b/tests/test_schema_loader.py @@ -12,6 +12,7 @@ from logging_objects_with_schema.errors import SchemaProblem from logging_objects_with_schema.schema_loader import ( + MAX_SCHEMA_DEPTH, SCHEMA_FILE_NAME, CompiledSchema, SchemaLeaf, @@ -20,6 +21,9 @@ _compile_schema_internal as compile_schema_internal, ) from logging_objects_with_schema.schema_loader import _format_path as format_path +from logging_objects_with_schema.schema_loader import ( + _get_schema_path as get_schema_path, +) from logging_objects_with_schema.schema_loader import ( _is_empty_or_none as is_empty_or_none, ) @@ -778,3 +782,150 @@ def test_validate_and_create_leaf_all_primitive_types() -> None: assert leaf.expected_type is expected_type assert problems == [] problems.clear() + + +def test_schema_exceeds_max_depth_produces_problem( + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, +) -> None: + """Schema exceeding MAX_SCHEMA_DEPTH should produce problem.""" + + monkeypatch.chdir(tmp_path) + + # Create a schema that exceeds MAX_SCHEMA_DEPTH (100 levels) + # We'll create a path with MAX_SCHEMA_DEPTH + 1 levels + schema = {} + current = schema + for i in range(MAX_SCHEMA_DEPTH + 1): + current[f"Level{i}"] = {} + current = current[f"Level{i}"] + + # Add a leaf at the deepest level + current["Value"] = {"type": "str", "source": "value"} + + _write_schema(tmp_path, schema) + + compiled, problems = compile_schema_internal() + + assert isinstance(compiled, CompiledSchema) + assert compiled.is_empty + assert any( + "exceeds maximum allowed depth" in p.message + and str(MAX_SCHEMA_DEPTH) in p.message + for p in problems + ) + + +def test_schema_at_max_depth_compiles_correctly( + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, +) -> None: + """Schema at exactly MAX_SCHEMA_DEPTH should compile correctly.""" + + monkeypatch.chdir(tmp_path) + + # Create a schema at exactly MAX_SCHEMA_DEPTH levels + schema = {} + current = schema + for i in range(MAX_SCHEMA_DEPTH): + current[f"Level{i}"] = {} + current = current[f"Level{i}"] + + # Add a leaf at the deepest level + current["Value"] = {"type": "str", "source": "value"} + + _write_schema(tmp_path, schema) + + compiled, problems = compile_schema_internal() + + assert isinstance(compiled, CompiledSchema) + assert not compiled.is_empty + assert len(compiled.leaves) == 1 + assert compiled.leaves[0].source == "value" + assert problems == [] + + +def test_get_schema_path_cached_file_deleted_re_searches( + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, +) -> None: + """_get_schema_path should re-search if cached file is deleted.""" + + monkeypatch.chdir(tmp_path) + + # Create schema file + _write_schema( + tmp_path, + {"ServicePayload": {"RequestID": {"type": "str", "source": "request_id"}}}, + ) + + # First call - should find and cache the file + path1 = get_schema_path() + assert path1.exists() + + # Delete the file + path1.unlink() + assert not path1.exists() + + # Second call - should re-search and return path in current directory + path2 = get_schema_path() + assert path2 == (tmp_path / SCHEMA_FILE_NAME).resolve() + assert not path2.exists() + + +def test_get_schema_path_cwd_change_invalidates_cache_when_file_not_found( + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, +) -> None: + """_get_schema_path should invalidate cache when CWD changes and file not found.""" + + # Create two directories + dir1 = tmp_path / "dir1" + dir2 = tmp_path / "dir2" + dir1.mkdir() + dir2.mkdir() + + # Start in dir1 (no schema file) + monkeypatch.chdir(dir1) + path1 = get_schema_path() + assert path1 == (dir1 / SCHEMA_FILE_NAME).resolve() + assert not path1.exists() + + # Change to dir2 (still no schema file, but different path expected) + monkeypatch.chdir(dir2) + path2 = get_schema_path() + assert path2 == (dir2 / SCHEMA_FILE_NAME).resolve() + assert path2 != path1 + + +def test_get_schema_path_cwd_change_preserves_cache_when_file_found( + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, +) -> None: + """_get_schema_path should preserve cache when CWD changes but file was found.""" + + # Create schema file in root + _write_schema( + tmp_path, + {"ServicePayload": {"RequestID": {"type": "str", "source": "request_id"}}}, + ) + + # Create subdirectory + sub_dir = tmp_path / "subdir" + sub_dir.mkdir() + + # Start in subdirectory - should find file in parent + monkeypatch.chdir(sub_dir) + path1 = get_schema_path() + assert path1.exists() + assert path1 == (tmp_path / SCHEMA_FILE_NAME).resolve() + + # Change to another subdirectory + sub_dir2 = tmp_path / "subdir2" + sub_dir2.mkdir() + monkeypatch.chdir(sub_dir2) + + # Should still return cached path (CWD-independent) + path2 = get_schema_path() + assert path2 == path1 + assert path2.exists() From 26eeecc36b3e7368cb43ac6782a0a6f5ae13bc49 Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Fri, 5 Dec 2025 23:48:29 +0400 Subject: [PATCH 23/53] ci(releaserc): remove [skip ci] from release message format - Updated the release message format in .releaserc.json to remove the [skip ci] directive, ensuring that CI is triggered for release commits. Signed-off-by: Dmitrii Safronov --- .releaserc.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.releaserc.json b/.releaserc.json index 8694940..cf3038d 100644 --- a/.releaserc.json +++ b/.releaserc.json @@ -29,7 +29,7 @@ }], ["@semantic-release/git", { "assets": ["pyproject.toml"], - "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" + "message": "chore(release): ${nextRelease.version}\n\n${nextRelease.notes}" }], ["@semantic-release/github", {}] ] From 803d647a3c5d436a90a004bda4cc068d562fa7b1 Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Fri, 5 Dec 2025 23:56:22 +0400 Subject: [PATCH 24/53] chore: update logging-objects-with-schema version to 0.1.1rc2 - Incremented the version of the logging-objects-with-schema package from 0.1.1rc1 to 0.1.1rc2 in the uv.lock file to reflect the latest release. Signed-off-by: Dmitrii Safronov --- uv.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uv.lock b/uv.lock index 1a38563..ae96c36 100644 --- a/uv.lock +++ b/uv.lock @@ -348,7 +348,7 @@ wheels = [ [[package]] name = "logging-objects-with-schema" -version = "0.1.1rc1" +version = "0.1.1rc2" source = { editable = "." } [package.optional-dependencies] From 750aa26f4e13197bd1143ad259b77d94d6480da0 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 5 Dec 2025 20:02:48 +0000 Subject: [PATCH 25/53] chore(release): 0.1.1-rc.3 ## [0.1.1-rc.3](https://github.com/disafronov/python-logging-objects-with-schema/compare/v0.1.1-rc.2...v0.1.1-rc.3) (2025-12-05) --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index a5198f6..8888095 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "uv_build" [project] name = "logging-objects-with-schema" -version = "0.1.1rc2" +version = "0.1.1rc3" description = "Proxy logging wrapper that validates extra fields against a JSON schema." readme = "README.md" requires-python = ">=3.10" From 9ee3bbb3bf812da5ac4268e816955c16684edc18 Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Sat, 6 Dec 2025 00:14:44 +0400 Subject: [PATCH 26/53] chore(release): update release preparation commands and assets - Modified the prepare command in .releaserc.json to update both the pyproject.toml and uv.lock files with the new version during the release process. - Added uv.lock to the list of assets to be included in the release commit, ensuring that all relevant files are updated and versioned correctly. Signed-off-by: Dmitrii Safronov --- .releaserc.json | 4 ++-- uv.lock | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.releaserc.json b/.releaserc.json index cf3038d..36cd72c 100644 --- a/.releaserc.json +++ b/.releaserc.json @@ -25,10 +25,10 @@ }], ["@semantic-release/release-notes-generator", { "preset": "conventionalcommits" }], ["@semantic-release/exec", { - "prepareCmd": "node -e \"const fs=require('fs'),toml=require('@iarna/toml');const f='pyproject.toml';const data=toml.parse(fs.readFileSync(f,'utf8'));let version='${nextRelease.version}';version=version.replace(/-rc\\./g,'rc');data.project.version=version;fs.writeFileSync(f,toml.stringify(data))\"" + "prepareCmd": "node -e \"const fs=require('fs'),toml=require('@iarna/toml');let version='${nextRelease.version}';version=version.replace(/-rc\\\\./g,'rc');const pyprojectFile='pyproject.toml';const pyprojectData=toml.parse(fs.readFileSync(pyprojectFile,'utf8'));const packageName=pyprojectData.project.name;pyprojectData.project.version=version;fs.writeFileSync(pyprojectFile,toml.stringify(pyprojectData));const uvLockFile='uv.lock';const uvLockData=toml.parse(fs.readFileSync(uvLockFile,'utf8'));const packageIndex=uvLockData.package.findIndex(p=>p.name===packageName);if(packageIndex!==-1){uvLockData.package[packageIndex].version=version;fs.writeFileSync(uvLockFile,toml.stringify(uvLockData));}\"" }], ["@semantic-release/git", { - "assets": ["pyproject.toml"], + "assets": ["pyproject.toml", "uv.lock"], "message": "chore(release): ${nextRelease.version}\n\n${nextRelease.notes}" }], ["@semantic-release/github", {}] diff --git a/uv.lock b/uv.lock index ae96c36..4c578f0 100644 --- a/uv.lock +++ b/uv.lock @@ -348,7 +348,7 @@ wheels = [ [[package]] name = "logging-objects-with-schema" -version = "0.1.1rc2" +version = "0.1.1rc3" source = { editable = "." } [package.optional-dependencies] From 596257627098a22a116c1606ae932c5008fdee67 Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Sat, 6 Dec 2025 00:26:30 +0400 Subject: [PATCH 27/53] refactor(schema_loader): add caching functions for schema file paths - Introduced new functions to manage caching of schema file paths: _check_cached_found_file_path, _check_cached_missing_file_path, _cache_and_return_found_path, and _cache_and_return_missing_path. - These functions enhance the efficiency of schema file retrieval by validating cached paths and handling changes in the current working directory. - Updated the _get_schema_path function to utilize these new caching mechanisms, improving its performance and reliability. Signed-off-by: Dmitrii Safronov --- .../schema_loader.py | 123 ++++++++++--- tests/test_schema_loader.py | 173 ++++++++++++++++++ 2 files changed, 266 insertions(+), 30 deletions(-) diff --git a/src/logging_objects_with_schema/schema_loader.py b/src/logging_objects_with_schema/schema_loader.py index 23d1951..918615c 100644 --- a/src/logging_objects_with_schema/schema_loader.py +++ b/src/logging_objects_with_schema/schema_loader.py @@ -109,6 +109,88 @@ def _find_schema_file() -> Path | None: return None +def _check_cached_found_file_path() -> Path | None: + """Check if cached path for a found file is still valid. + + When a schema file was found, its absolute path is cached as CWD-independent. + This function checks if the cached path still exists on disk. + + Returns: + Cached path if file still exists, None if file was deleted (cache invalidated). + """ + global _resolved_schema_path + + if _resolved_schema_path is None: + return None + + # Schema file was found, absolute path doesn't depend on CWD + # Return it if it still exists + if _resolved_schema_path.exists(): + return _resolved_schema_path + + # If cached path doesn't exist, re-search (schema might have been moved) + _resolved_schema_path = None + return None + + +def _check_cached_missing_file_path() -> Path | None: + """Check if cached path for a missing file is still valid. + + When a schema file was not found, a path based on CWD is cached. + This function checks if CWD has changed since caching. + + Returns: + Cached path if CWD unchanged, None if CWD changed (cache invalidated). + """ + global _resolved_schema_path, _cached_cwd + + if _resolved_schema_path is None or _cached_cwd is None: + return None + + # Cached path is based on CWD when file was not found, + # check if CWD changed + current_cwd = Path(os.getcwd()).resolve() + if current_cwd != _cached_cwd: + # CWD changed, invalidate cache and re-search from new CWD + _resolved_schema_path = None + _cached_cwd = None + return None + + # CWD unchanged, return cached path + return _resolved_schema_path + + +def _cache_and_return_found_path(found_path: Path) -> Path: + """Cache a found schema file path and return it. + + Args: + found_path: Absolute path to the found schema file. + + Returns: + The cached path (CWD-independent). + """ + global _resolved_schema_path, _cached_cwd + + _resolved_schema_path = found_path + _cached_cwd = None # Absolute path doesn't depend on CWD + return found_path + + +def _cache_and_return_missing_path() -> Path: + """Cache a missing schema file path and return it. + + Returns: + Absolute path in current working directory where schema file is expected. + """ + global _resolved_schema_path, _cached_cwd + + current_cwd = Path(os.getcwd()).resolve() + schema_path = (current_cwd / SCHEMA_FILE_NAME).resolve() + _resolved_schema_path = schema_path + _cached_cwd = current_cwd # Track CWD since path depends on it + return schema_path + + def _get_schema_path() -> Path: """Resolve the absolute path to the JSON schema file with caching semantics. @@ -129,44 +211,25 @@ def _get_schema_path() -> Path: Returns: Absolute path where the schema file is located or expected to be. """ - global _resolved_schema_path, _cached_cwd - with _path_cache_lock: - if _resolved_schema_path is not None: - # If cached path is an absolute path to a found file (CWD-independent) - if _cached_cwd is None: - # Schema file was found, absolute path doesn't depend on CWD - # Return it if it still exists - if _resolved_schema_path.exists(): - return _resolved_schema_path - # If cached path doesn't exist, re-search (schema might have been moved) - _resolved_schema_path = None - else: - # Cached path is based on CWD when file was not found, - # check if CWD changed - current_cwd = Path(os.getcwd()).resolve() - if current_cwd != _cached_cwd: - # CWD changed, invalidate cache and re-search from new CWD - _resolved_schema_path = None - _cached_cwd = None - else: - # CWD unchanged, return cached path - return _resolved_schema_path + # Check cached path for found file (CWD-independent) + cached_path = _check_cached_found_file_path() + if cached_path is not None: + return cached_path + + # Check cached path for missing file (CWD-dependent) + cached_path = _check_cached_missing_file_path() + if cached_path is not None: + return cached_path # Search for schema file found_path = _find_schema_file() if found_path is not None: - _resolved_schema_path = found_path - _cached_cwd = None # Absolute path doesn't depend on CWD - return found_path + return _cache_and_return_found_path(found_path) # Schema file not found, return absolute path in current working directory # (this path may not exist, but allows caller to report proper error) - current_cwd = Path(os.getcwd()).resolve() - schema_path = (current_cwd / SCHEMA_FILE_NAME).resolve() - _resolved_schema_path = schema_path - _cached_cwd = current_cwd # Track CWD since path depends on it - return schema_path + return _cache_and_return_missing_path() def _load_raw_schema() -> tuple[dict[str, Any], Path]: diff --git a/tests/test_schema_loader.py b/tests/test_schema_loader.py index 051aac8..ca27d46 100644 --- a/tests/test_schema_loader.py +++ b/tests/test_schema_loader.py @@ -10,6 +10,7 @@ import pytest +import logging_objects_with_schema.schema_loader as schema_loader from logging_objects_with_schema.errors import SchemaProblem from logging_objects_with_schema.schema_loader import ( MAX_SCHEMA_DEPTH, @@ -17,6 +18,18 @@ CompiledSchema, SchemaLeaf, ) +from logging_objects_with_schema.schema_loader import ( + _cache_and_return_found_path as cache_and_return_found_path, +) +from logging_objects_with_schema.schema_loader import ( + _cache_and_return_missing_path as cache_and_return_missing_path, +) +from logging_objects_with_schema.schema_loader import ( + _check_cached_found_file_path as check_cached_found_file_path, +) +from logging_objects_with_schema.schema_loader import ( + _check_cached_missing_file_path as check_cached_missing_file_path, +) from logging_objects_with_schema.schema_loader import ( _compile_schema_internal as compile_schema_internal, ) @@ -929,3 +942,163 @@ def test_get_schema_path_cwd_change_preserves_cache_when_file_found( path2 = get_schema_path() assert path2 == path1 assert path2.exists() + + +def test_check_cached_found_file_path_returns_path_when_exists( + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, +) -> None: + """_check_cached_found_file_path should return path when file exists.""" + + monkeypatch.chdir(tmp_path) + + # Create schema file + schema_file = tmp_path / SCHEMA_FILE_NAME + _write_schema( + tmp_path, + {"ServicePayload": {"RequestID": {"type": "str", "source": "request_id"}}}, + ) + + # Cache the path + with schema_loader._path_cache_lock: + schema_loader._resolved_schema_path = schema_file.resolve() + schema_loader._cached_cwd = None + + # Should return cached path + result = check_cached_found_file_path() + assert result == schema_file.resolve() + assert result.exists() + + +def test_check_cached_found_file_path_returns_none_when_file_deleted( + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, +) -> None: + """_check_cached_found_file_path should return None when file is deleted.""" + + monkeypatch.chdir(tmp_path) + + # Create and cache schema file + schema_file = tmp_path / SCHEMA_FILE_NAME + _write_schema( + tmp_path, + {"ServicePayload": {"RequestID": {"type": "str", "source": "request_id"}}}, + ) + + with schema_loader._path_cache_lock: + schema_loader._resolved_schema_path = schema_file.resolve() + schema_loader._cached_cwd = None + + # Delete the file + schema_file.unlink() + + # Should return None and invalidate cache + result = check_cached_found_file_path() + assert result is None + assert schema_loader._resolved_schema_path is None + + +def test_check_cached_found_file_path_returns_none_when_no_cache() -> None: + """_check_cached_found_file_path should return None when no cache exists.""" + + with schema_loader._path_cache_lock: + schema_loader._resolved_schema_path = None + + result = check_cached_found_file_path() + assert result is None + + +def test_check_cached_missing_file_path_returns_path_when_cwd_unchanged( + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, +) -> None: + """_check_cached_missing_file_path should return path when CWD unchanged.""" + + monkeypatch.chdir(tmp_path) + + expected_path = (tmp_path / SCHEMA_FILE_NAME).resolve() + + with schema_loader._path_cache_lock: + schema_loader._resolved_schema_path = expected_path + schema_loader._cached_cwd = tmp_path.resolve() + + result = check_cached_missing_file_path() + assert result == expected_path + + +def test_check_cached_missing_file_path_returns_none_when_cwd_changed( + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, +) -> None: + """_check_cached_missing_file_path should return None when CWD changed.""" + + dir1 = tmp_path / "dir1" + dir2 = tmp_path / "dir2" + dir1.mkdir() + dir2.mkdir() + + monkeypatch.chdir(dir1) + + with schema_loader._path_cache_lock: + schema_loader._resolved_schema_path = (dir1 / SCHEMA_FILE_NAME).resolve() + schema_loader._cached_cwd = dir1.resolve() + + # Change CWD + monkeypatch.chdir(dir2) + + # Should return None and invalidate cache + result = check_cached_missing_file_path() + assert result is None + assert schema_loader._resolved_schema_path is None + assert schema_loader._cached_cwd is None + + +def test_check_cached_missing_file_path_returns_none_when_no_cache() -> None: + """_check_cached_missing_file_path should return None when no cache exists.""" + + with schema_loader._path_cache_lock: + schema_loader._resolved_schema_path = None + schema_loader._cached_cwd = None + + result = check_cached_missing_file_path() + assert result is None + + +def test_cache_and_return_found_path_caches_path( + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, +) -> None: + """_cache_and_return_found_path should cache and return found path.""" + + monkeypatch.chdir(tmp_path) + + schema_file = tmp_path / SCHEMA_FILE_NAME + _write_schema( + tmp_path, + {"ServicePayload": {"RequestID": {"type": "str", "source": "request_id"}}}, + ) + + with schema_loader._path_cache_lock: + result = cache_and_return_found_path(schema_file.resolve()) + + assert result == schema_file.resolve() + assert schema_loader._resolved_schema_path == schema_file.resolve() + assert schema_loader._cached_cwd is None + + +def test_cache_and_return_missing_path_caches_path( + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, +) -> None: + """_cache_and_return_missing_path should cache and return missing path.""" + + monkeypatch.chdir(tmp_path) + + expected_path = (tmp_path / SCHEMA_FILE_NAME).resolve() + + with schema_loader._path_cache_lock: + result = cache_and_return_missing_path() + + assert result == expected_path + assert schema_loader._resolved_schema_path == expected_path + assert schema_loader._cached_cwd == tmp_path.resolve() From ab0e3468026906ff3ec2f95b4241f39c8f8883e7 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 5 Dec 2025 20:26:54 +0000 Subject: [PATCH 28/53] chore(release): 0.1.1-rc.4 ## [0.1.1-rc.4](https://github.com/disafronov/python-logging-objects-with-schema/compare/v0.1.1-rc.3...v0.1.1-rc.4) (2025-12-05) --- pyproject.toml | 2 +- uv.lock | 3185 +++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 2592 insertions(+), 595 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 8888095..5c09d66 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "uv_build" [project] name = "logging-objects-with-schema" -version = "0.1.1rc3" +version = "0.1.1rc4" description = "Proxy logging wrapper that validates extra fields against a JSON schema." readme = "README.md" requires-python = ">=3.10" diff --git a/uv.lock b/uv.lock index 4c578f0..4ed1617 100644 --- a/uv.lock +++ b/uv.lock @@ -5,748 +5,2745 @@ requires-python = ">=3.10" [[package]] name = "bandit" version = "1.9.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "pyyaml" }, - { name = "rich" }, - { name = "stevedore" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/cf/72/f704a97aac430aeb704fa16435dfa24fbeaf087d46724d0965eb1f756a2c/bandit-1.9.2.tar.gz", hash = "sha256:32410415cd93bf9c8b91972159d5cf1e7f063a9146d70345641cd3877de348ce", size = 4241659, upload-time = "2025-11-23T21:36:18.722Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/55/1a/5b0320642cca53a473e79c7d273071b5a9a8578f9e370b74da5daa2768d7/bandit-1.9.2-py3-none-any.whl", hash = "sha256:bda8d68610fc33a6e10b7a8f1d61d92c8f6c004051d5e946406be1fb1b16a868", size = 134377, upload-time = "2025-11-23T21:36:17.39Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [[package.dependencies]] + name = "colorama" + marker = "sys_platform == 'win32'" + + [[package.dependencies]] + name = "pyyaml" + + [[package.dependencies]] + name = "rich" + + [[package.dependencies]] + name = "stevedore" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/cf/72/f704a97aac430aeb704fa16435dfa24fbeaf087d46724d0965eb1f756a2c/bandit-1.9.2.tar.gz" + hash = "sha256:32410415cd93bf9c8b91972159d5cf1e7f063a9146d70345641cd3877de348ce" + size = 4_241_659 + upload-time = "2025-11-23T21:36:18.722Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/55/1a/5b0320642cca53a473e79c7d273071b5a9a8578f9e370b74da5daa2768d7/bandit-1.9.2-py3-none-any.whl" + hash = "sha256:bda8d68610fc33a6e10b7a8f1d61d92c8f6c004051d5e946406be1fb1b16a868" + size = 134_377 + upload-time = "2025-11-23T21:36:17.39Z" [[package]] name = "black" version = "25.11.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "mypy-extensions" }, - { name = "packaging" }, - { name = "pathspec" }, - { name = "platformdirs" }, - { name = "pytokens" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/8c/ad/33adf4708633d047950ff2dfdea2e215d84ac50ef95aff14a614e4b6e9b2/black-25.11.0.tar.gz", hash = "sha256:9a323ac32f5dc75ce7470501b887250be5005a01602e931a15e45593f70f6e08", size = 655669, upload-time = "2025-11-10T01:53:50.558Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/d2/6caccbc96f9311e8ec3378c296d4f4809429c43a6cd2394e3c390e86816d/black-25.11.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ec311e22458eec32a807f029b2646f661e6859c3f61bc6d9ffb67958779f392e", size = 1743501, upload-time = "2025-11-10T01:59:06.202Z" }, - { url = "https://files.pythonhosted.org/packages/69/35/b986d57828b3f3dccbf922e2864223197ba32e74c5004264b1c62bc9f04d/black-25.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1032639c90208c15711334d681de2e24821af0575573db2810b0763bcd62e0f0", size = 1597308, upload-time = "2025-11-10T01:57:58.633Z" }, - { url = "https://files.pythonhosted.org/packages/39/8e/8b58ef4b37073f52b64a7b2dd8c9a96c84f45d6f47d878d0aa557e9a2d35/black-25.11.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0c0f7c461df55cf32929b002335883946a4893d759f2df343389c4396f3b6b37", size = 1656194, upload-time = "2025-11-10T01:57:10.909Z" }, - { url = "https://files.pythonhosted.org/packages/8d/30/9c2267a7955ecc545306534ab88923769a979ac20a27cf618d370091e5dd/black-25.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:f9786c24d8e9bd5f20dc7a7f0cdd742644656987f6ea6947629306f937726c03", size = 1347996, upload-time = "2025-11-10T01:57:22.391Z" }, - { url = "https://files.pythonhosted.org/packages/c4/62/d304786b75ab0c530b833a89ce7d997924579fb7484ecd9266394903e394/black-25.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:895571922a35434a9d8ca67ef926da6bc9ad464522a5fe0db99b394ef1c0675a", size = 1727891, upload-time = "2025-11-10T02:01:40.507Z" }, - { url = "https://files.pythonhosted.org/packages/82/5d/ffe8a006aa522c9e3f430e7b93568a7b2163f4b3f16e8feb6d8c3552761a/black-25.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cb4f4b65d717062191bdec8e4a442539a8ea065e6af1c4f4d36f0cdb5f71e170", size = 1581875, upload-time = "2025-11-10T01:57:51.192Z" }, - { url = "https://files.pythonhosted.org/packages/cb/c8/7c8bda3108d0bb57387ac41b4abb5c08782b26da9f9c4421ef6694dac01a/black-25.11.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d81a44cbc7e4f73a9d6ae449ec2317ad81512d1e7dce7d57f6333fd6259737bc", size = 1642716, upload-time = "2025-11-10T01:56:51.589Z" }, - { url = "https://files.pythonhosted.org/packages/34/b9/f17dea34eecb7cc2609a89627d480fb6caea7b86190708eaa7eb15ed25e7/black-25.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:7eebd4744dfe92ef1ee349dc532defbf012a88b087bb7ddd688ff59a447b080e", size = 1352904, upload-time = "2025-11-10T01:59:26.252Z" }, - { url = "https://files.pythonhosted.org/packages/7f/12/5c35e600b515f35ffd737da7febdb2ab66bb8c24d88560d5e3ef3d28c3fd/black-25.11.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:80e7486ad3535636657aa180ad32a7d67d7c273a80e12f1b4bfa0823d54e8fac", size = 1772831, upload-time = "2025-11-10T02:03:47Z" }, - { url = "https://files.pythonhosted.org/packages/1a/75/b3896bec5a2bb9ed2f989a970ea40e7062f8936f95425879bbe162746fe5/black-25.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6cced12b747c4c76bc09b4db057c319d8545307266f41aaee665540bc0e04e96", size = 1608520, upload-time = "2025-11-10T01:58:46.895Z" }, - { url = "https://files.pythonhosted.org/packages/f3/b5/2bfc18330eddbcfb5aab8d2d720663cd410f51b2ed01375f5be3751595b0/black-25.11.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6cb2d54a39e0ef021d6c5eef442e10fd71fcb491be6413d083a320ee768329dd", size = 1682719, upload-time = "2025-11-10T01:56:55.24Z" }, - { url = "https://files.pythonhosted.org/packages/96/fb/f7dc2793a22cdf74a72114b5ed77fe3349a2e09ef34565857a2f917abdf2/black-25.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:ae263af2f496940438e5be1a0c1020e13b09154f3af4df0835ea7f9fe7bfa409", size = 1362684, upload-time = "2025-11-10T01:57:07.639Z" }, - { url = "https://files.pythonhosted.org/packages/ad/47/3378d6a2ddefe18553d1115e36aea98f4a90de53b6a3017ed861ba1bd3bc/black-25.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0a1d40348b6621cc20d3d7530a5b8d67e9714906dfd7346338249ad9c6cedf2b", size = 1772446, upload-time = "2025-11-10T02:02:16.181Z" }, - { url = "https://files.pythonhosted.org/packages/ba/4b/0f00bfb3d1f7e05e25bfc7c363f54dc523bb6ba502f98f4ad3acf01ab2e4/black-25.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:51c65d7d60bb25429ea2bf0731c32b2a2442eb4bd3b2afcb47830f0b13e58bfd", size = 1607983, upload-time = "2025-11-10T02:02:52.502Z" }, - { url = "https://files.pythonhosted.org/packages/99/fe/49b0768f8c9ae57eb74cc10a1f87b4c70453551d8ad498959721cc345cb7/black-25.11.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:936c4dd07669269f40b497440159a221ee435e3fddcf668e0c05244a9be71993", size = 1682481, upload-time = "2025-11-10T01:57:12.35Z" }, - { url = "https://files.pythonhosted.org/packages/55/17/7e10ff1267bfa950cc16f0a411d457cdff79678fbb77a6c73b73a5317904/black-25.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:f42c0ea7f59994490f4dccd64e6b2dd49ac57c7c84f38b8faab50f8759db245c", size = 1363869, upload-time = "2025-11-10T01:58:24.608Z" }, - { url = "https://files.pythonhosted.org/packages/67/c0/cc865ce594d09e4cd4dfca5e11994ebb51604328489f3ca3ae7bb38a7db5/black-25.11.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:35690a383f22dd3e468c85dc4b915217f87667ad9cce781d7b42678ce63c4170", size = 1771358, upload-time = "2025-11-10T02:03:33.331Z" }, - { url = "https://files.pythonhosted.org/packages/37/77/4297114d9e2fd2fc8ab0ab87192643cd49409eb059e2940391e7d2340e57/black-25.11.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:dae49ef7369c6caa1a1833fd5efb7c3024bb7e4499bf64833f65ad27791b1545", size = 1612902, upload-time = "2025-11-10T01:59:33.382Z" }, - { url = "https://files.pythonhosted.org/packages/de/63/d45ef97ada84111e330b2b2d45e1dd163e90bd116f00ac55927fb6bf8adb/black-25.11.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bd4a22a0b37401c8e492e994bce79e614f91b14d9ea911f44f36e262195fdda", size = 1680571, upload-time = "2025-11-10T01:57:04.239Z" }, - { url = "https://files.pythonhosted.org/packages/ff/4b/5604710d61cdff613584028b4cb4607e56e148801ed9b38ee7970799dab6/black-25.11.0-cp314-cp314-win_amd64.whl", hash = "sha256:aa211411e94fdf86519996b7f5f05e71ba34835d8f0c0f03c00a26271da02664", size = 1382599, upload-time = "2025-11-10T01:57:57.427Z" }, - { url = "https://files.pythonhosted.org/packages/00/5d/aed32636ed30a6e7f9efd6ad14e2a0b0d687ae7c8c7ec4e4a557174b895c/black-25.11.0-py3-none-any.whl", hash = "sha256:e3f562da087791e96cefcd9dda058380a442ab322a02e222add53736451f604b", size = 204918, upload-time = "2025-11-10T01:53:48.917Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [[package.dependencies]] + name = "click" + + [[package.dependencies]] + name = "mypy-extensions" + + [[package.dependencies]] + name = "packaging" + + [[package.dependencies]] + name = "pathspec" + + [[package.dependencies]] + name = "platformdirs" + + [[package.dependencies]] + name = "pytokens" + + [[package.dependencies]] + name = "tomli" + marker = "python_full_version < '3.11'" + + [[package.dependencies]] + name = "typing-extensions" + marker = "python_full_version < '3.11'" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/8c/ad/33adf4708633d047950ff2dfdea2e215d84ac50ef95aff14a614e4b6e9b2/black-25.11.0.tar.gz" + hash = "sha256:9a323ac32f5dc75ce7470501b887250be5005a01602e931a15e45593f70f6e08" + size = 655_669 + upload-time = "2025-11-10T01:53:50.558Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/b3/d2/6caccbc96f9311e8ec3378c296d4f4809429c43a6cd2394e3c390e86816d/black-25.11.0-cp310-cp310-macosx_10_9_x86_64.whl" + hash = "sha256:ec311e22458eec32a807f029b2646f661e6859c3f61bc6d9ffb67958779f392e" + size = 1_743_501 + upload-time = "2025-11-10T01:59:06.202Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/69/35/b986d57828b3f3dccbf922e2864223197ba32e74c5004264b1c62bc9f04d/black-25.11.0-cp310-cp310-macosx_11_0_arm64.whl" + hash = "sha256:1032639c90208c15711334d681de2e24821af0575573db2810b0763bcd62e0f0" + size = 1_597_308 + upload-time = "2025-11-10T01:57:58.633Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/39/8e/8b58ef4b37073f52b64a7b2dd8c9a96c84f45d6f47d878d0aa557e9a2d35/black-25.11.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + hash = "sha256:0c0f7c461df55cf32929b002335883946a4893d759f2df343389c4396f3b6b37" + size = 1_656_194 + upload-time = "2025-11-10T01:57:10.909Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/8d/30/9c2267a7955ecc545306534ab88923769a979ac20a27cf618d370091e5dd/black-25.11.0-cp310-cp310-win_amd64.whl" + hash = "sha256:f9786c24d8e9bd5f20dc7a7f0cdd742644656987f6ea6947629306f937726c03" + size = 1_347_996 + upload-time = "2025-11-10T01:57:22.391Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/c4/62/d304786b75ab0c530b833a89ce7d997924579fb7484ecd9266394903e394/black-25.11.0-cp311-cp311-macosx_10_9_x86_64.whl" + hash = "sha256:895571922a35434a9d8ca67ef926da6bc9ad464522a5fe0db99b394ef1c0675a" + size = 1_727_891 + upload-time = "2025-11-10T02:01:40.507Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/82/5d/ffe8a006aa522c9e3f430e7b93568a7b2163f4b3f16e8feb6d8c3552761a/black-25.11.0-cp311-cp311-macosx_11_0_arm64.whl" + hash = "sha256:cb4f4b65d717062191bdec8e4a442539a8ea065e6af1c4f4d36f0cdb5f71e170" + size = 1_581_875 + upload-time = "2025-11-10T01:57:51.192Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/cb/c8/7c8bda3108d0bb57387ac41b4abb5c08782b26da9f9c4421ef6694dac01a/black-25.11.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + hash = "sha256:d81a44cbc7e4f73a9d6ae449ec2317ad81512d1e7dce7d57f6333fd6259737bc" + size = 1_642_716 + upload-time = "2025-11-10T01:56:51.589Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/34/b9/f17dea34eecb7cc2609a89627d480fb6caea7b86190708eaa7eb15ed25e7/black-25.11.0-cp311-cp311-win_amd64.whl" + hash = "sha256:7eebd4744dfe92ef1ee349dc532defbf012a88b087bb7ddd688ff59a447b080e" + size = 1_352_904 + upload-time = "2025-11-10T01:59:26.252Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/7f/12/5c35e600b515f35ffd737da7febdb2ab66bb8c24d88560d5e3ef3d28c3fd/black-25.11.0-cp312-cp312-macosx_10_13_x86_64.whl" + hash = "sha256:80e7486ad3535636657aa180ad32a7d67d7c273a80e12f1b4bfa0823d54e8fac" + size = 1_772_831 + upload-time = "2025-11-10T02:03:47Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/1a/75/b3896bec5a2bb9ed2f989a970ea40e7062f8936f95425879bbe162746fe5/black-25.11.0-cp312-cp312-macosx_11_0_arm64.whl" + hash = "sha256:6cced12b747c4c76bc09b4db057c319d8545307266f41aaee665540bc0e04e96" + size = 1_608_520 + upload-time = "2025-11-10T01:58:46.895Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/f3/b5/2bfc18330eddbcfb5aab8d2d720663cd410f51b2ed01375f5be3751595b0/black-25.11.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + hash = "sha256:6cb2d54a39e0ef021d6c5eef442e10fd71fcb491be6413d083a320ee768329dd" + size = 1_682_719 + upload-time = "2025-11-10T01:56:55.24Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/96/fb/f7dc2793a22cdf74a72114b5ed77fe3349a2e09ef34565857a2f917abdf2/black-25.11.0-cp312-cp312-win_amd64.whl" + hash = "sha256:ae263af2f496940438e5be1a0c1020e13b09154f3af4df0835ea7f9fe7bfa409" + size = 1_362_684 + upload-time = "2025-11-10T01:57:07.639Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/ad/47/3378d6a2ddefe18553d1115e36aea98f4a90de53b6a3017ed861ba1bd3bc/black-25.11.0-cp313-cp313-macosx_10_13_x86_64.whl" + hash = "sha256:0a1d40348b6621cc20d3d7530a5b8d67e9714906dfd7346338249ad9c6cedf2b" + size = 1_772_446 + upload-time = "2025-11-10T02:02:16.181Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/ba/4b/0f00bfb3d1f7e05e25bfc7c363f54dc523bb6ba502f98f4ad3acf01ab2e4/black-25.11.0-cp313-cp313-macosx_11_0_arm64.whl" + hash = "sha256:51c65d7d60bb25429ea2bf0731c32b2a2442eb4bd3b2afcb47830f0b13e58bfd" + size = 1_607_983 + upload-time = "2025-11-10T02:02:52.502Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/99/fe/49b0768f8c9ae57eb74cc10a1f87b4c70453551d8ad498959721cc345cb7/black-25.11.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + hash = "sha256:936c4dd07669269f40b497440159a221ee435e3fddcf668e0c05244a9be71993" + size = 1_682_481 + upload-time = "2025-11-10T01:57:12.35Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/55/17/7e10ff1267bfa950cc16f0a411d457cdff79678fbb77a6c73b73a5317904/black-25.11.0-cp313-cp313-win_amd64.whl" + hash = "sha256:f42c0ea7f59994490f4dccd64e6b2dd49ac57c7c84f38b8faab50f8759db245c" + size = 1_363_869 + upload-time = "2025-11-10T01:58:24.608Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/67/c0/cc865ce594d09e4cd4dfca5e11994ebb51604328489f3ca3ae7bb38a7db5/black-25.11.0-cp314-cp314-macosx_10_15_x86_64.whl" + hash = "sha256:35690a383f22dd3e468c85dc4b915217f87667ad9cce781d7b42678ce63c4170" + size = 1_771_358 + upload-time = "2025-11-10T02:03:33.331Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/37/77/4297114d9e2fd2fc8ab0ab87192643cd49409eb059e2940391e7d2340e57/black-25.11.0-cp314-cp314-macosx_11_0_arm64.whl" + hash = "sha256:dae49ef7369c6caa1a1833fd5efb7c3024bb7e4499bf64833f65ad27791b1545" + size = 1_612_902 + upload-time = "2025-11-10T01:59:33.382Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/de/63/d45ef97ada84111e330b2b2d45e1dd163e90bd116f00ac55927fb6bf8adb/black-25.11.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + hash = "sha256:5bd4a22a0b37401c8e492e994bce79e614f91b14d9ea911f44f36e262195fdda" + size = 1_680_571 + upload-time = "2025-11-10T01:57:04.239Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/ff/4b/5604710d61cdff613584028b4cb4607e56e148801ed9b38ee7970799dab6/black-25.11.0-cp314-cp314-win_amd64.whl" + hash = "sha256:aa211411e94fdf86519996b7f5f05e71ba34835d8f0c0f03c00a26271da02664" + size = 1_382_599 + upload-time = "2025-11-10T01:57:57.427Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/00/5d/aed32636ed30a6e7f9efd6ad14e2a0b0d687ae7c8c7ec4e4a557174b895c/black-25.11.0-py3-none-any.whl" + hash = "sha256:e3f562da087791e96cefcd9dda058380a442ab322a02e222add53736451f604b" + size = 204_918 + upload-time = "2025-11-10T01:53:48.917Z" [[package]] name = "cfgv" version = "3.5.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334, upload-time = "2025-11-19T20:55:51.612Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445, upload-time = "2025-11-19T20:55:50.744Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz" + hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132" + size = 7_334 + upload-time = "2025-11-19T20:55:51.612Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl" + hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0" + size = 7_445 + upload-time = "2025-11-19T20:55:50.744Z" [[package]] name = "click" version = "8.3.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [[package.dependencies]] + name = "colorama" + marker = "sys_platform == 'win32'" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz" + hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a" + size = 295_065 + upload-time = "2025-11-15T20:45:42.706Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl" + hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6" + size = 108_274 + upload-time = "2025-11-15T20:45:41.139Z" [[package]] name = "colorama" version = "0.4.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz" + hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44" + size = 27_697 + upload-time = "2022-10-25T02:36:22.414Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl" + hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" + size = 25_335 + upload-time = "2022-10-25T02:36:20.889Z" [[package]] name = "coverage" version = "7.12.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/89/26/4a96807b193b011588099c3b5c89fbb05294e5b90e71018e065465f34eb6/coverage-7.12.0.tar.gz", hash = "sha256:fc11e0a4e372cb5f282f16ef90d4a585034050ccda536451901abfb19a57f40c", size = 819341, upload-time = "2025-11-18T13:34:20.766Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/26/4a/0dc3de1c172d35abe512332cfdcc43211b6ebce629e4cc42e6cd25ed8f4d/coverage-7.12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:32b75c2ba3f324ee37af3ccee5b30458038c50b349ad9b88cee85096132a575b", size = 217409, upload-time = "2025-11-18T13:31:53.122Z" }, - { url = "https://files.pythonhosted.org/packages/01/c3/086198b98db0109ad4f84241e8e9ea7e5fb2db8c8ffb787162d40c26cc76/coverage-7.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cb2a1b6ab9fe833714a483a915de350abc624a37149649297624c8d57add089c", size = 217927, upload-time = "2025-11-18T13:31:54.458Z" }, - { url = "https://files.pythonhosted.org/packages/5d/5f/34614dbf5ce0420828fc6c6f915126a0fcb01e25d16cf141bf5361e6aea6/coverage-7.12.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5734b5d913c3755e72f70bf6cc37a0518d4f4745cde760c5d8e12005e62f9832", size = 244678, upload-time = "2025-11-18T13:31:55.805Z" }, - { url = "https://files.pythonhosted.org/packages/55/7b/6b26fb32e8e4a6989ac1d40c4e132b14556131493b1d06bc0f2be169c357/coverage-7.12.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b527a08cdf15753279b7afb2339a12073620b761d79b81cbe2cdebdb43d90daa", size = 246507, upload-time = "2025-11-18T13:31:57.05Z" }, - { url = "https://files.pythonhosted.org/packages/06/42/7d70e6603d3260199b90fb48b537ca29ac183d524a65cc31366b2e905fad/coverage-7.12.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9bb44c889fb68004e94cab71f6a021ec83eac9aeabdbb5a5a88821ec46e1da73", size = 248366, upload-time = "2025-11-18T13:31:58.362Z" }, - { url = "https://files.pythonhosted.org/packages/2d/4a/d86b837923878424c72458c5b25e899a3c5ca73e663082a915f5b3c4d749/coverage-7.12.0-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4b59b501455535e2e5dde5881739897967b272ba25988c89145c12d772810ccb", size = 245366, upload-time = "2025-11-18T13:31:59.572Z" }, - { url = "https://files.pythonhosted.org/packages/e6/c2/2adec557e0aa9721875f06ced19730fdb7fc58e31b02b5aa56f2ebe4944d/coverage-7.12.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d8842f17095b9868a05837b7b1b73495293091bed870e099521ada176aa3e00e", size = 246408, upload-time = "2025-11-18T13:32:00.784Z" }, - { url = "https://files.pythonhosted.org/packages/5a/4b/8bd1f1148260df11c618e535fdccd1e5aaf646e55b50759006a4f41d8a26/coverage-7.12.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c5a6f20bf48b8866095c6820641e7ffbe23f2ac84a2efc218d91235e404c7777", size = 244416, upload-time = "2025-11-18T13:32:01.963Z" }, - { url = "https://files.pythonhosted.org/packages/0e/13/3a248dd6a83df90414c54a4e121fd081fb20602ca43955fbe1d60e2312a9/coverage-7.12.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:5f3738279524e988d9da2893f307c2093815c623f8d05a8f79e3eff3a7a9e553", size = 244681, upload-time = "2025-11-18T13:32:03.408Z" }, - { url = "https://files.pythonhosted.org/packages/76/30/aa833827465a5e8c938935f5d91ba055f70516941078a703740aaf1aa41f/coverage-7.12.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e0d68c1f7eabbc8abe582d11fa393ea483caf4f44b0af86881174769f185c94d", size = 245300, upload-time = "2025-11-18T13:32:04.686Z" }, - { url = "https://files.pythonhosted.org/packages/38/24/f85b3843af1370fb3739fa7571819b71243daa311289b31214fe3e8c9d68/coverage-7.12.0-cp310-cp310-win32.whl", hash = "sha256:7670d860e18b1e3ee5930b17a7d55ae6287ec6e55d9799982aa103a2cc1fa2ef", size = 220008, upload-time = "2025-11-18T13:32:05.806Z" }, - { url = "https://files.pythonhosted.org/packages/3a/a2/c7da5b9566f7164db9eefa133d17761ecb2c2fde9385d754e5b5c80f710d/coverage-7.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:f999813dddeb2a56aab5841e687b68169da0d3f6fc78ccf50952fa2463746022", size = 220943, upload-time = "2025-11-18T13:32:07.166Z" }, - { url = "https://files.pythonhosted.org/packages/5a/0c/0dfe7f0487477d96432e4815537263363fb6dd7289743a796e8e51eabdf2/coverage-7.12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aa124a3683d2af98bd9d9c2bfa7a5076ca7e5ab09fdb96b81fa7d89376ae928f", size = 217535, upload-time = "2025-11-18T13:32:08.812Z" }, - { url = "https://files.pythonhosted.org/packages/9b/f5/f9a4a053a5bbff023d3bec259faac8f11a1e5a6479c2ccf586f910d8dac7/coverage-7.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d93fbf446c31c0140208dcd07c5d882029832e8ed7891a39d6d44bd65f2316c3", size = 218044, upload-time = "2025-11-18T13:32:10.329Z" }, - { url = "https://files.pythonhosted.org/packages/95/c5/84fc3697c1fa10cd8571919bf9693f693b7373278daaf3b73e328d502bc8/coverage-7.12.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:52ca620260bd8cd6027317bdd8b8ba929be1d741764ee765b42c4d79a408601e", size = 248440, upload-time = "2025-11-18T13:32:12.536Z" }, - { url = "https://files.pythonhosted.org/packages/f4/36/2d93fbf6a04670f3874aed397d5a5371948a076e3249244a9e84fb0e02d6/coverage-7.12.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f3433ffd541380f3a0e423cff0f4926d55b0cc8c1d160fdc3be24a4c03aa65f7", size = 250361, upload-time = "2025-11-18T13:32:13.852Z" }, - { url = "https://files.pythonhosted.org/packages/5d/49/66dc65cc456a6bfc41ea3d0758c4afeaa4068a2b2931bf83be6894cf1058/coverage-7.12.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f7bbb321d4adc9f65e402c677cd1c8e4c2d0105d3ce285b51b4d87f1d5db5245", size = 252472, upload-time = "2025-11-18T13:32:15.068Z" }, - { url = "https://files.pythonhosted.org/packages/35/1f/ebb8a18dffd406db9fcd4b3ae42254aedcaf612470e8712f12041325930f/coverage-7.12.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:22a7aade354a72dff3b59c577bfd18d6945c61f97393bc5fb7bd293a4237024b", size = 248592, upload-time = "2025-11-18T13:32:16.328Z" }, - { url = "https://files.pythonhosted.org/packages/da/a8/67f213c06e5ea3b3d4980df7dc344d7fea88240b5fe878a5dcbdfe0e2315/coverage-7.12.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3ff651dcd36d2fea66877cd4a82de478004c59b849945446acb5baf9379a1b64", size = 250167, upload-time = "2025-11-18T13:32:17.687Z" }, - { url = "https://files.pythonhosted.org/packages/f0/00/e52aef68154164ea40cc8389c120c314c747fe63a04b013a5782e989b77f/coverage-7.12.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:31b8b2e38391a56e3cea39d22a23faaa7c3fc911751756ef6d2621d2a9daf742", size = 248238, upload-time = "2025-11-18T13:32:19.2Z" }, - { url = "https://files.pythonhosted.org/packages/1f/a4/4d88750bcf9d6d66f77865e5a05a20e14db44074c25fd22519777cb69025/coverage-7.12.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:297bc2da28440f5ae51c845a47c8175a4db0553a53827886e4fb25c66633000c", size = 247964, upload-time = "2025-11-18T13:32:21.027Z" }, - { url = "https://files.pythonhosted.org/packages/a7/6b/b74693158899d5b47b0bf6238d2c6722e20ba749f86b74454fac0696bb00/coverage-7.12.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6ff7651cc01a246908eac162a6a86fc0dbab6de1ad165dfb9a1e2ec660b44984", size = 248862, upload-time = "2025-11-18T13:32:22.304Z" }, - { url = "https://files.pythonhosted.org/packages/18/de/6af6730227ce0e8ade307b1cc4a08e7f51b419a78d02083a86c04ccceb29/coverage-7.12.0-cp311-cp311-win32.whl", hash = "sha256:313672140638b6ddb2c6455ddeda41c6a0b208298034544cfca138978c6baed6", size = 220033, upload-time = "2025-11-18T13:32:23.714Z" }, - { url = "https://files.pythonhosted.org/packages/e2/a1/e7f63021a7c4fe20994359fcdeae43cbef4a4d0ca36a5a1639feeea5d9e1/coverage-7.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:a1783ed5bd0d5938d4435014626568dc7f93e3cb99bc59188cc18857c47aa3c4", size = 220966, upload-time = "2025-11-18T13:32:25.599Z" }, - { url = "https://files.pythonhosted.org/packages/77/e8/deae26453f37c20c3aa0c4433a1e32cdc169bf415cce223a693117aa3ddd/coverage-7.12.0-cp311-cp311-win_arm64.whl", hash = "sha256:4648158fd8dd9381b5847622df1c90ff314efbfc1df4550092ab6013c238a5fc", size = 219637, upload-time = "2025-11-18T13:32:27.265Z" }, - { url = "https://files.pythonhosted.org/packages/02/bf/638c0427c0f0d47638242e2438127f3c8ee3cfc06c7fdeb16778ed47f836/coverage-7.12.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:29644c928772c78512b48e14156b81255000dcfd4817574ff69def189bcb3647", size = 217704, upload-time = "2025-11-18T13:32:28.906Z" }, - { url = "https://files.pythonhosted.org/packages/08/e1/706fae6692a66c2d6b871a608bbde0da6281903fa0e9f53a39ed441da36a/coverage-7.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8638cbb002eaa5d7c8d04da667813ce1067080b9a91099801a0053086e52b736", size = 218064, upload-time = "2025-11-18T13:32:30.161Z" }, - { url = "https://files.pythonhosted.org/packages/a9/8b/eb0231d0540f8af3ffda39720ff43cb91926489d01524e68f60e961366e4/coverage-7.12.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:083631eeff5eb9992c923e14b810a179798bb598e6a0dd60586819fc23be6e60", size = 249560, upload-time = "2025-11-18T13:32:31.835Z" }, - { url = "https://files.pythonhosted.org/packages/e9/a1/67fb52af642e974d159b5b379e4d4c59d0ebe1288677fbd04bbffe665a82/coverage-7.12.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:99d5415c73ca12d558e07776bd957c4222c687b9f1d26fa0e1b57e3598bdcde8", size = 252318, upload-time = "2025-11-18T13:32:33.178Z" }, - { url = "https://files.pythonhosted.org/packages/41/e5/38228f31b2c7665ebf9bdfdddd7a184d56450755c7e43ac721c11a4b8dab/coverage-7.12.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e949ebf60c717c3df63adb4a1a366c096c8d7fd8472608cd09359e1bd48ef59f", size = 253403, upload-time = "2025-11-18T13:32:34.45Z" }, - { url = "https://files.pythonhosted.org/packages/ec/4b/df78e4c8188f9960684267c5a4897836f3f0f20a20c51606ee778a1d9749/coverage-7.12.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6d907ddccbca819afa2cd014bc69983b146cca2735a0b1e6259b2a6c10be1e70", size = 249984, upload-time = "2025-11-18T13:32:35.747Z" }, - { url = "https://files.pythonhosted.org/packages/ba/51/bb163933d195a345c6f63eab9e55743413d064c291b6220df754075c2769/coverage-7.12.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b1518ecbad4e6173f4c6e6c4a46e49555ea5679bf3feda5edb1b935c7c44e8a0", size = 251339, upload-time = "2025-11-18T13:32:37.352Z" }, - { url = "https://files.pythonhosted.org/packages/15/40/c9b29cdb8412c837cdcbc2cfa054547dd83affe6cbbd4ce4fdb92b6ba7d1/coverage-7.12.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:51777647a749abdf6f6fd8c7cffab12de68ab93aab15efc72fbbb83036c2a068", size = 249489, upload-time = "2025-11-18T13:32:39.212Z" }, - { url = "https://files.pythonhosted.org/packages/c8/da/b3131e20ba07a0de4437a50ef3b47840dfabf9293675b0cd5c2c7f66dd61/coverage-7.12.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:42435d46d6461a3b305cdfcad7cdd3248787771f53fe18305548cba474e6523b", size = 249070, upload-time = "2025-11-18T13:32:40.598Z" }, - { url = "https://files.pythonhosted.org/packages/70/81/b653329b5f6302c08d683ceff6785bc60a34be9ae92a5c7b63ee7ee7acec/coverage-7.12.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5bcead88c8423e1855e64b8057d0544e33e4080b95b240c2a355334bb7ced937", size = 250929, upload-time = "2025-11-18T13:32:42.915Z" }, - { url = "https://files.pythonhosted.org/packages/a3/00/250ac3bca9f252a5fb1338b5ad01331ebb7b40223f72bef5b1b2cb03aa64/coverage-7.12.0-cp312-cp312-win32.whl", hash = "sha256:dcbb630ab034e86d2a0f79aefd2be07e583202f41e037602d438c80044957baa", size = 220241, upload-time = "2025-11-18T13:32:44.665Z" }, - { url = "https://files.pythonhosted.org/packages/64/1c/77e79e76d37ce83302f6c21980b45e09f8aa4551965213a10e62d71ce0ab/coverage-7.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:2fd8354ed5d69775ac42986a691fbf68b4084278710cee9d7c3eaa0c28fa982a", size = 221051, upload-time = "2025-11-18T13:32:46.008Z" }, - { url = "https://files.pythonhosted.org/packages/31/f5/641b8a25baae564f9e52cac0e2667b123de961985709a004e287ee7663cc/coverage-7.12.0-cp312-cp312-win_arm64.whl", hash = "sha256:737c3814903be30695b2de20d22bcc5428fdae305c61ba44cdc8b3252984c49c", size = 219692, upload-time = "2025-11-18T13:32:47.372Z" }, - { url = "https://files.pythonhosted.org/packages/b8/14/771700b4048774e48d2c54ed0c674273702713c9ee7acdfede40c2666747/coverage-7.12.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:47324fffca8d8eae7e185b5bb20c14645f23350f870c1649003618ea91a78941", size = 217725, upload-time = "2025-11-18T13:32:49.22Z" }, - { url = "https://files.pythonhosted.org/packages/17/a7/3aa4144d3bcb719bf67b22d2d51c2d577bf801498c13cb08f64173e80497/coverage-7.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ccf3b2ede91decd2fb53ec73c1f949c3e034129d1e0b07798ff1d02ea0c8fa4a", size = 218098, upload-time = "2025-11-18T13:32:50.78Z" }, - { url = "https://files.pythonhosted.org/packages/fc/9c/b846bbc774ff81091a12a10203e70562c91ae71badda00c5ae5b613527b1/coverage-7.12.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b365adc70a6936c6b0582dc38746b33b2454148c02349345412c6e743efb646d", size = 249093, upload-time = "2025-11-18T13:32:52.554Z" }, - { url = "https://files.pythonhosted.org/packages/76/b6/67d7c0e1f400b32c883e9342de4a8c2ae7c1a0b57c5de87622b7262e2309/coverage-7.12.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bc13baf85cd8a4cfcf4a35c7bc9d795837ad809775f782f697bf630b7e200211", size = 251686, upload-time = "2025-11-18T13:32:54.862Z" }, - { url = "https://files.pythonhosted.org/packages/cc/75/b095bd4b39d49c3be4bffbb3135fea18a99a431c52dd7513637c0762fecb/coverage-7.12.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:099d11698385d572ceafb3288a5b80fe1fc58bf665b3f9d362389de488361d3d", size = 252930, upload-time = "2025-11-18T13:32:56.417Z" }, - { url = "https://files.pythonhosted.org/packages/6e/f3/466f63015c7c80550bead3093aacabf5380c1220a2a93c35d374cae8f762/coverage-7.12.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:473dc45d69694069adb7680c405fb1e81f60b2aff42c81e2f2c3feaf544d878c", size = 249296, upload-time = "2025-11-18T13:32:58.074Z" }, - { url = "https://files.pythonhosted.org/packages/27/86/eba2209bf2b7e28c68698fc13437519a295b2d228ba9e0ec91673e09fa92/coverage-7.12.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:583f9adbefd278e9de33c33d6846aa8f5d164fa49b47144180a0e037f0688bb9", size = 251068, upload-time = "2025-11-18T13:32:59.646Z" }, - { url = "https://files.pythonhosted.org/packages/ec/55/ca8ae7dbba962a3351f18940b359b94c6bafdd7757945fdc79ec9e452dc7/coverage-7.12.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b2089cc445f2dc0af6f801f0d1355c025b76c24481935303cf1af28f636688f0", size = 249034, upload-time = "2025-11-18T13:33:01.481Z" }, - { url = "https://files.pythonhosted.org/packages/7a/d7/39136149325cad92d420b023b5fd900dabdd1c3a0d1d5f148ef4a8cedef5/coverage-7.12.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:950411f1eb5d579999c5f66c62a40961f126fc71e5e14419f004471957b51508", size = 248853, upload-time = "2025-11-18T13:33:02.935Z" }, - { url = "https://files.pythonhosted.org/packages/fe/b6/76e1add8b87ef60e00643b0b7f8f7bb73d4bf5249a3be19ebefc5793dd25/coverage-7.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b1aab7302a87bafebfe76b12af681b56ff446dc6f32ed178ff9c092ca776e6bc", size = 250619, upload-time = "2025-11-18T13:33:04.336Z" }, - { url = "https://files.pythonhosted.org/packages/95/87/924c6dc64f9203f7a3c1832a6a0eee5a8335dbe5f1bdadcc278d6f1b4d74/coverage-7.12.0-cp313-cp313-win32.whl", hash = "sha256:d7e0d0303c13b54db495eb636bc2465b2fb8475d4c8bcec8fe4b5ca454dfbae8", size = 220261, upload-time = "2025-11-18T13:33:06.493Z" }, - { url = "https://files.pythonhosted.org/packages/91/77/dd4aff9af16ff776bf355a24d87eeb48fc6acde54c907cc1ea89b14a8804/coverage-7.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:ce61969812d6a98a981d147d9ac583a36ac7db7766f2e64a9d4d059c2fe29d07", size = 221072, upload-time = "2025-11-18T13:33:07.926Z" }, - { url = "https://files.pythonhosted.org/packages/70/49/5c9dc46205fef31b1b226a6e16513193715290584317fd4df91cdaf28b22/coverage-7.12.0-cp313-cp313-win_arm64.whl", hash = "sha256:bcec6f47e4cb8a4c2dc91ce507f6eefc6a1b10f58df32cdc61dff65455031dfc", size = 219702, upload-time = "2025-11-18T13:33:09.631Z" }, - { url = "https://files.pythonhosted.org/packages/9b/62/f87922641c7198667994dd472a91e1d9b829c95d6c29529ceb52132436ad/coverage-7.12.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:459443346509476170d553035e4a3eed7b860f4fe5242f02de1010501956ce87", size = 218420, upload-time = "2025-11-18T13:33:11.153Z" }, - { url = "https://files.pythonhosted.org/packages/85/dd/1cc13b2395ef15dbb27d7370a2509b4aee77890a464fb35d72d428f84871/coverage-7.12.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:04a79245ab2b7a61688958f7a855275997134bc84f4a03bc240cf64ff132abf6", size = 218773, upload-time = "2025-11-18T13:33:12.569Z" }, - { url = "https://files.pythonhosted.org/packages/74/40/35773cc4bb1e9d4658d4fb669eb4195b3151bef3bbd6f866aba5cd5dac82/coverage-7.12.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:09a86acaaa8455f13d6a99221d9654df249b33937b4e212b4e5a822065f12aa7", size = 260078, upload-time = "2025-11-18T13:33:14.037Z" }, - { url = "https://files.pythonhosted.org/packages/ec/ee/231bb1a6ffc2905e396557585ebc6bdc559e7c66708376d245a1f1d330fc/coverage-7.12.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:907e0df1b71ba77463687a74149c6122c3f6aac56c2510a5d906b2f368208560", size = 262144, upload-time = "2025-11-18T13:33:15.601Z" }, - { url = "https://files.pythonhosted.org/packages/28/be/32f4aa9f3bf0b56f3971001b56508352c7753915345d45fab4296a986f01/coverage-7.12.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9b57e2d0ddd5f0582bae5437c04ee71c46cd908e7bc5d4d0391f9a41e812dd12", size = 264574, upload-time = "2025-11-18T13:33:17.354Z" }, - { url = "https://files.pythonhosted.org/packages/68/7c/00489fcbc2245d13ab12189b977e0cf06ff3351cb98bc6beba8bd68c5902/coverage-7.12.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:58c1c6aa677f3a1411fe6fb28ec3a942e4f665df036a3608816e0847fad23296", size = 259298, upload-time = "2025-11-18T13:33:18.958Z" }, - { url = "https://files.pythonhosted.org/packages/96/b4/f0760d65d56c3bea95b449e02570d4abd2549dc784bf39a2d4721a2d8ceb/coverage-7.12.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4c589361263ab2953e3c4cd2a94db94c4ad4a8e572776ecfbad2389c626e4507", size = 262150, upload-time = "2025-11-18T13:33:20.644Z" }, - { url = "https://files.pythonhosted.org/packages/c5/71/9a9314df00f9326d78c1e5a910f520d599205907432d90d1c1b7a97aa4b1/coverage-7.12.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:91b810a163ccad2e43b1faa11d70d3cf4b6f3d83f9fd5f2df82a32d47b648e0d", size = 259763, upload-time = "2025-11-18T13:33:22.189Z" }, - { url = "https://files.pythonhosted.org/packages/10/34/01a0aceed13fbdf925876b9a15d50862eb8845454301fe3cdd1df08b2182/coverage-7.12.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:40c867af715f22592e0d0fb533a33a71ec9e0f73a6945f722a0c85c8c1cbe3a2", size = 258653, upload-time = "2025-11-18T13:33:24.239Z" }, - { url = "https://files.pythonhosted.org/packages/8d/04/81d8fd64928acf1574bbb0181f66901c6c1c6279c8ccf5f84259d2c68ae9/coverage-7.12.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:68b0d0a2d84f333de875666259dadf28cc67858bc8fd8b3f1eae84d3c2bec455", size = 260856, upload-time = "2025-11-18T13:33:26.365Z" }, - { url = "https://files.pythonhosted.org/packages/f2/76/fa2a37bfaeaf1f766a2d2360a25a5297d4fb567098112f6517475eee120b/coverage-7.12.0-cp313-cp313t-win32.whl", hash = "sha256:73f9e7fbd51a221818fd11b7090eaa835a353ddd59c236c57b2199486b116c6d", size = 220936, upload-time = "2025-11-18T13:33:28.165Z" }, - { url = "https://files.pythonhosted.org/packages/f9/52/60f64d932d555102611c366afb0eb434b34266b1d9266fc2fe18ab641c47/coverage-7.12.0-cp313-cp313t-win_amd64.whl", hash = "sha256:24cff9d1f5743f67db7ba46ff284018a6e9aeb649b67aa1e70c396aa1b7cb23c", size = 222001, upload-time = "2025-11-18T13:33:29.656Z" }, - { url = "https://files.pythonhosted.org/packages/77/df/c303164154a5a3aea7472bf323b7c857fed93b26618ed9fc5c2955566bb0/coverage-7.12.0-cp313-cp313t-win_arm64.whl", hash = "sha256:c87395744f5c77c866d0f5a43d97cc39e17c7f1cb0115e54a2fe67ca75c5d14d", size = 220273, upload-time = "2025-11-18T13:33:31.415Z" }, - { url = "https://files.pythonhosted.org/packages/bf/2e/fc12db0883478d6e12bbd62d481210f0c8daf036102aa11434a0c5755825/coverage-7.12.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a1c59b7dc169809a88b21a936eccf71c3895a78f5592051b1af8f4d59c2b4f92", size = 217777, upload-time = "2025-11-18T13:33:32.86Z" }, - { url = "https://files.pythonhosted.org/packages/1f/c1/ce3e525d223350c6ec16b9be8a057623f54226ef7f4c2fee361ebb6a02b8/coverage-7.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8787b0f982e020adb732b9f051f3e49dd5054cebbc3f3432061278512a2b1360", size = 218100, upload-time = "2025-11-18T13:33:34.532Z" }, - { url = "https://files.pythonhosted.org/packages/15/87/113757441504aee3808cb422990ed7c8bcc2d53a6779c66c5adef0942939/coverage-7.12.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5ea5a9f7dc8877455b13dd1effd3202e0bca72f6f3ab09f9036b1bcf728f69ac", size = 249151, upload-time = "2025-11-18T13:33:36.135Z" }, - { url = "https://files.pythonhosted.org/packages/d9/1d/9529d9bd44049b6b05bb319c03a3a7e4b0a8a802d28fa348ad407e10706d/coverage-7.12.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fdba9f15849534594f60b47c9a30bc70409b54947319a7c4fd0e8e3d8d2f355d", size = 251667, upload-time = "2025-11-18T13:33:37.996Z" }, - { url = "https://files.pythonhosted.org/packages/11/bb/567e751c41e9c03dc29d3ce74b8c89a1e3396313e34f255a2a2e8b9ebb56/coverage-7.12.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a00594770eb715854fb1c57e0dea08cce6720cfbc531accdb9850d7c7770396c", size = 253003, upload-time = "2025-11-18T13:33:39.553Z" }, - { url = "https://files.pythonhosted.org/packages/e4/b3/c2cce2d8526a02fb9e9ca14a263ca6fc074449b33a6afa4892838c903528/coverage-7.12.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5560c7e0d82b42eb1951e4f68f071f8017c824ebfd5a6ebe42c60ac16c6c2434", size = 249185, upload-time = "2025-11-18T13:33:42.086Z" }, - { url = "https://files.pythonhosted.org/packages/0e/a7/967f93bb66e82c9113c66a8d0b65ecf72fc865adfba5a145f50c7af7e58d/coverage-7.12.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d6c2e26b481c9159c2773a37947a9718cfdc58893029cdfb177531793e375cfc", size = 251025, upload-time = "2025-11-18T13:33:43.634Z" }, - { url = "https://files.pythonhosted.org/packages/b9/b2/f2f6f56337bc1af465d5b2dc1ee7ee2141b8b9272f3bf6213fcbc309a836/coverage-7.12.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:6e1a8c066dabcde56d5d9fed6a66bc19a2883a3fe051f0c397a41fc42aedd4cc", size = 248979, upload-time = "2025-11-18T13:33:46.04Z" }, - { url = "https://files.pythonhosted.org/packages/f4/7a/bf4209f45a4aec09d10a01a57313a46c0e0e8f4c55ff2965467d41a92036/coverage-7.12.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:f7ba9da4726e446d8dd8aae5a6cd872511184a5d861de80a86ef970b5dacce3e", size = 248800, upload-time = "2025-11-18T13:33:47.546Z" }, - { url = "https://files.pythonhosted.org/packages/b8/b7/1e01b8696fb0521810f60c5bbebf699100d6754183e6cc0679bf2ed76531/coverage-7.12.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e0f483ab4f749039894abaf80c2f9e7ed77bbf3c737517fb88c8e8e305896a17", size = 250460, upload-time = "2025-11-18T13:33:49.537Z" }, - { url = "https://files.pythonhosted.org/packages/71/ae/84324fb9cb46c024760e706353d9b771a81b398d117d8c1fe010391c186f/coverage-7.12.0-cp314-cp314-win32.whl", hash = "sha256:76336c19a9ef4a94b2f8dc79f8ac2da3f193f625bb5d6f51a328cd19bfc19933", size = 220533, upload-time = "2025-11-18T13:33:51.16Z" }, - { url = "https://files.pythonhosted.org/packages/e2/71/1033629deb8460a8f97f83e6ac4ca3b93952e2b6f826056684df8275e015/coverage-7.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:7c1059b600aec6ef090721f8f633f60ed70afaffe8ecab85b59df748f24b31fe", size = 221348, upload-time = "2025-11-18T13:33:52.776Z" }, - { url = "https://files.pythonhosted.org/packages/0a/5f/ac8107a902f623b0c251abdb749be282dc2ab61854a8a4fcf49e276fce2f/coverage-7.12.0-cp314-cp314-win_arm64.whl", hash = "sha256:172cf3a34bfef42611963e2b661302a8931f44df31629e5b1050567d6b90287d", size = 219922, upload-time = "2025-11-18T13:33:54.316Z" }, - { url = "https://files.pythonhosted.org/packages/79/6e/f27af2d4da367f16077d21ef6fe796c874408219fa6dd3f3efe7751bd910/coverage-7.12.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:aa7d48520a32cb21c7a9b31f81799e8eaec7239db36c3b670be0fa2403828d1d", size = 218511, upload-time = "2025-11-18T13:33:56.343Z" }, - { url = "https://files.pythonhosted.org/packages/67/dd/65fd874aa460c30da78f9d259400d8e6a4ef457d61ab052fd248f0050558/coverage-7.12.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:90d58ac63bc85e0fb919f14d09d6caa63f35a5512a2205284b7816cafd21bb03", size = 218771, upload-time = "2025-11-18T13:33:57.966Z" }, - { url = "https://files.pythonhosted.org/packages/55/e0/7c6b71d327d8068cb79c05f8f45bf1b6145f7a0de23bbebe63578fe5240a/coverage-7.12.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ca8ecfa283764fdda3eae1bdb6afe58bf78c2c3ec2b2edcb05a671f0bba7b3f9", size = 260151, upload-time = "2025-11-18T13:33:59.597Z" }, - { url = "https://files.pythonhosted.org/packages/49/ce/4697457d58285b7200de6b46d606ea71066c6e674571a946a6ea908fb588/coverage-7.12.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:874fe69a0785d96bd066059cd4368022cebbec1a8958f224f0016979183916e6", size = 262257, upload-time = "2025-11-18T13:34:01.166Z" }, - { url = "https://files.pythonhosted.org/packages/2f/33/acbc6e447aee4ceba88c15528dbe04a35fb4d67b59d393d2e0d6f1e242c1/coverage-7.12.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5b3c889c0b8b283a24d721a9eabc8ccafcfc3aebf167e4cd0d0e23bf8ec4e339", size = 264671, upload-time = "2025-11-18T13:34:02.795Z" }, - { url = "https://files.pythonhosted.org/packages/87/ec/e2822a795c1ed44d569980097be839c5e734d4c0c1119ef8e0a073496a30/coverage-7.12.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8bb5b894b3ec09dcd6d3743229dc7f2c42ef7787dc40596ae04c0edda487371e", size = 259231, upload-time = "2025-11-18T13:34:04.397Z" }, - { url = "https://files.pythonhosted.org/packages/72/c5/a7ec5395bb4a49c9b7ad97e63f0c92f6bf4a9e006b1393555a02dae75f16/coverage-7.12.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:79a44421cd5fba96aa57b5e3b5a4d3274c449d4c622e8f76882d76635501fd13", size = 262137, upload-time = "2025-11-18T13:34:06.068Z" }, - { url = "https://files.pythonhosted.org/packages/67/0c/02c08858b764129f4ecb8e316684272972e60777ae986f3865b10940bdd6/coverage-7.12.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:33baadc0efd5c7294f436a632566ccc1f72c867f82833eb59820ee37dc811c6f", size = 259745, upload-time = "2025-11-18T13:34:08.04Z" }, - { url = "https://files.pythonhosted.org/packages/5a/04/4fd32b7084505f3829a8fe45c1a74a7a728cb251aaadbe3bec04abcef06d/coverage-7.12.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:c406a71f544800ef7e9e0000af706b88465f3573ae8b8de37e5f96c59f689ad1", size = 258570, upload-time = "2025-11-18T13:34:09.676Z" }, - { url = "https://files.pythonhosted.org/packages/48/35/2365e37c90df4f5342c4fa202223744119fe31264ee2924f09f074ea9b6d/coverage-7.12.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e71bba6a40883b00c6d571599b4627f50c360b3d0d02bfc658168936be74027b", size = 260899, upload-time = "2025-11-18T13:34:11.259Z" }, - { url = "https://files.pythonhosted.org/packages/05/56/26ab0464ca733fa325e8e71455c58c1c374ce30f7c04cebb88eabb037b18/coverage-7.12.0-cp314-cp314t-win32.whl", hash = "sha256:9157a5e233c40ce6613dead4c131a006adfda70e557b6856b97aceed01b0e27a", size = 221313, upload-time = "2025-11-18T13:34:12.863Z" }, - { url = "https://files.pythonhosted.org/packages/da/1c/017a3e1113ed34d998b27d2c6dba08a9e7cb97d362f0ec988fcd873dcf81/coverage-7.12.0-cp314-cp314t-win_amd64.whl", hash = "sha256:e84da3a0fd233aeec797b981c51af1cabac74f9bd67be42458365b30d11b5291", size = 222423, upload-time = "2025-11-18T13:34:15.14Z" }, - { url = "https://files.pythonhosted.org/packages/4c/36/bcc504fdd5169301b52568802bb1b9cdde2e27a01d39fbb3b4b508ab7c2c/coverage-7.12.0-cp314-cp314t-win_arm64.whl", hash = "sha256:01d24af36fedda51c2b1aca56e4330a3710f83b02a5ff3743a6b015ffa7c9384", size = 220459, upload-time = "2025-11-18T13:34:17.222Z" }, - { url = "https://files.pythonhosted.org/packages/ce/a3/43b749004e3c09452e39bb56347a008f0a0668aad37324a99b5c8ca91d9e/coverage-7.12.0-py3-none-any.whl", hash = "sha256:159d50c0b12e060b15ed3d39f87ed43d4f7f7ad40b8a534f4dd331adbb51104a", size = 209503, upload-time = "2025-11-18T13:34:18.892Z" }, -] - -[package.optional-dependencies] -toml = [ - { name = "tomli", marker = "python_full_version <= '3.11'" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/89/26/4a96807b193b011588099c3b5c89fbb05294e5b90e71018e065465f34eb6/coverage-7.12.0.tar.gz" + hash = "sha256:fc11e0a4e372cb5f282f16ef90d4a585034050ccda536451901abfb19a57f40c" + size = 819_341 + upload-time = "2025-11-18T13:34:20.766Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/26/4a/0dc3de1c172d35abe512332cfdcc43211b6ebce629e4cc42e6cd25ed8f4d/coverage-7.12.0-cp310-cp310-macosx_10_9_x86_64.whl" + hash = "sha256:32b75c2ba3f324ee37af3ccee5b30458038c50b349ad9b88cee85096132a575b" + size = 217_409 + upload-time = "2025-11-18T13:31:53.122Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/01/c3/086198b98db0109ad4f84241e8e9ea7e5fb2db8c8ffb787162d40c26cc76/coverage-7.12.0-cp310-cp310-macosx_11_0_arm64.whl" + hash = "sha256:cb2a1b6ab9fe833714a483a915de350abc624a37149649297624c8d57add089c" + size = 217_927 + upload-time = "2025-11-18T13:31:54.458Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/5d/5f/34614dbf5ce0420828fc6c6f915126a0fcb01e25d16cf141bf5361e6aea6/coverage-7.12.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl" + hash = "sha256:5734b5d913c3755e72f70bf6cc37a0518d4f4745cde760c5d8e12005e62f9832" + size = 244_678 + upload-time = "2025-11-18T13:31:55.805Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/55/7b/6b26fb32e8e4a6989ac1d40c4e132b14556131493b1d06bc0f2be169c357/coverage-7.12.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl" + hash = "sha256:b527a08cdf15753279b7afb2339a12073620b761d79b81cbe2cdebdb43d90daa" + size = 246_507 + upload-time = "2025-11-18T13:31:57.05Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/06/42/7d70e6603d3260199b90fb48b537ca29ac183d524a65cc31366b2e905fad/coverage-7.12.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + hash = "sha256:9bb44c889fb68004e94cab71f6a021ec83eac9aeabdbb5a5a88821ec46e1da73" + size = 248_366 + upload-time = "2025-11-18T13:31:58.362Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/2d/4a/d86b837923878424c72458c5b25e899a3c5ca73e663082a915f5b3c4d749/coverage-7.12.0-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl" + hash = "sha256:4b59b501455535e2e5dde5881739897967b272ba25988c89145c12d772810ccb" + size = 245_366 + upload-time = "2025-11-18T13:31:59.572Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/e6/c2/2adec557e0aa9721875f06ced19730fdb7fc58e31b02b5aa56f2ebe4944d/coverage-7.12.0-cp310-cp310-musllinux_1_2_aarch64.whl" + hash = "sha256:d8842f17095b9868a05837b7b1b73495293091bed870e099521ada176aa3e00e" + size = 246_408 + upload-time = "2025-11-18T13:32:00.784Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/5a/4b/8bd1f1148260df11c618e535fdccd1e5aaf646e55b50759006a4f41d8a26/coverage-7.12.0-cp310-cp310-musllinux_1_2_i686.whl" + hash = "sha256:c5a6f20bf48b8866095c6820641e7ffbe23f2ac84a2efc218d91235e404c7777" + size = 244_416 + upload-time = "2025-11-18T13:32:01.963Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/0e/13/3a248dd6a83df90414c54a4e121fd081fb20602ca43955fbe1d60e2312a9/coverage-7.12.0-cp310-cp310-musllinux_1_2_riscv64.whl" + hash = "sha256:5f3738279524e988d9da2893f307c2093815c623f8d05a8f79e3eff3a7a9e553" + size = 244_681 + upload-time = "2025-11-18T13:32:03.408Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/76/30/aa833827465a5e8c938935f5d91ba055f70516941078a703740aaf1aa41f/coverage-7.12.0-cp310-cp310-musllinux_1_2_x86_64.whl" + hash = "sha256:e0d68c1f7eabbc8abe582d11fa393ea483caf4f44b0af86881174769f185c94d" + size = 245_300 + upload-time = "2025-11-18T13:32:04.686Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/38/24/f85b3843af1370fb3739fa7571819b71243daa311289b31214fe3e8c9d68/coverage-7.12.0-cp310-cp310-win32.whl" + hash = "sha256:7670d860e18b1e3ee5930b17a7d55ae6287ec6e55d9799982aa103a2cc1fa2ef" + size = 220_008 + upload-time = "2025-11-18T13:32:05.806Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/3a/a2/c7da5b9566f7164db9eefa133d17761ecb2c2fde9385d754e5b5c80f710d/coverage-7.12.0-cp310-cp310-win_amd64.whl" + hash = "sha256:f999813dddeb2a56aab5841e687b68169da0d3f6fc78ccf50952fa2463746022" + size = 220_943 + upload-time = "2025-11-18T13:32:07.166Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/5a/0c/0dfe7f0487477d96432e4815537263363fb6dd7289743a796e8e51eabdf2/coverage-7.12.0-cp311-cp311-macosx_10_9_x86_64.whl" + hash = "sha256:aa124a3683d2af98bd9d9c2bfa7a5076ca7e5ab09fdb96b81fa7d89376ae928f" + size = 217_535 + upload-time = "2025-11-18T13:32:08.812Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/9b/f5/f9a4a053a5bbff023d3bec259faac8f11a1e5a6479c2ccf586f910d8dac7/coverage-7.12.0-cp311-cp311-macosx_11_0_arm64.whl" + hash = "sha256:d93fbf446c31c0140208dcd07c5d882029832e8ed7891a39d6d44bd65f2316c3" + size = 218_044 + upload-time = "2025-11-18T13:32:10.329Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/95/c5/84fc3697c1fa10cd8571919bf9693f693b7373278daaf3b73e328d502bc8/coverage-7.12.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl" + hash = "sha256:52ca620260bd8cd6027317bdd8b8ba929be1d741764ee765b42c4d79a408601e" + size = 248_440 + upload-time = "2025-11-18T13:32:12.536Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/f4/36/2d93fbf6a04670f3874aed397d5a5371948a076e3249244a9e84fb0e02d6/coverage-7.12.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl" + hash = "sha256:f3433ffd541380f3a0e423cff0f4926d55b0cc8c1d160fdc3be24a4c03aa65f7" + size = 250_361 + upload-time = "2025-11-18T13:32:13.852Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/5d/49/66dc65cc456a6bfc41ea3d0758c4afeaa4068a2b2931bf83be6894cf1058/coverage-7.12.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + hash = "sha256:f7bbb321d4adc9f65e402c677cd1c8e4c2d0105d3ce285b51b4d87f1d5db5245" + size = 252_472 + upload-time = "2025-11-18T13:32:15.068Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/35/1f/ebb8a18dffd406db9fcd4b3ae42254aedcaf612470e8712f12041325930f/coverage-7.12.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl" + hash = "sha256:22a7aade354a72dff3b59c577bfd18d6945c61f97393bc5fb7bd293a4237024b" + size = 248_592 + upload-time = "2025-11-18T13:32:16.328Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/da/a8/67f213c06e5ea3b3d4980df7dc344d7fea88240b5fe878a5dcbdfe0e2315/coverage-7.12.0-cp311-cp311-musllinux_1_2_aarch64.whl" + hash = "sha256:3ff651dcd36d2fea66877cd4a82de478004c59b849945446acb5baf9379a1b64" + size = 250_167 + upload-time = "2025-11-18T13:32:17.687Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/f0/00/e52aef68154164ea40cc8389c120c314c747fe63a04b013a5782e989b77f/coverage-7.12.0-cp311-cp311-musllinux_1_2_i686.whl" + hash = "sha256:31b8b2e38391a56e3cea39d22a23faaa7c3fc911751756ef6d2621d2a9daf742" + size = 248_238 + upload-time = "2025-11-18T13:32:19.2Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/1f/a4/4d88750bcf9d6d66f77865e5a05a20e14db44074c25fd22519777cb69025/coverage-7.12.0-cp311-cp311-musllinux_1_2_riscv64.whl" + hash = "sha256:297bc2da28440f5ae51c845a47c8175a4db0553a53827886e4fb25c66633000c" + size = 247_964 + upload-time = "2025-11-18T13:32:21.027Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/a7/6b/b74693158899d5b47b0bf6238d2c6722e20ba749f86b74454fac0696bb00/coverage-7.12.0-cp311-cp311-musllinux_1_2_x86_64.whl" + hash = "sha256:6ff7651cc01a246908eac162a6a86fc0dbab6de1ad165dfb9a1e2ec660b44984" + size = 248_862 + upload-time = "2025-11-18T13:32:22.304Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/18/de/6af6730227ce0e8ade307b1cc4a08e7f51b419a78d02083a86c04ccceb29/coverage-7.12.0-cp311-cp311-win32.whl" + hash = "sha256:313672140638b6ddb2c6455ddeda41c6a0b208298034544cfca138978c6baed6" + size = 220_033 + upload-time = "2025-11-18T13:32:23.714Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/e2/a1/e7f63021a7c4fe20994359fcdeae43cbef4a4d0ca36a5a1639feeea5d9e1/coverage-7.12.0-cp311-cp311-win_amd64.whl" + hash = "sha256:a1783ed5bd0d5938d4435014626568dc7f93e3cb99bc59188cc18857c47aa3c4" + size = 220_966 + upload-time = "2025-11-18T13:32:25.599Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/77/e8/deae26453f37c20c3aa0c4433a1e32cdc169bf415cce223a693117aa3ddd/coverage-7.12.0-cp311-cp311-win_arm64.whl" + hash = "sha256:4648158fd8dd9381b5847622df1c90ff314efbfc1df4550092ab6013c238a5fc" + size = 219_637 + upload-time = "2025-11-18T13:32:27.265Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/02/bf/638c0427c0f0d47638242e2438127f3c8ee3cfc06c7fdeb16778ed47f836/coverage-7.12.0-cp312-cp312-macosx_10_13_x86_64.whl" + hash = "sha256:29644c928772c78512b48e14156b81255000dcfd4817574ff69def189bcb3647" + size = 217_704 + upload-time = "2025-11-18T13:32:28.906Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/08/e1/706fae6692a66c2d6b871a608bbde0da6281903fa0e9f53a39ed441da36a/coverage-7.12.0-cp312-cp312-macosx_11_0_arm64.whl" + hash = "sha256:8638cbb002eaa5d7c8d04da667813ce1067080b9a91099801a0053086e52b736" + size = 218_064 + upload-time = "2025-11-18T13:32:30.161Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/a9/8b/eb0231d0540f8af3ffda39720ff43cb91926489d01524e68f60e961366e4/coverage-7.12.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl" + hash = "sha256:083631eeff5eb9992c923e14b810a179798bb598e6a0dd60586819fc23be6e60" + size = 249_560 + upload-time = "2025-11-18T13:32:31.835Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/e9/a1/67fb52af642e974d159b5b379e4d4c59d0ebe1288677fbd04bbffe665a82/coverage-7.12.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl" + hash = "sha256:99d5415c73ca12d558e07776bd957c4222c687b9f1d26fa0e1b57e3598bdcde8" + size = 252_318 + upload-time = "2025-11-18T13:32:33.178Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/41/e5/38228f31b2c7665ebf9bdfdddd7a184d56450755c7e43ac721c11a4b8dab/coverage-7.12.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + hash = "sha256:e949ebf60c717c3df63adb4a1a366c096c8d7fd8472608cd09359e1bd48ef59f" + size = 253_403 + upload-time = "2025-11-18T13:32:34.45Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/ec/4b/df78e4c8188f9960684267c5a4897836f3f0f20a20c51606ee778a1d9749/coverage-7.12.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl" + hash = "sha256:6d907ddccbca819afa2cd014bc69983b146cca2735a0b1e6259b2a6c10be1e70" + size = 249_984 + upload-time = "2025-11-18T13:32:35.747Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/ba/51/bb163933d195a345c6f63eab9e55743413d064c291b6220df754075c2769/coverage-7.12.0-cp312-cp312-musllinux_1_2_aarch64.whl" + hash = "sha256:b1518ecbad4e6173f4c6e6c4a46e49555ea5679bf3feda5edb1b935c7c44e8a0" + size = 251_339 + upload-time = "2025-11-18T13:32:37.352Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/15/40/c9b29cdb8412c837cdcbc2cfa054547dd83affe6cbbd4ce4fdb92b6ba7d1/coverage-7.12.0-cp312-cp312-musllinux_1_2_i686.whl" + hash = "sha256:51777647a749abdf6f6fd8c7cffab12de68ab93aab15efc72fbbb83036c2a068" + size = 249_489 + upload-time = "2025-11-18T13:32:39.212Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/c8/da/b3131e20ba07a0de4437a50ef3b47840dfabf9293675b0cd5c2c7f66dd61/coverage-7.12.0-cp312-cp312-musllinux_1_2_riscv64.whl" + hash = "sha256:42435d46d6461a3b305cdfcad7cdd3248787771f53fe18305548cba474e6523b" + size = 249_070 + upload-time = "2025-11-18T13:32:40.598Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/70/81/b653329b5f6302c08d683ceff6785bc60a34be9ae92a5c7b63ee7ee7acec/coverage-7.12.0-cp312-cp312-musllinux_1_2_x86_64.whl" + hash = "sha256:5bcead88c8423e1855e64b8057d0544e33e4080b95b240c2a355334bb7ced937" + size = 250_929 + upload-time = "2025-11-18T13:32:42.915Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/a3/00/250ac3bca9f252a5fb1338b5ad01331ebb7b40223f72bef5b1b2cb03aa64/coverage-7.12.0-cp312-cp312-win32.whl" + hash = "sha256:dcbb630ab034e86d2a0f79aefd2be07e583202f41e037602d438c80044957baa" + size = 220_241 + upload-time = "2025-11-18T13:32:44.665Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/64/1c/77e79e76d37ce83302f6c21980b45e09f8aa4551965213a10e62d71ce0ab/coverage-7.12.0-cp312-cp312-win_amd64.whl" + hash = "sha256:2fd8354ed5d69775ac42986a691fbf68b4084278710cee9d7c3eaa0c28fa982a" + size = 221_051 + upload-time = "2025-11-18T13:32:46.008Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/31/f5/641b8a25baae564f9e52cac0e2667b123de961985709a004e287ee7663cc/coverage-7.12.0-cp312-cp312-win_arm64.whl" + hash = "sha256:737c3814903be30695b2de20d22bcc5428fdae305c61ba44cdc8b3252984c49c" + size = 219_692 + upload-time = "2025-11-18T13:32:47.372Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/b8/14/771700b4048774e48d2c54ed0c674273702713c9ee7acdfede40c2666747/coverage-7.12.0-cp313-cp313-macosx_10_13_x86_64.whl" + hash = "sha256:47324fffca8d8eae7e185b5bb20c14645f23350f870c1649003618ea91a78941" + size = 217_725 + upload-time = "2025-11-18T13:32:49.22Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/17/a7/3aa4144d3bcb719bf67b22d2d51c2d577bf801498c13cb08f64173e80497/coverage-7.12.0-cp313-cp313-macosx_11_0_arm64.whl" + hash = "sha256:ccf3b2ede91decd2fb53ec73c1f949c3e034129d1e0b07798ff1d02ea0c8fa4a" + size = 218_098 + upload-time = "2025-11-18T13:32:50.78Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/fc/9c/b846bbc774ff81091a12a10203e70562c91ae71badda00c5ae5b613527b1/coverage-7.12.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl" + hash = "sha256:b365adc70a6936c6b0582dc38746b33b2454148c02349345412c6e743efb646d" + size = 249_093 + upload-time = "2025-11-18T13:32:52.554Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/76/b6/67d7c0e1f400b32c883e9342de4a8c2ae7c1a0b57c5de87622b7262e2309/coverage-7.12.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl" + hash = "sha256:bc13baf85cd8a4cfcf4a35c7bc9d795837ad809775f782f697bf630b7e200211" + size = 251_686 + upload-time = "2025-11-18T13:32:54.862Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/cc/75/b095bd4b39d49c3be4bffbb3135fea18a99a431c52dd7513637c0762fecb/coverage-7.12.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + hash = "sha256:099d11698385d572ceafb3288a5b80fe1fc58bf665b3f9d362389de488361d3d" + size = 252_930 + upload-time = "2025-11-18T13:32:56.417Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/6e/f3/466f63015c7c80550bead3093aacabf5380c1220a2a93c35d374cae8f762/coverage-7.12.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl" + hash = "sha256:473dc45d69694069adb7680c405fb1e81f60b2aff42c81e2f2c3feaf544d878c" + size = 249_296 + upload-time = "2025-11-18T13:32:58.074Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/27/86/eba2209bf2b7e28c68698fc13437519a295b2d228ba9e0ec91673e09fa92/coverage-7.12.0-cp313-cp313-musllinux_1_2_aarch64.whl" + hash = "sha256:583f9adbefd278e9de33c33d6846aa8f5d164fa49b47144180a0e037f0688bb9" + size = 251_068 + upload-time = "2025-11-18T13:32:59.646Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/ec/55/ca8ae7dbba962a3351f18940b359b94c6bafdd7757945fdc79ec9e452dc7/coverage-7.12.0-cp313-cp313-musllinux_1_2_i686.whl" + hash = "sha256:b2089cc445f2dc0af6f801f0d1355c025b76c24481935303cf1af28f636688f0" + size = 249_034 + upload-time = "2025-11-18T13:33:01.481Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/7a/d7/39136149325cad92d420b023b5fd900dabdd1c3a0d1d5f148ef4a8cedef5/coverage-7.12.0-cp313-cp313-musllinux_1_2_riscv64.whl" + hash = "sha256:950411f1eb5d579999c5f66c62a40961f126fc71e5e14419f004471957b51508" + size = 248_853 + upload-time = "2025-11-18T13:33:02.935Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/fe/b6/76e1add8b87ef60e00643b0b7f8f7bb73d4bf5249a3be19ebefc5793dd25/coverage-7.12.0-cp313-cp313-musllinux_1_2_x86_64.whl" + hash = "sha256:b1aab7302a87bafebfe76b12af681b56ff446dc6f32ed178ff9c092ca776e6bc" + size = 250_619 + upload-time = "2025-11-18T13:33:04.336Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/95/87/924c6dc64f9203f7a3c1832a6a0eee5a8335dbe5f1bdadcc278d6f1b4d74/coverage-7.12.0-cp313-cp313-win32.whl" + hash = "sha256:d7e0d0303c13b54db495eb636bc2465b2fb8475d4c8bcec8fe4b5ca454dfbae8" + size = 220_261 + upload-time = "2025-11-18T13:33:06.493Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/91/77/dd4aff9af16ff776bf355a24d87eeb48fc6acde54c907cc1ea89b14a8804/coverage-7.12.0-cp313-cp313-win_amd64.whl" + hash = "sha256:ce61969812d6a98a981d147d9ac583a36ac7db7766f2e64a9d4d059c2fe29d07" + size = 221_072 + upload-time = "2025-11-18T13:33:07.926Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/70/49/5c9dc46205fef31b1b226a6e16513193715290584317fd4df91cdaf28b22/coverage-7.12.0-cp313-cp313-win_arm64.whl" + hash = "sha256:bcec6f47e4cb8a4c2dc91ce507f6eefc6a1b10f58df32cdc61dff65455031dfc" + size = 219_702 + upload-time = "2025-11-18T13:33:09.631Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/9b/62/f87922641c7198667994dd472a91e1d9b829c95d6c29529ceb52132436ad/coverage-7.12.0-cp313-cp313t-macosx_10_13_x86_64.whl" + hash = "sha256:459443346509476170d553035e4a3eed7b860f4fe5242f02de1010501956ce87" + size = 218_420 + upload-time = "2025-11-18T13:33:11.153Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/85/dd/1cc13b2395ef15dbb27d7370a2509b4aee77890a464fb35d72d428f84871/coverage-7.12.0-cp313-cp313t-macosx_11_0_arm64.whl" + hash = "sha256:04a79245ab2b7a61688958f7a855275997134bc84f4a03bc240cf64ff132abf6" + size = 218_773 + upload-time = "2025-11-18T13:33:12.569Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/74/40/35773cc4bb1e9d4658d4fb669eb4195b3151bef3bbd6f866aba5cd5dac82/coverage-7.12.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl" + hash = "sha256:09a86acaaa8455f13d6a99221d9654df249b33937b4e212b4e5a822065f12aa7" + size = 260_078 + upload-time = "2025-11-18T13:33:14.037Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/ec/ee/231bb1a6ffc2905e396557585ebc6bdc559e7c66708376d245a1f1d330fc/coverage-7.12.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl" + hash = "sha256:907e0df1b71ba77463687a74149c6122c3f6aac56c2510a5d906b2f368208560" + size = 262_144 + upload-time = "2025-11-18T13:33:15.601Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/28/be/32f4aa9f3bf0b56f3971001b56508352c7753915345d45fab4296a986f01/coverage-7.12.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + hash = "sha256:9b57e2d0ddd5f0582bae5437c04ee71c46cd908e7bc5d4d0391f9a41e812dd12" + size = 264_574 + upload-time = "2025-11-18T13:33:17.354Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/68/7c/00489fcbc2245d13ab12189b977e0cf06ff3351cb98bc6beba8bd68c5902/coverage-7.12.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl" + hash = "sha256:58c1c6aa677f3a1411fe6fb28ec3a942e4f665df036a3608816e0847fad23296" + size = 259_298 + upload-time = "2025-11-18T13:33:18.958Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/96/b4/f0760d65d56c3bea95b449e02570d4abd2549dc784bf39a2d4721a2d8ceb/coverage-7.12.0-cp313-cp313t-musllinux_1_2_aarch64.whl" + hash = "sha256:4c589361263ab2953e3c4cd2a94db94c4ad4a8e572776ecfbad2389c626e4507" + size = 262_150 + upload-time = "2025-11-18T13:33:20.644Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/c5/71/9a9314df00f9326d78c1e5a910f520d599205907432d90d1c1b7a97aa4b1/coverage-7.12.0-cp313-cp313t-musllinux_1_2_i686.whl" + hash = "sha256:91b810a163ccad2e43b1faa11d70d3cf4b6f3d83f9fd5f2df82a32d47b648e0d" + size = 259_763 + upload-time = "2025-11-18T13:33:22.189Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/10/34/01a0aceed13fbdf925876b9a15d50862eb8845454301fe3cdd1df08b2182/coverage-7.12.0-cp313-cp313t-musllinux_1_2_riscv64.whl" + hash = "sha256:40c867af715f22592e0d0fb533a33a71ec9e0f73a6945f722a0c85c8c1cbe3a2" + size = 258_653 + upload-time = "2025-11-18T13:33:24.239Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/8d/04/81d8fd64928acf1574bbb0181f66901c6c1c6279c8ccf5f84259d2c68ae9/coverage-7.12.0-cp313-cp313t-musllinux_1_2_x86_64.whl" + hash = "sha256:68b0d0a2d84f333de875666259dadf28cc67858bc8fd8b3f1eae84d3c2bec455" + size = 260_856 + upload-time = "2025-11-18T13:33:26.365Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/f2/76/fa2a37bfaeaf1f766a2d2360a25a5297d4fb567098112f6517475eee120b/coverage-7.12.0-cp313-cp313t-win32.whl" + hash = "sha256:73f9e7fbd51a221818fd11b7090eaa835a353ddd59c236c57b2199486b116c6d" + size = 220_936 + upload-time = "2025-11-18T13:33:28.165Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/f9/52/60f64d932d555102611c366afb0eb434b34266b1d9266fc2fe18ab641c47/coverage-7.12.0-cp313-cp313t-win_amd64.whl" + hash = "sha256:24cff9d1f5743f67db7ba46ff284018a6e9aeb649b67aa1e70c396aa1b7cb23c" + size = 222_001 + upload-time = "2025-11-18T13:33:29.656Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/77/df/c303164154a5a3aea7472bf323b7c857fed93b26618ed9fc5c2955566bb0/coverage-7.12.0-cp313-cp313t-win_arm64.whl" + hash = "sha256:c87395744f5c77c866d0f5a43d97cc39e17c7f1cb0115e54a2fe67ca75c5d14d" + size = 220_273 + upload-time = "2025-11-18T13:33:31.415Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/bf/2e/fc12db0883478d6e12bbd62d481210f0c8daf036102aa11434a0c5755825/coverage-7.12.0-cp314-cp314-macosx_10_15_x86_64.whl" + hash = "sha256:a1c59b7dc169809a88b21a936eccf71c3895a78f5592051b1af8f4d59c2b4f92" + size = 217_777 + upload-time = "2025-11-18T13:33:32.86Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/1f/c1/ce3e525d223350c6ec16b9be8a057623f54226ef7f4c2fee361ebb6a02b8/coverage-7.12.0-cp314-cp314-macosx_11_0_arm64.whl" + hash = "sha256:8787b0f982e020adb732b9f051f3e49dd5054cebbc3f3432061278512a2b1360" + size = 218_100 + upload-time = "2025-11-18T13:33:34.532Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/15/87/113757441504aee3808cb422990ed7c8bcc2d53a6779c66c5adef0942939/coverage-7.12.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl" + hash = "sha256:5ea5a9f7dc8877455b13dd1effd3202e0bca72f6f3ab09f9036b1bcf728f69ac" + size = 249_151 + upload-time = "2025-11-18T13:33:36.135Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/d9/1d/9529d9bd44049b6b05bb319c03a3a7e4b0a8a802d28fa348ad407e10706d/coverage-7.12.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl" + hash = "sha256:fdba9f15849534594f60b47c9a30bc70409b54947319a7c4fd0e8e3d8d2f355d" + size = 251_667 + upload-time = "2025-11-18T13:33:37.996Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/11/bb/567e751c41e9c03dc29d3ce74b8c89a1e3396313e34f255a2a2e8b9ebb56/coverage-7.12.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + hash = "sha256:a00594770eb715854fb1c57e0dea08cce6720cfbc531accdb9850d7c7770396c" + size = 253_003 + upload-time = "2025-11-18T13:33:39.553Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/e4/b3/c2cce2d8526a02fb9e9ca14a263ca6fc074449b33a6afa4892838c903528/coverage-7.12.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl" + hash = "sha256:5560c7e0d82b42eb1951e4f68f071f8017c824ebfd5a6ebe42c60ac16c6c2434" + size = 249_185 + upload-time = "2025-11-18T13:33:42.086Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/0e/a7/967f93bb66e82c9113c66a8d0b65ecf72fc865adfba5a145f50c7af7e58d/coverage-7.12.0-cp314-cp314-musllinux_1_2_aarch64.whl" + hash = "sha256:d6c2e26b481c9159c2773a37947a9718cfdc58893029cdfb177531793e375cfc" + size = 251_025 + upload-time = "2025-11-18T13:33:43.634Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/b9/b2/f2f6f56337bc1af465d5b2dc1ee7ee2141b8b9272f3bf6213fcbc309a836/coverage-7.12.0-cp314-cp314-musllinux_1_2_i686.whl" + hash = "sha256:6e1a8c066dabcde56d5d9fed6a66bc19a2883a3fe051f0c397a41fc42aedd4cc" + size = 248_979 + upload-time = "2025-11-18T13:33:46.04Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/f4/7a/bf4209f45a4aec09d10a01a57313a46c0e0e8f4c55ff2965467d41a92036/coverage-7.12.0-cp314-cp314-musllinux_1_2_riscv64.whl" + hash = "sha256:f7ba9da4726e446d8dd8aae5a6cd872511184a5d861de80a86ef970b5dacce3e" + size = 248_800 + upload-time = "2025-11-18T13:33:47.546Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/b8/b7/1e01b8696fb0521810f60c5bbebf699100d6754183e6cc0679bf2ed76531/coverage-7.12.0-cp314-cp314-musllinux_1_2_x86_64.whl" + hash = "sha256:e0f483ab4f749039894abaf80c2f9e7ed77bbf3c737517fb88c8e8e305896a17" + size = 250_460 + upload-time = "2025-11-18T13:33:49.537Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/71/ae/84324fb9cb46c024760e706353d9b771a81b398d117d8c1fe010391c186f/coverage-7.12.0-cp314-cp314-win32.whl" + hash = "sha256:76336c19a9ef4a94b2f8dc79f8ac2da3f193f625bb5d6f51a328cd19bfc19933" + size = 220_533 + upload-time = "2025-11-18T13:33:51.16Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/e2/71/1033629deb8460a8f97f83e6ac4ca3b93952e2b6f826056684df8275e015/coverage-7.12.0-cp314-cp314-win_amd64.whl" + hash = "sha256:7c1059b600aec6ef090721f8f633f60ed70afaffe8ecab85b59df748f24b31fe" + size = 221_348 + upload-time = "2025-11-18T13:33:52.776Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/0a/5f/ac8107a902f623b0c251abdb749be282dc2ab61854a8a4fcf49e276fce2f/coverage-7.12.0-cp314-cp314-win_arm64.whl" + hash = "sha256:172cf3a34bfef42611963e2b661302a8931f44df31629e5b1050567d6b90287d" + size = 219_922 + upload-time = "2025-11-18T13:33:54.316Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/79/6e/f27af2d4da367f16077d21ef6fe796c874408219fa6dd3f3efe7751bd910/coverage-7.12.0-cp314-cp314t-macosx_10_15_x86_64.whl" + hash = "sha256:aa7d48520a32cb21c7a9b31f81799e8eaec7239db36c3b670be0fa2403828d1d" + size = 218_511 + upload-time = "2025-11-18T13:33:56.343Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/67/dd/65fd874aa460c30da78f9d259400d8e6a4ef457d61ab052fd248f0050558/coverage-7.12.0-cp314-cp314t-macosx_11_0_arm64.whl" + hash = "sha256:90d58ac63bc85e0fb919f14d09d6caa63f35a5512a2205284b7816cafd21bb03" + size = 218_771 + upload-time = "2025-11-18T13:33:57.966Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/55/e0/7c6b71d327d8068cb79c05f8f45bf1b6145f7a0de23bbebe63578fe5240a/coverage-7.12.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl" + hash = "sha256:ca8ecfa283764fdda3eae1bdb6afe58bf78c2c3ec2b2edcb05a671f0bba7b3f9" + size = 260_151 + upload-time = "2025-11-18T13:33:59.597Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/49/ce/4697457d58285b7200de6b46d606ea71066c6e674571a946a6ea908fb588/coverage-7.12.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl" + hash = "sha256:874fe69a0785d96bd066059cd4368022cebbec1a8958f224f0016979183916e6" + size = 262_257 + upload-time = "2025-11-18T13:34:01.166Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/2f/33/acbc6e447aee4ceba88c15528dbe04a35fb4d67b59d393d2e0d6f1e242c1/coverage-7.12.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + hash = "sha256:5b3c889c0b8b283a24d721a9eabc8ccafcfc3aebf167e4cd0d0e23bf8ec4e339" + size = 264_671 + upload-time = "2025-11-18T13:34:02.795Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/87/ec/e2822a795c1ed44d569980097be839c5e734d4c0c1119ef8e0a073496a30/coverage-7.12.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl" + hash = "sha256:8bb5b894b3ec09dcd6d3743229dc7f2c42ef7787dc40596ae04c0edda487371e" + size = 259_231 + upload-time = "2025-11-18T13:34:04.397Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/72/c5/a7ec5395bb4a49c9b7ad97e63f0c92f6bf4a9e006b1393555a02dae75f16/coverage-7.12.0-cp314-cp314t-musllinux_1_2_aarch64.whl" + hash = "sha256:79a44421cd5fba96aa57b5e3b5a4d3274c449d4c622e8f76882d76635501fd13" + size = 262_137 + upload-time = "2025-11-18T13:34:06.068Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/67/0c/02c08858b764129f4ecb8e316684272972e60777ae986f3865b10940bdd6/coverage-7.12.0-cp314-cp314t-musllinux_1_2_i686.whl" + hash = "sha256:33baadc0efd5c7294f436a632566ccc1f72c867f82833eb59820ee37dc811c6f" + size = 259_745 + upload-time = "2025-11-18T13:34:08.04Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/5a/04/4fd32b7084505f3829a8fe45c1a74a7a728cb251aaadbe3bec04abcef06d/coverage-7.12.0-cp314-cp314t-musllinux_1_2_riscv64.whl" + hash = "sha256:c406a71f544800ef7e9e0000af706b88465f3573ae8b8de37e5f96c59f689ad1" + size = 258_570 + upload-time = "2025-11-18T13:34:09.676Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/48/35/2365e37c90df4f5342c4fa202223744119fe31264ee2924f09f074ea9b6d/coverage-7.12.0-cp314-cp314t-musllinux_1_2_x86_64.whl" + hash = "sha256:e71bba6a40883b00c6d571599b4627f50c360b3d0d02bfc658168936be74027b" + size = 260_899 + upload-time = "2025-11-18T13:34:11.259Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/05/56/26ab0464ca733fa325e8e71455c58c1c374ce30f7c04cebb88eabb037b18/coverage-7.12.0-cp314-cp314t-win32.whl" + hash = "sha256:9157a5e233c40ce6613dead4c131a006adfda70e557b6856b97aceed01b0e27a" + size = 221_313 + upload-time = "2025-11-18T13:34:12.863Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/da/1c/017a3e1113ed34d998b27d2c6dba08a9e7cb97d362f0ec988fcd873dcf81/coverage-7.12.0-cp314-cp314t-win_amd64.whl" + hash = "sha256:e84da3a0fd233aeec797b981c51af1cabac74f9bd67be42458365b30d11b5291" + size = 222_423 + upload-time = "2025-11-18T13:34:15.14Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/4c/36/bcc504fdd5169301b52568802bb1b9cdde2e27a01d39fbb3b4b508ab7c2c/coverage-7.12.0-cp314-cp314t-win_arm64.whl" + hash = "sha256:01d24af36fedda51c2b1aca56e4330a3710f83b02a5ff3743a6b015ffa7c9384" + size = 220_459 + upload-time = "2025-11-18T13:34:17.222Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/ce/a3/43b749004e3c09452e39bb56347a008f0a0668aad37324a99b5c8ca91d9e/coverage-7.12.0-py3-none-any.whl" + hash = "sha256:159d50c0b12e060b15ed3d39f87ed43d4f7f7ad40b8a534f4dd331adbb51104a" + size = 209_503 + upload-time = "2025-11-18T13:34:18.892Z" + +[[package.optional-dependencies.toml]] +name = "tomli" +marker = "python_full_version <= '3.11'" [[package]] name = "distlib" version = "0.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605, upload-time = "2025-07-17T16:52:00.465Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz" + hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d" + size = 614_605 + upload-time = "2025-07-17T16:52:00.465Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl" + hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16" + size = 469_047 + upload-time = "2025-07-17T16:51:58.613Z" [[package]] name = "exceptiongroup" version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [[package.dependencies]] + name = "typing-extensions" + marker = "python_full_version < '3.13'" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz" + hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219" + size = 30_371 + upload-time = "2025-11-21T23:01:54.787Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl" + hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598" + size = 16_740 + upload-time = "2025-11-21T23:01:53.443Z" [[package]] name = "filelock" version = "3.20.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/58/46/0028a82567109b5ef6e4d2a1f04a583fb513e6cf9527fcdd09afd817deeb/filelock-3.20.0.tar.gz", hash = "sha256:711e943b4ec6be42e1d4e6690b48dc175c822967466bb31c0c293f34334c13f4", size = 18922, upload-time = "2025-10-08T18:03:50.056Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/91/7216b27286936c16f5b4d0c530087e4a54eead683e6b0b73dd0c64844af6/filelock-3.20.0-py3-none-any.whl", hash = "sha256:339b4732ffda5cd79b13f4e2711a31b0365ce445d95d243bb996273d072546a2", size = 16054, upload-time = "2025-10-08T18:03:48.35Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/58/46/0028a82567109b5ef6e4d2a1f04a583fb513e6cf9527fcdd09afd817deeb/filelock-3.20.0.tar.gz" + hash = "sha256:711e943b4ec6be42e1d4e6690b48dc175c822967466bb31c0c293f34334c13f4" + size = 18_922 + upload-time = "2025-10-08T18:03:50.056Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/76/91/7216b27286936c16f5b4d0c530087e4a54eead683e6b0b73dd0c64844af6/filelock-3.20.0-py3-none-any.whl" + hash = "sha256:339b4732ffda5cd79b13f4e2711a31b0365ce445d95d243bb996273d072546a2" + size = 16_054 + upload-time = "2025-10-08T18:03:48.35Z" [[package]] name = "flake8" version = "7.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mccabe" }, - { name = "pycodestyle" }, - { name = "pyflakes" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9b/af/fbfe3c4b5a657d79e5c47a2827a362f9e1b763336a52f926126aa6dc7123/flake8-7.3.0.tar.gz", hash = "sha256:fe044858146b9fc69b551a4b490d69cf960fcb78ad1edcb84e7fbb1b4a8e3872", size = 48326, upload-time = "2025-06-20T19:31:35.838Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9f/56/13ab06b4f93ca7cac71078fbe37fcea175d3216f31f85c3168a6bbd0bb9a/flake8-7.3.0-py2.py3-none-any.whl", hash = "sha256:b9696257b9ce8beb888cdbe31cf885c90d31928fe202be0889a7cdafad32f01e", size = 57922, upload-time = "2025-06-20T19:31:34.425Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [[package.dependencies]] + name = "mccabe" + + [[package.dependencies]] + name = "pycodestyle" + + [[package.dependencies]] + name = "pyflakes" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/9b/af/fbfe3c4b5a657d79e5c47a2827a362f9e1b763336a52f926126aa6dc7123/flake8-7.3.0.tar.gz" + hash = "sha256:fe044858146b9fc69b551a4b490d69cf960fcb78ad1edcb84e7fbb1b4a8e3872" + size = 48_326 + upload-time = "2025-06-20T19:31:35.838Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/9f/56/13ab06b4f93ca7cac71078fbe37fcea175d3216f31f85c3168a6bbd0bb9a/flake8-7.3.0-py2.py3-none-any.whl" + hash = "sha256:b9696257b9ce8beb888cdbe31cf885c90d31928fe202be0889a7cdafad32f01e" + size = 57_922 + upload-time = "2025-06-20T19:31:34.425Z" [[package]] name = "flake8-pyproject" version = "1.2.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "flake8" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/85/6a/cdee9ff7f2b7c6ddc219fd95b7c70c0a3d9f0367a506e9793eedfc72e337/flake8_pyproject-1.2.4-py3-none-any.whl", hash = "sha256:ea34c057f9a9329c76d98723bb2bb498cc6ba8ff9872c4d19932d48c91249a77", size = 5694, upload-time = "2025-11-28T21:40:01.309Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [[package.dependencies]] + name = "flake8" + + [[package.dependencies]] + name = "tomli" + marker = "python_full_version < '3.11'" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/85/6a/cdee9ff7f2b7c6ddc219fd95b7c70c0a3d9f0367a506e9793eedfc72e337/flake8_pyproject-1.2.4-py3-none-any.whl" + hash = "sha256:ea34c057f9a9329c76d98723bb2bb498cc6ba8ff9872c4d19932d48c91249a77" + size = 5_694 + upload-time = "2025-11-28T21:40:01.309Z" [[package]] name = "identify" version = "2.6.15" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ff/e7/685de97986c916a6d93b3876139e00eef26ad5bbbd61925d670ae8013449/identify-2.6.15.tar.gz", hash = "sha256:e4f4864b96c6557ef2a1e1c951771838f4edc9df3a72ec7118b338801b11c7bf", size = 99311, upload-time = "2025-10-02T17:43:40.631Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/1c/e5fd8f973d4f375adb21565739498e2e9a1e54c858a97b9a8ccfdc81da9b/identify-2.6.15-py2.py3-none-any.whl", hash = "sha256:1181ef7608e00704db228516541eb83a88a9f94433a8c80bb9b5bd54b1d81757", size = 99183, upload-time = "2025-10-02T17:43:39.137Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/ff/e7/685de97986c916a6d93b3876139e00eef26ad5bbbd61925d670ae8013449/identify-2.6.15.tar.gz" + hash = "sha256:e4f4864b96c6557ef2a1e1c951771838f4edc9df3a72ec7118b338801b11c7bf" + size = 99_311 + upload-time = "2025-10-02T17:43:40.631Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/0f/1c/e5fd8f973d4f375adb21565739498e2e9a1e54c858a97b9a8ccfdc81da9b/identify-2.6.15-py2.py3-none-any.whl" + hash = "sha256:1181ef7608e00704db228516541eb83a88a9f94433a8c80bb9b5bd54b1d81757" + size = 99_183 + upload-time = "2025-10-02T17:43:39.137Z" [[package]] name = "iniconfig" version = "2.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz" + hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730" + size = 20_503 + upload-time = "2025-10-18T21:55:43.219Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl" + hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12" + size = 7_484 + upload-time = "2025-10-18T21:55:41.639Z" [[package]] name = "isort" version = "7.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/63/53/4f3c058e3bace40282876f9b553343376ee687f3c35a525dc79dbd450f88/isort-7.0.0.tar.gz", hash = "sha256:5513527951aadb3ac4292a41a16cbc50dd1642432f5e8c20057d414bdafb4187", size = 805049, upload-time = "2025-10-11T13:30:59.107Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7f/ed/e3705d6d02b4f7aea715a353c8ce193efd0b5db13e204df895d38734c244/isort-7.0.0-py3-none-any.whl", hash = "sha256:1bcabac8bc3c36c7fb7b98a76c8abb18e0f841a3ba81decac7691008592499c1", size = 94672, upload-time = "2025-10-11T13:30:57.665Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/63/53/4f3c058e3bace40282876f9b553343376ee687f3c35a525dc79dbd450f88/isort-7.0.0.tar.gz" + hash = "sha256:5513527951aadb3ac4292a41a16cbc50dd1642432f5e8c20057d414bdafb4187" + size = 805_049 + upload-time = "2025-10-11T13:30:59.107Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/7f/ed/e3705d6d02b4f7aea715a353c8ce193efd0b5db13e204df895d38734c244/isort-7.0.0-py3-none-any.whl" + hash = "sha256:1bcabac8bc3c36c7fb7b98a76c8abb18e0f841a3ba81decac7691008592499c1" + size = 94_672 + upload-time = "2025-10-11T13:30:57.665Z" [[package]] name = "librt" version = "0.6.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/37/c3/cdff3c10e2e608490dc0a310ccf11ba777b3943ad4fcead2a2ade98c21e1/librt-0.6.3.tar.gz", hash = "sha256:c724a884e642aa2bbad52bb0203ea40406ad742368a5f90da1b220e970384aae", size = 54209, upload-time = "2025-11-29T14:01:56.058Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a6/84/859df8db21dedab2538ddfbe1d486dda3eb66a98c6ad7ba754a99e25e45e/librt-0.6.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:45660d26569cc22ed30adf583389d8a0d1b468f8b5e518fcf9bfe2cd298f9dd1", size = 27294, upload-time = "2025-11-29T14:00:35.053Z" }, - { url = "https://files.pythonhosted.org/packages/f7/01/ec3971cf9c4f827f17de6729bdfdbf01a67493147334f4ef8fac68936e3a/librt-0.6.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:54f3b2177fb892d47f8016f1087d21654b44f7fc4cf6571c1c6b3ea531ab0fcf", size = 27635, upload-time = "2025-11-29T14:00:36.496Z" }, - { url = "https://files.pythonhosted.org/packages/b4/f9/3efe201df84dd26388d2e0afa4c4dc668c8e406a3da7b7319152faf835a1/librt-0.6.3-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:c5b31bed2c2f2fa1fcb4815b75f931121ae210dc89a3d607fb1725f5907f1437", size = 81768, upload-time = "2025-11-29T14:00:37.451Z" }, - { url = "https://files.pythonhosted.org/packages/0a/13/f63e60bc219b17f3d8f3d13423cd4972e597b0321c51cac7bfbdd5e1f7b9/librt-0.6.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8f8ed5053ef9fb08d34f1fd80ff093ccbd1f67f147633a84cf4a7d9b09c0f089", size = 85884, upload-time = "2025-11-29T14:00:38.433Z" }, - { url = "https://files.pythonhosted.org/packages/c2/42/0068f14f39a79d1ce8a19d4988dd07371df1d0a7d3395fbdc8a25b1c9437/librt-0.6.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3f0e4bd9bcb0ee34fa3dbedb05570da50b285f49e52c07a241da967840432513", size = 85830, upload-time = "2025-11-29T14:00:39.418Z" }, - { url = "https://files.pythonhosted.org/packages/14/1c/87f5af3a9e6564f09e50c72f82fc3057fd42d1facc8b510a707d0438c4ad/librt-0.6.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d8f89c8d20dfa648a3f0a56861946eb00e5b00d6b00eea14bc5532b2fcfa8ef1", size = 88086, upload-time = "2025-11-29T14:00:40.555Z" }, - { url = "https://files.pythonhosted.org/packages/05/e5/22153b98b88a913b5b3f266f12e57df50a2a6960b3f8fcb825b1a0cfe40a/librt-0.6.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ecc2c526547eacd20cb9fbba19a5268611dbc70c346499656d6cf30fae328977", size = 86470, upload-time = "2025-11-29T14:00:41.827Z" }, - { url = "https://files.pythonhosted.org/packages/18/3c/ea1edb587799b1edcc22444e0630fa422e32d7aaa5bfb5115b948acc2d1c/librt-0.6.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:fbedeb9b48614d662822ee514567d2d49a8012037fc7b4cd63f282642c2f4b7d", size = 89079, upload-time = "2025-11-29T14:00:42.882Z" }, - { url = "https://files.pythonhosted.org/packages/73/ad/50bb4ae6b07c9f3ab19653e0830a210533b30eb9a18d515efb5a2b9d0c7c/librt-0.6.3-cp310-cp310-win32.whl", hash = "sha256:0765b0fe0927d189ee14b087cd595ae636bef04992e03fe6dfdaa383866c8a46", size = 19820, upload-time = "2025-11-29T14:00:44.211Z" }, - { url = "https://files.pythonhosted.org/packages/7a/12/7426ee78f3b1dbe11a90619d54cb241ca924ca3c0ff9ade3992178e9b440/librt-0.6.3-cp310-cp310-win_amd64.whl", hash = "sha256:8c659f9fb8a2f16dc4131b803fa0144c1dadcb3ab24bb7914d01a6da58ae2457", size = 21332, upload-time = "2025-11-29T14:00:45.427Z" }, - { url = "https://files.pythonhosted.org/packages/8b/80/bc60fd16fe24910bf5974fb914778a2e8540cef55385ab2cb04a0dfe42c4/librt-0.6.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:61348cc488b18d1b1ff9f3e5fcd5ac43ed22d3e13e862489d2267c2337285c08", size = 27285, upload-time = "2025-11-29T14:00:46.626Z" }, - { url = "https://files.pythonhosted.org/packages/88/3c/26335536ed9ba097c79cffcee148393592e55758fe76d99015af3e47a6d0/librt-0.6.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:64645b757d617ad5f98c08e07620bc488d4bced9ced91c6279cec418f16056fa", size = 27629, upload-time = "2025-11-29T14:00:47.863Z" }, - { url = "https://files.pythonhosted.org/packages/af/fd/2dcedeacfedee5d2eda23e7a49c1c12ce6221b5d58a13555f053203faafc/librt-0.6.3-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:26b8026393920320bb9a811b691d73c5981385d537ffc5b6e22e53f7b65d4122", size = 82039, upload-time = "2025-11-29T14:00:49.131Z" }, - { url = "https://files.pythonhosted.org/packages/48/ff/6aa11914b83b0dc2d489f7636942a8e3322650d0dba840db9a1b455f3caa/librt-0.6.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d998b432ed9ffccc49b820e913c8f327a82026349e9c34fa3690116f6b70770f", size = 86560, upload-time = "2025-11-29T14:00:50.403Z" }, - { url = "https://files.pythonhosted.org/packages/76/a1/d25af61958c2c7eb978164aeba0350719f615179ba3f428b682b9a5fdace/librt-0.6.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e18875e17ef69ba7dfa9623f2f95f3eda6f70b536079ee6d5763ecdfe6cc9040", size = 86494, upload-time = "2025-11-29T14:00:51.383Z" }, - { url = "https://files.pythonhosted.org/packages/7d/4b/40e75d3b258c801908e64b39788f9491635f9554f8717430a491385bd6f2/librt-0.6.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a218f85081fc3f70cddaed694323a1ad7db5ca028c379c214e3a7c11c0850523", size = 88914, upload-time = "2025-11-29T14:00:52.688Z" }, - { url = "https://files.pythonhosted.org/packages/97/6d/0070c81aba8a169224301c75fb5fb6c3c25ca67e6ced086584fc130d5a67/librt-0.6.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1ef42ff4edd369e84433ce9b188a64df0837f4f69e3d34d3b34d4955c599d03f", size = 86944, upload-time = "2025-11-29T14:00:53.768Z" }, - { url = "https://files.pythonhosted.org/packages/a6/94/809f38887941b7726692e0b5a083dbdc87dbb8cf893e3b286550c5f0b129/librt-0.6.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0e0f2b79993fec23a685b3e8107ba5f8675eeae286675a216da0b09574fa1e47", size = 89852, upload-time = "2025-11-29T14:00:54.71Z" }, - { url = "https://files.pythonhosted.org/packages/58/a3/b0e5b1cda675b91f1111d8ba941da455d8bfaa22f4d2d8963ba96ccb5b12/librt-0.6.3-cp311-cp311-win32.whl", hash = "sha256:fd98cacf4e0fabcd4005c452cb8a31750258a85cab9a59fb3559e8078da408d7", size = 19948, upload-time = "2025-11-29T14:00:55.989Z" }, - { url = "https://files.pythonhosted.org/packages/cc/73/70011c2b37e3be3ece3affd3abc8ebe5cda482b03fd6b3397906321a901e/librt-0.6.3-cp311-cp311-win_amd64.whl", hash = "sha256:e17b5b42c8045867ca9d1f54af00cc2275198d38de18545edaa7833d7e9e4ac8", size = 21406, upload-time = "2025-11-29T14:00:56.874Z" }, - { url = "https://files.pythonhosted.org/packages/91/ee/119aa759290af6ca0729edf513ca390c1afbeae60f3ecae9b9d56f25a8a9/librt-0.6.3-cp311-cp311-win_arm64.whl", hash = "sha256:87597e3d57ec0120a3e1d857a708f80c02c42ea6b00227c728efbc860f067c45", size = 20875, upload-time = "2025-11-29T14:00:57.752Z" }, - { url = "https://files.pythonhosted.org/packages/b4/2c/b59249c566f98fe90e178baf59e83f628d6c38fb8bc78319301fccda0b5e/librt-0.6.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:74418f718083009108dc9a42c21bf2e4802d49638a1249e13677585fcc9ca176", size = 27841, upload-time = "2025-11-29T14:00:58.925Z" }, - { url = "https://files.pythonhosted.org/packages/40/e8/9db01cafcd1a2872b76114c858f81cc29ce7ad606bc102020d6dabf470fb/librt-0.6.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:514f3f363d1ebc423357d36222c37e5c8e6674b6eae8d7195ac9a64903722057", size = 27844, upload-time = "2025-11-29T14:01:00.2Z" }, - { url = "https://files.pythonhosted.org/packages/59/4d/da449d3a7d83cc853af539dee42adc37b755d7eea4ad3880bacfd84b651d/librt-0.6.3-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cf1115207a5049d1f4b7b4b72de0e52f228d6c696803d94843907111cbf80610", size = 84091, upload-time = "2025-11-29T14:01:01.118Z" }, - { url = "https://files.pythonhosted.org/packages/ea/6c/f90306906fb6cc6eaf4725870f0347115de05431e1f96d35114392d31fda/librt-0.6.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ad8ba80cdcea04bea7b78fcd4925bfbf408961e9d8397d2ee5d3ec121e20c08c", size = 88239, upload-time = "2025-11-29T14:01:02.11Z" }, - { url = "https://files.pythonhosted.org/packages/e7/ae/473ce7b423cfac2cb503851a89d9d2195bf615f534d5912bf86feeebbee7/librt-0.6.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4018904c83eab49c814e2494b4e22501a93cdb6c9f9425533fe693c3117126f9", size = 88815, upload-time = "2025-11-29T14:01:03.114Z" }, - { url = "https://files.pythonhosted.org/packages/c4/6d/934df738c87fb9617cabefe4891eece585a06abe6def25b4bca3b174429d/librt-0.6.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8983c5c06ac9c990eac5eb97a9f03fe41dc7e9d7993df74d9e8682a1056f596c", size = 90598, upload-time = "2025-11-29T14:01:04.071Z" }, - { url = "https://files.pythonhosted.org/packages/72/89/eeaa124f5e0f431c2b39119550378ae817a4b1a3c93fd7122f0639336fff/librt-0.6.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d7769c579663a6f8dbf34878969ac71befa42067ce6bf78e6370bf0d1194997c", size = 88603, upload-time = "2025-11-29T14:01:05.02Z" }, - { url = "https://files.pythonhosted.org/packages/4d/ed/c60b3c1cfc27d709bc0288af428ce58543fcb5053cf3eadbc773c24257f5/librt-0.6.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d3c9a07eafdc70556f8c220da4a538e715668c0c63cabcc436a026e4e89950bf", size = 92112, upload-time = "2025-11-29T14:01:06.304Z" }, - { url = "https://files.pythonhosted.org/packages/c1/ab/f56169be5f716ef4ab0277be70bcb1874b4effc262e655d85b505af4884d/librt-0.6.3-cp312-cp312-win32.whl", hash = "sha256:38320386a48a15033da295df276aea93a92dfa94a862e06893f75ea1d8bbe89d", size = 20127, upload-time = "2025-11-29T14:01:07.283Z" }, - { url = "https://files.pythonhosted.org/packages/ff/8d/222750ce82bf95125529eaab585ac7e2829df252f3cfc05d68792fb1dd2c/librt-0.6.3-cp312-cp312-win_amd64.whl", hash = "sha256:c0ecf4786ad0404b072196b5df774b1bb23c8aacdcacb6c10b4128bc7b00bd01", size = 21545, upload-time = "2025-11-29T14:01:08.184Z" }, - { url = "https://files.pythonhosted.org/packages/72/c9/f731ddcfb72f446a92a8674c6b8e1e2242773cce43a04f41549bd8b958ff/librt-0.6.3-cp312-cp312-win_arm64.whl", hash = "sha256:9f2a6623057989ebc469cd9cc8fe436c40117a0147627568d03f84aef7854c55", size = 20946, upload-time = "2025-11-29T14:01:09.384Z" }, - { url = "https://files.pythonhosted.org/packages/dd/aa/3055dd440f8b8b3b7e8624539a0749dd8e1913e978993bcca9ce7e306231/librt-0.6.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9e716f9012148a81f02f46a04fc4c663420c6fbfeacfac0b5e128cf43b4413d3", size = 27874, upload-time = "2025-11-29T14:01:10.615Z" }, - { url = "https://files.pythonhosted.org/packages/ef/93/226d7dd455eaa4c26712b5ccb2dfcca12831baa7f898c8ffd3a831e29fda/librt-0.6.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:669ff2495728009a96339c5ad2612569c6d8be4474e68f3f3ac85d7c3261f5f5", size = 27852, upload-time = "2025-11-29T14:01:11.535Z" }, - { url = "https://files.pythonhosted.org/packages/4e/8b/db9d51191aef4e4cc06285250affe0bb0ad8b2ed815f7ca77951655e6f02/librt-0.6.3-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:349b6873ebccfc24c9efd244e49da9f8a5c10f60f07575e248921aae2123fc42", size = 84264, upload-time = "2025-11-29T14:01:12.461Z" }, - { url = "https://files.pythonhosted.org/packages/8d/53/297c96bda3b5a73bdaf748f1e3ae757edd29a0a41a956b9c10379f193417/librt-0.6.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c74c26736008481c9f6d0adf1aedb5a52aff7361fea98276d1f965c0256ee70", size = 88432, upload-time = "2025-11-29T14:01:13.405Z" }, - { url = "https://files.pythonhosted.org/packages/54/3a/c005516071123278e340f22de72fa53d51e259d49215295c212da16c4dc2/librt-0.6.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:408a36ddc75e91918cb15b03460bdc8a015885025d67e68c6f78f08c3a88f522", size = 89014, upload-time = "2025-11-29T14:01:14.373Z" }, - { url = "https://files.pythonhosted.org/packages/8e/9b/ea715f818d926d17b94c80a12d81a79e95c44f52848e61e8ca1ff29bb9a9/librt-0.6.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e61ab234624c9ffca0248a707feffe6fac2343758a36725d8eb8a6efef0f8c30", size = 90807, upload-time = "2025-11-29T14:01:15.377Z" }, - { url = "https://files.pythonhosted.org/packages/f0/fc/4e2e4c87e002fa60917a8e474fd13c4bac9a759df82be3778573bb1ab954/librt-0.6.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:324462fe7e3896d592b967196512491ec60ca6e49c446fe59f40743d08c97917", size = 88890, upload-time = "2025-11-29T14:01:16.633Z" }, - { url = "https://files.pythonhosted.org/packages/70/7f/c7428734fbdfd4db3d5b9237fc3a857880b2ace66492836f6529fef25d92/librt-0.6.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:36b2ec8c15030002c7f688b4863e7be42820d7c62d9c6eece3db54a2400f0530", size = 92300, upload-time = "2025-11-29T14:01:17.658Z" }, - { url = "https://files.pythonhosted.org/packages/f9/0c/738c4824fdfe74dc0f95d5e90ef9e759d4ecf7fd5ba964d54a7703322251/librt-0.6.3-cp313-cp313-win32.whl", hash = "sha256:25b1b60cb059471c0c0c803e07d0dfdc79e41a0a122f288b819219ed162672a3", size = 20159, upload-time = "2025-11-29T14:01:18.61Z" }, - { url = "https://files.pythonhosted.org/packages/f2/95/93d0e61bc617306ecf4c54636b5cbde4947d872563565c4abdd9d07a39d3/librt-0.6.3-cp313-cp313-win_amd64.whl", hash = "sha256:10a95ad074e2a98c9e4abc7f5b7d40e5ecbfa84c04c6ab8a70fabf59bd429b88", size = 21484, upload-time = "2025-11-29T14:01:19.506Z" }, - { url = "https://files.pythonhosted.org/packages/10/23/abd7ace79ab54d1dbee265f13529266f686a7ce2d21ab59a992f989009b6/librt-0.6.3-cp313-cp313-win_arm64.whl", hash = "sha256:17000df14f552e86877d67e4ab7966912224efc9368e998c96a6974a8d609bf9", size = 20935, upload-time = "2025-11-29T14:01:20.415Z" }, - { url = "https://files.pythonhosted.org/packages/83/14/c06cb31152182798ed98be73f54932ab984894f5a8fccf9b73130897a938/librt-0.6.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8e695f25d1a425ad7a272902af8ab8c8d66c1998b177e4b5f5e7b4e215d0c88a", size = 27566, upload-time = "2025-11-29T14:01:21.609Z" }, - { url = "https://files.pythonhosted.org/packages/0c/b1/ce83ca7b057b06150519152f53a0b302d7c33c8692ce2f01f669b5a819d9/librt-0.6.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:3e84a4121a7ae360ca4da436548a9c1ca8ca134a5ced76c893cc5944426164bd", size = 27753, upload-time = "2025-11-29T14:01:22.558Z" }, - { url = "https://files.pythonhosted.org/packages/3b/ec/739a885ef0a2839b6c25f1b01c99149d2cb6a34e933ffc8c051fcd22012e/librt-0.6.3-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:05f385a414de3f950886ea0aad8f109650d4b712cf9cc14cc17f5f62a9ab240b", size = 83178, upload-time = "2025-11-29T14:01:23.555Z" }, - { url = "https://files.pythonhosted.org/packages/db/bd/dc18bb1489d48c0911b9f4d72eae2d304ea264e215ba80f1e6ba4a9fc41d/librt-0.6.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36a8e337461150b05ca2c7bdedb9e591dfc262c5230422cea398e89d0c746cdc", size = 87266, upload-time = "2025-11-29T14:01:24.532Z" }, - { url = "https://files.pythonhosted.org/packages/94/f3/d0c5431b39eef15e48088b2d739ad84b17c2f1a22c0345c6d4c4a42b135e/librt-0.6.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dcbe48f6a03979384f27086484dc2a14959be1613cb173458bd58f714f2c48f3", size = 87623, upload-time = "2025-11-29T14:01:25.798Z" }, - { url = "https://files.pythonhosted.org/packages/3b/15/9a52e90834e4bd6ee16cdbaf551cb32227cbaad27398391a189c489318bc/librt-0.6.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4bca9e4c260233fba37b15c4ec2f78aa99c1a79fbf902d19dd4a763c5c3fb751", size = 89436, upload-time = "2025-11-29T14:01:26.769Z" }, - { url = "https://files.pythonhosted.org/packages/c3/8a/a7e78e46e8486e023c50f21758930ef4793999115229afd65de69e94c9cc/librt-0.6.3-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:760c25ed6ac968e24803eb5f7deb17ce026902d39865e83036bacbf5cf242aa8", size = 87540, upload-time = "2025-11-29T14:01:27.756Z" }, - { url = "https://files.pythonhosted.org/packages/49/01/93799044a1cccac31f1074b07c583e181829d240539657e7f305ae63ae2a/librt-0.6.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4aa4a93a353ccff20df6e34fa855ae8fd788832c88f40a9070e3ddd3356a9f0e", size = 90597, upload-time = "2025-11-29T14:01:29.35Z" }, - { url = "https://files.pythonhosted.org/packages/a7/29/00c7f58b8f8eb1bad6529ffb6c9cdcc0890a27dac59ecda04f817ead5277/librt-0.6.3-cp314-cp314-win32.whl", hash = "sha256:cb92741c2b4ea63c09609b064b26f7f5d9032b61ae222558c55832ec3ad0bcaf", size = 18955, upload-time = "2025-11-29T14:01:30.325Z" }, - { url = "https://files.pythonhosted.org/packages/d7/13/2739e6e197a9f751375a37908a6a5b0bff637b81338497a1bcb5817394da/librt-0.6.3-cp314-cp314-win_amd64.whl", hash = "sha256:fdcd095b1b812d756fa5452aca93b962cf620694c0cadb192cec2bb77dcca9a2", size = 20263, upload-time = "2025-11-29T14:01:31.287Z" }, - { url = "https://files.pythonhosted.org/packages/e1/73/393868fc2158705ea003114a24e73bb10b03bda31e9ad7b5c5ec6575338b/librt-0.6.3-cp314-cp314-win_arm64.whl", hash = "sha256:822ca79e28720a76a935c228d37da6579edef048a17cd98d406a2484d10eda78", size = 19575, upload-time = "2025-11-29T14:01:32.229Z" }, - { url = "https://files.pythonhosted.org/packages/48/6d/3c8ff3dec21bf804a205286dd63fd28dcdbe00b8dd7eb7ccf2e21a40a0b0/librt-0.6.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:078cd77064d1640cb7b0650871a772956066174d92c8aeda188a489b58495179", size = 28732, upload-time = "2025-11-29T14:01:33.165Z" }, - { url = "https://files.pythonhosted.org/packages/f4/90/e214b8b4aa34ed3d3f1040719c06c4d22472c40c5ef81a922d5af7876eb4/librt-0.6.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5cc22f7f5c0cc50ed69f4b15b9c51d602aabc4500b433aaa2ddd29e578f452f7", size = 29065, upload-time = "2025-11-29T14:01:34.088Z" }, - { url = "https://files.pythonhosted.org/packages/ab/90/ef61ed51f0a7770cc703422d907a757bbd8811ce820c333d3db2fd13542a/librt-0.6.3-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:14b345eb7afb61b9fdcdfda6738946bd11b8e0f6be258666b0646af3b9bb5916", size = 93703, upload-time = "2025-11-29T14:01:35.057Z" }, - { url = "https://files.pythonhosted.org/packages/a8/ae/c30bb119c35962cbe9a908a71da99c168056fc3f6e9bbcbc157d0b724d89/librt-0.6.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d46aa46aa29b067f0b8b84f448fd9719aaf5f4c621cc279164d76a9dc9ab3e8", size = 98890, upload-time = "2025-11-29T14:01:36.031Z" }, - { url = "https://files.pythonhosted.org/packages/d1/96/47a4a78d252d36f072b79d592df10600d379a895c3880c8cbd2ac699f0ad/librt-0.6.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1b51ba7d9d5d9001494769eca8c0988adce25d0a970c3ba3f2eb9df9d08036fc", size = 98255, upload-time = "2025-11-29T14:01:37.058Z" }, - { url = "https://files.pythonhosted.org/packages/e5/28/779b5cc3cd9987683884eb5f5672e3251676bebaaae6b7da1cf366eb1da1/librt-0.6.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ced0925a18fddcff289ef54386b2fc230c5af3c83b11558571124bfc485b8c07", size = 100769, upload-time = "2025-11-29T14:01:38.413Z" }, - { url = "https://files.pythonhosted.org/packages/28/d7/771755e57c375cb9d25a4e106f570607fd856e2cb91b02418db1db954796/librt-0.6.3-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:6bac97e51f66da2ca012adddbe9fd656b17f7368d439de30898f24b39512f40f", size = 98580, upload-time = "2025-11-29T14:01:39.459Z" }, - { url = "https://files.pythonhosted.org/packages/d0/ec/8b157eb8fbc066339a2f34b0aceb2028097d0ed6150a52e23284a311eafe/librt-0.6.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b2922a0e8fa97395553c304edc3bd36168d8eeec26b92478e292e5d4445c1ef0", size = 101706, upload-time = "2025-11-29T14:01:40.474Z" }, - { url = "https://files.pythonhosted.org/packages/82/a8/4aaead9a06c795a318282aebf7d3e3e578fa889ff396e1b640c3be4c7806/librt-0.6.3-cp314-cp314t-win32.whl", hash = "sha256:f33462b19503ba68d80dac8a1354402675849259fb3ebf53b67de86421735a3a", size = 19465, upload-time = "2025-11-29T14:01:41.77Z" }, - { url = "https://files.pythonhosted.org/packages/3a/61/b7e6a02746c1731670c19ba07d86da90b1ae45d29e405c0b5615abf97cde/librt-0.6.3-cp314-cp314t-win_amd64.whl", hash = "sha256:04f8ce401d4f6380cfc42af0f4e67342bf34c820dae01343f58f472dbac75dcf", size = 21042, upload-time = "2025-11-29T14:01:42.865Z" }, - { url = "https://files.pythonhosted.org/packages/0e/3d/72cc9ec90bb80b5b1a65f0bb74a0f540195837baaf3b98c7fa4a7aa9718e/librt-0.6.3-cp314-cp314t-win_arm64.whl", hash = "sha256:afb39550205cc5e5c935762c6bf6a2bb34f7d21a68eadb25e2db7bf3593fecc0", size = 20246, upload-time = "2025-11-29T14:01:44.13Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/37/c3/cdff3c10e2e608490dc0a310ccf11ba777b3943ad4fcead2a2ade98c21e1/librt-0.6.3.tar.gz" + hash = "sha256:c724a884e642aa2bbad52bb0203ea40406ad742368a5f90da1b220e970384aae" + size = 54_209 + upload-time = "2025-11-29T14:01:56.058Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/a6/84/859df8db21dedab2538ddfbe1d486dda3eb66a98c6ad7ba754a99e25e45e/librt-0.6.3-cp310-cp310-macosx_10_9_x86_64.whl" + hash = "sha256:45660d26569cc22ed30adf583389d8a0d1b468f8b5e518fcf9bfe2cd298f9dd1" + size = 27_294 + upload-time = "2025-11-29T14:00:35.053Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/f7/01/ec3971cf9c4f827f17de6729bdfdbf01a67493147334f4ef8fac68936e3a/librt-0.6.3-cp310-cp310-macosx_11_0_arm64.whl" + hash = "sha256:54f3b2177fb892d47f8016f1087d21654b44f7fc4cf6571c1c6b3ea531ab0fcf" + size = 27_635 + upload-time = "2025-11-29T14:00:36.496Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/b4/f9/3efe201df84dd26388d2e0afa4c4dc668c8e406a3da7b7319152faf835a1/librt-0.6.3-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl" + hash = "sha256:c5b31bed2c2f2fa1fcb4815b75f931121ae210dc89a3d607fb1725f5907f1437" + size = 81_768 + upload-time = "2025-11-29T14:00:37.451Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/0a/13/f63e60bc219b17f3d8f3d13423cd4972e597b0321c51cac7bfbdd5e1f7b9/librt-0.6.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + hash = "sha256:8f8ed5053ef9fb08d34f1fd80ff093ccbd1f67f147633a84cf4a7d9b09c0f089" + size = 85_884 + upload-time = "2025-11-29T14:00:38.433Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/c2/42/0068f14f39a79d1ce8a19d4988dd07371df1d0a7d3395fbdc8a25b1c9437/librt-0.6.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + hash = "sha256:3f0e4bd9bcb0ee34fa3dbedb05570da50b285f49e52c07a241da967840432513" + size = 85_830 + upload-time = "2025-11-29T14:00:39.418Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/14/1c/87f5af3a9e6564f09e50c72f82fc3057fd42d1facc8b510a707d0438c4ad/librt-0.6.3-cp310-cp310-musllinux_1_2_aarch64.whl" + hash = "sha256:d8f89c8d20dfa648a3f0a56861946eb00e5b00d6b00eea14bc5532b2fcfa8ef1" + size = 88_086 + upload-time = "2025-11-29T14:00:40.555Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/05/e5/22153b98b88a913b5b3f266f12e57df50a2a6960b3f8fcb825b1a0cfe40a/librt-0.6.3-cp310-cp310-musllinux_1_2_i686.whl" + hash = "sha256:ecc2c526547eacd20cb9fbba19a5268611dbc70c346499656d6cf30fae328977" + size = 86_470 + upload-time = "2025-11-29T14:00:41.827Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/18/3c/ea1edb587799b1edcc22444e0630fa422e32d7aaa5bfb5115b948acc2d1c/librt-0.6.3-cp310-cp310-musllinux_1_2_x86_64.whl" + hash = "sha256:fbedeb9b48614d662822ee514567d2d49a8012037fc7b4cd63f282642c2f4b7d" + size = 89_079 + upload-time = "2025-11-29T14:00:42.882Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/73/ad/50bb4ae6b07c9f3ab19653e0830a210533b30eb9a18d515efb5a2b9d0c7c/librt-0.6.3-cp310-cp310-win32.whl" + hash = "sha256:0765b0fe0927d189ee14b087cd595ae636bef04992e03fe6dfdaa383866c8a46" + size = 19_820 + upload-time = "2025-11-29T14:00:44.211Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/7a/12/7426ee78f3b1dbe11a90619d54cb241ca924ca3c0ff9ade3992178e9b440/librt-0.6.3-cp310-cp310-win_amd64.whl" + hash = "sha256:8c659f9fb8a2f16dc4131b803fa0144c1dadcb3ab24bb7914d01a6da58ae2457" + size = 21_332 + upload-time = "2025-11-29T14:00:45.427Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/8b/80/bc60fd16fe24910bf5974fb914778a2e8540cef55385ab2cb04a0dfe42c4/librt-0.6.3-cp311-cp311-macosx_10_9_x86_64.whl" + hash = "sha256:61348cc488b18d1b1ff9f3e5fcd5ac43ed22d3e13e862489d2267c2337285c08" + size = 27_285 + upload-time = "2025-11-29T14:00:46.626Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/88/3c/26335536ed9ba097c79cffcee148393592e55758fe76d99015af3e47a6d0/librt-0.6.3-cp311-cp311-macosx_11_0_arm64.whl" + hash = "sha256:64645b757d617ad5f98c08e07620bc488d4bced9ced91c6279cec418f16056fa" + size = 27_629 + upload-time = "2025-11-29T14:00:47.863Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/af/fd/2dcedeacfedee5d2eda23e7a49c1c12ce6221b5d58a13555f053203faafc/librt-0.6.3-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl" + hash = "sha256:26b8026393920320bb9a811b691d73c5981385d537ffc5b6e22e53f7b65d4122" + size = 82_039 + upload-time = "2025-11-29T14:00:49.131Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/48/ff/6aa11914b83b0dc2d489f7636942a8e3322650d0dba840db9a1b455f3caa/librt-0.6.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + hash = "sha256:d998b432ed9ffccc49b820e913c8f327a82026349e9c34fa3690116f6b70770f" + size = 86_560 + upload-time = "2025-11-29T14:00:50.403Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/76/a1/d25af61958c2c7eb978164aeba0350719f615179ba3f428b682b9a5fdace/librt-0.6.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + hash = "sha256:e18875e17ef69ba7dfa9623f2f95f3eda6f70b536079ee6d5763ecdfe6cc9040" + size = 86_494 + upload-time = "2025-11-29T14:00:51.383Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/7d/4b/40e75d3b258c801908e64b39788f9491635f9554f8717430a491385bd6f2/librt-0.6.3-cp311-cp311-musllinux_1_2_aarch64.whl" + hash = "sha256:a218f85081fc3f70cddaed694323a1ad7db5ca028c379c214e3a7c11c0850523" + size = 88_914 + upload-time = "2025-11-29T14:00:52.688Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/97/6d/0070c81aba8a169224301c75fb5fb6c3c25ca67e6ced086584fc130d5a67/librt-0.6.3-cp311-cp311-musllinux_1_2_i686.whl" + hash = "sha256:1ef42ff4edd369e84433ce9b188a64df0837f4f69e3d34d3b34d4955c599d03f" + size = 86_944 + upload-time = "2025-11-29T14:00:53.768Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/a6/94/809f38887941b7726692e0b5a083dbdc87dbb8cf893e3b286550c5f0b129/librt-0.6.3-cp311-cp311-musllinux_1_2_x86_64.whl" + hash = "sha256:0e0f2b79993fec23a685b3e8107ba5f8675eeae286675a216da0b09574fa1e47" + size = 89_852 + upload-time = "2025-11-29T14:00:54.71Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/58/a3/b0e5b1cda675b91f1111d8ba941da455d8bfaa22f4d2d8963ba96ccb5b12/librt-0.6.3-cp311-cp311-win32.whl" + hash = "sha256:fd98cacf4e0fabcd4005c452cb8a31750258a85cab9a59fb3559e8078da408d7" + size = 19_948 + upload-time = "2025-11-29T14:00:55.989Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/cc/73/70011c2b37e3be3ece3affd3abc8ebe5cda482b03fd6b3397906321a901e/librt-0.6.3-cp311-cp311-win_amd64.whl" + hash = "sha256:e17b5b42c8045867ca9d1f54af00cc2275198d38de18545edaa7833d7e9e4ac8" + size = 21_406 + upload-time = "2025-11-29T14:00:56.874Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/91/ee/119aa759290af6ca0729edf513ca390c1afbeae60f3ecae9b9d56f25a8a9/librt-0.6.3-cp311-cp311-win_arm64.whl" + hash = "sha256:87597e3d57ec0120a3e1d857a708f80c02c42ea6b00227c728efbc860f067c45" + size = 20_875 + upload-time = "2025-11-29T14:00:57.752Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/b4/2c/b59249c566f98fe90e178baf59e83f628d6c38fb8bc78319301fccda0b5e/librt-0.6.3-cp312-cp312-macosx_10_13_x86_64.whl" + hash = "sha256:74418f718083009108dc9a42c21bf2e4802d49638a1249e13677585fcc9ca176" + size = 27_841 + upload-time = "2025-11-29T14:00:58.925Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/40/e8/9db01cafcd1a2872b76114c858f81cc29ce7ad606bc102020d6dabf470fb/librt-0.6.3-cp312-cp312-macosx_11_0_arm64.whl" + hash = "sha256:514f3f363d1ebc423357d36222c37e5c8e6674b6eae8d7195ac9a64903722057" + size = 27_844 + upload-time = "2025-11-29T14:01:00.2Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/59/4d/da449d3a7d83cc853af539dee42adc37b755d7eea4ad3880bacfd84b651d/librt-0.6.3-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl" + hash = "sha256:cf1115207a5049d1f4b7b4b72de0e52f228d6c696803d94843907111cbf80610" + size = 84_091 + upload-time = "2025-11-29T14:01:01.118Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/ea/6c/f90306906fb6cc6eaf4725870f0347115de05431e1f96d35114392d31fda/librt-0.6.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + hash = "sha256:ad8ba80cdcea04bea7b78fcd4925bfbf408961e9d8397d2ee5d3ec121e20c08c" + size = 88_239 + upload-time = "2025-11-29T14:01:02.11Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/e7/ae/473ce7b423cfac2cb503851a89d9d2195bf615f534d5912bf86feeebbee7/librt-0.6.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + hash = "sha256:4018904c83eab49c814e2494b4e22501a93cdb6c9f9425533fe693c3117126f9" + size = 88_815 + upload-time = "2025-11-29T14:01:03.114Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/c4/6d/934df738c87fb9617cabefe4891eece585a06abe6def25b4bca3b174429d/librt-0.6.3-cp312-cp312-musllinux_1_2_aarch64.whl" + hash = "sha256:8983c5c06ac9c990eac5eb97a9f03fe41dc7e9d7993df74d9e8682a1056f596c" + size = 90_598 + upload-time = "2025-11-29T14:01:04.071Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/72/89/eeaa124f5e0f431c2b39119550378ae817a4b1a3c93fd7122f0639336fff/librt-0.6.3-cp312-cp312-musllinux_1_2_i686.whl" + hash = "sha256:d7769c579663a6f8dbf34878969ac71befa42067ce6bf78e6370bf0d1194997c" + size = 88_603 + upload-time = "2025-11-29T14:01:05.02Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/4d/ed/c60b3c1cfc27d709bc0288af428ce58543fcb5053cf3eadbc773c24257f5/librt-0.6.3-cp312-cp312-musllinux_1_2_x86_64.whl" + hash = "sha256:d3c9a07eafdc70556f8c220da4a538e715668c0c63cabcc436a026e4e89950bf" + size = 92_112 + upload-time = "2025-11-29T14:01:06.304Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/c1/ab/f56169be5f716ef4ab0277be70bcb1874b4effc262e655d85b505af4884d/librt-0.6.3-cp312-cp312-win32.whl" + hash = "sha256:38320386a48a15033da295df276aea93a92dfa94a862e06893f75ea1d8bbe89d" + size = 20_127 + upload-time = "2025-11-29T14:01:07.283Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/ff/8d/222750ce82bf95125529eaab585ac7e2829df252f3cfc05d68792fb1dd2c/librt-0.6.3-cp312-cp312-win_amd64.whl" + hash = "sha256:c0ecf4786ad0404b072196b5df774b1bb23c8aacdcacb6c10b4128bc7b00bd01" + size = 21_545 + upload-time = "2025-11-29T14:01:08.184Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/72/c9/f731ddcfb72f446a92a8674c6b8e1e2242773cce43a04f41549bd8b958ff/librt-0.6.3-cp312-cp312-win_arm64.whl" + hash = "sha256:9f2a6623057989ebc469cd9cc8fe436c40117a0147627568d03f84aef7854c55" + size = 20_946 + upload-time = "2025-11-29T14:01:09.384Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/dd/aa/3055dd440f8b8b3b7e8624539a0749dd8e1913e978993bcca9ce7e306231/librt-0.6.3-cp313-cp313-macosx_10_13_x86_64.whl" + hash = "sha256:9e716f9012148a81f02f46a04fc4c663420c6fbfeacfac0b5e128cf43b4413d3" + size = 27_874 + upload-time = "2025-11-29T14:01:10.615Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/ef/93/226d7dd455eaa4c26712b5ccb2dfcca12831baa7f898c8ffd3a831e29fda/librt-0.6.3-cp313-cp313-macosx_11_0_arm64.whl" + hash = "sha256:669ff2495728009a96339c5ad2612569c6d8be4474e68f3f3ac85d7c3261f5f5" + size = 27_852 + upload-time = "2025-11-29T14:01:11.535Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/4e/8b/db9d51191aef4e4cc06285250affe0bb0ad8b2ed815f7ca77951655e6f02/librt-0.6.3-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl" + hash = "sha256:349b6873ebccfc24c9efd244e49da9f8a5c10f60f07575e248921aae2123fc42" + size = 84_264 + upload-time = "2025-11-29T14:01:12.461Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/8d/53/297c96bda3b5a73bdaf748f1e3ae757edd29a0a41a956b9c10379f193417/librt-0.6.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + hash = "sha256:0c74c26736008481c9f6d0adf1aedb5a52aff7361fea98276d1f965c0256ee70" + size = 88_432 + upload-time = "2025-11-29T14:01:13.405Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/54/3a/c005516071123278e340f22de72fa53d51e259d49215295c212da16c4dc2/librt-0.6.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + hash = "sha256:408a36ddc75e91918cb15b03460bdc8a015885025d67e68c6f78f08c3a88f522" + size = 89_014 + upload-time = "2025-11-29T14:01:14.373Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/8e/9b/ea715f818d926d17b94c80a12d81a79e95c44f52848e61e8ca1ff29bb9a9/librt-0.6.3-cp313-cp313-musllinux_1_2_aarch64.whl" + hash = "sha256:e61ab234624c9ffca0248a707feffe6fac2343758a36725d8eb8a6efef0f8c30" + size = 90_807 + upload-time = "2025-11-29T14:01:15.377Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/f0/fc/4e2e4c87e002fa60917a8e474fd13c4bac9a759df82be3778573bb1ab954/librt-0.6.3-cp313-cp313-musllinux_1_2_i686.whl" + hash = "sha256:324462fe7e3896d592b967196512491ec60ca6e49c446fe59f40743d08c97917" + size = 88_890 + upload-time = "2025-11-29T14:01:16.633Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/70/7f/c7428734fbdfd4db3d5b9237fc3a857880b2ace66492836f6529fef25d92/librt-0.6.3-cp313-cp313-musllinux_1_2_x86_64.whl" + hash = "sha256:36b2ec8c15030002c7f688b4863e7be42820d7c62d9c6eece3db54a2400f0530" + size = 92_300 + upload-time = "2025-11-29T14:01:17.658Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/f9/0c/738c4824fdfe74dc0f95d5e90ef9e759d4ecf7fd5ba964d54a7703322251/librt-0.6.3-cp313-cp313-win32.whl" + hash = "sha256:25b1b60cb059471c0c0c803e07d0dfdc79e41a0a122f288b819219ed162672a3" + size = 20_159 + upload-time = "2025-11-29T14:01:18.61Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/f2/95/93d0e61bc617306ecf4c54636b5cbde4947d872563565c4abdd9d07a39d3/librt-0.6.3-cp313-cp313-win_amd64.whl" + hash = "sha256:10a95ad074e2a98c9e4abc7f5b7d40e5ecbfa84c04c6ab8a70fabf59bd429b88" + size = 21_484 + upload-time = "2025-11-29T14:01:19.506Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/10/23/abd7ace79ab54d1dbee265f13529266f686a7ce2d21ab59a992f989009b6/librt-0.6.3-cp313-cp313-win_arm64.whl" + hash = "sha256:17000df14f552e86877d67e4ab7966912224efc9368e998c96a6974a8d609bf9" + size = 20_935 + upload-time = "2025-11-29T14:01:20.415Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/83/14/c06cb31152182798ed98be73f54932ab984894f5a8fccf9b73130897a938/librt-0.6.3-cp314-cp314-macosx_10_13_x86_64.whl" + hash = "sha256:8e695f25d1a425ad7a272902af8ab8c8d66c1998b177e4b5f5e7b4e215d0c88a" + size = 27_566 + upload-time = "2025-11-29T14:01:21.609Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/0c/b1/ce83ca7b057b06150519152f53a0b302d7c33c8692ce2f01f669b5a819d9/librt-0.6.3-cp314-cp314-macosx_11_0_arm64.whl" + hash = "sha256:3e84a4121a7ae360ca4da436548a9c1ca8ca134a5ced76c893cc5944426164bd" + size = 27_753 + upload-time = "2025-11-29T14:01:22.558Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/3b/ec/739a885ef0a2839b6c25f1b01c99149d2cb6a34e933ffc8c051fcd22012e/librt-0.6.3-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl" + hash = "sha256:05f385a414de3f950886ea0aad8f109650d4b712cf9cc14cc17f5f62a9ab240b" + size = 83_178 + upload-time = "2025-11-29T14:01:23.555Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/db/bd/dc18bb1489d48c0911b9f4d72eae2d304ea264e215ba80f1e6ba4a9fc41d/librt-0.6.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + hash = "sha256:36a8e337461150b05ca2c7bdedb9e591dfc262c5230422cea398e89d0c746cdc" + size = 87_266 + upload-time = "2025-11-29T14:01:24.532Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/94/f3/d0c5431b39eef15e48088b2d739ad84b17c2f1a22c0345c6d4c4a42b135e/librt-0.6.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + hash = "sha256:dcbe48f6a03979384f27086484dc2a14959be1613cb173458bd58f714f2c48f3" + size = 87_623 + upload-time = "2025-11-29T14:01:25.798Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/3b/15/9a52e90834e4bd6ee16cdbaf551cb32227cbaad27398391a189c489318bc/librt-0.6.3-cp314-cp314-musllinux_1_2_aarch64.whl" + hash = "sha256:4bca9e4c260233fba37b15c4ec2f78aa99c1a79fbf902d19dd4a763c5c3fb751" + size = 89_436 + upload-time = "2025-11-29T14:01:26.769Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/c3/8a/a7e78e46e8486e023c50f21758930ef4793999115229afd65de69e94c9cc/librt-0.6.3-cp314-cp314-musllinux_1_2_i686.whl" + hash = "sha256:760c25ed6ac968e24803eb5f7deb17ce026902d39865e83036bacbf5cf242aa8" + size = 87_540 + upload-time = "2025-11-29T14:01:27.756Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/49/01/93799044a1cccac31f1074b07c583e181829d240539657e7f305ae63ae2a/librt-0.6.3-cp314-cp314-musllinux_1_2_x86_64.whl" + hash = "sha256:4aa4a93a353ccff20df6e34fa855ae8fd788832c88f40a9070e3ddd3356a9f0e" + size = 90_597 + upload-time = "2025-11-29T14:01:29.35Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/a7/29/00c7f58b8f8eb1bad6529ffb6c9cdcc0890a27dac59ecda04f817ead5277/librt-0.6.3-cp314-cp314-win32.whl" + hash = "sha256:cb92741c2b4ea63c09609b064b26f7f5d9032b61ae222558c55832ec3ad0bcaf" + size = 18_955 + upload-time = "2025-11-29T14:01:30.325Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/d7/13/2739e6e197a9f751375a37908a6a5b0bff637b81338497a1bcb5817394da/librt-0.6.3-cp314-cp314-win_amd64.whl" + hash = "sha256:fdcd095b1b812d756fa5452aca93b962cf620694c0cadb192cec2bb77dcca9a2" + size = 20_263 + upload-time = "2025-11-29T14:01:31.287Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/e1/73/393868fc2158705ea003114a24e73bb10b03bda31e9ad7b5c5ec6575338b/librt-0.6.3-cp314-cp314-win_arm64.whl" + hash = "sha256:822ca79e28720a76a935c228d37da6579edef048a17cd98d406a2484d10eda78" + size = 19_575 + upload-time = "2025-11-29T14:01:32.229Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/48/6d/3c8ff3dec21bf804a205286dd63fd28dcdbe00b8dd7eb7ccf2e21a40a0b0/librt-0.6.3-cp314-cp314t-macosx_10_13_x86_64.whl" + hash = "sha256:078cd77064d1640cb7b0650871a772956066174d92c8aeda188a489b58495179" + size = 28_732 + upload-time = "2025-11-29T14:01:33.165Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/f4/90/e214b8b4aa34ed3d3f1040719c06c4d22472c40c5ef81a922d5af7876eb4/librt-0.6.3-cp314-cp314t-macosx_11_0_arm64.whl" + hash = "sha256:5cc22f7f5c0cc50ed69f4b15b9c51d602aabc4500b433aaa2ddd29e578f452f7" + size = 29_065 + upload-time = "2025-11-29T14:01:34.088Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/ab/90/ef61ed51f0a7770cc703422d907a757bbd8811ce820c333d3db2fd13542a/librt-0.6.3-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl" + hash = "sha256:14b345eb7afb61b9fdcdfda6738946bd11b8e0f6be258666b0646af3b9bb5916" + size = 93_703 + upload-time = "2025-11-29T14:01:35.057Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/a8/ae/c30bb119c35962cbe9a908a71da99c168056fc3f6e9bbcbc157d0b724d89/librt-0.6.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + hash = "sha256:6d46aa46aa29b067f0b8b84f448fd9719aaf5f4c621cc279164d76a9dc9ab3e8" + size = 98_890 + upload-time = "2025-11-29T14:01:36.031Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/d1/96/47a4a78d252d36f072b79d592df10600d379a895c3880c8cbd2ac699f0ad/librt-0.6.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + hash = "sha256:1b51ba7d9d5d9001494769eca8c0988adce25d0a970c3ba3f2eb9df9d08036fc" + size = 98_255 + upload-time = "2025-11-29T14:01:37.058Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/e5/28/779b5cc3cd9987683884eb5f5672e3251676bebaaae6b7da1cf366eb1da1/librt-0.6.3-cp314-cp314t-musllinux_1_2_aarch64.whl" + hash = "sha256:ced0925a18fddcff289ef54386b2fc230c5af3c83b11558571124bfc485b8c07" + size = 100_769 + upload-time = "2025-11-29T14:01:38.413Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/28/d7/771755e57c375cb9d25a4e106f570607fd856e2cb91b02418db1db954796/librt-0.6.3-cp314-cp314t-musllinux_1_2_i686.whl" + hash = "sha256:6bac97e51f66da2ca012adddbe9fd656b17f7368d439de30898f24b39512f40f" + size = 98_580 + upload-time = "2025-11-29T14:01:39.459Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/d0/ec/8b157eb8fbc066339a2f34b0aceb2028097d0ed6150a52e23284a311eafe/librt-0.6.3-cp314-cp314t-musllinux_1_2_x86_64.whl" + hash = "sha256:b2922a0e8fa97395553c304edc3bd36168d8eeec26b92478e292e5d4445c1ef0" + size = 101_706 + upload-time = "2025-11-29T14:01:40.474Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/82/a8/4aaead9a06c795a318282aebf7d3e3e578fa889ff396e1b640c3be4c7806/librt-0.6.3-cp314-cp314t-win32.whl" + hash = "sha256:f33462b19503ba68d80dac8a1354402675849259fb3ebf53b67de86421735a3a" + size = 19_465 + upload-time = "2025-11-29T14:01:41.77Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/3a/61/b7e6a02746c1731670c19ba07d86da90b1ae45d29e405c0b5615abf97cde/librt-0.6.3-cp314-cp314t-win_amd64.whl" + hash = "sha256:04f8ce401d4f6380cfc42af0f4e67342bf34c820dae01343f58f472dbac75dcf" + size = 21_042 + upload-time = "2025-11-29T14:01:42.865Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/0e/3d/72cc9ec90bb80b5b1a65f0bb74a0f540195837baaf3b98c7fa4a7aa9718e/librt-0.6.3-cp314-cp314t-win_arm64.whl" + hash = "sha256:afb39550205cc5e5c935762c6bf6a2bb34f7d21a68eadb25e2db7bf3593fecc0" + size = 20_246 + upload-time = "2025-11-29T14:01:44.13Z" [[package]] name = "logging-objects-with-schema" -version = "0.1.1rc3" -source = { editable = "." } - -[package.optional-dependencies] -dev = [ - { name = "bandit" }, - { name = "black" }, - { name = "flake8" }, - { name = "flake8-pyproject" }, - { name = "isort" }, - { name = "mypy" }, - { name = "pre-commit" }, - { name = "pytest" }, - { name = "pytest-cov" }, -] - -[package.metadata] -requires-dist = [ - { name = "bandit", marker = "extra == 'dev'", specifier = ">=1.8.6" }, - { name = "black", marker = "extra == 'dev'", specifier = ">=23.0.0" }, - { name = "flake8", marker = "extra == 'dev'", specifier = ">=6.0.0" }, - { name = "flake8-pyproject", marker = "extra == 'dev'", specifier = ">=1.2.3" }, - { name = "isort", marker = "extra == 'dev'", specifier = ">=5.12.0" }, - { name = "mypy", marker = "extra == 'dev'", specifier = ">=1.18.1" }, - { name = "pre-commit", marker = "extra == 'dev'", specifier = ">=3.5.0" }, - { name = "pytest", marker = "extra == 'dev'", specifier = ">=7.0.0" }, - { name = "pytest-cov", marker = "extra == 'dev'", specifier = ">=4.0.0" }, -] -provides-extras = ["dev"] +version = "0.1.1rc4" + + [package.source] + editable = "." + +[[package.optional-dependencies.dev]] +name = "bandit" + +[[package.optional-dependencies.dev]] +name = "black" + +[[package.optional-dependencies.dev]] +name = "flake8" + +[[package.optional-dependencies.dev]] +name = "flake8-pyproject" + +[[package.optional-dependencies.dev]] +name = "isort" + +[[package.optional-dependencies.dev]] +name = "mypy" + +[[package.optional-dependencies.dev]] +name = "pre-commit" + +[[package.optional-dependencies.dev]] +name = "pytest" + +[[package.optional-dependencies.dev]] +name = "pytest-cov" + + [package.metadata] + provides-extras = [ "dev" ] + + [[package.metadata.requires-dist]] + name = "bandit" + marker = "extra == 'dev'" + specifier = ">=1.8.6" + + [[package.metadata.requires-dist]] + name = "black" + marker = "extra == 'dev'" + specifier = ">=23.0.0" + + [[package.metadata.requires-dist]] + name = "flake8" + marker = "extra == 'dev'" + specifier = ">=6.0.0" + + [[package.metadata.requires-dist]] + name = "flake8-pyproject" + marker = "extra == 'dev'" + specifier = ">=1.2.3" + + [[package.metadata.requires-dist]] + name = "isort" + marker = "extra == 'dev'" + specifier = ">=5.12.0" + + [[package.metadata.requires-dist]] + name = "mypy" + marker = "extra == 'dev'" + specifier = ">=1.18.1" + + [[package.metadata.requires-dist]] + name = "pre-commit" + marker = "extra == 'dev'" + specifier = ">=3.5.0" + + [[package.metadata.requires-dist]] + name = "pytest" + marker = "extra == 'dev'" + specifier = ">=7.0.0" + + [[package.metadata.requires-dist]] + name = "pytest-cov" + marker = "extra == 'dev'" + specifier = ">=4.0.0" [[package]] name = "markdown-it-py" version = "4.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mdurl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [[package.dependencies]] + name = "mdurl" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz" + hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3" + size = 73_070 + upload-time = "2025-08-11T12:57:52.854Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl" + hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147" + size = 87_321 + upload-time = "2025-08-11T12:57:51.923Z" [[package]] name = "mccabe" version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e7/ff/0ffefdcac38932a54d2b5eed4e0ba8a408f215002cd178ad1df0f2806ff8/mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", size = 9658, upload-time = "2022-01-24T01:14:51.113Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/27/1a/1f68f9ba0c207934b35b86a8ca3aad8395a3d6dd7921c0686e23853ff5a9/mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e", size = 7350, upload-time = "2022-01-24T01:14:49.62Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/e7/ff/0ffefdcac38932a54d2b5eed4e0ba8a408f215002cd178ad1df0f2806ff8/mccabe-0.7.0.tar.gz" + hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325" + size = 9_658 + upload-time = "2022-01-24T01:14:51.113Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/27/1a/1f68f9ba0c207934b35b86a8ca3aad8395a3d6dd7921c0686e23853ff5a9/mccabe-0.7.0-py2.py3-none-any.whl" + hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e" + size = 7_350 + upload-time = "2022-01-24T01:14:49.62Z" [[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, upload-time = "2022-08-14T12:40:10.846Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz" + hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba" + size = 8_729 + upload-time = "2022-08-14T12:40:10.846Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl" + hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8" + size = 9_979 + upload-time = "2022-08-14T12:40:09.779Z" [[package]] name = "mypy" version = "1.19.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "librt" }, - { name = "mypy-extensions" }, - { name = "pathspec" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f9/b5/b58cdc25fadd424552804bf410855d52324183112aa004f0732c5f6324cf/mypy-1.19.0.tar.gz", hash = "sha256:f6b874ca77f733222641e5c46e4711648c4037ea13646fd0cdc814c2eaec2528", size = 3579025, upload-time = "2025-11-28T15:49:01.26Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/98/8f/55fb488c2b7dabd76e3f30c10f7ab0f6190c1fcbc3e97b1e588ec625bbe2/mypy-1.19.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6148ede033982a8c5ca1143de34c71836a09f105068aaa8b7d5edab2b053e6c8", size = 13093239, upload-time = "2025-11-28T15:45:11.342Z" }, - { url = "https://files.pythonhosted.org/packages/72/1b/278beea978456c56b3262266274f335c3ba5ff2c8108b3b31bec1ffa4c1d/mypy-1.19.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a9ac09e52bb0f7fb912f5d2a783345c72441a08ef56ce3e17c1752af36340a39", size = 12156128, upload-time = "2025-11-28T15:46:02.566Z" }, - { url = "https://files.pythonhosted.org/packages/21/f8/e06f951902e136ff74fd7a4dc4ef9d884faeb2f8eb9c49461235714f079f/mypy-1.19.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:11f7254c15ab3f8ed68f8e8f5cbe88757848df793e31c36aaa4d4f9783fd08ab", size = 12753508, upload-time = "2025-11-28T15:44:47.538Z" }, - { url = "https://files.pythonhosted.org/packages/67/5a/d035c534ad86e09cee274d53cf0fd769c0b29ca6ed5b32e205be3c06878c/mypy-1.19.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:318ba74f75899b0e78b847d8c50821e4c9637c79d9a59680fc1259f29338cb3e", size = 13507553, upload-time = "2025-11-28T15:44:39.26Z" }, - { url = "https://files.pythonhosted.org/packages/6a/17/c4a5498e00071ef29e483a01558b285d086825b61cf1fb2629fbdd019d94/mypy-1.19.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cf7d84f497f78b682edd407f14a7b6e1a2212b433eedb054e2081380b7395aa3", size = 13792898, upload-time = "2025-11-28T15:44:31.102Z" }, - { url = "https://files.pythonhosted.org/packages/67/f6/bb542422b3ee4399ae1cdc463300d2d91515ab834c6233f2fd1d52fa21e0/mypy-1.19.0-cp310-cp310-win_amd64.whl", hash = "sha256:c3385246593ac2b97f155a0e9639be906e73534630f663747c71908dfbf26134", size = 10048835, upload-time = "2025-11-28T15:48:15.744Z" }, - { url = "https://files.pythonhosted.org/packages/0f/d2/010fb171ae5ac4a01cc34fbacd7544531e5ace95c35ca166dd8fd1b901d0/mypy-1.19.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a31e4c28e8ddb042c84c5e977e28a21195d086aaffaf08b016b78e19c9ef8106", size = 13010563, upload-time = "2025-11-28T15:48:23.975Z" }, - { url = "https://files.pythonhosted.org/packages/41/6b/63f095c9f1ce584fdeb595d663d49e0980c735a1d2004720ccec252c5d47/mypy-1.19.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:34ec1ac66d31644f194b7c163d7f8b8434f1b49719d403a5d26c87fff7e913f7", size = 12077037, upload-time = "2025-11-28T15:47:51.582Z" }, - { url = "https://files.pythonhosted.org/packages/d7/83/6cb93d289038d809023ec20eb0b48bbb1d80af40511fa077da78af6ff7c7/mypy-1.19.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cb64b0ba5980466a0f3f9990d1c582bcab8db12e29815ecb57f1408d99b4bff7", size = 12680255, upload-time = "2025-11-28T15:46:57.628Z" }, - { url = "https://files.pythonhosted.org/packages/99/db/d217815705987d2cbace2edd9100926196d6f85bcb9b5af05058d6e3c8ad/mypy-1.19.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:120cffe120cca5c23c03c77f84abc0c14c5d2e03736f6c312480020082f1994b", size = 13421472, upload-time = "2025-11-28T15:47:59.655Z" }, - { url = "https://files.pythonhosted.org/packages/4e/51/d2beaca7c497944b07594f3f8aad8d2f0e8fc53677059848ae5d6f4d193e/mypy-1.19.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7a500ab5c444268a70565e374fc803972bfd1f09545b13418a5174e29883dab7", size = 13651823, upload-time = "2025-11-28T15:45:29.318Z" }, - { url = "https://files.pythonhosted.org/packages/aa/d1/7883dcf7644db3b69490f37b51029e0870aac4a7ad34d09ceae709a3df44/mypy-1.19.0-cp311-cp311-win_amd64.whl", hash = "sha256:c14a98bc63fd867530e8ec82f217dae29d0550c86e70debc9667fff1ec83284e", size = 10049077, upload-time = "2025-11-28T15:45:39.818Z" }, - { url = "https://files.pythonhosted.org/packages/11/7e/1afa8fb188b876abeaa14460dc4983f909aaacaa4bf5718c00b2c7e0b3d5/mypy-1.19.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0fb3115cb8fa7c5f887c8a8d81ccdcb94cff334684980d847e5a62e926910e1d", size = 13207728, upload-time = "2025-11-28T15:46:26.463Z" }, - { url = "https://files.pythonhosted.org/packages/b2/13/f103d04962bcbefb1644f5ccb235998b32c337d6c13145ea390b9da47f3e/mypy-1.19.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f3e19e3b897562276bb331074d64c076dbdd3e79213f36eed4e592272dabd760", size = 12202945, upload-time = "2025-11-28T15:48:49.143Z" }, - { url = "https://files.pythonhosted.org/packages/e4/93/a86a5608f74a22284a8ccea8592f6e270b61f95b8588951110ad797c2ddd/mypy-1.19.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b9d491295825182fba01b6ffe2c6fe4e5a49dbf4e2bb4d1217b6ced3b4797bc6", size = 12718673, upload-time = "2025-11-28T15:47:37.193Z" }, - { url = "https://files.pythonhosted.org/packages/3d/58/cf08fff9ced0423b858f2a7495001fda28dc058136818ee9dffc31534ea9/mypy-1.19.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6016c52ab209919b46169651b362068f632efcd5eb8ef9d1735f6f86da7853b2", size = 13608336, upload-time = "2025-11-28T15:48:32.625Z" }, - { url = "https://files.pythonhosted.org/packages/64/ed/9c509105c5a6d4b73bb08733102a3ea62c25bc02c51bca85e3134bf912d3/mypy-1.19.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f188dcf16483b3e59f9278c4ed939ec0254aa8a60e8fc100648d9ab5ee95a431", size = 13833174, upload-time = "2025-11-28T15:45:48.091Z" }, - { url = "https://files.pythonhosted.org/packages/cd/71/01939b66e35c6f8cb3e6fdf0b657f0fd24de2f8ba5e523625c8e72328208/mypy-1.19.0-cp312-cp312-win_amd64.whl", hash = "sha256:0e3c3d1e1d62e678c339e7ade72746a9e0325de42cd2cccc51616c7b2ed1a018", size = 10112208, upload-time = "2025-11-28T15:46:41.702Z" }, - { url = "https://files.pythonhosted.org/packages/cb/0d/a1357e6bb49e37ce26fcf7e3cc55679ce9f4ebee0cd8b6ee3a0e301a9210/mypy-1.19.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7686ed65dbabd24d20066f3115018d2dce030d8fa9db01aa9f0a59b6813e9f9e", size = 13191993, upload-time = "2025-11-28T15:47:22.336Z" }, - { url = "https://files.pythonhosted.org/packages/5d/75/8e5d492a879ec4490e6ba664b5154e48c46c85b5ac9785792a5ec6a4d58f/mypy-1.19.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:fd4a985b2e32f23bead72e2fb4bbe5d6aceee176be471243bd831d5b2644672d", size = 12174411, upload-time = "2025-11-28T15:44:55.492Z" }, - { url = "https://files.pythonhosted.org/packages/71/31/ad5dcee9bfe226e8eaba777e9d9d251c292650130f0450a280aec3485370/mypy-1.19.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fc51a5b864f73a3a182584b1ac75c404396a17eced54341629d8bdcb644a5bba", size = 12727751, upload-time = "2025-11-28T15:44:14.169Z" }, - { url = "https://files.pythonhosted.org/packages/77/06/b6b8994ce07405f6039701f4b66e9d23f499d0b41c6dd46ec28f96d57ec3/mypy-1.19.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:37af5166f9475872034b56c5efdcf65ee25394e9e1d172907b84577120714364", size = 13593323, upload-time = "2025-11-28T15:46:34.699Z" }, - { url = "https://files.pythonhosted.org/packages/68/b1/126e274484cccdf099a8e328d4fda1c7bdb98a5e888fa6010b00e1bbf330/mypy-1.19.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:510c014b722308c9bd377993bcbf9a07d7e0692e5fa8fc70e639c1eb19fc6bee", size = 13818032, upload-time = "2025-11-28T15:46:18.286Z" }, - { url = "https://files.pythonhosted.org/packages/f8/56/53a8f70f562dfc466c766469133a8a4909f6c0012d83993143f2a9d48d2d/mypy-1.19.0-cp313-cp313-win_amd64.whl", hash = "sha256:cabbee74f29aa9cd3b444ec2f1e4fa5a9d0d746ce7567a6a609e224429781f53", size = 10120644, upload-time = "2025-11-28T15:47:43.99Z" }, - { url = "https://files.pythonhosted.org/packages/b0/f4/7751f32f56916f7f8c229fe902cbdba3e4dd3f3ea9e8b872be97e7fc546d/mypy-1.19.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:f2e36bed3c6d9b5f35d28b63ca4b727cb0228e480826ffc8953d1892ddc8999d", size = 13185236, upload-time = "2025-11-28T15:45:20.696Z" }, - { url = "https://files.pythonhosted.org/packages/35/31/871a9531f09e78e8d145032355890384f8a5b38c95a2c7732d226b93242e/mypy-1.19.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a18d8abdda14035c5718acb748faec09571432811af129bf0d9e7b2d6699bf18", size = 12213902, upload-time = "2025-11-28T15:46:10.117Z" }, - { url = "https://files.pythonhosted.org/packages/58/b8/af221910dd40eeefa2077a59107e611550167b9994693fc5926a0b0f87c0/mypy-1.19.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f75e60aca3723a23511948539b0d7ed514dda194bc3755eae0bfc7a6b4887aa7", size = 12738600, upload-time = "2025-11-28T15:44:22.521Z" }, - { url = "https://files.pythonhosted.org/packages/11/9f/c39e89a3e319c1d9c734dedec1183b2cc3aefbab066ec611619002abb932/mypy-1.19.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8f44f2ae3c58421ee05fe609160343c25f70e3967f6e32792b5a78006a9d850f", size = 13592639, upload-time = "2025-11-28T15:48:08.55Z" }, - { url = "https://files.pythonhosted.org/packages/97/6d/ffaf5f01f5e284d9033de1267e6c1b8f3783f2cf784465378a86122e884b/mypy-1.19.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:63ea6a00e4bd6822adbfc75b02ab3653a17c02c4347f5bb0cf1d5b9df3a05835", size = 13799132, upload-time = "2025-11-28T15:47:06.032Z" }, - { url = "https://files.pythonhosted.org/packages/fe/b0/c33921e73aaa0106224e5a34822411bea38046188eb781637f5a5b07e269/mypy-1.19.0-cp314-cp314-win_amd64.whl", hash = "sha256:3ad925b14a0bb99821ff6f734553294aa6a3440a8cb082fe1f5b84dfb662afb1", size = 10269832, upload-time = "2025-11-28T15:47:29.392Z" }, - { url = "https://files.pythonhosted.org/packages/09/0e/fe228ed5aeab470c6f4eb82481837fadb642a5aa95cc8215fd2214822c10/mypy-1.19.0-py3-none-any.whl", hash = "sha256:0c01c99d626380752e527d5ce8e69ffbba2046eb8a060db0329690849cf9b6f9", size = 2469714, upload-time = "2025-11-28T15:45:33.22Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [[package.dependencies]] + name = "librt" + + [[package.dependencies]] + name = "mypy-extensions" + + [[package.dependencies]] + name = "pathspec" + + [[package.dependencies]] + name = "tomli" + marker = "python_full_version < '3.11'" + + [[package.dependencies]] + name = "typing-extensions" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/f9/b5/b58cdc25fadd424552804bf410855d52324183112aa004f0732c5f6324cf/mypy-1.19.0.tar.gz" + hash = "sha256:f6b874ca77f733222641e5c46e4711648c4037ea13646fd0cdc814c2eaec2528" + size = 3_579_025 + upload-time = "2025-11-28T15:49:01.26Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/98/8f/55fb488c2b7dabd76e3f30c10f7ab0f6190c1fcbc3e97b1e588ec625bbe2/mypy-1.19.0-cp310-cp310-macosx_10_9_x86_64.whl" + hash = "sha256:6148ede033982a8c5ca1143de34c71836a09f105068aaa8b7d5edab2b053e6c8" + size = 13_093_239 + upload-time = "2025-11-28T15:45:11.342Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/72/1b/278beea978456c56b3262266274f335c3ba5ff2c8108b3b31bec1ffa4c1d/mypy-1.19.0-cp310-cp310-macosx_11_0_arm64.whl" + hash = "sha256:a9ac09e52bb0f7fb912f5d2a783345c72441a08ef56ce3e17c1752af36340a39" + size = 12_156_128 + upload-time = "2025-11-28T15:46:02.566Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/21/f8/e06f951902e136ff74fd7a4dc4ef9d884faeb2f8eb9c49461235714f079f/mypy-1.19.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + hash = "sha256:11f7254c15ab3f8ed68f8e8f5cbe88757848df793e31c36aaa4d4f9783fd08ab" + size = 12_753_508 + upload-time = "2025-11-28T15:44:47.538Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/67/5a/d035c534ad86e09cee274d53cf0fd769c0b29ca6ed5b32e205be3c06878c/mypy-1.19.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + hash = "sha256:318ba74f75899b0e78b847d8c50821e4c9637c79d9a59680fc1259f29338cb3e" + size = 13_507_553 + upload-time = "2025-11-28T15:44:39.26Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/6a/17/c4a5498e00071ef29e483a01558b285d086825b61cf1fb2629fbdd019d94/mypy-1.19.0-cp310-cp310-musllinux_1_2_x86_64.whl" + hash = "sha256:cf7d84f497f78b682edd407f14a7b6e1a2212b433eedb054e2081380b7395aa3" + size = 13_792_898 + upload-time = "2025-11-28T15:44:31.102Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/67/f6/bb542422b3ee4399ae1cdc463300d2d91515ab834c6233f2fd1d52fa21e0/mypy-1.19.0-cp310-cp310-win_amd64.whl" + hash = "sha256:c3385246593ac2b97f155a0e9639be906e73534630f663747c71908dfbf26134" + size = 10_048_835 + upload-time = "2025-11-28T15:48:15.744Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/0f/d2/010fb171ae5ac4a01cc34fbacd7544531e5ace95c35ca166dd8fd1b901d0/mypy-1.19.0-cp311-cp311-macosx_10_9_x86_64.whl" + hash = "sha256:a31e4c28e8ddb042c84c5e977e28a21195d086aaffaf08b016b78e19c9ef8106" + size = 13_010_563 + upload-time = "2025-11-28T15:48:23.975Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/41/6b/63f095c9f1ce584fdeb595d663d49e0980c735a1d2004720ccec252c5d47/mypy-1.19.0-cp311-cp311-macosx_11_0_arm64.whl" + hash = "sha256:34ec1ac66d31644f194b7c163d7f8b8434f1b49719d403a5d26c87fff7e913f7" + size = 12_077_037 + upload-time = "2025-11-28T15:47:51.582Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/d7/83/6cb93d289038d809023ec20eb0b48bbb1d80af40511fa077da78af6ff7c7/mypy-1.19.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + hash = "sha256:cb64b0ba5980466a0f3f9990d1c582bcab8db12e29815ecb57f1408d99b4bff7" + size = 12_680_255 + upload-time = "2025-11-28T15:46:57.628Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/99/db/d217815705987d2cbace2edd9100926196d6f85bcb9b5af05058d6e3c8ad/mypy-1.19.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + hash = "sha256:120cffe120cca5c23c03c77f84abc0c14c5d2e03736f6c312480020082f1994b" + size = 13_421_472 + upload-time = "2025-11-28T15:47:59.655Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/4e/51/d2beaca7c497944b07594f3f8aad8d2f0e8fc53677059848ae5d6f4d193e/mypy-1.19.0-cp311-cp311-musllinux_1_2_x86_64.whl" + hash = "sha256:7a500ab5c444268a70565e374fc803972bfd1f09545b13418a5174e29883dab7" + size = 13_651_823 + upload-time = "2025-11-28T15:45:29.318Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/aa/d1/7883dcf7644db3b69490f37b51029e0870aac4a7ad34d09ceae709a3df44/mypy-1.19.0-cp311-cp311-win_amd64.whl" + hash = "sha256:c14a98bc63fd867530e8ec82f217dae29d0550c86e70debc9667fff1ec83284e" + size = 10_049_077 + upload-time = "2025-11-28T15:45:39.818Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/11/7e/1afa8fb188b876abeaa14460dc4983f909aaacaa4bf5718c00b2c7e0b3d5/mypy-1.19.0-cp312-cp312-macosx_10_13_x86_64.whl" + hash = "sha256:0fb3115cb8fa7c5f887c8a8d81ccdcb94cff334684980d847e5a62e926910e1d" + size = 13_207_728 + upload-time = "2025-11-28T15:46:26.463Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/b2/13/f103d04962bcbefb1644f5ccb235998b32c337d6c13145ea390b9da47f3e/mypy-1.19.0-cp312-cp312-macosx_11_0_arm64.whl" + hash = "sha256:f3e19e3b897562276bb331074d64c076dbdd3e79213f36eed4e592272dabd760" + size = 12_202_945 + upload-time = "2025-11-28T15:48:49.143Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/e4/93/a86a5608f74a22284a8ccea8592f6e270b61f95b8588951110ad797c2ddd/mypy-1.19.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + hash = "sha256:b9d491295825182fba01b6ffe2c6fe4e5a49dbf4e2bb4d1217b6ced3b4797bc6" + size = 12_718_673 + upload-time = "2025-11-28T15:47:37.193Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/3d/58/cf08fff9ced0423b858f2a7495001fda28dc058136818ee9dffc31534ea9/mypy-1.19.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + hash = "sha256:6016c52ab209919b46169651b362068f632efcd5eb8ef9d1735f6f86da7853b2" + size = 13_608_336 + upload-time = "2025-11-28T15:48:32.625Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/64/ed/9c509105c5a6d4b73bb08733102a3ea62c25bc02c51bca85e3134bf912d3/mypy-1.19.0-cp312-cp312-musllinux_1_2_x86_64.whl" + hash = "sha256:f188dcf16483b3e59f9278c4ed939ec0254aa8a60e8fc100648d9ab5ee95a431" + size = 13_833_174 + upload-time = "2025-11-28T15:45:48.091Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/cd/71/01939b66e35c6f8cb3e6fdf0b657f0fd24de2f8ba5e523625c8e72328208/mypy-1.19.0-cp312-cp312-win_amd64.whl" + hash = "sha256:0e3c3d1e1d62e678c339e7ade72746a9e0325de42cd2cccc51616c7b2ed1a018" + size = 10_112_208 + upload-time = "2025-11-28T15:46:41.702Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/cb/0d/a1357e6bb49e37ce26fcf7e3cc55679ce9f4ebee0cd8b6ee3a0e301a9210/mypy-1.19.0-cp313-cp313-macosx_10_13_x86_64.whl" + hash = "sha256:7686ed65dbabd24d20066f3115018d2dce030d8fa9db01aa9f0a59b6813e9f9e" + size = 13_191_993 + upload-time = "2025-11-28T15:47:22.336Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/5d/75/8e5d492a879ec4490e6ba664b5154e48c46c85b5ac9785792a5ec6a4d58f/mypy-1.19.0-cp313-cp313-macosx_11_0_arm64.whl" + hash = "sha256:fd4a985b2e32f23bead72e2fb4bbe5d6aceee176be471243bd831d5b2644672d" + size = 12_174_411 + upload-time = "2025-11-28T15:44:55.492Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/71/31/ad5dcee9bfe226e8eaba777e9d9d251c292650130f0450a280aec3485370/mypy-1.19.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + hash = "sha256:fc51a5b864f73a3a182584b1ac75c404396a17eced54341629d8bdcb644a5bba" + size = 12_727_751 + upload-time = "2025-11-28T15:44:14.169Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/77/06/b6b8994ce07405f6039701f4b66e9d23f499d0b41c6dd46ec28f96d57ec3/mypy-1.19.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + hash = "sha256:37af5166f9475872034b56c5efdcf65ee25394e9e1d172907b84577120714364" + size = 13_593_323 + upload-time = "2025-11-28T15:46:34.699Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/68/b1/126e274484cccdf099a8e328d4fda1c7bdb98a5e888fa6010b00e1bbf330/mypy-1.19.0-cp313-cp313-musllinux_1_2_x86_64.whl" + hash = "sha256:510c014b722308c9bd377993bcbf9a07d7e0692e5fa8fc70e639c1eb19fc6bee" + size = 13_818_032 + upload-time = "2025-11-28T15:46:18.286Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/f8/56/53a8f70f562dfc466c766469133a8a4909f6c0012d83993143f2a9d48d2d/mypy-1.19.0-cp313-cp313-win_amd64.whl" + hash = "sha256:cabbee74f29aa9cd3b444ec2f1e4fa5a9d0d746ce7567a6a609e224429781f53" + size = 10_120_644 + upload-time = "2025-11-28T15:47:43.99Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/b0/f4/7751f32f56916f7f8c229fe902cbdba3e4dd3f3ea9e8b872be97e7fc546d/mypy-1.19.0-cp314-cp314-macosx_10_15_x86_64.whl" + hash = "sha256:f2e36bed3c6d9b5f35d28b63ca4b727cb0228e480826ffc8953d1892ddc8999d" + size = 13_185_236 + upload-time = "2025-11-28T15:45:20.696Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/35/31/871a9531f09e78e8d145032355890384f8a5b38c95a2c7732d226b93242e/mypy-1.19.0-cp314-cp314-macosx_11_0_arm64.whl" + hash = "sha256:a18d8abdda14035c5718acb748faec09571432811af129bf0d9e7b2d6699bf18" + size = 12_213_902 + upload-time = "2025-11-28T15:46:10.117Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/58/b8/af221910dd40eeefa2077a59107e611550167b9994693fc5926a0b0f87c0/mypy-1.19.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + hash = "sha256:f75e60aca3723a23511948539b0d7ed514dda194bc3755eae0bfc7a6b4887aa7" + size = 12_738_600 + upload-time = "2025-11-28T15:44:22.521Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/11/9f/c39e89a3e319c1d9c734dedec1183b2cc3aefbab066ec611619002abb932/mypy-1.19.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + hash = "sha256:8f44f2ae3c58421ee05fe609160343c25f70e3967f6e32792b5a78006a9d850f" + size = 13_592_639 + upload-time = "2025-11-28T15:48:08.55Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/97/6d/ffaf5f01f5e284d9033de1267e6c1b8f3783f2cf784465378a86122e884b/mypy-1.19.0-cp314-cp314-musllinux_1_2_x86_64.whl" + hash = "sha256:63ea6a00e4bd6822adbfc75b02ab3653a17c02c4347f5bb0cf1d5b9df3a05835" + size = 13_799_132 + upload-time = "2025-11-28T15:47:06.032Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/fe/b0/c33921e73aaa0106224e5a34822411bea38046188eb781637f5a5b07e269/mypy-1.19.0-cp314-cp314-win_amd64.whl" + hash = "sha256:3ad925b14a0bb99821ff6f734553294aa6a3440a8cb082fe1f5b84dfb662afb1" + size = 10_269_832 + upload-time = "2025-11-28T15:47:29.392Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/09/0e/fe228ed5aeab470c6f4eb82481837fadb642a5aa95cc8215fd2214822c10/mypy-1.19.0-py3-none-any.whl" + hash = "sha256:0c01c99d626380752e527d5ce8e69ffbba2046eb8a060db0329690849cf9b6f9" + size = 2_469_714 + upload-time = "2025-11-28T15:45:33.22Z" [[package]] name = "mypy-extensions" version = "1.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz" + hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558" + size = 6_343 + upload-time = "2025-04-22T14:54:24.164Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl" + hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505" + size = 4_963 + upload-time = "2025-04-22T14:54:22.983Z" [[package]] name = "nodeenv" version = "1.9.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437, upload-time = "2024-06-04T18:44:11.171Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314, upload-time = "2024-06-04T18:44:08.352Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz" + hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f" + size = 47_437 + upload-time = "2024-06-04T18:44:11.171Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl" + hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9" + size = 22_314 + upload-time = "2024-06-04T18:44:08.352Z" [[package]] name = "packaging" version = "25.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz" + hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f" + size = 165_727 + upload-time = "2025-04-19T11:48:59.673Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl" + hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484" + size = 66_469 + upload-time = "2025-04-19T11:48:57.875Z" [[package]] name = "pathspec" version = "0.12.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz" + hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712" + size = 51_043 + upload-time = "2023-12-10T22:30:45Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl" + hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08" + size = 31_191 + upload-time = "2023-12-10T22:30:43.14Z" [[package]] name = "platformdirs" version = "4.5.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/61/33/9611380c2bdb1225fdef633e2a9610622310fed35ab11dac9620972ee088/platformdirs-4.5.0.tar.gz", hash = "sha256:70ddccdd7c99fc5942e9fc25636a8b34d04c24b335100223152c2803e4063312", size = 21632, upload-time = "2025-10-08T17:44:48.791Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/73/cb/ac7874b3e5d58441674fb70742e6c374b28b0c7cb988d37d991cde47166c/platformdirs-4.5.0-py3-none-any.whl", hash = "sha256:e578a81bb873cbb89a41fcc904c7ef523cc18284b7e3b3ccf06aca1403b7ebd3", size = 18651, upload-time = "2025-10-08T17:44:47.223Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/61/33/9611380c2bdb1225fdef633e2a9610622310fed35ab11dac9620972ee088/platformdirs-4.5.0.tar.gz" + hash = "sha256:70ddccdd7c99fc5942e9fc25636a8b34d04c24b335100223152c2803e4063312" + size = 21_632 + upload-time = "2025-10-08T17:44:48.791Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/73/cb/ac7874b3e5d58441674fb70742e6c374b28b0c7cb988d37d991cde47166c/platformdirs-4.5.0-py3-none-any.whl" + hash = "sha256:e578a81bb873cbb89a41fcc904c7ef523cc18284b7e3b3ccf06aca1403b7ebd3" + size = 18_651 + upload-time = "2025-10-08T17:44:47.223Z" [[package]] name = "pluggy" version = "1.6.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz" + hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3" + size = 69_412 + upload-time = "2025-05-15T12:30:07.975Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl" + hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746" + size = 20_538 + upload-time = "2025-05-15T12:30:06.134Z" [[package]] name = "pre-commit" version = "4.5.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cfgv" }, - { name = "identify" }, - { name = "nodeenv" }, - { name = "pyyaml" }, - { name = "virtualenv" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f4/9b/6a4ffb4ed980519da959e1cf3122fc6cb41211daa58dbae1c73c0e519a37/pre_commit-4.5.0.tar.gz", hash = "sha256:dc5a065e932b19fc1d4c653c6939068fe54325af8e741e74e88db4d28a4dd66b", size = 198428, upload-time = "2025-11-22T21:02:42.304Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5d/c4/b2d28e9d2edf4f1713eb3c29307f1a63f3d67cf09bdda29715a36a68921a/pre_commit-4.5.0-py2.py3-none-any.whl", hash = "sha256:25e2ce09595174d9c97860a95609f9f852c0614ba602de3561e267547f2335e1", size = 226429, upload-time = "2025-11-22T21:02:40.836Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [[package.dependencies]] + name = "cfgv" + + [[package.dependencies]] + name = "identify" + + [[package.dependencies]] + name = "nodeenv" + + [[package.dependencies]] + name = "pyyaml" + + [[package.dependencies]] + name = "virtualenv" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/f4/9b/6a4ffb4ed980519da959e1cf3122fc6cb41211daa58dbae1c73c0e519a37/pre_commit-4.5.0.tar.gz" + hash = "sha256:dc5a065e932b19fc1d4c653c6939068fe54325af8e741e74e88db4d28a4dd66b" + size = 198_428 + upload-time = "2025-11-22T21:02:42.304Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/5d/c4/b2d28e9d2edf4f1713eb3c29307f1a63f3d67cf09bdda29715a36a68921a/pre_commit-4.5.0-py2.py3-none-any.whl" + hash = "sha256:25e2ce09595174d9c97860a95609f9f852c0614ba602de3561e267547f2335e1" + size = 226_429 + upload-time = "2025-11-22T21:02:40.836Z" [[package]] name = "pycodestyle" version = "2.14.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/11/e0/abfd2a0d2efe47670df87f3e3a0e2edda42f055053c85361f19c0e2c1ca8/pycodestyle-2.14.0.tar.gz", hash = "sha256:c4b5b517d278089ff9d0abdec919cd97262a3367449ea1c8b49b91529167b783", size = 39472, upload-time = "2025-06-20T18:49:48.75Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d7/27/a58ddaf8c588a3ef080db9d0b7e0b97215cee3a45df74f3a94dbbf5c893a/pycodestyle-2.14.0-py2.py3-none-any.whl", hash = "sha256:dd6bf7cb4ee77f8e016f9c8e74a35ddd9f67e1d5fd4184d86c3b98e07099f42d", size = 31594, upload-time = "2025-06-20T18:49:47.491Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/11/e0/abfd2a0d2efe47670df87f3e3a0e2edda42f055053c85361f19c0e2c1ca8/pycodestyle-2.14.0.tar.gz" + hash = "sha256:c4b5b517d278089ff9d0abdec919cd97262a3367449ea1c8b49b91529167b783" + size = 39_472 + upload-time = "2025-06-20T18:49:48.75Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/d7/27/a58ddaf8c588a3ef080db9d0b7e0b97215cee3a45df74f3a94dbbf5c893a/pycodestyle-2.14.0-py2.py3-none-any.whl" + hash = "sha256:dd6bf7cb4ee77f8e016f9c8e74a35ddd9f67e1d5fd4184d86c3b98e07099f42d" + size = 31_594 + upload-time = "2025-06-20T18:49:47.491Z" [[package]] name = "pyflakes" version = "3.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/45/dc/fd034dc20b4b264b3d015808458391acbf9df40b1e54750ef175d39180b1/pyflakes-3.4.0.tar.gz", hash = "sha256:b24f96fafb7d2ab0ec5075b7350b3d2d2218eab42003821c06344973d3ea2f58", size = 64669, upload-time = "2025-06-20T18:45:27.834Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c2/2f/81d580a0fb83baeb066698975cb14a618bdbed7720678566f1b046a95fe8/pyflakes-3.4.0-py2.py3-none-any.whl", hash = "sha256:f742a7dbd0d9cb9ea41e9a24a918996e8170c799fa528688d40dd582c8265f4f", size = 63551, upload-time = "2025-06-20T18:45:26.937Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/45/dc/fd034dc20b4b264b3d015808458391acbf9df40b1e54750ef175d39180b1/pyflakes-3.4.0.tar.gz" + hash = "sha256:b24f96fafb7d2ab0ec5075b7350b3d2d2218eab42003821c06344973d3ea2f58" + size = 64_669 + upload-time = "2025-06-20T18:45:27.834Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/c2/2f/81d580a0fb83baeb066698975cb14a618bdbed7720678566f1b046a95fe8/pyflakes-3.4.0-py2.py3-none-any.whl" + hash = "sha256:f742a7dbd0d9cb9ea41e9a24a918996e8170c799fa528688d40dd582c8265f4f" + size = 63_551 + upload-time = "2025-06-20T18:45:26.937Z" [[package]] name = "pygments" version = "2.19.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz" + hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887" + size = 4_968_631 + upload-time = "2025-06-21T13:39:12.283Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl" + hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b" + size = 1_225_217 + upload-time = "2025-06-21T13:39:07.939Z" [[package]] name = "pytest" version = "9.0.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, - { name = "iniconfig" }, - { name = "packaging" }, - { name = "pluggy" }, - { name = "pygments" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/07/56/f013048ac4bc4c1d9be45afd4ab209ea62822fb1598f40687e6bf45dcea4/pytest-9.0.1.tar.gz", hash = "sha256:3e9c069ea73583e255c3b21cf46b8d3c56f6e3a1a8f6da94ccb0fcf57b9d73c8", size = 1564125, upload-time = "2025-11-12T13:05:09.333Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0b/8b/6300fb80f858cda1c51ffa17075df5d846757081d11ab4aa35cef9e6258b/pytest-9.0.1-py3-none-any.whl", hash = "sha256:67be0030d194df2dfa7b556f2e56fb3c3315bd5c8822c6951162b92b32ce7dad", size = 373668, upload-time = "2025-11-12T13:05:07.379Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [[package.dependencies]] + name = "colorama" + marker = "sys_platform == 'win32'" + + [[package.dependencies]] + name = "exceptiongroup" + marker = "python_full_version < '3.11'" + + [[package.dependencies]] + name = "iniconfig" + + [[package.dependencies]] + name = "packaging" + + [[package.dependencies]] + name = "pluggy" + + [[package.dependencies]] + name = "pygments" + + [[package.dependencies]] + name = "tomli" + marker = "python_full_version < '3.11'" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/07/56/f013048ac4bc4c1d9be45afd4ab209ea62822fb1598f40687e6bf45dcea4/pytest-9.0.1.tar.gz" + hash = "sha256:3e9c069ea73583e255c3b21cf46b8d3c56f6e3a1a8f6da94ccb0fcf57b9d73c8" + size = 1_564_125 + upload-time = "2025-11-12T13:05:09.333Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/0b/8b/6300fb80f858cda1c51ffa17075df5d846757081d11ab4aa35cef9e6258b/pytest-9.0.1-py3-none-any.whl" + hash = "sha256:67be0030d194df2dfa7b556f2e56fb3c3315bd5c8822c6951162b92b32ce7dad" + size = 373_668 + upload-time = "2025-11-12T13:05:07.379Z" [[package]] name = "pytest-cov" version = "7.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "coverage", extra = ["toml"] }, - { name = "pluggy" }, - { name = "pytest" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5e/f7/c933acc76f5208b3b00089573cf6a2bc26dc80a8aece8f52bb7d6b1855ca/pytest_cov-7.0.0.tar.gz", hash = "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1", size = 54328, upload-time = "2025-09-09T10:57:02.113Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ee/49/1377b49de7d0c1ce41292161ea0f721913fa8722c19fb9c1e3aa0367eecb/pytest_cov-7.0.0-py3-none-any.whl", hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861", size = 22424, upload-time = "2025-09-09T10:57:00.695Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [[package.dependencies]] + name = "coverage" + extra = [ "toml" ] + + [[package.dependencies]] + name = "pluggy" + + [[package.dependencies]] + name = "pytest" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/5e/f7/c933acc76f5208b3b00089573cf6a2bc26dc80a8aece8f52bb7d6b1855ca/pytest_cov-7.0.0.tar.gz" + hash = "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1" + size = 54_328 + upload-time = "2025-09-09T10:57:02.113Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/ee/49/1377b49de7d0c1ce41292161ea0f721913fa8722c19fb9c1e3aa0367eecb/pytest_cov-7.0.0-py3-none-any.whl" + hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861" + size = 22_424 + upload-time = "2025-09-09T10:57:00.695Z" [[package]] name = "pytokens" version = "0.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4e/8d/a762be14dae1c3bf280202ba3172020b2b0b4c537f94427435f19c413b72/pytokens-0.3.0.tar.gz", hash = "sha256:2f932b14ed08de5fcf0b391ace2642f858f1394c0857202959000b68ed7a458a", size = 17644, upload-time = "2025-11-05T13:36:35.34Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/84/25/d9db8be44e205a124f6c98bc0324b2bb149b7431c53877fc6d1038dddaf5/pytokens-0.3.0-py3-none-any.whl", hash = "sha256:95b2b5eaf832e469d141a378872480ede3f251a5a5041b8ec6e581d3ac71bbf3", size = 12195, upload-time = "2025-11-05T13:36:33.183Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/4e/8d/a762be14dae1c3bf280202ba3172020b2b0b4c537f94427435f19c413b72/pytokens-0.3.0.tar.gz" + hash = "sha256:2f932b14ed08de5fcf0b391ace2642f858f1394c0857202959000b68ed7a458a" + size = 17_644 + upload-time = "2025-11-05T13:36:35.34Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/84/25/d9db8be44e205a124f6c98bc0324b2bb149b7431c53877fc6d1038dddaf5/pytokens-0.3.0-py3-none-any.whl" + hash = "sha256:95b2b5eaf832e469d141a378872480ede3f251a5a5041b8ec6e581d3ac71bbf3" + size = 12_195 + upload-time = "2025-11-05T13:36:33.183Z" [[package]] name = "pyyaml" version = "6.0.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/a0/39350dd17dd6d6c6507025c0e53aef67a9293a6d37d3511f23ea510d5800/pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", size = 184227, upload-time = "2025-09-25T21:31:46.04Z" }, - { url = "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", size = 174019, upload-time = "2025-09-25T21:31:47.706Z" }, - { url = "https://files.pythonhosted.org/packages/43/f7/0e6a5ae5599c838c696adb4e6330a59f463265bfa1e116cfd1fbb0abaaae/pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", size = 740646, upload-time = "2025-09-25T21:31:49.21Z" }, - { url = "https://files.pythonhosted.org/packages/2f/3a/61b9db1d28f00f8fd0ae760459a5c4bf1b941baf714e207b6eb0657d2578/pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", size = 840793, upload-time = "2025-09-25T21:31:50.735Z" }, - { url = "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", size = 770293, upload-time = "2025-09-25T21:31:51.828Z" }, - { url = "https://files.pythonhosted.org/packages/8b/ef/abd085f06853af0cd59fa5f913d61a8eab65d7639ff2a658d18a25d6a89d/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", size = 732872, upload-time = "2025-09-25T21:31:53.282Z" }, - { url = "https://files.pythonhosted.org/packages/1f/15/2bc9c8faf6450a8b3c9fc5448ed869c599c0a74ba2669772b1f3a0040180/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", size = 758828, upload-time = "2025-09-25T21:31:54.807Z" }, - { url = "https://files.pythonhosted.org/packages/a3/00/531e92e88c00f4333ce359e50c19b8d1de9fe8d581b1534e35ccfbc5f393/pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", size = 142415, upload-time = "2025-09-25T21:31:55.885Z" }, - { url = "https://files.pythonhosted.org/packages/2a/fa/926c003379b19fca39dd4634818b00dec6c62d87faf628d1394e137354d4/pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", size = 158561, upload-time = "2025-09-25T21:31:57.406Z" }, - { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload-time = "2025-09-25T21:31:58.655Z" }, - { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload-time = "2025-09-25T21:32:00.088Z" }, - { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload-time = "2025-09-25T21:32:01.31Z" }, - { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114, upload-time = "2025-09-25T21:32:03.376Z" }, - { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638, upload-time = "2025-09-25T21:32:04.553Z" }, - { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463, upload-time = "2025-09-25T21:32:06.152Z" }, - { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986, upload-time = "2025-09-25T21:32:07.367Z" }, - { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543, upload-time = "2025-09-25T21:32:08.95Z" }, - { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763, upload-time = "2025-09-25T21:32:09.96Z" }, - { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, - { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, - { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, - { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, - { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, - { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, - { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, - { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, - { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, - { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, - { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, - { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, - { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, - { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, - { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, - { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, - { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, - { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, - { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, - { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, - { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, - { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, - { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, - { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, - { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, - { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, - { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, - { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, - { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, - { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, - { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, - { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, - { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, - { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, - { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, - { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, - { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, - { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz" + hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f" + size = 130_960 + upload-time = "2025-09-25T21:33:16.546Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/f4/a0/39350dd17dd6d6c6507025c0e53aef67a9293a6d37d3511f23ea510d5800/pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl" + hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b" + size = 184_227 + upload-time = "2025-09-25T21:31:46.04Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl" + hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956" + size = 174_019 + upload-time = "2025-09-25T21:31:47.706Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/43/f7/0e6a5ae5599c838c696adb4e6330a59f463265bfa1e116cfd1fbb0abaaae/pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8" + size = 740_646 + upload-time = "2025-09-25T21:31:49.21Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/2f/3a/61b9db1d28f00f8fd0ae760459a5c4bf1b941baf714e207b6eb0657d2578/pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl" + hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198" + size = 840_793 + upload-time = "2025-09-25T21:31:50.735Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b" + size = 770_293 + upload-time = "2025-09-25T21:31:51.828Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/8b/ef/abd085f06853af0cd59fa5f913d61a8eab65d7639ff2a658d18a25d6a89d/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl" + hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0" + size = 732_872 + upload-time = "2025-09-25T21:31:53.282Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/1f/15/2bc9c8faf6450a8b3c9fc5448ed869c599c0a74ba2669772b1f3a0040180/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl" + hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69" + size = 758_828 + upload-time = "2025-09-25T21:31:54.807Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/a3/00/531e92e88c00f4333ce359e50c19b8d1de9fe8d581b1534e35ccfbc5f393/pyyaml-6.0.3-cp310-cp310-win32.whl" + hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e" + size = 142_415 + upload-time = "2025-09-25T21:31:55.885Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/2a/fa/926c003379b19fca39dd4634818b00dec6c62d87faf628d1394e137354d4/pyyaml-6.0.3-cp310-cp310-win_amd64.whl" + hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c" + size = 158_561 + upload-time = "2025-09-25T21:31:57.406Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl" + hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e" + size = 185_826 + upload-time = "2025-09-25T21:31:58.655Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl" + hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824" + size = 175_577 + upload-time = "2025-09-25T21:32:00.088Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c" + size = 775_556 + upload-time = "2025-09-25T21:32:01.31Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl" + hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00" + size = 882_114 + upload-time = "2025-09-25T21:32:03.376Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d" + size = 806_638 + upload-time = "2025-09-25T21:32:04.553Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl" + hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a" + size = 767_463 + upload-time = "2025-09-25T21:32:06.152Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl" + hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4" + size = 794_986 + upload-time = "2025-09-25T21:32:07.367Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl" + hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b" + size = 142_543 + upload-time = "2025-09-25T21:32:08.95Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl" + hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf" + size = 158_763 + upload-time = "2025-09-25T21:32:09.96Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl" + hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196" + size = 182_063 + upload-time = "2025-09-25T21:32:11.445Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl" + hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0" + size = 173_973 + upload-time = "2025-09-25T21:32:12.492Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28" + size = 775_116 + upload-time = "2025-09-25T21:32:13.652Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl" + hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c" + size = 844_011 + upload-time = "2025-09-25T21:32:15.21Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc" + size = 807_870 + upload-time = "2025-09-25T21:32:16.431Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl" + hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e" + size = 761_089 + upload-time = "2025-09-25T21:32:17.56Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl" + hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea" + size = 790_181 + upload-time = "2025-09-25T21:32:18.834Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl" + hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5" + size = 137_658 + upload-time = "2025-09-25T21:32:20.209Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl" + hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b" + size = 154_003 + upload-time = "2025-09-25T21:32:21.167Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl" + hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd" + size = 140_344 + upload-time = "2025-09-25T21:32:22.617Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl" + hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8" + size = 181_669 + upload-time = "2025-09-25T21:32:23.673Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl" + hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1" + size = 173_252 + upload-time = "2025-09-25T21:32:25.149Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c" + size = 767_081 + upload-time = "2025-09-25T21:32:26.575Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl" + hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5" + size = 841_159 + upload-time = "2025-09-25T21:32:27.727Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6" + size = 801_626 + upload-time = "2025-09-25T21:32:28.878Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl" + hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6" + size = 753_613 + upload-time = "2025-09-25T21:32:30.178Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl" + hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be" + size = 794_115 + upload-time = "2025-09-25T21:32:31.353Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl" + hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26" + size = 137_427 + upload-time = "2025-09-25T21:32:32.58Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl" + hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c" + size = 154_090 + upload-time = "2025-09-25T21:32:33.659Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl" + hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb" + size = 140_246 + upload-time = "2025-09-25T21:32:34.663Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl" + hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac" + size = 181_814 + upload-time = "2025-09-25T21:32:35.712Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl" + hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310" + size = 173_809 + upload-time = "2025-09-25T21:32:36.789Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7" + size = 766_454 + upload-time = "2025-09-25T21:32:37.966Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl" + hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788" + size = 836_355 + upload-time = "2025-09-25T21:32:39.178Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5" + size = 794_175 + upload-time = "2025-09-25T21:32:40.865Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl" + hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764" + size = 755_228 + upload-time = "2025-09-25T21:32:42.084Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl" + hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35" + size = 789_194 + upload-time = "2025-09-25T21:32:43.362Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl" + hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac" + size = 156_429 + upload-time = "2025-09-25T21:32:57.844Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl" + hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3" + size = 143_912 + upload-time = "2025-09-25T21:32:59.247Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl" + hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3" + size = 189_108 + upload-time = "2025-09-25T21:32:44.377Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl" + hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba" + size = 183_641 + upload-time = "2025-09-25T21:32:45.407Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c" + size = 831_901 + upload-time = "2025-09-25T21:32:48.83Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl" + hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702" + size = 861_132 + upload-time = "2025-09-25T21:32:50.149Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c" + size = 839_261 + upload-time = "2025-09-25T21:32:51.808Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl" + hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065" + size = 805_272 + upload-time = "2025-09-25T21:32:52.941Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl" + hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65" + size = 829_923 + upload-time = "2025-09-25T21:32:54.537Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl" + hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9" + size = 174_062 + upload-time = "2025-09-25T21:32:55.767Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl" + hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b" + size = 149_341 + upload-time = "2025-09-25T21:32:56.828Z" [[package]] name = "rich" version = "14.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markdown-it-py" }, - { name = "pygments" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fb/d2/8920e102050a0de7bfabeb4c4614a49248cf8d5d7a8d01885fbb24dc767a/rich-14.2.0.tar.gz", hash = "sha256:73ff50c7c0c1c77c8243079283f4edb376f0f6442433aecb8ce7e6d0b92d1fe4", size = 219990, upload-time = "2025-10-09T14:16:53.064Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/25/7a/b0178788f8dc6cafce37a212c99565fa1fe7872c70c6c9c1e1a372d9d88f/rich-14.2.0-py3-none-any.whl", hash = "sha256:76bc51fe2e57d2b1be1f96c524b890b816e334ab4c1e45888799bfaab0021edd", size = 243393, upload-time = "2025-10-09T14:16:51.245Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [[package.dependencies]] + name = "markdown-it-py" + + [[package.dependencies]] + name = "pygments" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/fb/d2/8920e102050a0de7bfabeb4c4614a49248cf8d5d7a8d01885fbb24dc767a/rich-14.2.0.tar.gz" + hash = "sha256:73ff50c7c0c1c77c8243079283f4edb376f0f6442433aecb8ce7e6d0b92d1fe4" + size = 219_990 + upload-time = "2025-10-09T14:16:53.064Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/25/7a/b0178788f8dc6cafce37a212c99565fa1fe7872c70c6c9c1e1a372d9d88f/rich-14.2.0-py3-none-any.whl" + hash = "sha256:76bc51fe2e57d2b1be1f96c524b890b816e334ab4c1e45888799bfaab0021edd" + size = 243_393 + upload-time = "2025-10-09T14:16:51.245Z" [[package]] name = "stevedore" version = "5.6.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/96/5b/496f8abebd10c3301129abba7ddafd46c71d799a70c44ab080323987c4c9/stevedore-5.6.0.tar.gz", hash = "sha256:f22d15c6ead40c5bbfa9ca54aa7e7b4a07d59b36ae03ed12ced1a54cf0b51945", size = 516074, upload-time = "2025-11-20T10:06:07.264Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/40/8561ce06dc46fd17242c7724ab25b257a2ac1b35f4ebf551b40ce6105cfa/stevedore-5.6.0-py3-none-any.whl", hash = "sha256:4a36dccefd7aeea0c70135526cecb7766c4c84c473b1af68db23d541b6dc1820", size = 54428, upload-time = "2025-11-20T10:06:05.946Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/96/5b/496f8abebd10c3301129abba7ddafd46c71d799a70c44ab080323987c4c9/stevedore-5.6.0.tar.gz" + hash = "sha256:f22d15c6ead40c5bbfa9ca54aa7e7b4a07d59b36ae03ed12ced1a54cf0b51945" + size = 516_074 + upload-time = "2025-11-20T10:06:07.264Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/f4/40/8561ce06dc46fd17242c7724ab25b257a2ac1b35f4ebf551b40ce6105cfa/stevedore-5.6.0-py3-none-any.whl" + hash = "sha256:4a36dccefd7aeea0c70135526cecb7766c4c84c473b1af68db23d541b6dc1820" + size = 54_428 + upload-time = "2025-11-20T10:06:05.946Z" [[package]] name = "tomli" version = "2.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/52/ed/3f73f72945444548f33eba9a87fc7a6e969915e7b1acc8260b30e1f76a2f/tomli-2.3.0.tar.gz", hash = "sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549", size = 17392, upload-time = "2025-10-08T22:01:47.119Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/2e/299f62b401438d5fe1624119c723f5d877acc86a4c2492da405626665f12/tomli-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:88bd15eb972f3664f5ed4b57c1634a97153b4bac4479dcb6a495f41921eb7f45", size = 153236, upload-time = "2025-10-08T22:01:00.137Z" }, - { url = "https://files.pythonhosted.org/packages/86/7f/d8fffe6a7aefdb61bced88fcb5e280cfd71e08939da5894161bd71bea022/tomli-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:883b1c0d6398a6a9d29b508c331fa56adbcdff647f6ace4dfca0f50e90dfd0ba", size = 148084, upload-time = "2025-10-08T22:01:01.63Z" }, - { url = "https://files.pythonhosted.org/packages/47/5c/24935fb6a2ee63e86d80e4d3b58b222dafaf438c416752c8b58537c8b89a/tomli-2.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d1381caf13ab9f300e30dd8feadb3de072aeb86f1d34a8569453ff32a7dea4bf", size = 234832, upload-time = "2025-10-08T22:01:02.543Z" }, - { url = "https://files.pythonhosted.org/packages/89/da/75dfd804fc11e6612846758a23f13271b76d577e299592b4371a4ca4cd09/tomli-2.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a0e285d2649b78c0d9027570d4da3425bdb49830a6156121360b3f8511ea3441", size = 242052, upload-time = "2025-10-08T22:01:03.836Z" }, - { url = "https://files.pythonhosted.org/packages/70/8c/f48ac899f7b3ca7eb13af73bacbc93aec37f9c954df3c08ad96991c8c373/tomli-2.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0a154a9ae14bfcf5d8917a59b51ffd5a3ac1fd149b71b47a3a104ca4edcfa845", size = 239555, upload-time = "2025-10-08T22:01:04.834Z" }, - { url = "https://files.pythonhosted.org/packages/ba/28/72f8afd73f1d0e7829bfc093f4cb98ce0a40ffc0cc997009ee1ed94ba705/tomli-2.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:74bf8464ff93e413514fefd2be591c3b0b23231a77f901db1eb30d6f712fc42c", size = 245128, upload-time = "2025-10-08T22:01:05.84Z" }, - { url = "https://files.pythonhosted.org/packages/b6/eb/a7679c8ac85208706d27436e8d421dfa39d4c914dcf5fa8083a9305f58d9/tomli-2.3.0-cp311-cp311-win32.whl", hash = "sha256:00b5f5d95bbfc7d12f91ad8c593a1659b6387b43f054104cda404be6bda62456", size = 96445, upload-time = "2025-10-08T22:01:06.896Z" }, - { url = "https://files.pythonhosted.org/packages/0a/fe/3d3420c4cb1ad9cb462fb52967080575f15898da97e21cb6f1361d505383/tomli-2.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:4dc4ce8483a5d429ab602f111a93a6ab1ed425eae3122032db7e9acf449451be", size = 107165, upload-time = "2025-10-08T22:01:08.107Z" }, - { url = "https://files.pythonhosted.org/packages/ff/b7/40f36368fcabc518bb11c8f06379a0fd631985046c038aca08c6d6a43c6e/tomli-2.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d7d86942e56ded512a594786a5ba0a5e521d02529b3826e7761a05138341a2ac", size = 154891, upload-time = "2025-10-08T22:01:09.082Z" }, - { url = "https://files.pythonhosted.org/packages/f9/3f/d9dd692199e3b3aab2e4e4dd948abd0f790d9ded8cd10cbaae276a898434/tomli-2.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:73ee0b47d4dad1c5e996e3cd33b8a76a50167ae5f96a2607cbe8cc773506ab22", size = 148796, upload-time = "2025-10-08T22:01:10.266Z" }, - { url = "https://files.pythonhosted.org/packages/60/83/59bff4996c2cf9f9387a0f5a3394629c7efa5ef16142076a23a90f1955fa/tomli-2.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:792262b94d5d0a466afb5bc63c7daa9d75520110971ee269152083270998316f", size = 242121, upload-time = "2025-10-08T22:01:11.332Z" }, - { url = "https://files.pythonhosted.org/packages/45/e5/7c5119ff39de8693d6baab6c0b6dcb556d192c165596e9fc231ea1052041/tomli-2.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4f195fe57ecceac95a66a75ac24d9d5fbc98ef0962e09b2eddec5d39375aae52", size = 250070, upload-time = "2025-10-08T22:01:12.498Z" }, - { url = "https://files.pythonhosted.org/packages/45/12/ad5126d3a278f27e6701abde51d342aa78d06e27ce2bb596a01f7709a5a2/tomli-2.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e31d432427dcbf4d86958c184b9bfd1e96b5b71f8eb17e6d02531f434fd335b8", size = 245859, upload-time = "2025-10-08T22:01:13.551Z" }, - { url = "https://files.pythonhosted.org/packages/fb/a1/4d6865da6a71c603cfe6ad0e6556c73c76548557a8d658f9e3b142df245f/tomli-2.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b0882799624980785240ab732537fcfc372601015c00f7fc367c55308c186f6", size = 250296, upload-time = "2025-10-08T22:01:14.614Z" }, - { url = "https://files.pythonhosted.org/packages/a0/b7/a7a7042715d55c9ba6e8b196d65d2cb662578b4d8cd17d882d45322b0d78/tomli-2.3.0-cp312-cp312-win32.whl", hash = "sha256:ff72b71b5d10d22ecb084d345fc26f42b5143c5533db5e2eaba7d2d335358876", size = 97124, upload-time = "2025-10-08T22:01:15.629Z" }, - { url = "https://files.pythonhosted.org/packages/06/1e/f22f100db15a68b520664eb3328fb0ae4e90530887928558112c8d1f4515/tomli-2.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:1cb4ed918939151a03f33d4242ccd0aa5f11b3547d0cf30f7c74a408a5b99878", size = 107698, upload-time = "2025-10-08T22:01:16.51Z" }, - { url = "https://files.pythonhosted.org/packages/89/48/06ee6eabe4fdd9ecd48bf488f4ac783844fd777f547b8d1b61c11939974e/tomli-2.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5192f562738228945d7b13d4930baffda67b69425a7f0da96d360b0a3888136b", size = 154819, upload-time = "2025-10-08T22:01:17.964Z" }, - { url = "https://files.pythonhosted.org/packages/f1/01/88793757d54d8937015c75dcdfb673c65471945f6be98e6a0410fba167ed/tomli-2.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:be71c93a63d738597996be9528f4abe628d1adf5e6eb11607bc8fe1a510b5dae", size = 148766, upload-time = "2025-10-08T22:01:18.959Z" }, - { url = "https://files.pythonhosted.org/packages/42/17/5e2c956f0144b812e7e107f94f1cc54af734eb17b5191c0bbfb72de5e93e/tomli-2.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c4665508bcbac83a31ff8ab08f424b665200c0e1e645d2bd9ab3d3e557b6185b", size = 240771, upload-time = "2025-10-08T22:01:20.106Z" }, - { url = "https://files.pythonhosted.org/packages/d5/f4/0fbd014909748706c01d16824eadb0307115f9562a15cbb012cd9b3512c5/tomli-2.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4021923f97266babc6ccab9f5068642a0095faa0a51a246a6a02fccbb3514eaf", size = 248586, upload-time = "2025-10-08T22:01:21.164Z" }, - { url = "https://files.pythonhosted.org/packages/30/77/fed85e114bde5e81ecf9bc5da0cc69f2914b38f4708c80ae67d0c10180c5/tomli-2.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4ea38c40145a357d513bffad0ed869f13c1773716cf71ccaa83b0fa0cc4e42f", size = 244792, upload-time = "2025-10-08T22:01:22.417Z" }, - { url = "https://files.pythonhosted.org/packages/55/92/afed3d497f7c186dc71e6ee6d4fcb0acfa5f7d0a1a2878f8beae379ae0cc/tomli-2.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ad805ea85eda330dbad64c7ea7a4556259665bdf9d2672f5dccc740eb9d3ca05", size = 248909, upload-time = "2025-10-08T22:01:23.859Z" }, - { url = "https://files.pythonhosted.org/packages/f8/84/ef50c51b5a9472e7265ce1ffc7f24cd4023d289e109f669bdb1553f6a7c2/tomli-2.3.0-cp313-cp313-win32.whl", hash = "sha256:97d5eec30149fd3294270e889b4234023f2c69747e555a27bd708828353ab606", size = 96946, upload-time = "2025-10-08T22:01:24.893Z" }, - { url = "https://files.pythonhosted.org/packages/b2/b7/718cd1da0884f281f95ccfa3a6cc572d30053cba64603f79d431d3c9b61b/tomli-2.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0c95ca56fbe89e065c6ead5b593ee64b84a26fca063b5d71a1122bf26e533999", size = 107705, upload-time = "2025-10-08T22:01:26.153Z" }, - { url = "https://files.pythonhosted.org/packages/19/94/aeafa14a52e16163008060506fcb6aa1949d13548d13752171a755c65611/tomli-2.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:cebc6fe843e0733ee827a282aca4999b596241195f43b4cc371d64fc6639da9e", size = 154244, upload-time = "2025-10-08T22:01:27.06Z" }, - { url = "https://files.pythonhosted.org/packages/db/e4/1e58409aa78eefa47ccd19779fc6f36787edbe7d4cd330eeeedb33a4515b/tomli-2.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4c2ef0244c75aba9355561272009d934953817c49f47d768070c3c94355c2aa3", size = 148637, upload-time = "2025-10-08T22:01:28.059Z" }, - { url = "https://files.pythonhosted.org/packages/26/b6/d1eccb62f665e44359226811064596dd6a366ea1f985839c566cd61525ae/tomli-2.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c22a8bf253bacc0cf11f35ad9808b6cb75ada2631c2d97c971122583b129afbc", size = 241925, upload-time = "2025-10-08T22:01:29.066Z" }, - { url = "https://files.pythonhosted.org/packages/70/91/7cdab9a03e6d3d2bb11beae108da5bdc1c34bdeb06e21163482544ddcc90/tomli-2.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0eea8cc5c5e9f89c9b90c4896a8deefc74f518db5927d0e0e8d4a80953d774d0", size = 249045, upload-time = "2025-10-08T22:01:31.98Z" }, - { url = "https://files.pythonhosted.org/packages/15/1b/8c26874ed1f6e4f1fcfeb868db8a794cbe9f227299402db58cfcc858766c/tomli-2.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b74a0e59ec5d15127acdabd75ea17726ac4c5178ae51b85bfe39c4f8a278e879", size = 245835, upload-time = "2025-10-08T22:01:32.989Z" }, - { url = "https://files.pythonhosted.org/packages/fd/42/8e3c6a9a4b1a1360c1a2a39f0b972cef2cc9ebd56025168c4137192a9321/tomli-2.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b5870b50c9db823c595983571d1296a6ff3e1b88f734a4c8f6fc6188397de005", size = 253109, upload-time = "2025-10-08T22:01:34.052Z" }, - { url = "https://files.pythonhosted.org/packages/22/0c/b4da635000a71b5f80130937eeac12e686eefb376b8dee113b4a582bba42/tomli-2.3.0-cp314-cp314-win32.whl", hash = "sha256:feb0dacc61170ed7ab602d3d972a58f14ee3ee60494292d384649a3dc38ef463", size = 97930, upload-time = "2025-10-08T22:01:35.082Z" }, - { url = "https://files.pythonhosted.org/packages/b9/74/cb1abc870a418ae99cd5c9547d6bce30701a954e0e721821df483ef7223c/tomli-2.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:b273fcbd7fc64dc3600c098e39136522650c49bca95df2d11cf3b626422392c8", size = 107964, upload-time = "2025-10-08T22:01:36.057Z" }, - { url = "https://files.pythonhosted.org/packages/54/78/5c46fff6432a712af9f792944f4fcd7067d8823157949f4e40c56b8b3c83/tomli-2.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:940d56ee0410fa17ee1f12b817b37a4d4e4dc4d27340863cc67236c74f582e77", size = 163065, upload-time = "2025-10-08T22:01:37.27Z" }, - { url = "https://files.pythonhosted.org/packages/39/67/f85d9bd23182f45eca8939cd2bc7050e1f90c41f4a2ecbbd5963a1d1c486/tomli-2.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f85209946d1fe94416debbb88d00eb92ce9cd5266775424ff81bc959e001acaf", size = 159088, upload-time = "2025-10-08T22:01:38.235Z" }, - { url = "https://files.pythonhosted.org/packages/26/5a/4b546a0405b9cc0659b399f12b6adb750757baf04250b148d3c5059fc4eb/tomli-2.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a56212bdcce682e56b0aaf79e869ba5d15a6163f88d5451cbde388d48b13f530", size = 268193, upload-time = "2025-10-08T22:01:39.712Z" }, - { url = "https://files.pythonhosted.org/packages/42/4f/2c12a72ae22cf7b59a7fe75b3465b7aba40ea9145d026ba41cb382075b0e/tomli-2.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c5f3ffd1e098dfc032d4d3af5c0ac64f6d286d98bc148698356847b80fa4de1b", size = 275488, upload-time = "2025-10-08T22:01:40.773Z" }, - { url = "https://files.pythonhosted.org/packages/92/04/a038d65dbe160c3aa5a624e93ad98111090f6804027d474ba9c37c8ae186/tomli-2.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5e01decd096b1530d97d5d85cb4dff4af2d8347bd35686654a004f8dea20fc67", size = 272669, upload-time = "2025-10-08T22:01:41.824Z" }, - { url = "https://files.pythonhosted.org/packages/be/2f/8b7c60a9d1612a7cbc39ffcca4f21a73bf368a80fc25bccf8253e2563267/tomli-2.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8a35dd0e643bb2610f156cca8db95d213a90015c11fee76c946aa62b7ae7e02f", size = 279709, upload-time = "2025-10-08T22:01:43.177Z" }, - { url = "https://files.pythonhosted.org/packages/7e/46/cc36c679f09f27ded940281c38607716c86cf8ba4a518d524e349c8b4874/tomli-2.3.0-cp314-cp314t-win32.whl", hash = "sha256:a1f7f282fe248311650081faafa5f4732bdbfef5d45fe3f2e702fbc6f2d496e0", size = 107563, upload-time = "2025-10-08T22:01:44.233Z" }, - { url = "https://files.pythonhosted.org/packages/84/ff/426ca8683cf7b753614480484f6437f568fd2fda2edbdf57a2d3d8b27a0b/tomli-2.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:70a251f8d4ba2d9ac2542eecf008b3c8a9fc5c3f9f02c56a9d7952612be2fdba", size = 119756, upload-time = "2025-10-08T22:01:45.234Z" }, - { url = "https://files.pythonhosted.org/packages/77/b8/0135fadc89e73be292b473cb820b4f5a08197779206b33191e801feeae40/tomli-2.3.0-py3-none-any.whl", hash = "sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b", size = 14408, upload-time = "2025-10-08T22:01:46.04Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/52/ed/3f73f72945444548f33eba9a87fc7a6e969915e7b1acc8260b30e1f76a2f/tomli-2.3.0.tar.gz" + hash = "sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549" + size = 17_392 + upload-time = "2025-10-08T22:01:47.119Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/b3/2e/299f62b401438d5fe1624119c723f5d877acc86a4c2492da405626665f12/tomli-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl" + hash = "sha256:88bd15eb972f3664f5ed4b57c1634a97153b4bac4479dcb6a495f41921eb7f45" + size = 153_236 + upload-time = "2025-10-08T22:01:00.137Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/86/7f/d8fffe6a7aefdb61bced88fcb5e280cfd71e08939da5894161bd71bea022/tomli-2.3.0-cp311-cp311-macosx_11_0_arm64.whl" + hash = "sha256:883b1c0d6398a6a9d29b508c331fa56adbcdff647f6ace4dfca0f50e90dfd0ba" + size = 148_084 + upload-time = "2025-10-08T22:01:01.63Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/47/5c/24935fb6a2ee63e86d80e4d3b58b222dafaf438c416752c8b58537c8b89a/tomli-2.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + hash = "sha256:d1381caf13ab9f300e30dd8feadb3de072aeb86f1d34a8569453ff32a7dea4bf" + size = 234_832 + upload-time = "2025-10-08T22:01:02.543Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/89/da/75dfd804fc11e6612846758a23f13271b76d577e299592b4371a4ca4cd09/tomli-2.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + hash = "sha256:a0e285d2649b78c0d9027570d4da3425bdb49830a6156121360b3f8511ea3441" + size = 242_052 + upload-time = "2025-10-08T22:01:03.836Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/70/8c/f48ac899f7b3ca7eb13af73bacbc93aec37f9c954df3c08ad96991c8c373/tomli-2.3.0-cp311-cp311-musllinux_1_2_aarch64.whl" + hash = "sha256:0a154a9ae14bfcf5d8917a59b51ffd5a3ac1fd149b71b47a3a104ca4edcfa845" + size = 239_555 + upload-time = "2025-10-08T22:01:04.834Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/ba/28/72f8afd73f1d0e7829bfc093f4cb98ce0a40ffc0cc997009ee1ed94ba705/tomli-2.3.0-cp311-cp311-musllinux_1_2_x86_64.whl" + hash = "sha256:74bf8464ff93e413514fefd2be591c3b0b23231a77f901db1eb30d6f712fc42c" + size = 245_128 + upload-time = "2025-10-08T22:01:05.84Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/b6/eb/a7679c8ac85208706d27436e8d421dfa39d4c914dcf5fa8083a9305f58d9/tomli-2.3.0-cp311-cp311-win32.whl" + hash = "sha256:00b5f5d95bbfc7d12f91ad8c593a1659b6387b43f054104cda404be6bda62456" + size = 96_445 + upload-time = "2025-10-08T22:01:06.896Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/0a/fe/3d3420c4cb1ad9cb462fb52967080575f15898da97e21cb6f1361d505383/tomli-2.3.0-cp311-cp311-win_amd64.whl" + hash = "sha256:4dc4ce8483a5d429ab602f111a93a6ab1ed425eae3122032db7e9acf449451be" + size = 107_165 + upload-time = "2025-10-08T22:01:08.107Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/ff/b7/40f36368fcabc518bb11c8f06379a0fd631985046c038aca08c6d6a43c6e/tomli-2.3.0-cp312-cp312-macosx_10_13_x86_64.whl" + hash = "sha256:d7d86942e56ded512a594786a5ba0a5e521d02529b3826e7761a05138341a2ac" + size = 154_891 + upload-time = "2025-10-08T22:01:09.082Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/f9/3f/d9dd692199e3b3aab2e4e4dd948abd0f790d9ded8cd10cbaae276a898434/tomli-2.3.0-cp312-cp312-macosx_11_0_arm64.whl" + hash = "sha256:73ee0b47d4dad1c5e996e3cd33b8a76a50167ae5f96a2607cbe8cc773506ab22" + size = 148_796 + upload-time = "2025-10-08T22:01:10.266Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/60/83/59bff4996c2cf9f9387a0f5a3394629c7efa5ef16142076a23a90f1955fa/tomli-2.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + hash = "sha256:792262b94d5d0a466afb5bc63c7daa9d75520110971ee269152083270998316f" + size = 242_121 + upload-time = "2025-10-08T22:01:11.332Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/45/e5/7c5119ff39de8693d6baab6c0b6dcb556d192c165596e9fc231ea1052041/tomli-2.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + hash = "sha256:4f195fe57ecceac95a66a75ac24d9d5fbc98ef0962e09b2eddec5d39375aae52" + size = 250_070 + upload-time = "2025-10-08T22:01:12.498Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/45/12/ad5126d3a278f27e6701abde51d342aa78d06e27ce2bb596a01f7709a5a2/tomli-2.3.0-cp312-cp312-musllinux_1_2_aarch64.whl" + hash = "sha256:e31d432427dcbf4d86958c184b9bfd1e96b5b71f8eb17e6d02531f434fd335b8" + size = 245_859 + upload-time = "2025-10-08T22:01:13.551Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/fb/a1/4d6865da6a71c603cfe6ad0e6556c73c76548557a8d658f9e3b142df245f/tomli-2.3.0-cp312-cp312-musllinux_1_2_x86_64.whl" + hash = "sha256:7b0882799624980785240ab732537fcfc372601015c00f7fc367c55308c186f6" + size = 250_296 + upload-time = "2025-10-08T22:01:14.614Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/a0/b7/a7a7042715d55c9ba6e8b196d65d2cb662578b4d8cd17d882d45322b0d78/tomli-2.3.0-cp312-cp312-win32.whl" + hash = "sha256:ff72b71b5d10d22ecb084d345fc26f42b5143c5533db5e2eaba7d2d335358876" + size = 97_124 + upload-time = "2025-10-08T22:01:15.629Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/06/1e/f22f100db15a68b520664eb3328fb0ae4e90530887928558112c8d1f4515/tomli-2.3.0-cp312-cp312-win_amd64.whl" + hash = "sha256:1cb4ed918939151a03f33d4242ccd0aa5f11b3547d0cf30f7c74a408a5b99878" + size = 107_698 + upload-time = "2025-10-08T22:01:16.51Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/89/48/06ee6eabe4fdd9ecd48bf488f4ac783844fd777f547b8d1b61c11939974e/tomli-2.3.0-cp313-cp313-macosx_10_13_x86_64.whl" + hash = "sha256:5192f562738228945d7b13d4930baffda67b69425a7f0da96d360b0a3888136b" + size = 154_819 + upload-time = "2025-10-08T22:01:17.964Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/f1/01/88793757d54d8937015c75dcdfb673c65471945f6be98e6a0410fba167ed/tomli-2.3.0-cp313-cp313-macosx_11_0_arm64.whl" + hash = "sha256:be71c93a63d738597996be9528f4abe628d1adf5e6eb11607bc8fe1a510b5dae" + size = 148_766 + upload-time = "2025-10-08T22:01:18.959Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/42/17/5e2c956f0144b812e7e107f94f1cc54af734eb17b5191c0bbfb72de5e93e/tomli-2.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + hash = "sha256:c4665508bcbac83a31ff8ab08f424b665200c0e1e645d2bd9ab3d3e557b6185b" + size = 240_771 + upload-time = "2025-10-08T22:01:20.106Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/d5/f4/0fbd014909748706c01d16824eadb0307115f9562a15cbb012cd9b3512c5/tomli-2.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + hash = "sha256:4021923f97266babc6ccab9f5068642a0095faa0a51a246a6a02fccbb3514eaf" + size = 248_586 + upload-time = "2025-10-08T22:01:21.164Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/30/77/fed85e114bde5e81ecf9bc5da0cc69f2914b38f4708c80ae67d0c10180c5/tomli-2.3.0-cp313-cp313-musllinux_1_2_aarch64.whl" + hash = "sha256:a4ea38c40145a357d513bffad0ed869f13c1773716cf71ccaa83b0fa0cc4e42f" + size = 244_792 + upload-time = "2025-10-08T22:01:22.417Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/55/92/afed3d497f7c186dc71e6ee6d4fcb0acfa5f7d0a1a2878f8beae379ae0cc/tomli-2.3.0-cp313-cp313-musllinux_1_2_x86_64.whl" + hash = "sha256:ad805ea85eda330dbad64c7ea7a4556259665bdf9d2672f5dccc740eb9d3ca05" + size = 248_909 + upload-time = "2025-10-08T22:01:23.859Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/f8/84/ef50c51b5a9472e7265ce1ffc7f24cd4023d289e109f669bdb1553f6a7c2/tomli-2.3.0-cp313-cp313-win32.whl" + hash = "sha256:97d5eec30149fd3294270e889b4234023f2c69747e555a27bd708828353ab606" + size = 96_946 + upload-time = "2025-10-08T22:01:24.893Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/b2/b7/718cd1da0884f281f95ccfa3a6cc572d30053cba64603f79d431d3c9b61b/tomli-2.3.0-cp313-cp313-win_amd64.whl" + hash = "sha256:0c95ca56fbe89e065c6ead5b593ee64b84a26fca063b5d71a1122bf26e533999" + size = 107_705 + upload-time = "2025-10-08T22:01:26.153Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/19/94/aeafa14a52e16163008060506fcb6aa1949d13548d13752171a755c65611/tomli-2.3.0-cp314-cp314-macosx_10_13_x86_64.whl" + hash = "sha256:cebc6fe843e0733ee827a282aca4999b596241195f43b4cc371d64fc6639da9e" + size = 154_244 + upload-time = "2025-10-08T22:01:27.06Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/db/e4/1e58409aa78eefa47ccd19779fc6f36787edbe7d4cd330eeeedb33a4515b/tomli-2.3.0-cp314-cp314-macosx_11_0_arm64.whl" + hash = "sha256:4c2ef0244c75aba9355561272009d934953817c49f47d768070c3c94355c2aa3" + size = 148_637 + upload-time = "2025-10-08T22:01:28.059Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/26/b6/d1eccb62f665e44359226811064596dd6a366ea1f985839c566cd61525ae/tomli-2.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + hash = "sha256:c22a8bf253bacc0cf11f35ad9808b6cb75ada2631c2d97c971122583b129afbc" + size = 241_925 + upload-time = "2025-10-08T22:01:29.066Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/70/91/7cdab9a03e6d3d2bb11beae108da5bdc1c34bdeb06e21163482544ddcc90/tomli-2.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + hash = "sha256:0eea8cc5c5e9f89c9b90c4896a8deefc74f518db5927d0e0e8d4a80953d774d0" + size = 249_045 + upload-time = "2025-10-08T22:01:31.98Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/15/1b/8c26874ed1f6e4f1fcfeb868db8a794cbe9f227299402db58cfcc858766c/tomli-2.3.0-cp314-cp314-musllinux_1_2_aarch64.whl" + hash = "sha256:b74a0e59ec5d15127acdabd75ea17726ac4c5178ae51b85bfe39c4f8a278e879" + size = 245_835 + upload-time = "2025-10-08T22:01:32.989Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/fd/42/8e3c6a9a4b1a1360c1a2a39f0b972cef2cc9ebd56025168c4137192a9321/tomli-2.3.0-cp314-cp314-musllinux_1_2_x86_64.whl" + hash = "sha256:b5870b50c9db823c595983571d1296a6ff3e1b88f734a4c8f6fc6188397de005" + size = 253_109 + upload-time = "2025-10-08T22:01:34.052Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/22/0c/b4da635000a71b5f80130937eeac12e686eefb376b8dee113b4a582bba42/tomli-2.3.0-cp314-cp314-win32.whl" + hash = "sha256:feb0dacc61170ed7ab602d3d972a58f14ee3ee60494292d384649a3dc38ef463" + size = 97_930 + upload-time = "2025-10-08T22:01:35.082Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/b9/74/cb1abc870a418ae99cd5c9547d6bce30701a954e0e721821df483ef7223c/tomli-2.3.0-cp314-cp314-win_amd64.whl" + hash = "sha256:b273fcbd7fc64dc3600c098e39136522650c49bca95df2d11cf3b626422392c8" + size = 107_964 + upload-time = "2025-10-08T22:01:36.057Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/54/78/5c46fff6432a712af9f792944f4fcd7067d8823157949f4e40c56b8b3c83/tomli-2.3.0-cp314-cp314t-macosx_10_13_x86_64.whl" + hash = "sha256:940d56ee0410fa17ee1f12b817b37a4d4e4dc4d27340863cc67236c74f582e77" + size = 163_065 + upload-time = "2025-10-08T22:01:37.27Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/39/67/f85d9bd23182f45eca8939cd2bc7050e1f90c41f4a2ecbbd5963a1d1c486/tomli-2.3.0-cp314-cp314t-macosx_11_0_arm64.whl" + hash = "sha256:f85209946d1fe94416debbb88d00eb92ce9cd5266775424ff81bc959e001acaf" + size = 159_088 + upload-time = "2025-10-08T22:01:38.235Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/26/5a/4b546a0405b9cc0659b399f12b6adb750757baf04250b148d3c5059fc4eb/tomli-2.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl" + hash = "sha256:a56212bdcce682e56b0aaf79e869ba5d15a6163f88d5451cbde388d48b13f530" + size = 268_193 + upload-time = "2025-10-08T22:01:39.712Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/42/4f/2c12a72ae22cf7b59a7fe75b3465b7aba40ea9145d026ba41cb382075b0e/tomli-2.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" + hash = "sha256:c5f3ffd1e098dfc032d4d3af5c0ac64f6d286d98bc148698356847b80fa4de1b" + size = 275_488 + upload-time = "2025-10-08T22:01:40.773Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/92/04/a038d65dbe160c3aa5a624e93ad98111090f6804027d474ba9c37c8ae186/tomli-2.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl" + hash = "sha256:5e01decd096b1530d97d5d85cb4dff4af2d8347bd35686654a004f8dea20fc67" + size = 272_669 + upload-time = "2025-10-08T22:01:41.824Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/be/2f/8b7c60a9d1612a7cbc39ffcca4f21a73bf368a80fc25bccf8253e2563267/tomli-2.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl" + hash = "sha256:8a35dd0e643bb2610f156cca8db95d213a90015c11fee76c946aa62b7ae7e02f" + size = 279_709 + upload-time = "2025-10-08T22:01:43.177Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/7e/46/cc36c679f09f27ded940281c38607716c86cf8ba4a518d524e349c8b4874/tomli-2.3.0-cp314-cp314t-win32.whl" + hash = "sha256:a1f7f282fe248311650081faafa5f4732bdbfef5d45fe3f2e702fbc6f2d496e0" + size = 107_563 + upload-time = "2025-10-08T22:01:44.233Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/84/ff/426ca8683cf7b753614480484f6437f568fd2fda2edbdf57a2d3d8b27a0b/tomli-2.3.0-cp314-cp314t-win_amd64.whl" + hash = "sha256:70a251f8d4ba2d9ac2542eecf008b3c8a9fc5c3f9f02c56a9d7952612be2fdba" + size = 119_756 + upload-time = "2025-10-08T22:01:45.234Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/77/b8/0135fadc89e73be292b473cb820b4f5a08197779206b33191e801feeae40/tomli-2.3.0-py3-none-any.whl" + hash = "sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b" + size = 14_408 + upload-time = "2025-10-08T22:01:46.04Z" [[package]] name = "typing-extensions" version = "4.15.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz" + hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466" + size = 109_391 + upload-time = "2025-08-25T13:49:26.313Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl" + hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548" + size = 44_614 + upload-time = "2025-08-25T13:49:24.86Z" [[package]] name = "virtualenv" version = "20.35.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "distlib" }, - { name = "filelock" }, - { name = "platformdirs" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/20/28/e6f1a6f655d620846bd9df527390ecc26b3805a0c5989048c210e22c5ca9/virtualenv-20.35.4.tar.gz", hash = "sha256:643d3914d73d3eeb0c552cbb12d7e82adf0e504dbf86a3182f8771a153a1971c", size = 6028799, upload-time = "2025-10-29T06:57:40.511Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/79/0c/c05523fa3181fdf0c9c52a6ba91a23fbf3246cc095f26f6516f9c60e6771/virtualenv-20.35.4-py3-none-any.whl", hash = "sha256:c21c9cede36c9753eeade68ba7d523529f228a403463376cf821eaae2b650f1b", size = 6005095, upload-time = "2025-10-29T06:57:37.598Z" }, -] + + [package.source] + registry = "https://pypi.org/simple" + + [[package.dependencies]] + name = "distlib" + + [[package.dependencies]] + name = "filelock" + + [[package.dependencies]] + name = "platformdirs" + + [[package.dependencies]] + name = "typing-extensions" + marker = "python_full_version < '3.11'" + + [package.sdist] + url = "https://files.pythonhosted.org/packages/20/28/e6f1a6f655d620846bd9df527390ecc26b3805a0c5989048c210e22c5ca9/virtualenv-20.35.4.tar.gz" + hash = "sha256:643d3914d73d3eeb0c552cbb12d7e82adf0e504dbf86a3182f8771a153a1971c" + size = 6_028_799 + upload-time = "2025-10-29T06:57:40.511Z" + + [[package.wheels]] + url = "https://files.pythonhosted.org/packages/79/0c/c05523fa3181fdf0c9c52a6ba91a23fbf3246cc095f26f6516f9c60e6771/virtualenv-20.35.4-py3-none-any.whl" + hash = "sha256:c21c9cede36c9753eeade68ba7d523529f228a403463376cf821eaae2b650f1b" + size = 6_005_095 + upload-time = "2025-10-29T06:57:37.598Z" From 5fef25f1afb26b43b034eeb89eb3a7c87ed30933 Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Sat, 6 Dec 2025 02:36:25 +0400 Subject: [PATCH 29/53] refactor(schema_applier): simplify value retrieval from extra_values - Changed the method of retrieving values from the extra_values dictionary to use direct indexing instead of the get method. This ensures that a KeyError is raised for missing keys, making the error handling more explicit. Signed-off-by: Dmitrii Safronov --- src/logging_objects_with_schema/schema_applier.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/logging_objects_with_schema/schema_applier.py b/src/logging_objects_with_schema/schema_applier.py index 7a76114..da44023 100644 --- a/src/logging_objects_with_schema/schema_applier.py +++ b/src/logging_objects_with_schema/schema_applier.py @@ -218,7 +218,7 @@ def _apply_schema_internal( if source not in extra_values: continue - value = extra_values.get(source) + value = extra_values[source] # Check for None values explicitly (None values are not allowed) # This check must be done once per source, not once per leaf From 804ed64d06fc4c8b45376c96acc09a8dd3181c85 Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Sat, 6 Dec 2025 02:41:19 +0400 Subject: [PATCH 30/53] refactor(schema_loader): consolidate exception handling in schema compilation - Merged the exception handling for FileNotFoundError and ValueError into a single block to streamline error processing during schema loading. This change simplifies the code and maintains the existing functionality of appending schema problems and caching results. Signed-off-by: Dmitrii Safronov --- src/logging_objects_with_schema/schema_loader.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/logging_objects_with_schema/schema_loader.py b/src/logging_objects_with_schema/schema_loader.py index 918615c..9acc8be 100644 --- a/src/logging_objects_with_schema/schema_loader.py +++ b/src/logging_objects_with_schema/schema_loader.py @@ -545,13 +545,7 @@ def _compile_schema_internal() -> tuple[CompiledSchema, list[SchemaProblem]]: try: raw_schema, loaded_path = _load_raw_schema() - except FileNotFoundError as exc: - problems.append(SchemaProblem(str(exc))) - result = (CompiledSchema(leaves=[]), problems) - with _cache_lock: - _SCHEMA_CACHE[schema_path] = result - return result - except ValueError as exc: + except (FileNotFoundError, ValueError) as exc: problems.append(SchemaProblem(str(exc))) result = (CompiledSchema(leaves=[]), problems) with _cache_lock: From edcf85f7a2b0b9decd2898c0be9330ee6ea14177 Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Sat, 6 Dec 2025 02:47:23 +0400 Subject: [PATCH 31/53] refactor(schema_loader): remove unused variable in schema compilation - Eliminated the unused `loaded_path` variable from the `_load_raw_schema()` call in the `_compile_schema_internal()` function. This change simplifies the code and removes unnecessary comments related to the variable, enhancing clarity. Signed-off-by: Dmitrii Safronov --- src/logging_objects_with_schema/schema_loader.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/logging_objects_with_schema/schema_loader.py b/src/logging_objects_with_schema/schema_loader.py index 9acc8be..7d48d25 100644 --- a/src/logging_objects_with_schema/schema_loader.py +++ b/src/logging_objects_with_schema/schema_loader.py @@ -544,7 +544,7 @@ def _compile_schema_internal() -> tuple[CompiledSchema, list[SchemaProblem]]: problems: list[SchemaProblem] = [] try: - raw_schema, loaded_path = _load_raw_schema() + raw_schema, _ = _load_raw_schema() except (FileNotFoundError, ValueError) as exc: problems.append(SchemaProblem(str(exc))) result = (CompiledSchema(leaves=[]), problems) @@ -569,10 +569,6 @@ def _compile_schema_internal() -> tuple[CompiledSchema, list[SchemaProblem]]: result = (compiled, problems) # Cache the result for this schema path (thread-safe write). - # NOTE: ``loaded_path`` is expected to be identical to ``schema_path`` here - # because both are derived from ``_get_schema_path()``. We still use - # ``schema_path`` as the cache key consistently to avoid any confusion if - # ``_load_raw_schema()`` implementation changes in the future. with _cache_lock: _SCHEMA_CACHE[schema_path] = result From fe80bb2ed3e84687d59b83aa40901321e6cf0036 Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Sat, 6 Dec 2025 02:50:04 +0400 Subject: [PATCH 32/53] refactor(schema_loader): create helper function for empty schema with problems - Introduced a new helper function `_create_empty_compiled_schema_with_problems` to encapsulate the creation of an empty `CompiledSchema` along with a list of schema problems. This change improves code readability and maintains the existing functionality in the `_compile_schema_internal` function by streamlining the handling of schema compilation errors. Signed-off-by: Dmitrii Safronov --- src/logging_objects_with_schema/schema_loader.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/logging_objects_with_schema/schema_loader.py b/src/logging_objects_with_schema/schema_loader.py index 7d48d25..738b100 100644 --- a/src/logging_objects_with_schema/schema_loader.py +++ b/src/logging_objects_with_schema/schema_loader.py @@ -56,6 +56,20 @@ def is_empty(self) -> bool: return not self.leaves +def _create_empty_compiled_schema_with_problems( + problems: list[SchemaProblem], +) -> tuple[CompiledSchema, list[SchemaProblem]]: + """Create an empty CompiledSchema with problems. + + Args: + problems: List of schema problems. + + Returns: + Tuple of (empty CompiledSchema, problems list). + """ + return (CompiledSchema(leaves=[]), problems) + + _TYPE_MAP: Mapping[str, type] = { "str": str, "int": int, @@ -547,7 +561,7 @@ def _compile_schema_internal() -> tuple[CompiledSchema, list[SchemaProblem]]: raw_schema, _ = _load_raw_schema() except (FileNotFoundError, ValueError) as exc: problems.append(SchemaProblem(str(exc))) - result = (CompiledSchema(leaves=[]), problems) + result = _create_empty_compiled_schema_with_problems(problems) with _cache_lock: _SCHEMA_CACHE[schema_path] = result return result From 192ad56ec1997ef60287191f5d487fedfd690386 Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Sat, 6 Dec 2025 02:51:32 +0400 Subject: [PATCH 33/53] refactor(schema_applier): optimize source tracking in schema application - Updated the method of tracking used sources in the `_apply_schema_internal` function by grouping leaves by source first. This change enhances code clarity and efficiency by directly utilizing the keys of the `source_to_leaves` dictionary to determine used sources. Signed-off-by: Dmitrii Safronov --- src/logging_objects_with_schema/schema_applier.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/logging_objects_with_schema/schema_applier.py b/src/logging_objects_with_schema/schema_applier.py index da44023..4bf41aa 100644 --- a/src/logging_objects_with_schema/schema_applier.py +++ b/src/logging_objects_with_schema/schema_applier.py @@ -207,13 +207,13 @@ def _apply_schema_internal( extra: dict[str, Any] = {} problems: list[DataProblem] = [] - used_sources = {leaf.source for leaf in compiled.leaves} - # Group leaves by source for efficient processing source_to_leaves: dict[str, list[SchemaLeaf]] = defaultdict(list) for leaf in compiled.leaves: source_to_leaves[leaf.source].append(leaf) + used_sources = set(source_to_leaves.keys()) + for source, leaves in source_to_leaves.items(): if source not in extra_values: continue From 00255244a5696c8eec07f57264ca053c9e35785e Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Sat, 6 Dec 2025 02:57:46 +0400 Subject: [PATCH 34/53] refactor(schema_loader): extract current working directory logic into a helper function - Replaced direct calls to `os.getcwd()` with a new helper function `_get_current_working_directory()` to improve code readability and maintainability. This change centralizes the logic for obtaining the current working directory, ensuring consistency across the schema loading functions. Signed-off-by: Dmitrii Safronov --- src/logging_objects_with_schema/schema_loader.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/logging_objects_with_schema/schema_loader.py b/src/logging_objects_with_schema/schema_loader.py index 738b100..0c00b36 100644 --- a/src/logging_objects_with_schema/schema_loader.py +++ b/src/logging_objects_with_schema/schema_loader.py @@ -105,7 +105,7 @@ def _find_schema_file() -> Path | None: Returns: Absolute path to schema file if found, None otherwise. """ - start_path = Path(os.getcwd()).resolve() + start_path = _get_current_working_directory() current = start_path while True: @@ -123,6 +123,15 @@ def _find_schema_file() -> Path | None: return None +def _get_current_working_directory() -> Path: + """Get the current working directory as a resolved Path. + + Returns: + Absolute path to the current working directory. + """ + return Path(os.getcwd()).resolve() + + def _check_cached_found_file_path() -> Path | None: """Check if cached path for a found file is still valid. @@ -163,7 +172,7 @@ def _check_cached_missing_file_path() -> Path | None: # Cached path is based on CWD when file was not found, # check if CWD changed - current_cwd = Path(os.getcwd()).resolve() + current_cwd = _get_current_working_directory() if current_cwd != _cached_cwd: # CWD changed, invalidate cache and re-search from new CWD _resolved_schema_path = None @@ -198,7 +207,7 @@ def _cache_and_return_missing_path() -> Path: """ global _resolved_schema_path, _cached_cwd - current_cwd = Path(os.getcwd()).resolve() + current_cwd = _get_current_working_directory() schema_path = (current_cwd / SCHEMA_FILE_NAME).resolve() _resolved_schema_path = schema_path _cached_cwd = current_cwd # Track CWD since path depends on it From fd52b6ba1f3aef739f493ac30280f64d68d7fc6a Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Sat, 6 Dec 2025 03:00:29 +0400 Subject: [PATCH 35/53] refactor(schema_loader): enhance schema loading tests and add new helper functions - Added new test cases for `_get_current_working_directory`, `_create_empty_compiled_schema_with_problems`, and `_load_raw_schema` to improve coverage and ensure correct functionality. - Introduced helper functions for checking root conflicts and compiling schema trees, enhancing the modularity and readability of the schema loading process. - Updated existing tests to validate behavior for various edge cases, including handling of invalid JSON and schema structures. Signed-off-by: Dmitrii Safronov --- tests/test_schema_loader.py | 332 ++++++++++++++++++++++++++++++++++++ 1 file changed, 332 insertions(+) diff --git a/tests/test_schema_loader.py b/tests/test_schema_loader.py index ca27d46..0bdf794 100644 --- a/tests/test_schema_loader.py +++ b/tests/test_schema_loader.py @@ -7,6 +7,7 @@ from __future__ import annotations from pathlib import Path +from typing import Any import pytest @@ -30,19 +31,37 @@ from logging_objects_with_schema.schema_loader import ( _check_cached_missing_file_path as check_cached_missing_file_path, ) +from logging_objects_with_schema.schema_loader import ( + _check_root_conflicts as check_root_conflicts, +) from logging_objects_with_schema.schema_loader import ( _compile_schema_internal as compile_schema_internal, ) +from logging_objects_with_schema.schema_loader import ( + _compile_schema_tree as compile_schema_tree, +) +from logging_objects_with_schema.schema_loader import ( + _create_empty_compiled_schema_with_problems as create_empty_schema, +) from logging_objects_with_schema.schema_loader import _format_path as format_path +from logging_objects_with_schema.schema_loader import ( + _get_current_working_directory as get_current_working_directory, +) from logging_objects_with_schema.schema_loader import ( _get_schema_path as get_schema_path, ) from logging_objects_with_schema.schema_loader import ( _is_empty_or_none as is_empty_or_none, ) +from logging_objects_with_schema.schema_loader import ( + _load_raw_schema as load_raw_schema, +) from logging_objects_with_schema.schema_loader import ( _validate_and_create_leaf as validate_and_create_leaf, ) +from logging_objects_with_schema.schema_loader import ( + get_builtin_logrecord_attributes, +) from tests.conftest import _write_schema @@ -1102,3 +1121,316 @@ def test_cache_and_return_missing_path_caches_path( assert result == expected_path assert schema_loader._resolved_schema_path == expected_path assert schema_loader._cached_cwd == tmp_path.resolve() + + +def test_get_current_working_directory_returns_resolved_path( + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, +) -> None: + """_get_current_working_directory should return resolved absolute path to CWD.""" + monkeypatch.chdir(tmp_path) + + result = get_current_working_directory() + + assert isinstance(result, Path) + assert result.is_absolute() + assert result == tmp_path.resolve() + + +def test_get_current_working_directory_changes_with_cwd( + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, +) -> None: + """_get_current_working_directory should return different paths for different CWDs.""" # noqa: E501 + dir1 = tmp_path / "dir1" + dir2 = tmp_path / "dir2" + dir1.mkdir() + dir2.mkdir() + + monkeypatch.chdir(dir1) + path1 = get_current_working_directory() + + monkeypatch.chdir(dir2) + path2 = get_current_working_directory() + + assert path1 != path2 + assert path1 == dir1.resolve() + assert path2 == dir2.resolve() + + +def test_create_empty_compiled_schema_with_problems() -> None: + """_create_empty_compiled_schema_with_problems creates empty schema with problems.""" # noqa: E501 + problems = [ + SchemaProblem("Problem 1"), + SchemaProblem("Problem 2"), + ] + + compiled, result_problems = create_empty_schema(problems) + + assert isinstance(compiled, CompiledSchema) + assert compiled.is_empty + assert compiled.leaves == [] + assert result_problems == problems + assert len(result_problems) == 2 + + +def test_create_empty_compiled_schema_with_empty_problems() -> None: + """_create_empty_compiled_schema_with_problems works with empty problems list.""" # noqa: E501 + problems: list[SchemaProblem] = [] + + compiled, result_problems = create_empty_schema(problems) + + assert isinstance(compiled, CompiledSchema) + assert compiled.is_empty + assert result_problems == [] + + +def test_load_raw_schema_loads_valid_schema( + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, +) -> None: + """_load_raw_schema should load and parse valid JSON schema.""" + monkeypatch.chdir(tmp_path) + schema_data = { + "ServicePayload": { + "RequestID": {"type": "str", "source": "request_id"}, + }, + } + _write_schema(tmp_path, schema_data) + + data, schema_path = load_raw_schema() + + assert isinstance(data, dict) + assert data == schema_data + assert schema_path == (tmp_path / SCHEMA_FILE_NAME).resolve() + assert schema_path.exists() + + +def test_load_raw_schema_raises_file_not_found_when_missing( + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, +) -> None: + """_load_raw_schema should raise FileNotFoundError when schema file is missing.""" + monkeypatch.chdir(tmp_path) + + with pytest.raises(FileNotFoundError) as exc_info: + load_raw_schema() + + assert "Schema file not found" in str(exc_info.value) + assert SCHEMA_FILE_NAME in str(exc_info.value) + + +def test_load_raw_schema_raises_value_error_for_invalid_json( + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, +) -> None: + """_load_raw_schema should raise ValueError for invalid JSON.""" + monkeypatch.chdir(tmp_path) + schema_file = tmp_path / SCHEMA_FILE_NAME + schema_file.write_text("{ invalid json }", encoding="utf-8") + + with pytest.raises(ValueError) as exc_info: + load_raw_schema() + + assert "Failed to parse JSON schema" in str(exc_info.value) + + +def test_load_raw_schema_raises_value_error_for_non_object( + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, +) -> None: + """_load_raw_schema should raise ValueError when top-level is not an object.""" + monkeypatch.chdir(tmp_path) + schema_file = tmp_path / SCHEMA_FILE_NAME + # Write a JSON array instead of an object + schema_file.write_text('["not", "an", "object"]', encoding="utf-8") + + with pytest.raises(ValueError) as exc_info: + load_raw_schema() + + assert "Top-level schema must be a JSON object" in str(exc_info.value) + + +def test_compile_schema_tree_compiles_simple_tree() -> None: + """_compile_schema_tree should compile a simple schema tree into leaves.""" + problems: list[SchemaProblem] = [] + node = { + "ServicePayload": { + "RequestID": {"type": "str", "source": "request_id"}, + "UserID": {"type": "int", "source": "user_id"}, + }, + } + + leaves = list(compile_schema_tree(node, (), problems)) + + assert len(leaves) == 2 + assert all(isinstance(leaf, SchemaLeaf) for leaf in leaves) + sources = {leaf.source for leaf in leaves} + assert sources == {"request_id", "user_id"} + assert problems == [] + + +def test_compile_schema_tree_handles_nested_structure() -> None: + """_compile_schema_tree should handle deeply nested structures.""" + problems: list[SchemaProblem] = [] + node = { + "Level1": { + "Level2": { + "Level3": { + "Value": {"type": "str", "source": "value"}, + }, + }, + }, + } + + leaves = list(compile_schema_tree(node, (), problems)) + + assert len(leaves) == 1 + assert leaves[0].path == ("Level1", "Level2", "Level3", "Value") + assert leaves[0].source == "value" + assert problems == [] + + +def test_compile_schema_tree_reports_invalid_nodes() -> None: + """_compile_schema_tree should report problems for invalid nodes.""" + problems: list[SchemaProblem] = [] + node = { + "Valid": { + "Leaf": {"type": "str", "source": "valid"}, + }, + "Invalid": "not-an-object", + } + + leaves = list(compile_schema_tree(node, (), problems)) + + assert len(leaves) == 1 + assert leaves[0].source == "valid" + assert len(problems) == 1 + assert "expected object" in problems[0].message.lower() + + +def test_compile_schema_tree_respects_max_depth() -> None: + """_compile_schema_tree should stop processing when max depth is exceeded.""" + problems: list[SchemaProblem] = [] + # Create a path that exceeds MAX_SCHEMA_DEPTH + node = {} + current = node + for i in range(MAX_SCHEMA_DEPTH + 1): + current[f"Level{i}"] = {} + current = current[f"Level{i}"] + + # Add a leaf at the deepest level + current["Value"] = {"type": "str", "source": "value"} + + leaves = list(compile_schema_tree(node, (), problems)) + + # Should not process the leaf beyond max depth + assert len(leaves) == 0 + assert any("exceeds maximum allowed depth" in p.message for p in problems) + + +def test_get_builtin_logrecord_attributes_returns_set() -> None: + """get_builtin_logrecord_attributes should return a set of attribute names.""" + attributes = get_builtin_logrecord_attributes() + + assert isinstance(attributes, set) + assert len(attributes) > 0 + assert all(isinstance(attr, str) for attr in attributes) + + +def test_get_builtin_logrecord_attributes_includes_common_fields() -> None: + """get_builtin_logrecord_attributes should include common LogRecord fields.""" + attributes = get_builtin_logrecord_attributes() + + # These are standard LogRecord attributes + assert "name" in attributes + assert "levelno" in attributes + assert "pathname" in attributes + assert "lineno" in attributes + assert "msg" in attributes + + +def test_get_builtin_logrecord_attributes_excludes_private_attributes() -> None: + """get_builtin_logrecord_attributes should not include private attributes.""" + attributes = get_builtin_logrecord_attributes() + + # Should not include private attributes (starting with _) + private_attrs = {attr for attr in attributes if attr.startswith("_")} + assert not private_attrs + + +def test_get_builtin_logrecord_attributes_excludes_methods() -> None: + """get_builtin_logrecord_attributes should not include callable methods.""" + attributes = get_builtin_logrecord_attributes() + + # Should not include methods (callable attributes) + import logging + + record = logging.LogRecord( + name="", + level=0, + pathname="", + lineno=0, + msg="", + args=(), + exc_info=None, + ) + + # Check that no callable attributes are in the set + for attr in attributes: + value = getattr(record, attr, None) + assert not callable(value), f"Attribute {attr} should not be callable" + + +def test_get_builtin_logrecord_attributes_is_cached() -> None: + """get_builtin_logrecord_attributes is cached (same result on multiple calls).""" # noqa: E501 + attrs1 = get_builtin_logrecord_attributes() + attrs2 = get_builtin_logrecord_attributes() + + # Should return the same set (cached) + assert attrs1 is attrs2 + + +def test_check_root_conflicts_reports_conflicts() -> None: + """_check_root_conflicts should report conflicts with reserved logging fields.""" + problems: list[SchemaProblem] = [] + schema_dict = { + "name": { + "Value": {"type": "str", "source": "value"}, + }, + "levelno": { + "Value": {"type": "int", "source": "value2"}, + }, + } + + check_root_conflicts(schema_dict, problems) + + assert len(problems) == 2 + assert all("conflicts with reserved logging fields" in p.message for p in problems) + + +def test_check_root_conflicts_no_conflicts() -> None: + """_check_root_conflicts should not report problems when no conflicts exist.""" + problems: list[SchemaProblem] = [] + schema_dict = { + "ServicePayload": { + "RequestID": {"type": "str", "source": "request_id"}, + }, + "UserPayload": { + "UserID": {"type": "int", "source": "user_id"}, + }, + } + + check_root_conflicts(schema_dict, problems) + + assert problems == [] + + +def test_check_root_conflicts_empty_schema() -> None: + """_check_root_conflicts should handle empty schema.""" + problems: list[SchemaProblem] = [] + schema_dict: dict[str, Any] = {} + + check_root_conflicts(schema_dict, problems) + + assert problems == [] From 0bc1a6cfb4d202832d36c30af2fa8b98d565f9a6 Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Sat, 6 Dec 2025 03:03:55 +0400 Subject: [PATCH 36/53] refactor(schema_logger): extract logger cleanup logic into a helper method - Introduced a new method `_cleanup_failed_logger` to encapsulate the logic for removing a logger instance from the logging manager when schema compilation fails. This change improves code readability and maintainability by centralizing the cleanup process, preventing broken logger instances from being cached. Signed-off-by: Dmitrii Safronov --- src/logging_objects_with_schema/schema_logger.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/logging_objects_with_schema/schema_logger.py b/src/logging_objects_with_schema/schema_logger.py index 14c43d9..5ef04c4 100644 --- a/src/logging_objects_with_schema/schema_logger.py +++ b/src/logging_objects_with_schema/schema_logger.py @@ -56,17 +56,25 @@ def __init__(self, name: str, level: int = logging.NOTSET) -> None: # registered in the logging manager if schema compilation fails. # Otherwise, subsequent logging.getLogger(name) calls could return # this broken instance and lead to AttributeError at runtime. - self.manager.loggerDict.pop(self.name, None) + self._cleanup_failed_logger() raise if problems: # Schema is invalid; remove this instance from the logging manager # cache before raising, for the same reason as above. - self.manager.loggerDict.pop(self.name, None) + self._cleanup_failed_logger() raise SchemaValidationError("Schema has problems", problems=problems) self._schema: CompiledSchema = compiled + def _cleanup_failed_logger(self) -> None: + """Remove this logger instance from the logging manager. + + Called when schema compilation fails to prevent broken logger + instances from being cached and reused. + """ + self.manager.loggerDict.pop(self.name, None) + def _log( self, level: int, From 6abaf80501feb78ade694eb27a8d637c9bd14793 Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Sat, 6 Dec 2025 03:07:55 +0400 Subject: [PATCH 37/53] refactor(schema_loader): add helper function to identify leaf nodes in schema - Introduced a new helper function `_is_leaf_node` to determine if a schema node is a leaf based on the presence of 'type' or 'source' fields. This change enhances code readability and modularity by centralizing the logic for leaf node identification. - Updated the `_compile_schema_tree` function to utilize the new helper function, improving clarity in the schema compilation process. Signed-off-by: Dmitrii Safronov --- .../schema_loader.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/logging_objects_with_schema/schema_loader.py b/src/logging_objects_with_schema/schema_loader.py index 0c00b36..7d7addc 100644 --- a/src/logging_objects_with_schema/schema_loader.py +++ b/src/logging_objects_with_schema/schema_loader.py @@ -322,6 +322,21 @@ def _is_empty_or_none(value: Any) -> bool: return value is None or (isinstance(value, str) and value.strip() == "") +def _is_leaf_node(value_dict: dict[str, Any]) -> bool: + """Check if a schema node is a leaf node. + + A leaf node is identified by having either 'type' or 'source' field. + Inner nodes have neither of these fields. + + Args: + value_dict: Dictionary containing node data. + + Returns: + True if the node is a leaf, False if it's an inner node. + """ + return value_dict.get("type") is not None or value_dict.get("source") is not None + + def _validate_and_create_leaf( value_dict: dict[str, Any], path: tuple[str, ...], @@ -445,10 +460,8 @@ def _compile_schema_tree( continue value_dict = dict(value) - leaf_type = value_dict.get("type") - leaf_source = value_dict.get("source") - if leaf_type is not None or leaf_source is not None: + if _is_leaf_node(value_dict): leaf = _validate_and_create_leaf(value_dict, path, key, problems) if leaf is not None: yield leaf From a9abcb43d6f4ab28ad98c46579053579cd70e7f6 Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Sat, 6 Dec 2025 03:10:34 +0400 Subject: [PATCH 38/53] test(schema_loader): add unit tests for _is_leaf_node function - Introduced multiple test cases for the new `_is_leaf_node` function to validate its behavior with various input scenarios, including nodes with and without 'type' and 'source' fields. This enhances test coverage and ensures the correctness of the leaf node identification logic. Signed-off-by: Dmitrii Safronov --- tests/test_schema_loader.py | 53 +++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/tests/test_schema_loader.py b/tests/test_schema_loader.py index 0bdf794..42bf9fe 100644 --- a/tests/test_schema_loader.py +++ b/tests/test_schema_loader.py @@ -53,6 +53,7 @@ from logging_objects_with_schema.schema_loader import ( _is_empty_or_none as is_empty_or_none, ) +from logging_objects_with_schema.schema_loader import _is_leaf_node as is_leaf_node from logging_objects_with_schema.schema_loader import ( _load_raw_schema as load_raw_schema, ) @@ -1434,3 +1435,55 @@ def test_check_root_conflicts_empty_schema() -> None: check_root_conflicts(schema_dict, problems) assert problems == [] + + +def test_is_leaf_node_with_type() -> None: + """_is_leaf_node should return True for node with type field.""" + value_dict = {"type": "str", "source": "request_id"} + assert is_leaf_node(value_dict) is True + + +def test_is_leaf_node_with_source() -> None: + """_is_leaf_node should return True for node with source field.""" + value_dict = {"source": "request_id"} + assert is_leaf_node(value_dict) is True + + +def test_is_leaf_node_with_both_fields() -> None: + """_is_leaf_node should return True for node with both type and source.""" + value_dict = {"type": "int", "source": "user_id"} + assert is_leaf_node(value_dict) is True + + +def test_is_leaf_node_without_fields() -> None: + """_is_leaf_node should return False for inner node without type or source.""" + value_dict = {"nested": {}} + assert is_leaf_node(value_dict) is False + + +def test_is_leaf_node_with_empty_dict() -> None: + """_is_leaf_node should return False for empty dictionary.""" + value_dict: dict[str, Any] = {} + assert is_leaf_node(value_dict) is False + + +def test_is_leaf_node_with_type_none() -> None: + """_is_leaf_node should return True when type is None but source is present.""" + value_dict = {"type": None, "source": "request_id"} + # Note: get() returns None, so "type" is None, but "source" is not None + # So this should still return True because source is present + assert is_leaf_node(value_dict) is True + + +def test_is_leaf_node_with_source_none() -> None: + """_is_leaf_node should return True when source is None but type is present.""" + value_dict = {"type": "str", "source": None} + # Note: get() returns None, so "source" is None, but "type" is not None + # So this should still return True because type is present + assert is_leaf_node(value_dict) is True + + +def test_is_leaf_node_with_both_none() -> None: + """_is_leaf_node should return False when both type and source are None.""" + value_dict = {"type": None, "source": None} + assert is_leaf_node(value_dict) is False From b4a00d100a1a3e3bf674fbe9f1af523fe0888ff5 Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Sat, 6 Dec 2025 03:19:37 +0400 Subject: [PATCH 39/53] refactor(schema_loader): simplify schema path resolution in compilation - Updated the `_compile_schema_internal` function to directly use the result of `_get_schema_path()` without calling `resolve()`. This change enhances code clarity by removing unnecessary complexity in the schema path handling. Signed-off-by: Dmitrii Safronov --- src/logging_objects_with_schema/schema_loader.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/logging_objects_with_schema/schema_loader.py b/src/logging_objects_with_schema/schema_loader.py index 7d7addc..4a667d5 100644 --- a/src/logging_objects_with_schema/schema_loader.py +++ b/src/logging_objects_with_schema/schema_loader.py @@ -568,7 +568,7 @@ def _compile_schema_internal() -> tuple[CompiledSchema, list[SchemaProblem]]: Returns: Tuple of (CompiledSchema, list[SchemaProblem]). """ - schema_path = _get_schema_path().resolve() + schema_path = _get_schema_path() # Fast-path: if we have already attempted to compile schema for this path, # return cached result (successful, missing-file, or invalid-schema). From 78d287772a44ca53668a8fbaad539b461d935069 Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Sat, 6 Dec 2025 03:28:20 +0400 Subject: [PATCH 40/53] refactor(schema_logger): enhance exception handling during schema compilation - Updated the exception handling in the `SchemaLogger` class to specifically catch `OSError`, `ValueError`, and `RuntimeError` during schema compilation. This change ensures that the logger instance is properly cleaned up from the logging manager in case of these exceptions, preventing partially initialized loggers from being cached. - Added unit tests to verify that the logger correctly handles these exceptions and cleans up as expected. Signed-off-by: Dmitrii Safronov --- .../schema_logger.py | 10 +- tests/test_schema_logger_mimic.py | 140 ++++++++++++++++++ 2 files changed, 149 insertions(+), 1 deletion(-) diff --git a/src/logging_objects_with_schema/schema_logger.py b/src/logging_objects_with_schema/schema_logger.py index 5ef04c4..2ad8fcf 100644 --- a/src/logging_objects_with_schema/schema_logger.py +++ b/src/logging_objects_with_schema/schema_logger.py @@ -51,7 +51,15 @@ def __init__(self, name: str, level: int = logging.NOTSET) -> None: try: compiled, problems = _compile_schema_internal() - except Exception: + except (OSError, ValueError, RuntimeError): + # Catch specific exceptions that can occur during schema compilation: + # - OSError: file system issues (e.g., os.getcwd() failures, + # permission errors) + # - ValueError: data validation issues (e.g., JSON parsing, + # schema structure) + # - RuntimeError: threading issues (e.g., lock acquisition problems) + # Note: System exceptions (KeyboardInterrupt, SystemExit) are not + # caught, which is the correct behavior. # Ensure that a partially initialised logger instance is not left # registered in the logging manager if schema compilation fails. # Otherwise, subsequent logging.getLogger(name) calls could return diff --git a/tests/test_schema_logger_mimic.py b/tests/test_schema_logger_mimic.py index 5b405ed..9c54e82 100644 --- a/tests/test_schema_logger_mimic.py +++ b/tests/test_schema_logger_mimic.py @@ -200,3 +200,143 @@ def test_schema_logger_does_not_leave_partially_initialised_logger_in_cache( assert "bad-schema-logger" not in logging.Logger.manager.loggerDict finally: logging.setLoggerClass(logging.Logger) + + +def test_schema_logger_handles_oserror_from_getcwd_and_cleans_up( + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, +) -> None: + """SchemaLogger should catch OSError from os.getcwd() and clean up logger. + + If os.getcwd() raises OSError (e.g., when CWD is deleted), the exception + should be caught, logger should be cleaned up from cache, and exception + should be re-raised. + """ + import os + + import logging_objects_with_schema.schema_loader as schema_loader + + monkeypatch.chdir(tmp_path) + _write_schema(tmp_path, {"ServicePayload": {}}) + + original_getcwd = os.getcwd + + def fake_getcwd() -> str: + raise OSError("Current working directory no longer exists") + + monkeypatch.setattr(os, "getcwd", fake_getcwd) + + logging.setLoggerClass(SchemaLogger) + try: + # Clear schema cache to force recompilation + with schema_loader._cache_lock: + schema_loader._SCHEMA_CACHE.clear() + with schema_loader._path_cache_lock: + schema_loader._resolved_schema_path = None + schema_loader._cached_cwd = None + + # Attempting to create/get the logger should raise OSError, + # and the partially initialised instance must be removed from cache. + with pytest.raises(OSError, match="Current working directory"): + logging.getLogger("oserror-logger") + + # Ensure that the logger with this name is not left registered in the + # logging manager cache after failed initialisation. + assert "oserror-logger" not in logging.Logger.manager.loggerDict + finally: + monkeypatch.setattr(os, "getcwd", original_getcwd) + logging.setLoggerClass(logging.Logger) + + +def test_schema_logger_handles_runtimeerror_from_lock_and_cleans_up( + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, +) -> None: + """SchemaLogger should catch RuntimeError from threading locks and clean up. + + If a threading lock raises RuntimeError (e.g., deadlock detection), + the exception should be caught, logger should be cleaned up from cache, + and exception should be re-raised. + """ + import logging_objects_with_schema.schema_loader as schema_loader + + monkeypatch.chdir(tmp_path) + _write_schema(tmp_path, {"ServicePayload": {}}) + + original_lock = schema_loader._cache_lock + + class FakeLock: + def __enter__(self) -> None: + raise RuntimeError("Lock acquisition failed") + + def __exit__(self, *args: object) -> None: + pass + + fake_lock = FakeLock() + monkeypatch.setattr(schema_loader, "_cache_lock", fake_lock) + + logging.setLoggerClass(SchemaLogger) + try: + # Clear schema cache to force recompilation + with original_lock: + schema_loader._SCHEMA_CACHE.clear() + with schema_loader._path_cache_lock: + schema_loader._resolved_schema_path = None + schema_loader._cached_cwd = None + + # Attempting to create/get the logger should raise RuntimeError, + # and the partially initialised instance must be removed from cache. + with pytest.raises(RuntimeError, match="Lock acquisition failed"): + logging.getLogger("runtimeerror-logger") + + # Ensure that the logger with this name is not left registered in the + # logging manager cache after failed initialisation. + assert "runtimeerror-logger" not in logging.Logger.manager.loggerDict + finally: + monkeypatch.setattr(schema_loader, "_cache_lock", original_lock) + logging.setLoggerClass(logging.Logger) + + +def test_schema_logger_handles_valueerror_and_cleans_up( + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, +) -> None: + """SchemaLogger should catch ValueError and clean up logger. + + If ValueError is raised during schema compilation (outside of the + try-except block in _compile_schema_internal), the exception should be + caught, logger should be cleaned up from cache, and exception should be + re-raised. + """ + import logging_objects_with_schema.schema_loader as schema_loader + + monkeypatch.chdir(tmp_path) + _write_schema(tmp_path, {"ServicePayload": {}}) + + original_get_schema_path = schema_loader._get_schema_path + + def fake_get_schema_path() -> Path: + raise ValueError("Unexpected value error during path resolution") + + monkeypatch.setattr(schema_loader, "_get_schema_path", fake_get_schema_path) + + logging.setLoggerClass(SchemaLogger) + try: + # Clear schema cache to force recompilation + with schema_loader._cache_lock: + schema_loader._SCHEMA_CACHE.clear() + with schema_loader._path_cache_lock: + schema_loader._resolved_schema_path = None + schema_loader._cached_cwd = None + + # Attempting to create/get the logger should raise ValueError, + # and the partially initialised instance must be removed from cache. + with pytest.raises(ValueError, match="Unexpected value error"): + logging.getLogger("valueerror-logger") + + # Ensure that the logger with this name is not left registered in the + # logging manager cache after failed initialisation. + assert "valueerror-logger" not in logging.Logger.manager.loggerDict + finally: + monkeypatch.setattr(schema_loader, "_get_schema_path", original_get_schema_path) + logging.setLoggerClass(logging.Logger) From 2f0d6e9a4da7a54ed952b17ccabb14923473af5d Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Sat, 6 Dec 2025 03:31:15 +0400 Subject: [PATCH 41/53] docs(README): clarify exception handling for schema validation - Added a note to the README regarding the handling of system-level errors such as `OSError` and `RuntimeError` during schema validation. This clarification helps users distinguish between schema validation failures and environmental issues, ensuring better understanding of exception management in the application. Signed-off-by: Dmitrii Safronov --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 8dfd319..2d23d65 100644 --- a/README.md +++ b/README.md @@ -323,6 +323,14 @@ consistent type expectations when reusing a `source` field. The application decides whether `SchemaValidationError` is a fatal error that should abort startup, or whether it should be logged and ignored. +**Note**: In rare cases, system-level errors may be raised directly instead of +being wrapped in `SchemaValidationError`. Specifically, `OSError` (e.g., when +the current working directory is inaccessible or deleted) and `RuntimeError` +(e.g., when thread lock acquisition fails) are propagated as-is to indicate +environmental issues rather than schema validation problems. Applications +should handle these exceptions separately if they need to distinguish between +schema validation failures and system-level errors. + ## Schema caching and thread safety - The library caches compiled schemas to avoid recompiling the same schema file From baa36c8c00373b6694317d9240ef1d978b28f234 Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Sat, 6 Dec 2025 03:31:46 +0400 Subject: [PATCH 42/53] docs(README): add handling for system-level errors during logger initialization - Updated the README to include information on handling system-level errors such as `OSError` and `RuntimeError` during logger initialization. This addition clarifies the distinction between schema validation errors and environmental issues, enhancing user understanding of exception management. Signed-off-by: Dmitrii Safronov --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 2d23d65..952b2c8 100644 --- a/README.md +++ b/README.md @@ -144,6 +144,11 @@ except SchemaValidationError as e: print(f" - {problem.message}") # Decide whether to abort or continue with default logger raise +except (OSError, RuntimeError) as e: + # System-level errors (e.g., inaccessible working directory, lock failures) + # are raised directly, not wrapped in SchemaValidationError + print(f"System error during logger initialization: {e}") + raise # When logging, handle DataValidationError try: From f6106bca9421a8071e97227d9faea0568013ab0a Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Sat, 6 Dec 2025 03:34:59 +0400 Subject: [PATCH 43/53] refactor(schema_applier): optimize redundant field reporting in schema application - Enhanced the logic for reporting redundant fields in the `_apply_schema_internal` function. If the schema is empty, all fields are now considered redundant, allowing for a more efficient membership check. This change improves performance and clarity in handling extra values not defined in the schema. Signed-off-by: Dmitrii Safronov --- .../schema_applier.py | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/logging_objects_with_schema/schema_applier.py b/src/logging_objects_with_schema/schema_applier.py index 4bf41aa..291a94e 100644 --- a/src/logging_objects_with_schema/schema_applier.py +++ b/src/logging_objects_with_schema/schema_applier.py @@ -234,13 +234,19 @@ def _apply_schema_internal( _validate_and_apply_leaf(leaf, value, source, extra, problems) # Report redundant fields for any keys not referenced by schema leaves. - for key in extra_values.keys(): - if key not in used_sources: - problems.append( - DataProblem( - f"Field '{key}' is not defined in schema and will be ignored", - ), - ) + # Optimization: if schema is empty (no used_sources), all fields are redundant, + # so we can skip the membership check for each key. + redundant_keys = ( + extra_values.keys() + if not used_sources + else (key for key in extra_values.keys() if key not in used_sources) + ) + for key in redundant_keys: + problems.append( + DataProblem( + f"Field '{key}' is not defined in schema and will be ignored", + ), + ) cleaned_extra = _strip_empty(extra) return cleaned_extra, problems From 0ff75b1e3d3403db6f78db57285d9f956d27faf5 Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Sat, 6 Dec 2025 03:39:17 +0400 Subject: [PATCH 44/53] docs(schema_applier): clarify type checking for list validation - Added a note in the `_validate_and_apply_leaf` function to emphasize the necessity of using `isinstance()` for type narrowing, despite the prior guarantee that `value` is a list. This clarification enhances code readability and understanding of type validation logic. Signed-off-by: Dmitrii Safronov --- src/logging_objects_with_schema/schema_applier.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/logging_objects_with_schema/schema_applier.py b/src/logging_objects_with_schema/schema_applier.py index 291a94e..392d7eb 100644 --- a/src/logging_objects_with_schema/schema_applier.py +++ b/src/logging_objects_with_schema/schema_applier.py @@ -117,6 +117,8 @@ def _validate_and_apply_leaf( # For lists, validate that all elements strictly match the declared # item_expected_type (homogeneous primitive list). + # Note: isinstance() check is needed for type narrowing (mypy), even though + # type(value) is list is already guaranteed by the check above. if leaf.expected_type is list and isinstance(value, list): list_problem = _validate_list_value(value, source, leaf.item_expected_type) if list_problem is not None: From ed8e214738c8c876ce0e9ca9fbee667f52d58cce Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Sat, 6 Dec 2025 03:46:09 +0400 Subject: [PATCH 45/53] docs: update exception handling for system-level errors - Revised the README to clarify the handling of system-level errors, including `OSError`, `ValueError`, and `RuntimeError`, during logger initialization and schema compilation. This update enhances user understanding of the distinction between schema validation failures and environmental issues. - Updated comments in the `SchemaLogger` class to reflect the new exception handling logic, specifically addressing path resolution issues and ensuring clarity in the documentation of potential exceptions during schema compilation. Signed-off-by: Dmitrii Safronov --- README.md | 17 +++++++++-------- .../schema_logger.py | 6 ++++-- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 952b2c8..e82b538 100644 --- a/README.md +++ b/README.md @@ -144,9 +144,9 @@ except SchemaValidationError as e: print(f" - {problem.message}") # Decide whether to abort or continue with default logger raise -except (OSError, RuntimeError) as e: - # System-level errors (e.g., inaccessible working directory, lock failures) - # are raised directly, not wrapped in SchemaValidationError +except (OSError, ValueError, RuntimeError) as e: + # System-level errors (e.g., inaccessible working directory, lock failures, + # path resolution issues) are raised directly, not wrapped in SchemaValidationError print(f"System error during logger initialization: {e}") raise @@ -330,11 +330,12 @@ should abort startup, or whether it should be logged and ignored. **Note**: In rare cases, system-level errors may be raised directly instead of being wrapped in `SchemaValidationError`. Specifically, `OSError` (e.g., when -the current working directory is inaccessible or deleted) and `RuntimeError` -(e.g., when thread lock acquisition fails) are propagated as-is to indicate -environmental issues rather than schema validation problems. Applications -should handle these exceptions separately if they need to distinguish between -schema validation failures and system-level errors. +the current working directory is inaccessible or deleted), `ValueError` (e.g., +when path resolution fails due to invalid characters or malformed paths), and +`RuntimeError` (e.g., when thread lock acquisition fails) are propagated as-is +to indicate environmental issues rather than schema validation problems. +Applications should handle these exceptions separately if they need to +distinguish between schema validation failures and system-level errors. ## Schema caching and thread safety diff --git a/src/logging_objects_with_schema/schema_logger.py b/src/logging_objects_with_schema/schema_logger.py index 2ad8fcf..a1dfb6d 100644 --- a/src/logging_objects_with_schema/schema_logger.py +++ b/src/logging_objects_with_schema/schema_logger.py @@ -55,9 +55,11 @@ def __init__(self, name: str, level: int = logging.NOTSET) -> None: # Catch specific exceptions that can occur during schema compilation: # - OSError: file system issues (e.g., os.getcwd() failures, # permission errors) - # - ValueError: data validation issues (e.g., JSON parsing, - # schema structure) + # - ValueError: path resolution issues (e.g., invalid path characters, + # malformed paths during schema file discovery) # - RuntimeError: threading issues (e.g., lock acquisition problems) + # Note: JSON parsing and schema structure validation errors are + # converted to SchemaProblem instances and do not raise ValueError here. # Note: System exceptions (KeyboardInterrupt, SystemExit) are not # caught, which is the correct behavior. # Ensure that a partially initialised logger instance is not left From 328b07a5e476e3d76f01aea4727d24b264dd6416 Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Sat, 6 Dec 2025 03:50:11 +0400 Subject: [PATCH 46/53] refactor(schema_loader): update _load_raw_schema to accept schema_path as an argument - Modified the `_load_raw_schema` function to take `schema_path` as a parameter instead of retrieving it internally. This change enhances flexibility and allows for better control over schema file loading. - Updated related tests to reflect the new function signature, ensuring that the correct schema path is passed during testing. Signed-off-by: Dmitrii Safronov --- src/logging_objects_with_schema/schema_loader.py | 9 +++++---- tests/test_schema_loader.py | 16 ++++++++++------ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/logging_objects_with_schema/schema_loader.py b/src/logging_objects_with_schema/schema_loader.py index 4a667d5..8d603d5 100644 --- a/src/logging_objects_with_schema/schema_loader.py +++ b/src/logging_objects_with_schema/schema_loader.py @@ -255,12 +255,15 @@ def _get_schema_path() -> Path: return _cache_and_return_missing_path() -def _load_raw_schema() -> tuple[dict[str, Any], Path]: +def _load_raw_schema(schema_path: Path) -> tuple[dict[str, Any], Path]: """Load raw JSON schema from the application root. This function always attempts to read the schema file and records any problems as :class:`SchemaProblem` instances. + Args: + schema_path: Absolute path to the schema file. + Note: This helper is part of the internal implementation and is not considered a public API. @@ -268,8 +271,6 @@ def _load_raw_schema() -> tuple[dict[str, Any], Path]: Returns: Tuple of (schema data, schema file path). """ - schema_path = _get_schema_path() - if not schema_path.exists(): # Let the caller decide how to report this. raise FileNotFoundError(f"Schema file not found: {schema_path}") @@ -580,7 +581,7 @@ def _compile_schema_internal() -> tuple[CompiledSchema, list[SchemaProblem]]: problems: list[SchemaProblem] = [] try: - raw_schema, _ = _load_raw_schema() + raw_schema, _ = _load_raw_schema(schema_path) except (FileNotFoundError, ValueError) as exc: problems.append(SchemaProblem(str(exc))) result = _create_empty_compiled_schema_with_problems(problems) diff --git a/tests/test_schema_loader.py b/tests/test_schema_loader.py index 42bf9fe..80434ed 100644 --- a/tests/test_schema_loader.py +++ b/tests/test_schema_loader.py @@ -1199,12 +1199,13 @@ def test_load_raw_schema_loads_valid_schema( } _write_schema(tmp_path, schema_data) - data, schema_path = load_raw_schema() + schema_path = get_schema_path() + data, returned_schema_path = load_raw_schema(schema_path) assert isinstance(data, dict) assert data == schema_data - assert schema_path == (tmp_path / SCHEMA_FILE_NAME).resolve() - assert schema_path.exists() + assert returned_schema_path == (tmp_path / SCHEMA_FILE_NAME).resolve() + assert returned_schema_path.exists() def test_load_raw_schema_raises_file_not_found_when_missing( @@ -1214,8 +1215,9 @@ def test_load_raw_schema_raises_file_not_found_when_missing( """_load_raw_schema should raise FileNotFoundError when schema file is missing.""" monkeypatch.chdir(tmp_path) + schema_path = get_schema_path() with pytest.raises(FileNotFoundError) as exc_info: - load_raw_schema() + load_raw_schema(schema_path) assert "Schema file not found" in str(exc_info.value) assert SCHEMA_FILE_NAME in str(exc_info.value) @@ -1230,8 +1232,9 @@ def test_load_raw_schema_raises_value_error_for_invalid_json( schema_file = tmp_path / SCHEMA_FILE_NAME schema_file.write_text("{ invalid json }", encoding="utf-8") + schema_path = get_schema_path() with pytest.raises(ValueError) as exc_info: - load_raw_schema() + load_raw_schema(schema_path) assert "Failed to parse JSON schema" in str(exc_info.value) @@ -1246,8 +1249,9 @@ def test_load_raw_schema_raises_value_error_for_non_object( # Write a JSON array instead of an object schema_file.write_text('["not", "an", "object"]', encoding="utf-8") + schema_path = get_schema_path() with pytest.raises(ValueError) as exc_info: - load_raw_schema() + load_raw_schema(schema_path) assert "Top-level schema must be a JSON object" in str(exc_info.value) From c922177ed29892ca8036f4315bc7b60a7a37d337 Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Sat, 6 Dec 2025 03:52:43 +0400 Subject: [PATCH 47/53] refactor(schema_loader): improve thread safety in schema compilation - Enhanced the thread safety of the `_compile_schema_internal` function by implementing double-checked locking. This change prevents multiple threads from compiling the same schema simultaneously, ensuring that cached results are returned correctly during concurrent access. - Updated comments to clarify the use of double-checked locking in the context of schema compilation. Signed-off-by: Dmitrii Safronov --- src/logging_objects_with_schema/schema_loader.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/logging_objects_with_schema/schema_loader.py b/src/logging_objects_with_schema/schema_loader.py index 8d603d5..6759dc1 100644 --- a/src/logging_objects_with_schema/schema_loader.py +++ b/src/logging_objects_with_schema/schema_loader.py @@ -81,7 +81,8 @@ def _create_empty_compiled_schema_with_problems( # Module-level cache for compiled schemas. # Key: absolute schema_path, Value: (CompiledSchema, list[SchemaProblem]) # This cache is thread-safe: all read and write operations are protected by -# _cache_lock. +# _cache_lock. Double-checked locking is used in _compile_schema_internal() +# to prevent multiple threads from compiling the same schema simultaneously. _SCHEMA_CACHE: dict[Path, tuple[CompiledSchema, list[SchemaProblem]]] = {} _cache_lock = threading.RLock() @@ -585,7 +586,12 @@ def _compile_schema_internal() -> tuple[CompiledSchema, list[SchemaProblem]]: except (FileNotFoundError, ValueError) as exc: problems.append(SchemaProblem(str(exc))) result = _create_empty_compiled_schema_with_problems(problems) + # Double-checked locking: another thread might have compiled the schema + # while we were handling the error. with _cache_lock: + cached = _SCHEMA_CACHE.get(schema_path) + if cached is not None: + return cached _SCHEMA_CACHE[schema_path] = result return result @@ -605,8 +611,12 @@ def _compile_schema_internal() -> tuple[CompiledSchema, list[SchemaProblem]]: compiled = CompiledSchema(leaves=leaves) result = (compiled, problems) - # Cache the result for this schema path (thread-safe write). + # Double-checked locking: another thread might have compiled the schema + # while we were compiling it. with _cache_lock: + cached = _SCHEMA_CACHE.get(schema_path) + if cached is not None: + return cached _SCHEMA_CACHE[schema_path] = result return result From 6e63a36b67feba3d0863a1c65b7f32a950aad360 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sat, 6 Dec 2025 00:12:59 +0000 Subject: [PATCH 48/53] chore(release): 0.1.1-rc.5 ## [0.1.1-rc.5](https://github.com/disafronov/python-logging-objects-with-schema/compare/v0.1.1-rc.4...v0.1.1-rc.5) (2025-12-06) --- pyproject.toml | 2 +- uv.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 5c09d66..6e0169e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "uv_build" [project] name = "logging-objects-with-schema" -version = "0.1.1rc4" +version = "0.1.1rc5" description = "Proxy logging wrapper that validates extra fields against a JSON schema." readme = "README.md" requires-python = ">=3.10" diff --git a/uv.lock b/uv.lock index 4ed1617..f676b62 100644 --- a/uv.lock +++ b/uv.lock @@ -1394,7 +1394,7 @@ version = "0.6.3" [[package]] name = "logging-objects-with-schema" -version = "0.1.1rc4" +version = "0.1.1rc5" [package.source] editable = "." From 21637eb12f92cc6877ef13909ce1235eb316cc9e Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Sat, 6 Dec 2025 04:03:25 +0400 Subject: [PATCH 49/53] docs: enhance README and comments for system-level error handling - Updated the README to provide clearer distinctions between schema validation errors and system-level errors, specifically detailing the handling of `OSError`, `ValueError`, and `RuntimeError`. - Improved comments in the `schema_loader` and `schema_logger` modules to clarify the propagation of exceptions during schema file reading and compilation, ensuring users understand the context of these errors. Signed-off-by: Dmitrii Safronov --- README.md | 22 +++++++++++++------ .../schema_loader.py | 6 +++-- .../schema_logger.py | 7 ++++-- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index e82b538..5324733 100644 --- a/README.md +++ b/README.md @@ -145,8 +145,10 @@ except SchemaValidationError as e: # Decide whether to abort or continue with default logger raise except (OSError, ValueError, RuntimeError) as e: - # System-level errors (e.g., inaccessible working directory, lock failures, - # path resolution issues) are raised directly, not wrapped in SchemaValidationError + # System-level errors (e.g., inaccessible working directory when os.getcwd() + # fails, lock failures, path resolution issues) are raised directly, not + # wrapped in SchemaValidationError. Note: OSError when reading the schema + # file is converted to SchemaValidationError and handled above. print(f"System error during logger initialization: {e}") raise @@ -329,11 +331,17 @@ The application decides whether `SchemaValidationError` is a fatal error that should abort startup, or whether it should be logged and ignored. **Note**: In rare cases, system-level errors may be raised directly instead of -being wrapped in `SchemaValidationError`. Specifically, `OSError` (e.g., when -the current working directory is inaccessible or deleted), `ValueError` (e.g., -when path resolution fails due to invalid characters or malformed paths), and -`RuntimeError` (e.g., when thread lock acquisition fails) are propagated as-is -to indicate environmental issues rather than schema validation problems. +being wrapped in `SchemaValidationError`. Specifically: + +- `OSError` when the current working directory is inaccessible or deleted (e.g., + when `os.getcwd()` fails) is propagated as-is to indicate environmental issues. + However, `OSError` that occurs when reading the schema file (e.g., permission + denied, I/O errors) is converted to `SchemaValidationError` and reported as a + schema problem. +- `ValueError` when path resolution fails due to invalid characters or malformed + paths during schema file discovery is propagated as-is. +- `RuntimeError` when thread lock acquisition fails is propagated as-is. + Applications should handle these exceptions separately if they need to distinguish between schema validation failures and system-level errors. diff --git a/src/logging_objects_with_schema/schema_loader.py b/src/logging_objects_with_schema/schema_loader.py index 6759dc1..639de0c 100644 --- a/src/logging_objects_with_schema/schema_loader.py +++ b/src/logging_objects_with_schema/schema_loader.py @@ -280,9 +280,11 @@ def _load_raw_schema(schema_path: Path) -> tuple[dict[str, Any], Path]: with schema_path.open("r", encoding="utf-8") as f: data = json.load(f) except OSError as exc: - # Normalise I/O errors to ValueError so that _compile_schema_internal() + # Normalise I/O errors when reading the schema file (e.g., permission + # denied, file not found) to ValueError so that _compile_schema_internal() # can report them as SchemaProblem instances instead of leaking raw - # OSError to callers. + # OSError to callers. Note: System-level OSError (e.g., from os.getcwd()) + # is not caught here and propagates directly. raise ValueError( f"Failed to read schema file {schema_path}: {exc}", ) from exc diff --git a/src/logging_objects_with_schema/schema_logger.py b/src/logging_objects_with_schema/schema_logger.py index a1dfb6d..1c0b363 100644 --- a/src/logging_objects_with_schema/schema_logger.py +++ b/src/logging_objects_with_schema/schema_logger.py @@ -53,8 +53,11 @@ def __init__(self, name: str, level: int = logging.NOTSET) -> None: compiled, problems = _compile_schema_internal() except (OSError, ValueError, RuntimeError): # Catch specific exceptions that can occur during schema compilation: - # - OSError: file system issues (e.g., os.getcwd() failures, - # permission errors) + # - OSError: system-level file system issues (e.g., os.getcwd() failures + # when the current working directory is inaccessible or deleted). + # Note: OSError that occurs when reading the schema file (e.g., permission + # denied, I/O errors) is converted to SchemaValidationError in + # _load_raw_schema() and does not reach this exception handler. # - ValueError: path resolution issues (e.g., invalid path characters, # malformed paths during schema file discovery) # - RuntimeError: threading issues (e.g., lock acquisition problems) From 6f2e1e9ea82284515e726722da5b68cd370fc41b Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Sat, 6 Dec 2025 04:31:09 +0400 Subject: [PATCH 50/53] ci: add GitHub Actions workflow for automatic PR description generation - Introduced a new workflow that triggers on pull request events to the release branch. It generates a PR description and automatically updates the PR title and body to include a timestamped release note. - This enhancement streamlines the release process by ensuring consistent and informative PR descriptions. Signed-off-by: Dmitrii Safronov --- .github/workflows/auto-pr-description.yml | 39 +++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .github/workflows/auto-pr-description.yml diff --git a/.github/workflows/auto-pr-description.yml b/.github/workflows/auto-pr-description.yml new file mode 100644 index 0000000..edc4811 --- /dev/null +++ b/.github/workflows/auto-pr-description.yml @@ -0,0 +1,39 @@ +name: Force Release PR + +on: + pull_request: + types: + - opened + - synchronize + - reopened + branches: + - release + +jobs: + force-release-pr: + runs-on: ubuntu-latest + if: github.event.pull_request.head.ref == 'main' + + steps: + - uses: actions/checkout@v4 + + - name: Generate PR description + id: gen + uses: riskledger/generate-pull-request-description@v1 + + - name: Force overwrite PR title and body + uses: actions/github-script@v7 + env: + PR_BODY: ${{ steps.gen.outputs.description }} + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const now = new Date().toISOString().slice(0,16).replace('T',' '); + const body = process.env.PR_BODY; + await github.rest.pulls.update({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.payload.pull_request.number, + title: `Release PR for ${now}`, + body: body + }); From 33b3bb2040da6d86b8693b731fb261c5f513a926 Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Sat, 6 Dec 2025 04:34:02 +0400 Subject: [PATCH 51/53] ci: update GitHub Actions workflow permissions for PR handling - Added permissions for reading contents and writing to pull requests in the auto PR description workflow. This enhancement ensures the workflow can properly access and modify PR details as needed. Signed-off-by: Dmitrii Safronov --- .github/workflows/auto-pr-description.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/auto-pr-description.yml b/.github/workflows/auto-pr-description.yml index edc4811..9894076 100644 --- a/.github/workflows/auto-pr-description.yml +++ b/.github/workflows/auto-pr-description.yml @@ -12,6 +12,9 @@ on: jobs: force-release-pr: runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write if: github.event.pull_request.head.ref == 'main' steps: From bd531cb19535e9ba2dff9e86f32d819e2fab9cda Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Sat, 6 Dec 2025 04:46:23 +0400 Subject: [PATCH 52/53] ci: update PR description generation action and output variable - Changed the action used for generating pull request descriptions from `riskledger/generate-pull-request-description@v1` to `octue/generate-pull-request-description@1.0.0.beta-2`. - Updated the output variable from `description` to `pull_request_description` to align with the new action's output format. Signed-off-by: Dmitrii Safronov --- .github/workflows/auto-pr-description.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/auto-pr-description.yml b/.github/workflows/auto-pr-description.yml index 9894076..88c1522 100644 --- a/.github/workflows/auto-pr-description.yml +++ b/.github/workflows/auto-pr-description.yml @@ -22,12 +22,15 @@ jobs: - name: Generate PR description id: gen - uses: riskledger/generate-pull-request-description@v1 + uses: octue/generate-pull-request-description@1.0.0.beta-2 + with: + pull_request_url: ${{ github.event.pull_request.html_url }} + api_token: ${{ secrets.GITHUB_TOKEN }} - name: Force overwrite PR title and body uses: actions/github-script@v7 env: - PR_BODY: ${{ steps.gen.outputs.description }} + PR_BODY: ${{ steps.gen.outputs.pull_request_description }} with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | From 515509cf078417352514d4bdab56061f05705658 Mon Sep 17 00:00:00 2001 From: Dmitrii Safronov Date: Sat, 6 Dec 2025 04:49:05 +0400 Subject: [PATCH 53/53] ci: update PR description generation action to stable version - Changed the action used for generating pull request descriptions from `octue/generate-pull-request-description@1.0.0.beta-2` to `tanmay-pathak/generate-pull-request-description@v1.0.0`. - Updated the input variable for the pull request URL to use the more direct `github.event.pull_request.url`. Signed-off-by: Dmitrii Safronov --- .github/workflows/auto-pr-description.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/auto-pr-description.yml b/.github/workflows/auto-pr-description.yml index 88c1522..2cd8f26 100644 --- a/.github/workflows/auto-pr-description.yml +++ b/.github/workflows/auto-pr-description.yml @@ -22,9 +22,9 @@ jobs: - name: Generate PR description id: gen - uses: octue/generate-pull-request-description@1.0.0.beta-2 + uses: tanmay-pathak/generate-pull-request-description@v1.0.0 with: - pull_request_url: ${{ github.event.pull_request.html_url }} + pull_request_url: ${{ github.event.pull_request.url }} api_token: ${{ secrets.GITHUB_TOKEN }} - name: Force overwrite PR title and body