test: add quality-depth gates and mature CPU coverage

This commit is contained in:
Joseph Magly
2026-08-14 14:08:23 -04:00
parent b80c1a1694
commit 951700a285
21 changed files with 1986 additions and 80 deletions
+71
View File
@@ -200,6 +200,9 @@ jobs:
run: >-
python -m ruff check --select F app.py obliteratus tests
scripts/check_coverage_thresholds.py
scripts/check_mutation_score.py
scripts/check_quality_policy.py
scripts/run_repeat_gate.py
scripts/check_supply_chain_policy.py
scripts/gemma4_12b_recursive_loop.py
@@ -208,6 +211,9 @@ jobs:
run: >-
python -m ruff check --select E501 --statistics app.py obliteratus tests
scripts/check_coverage_thresholds.py
scripts/check_mutation_score.py
scripts/check_quality_policy.py
scripts/run_repeat_gate.py
scripts/check_supply_chain_policy.py
scripts/gemma4_12b_recursive_loop.py || true
@@ -297,6 +303,12 @@ jobs:
--min-changed 90
--base-ref "$COVERAGE_BASE"
- name: Enforce mature CPU-scope coverage and immutable quality policy
run: >-
"$TEST_ENV/bin/python" scripts/check_quality_policy.py
--policy ci/test-quality-policy.json
--coverage "test-results/coverage-py${{ matrix.python-version }}.json"
- name: Upload test and coverage evidence
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
@@ -306,6 +318,65 @@ jobs:
if-no-files-found: error
retention-days: 14
quality-depth:
name: Quality depth
runs-on: ubuntu-latest
timeout-minutes: 20
env:
CUDA_VISIBLE_DEVICES: ""
HF_DATASETS_OFFLINE: "1"
HF_HUB_DISABLE_TELEMETRY: "1"
HF_HUB_OFFLINE: "1"
TOKENIZERS_PARALLELISM: "false"
TRANSFORMERS_OFFLINE: "1"
QUALITY_ENV: /tmp/obliteratus-quality-env
steps:
- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Set up Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.12"
cache: pip
cache-dependency-path: |
pyproject.toml
uv.lock
- name: Install locked quality tooling
run: |
python -m pip install "uv==${UV_VERSION}"
UV_PROJECT_ENVIRONMENT="$QUALITY_ENV" \
uv sync --locked --extra dev --group quality --no-editable
mkdir -p quality-evidence
- name: Run deterministic order and hash-seed repeats
run: >-
"$QUALITY_ENV/bin/python" scripts/run_repeat_gate.py
--output quality-evidence/repeat-gate.json
- name: Run bounded selective mutation gate
run: |
/usr/bin/time -f 'elapsed_seconds=%e\nmax_rss_kb=%M' \
-o quality-evidence/mutation-time.txt \
"$QUALITY_ENV/bin/mutmut" run --max-children 4
"$QUALITY_ENV/bin/mutmut" results > quality-evidence/mutation-survivors.txt
"$QUALITY_ENV/bin/mutmut" export-cicd-stats
cp mutants/mutmut-cicd-stats.json quality-evidence/mutation-stats.json
cp mutants/mutmut-stats.json quality-evidence/mutation-test-selection.json
"$QUALITY_ENV/bin/python" scripts/check_mutation_score.py \
quality-evidence/mutation-stats.json --minimum 70
- name: Upload quality-depth evidence
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: quality-depth-py3.12
path: quality-evidence/
if-no-files-found: error
retention-days: 14
supply-chain:
name: Supply chain
runs-on: ubuntu-latest
+1
View File
@@ -85,3 +85,4 @@ docs/EFFICIENCY_AUDIT.md
coverage.xml
htmlcov/
test-results/
mutants/
+24 -3
View File
@@ -37,15 +37,36 @@ The mandatory gate currently requires at least 60% repository statement coverage
coverage in the device, loader, architecture-profile, CLI, simulated MLX,
evaluation-metric, reporting, community-contribution, and telemetry boundary
modules. New changes should raise these floors rather than consume the existing
margin.
margin. A separately measured mature CPU-only scope must remain at or above 80%
statement and 75% branch coverage; its environment-bound exclusions and their
conditional-test ownership are versioned in `ci/test-quality-policy.json`.
The quality-depth job repeats the highest-consequence pure tests three times in
different file orders and with different deterministic hash seeds. It also runs
selective mutation testing over configuration parsing and the coverage-policy
gate. The initial mutation floor is 70%. Run these checks locally with:
```bash
uv sync --locked --extra dev --group quality
python scripts/run_repeat_gate.py --output test-results/repeat-gate.json
mutmut run --max-children 4
mutmut export-cicd-stats
python scripts/check_mutation_score.py mutants/mutmut-cicd-stats.json --minimum 70
```
On the calibration runner, the repeat gate took approximately 23 seconds and
the 141-mutant selection took approximately 11 seconds after environment setup.
CI retains repeat timing/output, mutation timing, test selection, score, and
survivor evidence for 14 days. Thresholds may move downward only through a
time-bounded exception linked to a reviewed repository issue.
## Code Style
We use [ruff](https://docs.astral.sh/ruff/) for linting and formatting:
```bash
python -m ruff check --select F obliteratus tests scripts/gemma4_12b_recursive_loop.py
python -m ruff check --select E501 --statistics obliteratus tests scripts/gemma4_12b_recursive_loop.py # known non-blocking line-length debt report
python -m ruff check --select F app.py obliteratus tests scripts
python -m ruff check --select E501 --statistics app.py obliteratus tests scripts # known non-blocking line-length debt report
```
- Line length: 100 characters
+5 -2
View File
@@ -756,13 +756,16 @@ pip install -e ".[dev]"
pytest
```
The mandatory CPU suite currently contains 1,001 tests across 44 test files,
The mandatory CPU suite currently contains 1,123 tests across 52 test files,
including a repository-owned synthetic model that exercises the offline pipeline,
installed-wheel CLI, study runner, transactional checkpoint recovery, and resumable
auto-obliteration state. The suite also covers model/device/quantization/MLX
boundaries, all analysis modules, architecture detection, visualization sanitization,
community contributions, edge cases, and evaluation metrics. CI enforces at least
60% statement coverage, 42% branch coverage, and 90% changed-line coverage.
60% repository statement coverage, 42% repository branch coverage, 90%
changed-line coverage, and 80% statement / 75% branch coverage for the documented
mature CPU-only scope. Deterministic property, order-repeat, and selective mutation
gates provide additional depth for numerical and policy-critical behavior.
## License
+144
View File
@@ -0,0 +1,144 @@
{
"schema_version": 1,
"minimums": {
"repository_statement": 60.0,
"repository_branch": 42.0,
"changed_line": 90.0,
"mature_cpu_statement": 80.0,
"mature_cpu_branch": 75.0,
"mutation_score": 70.0,
"warning_budget": 0
},
"mature_cpu_scope": {
"description": "All source modules except boundaries that intrinsically require a real model runtime, an external service, an interactive UI, or remote/hardware execution.",
"exclusions": [
{
"path": "obliteratus/abliterate.py",
"boundary": "model-runtime",
"rationale": "Uncovered paths load, mutate, generate with, or save real transformer architectures and accelerator-specific weights.",
"conditional_issue": "https://github.com/elder-plinius/OBLITERATUS/issues/71",
"conditional_gate": "model-download-runtime"
},
{
"path": "obliteratus/auto_obliterate.py",
"boundary": "model-runtime",
"rationale": "The remaining loop performs repeated model mutation, generation, benchmarking, and checkpoint persistence.",
"conditional_issue": "https://github.com/elder-plinius/OBLITERATUS/issues/71",
"conditional_gate": "model-download-runtime"
},
{
"path": "obliteratus/bayesian_optimizer.py",
"boundary": "model-runtime",
"rationale": "Optimization trials require optional Optuna plus repeated mutation and inference on a loaded transformer model.",
"conditional_issue": "https://github.com/elder-plinius/OBLITERATUS/issues/71",
"conditional_gate": "model-download-runtime"
},
{
"path": "obliteratus/bestiary_sync.py",
"boundary": "network-service",
"rationale": "This adapter reads the external BESTIARY catalog over HTTP or from an operator-provided service artifact.",
"conditional_issue": "https://github.com/elder-plinius/OBLITERATUS/issues/71",
"conditional_gate": "network-services"
},
{
"path": "obliteratus/evaluation/baselines.py",
"boundary": "model-runtime",
"rationale": "Control baselines mutate and repeatedly evaluate a live transformer pipeline.",
"conditional_issue": "https://github.com/elder-plinius/OBLITERATUS/issues/71",
"conditional_gate": "model-download-runtime"
},
{
"path": "obliteratus/evaluation/evaluator.py",
"boundary": "model-runtime",
"rationale": "The remaining branches tokenize datasets and execute causal-LM or classifier forward passes.",
"conditional_issue": "https://github.com/elder-plinius/OBLITERATUS/issues/71",
"conditional_gate": "model-download-runtime"
},
{
"path": "obliteratus/evaluation/heretic_eval.py",
"boundary": "external-evaluator",
"rationale": "Publication evaluation depends on downloaded benchmark data, classifiers, live models, and lm-eval.",
"conditional_issue": "https://github.com/elder-plinius/OBLITERATUS/issues/71",
"conditional_gate": "external-evaluation"
},
{
"path": "obliteratus/evaluation/lm_eval_integration.py",
"boundary": "external-evaluator",
"rationale": "This optional adapter requires lm-evaluation-harness, benchmark downloads, and a model runtime.",
"conditional_issue": "https://github.com/elder-plinius/OBLITERATUS/issues/71",
"conditional_gate": "external-evaluation"
},
{
"path": "obliteratus/informed_pipeline.py",
"boundary": "model-runtime",
"rationale": "The uncovered orchestration stages load a model, collect activations, mutate weights, generate, and save.",
"conditional_issue": "https://github.com/elder-plinius/OBLITERATUS/issues/71",
"conditional_gate": "model-download-runtime"
},
{
"path": "obliteratus/interactive.py",
"boundary": "interactive-ui",
"rationale": "Rich prompt flows require an interactive terminal and operator responses.",
"conditional_issue": "https://github.com/elder-plinius/OBLITERATUS/issues/71",
"conditional_gate": "operator-ui"
},
{
"path": "obliteratus/local_ui.py",
"boundary": "interactive-ui",
"rationale": "Browser, port, authentication, Gradio launch, and signal behavior require an operator UI environment.",
"conditional_issue": "https://github.com/elder-plinius/OBLITERATUS/issues/71",
"conditional_gate": "operator-ui"
},
{
"path": "obliteratus/lora_ablation.py",
"boundary": "model-runtime",
"rationale": "Adapter construction and validation require real transformer projections and optional PEFT integration.",
"conditional_issue": "https://github.com/elder-plinius/OBLITERATUS/issues/71",
"conditional_gate": "model-download-runtime"
},
{
"path": "obliteratus/models_client.py",
"boundary": "network-service",
"rationale": "Catalog resolution depends on operator paths or a BESTIARY HTTP endpoint.",
"conditional_issue": "https://github.com/elder-plinius/OBLITERATUS/issues/71",
"conditional_gate": "network-services"
},
{
"path": "obliteratus/remote.py",
"boundary": "remote-execution",
"rationale": "SSH discovery, transfer, execution, cancellation, and result synchronization require a credentialed remote host.",
"conditional_issue": "https://github.com/elder-plinius/OBLITERATUS/issues/71",
"conditional_gate": "remote-execution"
},
{
"path": "obliteratus/sweep.py",
"boundary": "model-runtime",
"rationale": "Each sweep point creates and evaluates a live ablation study against a transformer model.",
"conditional_issue": "https://github.com/elder-plinius/OBLITERATUS/issues/71",
"conditional_gate": "model-download-runtime"
},
{
"path": "obliteratus/tourney.py",
"boundary": "model-and-service-runtime",
"rationale": "Tournament rounds load and mutate multiple models, benchmark them, and may publish to Hugging Face Hub.",
"conditional_issue": "https://github.com/elder-plinius/OBLITERATUS/issues/71",
"conditional_gate": "external-evaluation"
},
{
"path": "obliteratus/ui_watchtower.py",
"boundary": "interactive-ui",
"rationale": "The module constructs live Gradio tabs and scheduler controls around service-backed state.",
"conditional_issue": "https://github.com/elder-plinius/OBLITERATUS/issues/71",
"conditional_gate": "operator-ui"
},
{
"path": "obliteratus/watchtower.py",
"boundary": "network-service",
"rationale": "Scanning, scheduling, and queue state depend on live Hugging Face service responses and time-based execution.",
"conditional_issue": "https://github.com/elder-plinius/OBLITERATUS/issues/71",
"conditional_gate": "network-services"
}
]
},
"threshold_exceptions": []
}
+1 -1
View File
@@ -132,7 +132,7 @@ def plot_pareto_frontier(results: list[dict], title_suffix: str = "") -> plt.Fig
_style_ax(ax, f"Capability-Safety Pareto Frontier{title_suffix}",
"Refusal Rate (%)", "Perplexity (lower = better)")
ax.set_xlim(left=-2)
if frontier_x:
if len(frontier_x) > 1:
ax.legend(loc="upper right", fontsize=8)
fig.tight_layout()
return fig
+19
View File
@@ -45,6 +45,7 @@ dependencies = [
[project.optional-dependencies]
dev = [
"build==1.2.2.post1",
"hypothesis==6.165.3",
"mypy==1.13.0",
"pytest==9.1.1",
"pytest-cov==7.1.0",
@@ -58,6 +59,9 @@ ci = [
"pip-licenses==5.5.5",
"twine==7.0.0",
]
quality = [
"mutmut==3.7.0",
]
[project.scripts]
obliteratus = "obliteratus.cli:main"
@@ -104,6 +108,21 @@ markers = [
"remote: tests that require a remote execution provider or credentials",
]
[tool.mutmut]
source_paths = ["obliteratus/", "scripts/"]
only_mutate = [
"obliteratus/config.py",
"scripts/check_coverage_thresholds.py",
]
pytest_add_cli_args = ["--no-cov", "-q"]
pytest_add_cli_args_test_selection = [
"tests/test_config.py",
"tests/test_config_properties.py",
"tests/test_coverage_thresholds.py",
]
mutate_only_covered_lines = true
on_dependency_change = "rerun"
[tool.uv]
constraint-dependencies = ["pillow>=12.2.0"]
exclude-newer = "3 days"
+78
View File
@@ -0,0 +1,78 @@
#!/usr/bin/env python3
"""Validate machine-readable mutmut CI statistics against a score floor."""
from __future__ import annotations
import argparse
import json
import math
from pathlib import Path
from typing import Any
def mutation_score(stats: dict[str, Any]) -> tuple[int, int, float]:
"""Return killed, total, and percentage after validating mutmut statistics."""
killed = stats.get("killed")
total = stats.get("total")
if isinstance(killed, bool) or not isinstance(killed, int) or killed < 0:
raise ValueError("mutation statistics require a non-negative integer 'killed'")
if isinstance(total, bool) or not isinstance(total, int) or total <= 0:
raise ValueError("mutation statistics require a positive integer 'total'")
if killed > total:
raise ValueError("mutation statistics cannot report more killed mutants than total")
return killed, total, killed / total * 100
def validate_mutation_stats(
stats: dict[str, Any], *, minimum: float,
) -> list[str]:
"""Return failures for an incomplete run or a score below the policy floor."""
if not math.isfinite(minimum) or minimum < 0 or minimum > 100:
return ["minimum mutation score must be between 0 and 100"]
try:
killed, total, score = mutation_score(stats)
except ValueError as exc:
return [str(exc)]
failures: list[str] = []
if stats.get("check_was_interrupted_by_user"):
failures.append("mutation run was interrupted")
if score < minimum:
failures.append(
f"mutation score {score:.2f}% ({killed}/{total}) is below "
f"the {minimum:.2f}% floor",
)
return failures
def _parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("stats", type=Path, help="mutmut-cicd-stats.json path")
parser.add_argument("--minimum", type=float, required=True)
return parser
def main() -> int:
args = _parser().parse_args()
try:
stats = json.loads(args.stats.read_text(encoding="utf-8"))
except (OSError, json.JSONDecodeError) as exc:
print(f"mutation gate failed: cannot read statistics: {exc}")
return 1
if not isinstance(stats, dict):
print("mutation gate failed: statistics root must be an object")
return 1
failures = validate_mutation_stats(stats, minimum=args.minimum)
if failures:
for failure in failures:
print(f"mutation gate failed: {failure}")
return 1
killed, total, score = mutation_score(stats)
print(f"mutation gate passed: {score:.2f}% ({killed}/{total})")
return 0
if __name__ == "__main__":
raise SystemExit(main())
+195
View File
@@ -0,0 +1,195 @@
#!/usr/bin/env python3
"""Validate immutable quality floors and mature CPU-scope coverage."""
from __future__ import annotations
import argparse
import json
import math
from pathlib import Path
from typing import Any
BASELINE_FLOORS = {
"repository_statement": 60.0,
"repository_branch": 42.0,
"changed_line": 90.0,
"mature_cpu_statement": 80.0,
"mature_cpu_branch": 75.0,
"mutation_score": 70.0,
"warning_budget": 0.0,
}
def _valid_exception(exceptions: Any, name: str, current: float) -> bool:
if not isinstance(exceptions, list):
return False
for exception in exceptions:
if not isinstance(exception, dict) or exception.get("threshold") != name:
continue
return (
exception.get("new_value") == current
and isinstance(exception.get("reason"), str)
and bool(exception["reason"].strip())
and isinstance(exception.get("approved_issue"), str)
and exception["approved_issue"].startswith(
"https://github.com/elder-plinius/OBLITERATUS/issues/",
)
and isinstance(exception.get("expires"), str)
and bool(exception["expires"].strip())
)
return False
def validate_policy(policy: dict[str, Any]) -> list[str]:
"""Validate policy structure, immutable floors, and exclusion traceability."""
failures: list[str] = []
minimums = policy.get("minimums")
if not isinstance(minimums, dict):
return ["quality policy is missing the minimums object"]
exceptions = policy.get("threshold_exceptions", [])
for name, baseline in BASELINE_FLOORS.items():
value = minimums.get(name)
if (
isinstance(value, bool)
or not isinstance(value, (int, float))
or not math.isfinite(value)
):
failures.append(f"quality policy requires numeric minimum {name}")
elif value < baseline and not _valid_exception(exceptions, name, float(value)):
failures.append(
f"quality minimum {name} cannot move below {baseline:g} "
"without an explicit reviewed exception",
)
scope = policy.get("mature_cpu_scope")
exclusions = scope.get("exclusions") if isinstance(scope, dict) else None
if not isinstance(exclusions, list):
failures.append("quality policy is missing mature_cpu_scope.exclusions")
return failures
paths: set[str] = set()
for index, exclusion in enumerate(exclusions):
label = f"mature CPU exclusion {index}"
if not isinstance(exclusion, dict):
failures.append(f"{label} must be an object")
continue
path = exclusion.get("path")
if not isinstance(path, str) or not path.startswith("obliteratus/"):
failures.append(f"{label} requires an obliteratus source path")
elif path in paths:
failures.append(f"mature CPU exclusion path is duplicated: {path}")
else:
paths.add(path)
for key in ("boundary", "rationale", "conditional_gate"):
if not isinstance(exclusion.get(key), str) or not exclusion[key].strip():
failures.append(f"{label} requires non-empty {key}")
issue = exclusion.get("conditional_issue")
if issue != "https://github.com/elder-plinius/OBLITERATUS/issues/71":
failures.append(f"{label} must link the conditional-test issue #71")
return failures
def measure_mature_cpu_scope(
report: dict[str, Any], policy: dict[str, Any],
) -> tuple[dict[str, float | int], list[str]]:
"""Measure coverage after removing only documented environment boundaries."""
files = report.get("files")
if not isinstance(files, dict):
return {}, ["coverage report is missing the files object"]
exclusions = policy["mature_cpu_scope"]["exclusions"]
excluded_paths = {entry["path"] for entry in exclusions}
missing = sorted(excluded_paths - files.keys())
if missing:
return {}, [f"coverage report is missing excluded source file {path}" for path in missing]
statements = covered_lines = branches = covered_branches = 0
for path, entry in files.items():
if path in excluded_paths or not path.startswith("obliteratus/"):
continue
summary = entry.get("summary") if isinstance(entry, dict) else None
if not isinstance(summary, dict):
return {}, [f"coverage report is missing summary for {path}"]
statements += int(summary.get("num_statements", 0))
covered_lines += int(summary.get("covered_lines", 0))
branches += int(summary.get("num_branches", 0))
covered_branches += int(summary.get("covered_branches", 0))
measurement: dict[str, float | int] = {
"statements": statements,
"covered_lines": covered_lines,
"line_percent": covered_lines / statements * 100 if statements else 100.0,
"branches": branches,
"covered_branches": covered_branches,
"branch_percent": covered_branches / branches * 100 if branches else 100.0,
}
return measurement, []
def validate_mature_cpu_scope(
report: dict[str, Any], policy: dict[str, Any],
) -> tuple[dict[str, float | int], list[str]]:
measurement, failures = measure_mature_cpu_scope(report, policy)
if failures:
return measurement, failures
minimums = policy["minimums"]
for label in ("line", "branch"):
value = float(measurement[f"{label}_percent"])
floor = float(minimums[f"mature_cpu_{'statement' if label == 'line' else 'branch'}"])
if value < floor:
failures.append(
f"mature CPU {label} coverage {value:.2f}% is below the {floor:.2f}% floor",
)
return measurement, failures
def _parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--policy", type=Path, required=True)
parser.add_argument("--coverage", type=Path)
return parser
def main() -> int:
args = _parser().parse_args()
try:
policy = json.loads(args.policy.read_text(encoding="utf-8"))
except (OSError, json.JSONDecodeError) as exc:
print(f"quality policy failed: cannot read policy: {exc}")
return 1
if not isinstance(policy, dict):
print("quality policy failed: policy root must be an object")
return 1
failures = validate_policy(policy)
measurement = None
if args.coverage is not None and not failures:
try:
report = json.loads(args.coverage.read_text(encoding="utf-8"))
except (OSError, json.JSONDecodeError) as exc:
failures.append(f"cannot read coverage report: {exc}")
else:
if not isinstance(report, dict):
failures.append("coverage report root must be an object")
else:
measurement, coverage_failures = validate_mature_cpu_scope(report, policy)
failures.extend(coverage_failures)
if failures:
for failure in failures:
print(f"quality policy failed: {failure}")
return 1
if measurement is None:
print("quality policy passed")
else:
print(
"quality policy passed: mature CPU "
f"line={measurement['line_percent']:.2f}% "
f"branch={measurement['branch_percent']:.2f}%",
)
return 0
if __name__ == "__main__":
raise SystemExit(main())
+111
View File
@@ -0,0 +1,111 @@
#!/usr/bin/env python3
"""Repeat deterministic tests in varied orders and emit timing evidence."""
from __future__ import annotations
import argparse
import json
import os
import subprocess
import sys
import time
from pathlib import Path
from typing import Any, Sequence
DEFAULT_TESTS = (
"tests/test_config.py",
"tests/test_config_properties.py",
"tests/test_coverage_thresholds.py",
"tests/test_property_contracts.py",
"tests/test_advanced_metrics.py",
"tests/test_metrics.py",
)
HASH_SEEDS = ("0", "1", "8675309")
def test_orders(paths: Sequence[str]) -> list[list[str]]:
"""Return stable forward, reverse, and interleaved orders."""
forward = list(paths)
reverse = list(reversed(paths))
interleaved = forward[::2] + forward[1::2]
return [forward, reverse, interleaved]
def run_repeat_gate(
paths: Sequence[str], *, output: Path, python: str = sys.executable,
) -> int:
"""Run three deterministic passes, always writing a JSON evidence record."""
output.parent.mkdir(parents=True, exist_ok=True)
results: list[dict[str, Any]] = []
started = time.monotonic()
exit_code = 0
for index, (order, hash_seed) in enumerate(
zip(test_orders(paths), HASH_SEEDS, strict=True),
start=1,
):
command = [python, "-m", "pytest", "--no-cov", "-q", *order]
environment = os.environ.copy()
environment["PYTHONHASHSEED"] = hash_seed
pass_started = time.monotonic()
completed = subprocess.run(
command,
capture_output=True,
text=True,
env=environment,
check=False,
)
duration = time.monotonic() - pass_started
results.append({
"pass": index,
"python_hash_seed": hash_seed,
"tests": order,
"duration_seconds": round(duration, 3),
"return_code": completed.returncode,
"stdout": completed.stdout[-4000:],
"stderr": completed.stderr[-4000:],
})
if completed.returncode != 0:
exit_code = completed.returncode
break
evidence = {
"schema_version": 1,
"status": "passed" if exit_code == 0 else "failed",
"total_duration_seconds": round(time.monotonic() - started, 3),
"passes": results,
}
output.write_text(json.dumps(evidence, indent=2) + "\n", encoding="utf-8")
if exit_code:
failed = results[-1]
print(
f"repeat gate failed on pass {failed['pass']} "
f"with PYTHONHASHSEED={failed['python_hash_seed']}",
)
if failed["stdout"]:
print(failed["stdout"])
if failed["stderr"]:
print(failed["stderr"], file=sys.stderr)
return exit_code
print(
f"repeat gate passed: {len(results)} orders in "
f"{evidence['total_duration_seconds']:.3f}s",
)
return 0
def _parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("tests", nargs="*", default=list(DEFAULT_TESTS))
parser.add_argument("--output", type=Path, required=True)
return parser
def main() -> int:
args = _parser().parse_args()
return run_repeat_gate(args.tests, output=args.output)
if __name__ == "__main__":
raise SystemExit(main())
+6 -1
View File
@@ -6,7 +6,6 @@ import socket
from unittest.mock import MagicMock
import pytest
import torch
_EXTERNAL_MARKERS = ("network", "download", "remote")
@@ -46,6 +45,8 @@ def mock_model():
- model.config with config.num_hidden_layers = 4
- model.named_parameters() returning fake weight tensors
"""
import torch
model = MagicMock()
# Config with num_hidden_layers
@@ -83,6 +84,8 @@ def mock_tokenizer():
@pytest.fixture
def refusal_direction():
"""A normalized random torch tensor of shape (768,)."""
import torch
t = torch.randn(768)
return t / t.norm()
@@ -90,6 +93,8 @@ def refusal_direction():
@pytest.fixture
def activation_pair():
"""A tuple of (harmful_activations, harmless_activations) as random tensors of shape (10, 768)."""
import torch
harmful_activations = torch.randn(10, 768)
harmless_activations = torch.randn(10, 768)
return (harmful_activations, harmless_activations)
+178
View File
@@ -0,0 +1,178 @@
"""CPU-only behavioral tests for telemetry-driven adaptive defaults."""
from __future__ import annotations
import pytest
from obliteratus import adaptive_defaults as adaptive
def _record(
method="advanced", *, architecture="LlamaForCausalLM", params_b=7,
refusal=0.1, coherence=0.9, config=None, session="session",
):
return {
"session_id": session,
"timestamp": session,
"model": {
"architecture": architecture,
"num_layers": 32,
"hidden_size": 4096,
"total_params": int(params_b * 1e9),
},
"method": method,
"method_config": (
config if config is not None else {"strength": 1.0, "cot_aware": False}
),
"quality_metrics": {
"refusal_rate": refusal,
"coherence": coherence,
"kl_divergence": 0.1,
"perplexity": 10.0,
},
}
@pytest.mark.parametrize(
("params", "expected"),
[(-1, "tiny"), (0.5, "tiny"), (4, "small"), (16, "medium"), (80, "large"), (81, "frontier")],
)
def test_parameter_buckets_have_closed_boundaries(params, expected):
assert adaptive._param_bucket(params) == expected
def test_architecture_key_handles_schema_estimates_moe_and_reasoning():
assert adaptive._extract_arch_key({"model": "legacy"}) is None
assert adaptive._extract_arch_key({"model": {"architecture": "unknown"}}) is None
assert adaptive._extract_arch_key(_record()) == (
"dense", "standard", "medium",
)
record = _record(architecture="Qwen3_MoE_Reasoning", params_b=120)
assert adaptive._extract_arch_key(record) == ("large_moe", "reasoning", "frontier")
record = _record(params_b=8)
record["model"]["total_params"] = 0
record["method_config"] = {"per_expert_directions": True, "cot_aware": True}
assert adaptive._extract_arch_key(record) == ("small_moe", "reasoning", "medium")
def test_composite_score_defaults_and_complete_metrics():
assert adaptive._composite_score({}) == pytest.approx(0.15)
assert adaptive._composite_score({
"refusal_rate": 0.0,
"coherence": 1.0,
"kl_divergence": 0.0,
"perplexity": 0.0,
}) == pytest.approx(1.0)
def test_method_statistics_ranges_and_bucket_ranking():
empty = adaptive.MethodStats("empty")
assert (empty.mean_score, empty.best_score, empty.median_score) == (0, 0, 0)
assert empty.best_config_ranges() == {}
stats = adaptive.MethodStats(
"strong",
n_runs=4,
scores=[0.1, 0.9, 0.8, 0.7],
configs=[
{"strength": 1, "enabled": False, "label": "skip"},
{"strength": 4, "enabled": True},
{"strength": 3, "enabled": True},
{"strength": 2, "enabled": False},
],
)
assert stats.best_config_ranges() == {"strength": 4, "enabled": True}
bucket = adaptive.BucketKnowledge(
("dense", "standard", "small"),
methods={"empty": empty, "strong": stats},
total_runs=4,
)
assert bucket.best_method == "strong"
assert bucket.ranked_methods[0][0] == "strong"
assert adaptive.BucketKnowledge(("dense", "standard", "tiny")).best_method is None
def test_build_knowledge_base_filters_invalid_runs_and_aggregates_metrics():
records = [
_record(session="one"),
_record(method="basic", refusal=0.4, coherence=0.5, config={}, session="two"),
{**_record(session="error"), "error": "failed"},
{**_record(session="no-method"), "method": ""},
{**_record(session="no-metrics"), "quality_metrics": {}},
{**_record(session="legacy"), "model": "legacy"},
]
knowledge = adaptive.build_knowledge_base(records)
bucket = knowledge[("dense", "standard", "medium")]
assert bucket.total_runs == 2
assert bucket.methods["advanced"].n_runs == 1
assert bucket.methods["advanced"].refusal_rates == [0.1]
assert bucket.methods["basic"].configs == []
def test_fetch_records_caches_deduplicates_and_tolerates_sources(monkeypatch):
adaptive._cache.clear()
monkeypatch.setattr(adaptive, "_cache_ts", 0.0)
import obliteratus.telemetry as telemetry
monkeypatch.setattr(telemetry, "read_telemetry", lambda: [_record(session="same")])
monkeypatch.setattr(
telemetry,
"fetch_hub_records",
lambda: [_record(session="same"), _record(session="other")],
)
first = adaptive._fetch_all_records()
assert len(first) == 2
monkeypatch.setattr(telemetry, "read_telemetry", lambda: (_ for _ in ()).throw(RuntimeError()))
assert adaptive._fetch_all_records() is first
adaptive._cache.clear()
monkeypatch.setattr(adaptive, "_cache_ts", 0.0)
monkeypatch.setattr(telemetry, "fetch_hub_records", lambda: (_ for _ in ()).throw(RuntimeError()))
assert adaptive._fetch_all_records() == []
def test_recommendation_exact_fallback_confidence_and_formatting():
records = [
_record("advanced", refusal=0.05, coherence=0.95, session=f"a-{index}")
for index in range(5)
] + [
_record("basic", refusal=0.5, coherence=0.4, session=f"b-{index}")
for index in range(5)
]
knowledge = adaptive.build_knowledge_base(records)
rec = adaptive.get_adaptive_recommendation("dense", "standard", 7, knowledge=knowledge)
assert rec.recommended_method == "advanced"
assert rec.confidence == "medium"
assert rec.best_refusal_rate == 0.05
assert "Runner-up" in rec.reason
assert rec.to_dict()["arch_key"] == ["dense", "standard", "medium"]
formatted = adaptive.format_recommendation(rec)
assert "Adaptive Recommendation" in formatted
assert "strength" in formatted
sparse_knowledge = adaptive.build_knowledge_base([
_record("advanced", params_b=1, session="small"),
_record("advanced", params_b=30, session="large"),
])
fallback = adaptive.get_adaptive_recommendation(
"dense", "reasoning", 7, knowledge=sparse_knowledge,
)
assert fallback.confidence == "low"
assert fallback.arch_key == ("dense", "*", "*")
none = adaptive.get_adaptive_recommendation("small_moe", "standard", 7, knowledge={})
assert none.confidence == "none"
assert "No telemetry data" in adaptive.format_recommendation(none)
def test_global_insights_reports_rankings_buckets_and_hyperparameters():
knowledge = adaptive.build_knowledge_base([
_record("advanced", config={"strength": 1.5, "enabled": True}, session="one"),
_record("basic", config={"strength": 0.5, "enabled": False}, session="two"),
])
insights = adaptive.get_global_insights(knowledge)
assert insights["total_records"] == 2
assert insights["overall_best_methods"][0]["method"] == "advanced"
assert insights["hyperparameter_trends"]["strength"]["type"] == "numeric"
assert insights["hyperparameter_trends"]["enabled"]["type"] == "bool"
+108
View File
@@ -0,0 +1,108 @@
"""CPU-only contracts for benchmark visualization generation."""
from __future__ import annotations
import matplotlib.pyplot as plt
import pytest
from obliteratus.evaluation import benchmark_plots as plots
@pytest.fixture
def results():
return [
{
"method": "advanced",
"model": "org/model-a",
"model_short": "model-a",
"perplexity": 10.0,
"refusal_rate": 0.1,
"coherence": 0.9,
"time_s": 2.0,
"strong_layers": 3,
"ega_expert_dirs": 2,
"cot_preserved": 1,
"expert_classified_layers": 4,
},
{
"method": "unknown/hf_secret123456",
"model": "org/model-b",
"perplexity": 12.0,
"refusal_rate": 0.2,
"coherence": 0.8,
"time_s": 3.0,
"strong_layers": 0,
"ega_expert_dirs": 0,
"cot_preserved": 0,
"ega_safety_layers": 0,
},
]
def test_label_sanitization_and_palette_fallback():
label = plots._sanitize_label(
"/private/path/model hf_secret123456 0123456789abcdef0123456789abcdef", max_len=40,
)
assert "/private/path" not in label
assert "hf_secret" not in label
assert label == "model <TOKEN> <REDACTED>"
assert plots._get_color("basic") == plots.PALETTE["basic"]
assert plots._get_color("custom", 9) == plots.MODEL_PALETTE[1]
@pytest.mark.parametrize(
"factory",
[
plots.plot_pareto_frontier,
plots.plot_method_radar,
plots.plot_metric_bars,
plots.plot_timing_efficiency,
plots.plot_moe_metrics,
plots.plot_model_scaling,
],
)
def test_each_plot_returns_a_figure_for_empty_input(factory):
figure = factory([])
assert isinstance(figure, plt.Figure)
plt.close(figure)
@pytest.mark.parametrize(
"factory",
[
plots.plot_pareto_frontier,
plots.plot_method_radar,
plots.plot_metric_bars,
plots.plot_timing_efficiency,
plots.plot_moe_metrics,
plots.plot_model_scaling,
],
)
def test_each_plot_renders_synthetic_results(factory, results):
figure = factory(results, " — fixture")
assert isinstance(figure, plt.Figure)
assert figure.axes
plt.close(figure)
def test_pareto_handles_single_point_without_frontier_line(results):
figure = plots.plot_pareto_frontier(results[:1])
assert isinstance(figure, plt.Figure)
plt.close(figure)
def test_moe_plot_handles_non_moe_results(results):
figure = plots.plot_moe_metrics(results[1:])
assert "No MoE-specific features" in figure.axes[0].texts[0].get_text()
plt.close(figure)
def test_dashboard_modes_and_optional_moe_panel(results):
assert plots.generate_benchmark_dashboard([]) == []
method_figures = plots.generate_benchmark_dashboard(results, mode="multi_method")
model_figures = plots.generate_benchmark_dashboard(results, mode="multi_model")
assert len(method_figures) == 5
assert len(model_figures) == 5
assert plots.generate_benchmark_dashboard(results, mode="unsupported") == []
for figure in method_figures + model_figures:
plt.close(figure)
+38
View File
@@ -0,0 +1,38 @@
"""Deterministic property contracts for configuration serialization."""
from __future__ import annotations
from hypothesis import given, seed, settings, strategies as st
from obliteratus.config import StudyConfig
PROPERTY_SETTINGS = settings(max_examples=60, deadline=None, database=None)
@seed(7007)
@PROPERTY_SETTINGS
@given(
batch_size=st.integers(1, 32),
max_length=st.integers(2, 4096),
strategy_names=st.lists(
st.text(alphabet="abcdefghijklmnopqrstuvwxyz_", min_size=1, max_size=16),
min_size=1,
max_size=8,
),
)
def test_study_config_public_roundtrip_preserves_explicit_values(
batch_size, max_length, strategy_names,
):
raw = {
"model": {"name": "fixture", "device": "cpu"},
"dataset": {"name": "fixture", "max_samples": 12},
"strategies": [{"name": name, "params": {"strength": 0.5}} for name in strategy_names],
"metrics": ["perplexity", "accuracy"],
"batch_size": batch_size,
"max_length": max_length,
"output_dir": "results/property",
}
config = StudyConfig.from_dict(raw)
restored = StudyConfig.from_dict(config.to_dict())
assert restored == config
+63 -9
View File
@@ -2,15 +2,7 @@
from __future__ import annotations
import importlib.util
from pathlib import Path
SCRIPT = Path(__file__).parents[1] / "scripts" / "check_coverage_thresholds.py"
SPEC = importlib.util.spec_from_file_location("check_coverage_thresholds", SCRIPT)
assert SPEC is not None and SPEC.loader is not None
MODULE = importlib.util.module_from_spec(SPEC)
SPEC.loader.exec_module(MODULE)
from scripts import check_coverage_thresholds as MODULE
def _report(line: float = 55.0, branch: float = 42.0) -> dict[str, object]:
@@ -86,6 +78,30 @@ def test_validate_coverage_enforces_critical_file_floors():
]
def test_critical_file_validation_continues_and_rejects_malformed_values():
report = _report()
report["files"]["bool.py"] = {
"summary": {"percent_statements_covered": True},
}
report["files"]["text.py"] = {
"summary": {"percent_statements_covered": "70"},
}
assert MODULE.validate_coverage(
report,
min_line=55.0,
min_branch=42.0,
file_floors={
"missing.py": 70.0,
"bool.py": 70.0,
"text.py": 70.0,
},
) == [
"coverage report is missing critical file missing.py",
"coverage report is missing numeric line coverage for bool.py",
"coverage report is missing numeric line coverage for text.py",
]
def test_parse_changed_lines_and_measurement_ignore_non_executable_lines():
diff = """diff --git a/obliteratus/example.py b/obliteratus/example.py
+++ b/obliteratus/example.py
@@ -111,3 +127,41 @@ def test_changed_line_gate_passes_when_diff_has_no_measured_source():
0,
100.0,
)
def test_changed_line_parser_ignores_hunks_before_paths_and_defaults_count_to_one():
diff = """@@ -1 +99 @@
+++ b/obliteratus/example.py
@@ -2 +3 @@
"""
assert MODULE.parse_changed_lines(diff) == {"obliteratus/example.py": {3}}
def test_changed_line_measurement_handles_missing_fields_and_multiple_files():
report = {
"files": {
"obliteratus/no-fields.py": {"summary": {}},
"obliteratus/first.py": {
"executed_lines": [1],
"missing_lines": [2],
},
"obliteratus/second.py": {
"executed_lines": [4],
"missing_lines": [5],
},
},
}
changed = {
"missing-entry.py": {1},
"obliteratus/no-fields.py": {1},
"obliteratus/first.py": {1, 2, 99},
"obliteratus/second.py": {4, 5, 100},
}
assert MODULE.changed_line_coverage(report, changed) == (2, 4, 50.0)
def test_changed_line_gate_accepts_exact_floor():
changed = {"obliteratus/example.py": {1, 2, 3, 4}}
assert MODULE.validate_changed_coverage(
_report(), changed, minimum=75.0,
) == []
+99
View File
@@ -0,0 +1,99 @@
"""Numerical and error-path tests for Fisher/LEACE direction extraction."""
from __future__ import annotations
import pytest
import torch
from obliteratus.analysis.leace import LEACEExtractor
def _activations():
harmful = [
torch.tensor([2.0, 0.0, 1.0]),
torch.tensor([3.0, 1.0, 0.0]),
torch.tensor([4.0, -1.0, 1.0]),
]
harmless = [
torch.tensor([-2.0, 0.0, 1.0]),
torch.tensor([-3.0, 1.0, 0.0]),
torch.tensor([-4.0, -1.0, 1.0]),
]
return harmful, harmless
def test_extract_returns_normalized_reproducible_diagnostics():
harmful, harmless = _activations()
result = LEACEExtractor().extract(harmful, harmless, layer_idx=7)
assert result.layer_idx == 7
assert result.direction.norm().item() == pytest.approx(1.0)
assert result.direction[0].abs().item() > 0.99
assert result.generalized_eigenvalue > 0
assert result.mean_diff_norm == pytest.approx(6.0)
assert result.erasure_loss > 0
assert result.within_class_condition >= 1
def test_extract_accepts_singleton_sequence_axis_and_shrinkage():
harmful, harmless = _activations()
harmful_3d = [value.unsqueeze(0) for value in harmful]
harmless_3d = [value.unsqueeze(0) for value in harmless]
result = LEACEExtractor(shrinkage=0.5).extract(harmful_3d, harmless_3d)
assert result.direction.shape == (3,)
assert torch.isfinite(result.direction).all()
def test_degenerate_classes_return_zero_direction():
samples = [torch.ones(3), torch.ones(3)]
result = LEACEExtractor().extract(samples, samples)
assert torch.equal(result.direction, torch.zeros(3))
assert result.generalized_eigenvalue == 0
def test_solver_failure_uses_least_squares(monkeypatch):
harmful, harmless = _activations()
def fail_solve(*_args, **_kwargs):
raise torch.linalg.LinAlgError("fixture")
monkeypatch.setattr(torch.linalg, "solve", fail_solve)
result = LEACEExtractor().extract(harmful, harmless)
assert result.direction.norm().item() == pytest.approx(1.0)
def test_condition_failure_is_reported_as_infinite(monkeypatch):
harmful, harmless = _activations()
original_solve = torch.linalg.solve
monkeypatch.setattr(
torch.linalg,
"eigvalsh",
lambda *_args, **_kwargs: (_ for _ in ()).throw(RuntimeError("fixture")),
)
monkeypatch.setattr(torch.linalg, "solve", original_solve)
result = LEACEExtractor().extract(harmful, harmless)
assert result.within_class_condition == float("inf")
def test_extract_all_layers_skips_unpaired_layers_and_sorts():
harmful, harmless = _activations()
results = LEACEExtractor().extract_all_layers(
{2: harmful, 1: harmful, 3: harmful},
{1: harmless, 2: harmless},
)
assert list(results) == [1, 2]
assert results[1].layer_idx == 1
def test_compare_with_diff_of_means_handles_regular_and_degenerate_difference():
harmful, harmless = _activations()
result = LEACEExtractor().extract(harmful, harmless)
comparison = LEACEExtractor.compare_with_diff_of_means(
result,
torch.stack(harmful).mean(0),
torch.stack(harmless).mean(0),
)
assert comparison["cosine_similarity"] == pytest.approx(1.0)
degenerate = LEACEExtractor.compare_with_diff_of_means(
result, torch.zeros(3), torch.zeros(3),
)
assert degenerate["cosine_similarity"] == 0
+128
View File
@@ -0,0 +1,128 @@
"""Offline tests for prompt registry parsing and external schema boundaries."""
from __future__ import annotations
import sys
from types import SimpleNamespace
import pytest
from obliteratus import prompts
@pytest.fixture(autouse=True)
def clean_cache():
prompts.clear_dataset_cache()
yield
prompts.clear_dataset_cache()
def _datasets(monkeypatch, rows_or_error):
def load_dataset(*_args, **_kwargs):
if isinstance(rows_or_error, Exception):
raise rows_or_error
return rows_or_error
monkeypatch.setitem(sys.modules, "datasets", SimpleNamespace(load_dataset=load_dataset))
def test_cache_copies_results_and_builtin_loader_isolated():
calls = []
def loader():
calls.append(True)
return ["harm"], ["safe"]
first = prompts._cached_load("fixture", loader)
first[0].append("mutation")
assert prompts._cached_load("fixture", loader) == (["harm"], ["safe"])
assert len(calls) == 1
harmful, harmless = prompts._load_builtin()
assert len(harmful) == len(harmless) == 842
@pytest.mark.parametrize(
("loader", "rows", "expected"),
[
(prompts._load_harmbench, [{"Behavior": "A sufficiently long behavior"}], "A sufficiently long behavior"),
(prompts._load_advbench, [{"goal": "A sufficiently long goal prompt"}], "A sufficiently long goal prompt"),
],
)
def test_single_column_external_sources(monkeypatch, loader, rows, expected):
_datasets(monkeypatch, rows)
harmful, harmless = loader()
assert harmful == [expected]
assert len(harmless) == 1
def test_anthropic_parser_deduplicates_and_uses_fallback(monkeypatch):
calls = []
def load_dataset(*_args, **kwargs):
calls.append(kwargs)
if "data_dir" in kwargs:
raise RuntimeError("primary unavailable")
return [
{"chosen": "Human: A unique and sufficiently long prompt Assistant: response"},
{"rejected": "Human: A unique and sufficiently long prompt Assistant: other"},
{"chosen": "no conversation markers"},
]
monkeypatch.setitem(sys.modules, "datasets", SimpleNamespace(load_dataset=load_dataset))
harmful, harmless = prompts._load_anthropic_redteam()
assert harmful == ["A unique and sufficiently long prompt"]
assert len(harmless) == 1
assert len(calls) == 2
def test_wildjailbreak_requires_pairs_and_deduplicates(monkeypatch):
_datasets(monkeypatch, [
{"adversarial_query": "A sufficiently long adversarial prompt", "vanilla_query": "safe"},
{"adversarial": "A sufficiently long adversarial prompt", "vanilla": "duplicate"},
{"adversarial": "missing pair"},
])
harmful, harmless = prompts._load_wildjailbreak()
assert harmful == ["A sufficiently long adversarial prompt"]
assert harmless == ["safe"]
@pytest.mark.parametrize(
"loader",
[prompts._load_harmbench, prompts._load_advbench, prompts._load_wildjailbreak],
)
def test_external_loaders_explain_empty_schemas(monkeypatch, loader):
_datasets(monkeypatch, [{"unexpected": "value"}])
with pytest.raises(RuntimeError, match="0 prompts extracted"):
loader()
def test_anthropic_empty_parse_is_rejected(monkeypatch):
_datasets(monkeypatch, [{"chosen": "not a conversation"}])
with pytest.raises(RuntimeError, match="0 prompts extracted"):
prompts._load_anthropic_redteam()
def test_custom_prompt_validation_padding_and_registry_access():
harmful_text = "\n".join(f"harm {index}" for index in range(5))
with pytest.raises(ValueError, match="at least 5"):
prompts.load_custom_prompts("only one", "safe")
harmful, harmless = prompts.load_custom_prompts(harmful_text, "")
assert len(harmful) == len(harmless) == 5
harmful, harmless = prompts.load_custom_prompts(harmful_text, "safe one\nsafe two")
assert harmless[:2] == ["safe one", "safe two"]
assert len(harmless) == 5
with pytest.raises(ValueError, match="Unknown dataset source"):
prompts.load_dataset_source("missing")
assert prompts.get_source_key_from_label("missing label") == "builtin"
assert prompts.get_source_key_from_label(prompts.DATASET_SOURCES["advbench"].label) == "advbench"
assert len(prompts.get_source_choices()) == len(prompts.DATASET_SOURCES)
assert prompts.get_valid_volumes("missing") == ["all (use entire dataset)"]
assert prompts.get_valid_volumes("harmbench")[-1] == "all (use entire dataset)"
def test_harmless_generator_cycles_deterministically():
count = len(prompts._HARMLESS_POOL) + 1
generated = prompts._generate_harmless_counterparts(count)
assert generated[0] == generated[-1]
+124
View File
@@ -0,0 +1,124 @@
"""Deterministic property contracts for high-consequence pure behavior."""
from __future__ import annotations
import pytest
import torch
from hypothesis import given, seed, settings, strategies as st
from obliteratus.evaluation.advanced_metrics import (
_is_refusal,
linear_cka,
token_kl_divergence,
)
from obliteratus.evaluation.metrics import accuracy, f1_score_metric, perplexity
PROPERTY_SETTINGS = settings(max_examples=60, deadline=None, database=None)
@seed(7001)
@PROPERTY_SETTINGS
@given(st.lists(st.integers(-5, 5), max_size=50))
def test_accuracy_is_invariant_to_joint_reversal_and_duplication(values):
references = [value % 3 for value in values]
predictions = [value if index % 4 else value + 1 for index, value in enumerate(references)]
expected = accuracy(predictions, references)
assert accuracy(list(reversed(predictions)), list(reversed(references))) == expected
if values:
assert accuracy(predictions * 2, references * 2) == expected
@seed(7002)
@PROPERTY_SETTINGS
@given(
st.lists(st.integers(0, 4), min_size=1, max_size=50),
st.lists(st.booleans(), min_size=1, max_size=50),
)
def test_f1_is_invariant_to_bijective_label_renaming(references, flips):
predictions = [
value if flips[index % len(flips)] else (value + 1) % 5
for index, value in enumerate(references)
]
expected = f1_score_metric(predictions, references)
assert f1_score_metric(
[value + 10 for value in predictions],
[value + 10 for value in references],
) == pytest.approx(expected)
@seed(7003)
@PROPERTY_SETTINGS
@given(
vocab_size=st.integers(2, 40),
batch_size=st.integers(1, 4),
sequence_length=st.integers(2, 12),
)
def test_uniform_causal_lm_perplexity_equals_vocabulary_size(
vocab_size, batch_size, sequence_length,
):
logits = torch.zeros(batch_size, sequence_length, vocab_size)
labels = torch.arange(batch_size * sequence_length).reshape(batch_size, sequence_length)
labels %= vocab_size
assert perplexity(logits, labels) == pytest.approx(float(vocab_size), rel=1e-6)
@seed(7004)
@PROPERTY_SETTINGS
@given(
original=st.lists(
st.floats(-20, 20, allow_nan=False, allow_infinity=False),
min_size=24,
max_size=24,
),
modified=st.lists(
st.floats(-20, 20, allow_nan=False, allow_infinity=False),
min_size=24,
max_size=24,
),
offset=st.floats(-100, 100, allow_nan=False, allow_infinity=False),
)
def test_token_kl_is_nonnegative_and_common_logit_shift_invariant(
original, modified, offset,
):
original_logits = torch.tensor(original).reshape(2, 3, 4)
modified_logits = torch.tensor(modified).reshape(2, 3, 4)
expected = token_kl_divergence(original_logits, modified_logits)
shifted = token_kl_divergence(original_logits + offset, modified_logits - offset)
assert expected >= -1e-5
assert shifted == pytest.approx(expected, abs=2e-5)
@seed(7005)
@PROPERTY_SETTINGS
@given(
scale=st.floats(
min_value=0.1, max_value=20, allow_nan=False, allow_infinity=False,
),
offset=st.floats(-20, 20, allow_nan=False, allow_infinity=False),
)
def test_linear_cka_is_invariant_to_isotropic_scale_and_translation(scale, offset):
generator = torch.Generator().manual_seed(7005)
representation = torch.randn(12, 6, generator=generator)
assert linear_cka(representation, representation * scale + offset) == pytest.approx(
1.0, abs=1e-5,
)
@seed(7006)
@PROPERTY_SETTINGS
@given(
refusal=st.sampled_from([
"I'm sorry, I cannot help with that.",
"I must decline this request.",
"Je ne peux pas vous aider.",
"我无法帮助这个请求。",
]),
leading_space=st.integers(0, 8),
upper=st.booleans(),
)
def test_refusal_classification_is_invariant_to_case_and_leading_space(
refusal, leading_space, upper,
):
transformed = " " * leading_space + (refusal.upper() if upper else refusal.lower())
assert _is_refusal(transformed, mode="combined")
+70
View File
@@ -0,0 +1,70 @@
"""Unit tests for quality-depth gate helpers."""
from __future__ import annotations
import json
from types import SimpleNamespace
from scripts import check_mutation_score
from scripts import run_repeat_gate
def test_mutation_score_accepts_exact_floor_and_rejects_regression():
stats = {"killed": 70, "total": 100, "check_was_interrupted_by_user": 0}
assert check_mutation_score.validate_mutation_stats(stats, minimum=70) == []
assert check_mutation_score.validate_mutation_stats(stats, minimum=70.01) == [
"mutation score 70.00% (70/100) is below the 70.01% floor",
]
def test_mutation_score_rejects_malformed_and_interrupted_runs():
assert check_mutation_score.validate_mutation_stats(
{"killed": True, "total": 1}, minimum=70,
) == ["mutation statistics require a non-negative integer 'killed'"]
assert check_mutation_score.validate_mutation_stats(
{"killed": 1, "total": 1, "check_was_interrupted_by_user": 1}, minimum=70,
) == ["mutation run was interrupted"]
def test_repeat_orders_are_distinct_and_deterministic():
paths = ["a", "b", "c", "d"]
assert run_repeat_gate.test_orders(paths) == [
["a", "b", "c", "d"],
["d", "c", "b", "a"],
["a", "c", "b", "d"],
]
def test_repeat_gate_records_each_pass(monkeypatch, tmp_path):
calls = []
def fake_run(command, **kwargs):
calls.append((command, kwargs["env"]["PYTHONHASHSEED"]))
return SimpleNamespace(returncode=0, stdout="2 passed\n", stderr="")
monkeypatch.setattr(run_repeat_gate.subprocess, "run", fake_run)
output = tmp_path / "repeat.json"
assert run_repeat_gate.run_repeat_gate(
["first.py", "second.py"], output=output, python="python-fixture",
) == 0
evidence = json.loads(output.read_text())
assert evidence["status"] == "passed"
assert [entry["python_hash_seed"] for entry in evidence["passes"]] == [
"0", "1", "8675309",
]
assert calls[0][0] == [
"python-fixture", "-m", "pytest", "--no-cov", "-q", "first.py", "second.py",
]
def test_repeat_gate_stops_and_preserves_failure_output(monkeypatch, tmp_path):
def fake_run(*_args, **_kwargs):
return SimpleNamespace(returncode=3, stdout="failed output", stderr="failure detail")
monkeypatch.setattr(run_repeat_gate.subprocess, "run", fake_run)
output = tmp_path / "repeat.json"
assert run_repeat_gate.run_repeat_gate(["test.py"], output=output) == 3
evidence = json.loads(output.read_text())
assert evidence["status"] == "failed"
assert len(evidence["passes"]) == 1
assert evidence["passes"][0]["stderr"] == "failure detail"
+96
View File
@@ -0,0 +1,96 @@
"""Tests for quality-policy immutability and mature-scope measurement."""
from __future__ import annotations
from copy import deepcopy
from scripts import check_quality_policy as quality
def _policy():
return {
"minimums": dict(quality.BASELINE_FLOORS),
"mature_cpu_scope": {
"exclusions": [{
"path": "obliteratus/external.py",
"boundary": "network-service",
"rationale": "Requires a live external service.",
"conditional_issue": "https://github.com/elder-plinius/OBLITERATUS/issues/71",
"conditional_gate": "network-services",
}],
},
"threshold_exceptions": [],
}
def _coverage():
return {
"files": {
"obliteratus/pure.py": {
"summary": {
"num_statements": 100,
"covered_lines": 80,
"num_branches": 20,
"covered_branches": 15,
},
},
"obliteratus/external.py": {
"summary": {
"num_statements": 1000,
"covered_lines": 0,
"num_branches": 500,
"covered_branches": 0,
},
},
},
}
def test_policy_and_exact_mature_floors_pass():
policy = _policy()
assert quality.validate_policy(policy) == []
measurement, failures = quality.validate_mature_cpu_scope(_coverage(), policy)
assert failures == []
assert measurement["line_percent"] == 80
assert measurement["branch_percent"] == 75
def test_floor_regression_requires_structured_reviewed_exception():
policy = _policy()
policy["minimums"]["mutation_score"] = 69
assert quality.validate_policy(policy) == [
"quality minimum mutation_score cannot move below 70 without an explicit reviewed exception",
]
policy["threshold_exceptions"] = [{
"threshold": "mutation_score",
"new_value": 69,
"reason": "Temporary tool regression",
"approved_issue": "https://github.com/elder-plinius/OBLITERATUS/issues/999",
"expires": "2026-09-01",
}]
assert quality.validate_policy(policy) == []
def test_exclusions_require_unique_traceable_environment_boundaries():
policy = _policy()
duplicate = deepcopy(policy["mature_cpu_scope"]["exclusions"][0])
duplicate["rationale"] = ""
policy["mature_cpu_scope"]["exclusions"].append(duplicate)
failures = quality.validate_policy(policy)
assert "mature CPU exclusion path is duplicated: obliteratus/external.py" in failures
assert "mature CPU exclusion 1 requires non-empty rationale" in failures
def test_mature_scope_rejects_regression_and_stale_exclusion():
policy = _policy()
report = _coverage()
report["files"]["obliteratus/pure.py"]["summary"]["covered_lines"] = 79
_, failures = quality.validate_mature_cpu_scope(report, policy)
assert failures == [
"mature CPU line coverage 79.00% is below the 80.00% floor",
]
del report["files"]["obliteratus/external.py"]
_, failures = quality.measure_mature_cpu_scope(report, policy)
assert failures == [
"coverage report is missing excluded source file obliteratus/external.py",
]
Generated
+427 -64
View File
@@ -4,7 +4,8 @@ requires-python = ">=3.10"
resolution-markers = [
"(python_full_version >= '3.14' and sys_platform == 'linux') or (python_full_version >= '3.14' and sys_platform == 'win32')",
"(python_full_version == '3.13.*' and sys_platform == 'linux') or (python_full_version == '3.13.*' and sys_platform == 'win32')",
"python_full_version >= '3.13' and sys_platform != 'linux' and sys_platform != 'win32'",
"python_full_version >= '3.14' and sys_platform != 'linux' and sys_platform != 'win32'",
"python_full_version == '3.13.*' and sys_platform != 'linux' and sys_platform != 'win32'",
"(python_full_version == '3.12.*' and sys_platform == 'linux') or (python_full_version == '3.12.*' and sys_platform == 'win32')",
"python_full_version == '3.12.*' and sys_platform != 'linux' and sys_platform != 'win32'",
"(python_full_version == '3.11.*' and sys_platform == 'linux') or (python_full_version == '3.11.*' and sys_platform == 'win32')",
@@ -14,7 +15,7 @@ resolution-markers = [
]
[options]
exclude-newer = "0001-01-01T00:00:00Z" # This has no effect and is included for backwards compatibility when using relative exclude-newer values.
exclude-newer = "2026-08-11T17:42:28.049938237Z"
exclude-newer-span = "P3D"
[manifest]
@@ -423,7 +424,7 @@ name = "cffi"
version = "2.1.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pycparser", marker = "implementation_name != 'PyPy'" },
{ name = "pycparser", marker = "(implementation_name != 'PyPy' and sys_platform == 'linux') or (implementation_name != 'PyPy' and sys_platform == 'win32')" },
]
sdist = { url = "https://files.pythonhosted.org/packages/9e/ef/008a1939e372c06329a3fce4279c02f328488f3526744906eeec3da7ad5f/cffi-2.1.1.tar.gz", hash = "sha256:dd31f52ea1086513bb9df30f8fcee9b8918323ae067a3d5b78bc826a000712be", size = 530807, upload-time = "2026-08-03T21:21:18.939Z" }
wheels = [
@@ -590,7 +591,7 @@ resolution-markers = [
"python_full_version < '3.11' and sys_platform != 'linux' and sys_platform != 'win32'",
]
dependencies = [
{ name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" } },
{ name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/66/54/eb9bfc647b19f2009dd5c7f5ec51c4e6ca831725f1aea7a993034f483147/contourpy-1.3.2.tar.gz", hash = "sha256:b6945942715a034c671b7fc54f9588126b0b8bf23db2696e3ca8328f3ff0ab54", size = 13466130, upload-time = "2025-04-15T17:47:53.79Z" }
wheels = [
@@ -659,14 +660,15 @@ source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"(python_full_version >= '3.14' and sys_platform == 'linux') or (python_full_version >= '3.14' and sys_platform == 'win32')",
"(python_full_version == '3.13.*' and sys_platform == 'linux') or (python_full_version == '3.13.*' and sys_platform == 'win32')",
"python_full_version >= '3.13' and sys_platform != 'linux' and sys_platform != 'win32'",
"python_full_version >= '3.14' and sys_platform != 'linux' and sys_platform != 'win32'",
"python_full_version == '3.13.*' and sys_platform != 'linux' and sys_platform != 'win32'",
"(python_full_version == '3.12.*' and sys_platform == 'linux') or (python_full_version == '3.12.*' and sys_platform == 'win32')",
"python_full_version == '3.12.*' and sys_platform != 'linux' and sys_platform != 'win32'",
"(python_full_version == '3.11.*' and sys_platform == 'linux') or (python_full_version == '3.11.*' and sys_platform == 'win32')",
"python_full_version == '3.11.*' and sys_platform != 'linux' and sys_platform != 'win32'",
]
dependencies = [
{ name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
{ name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" },
{ name = "numpy", version = "2.5.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/58/01/1253e6698a07380cd31a736d248a3f2a50a7c88779a1813da27503cadc2a/contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880", size = 13466174, upload-time = "2025-07-26T12:03:12.549Z" }
@@ -882,8 +884,8 @@ name = "cryptography"
version = "50.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "cffi", marker = "platform_python_implementation != 'PyPy'" },
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
{ name = "cffi", marker = "(platform_python_implementation != 'PyPy' and sys_platform == 'linux') or (platform_python_implementation != 'PyPy' and sys_platform == 'win32')" },
{ name = "typing-extensions", marker = "(python_full_version < '3.11' and sys_platform == 'linux') or (python_full_version < '3.11' and sys_platform == 'win32')" },
]
sdist = { url = "https://files.pythonhosted.org/packages/de/41/6cbdcf9142d00fe82836fbb51e503e58088575cf7a0fe1dbff6695bf0840/cryptography-50.0.0.tar.gz", hash = "sha256:eeac2acb5a20ed25e0ad6d1df9891a520b78b404266b6d11778f25d5d691a6c9", size = 880201, upload-time = "2026-07-31T14:25:10.11Z" }
wheels = [
@@ -979,7 +981,7 @@ name = "exceptiongroup"
version = "1.3.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "typing-extensions" },
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
]
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 = [
@@ -1363,6 +1365,79 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/de/d8/95b735e183957c1f26d94c52977f09d466d55119cbbc1558ea4975e4c216/huggingface_hub-1.27.0-py3-none-any.whl", hash = "sha256:7df6827c2f956c60fbaa64646e979e566db76f619dd0a9729dfb8c5a3eb4f68d", size = 784926, upload-time = "2026-08-07T12:48:02.905Z" },
]
[[package]]
name = "hypothesis"
version = "6.165.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
{ name = "sortedcontainers" },
]
sdist = { url = "https://files.pythonhosted.org/packages/18/7a/7a277ac07776191be594f74f6425649d529e4876f7d3ff1ee96d393ffdbc/hypothesis-6.165.3.tar.gz", hash = "sha256:687c5abb1a9c11478577c2cf18685c0eb82150d278477d3e14da290a1ef2a098", size = 502263, upload-time = "2026-08-11T01:23:09.1Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/f9/c7/18152acad5f85f91554b2030000319b952a54151509953651ec40f37d50d/hypothesis-6.165.3-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:56af539c811b11ab5475704c300b8f0b46cc6dd0edc267e02a16487e803c77f8", size = 781671, upload-time = "2026-08-11T01:22:09.176Z" },
{ url = "https://files.pythonhosted.org/packages/d3/77/4293ea8a7fdb713956a8bf460b9070115df69f8216a900507633f9cdb225/hypothesis-6.165.3-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:f40c10cfdb1ea2cd75e5d4e6e0cfdcb6198ab8406e8922666480e6dc11eea341", size = 777291, upload-time = "2026-08-11T01:22:15.991Z" },
{ url = "https://files.pythonhosted.org/packages/02/fa/fa2071a6afaefc082dc7a033f41ae61436caf442d5973ba8ca9c29a69460/hypothesis-6.165.3-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a0854b1de4577f7e1beb1d681360285b5d678b65a809787ff4eab5b8b25efca", size = 1106490, upload-time = "2026-08-11T01:22:07.858Z" },
{ url = "https://files.pythonhosted.org/packages/ba/86/de724b7f9cd10e3be4efa21770457172e549d7576b1d8e29d6177eef5e47/hypothesis-6.165.3-cp310-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:360991cda8e488924905af48949033b90d4877ac97b9ad5d826d4d0f5a4b8cfb", size = 1135054, upload-time = "2026-08-11T01:22:29.499Z" },
{ url = "https://files.pythonhosted.org/packages/12/6a/96721cf447bd3c64b5e6843dde4444b20f3ddd901ad366cc73d0e7314bf5/hypothesis-6.165.3-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf502000f4a8ef4c9ab9493ca3b4fe17ae3033c18a8e2a31cdd69515dc7d97be", size = 1155997, upload-time = "2026-08-11T01:21:48.496Z" },
{ url = "https://files.pythonhosted.org/packages/0f/ae/a793cce6497f233b155f97684bf7d0e424c25613dd87b8af8a4e87820232/hypothesis-6.165.3-cp310-abi3-manylinux_2_31_riscv64.whl", hash = "sha256:b9fcf47ad18f87f7c15bd36289bd45708bbfd250129d73bf554653e2f9afc931", size = 1111326, upload-time = "2026-08-11T01:22:21.9Z" },
{ url = "https://files.pythonhosted.org/packages/28/8d/dc3cdfd55843d038effa2458a9c9bd73002218a8c0fd58c2c0ab7fa328db/hypothesis-6.165.3-cp310-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2fb05529cbcab5a317d03d7bb0e90d382f79ef1643e3568577916d0e24bfe70b", size = 1148079, upload-time = "2026-08-11T01:21:51.071Z" },
{ url = "https://files.pythonhosted.org/packages/db/4b/2f62924ac41f3d3482b29ded4c213f27ff4a103e56e84eeb528d4900cac7/hypothesis-6.165.3-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:57eae10a64340cd621a78eae9cb0459bd68ea99fbaa933c4f00e34d5087b6376", size = 1281862, upload-time = "2026-08-11T01:21:39.274Z" },
{ url = "https://files.pythonhosted.org/packages/7e/d4/01c78b7b7348b6e8cef9b999109dfb93b14c7e1e38bc22170129f8b17181/hypothesis-6.165.3-cp310-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:19df0f2239052e9a870634a1d9bcdff95e2a2ab508573e5dd5c3d1ca545f5b3c", size = 1408437, upload-time = "2026-08-11T01:22:13.243Z" },
{ url = "https://files.pythonhosted.org/packages/35/76/e940b5a5aaf75bcd4784f1f3f9bf2b9a642a706bc0a9639077ca84f1325f/hypothesis-6.165.3-cp310-abi3-musllinux_1_2_riscv64.whl", hash = "sha256:9781a8026adff4b4516404cf0e5f2cadcb471318c2882a264e1c57c4c092266f", size = 1281168, upload-time = "2026-08-11T01:21:58.964Z" },
{ url = "https://files.pythonhosted.org/packages/fc/84/b153e81a614f45e0902e3b9e8a8b079e64214c50abb6fbe9acc62ccf686d/hypothesis-6.165.3-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1dd7e05f88e3e108a5e4f5f71a3eaf205559e8951e3c1f1ffd04cea82ed3b731", size = 1323263, upload-time = "2026-08-11T01:21:52.374Z" },
{ url = "https://files.pythonhosted.org/packages/fb/5f/e5144d9e91ab7260650cb1ee032ca23208d49ebb1334845baf6407c1a9d9/hypothesis-6.165.3-cp310-abi3-win32.whl", hash = "sha256:d1389bda38cb222acc109aef5b31643ce799a39a76294a50ad8b84e32f92d76d", size = 667499, upload-time = "2026-08-11T01:21:47.36Z" },
{ url = "https://files.pythonhosted.org/packages/a9/18/f008b6f1f1c293d51c2776f8815d95bccb777dcf87df2a0ab56b273b47dc/hypothesis-6.165.3-cp310-abi3-win_amd64.whl", hash = "sha256:10cda6988ca4b1da389548b6fdd71af236b588a601fc1757e56eb8988e4240d8", size = 673643, upload-time = "2026-08-11T01:22:46.975Z" },
{ url = "https://files.pythonhosted.org/packages/b9/e9/2aaded93d3e299452988132a98921670e5992963a33b987e6ebd0cdf7b3c/hypothesis-6.165.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:244b2dfe86b5b98f58f5228b082b797e983259e213a86896c964498a31de6dea", size = 782413, upload-time = "2026-08-11T01:23:07.214Z" },
{ url = "https://files.pythonhosted.org/packages/ca/2a/0e170b864bab77ad801145d8d632292fd4b5d48e8c0f525730e13be2118d/hypothesis-6.165.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:83957338a78ae69c5f6fc12390abad82e48f8716f67beb6b9dab6debf78405f4", size = 778143, upload-time = "2026-08-11T01:22:58.684Z" },
{ url = "https://files.pythonhosted.org/packages/a3/a1/f1501c877afeea9d3e48006e2e2394021fb88371d130afe5675709be1cdf/hypothesis-6.165.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9faab7c0f9a229945a931b8daafc9c5d72a0647d2c62377deb94adfe92fd60d8", size = 1106988, upload-time = "2026-08-11T01:22:32.538Z" },
{ url = "https://files.pythonhosted.org/packages/11/4f/c0e84fd51e6d0d8fd1c540b5acc4a9ced141179282b5336df2b0a8c0ab94/hypothesis-6.165.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d203a1116ebbb2e339d2595788553cee29f3a313dc59f35d435bd958431c9586", size = 1156587, upload-time = "2026-08-11T01:22:17.685Z" },
{ url = "https://files.pythonhosted.org/packages/1c/b9/b7b406cbbd557736674d0a8b8e05171c4e4f0d32d6fa8674930b4834dc75/hypothesis-6.165.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b137d855d6f3301a7099e5a329099e7a32e8f4c81672a9b56e251bc11ed3d4df", size = 1282604, upload-time = "2026-08-11T01:23:01.905Z" },
{ url = "https://files.pythonhosted.org/packages/bd/43/3edd0dbc97c3a345d165bd824249e570144a3ec771b79b7415220340d103/hypothesis-6.165.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:82d794f885502d772c85a531097294e2cc52bc86c424dc2a5506a99d67c84cda", size = 1323579, upload-time = "2026-08-11T01:22:11.672Z" },
{ url = "https://files.pythonhosted.org/packages/fb/b0/8cf87f258888cb056e8f5e440995d3526d61b5bd49dfeb6d27d42c669198/hypothesis-6.165.3-cp310-cp310-win_amd64.whl", hash = "sha256:416a716dd383bc7b03feaf1d046744ca7a02c4ea55bbf79fca2394ee9a83b534", size = 673537, upload-time = "2026-08-11T01:22:03.905Z" },
{ url = "https://files.pythonhosted.org/packages/42/61/81db899aaedd6fd05d4aed078e2dd683513c941fa281264b5430f9c32021/hypothesis-6.165.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:874bbf116bc99684a40b61d9b2a073bf67fb2354365853d4e9b8cb6e1d025324", size = 782183, upload-time = "2026-08-11T01:22:51.73Z" },
{ url = "https://files.pythonhosted.org/packages/87/32/282f7a78a554f776cc66157392d7cdf9bf6655f13a66a1dab6ff0a6a4907/hypothesis-6.165.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:00c63ce0d532368edcb7c201c2a29dc7cbef81ac15b96d7b97179de6390739ca", size = 777964, upload-time = "2026-08-11T01:22:19.029Z" },
{ url = "https://files.pythonhosted.org/packages/a0/15/c883a514925b2bacef5d6749d281f437c916b85ff0b2aaca173055b3f2f3/hypothesis-6.165.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd3b62c67b4b9fca4ced59d86ffd4204ea44cf182b9eba8200a881592000150f", size = 1106849, upload-time = "2026-08-11T01:22:57.019Z" },
{ url = "https://files.pythonhosted.org/packages/12/43/a40fe426c902e6c2e30a5ee4cb1405786be378ddc7432fe0a6944b0e4653/hypothesis-6.165.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d587a6df45237276b79ecd6d9e0245f16b1b21ea2c35f9fc49756df3ef3daa19", size = 1156325, upload-time = "2026-08-11T01:21:46.2Z" },
{ url = "https://files.pythonhosted.org/packages/2b/be/2cffa1a57ee1e213a929b1b28fd67c392cce3f1fc822a1593dccaf2f5a42/hypothesis-6.165.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:084e113e0f5b70902d5872d2fbd27b6acb4481cd431f3fae6a54f4dac4601738", size = 1282183, upload-time = "2026-08-11T01:21:49.737Z" },
{ url = "https://files.pythonhosted.org/packages/23/d6/dd92c23788a11931d8ec1c528c25f0050e540e667fd95bfbb346fa7b7443/hypothesis-6.165.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:2f805bd7b3c2a4449d1c9129a57750bae4b3d1f056ff96581a78f9efc6c0e7a0", size = 1323523, upload-time = "2026-08-11T01:22:26.145Z" },
{ url = "https://files.pythonhosted.org/packages/94/7a/257d4c0d0777f7ecffd71c1f1717922a70ac6ed43fff8d169631da730c44/hypothesis-6.165.3-cp311-cp311-win_amd64.whl", hash = "sha256:67c0d3cb622415e72022beba1fe272502e9ecdbb614a36bee0f4c816810cf3f1", size = 673355, upload-time = "2026-08-11T01:21:43.991Z" },
{ url = "https://files.pythonhosted.org/packages/e2/3d/e7eade134bd7f57d4071d82ae84691bc3017fe6945af0bb149578ba8b565/hypothesis-6.165.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f88fe4915f8dd4f8999a197f9e22c3a7177042aa994d35c0c7c7b22541d2885b", size = 783298, upload-time = "2026-08-11T01:22:14.706Z" },
{ url = "https://files.pythonhosted.org/packages/d6/a5/668810f493feaf886a9240ad689792fb32450667c8e5770c3bcaa7fabeac/hypothesis-6.165.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c7d9f6c36b812f6069c7436492e12812cf541391954e21d5bd7fcafc9fb46700", size = 774856, upload-time = "2026-08-11T01:22:35.836Z" },
{ url = "https://files.pythonhosted.org/packages/e4/a0/0af93a70f5128763079ab714277ccad4a7de42d442d67dd43e3029178162/hypothesis-6.165.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:423ca8e30087bb41db7e6f47dbf98690a2155241b9f1057e366dc138d7dcc4fe", size = 1105274, upload-time = "2026-08-11T01:23:03.591Z" },
{ url = "https://files.pythonhosted.org/packages/7b/00/ddcdc99beee469573addf5cfcd817c9a20a71832b1ca88404b6d3f99c44c/hypothesis-6.165.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c58c66f3e1b8d4091bb52664d5af4b0c1715293c6822d5344b166494534cd498", size = 1155379, upload-time = "2026-08-11T01:22:23.371Z" },
{ url = "https://files.pythonhosted.org/packages/de/10/d574b21e63f16a1cad9c0cf4592aa170285940f034d04bb33a1e08025397/hypothesis-6.165.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3774882c4685e5474b7940697da55963e591b71c6dce593d90ac4128766371ad", size = 1279259, upload-time = "2026-08-11T01:21:53.63Z" },
{ url = "https://files.pythonhosted.org/packages/b9/3f/13f6b6c7d7d0b9bb570a18617eb659b015c312b1d8d1d3aaf9f2edea9628/hypothesis-6.165.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5cb3a397a5422c67387f4408989dbdfc2b1e0306f883f2aa79b9472c80958464", size = 1322605, upload-time = "2026-08-11T01:21:42.853Z" },
{ url = "https://files.pythonhosted.org/packages/6c/dd/243317f5fb8497601dc65d3ded984834eb5f36b8ec59e7853ef753ec0ee1/hypothesis-6.165.3-cp312-cp312-win_amd64.whl", hash = "sha256:dbb74811d54b6317ba0d2047aad269c09afefaa25d1849f8f33f80a638b0c3af", size = 670812, upload-time = "2026-08-11T01:22:50.245Z" },
{ url = "https://files.pythonhosted.org/packages/03/3e/95cba31dbe775b99a4548cdae192e1ad15cee7b64fbdfe6cd4c9d00031b4/hypothesis-6.165.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:447f139d6dd70a5d8b178ef507463fb0430ace9ce42e3b2351d2803a391fe774", size = 783183, upload-time = "2026-08-11T01:22:45.286Z" },
{ url = "https://files.pythonhosted.org/packages/56/0e/51bf125cdf7855b69097b8f59c73ef3cf5f4e3d68a16e808d2d1f08a1ff1/hypothesis-6.165.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6152c718606f1705e673c6b30a6ebd3ff08d340da85291dd3c432c73b28a9b3a", size = 774820, upload-time = "2026-08-11T01:22:24.825Z" },
{ url = "https://files.pythonhosted.org/packages/0a/69/b954f742b97441a5c49f8f8704826ee0637a6cce3a7d06ce85fbefc54ac5/hypothesis-6.165.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27fe7826ad83ccc2e8062f0fab43b137bab34cef1a149a926b34a7b8382ee22c", size = 1105186, upload-time = "2026-08-11T01:21:41.733Z" },
{ url = "https://files.pythonhosted.org/packages/6e/8a/33e41d9cc1be7661e0b4129c225a93c3f12544714300aadb95ae7eedf894/hypothesis-6.165.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1ff92876a324f7b9cdb92cedf103e380b7a12aa7df55ebcb16dd0f495a879e8", size = 1155215, upload-time = "2026-08-11T01:22:06.604Z" },
{ url = "https://files.pythonhosted.org/packages/ee/53/ba09526c9100ace5752908ac7251d2dc3960ce7e0e97a31152aaa26c33ee/hypothesis-6.165.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:53f1564c97d27fc109f212404d49cd71d7789777dbe0685628ffe9838df56240", size = 1279245, upload-time = "2026-08-11T01:21:56.182Z" },
{ url = "https://files.pythonhosted.org/packages/c1/93/fc637d355791a65364a3409ff06ade7ba5d3fc6f1d07a729781dec315fa0/hypothesis-6.165.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:788a9b0a7aae719a2b71a1c2f07e51deb1d0fe990164a9090c686833ed4bfbad", size = 1322370, upload-time = "2026-08-11T01:22:48.492Z" },
{ url = "https://files.pythonhosted.org/packages/b6/8d/826053ba0263143fed2b0e8af009dc868d8a932e7246e191deb8ca7ce8ff/hypothesis-6.165.3-cp313-cp313-win_amd64.whl", hash = "sha256:37830f0795abfdf738d2a5b6f829a73f3ab498de45a2e61b0bf3bd38d8c9ddb9", size = 670804, upload-time = "2026-08-11T01:22:00.103Z" },
{ url = "https://files.pythonhosted.org/packages/e7/27/3230f8de3d853b2b547731916ae1d1026bd197cd3f2d35dafc0b445da46b/hypothesis-6.165.3-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:38826441dbf528cc156388d0a05526086a12da3e1348353d3fa14de03e57c4b2", size = 783286, upload-time = "2026-08-11T01:22:40.816Z" },
{ url = "https://files.pythonhosted.org/packages/6c/28/9f9ca830d376c50babe55c616f6d99eea886c6ebcd8b512dcd5d56f9e40c/hypothesis-6.165.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:87490115edd34a246a4ba8b1144cbdf571438c46c406ece05caf65908667c9a9", size = 774963, upload-time = "2026-08-11T01:23:05.409Z" },
{ url = "https://files.pythonhosted.org/packages/33/3c/3c81f08ec1edce160da509c5785d78c0e25a7913899c4b9ff724bfd01420/hypothesis-6.165.3-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f51f4346cfa26bca68c68f7bbbd2b1812208bc9f572187c95ecab080ed402153", size = 1105730, upload-time = "2026-08-11T01:22:42.311Z" },
{ url = "https://files.pythonhosted.org/packages/bf/b5/f6f81b9aec9999ec63920d168617cab67a038be05487eff3410ccd072bfe/hypothesis-6.165.3-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4da89eb4b36b3260ff714d2ecc3274b9bd599fd96687d2d9ed53d5e1a801a7a7", size = 1155383, upload-time = "2026-08-11T01:21:57.58Z" },
{ url = "https://files.pythonhosted.org/packages/dd/27/7f3a8c6101675bf95c80cd8c9173d65892ca0b7b640551156dc4537fab1f/hypothesis-6.165.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:eb6d31c14d7bdfe03e501d88ee296c149a74cc93e3d01c76ea335e64ee5f33ec", size = 1279606, upload-time = "2026-08-11T01:22:37.56Z" },
{ url = "https://files.pythonhosted.org/packages/d9/16/0c23e06a24e421e532f62a95021fae34f685f3a194c081c6991b4ab202b3/hypothesis-6.165.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:0863e1a9258bc103abe616fa9471cfa66a1535ea404dd8a0bf360e0a29502397", size = 1322697, upload-time = "2026-08-11T01:22:27.857Z" },
{ url = "https://files.pythonhosted.org/packages/dc/56/8356dadf45e5c635b46aa2b57fa74f3210250a8e38b860b6b75f50ed0b42/hypothesis-6.165.3-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:53c56155f2cfbb45ec97fef9ea3b8453b4a34c48c3c5cacee16f97dd2a037994", size = 614859, upload-time = "2026-08-11T01:22:01.304Z" },
{ url = "https://files.pythonhosted.org/packages/e3/79/124d4faf235219acd685c359760a5cb3995609bc50ce465e54c3249841ee/hypothesis-6.165.3-cp314-cp314-win_amd64.whl", hash = "sha256:c48f41e950b5e602e2fdf8f92dcc8ac7bf715a003bf822afb7c9d5cbc41bc344", size = 670600, upload-time = "2026-08-11T01:22:10.356Z" },
{ url = "https://files.pythonhosted.org/packages/01/7a/41ac5e68d9ce079d1b76d4c54126354df61b948c3d519d1289aca877eedc/hypothesis-6.165.3-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:9563d3040178fb1f522665bcec6458cc0d21ab77d7c637058a8be4ea8c01d236", size = 781746, upload-time = "2026-08-11T01:22:34.472Z" },
{ url = "https://files.pythonhosted.org/packages/5d/fb/7ecc21aae63a83dbc8036f9a0544c6b3d798db566b97b5202bdf8e770f80/hypothesis-6.165.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1fe1783543b43ba9808c016950e5e84b3804dc3365ba77c37c427b5896a558a1", size = 773382, upload-time = "2026-08-11T01:22:55.279Z" },
{ url = "https://files.pythonhosted.org/packages/cb/f2/9cc2a4768f9a483b12e307ba585f5eb9c7f5500bd16ff82ddbf62a9a1b88/hypothesis-6.165.3-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9ea34806a4df4e8305a096dcf8e53cdd903c96c1e0d2dd5b001d2283f639c3f1", size = 1103911, upload-time = "2026-08-11T01:23:00.286Z" },
{ url = "https://files.pythonhosted.org/packages/54/9e/b551a494f84976ee5bb9374c197ccc126dea2ec6f22098d5f70705237473/hypothesis-6.165.3-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d188454b95ce46ba991e3c52161255d76af25170ad28591f6b30b045e501216e", size = 1154060, upload-time = "2026-08-11T01:22:20.413Z" },
{ url = "https://files.pythonhosted.org/packages/69/37/8e22a236f1f1e599525549a34672fb0523109f571486fe209b12a84a942e/hypothesis-6.165.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:a1c47b15ce97a9b1346bc7d7013c5f215380f78ae01c0f73a1638bd8b98bdd76", size = 1277631, upload-time = "2026-08-11T01:22:30.965Z" },
{ url = "https://files.pythonhosted.org/packages/13/0f/feb33bfc23853b4ba6360ff5e34235cd8bea0d7dd1eb21e17491f581c4e2/hypothesis-6.165.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:996077ef7a3bb332b6638f698ddf7555c82784b58dde80eeba3f07c0a322b40f", size = 1321326, upload-time = "2026-08-11T01:21:45.089Z" },
{ url = "https://files.pythonhosted.org/packages/9f/3b/ad56b56540a0719f493edec0dd442ebb21272147d2482ef505d19760a6d3/hypothesis-6.165.3-cp314-cp314t-win_amd64.whl", hash = "sha256:57a8273bdafe3f450afe66999fd130d4935d775eaf4ef63fcac0bee8015fc512", size = 670613, upload-time = "2026-08-11T01:22:05.294Z" },
{ url = "https://files.pythonhosted.org/packages/6f/22/e734aff77ab104d931151ae6271f9284f6a75f4f81692bdf1a91a27115e2/hypothesis-6.165.3-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:d7d366a66116c3aff4b9f8dcfd1762b20ff7d53bdd77960c14ff2f52a31ad149", size = 783103, upload-time = "2026-08-11T01:21:54.961Z" },
{ url = "https://files.pythonhosted.org/packages/dd/4c/142b6e79c43feade6a0a7992691d7500024954c2545bf37bb85c53754f70/hypothesis-6.165.3-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:6133f89de9a13ca7322ac2fe256d2c13dcaba3ef43873e1c8704d964239addb0", size = 778953, upload-time = "2026-08-11T01:22:53.398Z" },
{ url = "https://files.pythonhosted.org/packages/92/d2/e192179a59d7e2eb59c203ca849eb2b54a5871bde38b46dfe2ecb7b9e071/hypothesis-6.165.3-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:812f05d49ad7970673d73ace920f17a251f8843369850dedb87932ee9b0f0386", size = 1107830, upload-time = "2026-08-11T01:22:02.615Z" },
{ url = "https://files.pythonhosted.org/packages/29/dd/b75399a8cddc49510b20c910364c536db131765e05f8a0c3d20e20ed90d8/hypothesis-6.165.3-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d4f95c93ae6afdae545f83374d3bf9585edb4555e4623d93140686ea612b933", size = 1157576, upload-time = "2026-08-11T01:22:39.196Z" },
{ url = "https://files.pythonhosted.org/packages/9e/b7/7f5be4883a60b78665bb071a320d6f5c10341385bf708120d34712513683/hypothesis-6.165.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:f93f0d8e8e1fa9e2069ba1c95b75a771f79d46efc212db518219838906039254", size = 674476, upload-time = "2026-08-11T01:22:43.842Z" },
]
[[package]]
name = "id"
version = "1.6.1"
@@ -1389,7 +1464,7 @@ name = "importlib-metadata"
version = "9.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "zipp" },
{ name = "zipp", marker = "python_full_version < '3.12'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a9/01/15bb152d77b21318514a96f43af312635eb2500c96b55398d020c93d86ea/importlib_metadata-9.0.0.tar.gz", hash = "sha256:a4f57ab599e6a2e3016d7595cfd72eb4661a5106e787a95bcc90c7105b831efc", size = 56405, upload-time = "2026-03-20T06:42:56.999Z" }
wheels = [
@@ -1613,6 +1688,86 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/0a/dd/8050c947d435c8d4bc94e3252f4d8bb8a76cfb424f043a8680be637a57f1/kiwisolver-1.5.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:59cd8683f575d96df5bb48f6add94afc055012c29e28124fcae2b63661b9efb1", size = 73558, upload-time = "2026-03-09T13:15:52.112Z" },
]
[[package]]
name = "libcst"
version = "1.9.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pyyaml", marker = "python_full_version != '3.13.*'" },
{ name = "pyyaml-ft", marker = "python_full_version == '3.13.*'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/02/c0/098e5c91ff1537f00c85a6438b6cb1863d17144680cc91f47c87f104a200/libcst-1.9.0.tar.gz", hash = "sha256:087b58a9afe076bb08e2d726478e1f16cb928d67ffa9092817e033c335de522a", size = 914739, upload-time = "2026-07-29T21:28:43.153Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/f9/b3/23144dcd9f9cd6f6150058653ecd0357c6b09361656ebd286165a5d76d34/libcst-1.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5705f664266742b8d9323db714f58cf06a6cde739eb09fd9ca31cd233f9806e5", size = 2055037, upload-time = "2026-07-29T19:24:27.708Z" },
{ url = "https://files.pythonhosted.org/packages/5d/87/164a9bac39a817b505d27cf4490e6f66b2a1b8adb6b4e022b1ef4613bcfe/libcst-1.9.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:7dcddfb4905c5ef90a6fdc58dccbc049faf0056b68161042fc1e0526b20cba05", size = 2210166, upload-time = "2026-07-29T19:24:29.386Z" },
{ url = "https://files.pythonhosted.org/packages/1c/cb/b5aeaefbe471c4225c145c15c3bac96d67b0641a5e3ec9b871c62858c88c/libcst-1.9.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:cc84aee3c293a012db722aa2d6ea87be524646852684a5a4e54c1fb98ea9072f", size = 2260568, upload-time = "2026-07-29T19:24:31.021Z" },
{ url = "https://files.pythonhosted.org/packages/ab/0f/351dcd23629732e35e716e13ad536a193124cda075ac5e59dc866503447b/libcst-1.9.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:329ffda6b0ef708ff22876f982ec886a509c8f73ac1ccb0190693d35cb09aa0f", size = 2276024, upload-time = "2026-07-29T19:24:32.393Z" },
{ url = "https://files.pythonhosted.org/packages/74/f5/0da2b60137a6290ba7dda902b32da64d46c9a5107aa002da578f8b1ff8c8/libcst-1.9.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5302fc698ef863e1a2fb540e95793b3d5a96abc89aa6423ee9c389d7d7ec5eab", size = 2384413, upload-time = "2026-07-29T19:24:33.983Z" },
{ url = "https://files.pythonhosted.org/packages/8f/80/7e48d2fc1afda13a6de50ab6f8340dbd104fd6c9bcd2ff11dec66e320f2c/libcst-1.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:a6615b036694f6906e30dc018b5b34898cff7ff760ab549f9dea1ada4f53495b", size = 2110204, upload-time = "2026-07-29T19:24:35.491Z" },
{ url = "https://files.pythonhosted.org/packages/42/87/52c88c7ba873011526aa35b8fa0cf55d50effe967c999e7cb688155c5691/libcst-1.9.0-cp310-cp310-win_arm64.whl", hash = "sha256:dacc583bcd8db56e457ae559b910673c6b5df66f694d1f1154ce0b3982158d17", size = 1988757, upload-time = "2026-07-29T19:24:37.053Z" },
{ url = "https://files.pythonhosted.org/packages/53/36/b45e6950878d9143f95db609432031ac688b311aa14450a8df239c648c45/libcst-1.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3cdbafbc992b38ea005ef37e20243c4177879020c82d414789fbb7fa22d6d3a9", size = 2054911, upload-time = "2026-07-29T19:24:38.542Z" },
{ url = "https://files.pythonhosted.org/packages/6f/d8/1c1ae22e05fbc763dc5a4e4c3cab356166913ef19d2c2da42e6f1be5c98c/libcst-1.9.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:3f735e3acb3afc75d50803fde1598b467bf05d12d6854025df4398aebd75a14c", size = 2209147, upload-time = "2026-07-29T19:24:40.039Z" },
{ url = "https://files.pythonhosted.org/packages/84/e1/0d5eaeac4dadd34fcd9ea154d0a6e5ce10c9fec0e02c73f807a16475b8b0/libcst-1.9.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:951f13c193e590fc88c9582a5341a130fe53ecece51043cff4bd54e25a5e022d", size = 2260355, upload-time = "2026-07-29T19:24:41.423Z" },
{ url = "https://files.pythonhosted.org/packages/71/b2/45ce33c6bca5c1961a90f2999138741daa0dc8cf6fe8b122c0ca2502632d/libcst-1.9.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bc6aa3e7f21315dbe9868c0d13ffaac309514e8c816320c5f91230fa5b21df92", size = 2275659, upload-time = "2026-07-29T19:24:42.828Z" },
{ url = "https://files.pythonhosted.org/packages/bb/b1/936d2f17d93fb160579ff56ca671d26154209bbc07ea8645eb11db1f9633/libcst-1.9.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f101e0bf8638eba80694ecc3c3abb5309eb488f5271427536cb379c5c1e0ba9e", size = 2383467, upload-time = "2026-07-29T19:24:44.397Z" },
{ url = "https://files.pythonhosted.org/packages/e7/59/db667f15d62cb22c75b24f6b13c4151292aa1889a64ff9abce92f60d5a97/libcst-1.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:77d9303572cf0fbd0a2eb71aff167a4246541f43bf58b781b35b9d0bbab80ddc", size = 2109985, upload-time = "2026-07-29T19:24:45.966Z" },
{ url = "https://files.pythonhosted.org/packages/6d/a8/99926865cd3f97c0cffc71cd38152c883b7ae666eb8327d355f01bddb33a/libcst-1.9.0-cp311-cp311-win_arm64.whl", hash = "sha256:4090105fa4ad114766d0f8b34418d9a3b359bc8645da860a447e19770b5705d1", size = 1988559, upload-time = "2026-07-29T19:24:47.528Z" },
{ url = "https://files.pythonhosted.org/packages/b0/bb/d22c37c33dfe18084634f5ef89f8f0749ffe7b6e0ad312722aafd86bbbdb/libcst-1.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cd1a3500c41784075c4946a995d5ad89f68fa0d226b63ff3c4d78f6ea6dd23e5", size = 2043159, upload-time = "2026-07-29T19:24:49.013Z" },
{ url = "https://files.pythonhosted.org/packages/10/b8/2dedef84d72e7271119217503b69ed6dc5d0b2077685e163caae669d9c70/libcst-1.9.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:611cebd3bbc2014576f4dcc7b845b3c594c96ddc287a3db9b78f22eff156a7d3", size = 2203245, upload-time = "2026-07-29T19:24:50.399Z" },
{ url = "https://files.pythonhosted.org/packages/e8/90/e02ac2dad647423f947bb11f8322bfdba8ccfdd380e6c7b695add2d1acd4/libcst-1.9.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:8d731abe1307720ea1a52d447555e8443a6d130e0e520243c0634a58f6edbc9d", size = 2255388, upload-time = "2026-07-29T19:24:52.21Z" },
{ url = "https://files.pythonhosted.org/packages/13/5f/6089a51518cfd2ff40950eb26bcc36951d7b6d4f4213568aa0290265aff7/libcst-1.9.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8bc5351d92ca6ac1cc32e097700e1161ad1ceaa4d9b2cca5abadb1e94576b325", size = 2268982, upload-time = "2026-07-29T19:24:53.562Z" },
{ url = "https://files.pythonhosted.org/packages/ed/78/26881ec466fb70cbc129dca26ccb5a52a0061face2c5822e4b61f00f9699/libcst-1.9.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:03165a264653bb77f6a11b412ae09c08bdb0c25864f3b8d42b816ac64b9d4b9e", size = 2378174, upload-time = "2026-07-29T19:24:55.175Z" },
{ url = "https://files.pythonhosted.org/packages/e1/7a/a4dba5f11faf12a12ffba06d18019987851aab33b590242a602ffd4fb1bd/libcst-1.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:b755ed4a4bc2faee849b54820023137d60d4c199e0a0822f0ff0c1bc49e49b48", size = 2103462, upload-time = "2026-07-29T19:24:56.966Z" },
{ url = "https://files.pythonhosted.org/packages/f5/13/57cb129093e0d6744b3c914ba6cbbdf51ed1b2c823882936c553a3a0cf1b/libcst-1.9.0-cp312-cp312-win_arm64.whl", hash = "sha256:6e50576bad7d56459d9792cd0b0dfe5469dad13646e9a9c0a8b1ba20b269f332", size = 1979825, upload-time = "2026-07-29T19:24:58.403Z" },
{ url = "https://files.pythonhosted.org/packages/f2/b1/befc0544283bb3923a928accf79ed685e5a725524bdb3491826670affc07/libcst-1.9.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b8b9df30f524317b097dc53065b25dda33d6a4cc3c7c8bf4fc83ca7559c58cc0", size = 2043754, upload-time = "2026-07-29T19:24:59.885Z" },
{ url = "https://files.pythonhosted.org/packages/45/50/fef7c172a8457c95894edf5fb04805024899cdfea41fa01b0636587b79e1/libcst-1.9.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:e465a7bc9c2b9533eb9e06d2391f8819f811b5112919d4064c9fb8565aaafa08", size = 2203548, upload-time = "2026-07-29T19:25:01.323Z" },
{ url = "https://files.pythonhosted.org/packages/18/ff/764cd2be1fd99d774fc44039c319dc0ed1d9d9afeaa02759a05121cccd4b/libcst-1.9.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:8504b422c95676a8c27b517e1ac01413ece91bf356865c587ca9bdcd5708a2f7", size = 2255274, upload-time = "2026-07-29T19:25:02.764Z" },
{ url = "https://files.pythonhosted.org/packages/34/a7/474748a27a02fa83e3556b260d5f5236ca48164fa7beffecf3b2cad24dca/libcst-1.9.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bcb9f9d4fcfe2ec7a40d2c26e03a538d5d9dc189c38551eb3f94ab661afee7c0", size = 2269126, upload-time = "2026-07-29T19:25:04.158Z" },
{ url = "https://files.pythonhosted.org/packages/8a/b7/655e45363b8cf87b91e41e060b21c89e5316c7ef36eb14a1a498b27bb71e/libcst-1.9.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e8d671c39a431c309476099b8ec811e412503ec0f4465f6fc907cb51c70e8e6b", size = 2378602, upload-time = "2026-07-29T19:25:06.424Z" },
{ url = "https://files.pythonhosted.org/packages/db/13/6da63f0902ece43bf9d737017251ad7ad06edd9d3c4e1856450403cb4473/libcst-1.9.0-cp313-cp313-win_amd64.whl", hash = "sha256:4d382fba04077eb556a1ea4295a4482e192aa93639c5a07ba0885841965ea0c0", size = 2103486, upload-time = "2026-07-29T19:25:07.979Z" },
{ url = "https://files.pythonhosted.org/packages/fd/ff/dccb1a55e38b4e47256a97242d61d2bef5366c744faf88fb087d4fa0f995/libcst-1.9.0-cp313-cp313-win_arm64.whl", hash = "sha256:a621e261990148c1cfbe26c1798bd2375c131cf358a44a7a4659fc41c1a336e1", size = 1979907, upload-time = "2026-07-29T19:25:09.532Z" },
{ url = "https://files.pythonhosted.org/packages/65/2a/4943c71d90975bc59034a057dea346b365c276f308c1d31f5cf2bd85492d/libcst-1.9.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:eccf4c57d273cdd3fe1c67b72cf9bb1bbd4547aa011824e96ccf5b7136057aa4", size = 2044529, upload-time = "2026-07-29T19:25:11.04Z" },
{ url = "https://files.pythonhosted.org/packages/be/ed/1168b98c2a0f338be3a44753647baab051feaf6167cc887bf4447f8fd920/libcst-1.9.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:32395244edfe6538e0ea2bf82051d60103d3f54861274805c4fb3745efb70a85", size = 2203519, upload-time = "2026-07-29T19:25:12.543Z" },
{ url = "https://files.pythonhosted.org/packages/25/7d/2eaa697a80f899bcf2245680bbfcc1e478eb3b3328c21d4b2880bdf00dac/libcst-1.9.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:444e84c76cd035cd2fe136838c1a524d34b08216521f6f5093df8a6f6cfa5799", size = 2255879, upload-time = "2026-07-29T19:25:14.137Z" },
{ url = "https://files.pythonhosted.org/packages/90/03/793b9fd96dd52d202f5f2b88d7e54f05ebed767d1bb3b32395a1817bf6ab/libcst-1.9.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:bb5d0946f2b4c6711b5d69fe4f833b364f9e7a1a2b08f88b98619dc18975099a", size = 2269807, upload-time = "2026-07-29T19:25:15.647Z" },
{ url = "https://files.pythonhosted.org/packages/a3/f4/1bc7aaea03971c45e8a885fed9fc1c73176dbbd00b0296a3cde9529bafd6/libcst-1.9.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:45808c03528b3ad40b14095348a918e08d98c47b4a125d631cb78e817c0a5b16", size = 2378171, upload-time = "2026-07-29T19:25:17.289Z" },
{ url = "https://files.pythonhosted.org/packages/8e/f7/bc49e367d2bc8817213594dd52cf6b2da2dbbda90b5382d60653999274ac/libcst-1.9.0-cp314-cp314-win_amd64.whl", hash = "sha256:568288cdbfe3b4ca3ae4852cb0a439ff053dd54c841bc4995bf2b71238b5de40", size = 2177847, upload-time = "2026-07-29T19:25:19.35Z" },
{ url = "https://files.pythonhosted.org/packages/87/80/4d81577a22e6d535d1a3409f3a1c6903e09036f0e17fc47f92169dbc3501/libcst-1.9.0-cp314-cp314-win_arm64.whl", hash = "sha256:107593af46945593e7825821793393262bc4fa1d3ea24c3ed487b61269bbbdf8", size = 2058134, upload-time = "2026-07-29T19:25:20.769Z" },
{ url = "https://files.pythonhosted.org/packages/d1/7f/c3f3a0e7a1a2adaa76e815e82a7814d6bfe7d49432276bba652248c68d0b/libcst-1.9.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f6248cb07444ab9a6733a855737a9febed8b9adca51347019348b09a3ac7dfe9", size = 2036102, upload-time = "2026-07-29T19:25:22.212Z" },
{ url = "https://files.pythonhosted.org/packages/4e/af/2f5543255b2c7d749b966adeccc6bfb1652cf8b425afb913d0f3f025a865/libcst-1.9.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:496c24e0d3240bc7da45dae543aff3f5b6509978c39262d6b84ed2fb999dded2", size = 2194806, upload-time = "2026-07-29T19:25:24.017Z" },
{ url = "https://files.pythonhosted.org/packages/cb/5b/03f4cddce426d005e208b39ea7b2d456e667cdee0f1891360f0fc8430f20/libcst-1.9.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:ea490fa8540503db5f321f0268becab46eb50f710e8cec8041e241fd66f6874f", size = 2246762, upload-time = "2026-07-29T19:25:25.365Z" },
{ url = "https://files.pythonhosted.org/packages/d8/31/9d5fe1e43dc3dbcc74f70f3e0e73fcdd8d84effc1059d8b45974f0d0d2eb/libcst-1.9.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:50ab94bb2524b419056d4003032b8c67102ac800f8d85b3c4260a01746d94dbb", size = 2259633, upload-time = "2026-07-29T19:25:26.928Z" },
{ url = "https://files.pythonhosted.org/packages/a8/2b/6752b28d88c3a19b3bc0b9e1838443b6760d5c862b4f4b37955402659e24/libcst-1.9.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a2faaf92500d0226358125630f5aab4758e8aad3f2d70a10892ec3c700781a54", size = 2368043, upload-time = "2026-07-29T19:25:28.344Z" },
{ url = "https://files.pythonhosted.org/packages/e2/94/775825b2637f8ab05694b6a4b3802ae6783b4e799f9b58d2400c7e2d4369/libcst-1.9.0-cp314-cp314t-win_amd64.whl", hash = "sha256:0c7b548512db25af9c2997a95fa731bd6b6928ecbad6c0915d7482d8bb42d34f", size = 2176432, upload-time = "2026-07-29T19:25:29.921Z" },
{ url = "https://files.pythonhosted.org/packages/fb/3d/88ad67427c6fd9db929e087912b0a540e5140e5cb77e7ca4170edaac8531/libcst-1.9.0-cp314-cp314t-win_arm64.whl", hash = "sha256:497d5329345f1f5df84e41b0bbd00204b64a2fd30dfe3cfaeaebca633a31e877", size = 2052931, upload-time = "2026-07-29T19:25:31.397Z" },
{ url = "https://files.pythonhosted.org/packages/39/e4/ad790b043a38b10cea13166c8dd716654ad8b227c20f12eebf6326191cd9/libcst-1.9.0-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:a5068bf6114f6f4d79af7a6c80a28d1deb50441150ea1db13b5458ab34bec159", size = 2043987, upload-time = "2026-08-11T05:54:02.122Z" },
{ url = "https://files.pythonhosted.org/packages/15/6b/d3cd8275cc54ffc9817ade91442b3e6e9edd1a4518bd4e6dda13e3152dbe/libcst-1.9.0-cp315-cp315-manylinux_2_28_aarch64.whl", hash = "sha256:7acfd18adcdd32dcf41ce676cf121002afcbe9ad2c72dc0c18d78465beedc228", size = 2204003, upload-time = "2026-08-11T05:54:04.031Z" },
{ url = "https://files.pythonhosted.org/packages/da/62/87eddccb11d5d221d50ac4fff4b6e9b8d48c547028d01f7d0fbc5c8a1d75/libcst-1.9.0-cp315-cp315-manylinux_2_28_x86_64.whl", hash = "sha256:86361e2b426bd1b403e52375703c8b764e226e571adcb30442510710681edbf0", size = 2256053, upload-time = "2026-08-11T05:54:06.228Z" },
{ url = "https://files.pythonhosted.org/packages/18/53/a44126aeb9fca8b4e342e0cc803ea00ca8f6cd5712619a7897b3eba13797/libcst-1.9.0-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:8c14abe844bec8b021111b3985474e49f5af799c020e8e40dedcac87c97a40c5", size = 2270576, upload-time = "2026-08-11T05:54:08.01Z" },
{ url = "https://files.pythonhosted.org/packages/bb/51/3af3dd44b117d66486e0ed61e43a16b7fc8cc5c372e1dd4ca0e70b888d46/libcst-1.9.0-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:8930971d2299b7006bb5d10c10038f44efb6da89d5bca2823595e31a9cdb96af", size = 2378573, upload-time = "2026-08-11T05:54:10.093Z" },
{ url = "https://files.pythonhosted.org/packages/fc/e8/e545087d298dbf6494e84a8092f0f5dbd62eedacabd4ecd6b364367b4804/libcst-1.9.0-cp315-cp315-win_amd64.whl", hash = "sha256:5891ce9cff815077614f509e3a23888c5ddb8081d6188e8ba1172c0ccc369022", size = 2177937, upload-time = "2026-08-11T05:54:12.168Z" },
{ url = "https://files.pythonhosted.org/packages/84/17/93a00a8e03494a84db102dd0e3d35b8876b1084ca2c194b331a168d86eb1/libcst-1.9.0-cp315-cp315-win_arm64.whl", hash = "sha256:1260b5d070a3324447a53a00387225a55472a62077ce01922d30a2a78cc4b138", size = 2058633, upload-time = "2026-08-11T05:54:13.817Z" },
{ url = "https://files.pythonhosted.org/packages/d7/00/c3751b12eb81822ea0b6131d374a98bc6c024c4b9ec5f6ea8f53dc23e967/libcst-1.9.0-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:02ee2dbdb5c218116f16a021350fc267a14be205b50d81c33f5d73857ab6fbf7", size = 2036178, upload-time = "2026-08-11T05:54:15.545Z" },
{ url = "https://files.pythonhosted.org/packages/2f/12/48ff486eb5adc593f4818569e8896b74b672414ab4722a74b17e4c4cf31e/libcst-1.9.0-cp315-cp315t-manylinux_2_28_aarch64.whl", hash = "sha256:3e5b684191a0462b2d40a73261ea7f4da6a49e7a030b7e0fceca46bebb51dfe5", size = 2195496, upload-time = "2026-08-11T05:54:17.625Z" },
{ url = "https://files.pythonhosted.org/packages/51/18/b13a4669864d41a4801fed7b86ede1049dc9a1e1dde250a7ee1f9c3b1285/libcst-1.9.0-cp315-cp315t-manylinux_2_28_x86_64.whl", hash = "sha256:2b150c4f298fe54eb0fe73abf71f57db74d070796140a8c206c9615b6861f01e", size = 2245769, upload-time = "2026-08-11T05:54:19.343Z" },
{ url = "https://files.pythonhosted.org/packages/c8/c7/cf2d46744825e84afbd7228fdeeea8d23cf6c4b2074253c27efb7705c653/libcst-1.9.0-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:50b913e37187f00a6fb88962009364e1cf1b1284aa1762304f34b52b972f2218", size = 2260576, upload-time = "2026-08-11T05:54:21.444Z" },
{ url = "https://files.pythonhosted.org/packages/d1/4d/5433d3d62250b2e4325938db101766bcab2a006819684713bcccb6259a88/libcst-1.9.0-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:9f92c75283030fd58fb7d6e560168a00381e0e3368ec8a026a3ec8a828a05f93", size = 2368709, upload-time = "2026-08-11T05:54:23.276Z" },
{ url = "https://files.pythonhosted.org/packages/87/39/9f0e1690727623f99489895db0e42048a3e1e8cea0627517c593e437fd83/libcst-1.9.0-cp315-cp315t-win_amd64.whl", hash = "sha256:4adf97bb1aff8039b0bd4991e2f838be6e4fad552821b26b71a5d1a653c2582f", size = 2177866, upload-time = "2026-08-11T05:54:25.144Z" },
{ url = "https://files.pythonhosted.org/packages/cd/79/9dc7811883e67ea771057e8937bc536eb3e77f3635fc5a93cd85b6fe1ea8/libcst-1.9.0-cp315-cp315t-win_arm64.whl", hash = "sha256:8f0dd08a5773d7051e105250b2a2c73d8065ea9b2d68e7e1bdc5244660e75f93", size = 2052908, upload-time = "2026-08-11T05:54:26.835Z" },
]
[[package]]
name = "linkify-it-py"
version = "2.1.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "uc-micro-py" },
]
sdist = { url = "https://files.pythonhosted.org/packages/2e/c9/06ea13676ef354f0af6169587ae292d3e2406e212876a413bf9eece4eb23/linkify_it_py-2.1.0.tar.gz", hash = "sha256:43360231720999c10e9328dc3691160e27a718e280673d444c38d7d3aaa3b98b", size = 29158, upload-time = "2026-03-01T07:48:47.683Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b4/de/88b3be5c31b22333b3ca2f6ff1de4e863d8fe45aaea7485f591970ec1d3e/linkify_it_py-2.1.0-py3-none-any.whl", hash = "sha256:0d252c1594ecba2ecedc444053db5d3a9b7ec1b0dd929c8f1d74dce89f86c05e", size = 19878, upload-time = "2026-03-01T07:48:46.098Z" },
]
[[package]]
name = "markdown-it-py"
version = "4.2.0"
@@ -1625,6 +1780,11 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl", hash = "sha256:9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a", size = 91687, upload-time = "2026-05-07T12:08:27.182Z" },
]
[package.optional-dependencies]
linkify = [
{ name = "linkify-it-py" },
]
[[package]]
name = "markupsafe"
version = "2.1.5"
@@ -1672,15 +1832,15 @@ resolution-markers = [
"python_full_version < '3.11' and sys_platform != 'linux' and sys_platform != 'win32'",
]
dependencies = [
{ name = "contourpy", version = "1.3.2", source = { registry = "https://pypi.org/simple" } },
{ name = "cycler" },
{ name = "fonttools" },
{ name = "kiwisolver" },
{ name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" } },
{ name = "packaging" },
{ name = "pillow" },
{ name = "pyparsing" },
{ name = "python-dateutil" },
{ name = "contourpy", version = "1.3.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
{ name = "cycler", marker = "python_full_version < '3.11'" },
{ name = "fonttools", marker = "python_full_version < '3.11'" },
{ name = "kiwisolver", marker = "python_full_version < '3.11'" },
{ name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
{ name = "packaging", marker = "python_full_version < '3.11'" },
{ name = "pillow", marker = "python_full_version < '3.11'" },
{ name = "pyparsing", marker = "python_full_version < '3.11'" },
{ name = "python-dateutil", marker = "python_full_version < '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/63/1b/4be5be87d43d327a0cf4de1a56e86f7f84c89312452406cf122efe2839e6/matplotlib-3.10.9.tar.gz", hash = "sha256:fd66508e8c6877d98e586654b608a0456db8d7e8a546eb1e2600efd957302358", size = 34811233, upload-time = "2026-04-24T00:14:13.539Z" }
wheels = [
@@ -1747,23 +1907,24 @@ source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"(python_full_version >= '3.14' and sys_platform == 'linux') or (python_full_version >= '3.14' and sys_platform == 'win32')",
"(python_full_version == '3.13.*' and sys_platform == 'linux') or (python_full_version == '3.13.*' and sys_platform == 'win32')",
"python_full_version >= '3.13' and sys_platform != 'linux' and sys_platform != 'win32'",
"python_full_version >= '3.14' and sys_platform != 'linux' and sys_platform != 'win32'",
"python_full_version == '3.13.*' and sys_platform != 'linux' and sys_platform != 'win32'",
"(python_full_version == '3.12.*' and sys_platform == 'linux') or (python_full_version == '3.12.*' and sys_platform == 'win32')",
"python_full_version == '3.12.*' and sys_platform != 'linux' and sys_platform != 'win32'",
"(python_full_version == '3.11.*' and sys_platform == 'linux') or (python_full_version == '3.11.*' and sys_platform == 'win32')",
"python_full_version == '3.11.*' and sys_platform != 'linux' and sys_platform != 'win32'",
]
dependencies = [
{ name = "contourpy", version = "1.3.3", source = { registry = "https://pypi.org/simple" } },
{ name = "cycler" },
{ name = "fonttools" },
{ name = "kiwisolver" },
{ name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
{ name = "contourpy", version = "1.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
{ name = "cycler", marker = "python_full_version >= '3.11'" },
{ name = "fonttools", marker = "python_full_version >= '3.11'" },
{ name = "kiwisolver", marker = "python_full_version >= '3.11'" },
{ name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" },
{ name = "numpy", version = "2.5.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
{ name = "packaging" },
{ name = "pillow" },
{ name = "pyparsing" },
{ name = "python-dateutil" },
{ name = "packaging", marker = "python_full_version >= '3.11'" },
{ name = "pillow", marker = "python_full_version >= '3.11'" },
{ name = "pyparsing", marker = "python_full_version >= '3.11'" },
{ name = "python-dateutil", marker = "python_full_version >= '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/49/64/f9a391af28f518b11ad45a8a712353c94a0aefce09d3703200e5c54b610a/matplotlib-3.11.1.tar.gz", hash = "sha256:69647db5746941c793d6e445a4cd349323ffb87d9cc958c2ad84a659b4832d30", size = 32612045, upload-time = "2026-07-18T03:39:46.63Z" }
wheels = [
@@ -1814,6 +1975,18 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/8a/6d/69552382fcc8e93d1f2763ef2665980a900a48b7f3a4c57ed290726d1cbc/matplotlib-3.11.1-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e4b9ac2f1f607ecda2af90a5232beee2af7582fce1cc30c4b6a1b012dc21ee99", size = 10019439, upload-time = "2026-07-18T03:39:43.78Z" },
]
[[package]]
name = "mdit-py-plugins"
version = "0.6.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "markdown-it-py" },
]
sdist = { url = "https://files.pythonhosted.org/packages/59/fc/f8d0863f8862f25602c0404d75568e89fb6b4109804645e5cdfb1be5cf56/mdit_py_plugins-0.6.1.tar.gz", hash = "sha256:a2bca0f039f39dbd35fb74ae1b5f998608c437463371f0ff7f49a19a17a114d0", size = 56114, upload-time = "2026-05-13T09:03:38.91Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/a5/69/6da5581c6a7fede7dc261bf4e67d6adca4196f176b43288b55b3db395b6e/mdit_py_plugins-0.6.1-py3-none-any.whl", hash = "sha256:214c82fb2ac524472ab6a5bcab1de80f73b50443e187f401bfd77efbc7c6481d", size = 66663, upload-time = "2026-05-13T09:03:37.76Z" },
]
[[package]]
name = "mdurl"
version = "0.1.2"
@@ -2002,6 +2175,24 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/7e/82/69e539c4c2027f1e1697e09aaa2449243085a0edf81ae2c6341e84d769b6/multiprocess-0.70.19-py39-none-any.whl", hash = "sha256:0d4b4397ed669d371c81dcd1ef33fd384a44d6c3de1bd0ca7ac06d837720d3c5", size = 133477, upload-time = "2026-01-19T06:47:38.619Z" },
]
[[package]]
name = "mutmut"
version = "3.7.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "click" },
{ name = "coverage" },
{ name = "libcst" },
{ name = "pytest" },
{ name = "setproctitle" },
{ name = "textual" },
{ name = "toml", marker = "python_full_version < '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/d5/f9/a63500696f3f35c443ef566528e55630bf7e064436416278927f7bc9c408/mutmut-3.7.0.tar.gz", hash = "sha256:dc93260fabb3a6fd3693aa8d1746825885cb6f9e66c7f9cc1a0f34fc6388e14a", size = 63735, upload-time = "2026-07-31T10:52:58.876Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/93/16/93e3e6aa30e5bc4141724463ae9d9bcc283d08b02aa85dbf5a2b665f3108/mutmut-3.7.0-py3-none-any.whl", hash = "sha256:1d2f9a1bfa4a474b2213df6b17223150b492bf4a85af0eda4fb322297337fb32", size = 59070, upload-time = "2026-07-31T10:53:00.005Z" },
]
[[package]]
name = "mypy"
version = "1.13.0"
@@ -2074,7 +2265,8 @@ source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"(python_full_version >= '3.14' and sys_platform == 'linux') or (python_full_version >= '3.14' and sys_platform == 'win32')",
"(python_full_version == '3.13.*' and sys_platform == 'linux') or (python_full_version == '3.13.*' and sys_platform == 'win32')",
"python_full_version >= '3.13' and sys_platform != 'linux' and sys_platform != 'win32'",
"python_full_version >= '3.14' and sys_platform != 'linux' and sys_platform != 'win32'",
"python_full_version == '3.13.*' and sys_platform != 'linux' and sys_platform != 'win32'",
"(python_full_version == '3.12.*' and sys_platform == 'linux') or (python_full_version == '3.12.*' and sys_platform == 'win32')",
"python_full_version == '3.12.*' and sys_platform != 'linux' and sys_platform != 'win32'",
"(python_full_version == '3.11.*' and sys_platform == 'linux') or (python_full_version == '3.11.*' and sys_platform == 'win32')",
@@ -2275,7 +2467,8 @@ source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"(python_full_version >= '3.14' and sys_platform == 'linux') or (python_full_version >= '3.14' and sys_platform == 'win32')",
"(python_full_version == '3.13.*' and sys_platform == 'linux') or (python_full_version == '3.13.*' and sys_platform == 'win32')",
"python_full_version >= '3.13' and sys_platform != 'linux' and sys_platform != 'win32'",
"python_full_version >= '3.14' and sys_platform != 'linux' and sys_platform != 'win32'",
"python_full_version == '3.13.*' and sys_platform != 'linux' and sys_platform != 'win32'",
"(python_full_version == '3.12.*' and sys_platform == 'linux') or (python_full_version == '3.12.*' and sys_platform == 'win32')",
"python_full_version == '3.12.*' and sys_platform != 'linux' and sys_platform != 'win32'",
]
@@ -2377,6 +2570,7 @@ dependencies = [
[package.optional-dependencies]
dev = [
{ name = "build" },
{ name = "hypothesis" },
{ name = "mypy" },
{ name = "pytest" },
{ name = "pytest-cov" },
@@ -2392,6 +2586,9 @@ ci = [
{ name = "pip-licenses" },
{ name = "twine" },
]
quality = [
{ name = "mutmut" },
]
[package.metadata]
requires-dist = [
@@ -2400,6 +2597,7 @@ requires-dist = [
{ name = "build", marker = "extra == 'dev'", specifier = "==1.2.2.post1" },
{ name = "datasets", specifier = ">=2.14" },
{ name = "gradio", marker = "extra == 'spaces'", specifier = ">=6.7,<7.0" },
{ name = "hypothesis", marker = "extra == 'dev'", specifier = "==6.165.3" },
{ name = "matplotlib", specifier = ">=3.7" },
{ name = "mypy", marker = "extra == 'dev'", specifier = "==1.13.0" },
{ name = "numpy", specifier = ">=1.24" },
@@ -2425,6 +2623,7 @@ ci = [
{ name = "pip-licenses", specifier = "==5.5.5" },
{ name = "twine", specifier = "==7.0.0" },
]
quality = [{ name = "mutmut", specifier = "==3.7.0" }]
[[package]]
name = "orjson"
@@ -2686,6 +2885,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/2a/9a/6acfdb8d463eac7cdae7534d35d72237eca63f5fbafe797289d8a5fae447/pip_licenses-5.5.5-py3-none-any.whl", hash = "sha256:f4c4c6d9e6a03612cf59f29f19dc8ab54904d82e055b8e191498f2279a224e14", size = 23247, upload-time = "2026-03-28T22:12:54.89Z" },
]
[[package]]
name = "platformdirs"
version = "4.11.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/e5/98/0bf930c4f97d0266b58a89e36c015f56232c52b5d2f207215d48cca9e8f7/platformdirs-4.11.2.tar.gz", hash = "sha256:3a2ae5fca3520a01ab1be8b45613537f52ddf5b5f6f53d88233892dfbf0cd82d", size = 32716, upload-time = "2026-08-10T15:48:06.092Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/49/e2/4e6eee633809c376c024821b91ade709cbfd040ec53939ffbcc292aa7eee/platformdirs-4.11.2-py3-none-any.whl", hash = "sha256:7f89089b6ea71bda7962953edcf784b2e2d9d285b40ad88be2bb75c6e9d82ab4", size = 23361, upload-time = "2026-08-10T15:48:04.855Z" },
]
[[package]]
name = "pluggy"
version = "1.6.0"
@@ -3224,6 +3432,30 @@ wheels = [
{ 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]]
name = "pyyaml-ft"
version = "8.0.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/5e/eb/5a0d575de784f9a1f94e2b1288c6886f13f34185e13117ed530f32b6f8a8/pyyaml_ft-8.0.0.tar.gz", hash = "sha256:0c947dce03954c7b5d38869ed4878b2e6ff1d44b08a0d84dc83fdad205ae39ab", size = 141057, upload-time = "2025-06-10T15:32:15.613Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/68/ba/a067369fe61a2e57fb38732562927d5bae088c73cb9bb5438736a9555b29/pyyaml_ft-8.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8c1306282bc958bfda31237f900eb52c9bedf9b93a11f82e1aab004c9a5657a6", size = 187027, upload-time = "2025-06-10T15:31:48.722Z" },
{ url = "https://files.pythonhosted.org/packages/ad/c5/a3d2020ce5ccfc6aede0d45bcb870298652ac0cf199f67714d250e0cdf39/pyyaml_ft-8.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:30c5f1751625786c19de751e3130fc345ebcba6a86f6bddd6e1285342f4bbb69", size = 176146, upload-time = "2025-06-10T15:31:50.584Z" },
{ url = "https://files.pythonhosted.org/packages/e3/bb/23a9739291086ca0d3189eac7cd92b4d00e9fdc77d722ab610c35f9a82ba/pyyaml_ft-8.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3fa992481155ddda2e303fcc74c79c05eddcdbc907b888d3d9ce3ff3e2adcfb0", size = 746792, upload-time = "2025-06-10T15:31:52.304Z" },
{ url = "https://files.pythonhosted.org/packages/5f/c2/e8825f4ff725b7e560d62a3609e31d735318068e1079539ebfde397ea03e/pyyaml_ft-8.0.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cec6c92b4207004b62dfad1f0be321c9f04725e0f271c16247d8b39c3bf3ea42", size = 786772, upload-time = "2025-06-10T15:31:54.712Z" },
{ url = "https://files.pythonhosted.org/packages/35/be/58a4dcae8854f2fdca9b28d9495298fd5571a50d8430b1c3033ec95d2d0e/pyyaml_ft-8.0.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06237267dbcab70d4c0e9436d8f719f04a51123f0ca2694c00dd4b68c338e40b", size = 778723, upload-time = "2025-06-10T15:31:56.093Z" },
{ url = "https://files.pythonhosted.org/packages/86/ed/fed0da92b5d5d7340a082e3802d84c6dc9d5fa142954404c41a544c1cb92/pyyaml_ft-8.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8a7f332bc565817644cdb38ffe4739e44c3e18c55793f75dddb87630f03fc254", size = 758478, upload-time = "2025-06-10T15:31:58.314Z" },
{ url = "https://files.pythonhosted.org/packages/f0/69/ac02afe286275980ecb2dcdc0156617389b7e0c0a3fcdedf155c67be2b80/pyyaml_ft-8.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7d10175a746be65f6feb86224df5d6bc5c049ebf52b89a88cf1cd78af5a367a8", size = 799159, upload-time = "2025-06-10T15:31:59.675Z" },
{ url = "https://files.pythonhosted.org/packages/4e/ac/c492a9da2e39abdff4c3094ec54acac9747743f36428281fb186a03fab76/pyyaml_ft-8.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:58e1015098cf8d8aec82f360789c16283b88ca670fe4275ef6c48c5e30b22a96", size = 158779, upload-time = "2025-06-10T15:32:01.029Z" },
{ url = "https://files.pythonhosted.org/packages/5d/9b/41998df3298960d7c67653669f37710fa2d568a5fc933ea24a6df60acaf6/pyyaml_ft-8.0.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:e64fa5f3e2ceb790d50602b2fd4ec37abbd760a8c778e46354df647e7c5a4ebb", size = 191331, upload-time = "2025-06-10T15:32:02.602Z" },
{ url = "https://files.pythonhosted.org/packages/0f/16/2710c252ee04cbd74d9562ebba709e5a284faeb8ada88fcda548c9191b47/pyyaml_ft-8.0.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:8d445bf6ea16bb93c37b42fdacfb2f94c8e92a79ba9e12768c96ecde867046d1", size = 182879, upload-time = "2025-06-10T15:32:04.466Z" },
{ url = "https://files.pythonhosted.org/packages/9a/40/ae8163519d937fa7bfa457b6f78439cc6831a7c2b170e4f612f7eda71815/pyyaml_ft-8.0.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c56bb46b4fda34cbb92a9446a841da3982cdde6ea13de3fbd80db7eeeab8b49", size = 811277, upload-time = "2025-06-10T15:32:06.214Z" },
{ url = "https://files.pythonhosted.org/packages/f9/66/28d82dbff7f87b96f0eeac79b7d972a96b4980c1e445eb6a857ba91eda00/pyyaml_ft-8.0.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dab0abb46eb1780da486f022dce034b952c8ae40753627b27a626d803926483b", size = 831650, upload-time = "2025-06-10T15:32:08.076Z" },
{ url = "https://files.pythonhosted.org/packages/e8/df/161c4566facac7d75a9e182295c223060373d4116dead9cc53a265de60b9/pyyaml_ft-8.0.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd48d639cab5ca50ad957b6dd632c7dd3ac02a1abe0e8196a3c24a52f5db3f7a", size = 815755, upload-time = "2025-06-10T15:32:09.435Z" },
{ url = "https://files.pythonhosted.org/packages/05/10/f42c48fa5153204f42eaa945e8d1fd7c10d6296841dcb2447bf7da1be5c4/pyyaml_ft-8.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:052561b89d5b2a8e1289f326d060e794c21fa068aa11255fe71d65baf18a632e", size = 810403, upload-time = "2025-06-10T15:32:11.051Z" },
{ url = "https://files.pythonhosted.org/packages/d5/d2/e369064aa51009eb9245399fd8ad2c562bd0bcd392a00be44b2a824ded7c/pyyaml_ft-8.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:3bb4b927929b0cb162fb1605392a321e3333e48ce616cdcfa04a839271373255", size = 835581, upload-time = "2025-06-10T15:32:12.897Z" },
{ url = "https://files.pythonhosted.org/packages/c0/28/26534bed77109632a956977f60d8519049f545abc39215d086e33a61f1f2/pyyaml_ft-8.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:de04cfe9439565e32f178106c51dd6ca61afaa2907d143835d501d84703d3793", size = 171579, upload-time = "2025-06-10T15:32:14.34Z" },
]
[[package]]
name = "readme-renderer"
version = "45.0"
@@ -3478,10 +3710,10 @@ resolution-markers = [
"python_full_version < '3.11' and sys_platform != 'linux' and sys_platform != 'win32'",
]
dependencies = [
{ name = "joblib" },
{ name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" } },
{ name = "scipy", version = "1.15.3", source = { registry = "https://pypi.org/simple" } },
{ name = "threadpoolctl" },
{ name = "joblib", marker = "python_full_version < '3.11'" },
{ name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
{ name = "scipy", version = "1.15.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
{ name = "threadpoolctl", marker = "python_full_version < '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/98/c2/a7855e41c9d285dfe86dc50b250978105dce513d6e459ea66a6aeb0e1e0c/scikit_learn-1.7.2.tar.gz", hash = "sha256:20e9e49ecd130598f1ca38a1d85090e1a600147b9c02fa6f15d69cb53d968fda", size = 7193136, upload-time = "2025-09-09T08:21:29.075Z" }
wheels = [
@@ -3524,20 +3756,21 @@ source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"(python_full_version >= '3.14' and sys_platform == 'linux') or (python_full_version >= '3.14' and sys_platform == 'win32')",
"(python_full_version == '3.13.*' and sys_platform == 'linux') or (python_full_version == '3.13.*' and sys_platform == 'win32')",
"python_full_version >= '3.13' and sys_platform != 'linux' and sys_platform != 'win32'",
"python_full_version >= '3.14' and sys_platform != 'linux' and sys_platform != 'win32'",
"python_full_version == '3.13.*' and sys_platform != 'linux' and sys_platform != 'win32'",
"(python_full_version == '3.12.*' and sys_platform == 'linux') or (python_full_version == '3.12.*' and sys_platform == 'win32')",
"python_full_version == '3.12.*' and sys_platform != 'linux' and sys_platform != 'win32'",
"(python_full_version == '3.11.*' and sys_platform == 'linux') or (python_full_version == '3.11.*' and sys_platform == 'win32')",
"python_full_version == '3.11.*' and sys_platform != 'linux' and sys_platform != 'win32'",
]
dependencies = [
{ name = "joblib" },
{ name = "narwhals" },
{ name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
{ name = "joblib", marker = "python_full_version >= '3.11'" },
{ name = "narwhals", marker = "python_full_version >= '3.11'" },
{ name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" },
{ name = "numpy", version = "2.5.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
{ name = "scipy", version = "1.17.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
{ name = "scipy", version = "1.17.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" },
{ name = "scipy", version = "1.18.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
{ name = "threadpoolctl" },
{ name = "threadpoolctl", marker = "python_full_version >= '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/fa/6f/37092bdb25f712817231799fc5674d8e704066a8a70c1d2d40517e18b4ab/scikit_learn-1.9.0.tar.gz", hash = "sha256:8833266989d3a5110178a9fae30783675460724d0e1efb13b14901d2c660c557", size = 7750767, upload-time = "2026-06-02T11:54:32.706Z" }
wheels = [
@@ -3582,7 +3815,7 @@ resolution-markers = [
"python_full_version < '3.11' and sys_platform != 'linux' and sys_platform != 'win32'",
]
dependencies = [
{ name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" } },
{ name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/0f/37/6964b830433e654ec7485e45a00fc9a27cf868d622838f6b6d9c5ec0d532/scipy-1.15.3.tar.gz", hash = "sha256:eae3cf522bc7df64b42cad3925c876e1b0b6c35c1337c93e12c0f366f55b0eaf", size = 59419214, upload-time = "2025-05-08T16:13:05.955Z" }
wheels = [
@@ -3642,7 +3875,7 @@ resolution-markers = [
"python_full_version == '3.11.*' and sys_platform != 'linux' and sys_platform != 'win32'",
]
dependencies = [
{ name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" } },
{ name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/7a/97/5a3609c4f8d58b039179648e62dd220f89864f56f7357f5d4f45c29eb2cc/scipy-1.17.1.tar.gz", hash = "sha256:95d8e012d8cb8816c226aef832200b1d45109ed4464303e997c5b13122b297c0", size = 30573822, upload-time = "2026-02-23T00:26:24.851Z" }
wheels = [
@@ -3715,12 +3948,13 @@ source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"(python_full_version >= '3.14' and sys_platform == 'linux') or (python_full_version >= '3.14' and sys_platform == 'win32')",
"(python_full_version == '3.13.*' and sys_platform == 'linux') or (python_full_version == '3.13.*' and sys_platform == 'win32')",
"python_full_version >= '3.13' and sys_platform != 'linux' and sys_platform != 'win32'",
"python_full_version >= '3.14' and sys_platform != 'linux' and sys_platform != 'win32'",
"python_full_version == '3.13.*' and sys_platform != 'linux' and sys_platform != 'win32'",
"(python_full_version == '3.12.*' and sys_platform == 'linux') or (python_full_version == '3.12.*' and sys_platform == 'win32')",
"python_full_version == '3.12.*' and sys_platform != 'linux' and sys_platform != 'win32'",
]
dependencies = [
{ name = "numpy", version = "2.5.2", source = { registry = "https://pypi.org/simple" } },
{ name = "numpy", version = "2.5.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a7/25/c2700dfaf6442b4effaa91af24ebce5dc9d31bb4a69706313aae70d72cd0/scipy-1.18.0.tar.gz", hash = "sha256:67b2ad2ad54c72ca6d04975a9b2df8c3638c34ddd5b28738e94fc2b57929d378", size = 30774447, upload-time = "2026-06-19T15:01:43.456Z" }
wheels = [
@@ -3788,8 +4022,8 @@ name = "secretstorage"
version = "3.5.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "cryptography" },
{ name = "jeepney" },
{ name = "cryptography", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
{ name = "jeepney", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/1c/03/e834bcd866f2f8a49a85eaff47340affa3bfa391ee9912a952a1faa68c7b/secretstorage-3.5.0.tar.gz", hash = "sha256:f04b8e4689cbce351744d5537bf6b1329c6fc68f91fa666f60a380edddcd11be", size = 19884, upload-time = "2025-11-23T19:02:53.191Z" }
wheels = [
@@ -3805,6 +4039,90 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/6a/23/8146aad7d88f4fcb3a6218f41a60f6c2d4e3a72de72da1825dc7c8f7877c/semantic_version-2.10.0-py2.py3-none-any.whl", hash = "sha256:de78a3b8e0feda74cabc54aab2da702113e33ac9d9eb9d2389bcf1f58b7d9177", size = 15552, upload-time = "2022-05-26T13:35:21.206Z" },
]
[[package]]
name = "setproctitle"
version = "1.3.7"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/8d/48/49393a96a2eef1ab418b17475fb92b8fcfad83d099e678751b05472e69de/setproctitle-1.3.7.tar.gz", hash = "sha256:bc2bc917691c1537d5b9bca1468437176809c7e11e5694ca79a9ca12345dcb9e", size = 27002, upload-time = "2025-09-05T12:51:25.278Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/f2/48/fb401ec8c4953d519d05c87feca816ad668b8258448ff60579ac7a1c1386/setproctitle-1.3.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cf555b6299f10a6eb44e4f96d2f5a3884c70ce25dc5c8796aaa2f7b40e72cb1b", size = 18079, upload-time = "2025-09-05T12:49:07.732Z" },
{ url = "https://files.pythonhosted.org/packages/cc/a3/c2b0333c2716fb3b4c9a973dd113366ac51b4f8d56b500f4f8f704b4817a/setproctitle-1.3.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:690b4776f9c15aaf1023bb07d7c5b797681a17af98a4a69e76a1d504e41108b7", size = 13099, upload-time = "2025-09-05T12:49:09.222Z" },
{ url = "https://files.pythonhosted.org/packages/0e/f8/17bda581c517678260e6541b600eeb67745f53596dc077174141ba2f6702/setproctitle-1.3.7-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:00afa6fc507967d8c9d592a887cdc6c1f5742ceac6a4354d111ca0214847732c", size = 31793, upload-time = "2025-09-05T12:49:10.297Z" },
{ url = "https://files.pythonhosted.org/packages/27/d1/76a33ae80d4e788ecab9eb9b53db03e81cfc95367ec7e3fbf4989962fedd/setproctitle-1.3.7-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9e02667f6b9fc1238ba753c0f4b0a37ae184ce8f3bbbc38e115d99646b3f4cd3", size = 32779, upload-time = "2025-09-05T12:49:12.157Z" },
{ url = "https://files.pythonhosted.org/packages/59/27/1a07c38121967061564f5e0884414a5ab11a783260450172d4fc68c15621/setproctitle-1.3.7-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:83fcd271567d133eb9532d3b067c8a75be175b2b3b271e2812921a05303a693f", size = 34578, upload-time = "2025-09-05T12:49:13.393Z" },
{ url = "https://files.pythonhosted.org/packages/d8/d4/725e6353935962d8bb12cbf7e7abba1d0d738c7f6935f90239d8e1ccf913/setproctitle-1.3.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13fe37951dda1a45c35d77d06e3da5d90e4f875c4918a7312b3b4556cfa7ff64", size = 32030, upload-time = "2025-09-05T12:49:15.362Z" },
{ url = "https://files.pythonhosted.org/packages/67/24/e4677ae8e1cb0d549ab558b12db10c175a889be0974c589c428fece5433e/setproctitle-1.3.7-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:a05509cfb2059e5d2ddff701d38e474169e9ce2a298cf1b6fd5f3a213a553fe5", size = 33363, upload-time = "2025-09-05T12:49:16.829Z" },
{ url = "https://files.pythonhosted.org/packages/55/d4/69ce66e4373a48fdbb37489f3ded476bb393e27f514968c3a69a67343ae0/setproctitle-1.3.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:6da835e76ae18574859224a75db6e15c4c2aaa66d300a57efeaa4c97ca4c7381", size = 31508, upload-time = "2025-09-05T12:49:18.032Z" },
{ url = "https://files.pythonhosted.org/packages/4b/5a/42c1ed0e9665d068146a68326529b5686a1881c8b9197c2664db4baf6aeb/setproctitle-1.3.7-cp310-cp310-win32.whl", hash = "sha256:9e803d1b1e20240a93bac0bc1025363f7f80cb7eab67dfe21efc0686cc59ad7c", size = 12558, upload-time = "2025-09-05T12:49:19.742Z" },
{ url = "https://files.pythonhosted.org/packages/dc/fe/dd206cc19a25561921456f6cb12b405635319299b6f366e0bebe872abc18/setproctitle-1.3.7-cp310-cp310-win_amd64.whl", hash = "sha256:a97200acc6b64ec4cada52c2ecaf1fba1ef9429ce9c542f8a7db5bcaa9dcbd95", size = 13245, upload-time = "2025-09-05T12:49:21.023Z" },
{ url = "https://files.pythonhosted.org/packages/04/cd/1b7ba5cad635510720ce19d7122154df96a2387d2a74217be552887c93e5/setproctitle-1.3.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a600eeb4145fb0ee6c287cb82a2884bd4ec5bbb076921e287039dcc7b7cc6dd0", size = 18085, upload-time = "2025-09-05T12:49:22.183Z" },
{ url = "https://files.pythonhosted.org/packages/8f/1a/b2da0a620490aae355f9d72072ac13e901a9fec809a6a24fc6493a8f3c35/setproctitle-1.3.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:97a090fed480471bb175689859532709e28c085087e344bca45cf318034f70c4", size = 13097, upload-time = "2025-09-05T12:49:23.322Z" },
{ url = "https://files.pythonhosted.org/packages/18/2e/bd03ff02432a181c1787f6fc2a678f53b7dacdd5ded69c318fe1619556e8/setproctitle-1.3.7-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1607b963e7b53e24ec8a2cb4e0ab3ae591d7c6bf0a160feef0551da63452b37f", size = 32191, upload-time = "2025-09-05T12:49:24.567Z" },
{ url = "https://files.pythonhosted.org/packages/28/78/1e62fc0937a8549f2220445ed2175daacee9b6764c7963b16148119b016d/setproctitle-1.3.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a20fb1a3974e2dab857870cf874b325b8705605cb7e7e8bcbb915bca896f52a9", size = 33203, upload-time = "2025-09-05T12:49:25.871Z" },
{ url = "https://files.pythonhosted.org/packages/a0/3c/65edc65db3fa3df400cf13b05e9d41a3c77517b4839ce873aa6b4043184f/setproctitle-1.3.7-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f8d961bba676e07d77665204f36cffaa260f526e7b32d07ab3df6a2c1dfb44ba", size = 34963, upload-time = "2025-09-05T12:49:27.044Z" },
{ url = "https://files.pythonhosted.org/packages/a1/32/89157e3de997973e306e44152522385f428e16f92f3cf113461489e1e2ee/setproctitle-1.3.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:db0fd964fbd3a9f8999b502f65bd2e20883fdb5b1fae3a424e66db9a793ed307", size = 32398, upload-time = "2025-09-05T12:49:28.909Z" },
{ url = "https://files.pythonhosted.org/packages/4a/18/77a765a339ddf046844cb4513353d8e9dcd8183da9cdba6e078713e6b0b2/setproctitle-1.3.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:db116850fcf7cca19492030f8d3b4b6e231278e8fe097a043957d22ce1bdf3ee", size = 33657, upload-time = "2025-09-05T12:49:30.323Z" },
{ url = "https://files.pythonhosted.org/packages/6b/63/f0b6205c64d74d2a24a58644a38ec77bdbaa6afc13747e75973bf8904932/setproctitle-1.3.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:316664d8b24a5c91ee244460bdaf7a74a707adaa9e14fbe0dc0a53168bb9aba1", size = 31836, upload-time = "2025-09-05T12:49:32.309Z" },
{ url = "https://files.pythonhosted.org/packages/ba/51/e1277f9ba302f1a250bbd3eedbbee747a244b3cc682eb58fb9733968f6d8/setproctitle-1.3.7-cp311-cp311-win32.whl", hash = "sha256:b74774ca471c86c09b9d5037c8451fff06bb82cd320d26ae5a01c758088c0d5d", size = 12556, upload-time = "2025-09-05T12:49:33.529Z" },
{ url = "https://files.pythonhosted.org/packages/b6/7b/822a23f17e9003dfdee92cd72758441ca2a3680388da813a371b716fb07f/setproctitle-1.3.7-cp311-cp311-win_amd64.whl", hash = "sha256:acb9097213a8dd3410ed9f0dc147840e45ca9797785272928d4be3f0e69e3be4", size = 13243, upload-time = "2025-09-05T12:49:34.553Z" },
{ url = "https://files.pythonhosted.org/packages/fb/f0/2dc88e842077719d7384d86cc47403e5102810492b33680e7dadcee64cd8/setproctitle-1.3.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2dc99aec591ab6126e636b11035a70991bc1ab7a261da428491a40b84376654e", size = 18049, upload-time = "2025-09-05T12:49:36.241Z" },
{ url = "https://files.pythonhosted.org/packages/f0/b4/50940504466689cda65680c9e9a1e518e5750c10490639fa687489ac7013/setproctitle-1.3.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cdd8aa571b7aa39840fdbea620e308a19691ff595c3a10231e9ee830339dd798", size = 13079, upload-time = "2025-09-05T12:49:38.088Z" },
{ url = "https://files.pythonhosted.org/packages/d0/99/71630546b9395b095f4082be41165d1078204d1696c2d9baade3de3202d0/setproctitle-1.3.7-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2906b6c7959cdb75f46159bf0acd8cc9906cf1361c9e1ded0d065fe8f9039629", size = 32932, upload-time = "2025-09-05T12:49:39.271Z" },
{ url = "https://files.pythonhosted.org/packages/50/22/cee06af4ffcfb0e8aba047bd44f5262e644199ae7527ae2c1f672b86495c/setproctitle-1.3.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6915964a6dda07920a1159321dcd6d94fc7fc526f815ca08a8063aeca3c204f1", size = 33736, upload-time = "2025-09-05T12:49:40.565Z" },
{ url = "https://files.pythonhosted.org/packages/5c/00/a5949a8bb06ef5e7df214fc393bb2fb6aedf0479b17214e57750dfdd0f24/setproctitle-1.3.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cff72899861c765bd4021d1ff1c68d60edc129711a2fdba77f9cb69ef726a8b6", size = 35605, upload-time = "2025-09-05T12:49:42.362Z" },
{ url = "https://files.pythonhosted.org/packages/b0/3a/50caca532a9343828e3bf5778c7a84d6c737a249b1796d50dd680290594d/setproctitle-1.3.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b7cb05bd446687ff816a3aaaf831047fc4c364feff7ada94a66024f1367b448c", size = 33143, upload-time = "2025-09-05T12:49:43.515Z" },
{ url = "https://files.pythonhosted.org/packages/ca/14/b843a251296ce55e2e17c017d6b9f11ce0d3d070e9265de4ecad948b913d/setproctitle-1.3.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:3a57b9a00de8cae7e2a1f7b9f0c2ac7b69372159e16a7708aa2f38f9e5cc987a", size = 34434, upload-time = "2025-09-05T12:49:45.31Z" },
{ url = "https://files.pythonhosted.org/packages/c8/b7/06145c238c0a6d2c4bc881f8be230bb9f36d2bf51aff7bddcb796d5eed67/setproctitle-1.3.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d8828b356114f6b308b04afe398ed93803d7fca4a955dd3abe84430e28d33739", size = 32795, upload-time = "2025-09-05T12:49:46.419Z" },
{ url = "https://files.pythonhosted.org/packages/ef/dc/ef76a81fac9bf27b84ed23df19c1f67391a753eed6e3c2254ebcb5133f56/setproctitle-1.3.7-cp312-cp312-win32.whl", hash = "sha256:b0304f905efc845829ac2bc791ddebb976db2885f6171f4a3de678d7ee3f7c9f", size = 12552, upload-time = "2025-09-05T12:49:47.635Z" },
{ url = "https://files.pythonhosted.org/packages/e2/5b/a9fe517912cd6e28cf43a212b80cb679ff179a91b623138a99796d7d18a0/setproctitle-1.3.7-cp312-cp312-win_amd64.whl", hash = "sha256:9888ceb4faea3116cf02a920ff00bfbc8cc899743e4b4ac914b03625bdc3c300", size = 13247, upload-time = "2025-09-05T12:49:49.16Z" },
{ url = "https://files.pythonhosted.org/packages/5d/2f/fcedcade3b307a391b6e17c774c6261a7166aed641aee00ed2aad96c63ce/setproctitle-1.3.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c3736b2a423146b5e62230502e47e08e68282ff3b69bcfe08a322bee73407922", size = 18047, upload-time = "2025-09-05T12:49:50.271Z" },
{ url = "https://files.pythonhosted.org/packages/23/ae/afc141ca9631350d0a80b8f287aac79a76f26b6af28fd8bf92dae70dc2c5/setproctitle-1.3.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3384e682b158d569e85a51cfbde2afd1ab57ecf93ea6651fe198d0ba451196ee", size = 13073, upload-time = "2025-09-05T12:49:51.46Z" },
{ url = "https://files.pythonhosted.org/packages/87/ed/0a4f00315bc02510395b95eec3d4aa77c07192ee79f0baae77ea7b9603d8/setproctitle-1.3.7-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0564a936ea687cd24dffcea35903e2a20962aa6ac20e61dd3a207652401492dd", size = 33284, upload-time = "2025-09-05T12:49:52.741Z" },
{ url = "https://files.pythonhosted.org/packages/fc/e4/adf3c4c0a2173cb7920dc9df710bcc67e9bcdbf377e243b7a962dc31a51a/setproctitle-1.3.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a5d1cb3f81531f0eb40e13246b679a1bdb58762b170303463cb06ecc296f26d0", size = 34104, upload-time = "2025-09-05T12:49:54.416Z" },
{ url = "https://files.pythonhosted.org/packages/52/4f/6daf66394152756664257180439d37047aa9a1cfaa5e4f5ed35e93d1dc06/setproctitle-1.3.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a7d159e7345f343b44330cbba9194169b8590cb13dae940da47aa36a72aa9929", size = 35982, upload-time = "2025-09-05T12:49:56.295Z" },
{ url = "https://files.pythonhosted.org/packages/1b/62/f2c0595403cf915db031f346b0e3b2c0096050e90e0be658a64f44f4278a/setproctitle-1.3.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0b5074649797fd07c72ca1f6bff0406f4a42e1194faac03ecaab765ce605866f", size = 33150, upload-time = "2025-09-05T12:49:58.025Z" },
{ url = "https://files.pythonhosted.org/packages/a0/29/10dd41cde849fb2f9b626c846b7ea30c99c81a18a5037a45cc4ba33c19a7/setproctitle-1.3.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:61e96febced3f61b766115381d97a21a6265a0f29188a791f6df7ed777aef698", size = 34463, upload-time = "2025-09-05T12:49:59.424Z" },
{ url = "https://files.pythonhosted.org/packages/71/3c/cedd8eccfaf15fb73a2c20525b68c9477518917c9437737fa0fda91e378f/setproctitle-1.3.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:047138279f9463f06b858e579cc79580fbf7a04554d24e6bddf8fe5dddbe3d4c", size = 32848, upload-time = "2025-09-05T12:50:01.107Z" },
{ url = "https://files.pythonhosted.org/packages/d1/3e/0a0e27d1c9926fecccfd1f91796c244416c70bf6bca448d988638faea81d/setproctitle-1.3.7-cp313-cp313-win32.whl", hash = "sha256:7f47accafac7fe6535ba8ba9efd59df9d84a6214565108d0ebb1199119c9cbbd", size = 12544, upload-time = "2025-09-05T12:50:15.81Z" },
{ url = "https://files.pythonhosted.org/packages/36/1b/6bf4cb7acbbd5c846ede1c3f4d6b4ee52744d402e43546826da065ff2ab7/setproctitle-1.3.7-cp313-cp313-win_amd64.whl", hash = "sha256:fe5ca35aeec6dc50cabab9bf2d12fbc9067eede7ff4fe92b8f5b99d92e21263f", size = 13235, upload-time = "2025-09-05T12:50:16.89Z" },
{ url = "https://files.pythonhosted.org/packages/e6/a4/d588d3497d4714750e3eaf269e9e8985449203d82b16b933c39bd3fc52a1/setproctitle-1.3.7-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:10e92915c4b3086b1586933a36faf4f92f903c5554f3c34102d18c7d3f5378e9", size = 18058, upload-time = "2025-09-05T12:50:02.501Z" },
{ url = "https://files.pythonhosted.org/packages/05/77/7637f7682322a7244e07c373881c7e982567e2cb1dd2f31bd31481e45500/setproctitle-1.3.7-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:de879e9c2eab637f34b1a14c4da1e030c12658cdc69ee1b3e5be81b380163ce5", size = 13072, upload-time = "2025-09-05T12:50:03.601Z" },
{ url = "https://files.pythonhosted.org/packages/52/09/f366eca0973cfbac1470068d1313fa3fe3de4a594683385204ec7f1c4101/setproctitle-1.3.7-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c18246d88e227a5b16248687514f95642505000442165f4b7db354d39d0e4c29", size = 34490, upload-time = "2025-09-05T12:50:04.948Z" },
{ url = "https://files.pythonhosted.org/packages/71/36/611fc2ed149fdea17c3677e1d0df30d8186eef9562acc248682b91312706/setproctitle-1.3.7-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7081f193dab22df2c36f9fc6d113f3793f83c27891af8fe30c64d89d9a37e152", size = 35267, upload-time = "2025-09-05T12:50:06.015Z" },
{ url = "https://files.pythonhosted.org/packages/88/a4/64e77d0671446bd5a5554387b69e1efd915274686844bea733714c828813/setproctitle-1.3.7-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9cc9b901ce129350637426a89cfd650066a4adc6899e47822e2478a74023ff7c", size = 37376, upload-time = "2025-09-05T12:50:07.484Z" },
{ url = "https://files.pythonhosted.org/packages/89/bc/ad9c664fe524fb4a4b2d3663661a5c63453ce851736171e454fa2cdec35c/setproctitle-1.3.7-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:80e177eff2d1ec172188d0d7fd9694f8e43d3aab76a6f5f929bee7bf7894e98b", size = 33963, upload-time = "2025-09-05T12:50:09.056Z" },
{ url = "https://files.pythonhosted.org/packages/ab/01/a36de7caf2d90c4c28678da1466b47495cbbad43badb4e982d8db8167ed4/setproctitle-1.3.7-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:23e520776c445478a67ee71b2a3c1ffdafbe1f9f677239e03d7e2cc635954e18", size = 35550, upload-time = "2025-09-05T12:50:10.791Z" },
{ url = "https://files.pythonhosted.org/packages/dd/68/17e8aea0ed5ebc17fbf03ed2562bfab277c280e3625850c38d92a7b5fcd9/setproctitle-1.3.7-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5fa1953126a3b9bd47049d58c51b9dac72e78ed120459bd3aceb1bacee72357c", size = 33727, upload-time = "2025-09-05T12:50:12.032Z" },
{ url = "https://files.pythonhosted.org/packages/b2/33/90a3bf43fe3a2242b4618aa799c672270250b5780667898f30663fd94993/setproctitle-1.3.7-cp313-cp313t-win32.whl", hash = "sha256:4a5e212bf438a4dbeece763f4962ad472c6008ff6702e230b4f16a037e2f6f29", size = 12549, upload-time = "2025-09-05T12:50:13.074Z" },
{ url = "https://files.pythonhosted.org/packages/0b/0e/50d1f07f3032e1f23d814ad6462bc0a138f369967c72494286b8a5228e40/setproctitle-1.3.7-cp313-cp313t-win_amd64.whl", hash = "sha256:cf2727b733e90b4f874bac53e3092aa0413fe1ea6d4f153f01207e6ce65034d9", size = 13243, upload-time = "2025-09-05T12:50:14.146Z" },
{ url = "https://files.pythonhosted.org/packages/89/c7/43ac3a98414f91d1b86a276bc2f799ad0b4b010e08497a95750d5bc42803/setproctitle-1.3.7-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:80c36c6a87ff72eabf621d0c79b66f3bdd0ecc79e873c1e9f0651ee8bf215c63", size = 18052, upload-time = "2025-09-05T12:50:17.928Z" },
{ url = "https://files.pythonhosted.org/packages/cd/2c/dc258600a25e1a1f04948073826bebc55e18dbd99dc65a576277a82146fa/setproctitle-1.3.7-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b53602371a52b91c80aaf578b5ada29d311d12b8a69c0c17fbc35b76a1fd4f2e", size = 13071, upload-time = "2025-09-05T12:50:19.061Z" },
{ url = "https://files.pythonhosted.org/packages/ab/26/8e3bb082992f19823d831f3d62a89409deb6092e72fc6940962983ffc94f/setproctitle-1.3.7-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fcb966a6c57cf07cc9448321a08f3be6b11b7635be502669bc1d8745115d7e7f", size = 33180, upload-time = "2025-09-05T12:50:20.395Z" },
{ url = "https://files.pythonhosted.org/packages/f1/af/ae692a20276d1159dd0cf77b0bcf92cbb954b965655eb4a69672099bb214/setproctitle-1.3.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46178672599b940368d769474fe13ecef1b587d58bb438ea72b9987f74c56ea5", size = 34043, upload-time = "2025-09-05T12:50:22.454Z" },
{ url = "https://files.pythonhosted.org/packages/34/b2/6a092076324dd4dac1a6d38482bedebbff5cf34ef29f58585ec76e47bc9d/setproctitle-1.3.7-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7f9e9e3ff135cbcc3edd2f4cf29b139f4aca040d931573102742db70ff428c17", size = 35892, upload-time = "2025-09-05T12:50:23.937Z" },
{ url = "https://files.pythonhosted.org/packages/1c/1a/8836b9f28cee32859ac36c3df85aa03e1ff4598d23ea17ca2e96b5845a8f/setproctitle-1.3.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:14c7eba8d90c93b0e79c01f0bd92a37b61983c27d6d7d5a3b5defd599113d60e", size = 32898, upload-time = "2025-09-05T12:50:25.617Z" },
{ url = "https://files.pythonhosted.org/packages/ef/22/8fabdc24baf42defb599714799d8445fe3ae987ec425a26ec8e80ea38f8e/setproctitle-1.3.7-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:9e64e98077fb30b6cf98073d6c439cd91deb8ebbf8fc62d9dbf52bd38b0c6ac0", size = 34308, upload-time = "2025-09-05T12:50:26.827Z" },
{ url = "https://files.pythonhosted.org/packages/15/1b/b9bee9de6c8cdcb3b3a6cb0b3e773afdb86bbbc1665a3bfa424a4294fda2/setproctitle-1.3.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b91387cc0f02a00ac95dcd93f066242d3cca10ff9e6153de7ee07069c6f0f7c8", size = 32536, upload-time = "2025-09-05T12:50:28.5Z" },
{ url = "https://files.pythonhosted.org/packages/37/0c/75e5f2685a5e3eda0b39a8b158d6d8895d6daf3ba86dec9e3ba021510272/setproctitle-1.3.7-cp314-cp314-win32.whl", hash = "sha256:52b054a61c99d1b72fba58b7f5486e04b20fefc6961cd76722b424c187f362ed", size = 12731, upload-time = "2025-09-05T12:50:43.955Z" },
{ url = "https://files.pythonhosted.org/packages/d2/ae/acddbce90d1361e1786e1fb421bc25baeb0c22ef244ee5d0176511769ec8/setproctitle-1.3.7-cp314-cp314-win_amd64.whl", hash = "sha256:5818e4080ac04da1851b3ec71e8a0f64e3748bf9849045180566d8b736702416", size = 13464, upload-time = "2025-09-05T12:50:45.057Z" },
{ url = "https://files.pythonhosted.org/packages/01/6d/20886c8ff2e6d85e3cabadab6aab9bb90acaf1a5cfcb04d633f8d61b2626/setproctitle-1.3.7-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:6fc87caf9e323ac426910306c3e5d3205cd9f8dcac06d233fcafe9337f0928a3", size = 18062, upload-time = "2025-09-05T12:50:29.78Z" },
{ url = "https://files.pythonhosted.org/packages/9a/60/26dfc5f198715f1343b95c2f7a1c16ae9ffa45bd89ffd45a60ed258d24ea/setproctitle-1.3.7-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6134c63853d87a4897ba7d5cc0e16abfa687f6c66fc09f262bb70d67718f2309", size = 13075, upload-time = "2025-09-05T12:50:31.604Z" },
{ url = "https://files.pythonhosted.org/packages/21/9c/980b01f50d51345dd513047e3ba9e96468134b9181319093e61db1c47188/setproctitle-1.3.7-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1403d2abfd32790b6369916e2313dffbe87d6b11dca5bbd898981bcde48e7a2b", size = 34744, upload-time = "2025-09-05T12:50:32.777Z" },
{ url = "https://files.pythonhosted.org/packages/86/b4/82cd0c86e6d1c4538e1a7eb908c7517721513b801dff4ba3f98ef816a240/setproctitle-1.3.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e7c5bfe4228ea22373e3025965d1a4116097e555ee3436044f5c954a5e63ac45", size = 35589, upload-time = "2025-09-05T12:50:34.13Z" },
{ url = "https://files.pythonhosted.org/packages/8a/4f/9f6b2a7417fd45673037554021c888b31247f7594ff4bd2239918c5cd6d0/setproctitle-1.3.7-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:585edf25e54e21a94ccb0fe81ad32b9196b69ebc4fc25f81da81fb8a50cca9e4", size = 37698, upload-time = "2025-09-05T12:50:35.524Z" },
{ url = "https://files.pythonhosted.org/packages/20/92/927b7d4744aac214d149c892cb5fa6dc6f49cfa040cb2b0a844acd63dcaf/setproctitle-1.3.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:96c38cdeef9036eb2724c2210e8d0b93224e709af68c435d46a4733a3675fee1", size = 34201, upload-time = "2025-09-05T12:50:36.697Z" },
{ url = "https://files.pythonhosted.org/packages/0a/0c/fd4901db5ba4b9d9013e62f61d9c18d52290497f956745cd3e91b0d80f90/setproctitle-1.3.7-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:45e3ef48350abb49cf937d0a8ba15e42cee1e5ae13ca41a77c66d1abc27a5070", size = 35801, upload-time = "2025-09-05T12:50:38.314Z" },
{ url = "https://files.pythonhosted.org/packages/e7/e3/54b496ac724e60e61cc3447f02690105901ca6d90da0377dffe49ff99fc7/setproctitle-1.3.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:1fae595d032b30dab4d659bece20debd202229fce12b55abab978b7f30783d73", size = 33958, upload-time = "2025-09-05T12:50:39.841Z" },
{ url = "https://files.pythonhosted.org/packages/ea/a8/c84bb045ebf8c6fdc7f7532319e86f8380d14bbd3084e6348df56bdfe6fd/setproctitle-1.3.7-cp314-cp314t-win32.whl", hash = "sha256:02432f26f5d1329ab22279ff863c83589894977063f59e6c4b4845804a08f8c2", size = 12745, upload-time = "2025-09-05T12:50:41.377Z" },
{ url = "https://files.pythonhosted.org/packages/08/b6/3a5a4f9952972791a9114ac01dfc123f0df79903577a3e0a7a404a695586/setproctitle-1.3.7-cp314-cp314t-win_amd64.whl", hash = "sha256:cbc388e3d86da1f766d8fc2e12682e446064c01cea9f88a88647cfe7c011de6a", size = 13469, upload-time = "2025-09-05T12:50:42.67Z" },
{ url = "https://files.pythonhosted.org/packages/34/8a/aff5506ce89bc3168cb492b18ba45573158d528184e8a9759a05a09088a9/setproctitle-1.3.7-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:eb440c5644a448e6203935ed60466ec8d0df7278cd22dc6cf782d07911bcbea6", size = 12654, upload-time = "2025-09-05T12:51:17.141Z" },
{ url = "https://files.pythonhosted.org/packages/41/89/5b6f2faedd6ced3d3c085a5efbd91380fb1f61f4c12bc42acad37932f4e9/setproctitle-1.3.7-pp310-pypy310_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:502b902a0e4c69031b87870ff4986c290ebbb12d6038a70639f09c331b18efb2", size = 14284, upload-time = "2025-09-05T12:51:18.393Z" },
{ url = "https://files.pythonhosted.org/packages/0a/c0/4312fed3ca393a29589603fd48f17937b4ed0638b923bac75a728382e730/setproctitle-1.3.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f6f268caeabb37ccd824d749e7ce0ec6337c4ed954adba33ec0d90cc46b0ab78", size = 13282, upload-time = "2025-09-05T12:51:19.703Z" },
{ url = "https://files.pythonhosted.org/packages/c3/5b/5e1c117ac84e3cefcf8d7a7f6b2461795a87e20869da065a5c087149060b/setproctitle-1.3.7-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:b1cac6a4b0252b8811d60b6d8d0f157c0fdfed379ac89c25a914e6346cf355a1", size = 12587, upload-time = "2025-09-05T12:51:21.195Z" },
{ url = "https://files.pythonhosted.org/packages/73/02/b9eadc226195dcfa90eed37afe56b5dd6fa2f0e5220ab8b7867b8862b926/setproctitle-1.3.7-pp311-pypy311_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f1704c9e041f2b1dc38f5be4552e141e1432fba3dd52c72eeffd5bc2db04dc65", size = 14286, upload-time = "2025-09-05T12:51:22.61Z" },
{ url = "https://files.pythonhosted.org/packages/28/26/1be1d2a53c2a91ec48fa2ff4a409b395f836798adf194d99de9c059419ea/setproctitle-1.3.7-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:b08b61976ffa548bd5349ce54404bf6b2d51bd74d4f1b241ed1b0f25bce09c3a", size = 13282, upload-time = "2025-09-05T12:51:24.094Z" },
]
[[package]]
name = "setuptools"
version = "84.0.0"
@@ -3832,6 +4150,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" },
]
[[package]]
name = "sortedcontainers"
version = "2.4.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594, upload-time = "2021-05-16T22:03:42.897Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575, upload-time = "2021-05-16T22:03:41.177Z" },
]
[[package]]
name = "starlette"
version = "1.6.0"
@@ -3857,6 +4184,23 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353, upload-time = "2025-04-27T18:04:59.103Z" },
]
[[package]]
name = "textual"
version = "8.2.8"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "markdown-it-py", extra = ["linkify"] },
{ name = "mdit-py-plugins" },
{ name = "platformdirs" },
{ name = "pygments" },
{ name = "rich" },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/00/21/39a76b01bd5eea82a04baaca7580e105d8c59450df03998345bb2cfb307b/textual-8.2.8.tar.gz", hash = "sha256:3f106a9fbc73e39dd266c9712432087de78a6d644084c7c241d6a25c3169115b", size = 1860502, upload-time = "2026-06-30T06:51:24.495Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/fb/be/35261223d9416a0751cdff1c7b4a6f881387218a12d439fe22fefebc8c04/textual-8.2.8-py3-none-any.whl", hash = "sha256:267375fd402dc8d981457212efa71f0e3365fd17bba144ba9bb3ed7563cb374a", size = 731418, upload-time = "2026-06-30T06:51:26.364Z" },
]
[[package]]
name = "threadpoolctl"
version = "3.6.0"
@@ -3896,6 +4240,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/59/8c/b1c87148aa15e099243ec9f0cf9d0e970cc2234c3257d558c25a2c5304e6/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f01a9c019878532f98927d2bacb79bbb404b43d3437455522a00a30718cdedb5", size = 3373542, upload-time = "2026-01-05T10:40:52.803Z" },
]
[[package]]
name = "toml"
version = "0.10.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/be/ba/1f744cdc819428fc6b5084ec34d9b30660f6f9daaf70eead706e3203ec3c/toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f", size = 22253, upload-time = "2020-11-01T01:40:22.204Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588, upload-time = "2020-11-01T01:40:20.672Z" },
]
[[package]]
name = "tomli"
version = "2.4.1"
@@ -3964,20 +4317,21 @@ name = "torch"
version = "2.13.0"
source = { registry = "https://pypi.org/simple" }
resolution-markers = [
"python_full_version >= '3.13' and sys_platform != 'linux' and sys_platform != 'win32'",
"python_full_version >= '3.14' and sys_platform != 'linux' and sys_platform != 'win32'",
"python_full_version == '3.13.*' and sys_platform != 'linux' and sys_platform != 'win32'",
"python_full_version == '3.12.*' and sys_platform != 'linux' and sys_platform != 'win32'",
"python_full_version == '3.11.*' and sys_platform != 'linux' and sys_platform != 'win32'",
"python_full_version < '3.11' and sys_platform != 'linux' and sys_platform != 'win32'",
]
dependencies = [
{ name = "filelock" },
{ name = "fsspec" },
{ name = "jinja2" },
{ name = "networkx", version = "3.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
{ name = "networkx", version = "3.6.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
{ name = "setuptools" },
{ name = "sympy" },
{ name = "typing-extensions" },
{ name = "filelock", marker = "sys_platform != 'linux' and sys_platform != 'win32'" },
{ name = "fsspec", marker = "sys_platform != 'linux' and sys_platform != 'win32'" },
{ name = "jinja2", marker = "sys_platform != 'linux' and sys_platform != 'win32'" },
{ name = "networkx", version = "3.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' and sys_platform != 'linux' and sys_platform != 'win32'" },
{ name = "networkx", version = "3.6.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and sys_platform != 'linux' and sys_platform != 'win32'" },
{ name = "setuptools", marker = "sys_platform != 'linux' and sys_platform != 'win32'" },
{ name = "sympy", marker = "sys_platform != 'linux' and sys_platform != 'win32'" },
{ name = "typing-extensions", marker = "sys_platform != 'linux' and sys_platform != 'win32'" },
]
wheels = [
{ url = "https://files.pythonhosted.org/packages/7f/e7/19894fdb51c7dbaf94f5a79bb0871da0992e8e4241e579cb006da46d2e58/torch-2.13.0-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:94f0de129916f77b8dc2c7a8eff644cfeddfe59e39c9f55e9f6e17543410281d", size = 111178962, upload-time = "2026-07-08T16:05:49.855Z" },
@@ -4000,14 +4354,14 @@ resolution-markers = [
"(python_full_version < '3.11' and sys_platform == 'linux') or (python_full_version < '3.11' and sys_platform == 'win32')",
]
dependencies = [
{ name = "filelock" },
{ name = "fsspec" },
{ name = "jinja2" },
{ name = "networkx", version = "3.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
{ name = "networkx", version = "3.6.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
{ name = "setuptools" },
{ name = "sympy" },
{ name = "typing-extensions" },
{ name = "filelock", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
{ name = "fsspec", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
{ name = "jinja2", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
{ name = "networkx", version = "3.4.2", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version < '3.11' and sys_platform == 'linux') or (python_full_version < '3.11' and sys_platform == 'win32')" },
{ name = "networkx", version = "3.6.1", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version >= '3.11' and sys_platform == 'linux') or (python_full_version >= '3.11' and sys_platform == 'win32')" },
{ name = "setuptools", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
{ name = "sympy", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
{ name = "typing-extensions", marker = "sys_platform == 'linux' or sys_platform == 'win32'" },
]
wheels = [
{ url = "https://download-r2.pytorch.org/whl/cpu/torch-2.13.0%2Bcpu-cp310-cp310-linux_s390x.whl", hash = "sha256:0555fde6108ca90247ae33d4e1237cbae475c86a223bb2f0f91d9addf1f611bd", upload-time = "2026-07-08T19:27:11Z" },
@@ -4142,6 +4496,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/e5/6d/b53b99a9f2766d095985947a5782f1702cabb129a34f7a802d7197af832f/tzdata-2026.3-py2.py3-none-any.whl", hash = "sha256:dc096730c87af6cab1b171c9d532be840741ff5d459015e7f6947bd7d7e54931", size = 348168, upload-time = "2026-07-10T08:50:36.46Z" },
]
[[package]]
name = "uc-micro-py"
version = "2.0.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/78/67/9a363818028526e2d4579334460df777115bdec1bb77c08f9db88f6389f2/uc_micro_py-2.0.0.tar.gz", hash = "sha256:c53691e495c8db60e16ffc4861a35469b0ba0821fe409a8a7a0a71864d33a811", size = 6611, upload-time = "2026-03-01T06:31:27.526Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/61/73/d21edf5b204d1467e06500080a50f79d49ef2b997c79123a536d4a17d97c/uc_micro_py-2.0.0-py3-none-any.whl", hash = "sha256:3603a3859af53e5a39bc7677713c78ea6589ff188d70f4fee165db88e22b242c", size = 6383, upload-time = "2026-03-01T06:31:26.257Z" },
]
[[package]]
name = "urllib3"
version = "2.7.0"