diff --git a/AGENTS.md b/AGENTS.md index 69df9d8..264ee03 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -295,7 +295,7 @@ just ci # Full CI simulation (checks + tests + examples + bench co just test # Lib + doc tests (fast) just test-all # All tests (Rust, benchmark inputs, and Python) just examples # Run all examples -just update # Update dependency locks and repository-owned Cargo tools +just update # Update dependency requirements, locks, and repository-owned Cargo tools just update-version vX.Y.Z # Update release metadata without upgrading dependencies ``` diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6fb4a82..d3d5732 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -26,12 +26,12 @@ Use `just fix` when you intentionally want formatters and automatic fixes to change files. Run `just --list` for the full command surface. Use `just update` for deliberate dependency and tool maintenance. It composes -`just update-dependencies`, which advances Cargo dependency requirements and -the Cargo/uv locks, with `just update-cargo-tools`, which upgrades only the -Cargo CLI packages owned by `setup-tools` and atomically reconciles their root -`justfile` pins. The tool updater requires `cargo-install-update` from the -`cargo-update` package and does not touch unrelated Cargo executables or uv's -user-global tool environments. +`just update-dependencies`, which advances Cargo dependency requirements, exact +Python development-tool pins, and the Cargo/uv locks, with +`just update-cargo-tools`, which upgrades only the Cargo CLI packages owned by +`setup-tools` and atomically reconciles their root `justfile` pins. The tool +updater requires `cargo-install-update` from the `cargo-update` package and does +not touch unrelated Cargo executables or uv's user-global tool environments. The repository uses `cargo-nextest` for runnable Rust tests, `cargo-machete` for unused-dependency checks, and `just cargo-lock-check` to verify that the diff --git a/Cargo.lock b/Cargo.lock index 0831134..a7ae053 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -108,9 +108,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.4.3" +version = "1.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "509591b7bcd67f4ef775afad7662703b4935daaa6ec0e5605cfb1090b32a2b6d" +checksum = "0ad534f4357a5264cce5019c989cf66a4f0dc4e0d1b1d15f8aacec0ff7360273" dependencies = [ "find-msvc-tools", "shlex", diff --git a/docs/RELEASING.md b/docs/RELEASING.md index 0f10470..80aed3f 100644 --- a/docs/RELEASING.md +++ b/docs/RELEASING.md @@ -29,8 +29,9 @@ git switch main git pull --ff-only ``` -Refresh dependency requirements, lockfiles, and repository-owned Cargo tool -pins before creating the release branch: +Refresh Cargo dependency requirements, exact Python development-tool pins, +lockfiles, and repository-owned Cargo tool pins before creating the release +branch: ```bash just update diff --git a/justfile b/justfile index 6bdc62d..d0ba556 100644 --- a/justfile +++ b/justfile @@ -1084,11 +1084,20 @@ update-cargo-tools: _ensure-uv cargo install-update --locked "${packages[@]}" uv run --locked update-cargo-tool-pins -# Advance Cargo dependency declarations, update Cargo and uv locks, then sync uv dev tools. -[doc('Update Cargo.toml dependency requirements and all Cargo/uv locked dependencies.')] -update-dependencies: _ensure-uv _ensure-cargo-edit +# Advance Cargo and exact Python development requirements plus their lockfiles. +[doc('Update Cargo and Python development requirements plus all Cargo/uv locked dependencies.')] +update-dependencies: update-cargo-dependencies update-python-dependencies + +# Advance Cargo dependency declarations and lockfile entries. +[doc('Update Cargo.toml dependency requirements and Cargo.lock.')] +update-cargo-dependencies: _ensure-cargo-edit cargo upgrade cargo update + +# Resolve latest Python development tools, retain exact pins, and sync the environment. +[doc('Update exact dependency-groups.dev pins and uv.lock through uv.')] +update-python-dependencies: _ensure-uv + uv run --locked update-python-dev-pins uv lock --upgrade uv sync --locked --group dev diff --git a/pyproject.toml b/pyproject.toml index 26b6cd9..5de644d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,11 +43,12 @@ tag-release = "tag_release:main" check-docs-version-sync = "check_docs_version_sync:main" update-release-version = "update_release_version:main" update-cargo-tool-pins = "update_cargo_tool_pins:main" +update-python-dev-pins = "update_python_dev_pins:main" # Configure setuptools to find modules in scripts/ directory. [tool.setuptools] package-dir = { "" = "scripts" } -py-modules = [ "archive_changelog", "archive_performance", "bench_compare", "benchmark_contract", "check_docs_version_sync", "check_semgrep_fixtures", "criterion_dim_plot", "performance_artifacts", "postprocess_changelog", "subprocess_utils", "tag_release", "update_cargo_tool_pins", "update_release_version" ] +py-modules = [ "archive_changelog", "archive_performance", "bench_compare", "benchmark_contract", "check_docs_version_sync", "check_semgrep_fixtures", "criterion_dim_plot", "performance_artifacts", "postprocess_changelog", "subprocess_utils", "tag_release", "update_cargo_tool_pins", "update_python_dev_pins", "update_release_version" ] [tool.ruff] line-length = 160 @@ -99,6 +100,7 @@ known-first-party = [ "subprocess_utils", "tag_release", "update_cargo_tool_pins", + "update_python_dev_pins", ] force-single-line = false split-on-trailing-comma = true @@ -149,10 +151,10 @@ package = true dev = [ "actionlint-py==1.7.12.24", "pytest==9.1.1", - "ruff==0.16.2", - "semgrep==1.172.0", + "ruff==0.16.4", + "semgrep==1.174.0", "shellcheck-py==0.11.0.1", "shfmt-py==4.0.0", - "ty==0.0.69", + "ty==0.0.73", "yamllint==1.38.0", ] diff --git a/scripts/README.md b/scripts/README.md index 7c2bc64..ab03c39 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -27,9 +27,11 @@ uv sync --locked --group dev ### Updating dependencies and repository-owned tools Run `just update` for the deliberate maintenance workflow. It updates Cargo and -uv dependency declarations and locks, upgrades only the Cargo CLI packages -owned by `setup-tools`, and then uses `update-cargo-tool-pins` to reconcile the -installed package versions with the root `justfile` atomically. +exact Python development-tool declarations and their locks, upgrades only the +Cargo CLI packages owned by `setup-tools`, and then reconciles the installed +package versions with the root `justfile` atomically. The Python updater asks +uv to resolve one cross-platform tool set before applying all changed exact +pins together; it does not change runtime or build-system requirements. ## How to use it @@ -282,6 +284,7 @@ validates SemVer, and handles GitHub's 125KB tag-annotation size limit. | `postprocess_changelog.py` | Normalize and reflow generated git-cliff Markdown safely | | `subprocess_utils.py` | Safe subprocess wrappers for git commands | | `update_cargo_tool_pins.py` | Reconcile repository-owned Cargo tool pins with installed versions | +| `update_python_dev_pins.py` | Resolve and advance exact Python development-tool pins through uv | | `update_release_version.py` | Transactionally update deterministic release-version metadata | See `docs/RELEASING.md` for the full release workflow. diff --git a/scripts/postprocess_changelog.py b/scripts/postprocess_changelog.py index bea2811..662f58c 100644 --- a/scripts/postprocess_changelog.py +++ b/scripts/postprocess_changelog.py @@ -23,6 +23,7 @@ import sys from dataclasses import dataclass from pathlib import Path +from typing import cast # rumdl MD013 line-length limit used by this project. MAX_LINE_WIDTH = 160 @@ -216,17 +217,17 @@ def _squash_heading_parts(line: str) -> tuple[str, str, str] | None: if match is None: return None - raw_prefix = match.group("prefix") + raw_prefix = cast("str", match.group("prefix")) kind = re.sub(r"\([^)]+\)", "", raw_prefix).rstrip("!").casefold() label = _SQUASH_HEADING_LABELS.get(kind) if label is None: return None - title = match.group("title").strip() + title = cast("str", match.group("title")).strip() if not title: return None - return match.group("indent"), label, title[0].upper() + title[1:] + return cast("str", match.group("indent")), label, title[0].upper() + title[1:] def _normalize_squash_heading(line: str, *, nested: bool = False) -> str: @@ -678,7 +679,11 @@ def _fence_parts(line: str) -> tuple[str, str, str] | None: match = _FENCE_RE.fullmatch(line) if match is None: return None - return match.group("indent"), match.group("fence"), match.group("info") + return ( + cast("str", match.group("indent")), + cast("str", match.group("fence")), + cast("str", match.group("info")), + ) def _opening_code_fence(line: str) -> _CodeFence | None: diff --git a/scripts/subprocess_utils.py b/scripts/subprocess_utils.py index f2021d8..6b66f09 100644 --- a/scripts/subprocess_utils.py +++ b/scripts/subprocess_utils.py @@ -18,7 +18,7 @@ import subprocess import tempfile from pathlib import Path -from typing import Any +from typing import Any, cast type RunKwargs = dict[str, Any] @@ -105,10 +105,13 @@ def run_git_command( """ git_path = get_safe_executable("git") run_kwargs = _build_run_kwargs("run_git_command", **kwargs) - return subprocess.run( # noqa: S603,PLW1510 - [git_path, *args], - cwd=cwd, - **run_kwargs, + return cast( + "subprocess.CompletedProcess[str]", + subprocess.run( # noqa: S603,PLW1510 + [git_path, *args], + cwd=cwd, + **run_kwargs, + ), ) @@ -134,10 +137,13 @@ def run_cargo_command( """ cargo_path = get_safe_executable("cargo") run_kwargs = _build_run_kwargs("run_cargo_command", **kwargs) - return subprocess.run( # noqa: S603,PLW1510 - [cargo_path, *args], - cwd=cwd, - **run_kwargs, + return cast( + "subprocess.CompletedProcess[str]", + subprocess.run( # noqa: S603,PLW1510 + [cargo_path, *args], + cwd=cwd, + **run_kwargs, + ), ) @@ -165,10 +171,13 @@ def run_safe_command( """ command_path = get_safe_executable(command) run_kwargs = _build_run_kwargs(f"run_safe_command for {command}", **kwargs) - return subprocess.run( # noqa: S603,PLW1510 - [command_path, *args], - cwd=cwd, - **run_kwargs, + return cast( + "subprocess.CompletedProcess[str]", + subprocess.run( # noqa: S603,PLW1510 + [command_path, *args], + cwd=cwd, + **run_kwargs, + ), ) @@ -279,11 +288,14 @@ def run_git_command_with_input( with tempfile.TemporaryFile() as stdin: stdin.write(payload) stdin.seek(0) - return subprocess.run( # noqa: S603,PLW1510 - [git_path, *args], - cwd=cwd, - stdin=stdin, - **run_kwargs, + return cast( + "subprocess.CompletedProcess[str]", + subprocess.run( # noqa: S603,PLW1510 + [git_path, *args], + cwd=cwd, + stdin=stdin, + **run_kwargs, + ), ) diff --git a/scripts/tests/test_justfile_discoverability.py b/scripts/tests/test_justfile_discoverability.py index 50061e4..8e4db34 100644 --- a/scripts/tests/test_justfile_discoverability.py +++ b/scripts/tests/test_justfile_discoverability.py @@ -77,14 +77,17 @@ def test_update_workflow_composes_scoped_dependency_and_tool_updates() -> None: """Update recipes should cover repo state without touching unrelated global tools.""" recipes = just_recipes() update_dependencies = {dependency["recipe"] for dependency in recipes["update"]["dependencies"]} + dependency_updates = {dependency["recipe"] for dependency in recipes["update-dependencies"]["dependencies"]} assert update_dependencies == {"update-cargo-tools", "update-dependencies"} + assert dependency_updates == {"update-cargo-dependencies", "update-python-dependencies"} dependency_result = run_just("--dry-run", "update-dependencies") dependency_update = dependency_result.stdout + dependency_result.stderr assert "cargo upgrade" in dependency_update assert "cargo upgrade --incompatible allow" not in dependency_update assert "cargo update" in dependency_update + assert "update-python-dev-pins" in dependency_update assert "uv lock --upgrade" in dependency_update assert "uv sync --locked --group dev" in dependency_update assert "cargo install-update --all" not in dependency_update diff --git a/scripts/tests/test_update_python_dev_pins.py b/scripts/tests/test_update_python_dev_pins.py new file mode 100644 index 0000000..1ff027b --- /dev/null +++ b/scripts/tests/test_update_python_dev_pins.py @@ -0,0 +1,122 @@ +"""Tests for resolver-backed Python development-tool pin updates.""" + +import subprocess +from typing import TYPE_CHECKING + +import pytest + +import update_python_dev_pins + +if TYPE_CHECKING: + from pathlib import Path + + +def project_text(*requirements: str) -> str: + """Return a minimal project with exact development-tool pins.""" + rendered = "\n".join(f' "{requirement}",' for requirement in requirements) + return f"""[project] +name = "fixture" +version = "0.1.0" +requires-python = ">=3.14" + +[dependency-groups] +dev = [ +{rendered} +] +""" + + +def test_parse_project_accepts_exact_simple_dev_pins() -> None: + python_version, pins = update_python_dev_pins.parse_project(project_text("ruff==0.16.2", "semgrep==1.172.0")) + + assert python_version == "3.14" + assert pins == [ + update_python_dev_pins.DevPin("ruff", "0.16.2"), + update_python_dev_pins.DevPin("semgrep", "1.172.0"), + ] + + +def test_parse_project_rejects_non_exact_dev_requirement() -> None: + with pytest.raises(ValueError, match=r"development-tool requirements must be exact simple pins: ruff>=0\.16"): + update_python_dev_pins.parse_project(project_text("ruff>=0.16")) + + +def test_parse_resolution_preserves_direct_order_and_ignores_transitives() -> None: + pins = [ + update_python_dev_pins.DevPin("ruff", "0.16.2"), + update_python_dev_pins.DevPin("semgrep", "1.172.0"), + ] + output = "packaging==26.3\nsemgrep==1.174.0\nruff==0.16.4\nmcp==1.29.0\n" + + assert update_python_dev_pins.parse_resolution(output, pins) == [ + update_python_dev_pins.DevPin("ruff", "0.16.4"), + update_python_dev_pins.DevPin("semgrep", "1.174.0"), + ] + + +def test_parse_resolution_rejects_missing_direct_tool() -> None: + pins = [update_python_dev_pins.DevPin("semgrep", "1.172.0")] + + with pytest.raises(ValueError, match="uv resolver output omitted direct development tool: semgrep"): + update_python_dev_pins.parse_resolution("mcp==1.29.0\n", pins) + + +def test_update_dev_pins_resolves_then_applies_one_exact_transaction( + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, +) -> None: + pyproject = tmp_path / "pyproject.toml" + pyproject.write_text(project_text("ruff==0.16.2", "semgrep==1.172.0"), encoding="utf-8") + calls: list[tuple[str, list[str], dict[str, object]]] = [] + + def fake_run(command: str, args: list[str], **kwargs: object) -> subprocess.CompletedProcess[str]: + calls.append((command, args, kwargs)) + output = "ruff==0.16.4\nsemgrep==1.174.0\nmcp==1.29.0\n" if args[:2] == ["pip", "compile"] else "" + return subprocess.CompletedProcess([command, *args], 0, stdout=output, stderr="") + + monkeypatch.setattr(update_python_dev_pins, "run_safe_command", fake_run) + + changes = update_python_dev_pins.update_dev_pins(pyproject) + + assert changes == { + "ruff": ("0.16.2", "0.16.4"), + "semgrep": ("1.172.0", "1.174.0"), + } + assert calls[0] == ( + "uv", + [ + "pip", + "compile", + "-", + "--universal", + "--no-header", + "--no-annotate", + "--python-version", + "3.14", + ], + {"cwd": tmp_path, "input": "ruff\nsemgrep\n"}, + ) + assert calls[1] == ( + "uv", + ["add", "--dev", "--no-sync", "ruff==0.16.4", "semgrep==1.174.0"], + {"cwd": tmp_path}, + ) + + +def test_main_reports_uv_diagnostics_without_traceback( + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, + capsys: pytest.CaptureFixture[str], +) -> None: + pyproject = tmp_path / "pyproject.toml" + pyproject.write_text(project_text("semgrep==1.172.0"), encoding="utf-8") + + def failed_uv(_command: str, args: list[str], **_kwargs: object) -> subprocess.CompletedProcess[str]: + raise subprocess.CalledProcessError(1, ["uv", *args], stderr="resolver conflict") + + monkeypatch.setattr(update_python_dev_pins, "run_safe_command", failed_uv) + + assert update_python_dev_pins.main(["--pyproject", str(pyproject)]) == 1 + captured = capsys.readouterr() + assert captured.out == "" + assert captured.err == "failed to update Python development-tool pins: resolver conflict\n" diff --git a/scripts/update_python_dev_pins.py b/scripts/update_python_dev_pins.py new file mode 100644 index 0000000..d857e3d --- /dev/null +++ b/scripts/update_python_dev_pins.py @@ -0,0 +1,198 @@ +"""Advance exact Python development-tool pins with uv's resolver.""" + +import argparse +import re +import subprocess +import sys +import tomllib +from dataclasses import dataclass +from pathlib import Path +from typing import cast + +from subprocess_utils import ExecutableNotFoundError, run_safe_command + +EXACT_REQUIREMENT = re.compile( + r"^(?P[A-Za-z0-9][A-Za-z0-9._-]*)==(?P[^;\s]+)$", +) +RESOLVED_REQUIREMENT = re.compile( + r"^(?P[A-Za-z0-9][A-Za-z0-9._-]*)==(?P[^;\s]+)(?:\s*;\s*.+)?$", +) +PYTHON_FLOOR = re.compile(r"^>=(?P[0-9]+\.[0-9]+)$") + + +@dataclass(frozen=True) +class DevPin: + """One exact development-tool requirement.""" + + name: str + version: str + + +def canonicalize_name(name: str) -> str: + """Return the normalized distribution name used for comparisons.""" + return re.sub(r"[-_.]+", "-", name).casefold() + + +def _required_table(data: dict[str, object], name: str) -> dict[str, object]: + """Return a required TOML table with a typed failure.""" + table = data.get(name) + if not isinstance(table, dict): + msg = f"pyproject.toml must contain a [{name}] table" + raise TypeError(msg) + return cast("dict[str, object]", table) + + +def _python_floor(project: dict[str, object]) -> str: + """Return the repository's single supported Python lower bound.""" + requires_python = project.get("requires-python") + if not isinstance(requires_python, str): + msg = "project.requires-python must be a string" + raise TypeError(msg) + python_match = PYTHON_FLOOR.fullmatch(requires_python) + if python_match is None: + msg = f"expected project.requires-python to be a single lower bound, found: {requires_python}" + raise ValueError(msg) + return cast("str", python_match.group("version")) + + +def _dev_pins(groups: dict[str, object]) -> list[DevPin]: + """Return validated exact pins from dependency-groups.dev.""" + dev = groups.get("dev") + if not isinstance(dev, list): + msg = "dependency-groups.dev must be an array" + raise TypeError(msg) + if not dev: + msg = "dependency-groups.dev must be a non-empty array" + raise ValueError(msg) + + pins: list[DevPin] = [] + normalized_names: set[str] = set() + for requirement in dev: + if not isinstance(requirement, str): + msg = "dependency-groups.dev entries must be strings" + raise TypeError(msg) + requirement_match = EXACT_REQUIREMENT.fullmatch(requirement) + if requirement_match is None: + msg = f"development-tool requirements must be exact simple pins: {requirement}" + raise ValueError(msg) + pin = DevPin(requirement_match.group("name"), requirement_match.group("version")) + normalized = canonicalize_name(pin.name) + if normalized in normalized_names: + msg = f"duplicate development-tool requirement: {pin.name}" + raise ValueError(msg) + normalized_names.add(normalized) + pins.append(pin) + return pins + + +def parse_project(text: str) -> tuple[str, list[DevPin]]: + """Parse the Python floor and exact development-tool pins.""" + data = tomllib.loads(text) + return _python_floor(_required_table(data, "project")), _dev_pins(_required_table(data, "dependency-groups")) + + +def parse_resolution(output: str, pins: list[DevPin]) -> list[DevPin]: + """Extract one resolver-selected version for every direct development tool.""" + requested = {canonicalize_name(pin.name): pin.name for pin in pins} + resolved: dict[str, set[str]] = {name: set() for name in requested} + + for raw_line in output.splitlines(): + match = RESOLVED_REQUIREMENT.fullmatch(raw_line.strip()) + if match is None: + continue + normalized = canonicalize_name(match.group("name")) + if normalized in resolved: + resolved[normalized].add(match.group("version")) + + latest: list[DevPin] = [] + for pin in pins: + versions = resolved[canonicalize_name(pin.name)] + if not versions: + msg = f"uv resolver output omitted direct development tool: {pin.name}" + raise ValueError(msg) + if len(versions) != 1: + rendered = ", ".join(sorted(versions)) + msg = f"uv resolver selected multiple versions for {pin.name}: {rendered}" + raise ValueError(msg) + latest.append(DevPin(pin.name, next(iter(versions)))) + return latest + + +def resolve_latest_pins(pins: list[DevPin], python_version: str, project_root: Path) -> list[DevPin]: + """Resolve the latest cross-platform set without changing repository files.""" + requirements = "".join(f"{pin.name}\n" for pin in pins) + result = run_safe_command( + "uv", + [ + "pip", + "compile", + "-", + "--universal", + "--no-header", + "--no-annotate", + "--python-version", + python_version, + ], + cwd=project_root, + input=requirements, + ) + return parse_resolution(result.stdout, pins) + + +def update_dev_pins(pyproject: Path) -> dict[str, tuple[str, str]]: + """Resolve and apply all changed direct pins in one uv transaction.""" + python_version, current = parse_project(pyproject.read_text(encoding="utf-8")) + latest = resolve_latest_pins(current, python_version, pyproject.parent) + changes = {old.name: (old.version, new.version) for old, new in zip(current, latest, strict=True) if old.version != new.version} + if not changes: + return changes + + run_safe_command( + "uv", + ["add", "--dev", "--no-sync", *(f"{pin.name}=={pin.version}" for pin in latest)], + cwd=pyproject.parent, + ) + return changes + + +def parse_args(argv: list[str] | None = None) -> argparse.Namespace: + """Parse command-line arguments.""" + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument( + "--pyproject", + type=Path, + default=Path("pyproject.toml"), + help="project manifest containing exact dependency-groups.dev pins", + ) + return parser.parse_args(argv) + + +def _subprocess_detail(error: subprocess.CalledProcessError) -> str: + """Return captured tool diagnostics when available.""" + detail = error.stderr if isinstance(error.stderr, str) else error.stdout if isinstance(error.stdout, str) else "" + detail = detail.strip() + return cast("str", detail or str(error)) + + +def main(argv: list[str] | None = None) -> int: + """Advance exact development-tool pins and their uv lock resolution.""" + args = parse_args(argv) + try: + changes = update_dev_pins(args.pyproject) + except subprocess.CalledProcessError as error: + print(f"failed to update Python development-tool pins: {_subprocess_detail(error)}", file=sys.stderr) + return 1 + except (ExecutableNotFoundError, OSError, subprocess.TimeoutExpired, TypeError, ValueError) as error: + print(f"failed to update Python development-tool pins: {error}", file=sys.stderr) + return 1 + + if not changes: + print("Python development-tool pins are already current.") + return 0 + for name, (old_version, new_version) in changes.items(): + print(f"Updated {name}: {old_version} -> {new_version}") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/uv.lock b/uv.lock index 86ad300..83fe52f 100644 --- a/uv.lock +++ b/uv.lock @@ -474,11 +474,11 @@ dev = [ dev = [ { name = "actionlint-py", specifier = "==1.7.12.24" }, { name = "pytest", specifier = "==9.1.1" }, - { name = "ruff", specifier = "==0.16.2" }, - { name = "semgrep", specifier = "==1.172.0" }, + { name = "ruff", specifier = "==0.16.4" }, + { name = "semgrep", specifier = "==1.174.0" }, { name = "shellcheck-py", specifier = "==0.11.0.1" }, { name = "shfmt-py", specifier = "==4.0.0" }, - { name = "ty", specifier = "==0.0.69" }, + { name = "ty", specifier = "==0.0.73" }, { name = "yamllint", specifier = "==1.38.0" }, ] @@ -496,7 +496,7 @@ wheels = [ [[package]] name = "mcp" -version = "1.23.3" +version = "1.29.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, @@ -514,9 +514,9 @@ dependencies = [ { name = "typing-inspection" }, { name = "uvicorn", marker = "sys_platform != 'emscripten'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a7/a4/d06a303f45997e266f2c228081abe299bbcba216cb806128e2e49095d25f/mcp-1.23.3.tar.gz", hash = "sha256:b3b0da2cc949950ce1259c7bfc1b081905a51916fcd7c8182125b85e70825201", size = 600697, upload-time = "2025-12-09T16:04:37.351Z" } +sdist = { url = "https://files.pythonhosted.org/packages/30/d3/f9acc21dfc886e4f78e2add1a47db46ce16884346afde53f8a064c02c891/mcp-1.29.0.tar.gz", hash = "sha256:52d01f334de1868cc3bb2d6604931126a67631f99a6c5d3b82ba47290315ec36", size = 643148, upload-time = "2026-07-28T13:41:41.939Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/32/c6/13c1a26b47b3f3a3b480783001ada4268917c9f42d78a079c336da2e75e5/mcp-1.23.3-py3-none-any.whl", hash = "sha256:32768af4b46a1b4f7df34e2bfdf5c6011e7b63d7f1b0e321d0fdef4cd6082031", size = 231570, upload-time = "2025-12-09T16:04:35.56Z" }, + { url = "https://files.pythonhosted.org/packages/01/c8/248b201f6d753d69fd5d6506011abbb35a946d9142b2ae311a948fd0be3d/mcp-1.29.0-py3-none-any.whl", hash = "sha256:f5a075bb611f23d6f4d080c6a1699fa62772eebc562ba9e66b306ddde1c755f7", size = 223436, upload-time = "2026-07-28T13:41:40.337Z" }, ] [[package]] @@ -1022,27 +1022,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.16.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/73/e1/4508a569211b35599016e84ba65c1a992b7a4004b4b6c4bea02a851cba1b/ruff-0.16.2.tar.gz", hash = "sha256:c3d7828d12e8927a6fc65fe38e2c2541b9e762d360a1786d752cb1b8883b3c9c", size = 4885811, upload-time = "2026-08-07T13:31:01.432Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/14/57/db19951540f98859c956b50bdb4d31089b4d91e9f15e2968e7d5193806d5/ruff-0.16.2-py3-none-linux_armv6l.whl", hash = "sha256:3c8de4cf2181f01d57946d87d777aa52916976fc09942aed89938fab5e013318", size = 10847925, upload-time = "2026-08-07T13:30:14.468Z" }, - { url = "https://files.pythonhosted.org/packages/13/5a/995fe85a8470d3e391ac0f7fa8054bb454eaf33ee138196d6172ed1079c0/ruff-0.16.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9a48cc05c6fbc811ca81b5d7ba95375affea6582d1b8024e455e41afbbf55344", size = 11072662, upload-time = "2026-08-07T13:30:18.143Z" }, - { url = "https://files.pythonhosted.org/packages/32/53/370d767c61c71a971a4ace36703a7ecd8c393956349a7325d7fab2b56827/ruff-0.16.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:a2c0d14fcbb26c91f0f867a6dc9bd71bbc30b1b6151829c884f23faeab2e5700", size = 10566771, upload-time = "2026-08-07T13:30:20.899Z" }, - { url = "https://files.pythonhosted.org/packages/85/d6/9d96948caf5a632be62d62202d5ec914d6856f204fd79eb036e5915e79ea/ruff-0.16.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:335c621622c4650330be50842561c6586ac6971bb8ab5407fe34dcc9efb16bbe", size = 10975825, upload-time = "2026-08-07T13:30:23.517Z" }, - { url = "https://files.pythonhosted.org/packages/3b/92/ea87129b3414acb0b5770563779c51804d37ac67675c7ba35447ddb14773/ruff-0.16.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:20e66910f2c37cc753f9ef6580c914a621b80c4fa3549d3e3521e29d0f5bfc3f", size = 10649437, upload-time = "2026-08-07T13:30:26.097Z" }, - { url = "https://files.pythonhosted.org/packages/ac/43/f8f291dcd4af5bb7872b74fdfa41a7cd7c856ca1d4069670971cf1b9f5cb/ruff-0.16.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7e36fbfba65510548156902bcf1350a979a958ce0347ce0f90d73894036b39f", size = 11446761, upload-time = "2026-08-07T13:30:28.752Z" }, - { url = "https://files.pythonhosted.org/packages/71/4a/ef991fb2fcf516ab71f0808adcdd8da5e18c8cde447f4ceaf5f47a5132a5/ruff-0.16.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f0eab35f80df8f134aae5d1630e751901321d317cc8e50dc39e36fa3ed34cd12", size = 12336364, upload-time = "2026-08-07T13:30:31.468Z" }, - { url = "https://files.pythonhosted.org/packages/f3/24/f615e74f307e6ca0e56a482872477b856c70d530aa356abfb6dfe5ca8a80/ruff-0.16.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40ea8c0594feb894e89c8c61ab9c103d38b0ea72dfde6c594107147ca31b1140", size = 11630720, upload-time = "2026-08-07T13:30:34.426Z" }, - { url = "https://files.pythonhosted.org/packages/c5/d3/8ef50149e8412a77f7ab409efdef0e2b23803707a3863da4fc64cb23d459/ruff-0.16.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab3d62dde0b19facdd632008cc4827fc28ada7736c6bd35ab6f1050f0bfed53f", size = 11466130, upload-time = "2026-08-07T13:30:36.958Z" }, - { url = "https://files.pythonhosted.org/packages/dd/a7/a19334985c4dea8c381981fa252cd854c7ee52dc4b1686dc16f4a911c702/ruff-0.16.2-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:e43e1f5b8388da9eca1b9e88328d47a5cec794633ccf6f7484ac2dd15eee92c0", size = 11523634, upload-time = "2026-08-07T13:30:39.822Z" }, - { url = "https://files.pythonhosted.org/packages/6e/6c/96d192b0e742412ceda08c0a50f9669b253dde9fd6a60ea1a10c9fa79a63/ruff-0.16.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:c24788a980581e1d7ea3a0cbe4344c4fbeb0a6a9b1f4713aa46bb104f8294690", size = 10949807, upload-time = "2026-08-07T13:30:42.745Z" }, - { url = "https://files.pythonhosted.org/packages/fa/51/e26599ceca11e79ee255c7df515995561edf87e9ca1893284e44d98f5a86/ruff-0.16.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:81806b08329130005dd4a8a8394a0c9da8c6f4cafb16ba438d2a2ee6a18bedf1", size = 10646891, upload-time = "2026-08-07T13:30:45.522Z" }, - { url = "https://files.pythonhosted.org/packages/68/01/800c4b1f97bc8d7c6029e06b1f20473a3cf1e13c4933d8f3342add83fc55/ruff-0.16.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:4ce4e02bad779bef557f541a1b31f20d6abeae1cc05ed1b1ac019d4ffd1044c8", size = 11162063, upload-time = "2026-08-07T13:30:48.131Z" }, - { url = "https://files.pythonhosted.org/packages/e4/d0/1477ea50fc5a0d4b0b71d1d63d50770bdd794d90b43e37a7618e63ec9894/ruff-0.16.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e0422abdf70070255fc4073ce9dfc814cc03db577013761ddd09bc1e4a9a4fbd", size = 11556038, upload-time = "2026-08-07T13:30:50.686Z" }, - { url = "https://files.pythonhosted.org/packages/b8/76/a7776f32048d991e16d4fa8ff91790b877342d3596cc3ed04acdbf1aaedc/ruff-0.16.2-py3-none-win32.whl", hash = "sha256:bf3a63d78fb39f4bf5ac8ae52051c5520505301abe19ba4e204c453b3f09bb0b", size = 10872850, upload-time = "2026-08-07T13:30:53.471Z" }, - { url = "https://files.pythonhosted.org/packages/00/0d/929c800d920e61397d82a01b60bffc68da3052c17d31de59efaad2e4ed75/ruff-0.16.2-py3-none-win_amd64.whl", hash = "sha256:bcabe2f6d0fc7819f1431793005af4e4de7371927d037345bf941252b195b9fa", size = 12023338, upload-time = "2026-08-07T13:30:56.193Z" }, - { url = "https://files.pythonhosted.org/packages/5b/6c/93e26c22c5f78ff87363e07da49c84955affbeb1098bd1936bf3b3f293bf/ruff-0.16.2-py3-none-win_arm64.whl", hash = "sha256:d614e95cedf38a2053fd351c55b103ba30d017d61688fdbfd40ee0412852a99f", size = 11374065, upload-time = "2026-08-07T13:30:58.775Z" }, +version = "0.16.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/00/8f/d8074b1f25e003164087a8bfe79a0f1a3945135764dbb6aaab04103dcaf9/ruff-0.16.4.tar.gz", hash = "sha256:13171aa9d9af2240ee3504e639de73122c67e74036de5ba2e1d01422cd17e3dc", size = 4899731, upload-time = "2026-08-20T17:43:59.196Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ff/80/779895ef584e089d22f2c6df0d0e99a65ec2df0805f1fffd439415b8c1f0/ruff-0.16.4-py3-none-linux_armv6l.whl", hash = "sha256:df4075f71ddac40b9934af60c3ec8a53047dd5a5fdc43224e6e4e8e9a27cb6f7", size = 10006909, upload-time = "2026-08-20T17:43:16.888Z" }, + { url = "https://files.pythonhosted.org/packages/a9/e6/f553199b5e8927a05cb5c422d921fd0656b29ab976e91c44802107c6b0da/ruff-0.16.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:0c95538517af68004306b0fb3214ff2f2af67a65092aee77cd9eb86db6656604", size = 10240201, upload-time = "2026-08-20T17:43:19.337Z" }, + { url = "https://files.pythonhosted.org/packages/1c/70/4a6dc4bb34da4dee35e30f09bbd1bfbdd26f33b62fb9b8df31f08a199cd2/ruff-0.16.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:963f83df8e69e575b64d67dd447ebbc917db41a14bf38d4593a4183e7aaa8255", size = 9835122, upload-time = "2026-08-20T17:43:21.708Z" }, + { url = "https://files.pythonhosted.org/packages/24/12/c6e22d686372c15bcb7af99831f1a1be96df696491babf4f24e4f942c527/ruff-0.16.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32a5057c7ff3f6e6480a48fccfb3a412a690f48a3d03ac5cf08177d6c2da3ade", size = 9977162, upload-time = "2026-08-20T17:43:24.236Z" }, + { url = "https://files.pythonhosted.org/packages/46/49/72b10ec912f5ab5854992eaf7aa7cd36729b6937d9dc4e0fb41b3bf428ec/ruff-0.16.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b3dce8d9b0c57c265b91885a66a567d8ea1372e8eb4e250fa8e5e3f579e99cff", size = 9829789, upload-time = "2026-08-20T17:43:26.966Z" }, + { url = "https://files.pythonhosted.org/packages/fa/80/0f30e32e7f6ee26edc39075502db9d368d788a44a79b55f763eb4ab03796/ruff-0.16.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7dc651db49283c69f8e72c834eec4fe5573e4c646856aebece0ce385dceb2a80", size = 10527949, upload-time = "2026-08-20T17:43:29.384Z" }, + { url = "https://files.pythonhosted.org/packages/52/3d/86e8ad3542169e56cac3859a343afdb9df2ad54d35a59ce1e67baee83421/ruff-0.16.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3817b87dbcabc92f13b05019257c5b89b5b4d51b5fb20f56fb5235ceb723cd07", size = 11333695, upload-time = "2026-08-20T17:43:31.872Z" }, + { url = "https://files.pythonhosted.org/packages/d0/16/481c29b380c20a0054a8261066665e1b3488e23636c49d0a43e75975b9bb/ruff-0.16.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e9fce1499134b2c8c68e5166f95705a5812062bb93aacc5f9873bb1a27084bc7", size = 10727741, upload-time = "2026-08-20T17:43:34.596Z" }, + { url = "https://files.pythonhosted.org/packages/5e/b6/56bc0b8cf45b54b28b3a5e6381c8945d51b5b18adf659454c32295209a31/ruff-0.16.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2d812e482f5a7e02eee26cd73d2a37ebbdf47d795ea63ba1b89110ae93e9fb3", size = 10286522, upload-time = "2026-08-20T17:43:37.288Z" }, + { url = "https://files.pythonhosted.org/packages/e8/8b/b345b4fb110f2fbe2bd31eabd271e5e8b3b7e4ee6c0e02f2dc6be78db000/ruff-0.16.4-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:6baaf984aa7976edf93d3b627fe2d1d22ee94bbca05fa6f90fc76d73924e3454", size = 10584182, upload-time = "2026-08-20T17:43:39.984Z" }, + { url = "https://files.pythonhosted.org/packages/29/e5/827b34041c35f58774a9681a4213994c164fc987800f4dddabcf451da0bf/ruff-0.16.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:bdfcf0b28662eb890372d50f92c283bb94e67e7635ed93c7fd533970acff7b2b", size = 10134195, upload-time = "2026-08-20T17:43:42.351Z" }, + { url = "https://files.pythonhosted.org/packages/0f/10/d0bffcdd6729b87afc82ba0ef377173356a7dc8e972f5179968cf2fdf98c/ruff-0.16.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:b66b02cb9b04f537643cadf5768e5f98dc461890d530cb67113d71c8c76e605d", size = 9825821, upload-time = "2026-08-20T17:43:44.532Z" }, + { url = "https://files.pythonhosted.org/packages/f5/32/0db2a863b796ca62d83e92a07a3ccf00921b14db02059347576a2fda3d4b/ruff-0.16.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:8528bf9a4b291a60bf02ea453511e8ce6215bd2b982ee80405b66b008b6c30a0", size = 10267658, upload-time = "2026-08-20T17:43:46.989Z" }, + { url = "https://files.pythonhosted.org/packages/b2/a0/fbdeb59e48c6261f523e56c8f12e9c08fbe693786595cc7e3959207a9232/ruff-0.16.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:fbd85d2875fdd67e833213a651f613bbf25303abf6aa822a5121f4531195678d", size = 10697071, upload-time = "2026-08-20T17:43:49.891Z" }, + { url = "https://files.pythonhosted.org/packages/aa/28/0c6dd865859c6d17bc8ccc34cb72b0e02d6c7eb25e8a1e22b5bea681e2c0/ruff-0.16.4-py3-none-win32.whl", hash = "sha256:312769988007aaeb8e189b443ccdd03c0e6374489e053467be6d96518ebff76e", size = 10021687, upload-time = "2026-08-20T17:43:52.281Z" }, + { url = "https://files.pythonhosted.org/packages/a3/03/e724450f621698117f9aa6dd241c94d0274ae96781378dc86745ae29f0e7/ruff-0.16.4-py3-none-win_amd64.whl", hash = "sha256:05d9d27a18c4bcbefada602480ec9e01e0bc949d432e0ced5df77edac195919c", size = 10567657, upload-time = "2026-08-20T17:43:54.78Z" }, + { url = "https://files.pythonhosted.org/packages/0e/fe/da8b9e1347696bb22120b77280ec5ce25d500ca5cb39d5ad6e5c18de19c1/ruff-0.16.4-py3-none-win_arm64.whl", hash = "sha256:a3a61621c9b6f6a89573e938a080e648f1695baa3f58570a3a707bc51ff65a21", size = 10451579, upload-time = "2026-08-20T17:43:57.135Z" }, ] [[package]] @@ -1056,7 +1056,7 @@ wheels = [ [[package]] name = "semgrep" -version = "1.172.0" +version = "1.174.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, @@ -1087,15 +1087,15 @@ dependencies = [ { name = "urllib3" }, { name = "wcmatch" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/16/a3/5fb66c45b192916656884b6cc47c517f71c332bb4f66c9a7e5a4eaad21ad/semgrep-1.172.0.tar.gz", hash = "sha256:7377cc350c64c7b83de20090cb2843d875da1d806690fd604e446ed544b56d71", size = 499524, upload-time = "2026-07-28T22:41:36.122Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e2/11/6066e752cf787fbff0374babc0faeddbfc9f114c3cc2c06d191fb05719e7/semgrep-1.174.0.tar.gz", hash = "sha256:8a1186609756ca679348b175ad92e27620c1d575754db6fc91aa722e54bb4bd4", size = 507637, upload-time = "2026-08-20T15:59:03.663Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/58/7b/ac982bfb94cbc94da4b4144f538dc30b4c124ef970292b5c360785b44788/semgrep-1.172.0-cp310.cp311.cp312.cp313.cp314.py310.py311.py312.py313.py314-none-macosx_10_14_x86_64.whl", hash = "sha256:7bcac633a0ffb7dfe75b7b99e44876f839590f2c01cd159c44caecc35e591df4", size = 45329663, upload-time = "2026-07-28T22:43:21.167Z" }, - { url = "https://files.pythonhosted.org/packages/7c/f9/53ce7d543898b7f4da49e6f97471cbd80a91620c0111d26e3f6b741c6f20/semgrep-1.172.0-cp310.cp311.cp312.cp313.cp314.py310.py311.py312.py313.py314-none-macosx_11_0_arm64.whl", hash = "sha256:09e92c9e6c1635a1549d4e297b2d4a9684dcd351b216ed7f2eb51cfc55479c49", size = 49305567, upload-time = "2026-07-28T22:43:25.348Z" }, - { url = "https://files.pythonhosted.org/packages/1b/45/35488f2f609db23eed350ada093722484a6f8cb3b1eaf8ecfd54e2338521/semgrep-1.172.0-cp310.cp311.cp312.cp313.cp314.py310.py311.py312.py313.py314-none-manylinux_2_34_aarch64.whl", hash = "sha256:c881a305b965e594b88b15c2c6419b398e76e438ec61e60916c8b2effe927240", size = 71707066, upload-time = "2026-07-28T22:43:29.623Z" }, - { url = "https://files.pythonhosted.org/packages/84/a5/21624510b65271a673961a894af7511b5123d662e84c74c765560ea28b27/semgrep-1.172.0-cp310.cp311.cp312.cp313.cp314.py310.py311.py312.py313.py314-none-manylinux_2_34_x86_64.whl", hash = "sha256:d8b94af4266a575287ad2cd844573743ab4fe58f6bfb6d9229327807937eade3", size = 69575334, upload-time = "2026-07-28T22:43:34.598Z" }, - { url = "https://files.pythonhosted.org/packages/39/5a/625d5b736e386cec4a7cc8cdf79bdf3ef00d24b668f656373a2282ba9b31/semgrep-1.172.0-cp310.cp311.cp312.cp313.cp314.py310.py311.py312.py313.py314-none-musllinux_1_2_aarch64.whl", hash = "sha256:8ba0d661c8cb3a451b27d4300b2d958483d6761262ce84e4dd5ff4f94e700346", size = 78491563, upload-time = "2026-07-28T22:43:40.194Z" }, - { url = "https://files.pythonhosted.org/packages/97/1a/b08bc7644ece6700f4ccce24630ffb9cd01d25a7473ace69c62df599e985/semgrep-1.172.0-cp310.cp311.cp312.cp313.cp314.py310.py311.py312.py313.py314-none-musllinux_1_2_x86_64.whl", hash = "sha256:f13ddebc870e784b03c9247f095720f49f67244eca1e7da493364f55c65b4493", size = 75992900, upload-time = "2026-07-28T22:43:45.91Z" }, - { url = "https://files.pythonhosted.org/packages/8d/2b/db00aa8b50d4a3172f7d1a90005d359875004cf840b50db4b8606845453b/semgrep-1.172.0-cp310.cp311.cp312.cp313.cp314.py310.py311.py312.py313.py314-none-win_amd64.whl", hash = "sha256:e32868faeb67b241bbd3fabd82a12fba4b467464dedde9da285b9bf78e808ba3", size = 57257253, upload-time = "2026-07-28T22:43:51.309Z" }, + { url = "https://files.pythonhosted.org/packages/f7/16/cfee78fe14b4903981d8f4393a1671e7c97db65f2da3ad33304713bc9af6/semgrep-1.174.0-cp310.cp311.cp312.cp313.cp314.py310.py311.py312.py313.py314-none-macosx_10_14_x86_64.whl", hash = "sha256:f7ddf897bc00bd8531550e286ec3f62e87555902188c2aad6c175e8dccd17878", size = 45483323, upload-time = "2026-08-20T16:01:12.255Z" }, + { url = "https://files.pythonhosted.org/packages/d3/aa/27825ca89b255be1407c68ba84d3e3f3e21a72f433dd0d392b27be157f4d/semgrep-1.174.0-cp310.cp311.cp312.cp313.cp314.py310.py311.py312.py313.py314-none-macosx_11_0_arm64.whl", hash = "sha256:a7904f5556f827d95cce7ebd3ce2e79b4f6f511317c34ffaab389064a9102db4", size = 49480382, upload-time = "2026-08-20T16:01:17.424Z" }, + { url = "https://files.pythonhosted.org/packages/7d/db/5a9f87de501e31900d2eb0cb32b26bf86380242dc90f54685b194b07acac/semgrep-1.174.0-cp310.cp311.cp312.cp313.cp314.py310.py311.py312.py313.py314-none-manylinux_2_34_aarch64.whl", hash = "sha256:5d9f3f3f59a661a4ad4666bdbc4c0e74ee02a19103280c6dec9f138162e8d8b0", size = 71953648, upload-time = "2026-08-20T16:01:24.418Z" }, + { url = "https://files.pythonhosted.org/packages/f9/1d/e1fd6313ecd860b2983456b2b20b7efe4cd7f301eafaaca7a765c7049afa/semgrep-1.174.0-cp310.cp311.cp312.cp313.cp314.py310.py311.py312.py313.py314-none-manylinux_2_34_x86_64.whl", hash = "sha256:f974909997147387e5413aaf1b68f0bf67895213aa6ba92e1284d52736f62ea3", size = 69809451, upload-time = "2026-08-20T16:01:31.124Z" }, + { url = "https://files.pythonhosted.org/packages/27/a9/c7b0576c25d4c73e16cbf10f94194bdf717d070641c2c2ab9f76db1b4ef0/semgrep-1.174.0-cp310.cp311.cp312.cp313.cp314.py310.py311.py312.py313.py314-none-musllinux_1_2_aarch64.whl", hash = "sha256:4f916a51f71e2ac37852830f8003af0d0c484c53ce480e6ec96c7a60d092d536", size = 78763775, upload-time = "2026-08-20T16:01:40.258Z" }, + { url = "https://files.pythonhosted.org/packages/a2/fc/91ce16a505ce29fd13f5cbc60cd125e8bddfeabd1d04f237261493985bec/semgrep-1.174.0-cp310.cp311.cp312.cp313.cp314.py310.py311.py312.py313.py314-none-musllinux_1_2_x86_64.whl", hash = "sha256:bbf20fdae8d6776a0afa3afe2aa20f07e8a24a86b3cd89b70b8b85a468e5dd24", size = 76267856, upload-time = "2026-08-20T16:01:49.222Z" }, + { url = "https://files.pythonhosted.org/packages/a8/04/107603788e681950e1f7a9ba1f7b3322072d86a88ce9892bd66e3134262f/semgrep-1.174.0-cp310.cp311.cp312.cp313.cp314.py310.py311.py312.py313.py314-none-win_amd64.whl", hash = "sha256:e2af9221646c1c6f4f5af543176319d3363ba44ccc977d346c3b3d0156ba51b1", size = 57443707, upload-time = "2026-08-20T16:01:56.888Z" }, ] [[package]] @@ -1177,27 +1177,27 @@ wheels = [ [[package]] name = "ty" -version = "0.0.69" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/5b/7a618632dfe9373b7df572ecd7a08c8f799d772fbc317da82dd3aa363207/ty-0.0.69.tar.gz", hash = "sha256:b65106e9ff24fa76e25e1142fb09c85244e815c40450e3021d2bf652c231bb43", size = 6565094, upload-time = "2026-08-06T10:04:25.667Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/06/60/6534092f4d2c15e2491807edd609c2e50d527c1fed957acf40b9f110b64a/ty-0.0.69-py3-none-linux_armv6l.whl", hash = "sha256:98bfd383b273540829af673e7f98b9c1c4bcc8547d12a1a3806cd0bec7f0e087", size = 12364185, upload-time = "2026-08-06T10:03:47.137Z" }, - { url = "https://files.pythonhosted.org/packages/34/2b/5c29689bd4f74c2e3394d983d85e4011b629f2ce3730c9442553b8554bf8/ty-0.0.69-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:964621ddd05771660017c51b4e74078d861d9fc863c21ef2a500db1ab62c9ccf", size = 12042510, upload-time = "2026-08-06T10:03:49.481Z" }, - { url = "https://files.pythonhosted.org/packages/09/46/fa085bde4d23516d7ef14b24736fc5dd7dc498f60f52b3d077e59ffdea20/ty-0.0.69-py3-none-macosx_11_0_arm64.whl", hash = "sha256:3ffea4048dd0da4c9c97393b4be0901098a9065b06fa81be2477cbde65d8a151", size = 11549397, upload-time = "2026-08-06T10:03:51.747Z" }, - { url = "https://files.pythonhosted.org/packages/25/cc/97b9efb2061dcab6fef1e94a4ad99df0bb45bd2cc15d4f5794c787ee0552/ty-0.0.69-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a8684d4a70aadd1eab0f41bdba835e3288ef49db8402a8e6ca81bab52ed5d610", size = 12115567, upload-time = "2026-08-06T10:03:53.79Z" }, - { url = "https://files.pythonhosted.org/packages/e0/c1/a5e0404965093835f3e62544e661784ec0aa8ef0b006ed50af50b19c107e/ty-0.0.69-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:afaaba240ab4122e2069a796836d10be81b4ddb053ae268b3dff962a0b4ca5c7", size = 12149770, upload-time = "2026-08-06T10:03:55.993Z" }, - { url = "https://files.pythonhosted.org/packages/e2/39/8cad6b205a4abe8a044ca0c84aea71e8ccda29b07a75a5f090e310605580/ty-0.0.69-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11ea63ef07d4e33aeb1a775cf5f2c736b3ed22fa6f8b1b608591612c36795044", size = 12941278, upload-time = "2026-08-06T10:03:58.324Z" }, - { url = "https://files.pythonhosted.org/packages/d6/8b/8766d96b732c2a060d70dc8ccafcc4d6a54109a2a95f1deb0705de88892b/ty-0.0.69-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cb3730b1268e92a2907d7aea3afe8dd1b360ae65862f0557080cf479d481b424", size = 13426509, upload-time = "2026-08-06T10:04:00.621Z" }, - { url = "https://files.pythonhosted.org/packages/02/1f/e991b2cde953ea5b94d6a9a4c45c87937bd916bc09235f764407bf471c0a/ty-0.0.69-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a544ff57a752ef186ed40b5a2f44c17402af4cdefeb74a311ca02ebd57c4fca0", size = 13106582, upload-time = "2026-08-06T10:04:02.818Z" }, - { url = "https://files.pythonhosted.org/packages/ea/bb/73538f1b99e3558fd9db87b98698426f0f60fc8666da0b1efd0e70e275eb/ty-0.0.69-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87ed2cbca20caddfdf8e3e14d213ce91b67e75feed78900f4aaf3ef884954028", size = 12708931, upload-time = "2026-08-06T10:04:05.233Z" }, - { url = "https://files.pythonhosted.org/packages/87/cd/484a5208d74c4ad1155933906295ccdce9aa81a257d8df2ab9e41bd60133/ty-0.0.69-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:2684efcbce5b6fe45045faf610b377b50781b6d2aa7e61ea23ecf5b3d2bce421", size = 12985322, upload-time = "2026-08-06T10:04:07.587Z" }, - { url = "https://files.pythonhosted.org/packages/6e/81/b75003f0d4da9ab3bc8fd4f4802f836cb9921ff7e70f460604f7b769a0b5/ty-0.0.69-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:da9aeb26fdac1d2214937542b59e0d4d1ba94ec7a3f45444f33c846de1eb1d63", size = 12063910, upload-time = "2026-08-06T10:04:09.835Z" }, - { url = "https://files.pythonhosted.org/packages/8a/76/088469f547ef63dceefc4a75826aedee5014f9371dc5171cde931896a82c/ty-0.0.69-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:00e7677cd14ede381f705f71104ea7b8ea0ce217a8634e19a89781953de0e9ad", size = 12166823, upload-time = "2026-08-06T10:04:12.114Z" }, - { url = "https://files.pythonhosted.org/packages/0a/c9/ce88a0bec0d46d8ae180b99c6ec014866fecc4cba1727b5feec8877b2765/ty-0.0.69-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d91965eb799649833d0d6042db09cd03d15289125245337cc46a2606effb7bda", size = 12483136, upload-time = "2026-08-06T10:04:14.33Z" }, - { url = "https://files.pythonhosted.org/packages/63/9e/6fae0ff225a0012642cf72c077e20f8f448c0a80771bc3360e8178fe2f32/ty-0.0.69-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1f03359cd8e5c412aa0c181118fa9b9061a4dddaedbb61bac0a424fb0814d402", size = 12799025, upload-time = "2026-08-06T10:04:16.445Z" }, - { url = "https://files.pythonhosted.org/packages/e4/43/78a658d18b2a4ccf35b053392f2213bf12e3c63b2abea512d3b6751d1f4c/ty-0.0.69-py3-none-win32.whl", hash = "sha256:ec460e01586b1eb91894c4a8403bee3e045a47e7a4ada943cc27ce8e348e88cf", size = 11787774, upload-time = "2026-08-06T10:04:18.622Z" }, - { url = "https://files.pythonhosted.org/packages/3a/5e/88db1f674403f2b81316a853a44a81ed220621fa96f8f7ae586fb6ca7513/ty-0.0.69-py3-none-win_amd64.whl", hash = "sha256:18976ca26a4e28fc3249477f79a695d5502e670803f2e080d89ac905baef3c6e", size = 12864038, upload-time = "2026-08-06T10:04:20.748Z" }, - { url = "https://files.pythonhosted.org/packages/4d/7b/6fc6efd00c69103d70f2bdbe824343089cd70b17b3079170057d3e5a3ac0/ty-0.0.69-py3-none-win_arm64.whl", hash = "sha256:7d4ca3bb74d91cb9947ba3f3b4cb131ad6a2b3ecc76d34040c4ec6092d2e411d", size = 12196693, upload-time = "2026-08-06T10:04:22.902Z" }, +version = "0.0.73" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e5/90/c4e1bb4cead3b644c3e258a27f9b05c7dc5eb0ec96a4f5282194edae9e0d/ty-0.0.73.tar.gz", hash = "sha256:823d4ce0d237bfc7eb6bcee70842f2c0706113813a16951077840743712f4b74", size = 6712739, upload-time = "2026-08-19T03:12:43.381Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e4/0f/f5e1801e55cc631f2db193276675b30561b963a2403da832bffb5d100267/ty-0.0.73-py3-none-linux_armv6l.whl", hash = "sha256:90a946082bf9bc446b5e72973d9f4ff1222a240b2ca4c9e6eed61eb913e30810", size = 12715452, upload-time = "2026-08-19T03:12:06.673Z" }, + { url = "https://files.pythonhosted.org/packages/54/32/515dd05074c213b433524ab97eb003b0132ae7e358e0d75633ba7a314ed8/ty-0.0.73-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b7d6b5c6a6db7ea95fbbc16af514ef44a27a29a2fe1dc798900790364d170209", size = 12301870, upload-time = "2026-08-19T03:12:08.924Z" }, + { url = "https://files.pythonhosted.org/packages/50/4d/085b4889f0d4bbe4af8b96242d4a1cb209fff95967cfa239ea141983719b/ty-0.0.73-py3-none-macosx_11_0_arm64.whl", hash = "sha256:dd6f657f463e01372d8688f235be164750c8db722c97da27fa4903aa8d40b203", size = 12111741, upload-time = "2026-08-19T03:12:11.067Z" }, + { url = "https://files.pythonhosted.org/packages/95/f6/d6ec277cadfecf03ad4c18551b67c4c6eb7807a0560d801db14be99d7a89/ty-0.0.73-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc2de468e33fd44c9ff1c43473a7316f4289480f5cba8995a67b6d22aee39ca9", size = 12196124, upload-time = "2026-08-19T03:12:13.14Z" }, + { url = "https://files.pythonhosted.org/packages/75/b7/ce78d8707563af9cae9bbd25328bfbc4931035085bd20089adf0c418f70e/ty-0.0.73-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2942fa0ef795a66034cdc8d75a72f453442f3b58ff2f69b4da05b7b954765b55", size = 12488557, upload-time = "2026-08-19T03:12:15.252Z" }, + { url = "https://files.pythonhosted.org/packages/d8/e8/329b9851b23502758c5c98e8cc875ea2a1b4c9674b4ca3a86da56a5063d3/ty-0.0.73-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e0f1ef14f642e18ac4e7a616a2796dcf7a5d82e28cd17f9796494acc7c4aabb", size = 13215606, upload-time = "2026-08-19T03:12:17.225Z" }, + { url = "https://files.pythonhosted.org/packages/36/38/67fedfd2cb77516ef0066b1642f487dba0eb3006493cf3475b15f5b8b228/ty-0.0.73-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16981e15fdceedb37d0aff76c5ac25914595dfee2675af95335550064251ad22", size = 13665497, upload-time = "2026-08-19T03:12:19.286Z" }, + { url = "https://files.pythonhosted.org/packages/8e/b3/154f4dd48ec5eebc186ab4b822c6e62f982fc5ddfd262d6e3903c2acba44/ty-0.0.73-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:644b2bec8a2e2e4957a942ae81d6cff5571c489bb5a8675e4d3886de537a694d", size = 13351231, upload-time = "2026-08-19T03:12:21.353Z" }, + { url = "https://files.pythonhosted.org/packages/35/5f/d462496903fbe453fb76363f8478be929c8e6ff21e6928c57dcd7e5fa21f/ty-0.0.73-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:338d565be3186f50ff8e9d10483685549c2d23f0754485d5ede3b54f4319188a", size = 12782586, upload-time = "2026-08-19T03:12:23.667Z" }, + { url = "https://files.pythonhosted.org/packages/87/52/ec6d24b74abe3ec324204c1c71e6d0c6c76a17ffc15fd51d603b0a302abe/ty-0.0.73-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:11c7b6d839309d2c102cb3a4c03d817176bbfab5b2fccc95a75ec5c9597421c9", size = 13247134, upload-time = "2026-08-19T03:12:25.956Z" }, + { url = "https://files.pythonhosted.org/packages/26/20/cc74650fec56a54786c6d7c89e09576fcad3092be34cf21715d39a406a9b/ty-0.0.73-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:488572db7ff97fb50ea36a76250f2d617c9727d143da6c7bf0623276eb0fc507", size = 12309344, upload-time = "2026-08-19T03:12:28.122Z" }, + { url = "https://files.pythonhosted.org/packages/89/bd/4b0a9087f4315d7fbadf77a3ce44c816cc9ffabed1ced06cc5be81fbc414/ty-0.0.73-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:1b958ebceefbbf594e59eb8d3d55bbd033ce634026fcba3e4bc3179e78e45bb7", size = 12502319, upload-time = "2026-08-19T03:12:30.128Z" }, + { url = "https://files.pythonhosted.org/packages/11/80/0a925074911fe111912ea29d9eed309bcc183f43d2fb3eef07db056a0beb/ty-0.0.73-py3-none-musllinux_1_2_i686.whl", hash = "sha256:91a32993b3c34e42c3f323ad6c0399cb596bd1c27e9b7f20db7cd64c1067b68e", size = 12753688, upload-time = "2026-08-19T03:12:32.433Z" }, + { url = "https://files.pythonhosted.org/packages/24/6b/aeccaf89efbc2e112bd415340a22e2669ec998aa397242503e747b712ca4/ty-0.0.73-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:bab8a19fbf51f479bddb2a12c5fabfe52f918a5590362321ed5d89b44eb62c15", size = 13069050, upload-time = "2026-08-19T03:12:35.398Z" }, + { url = "https://files.pythonhosted.org/packages/d7/3e/eae485fd86c1585943fd4e1746b0757b2da01e2c43136ebe8c686fe1c7f1/ty-0.0.73-py3-none-win32.whl", hash = "sha256:03347a612f0fa020b19bfd8dbd521db6ecc75d377a3e4d4f6e6c2e62871da4cc", size = 12053187, upload-time = "2026-08-19T03:12:37.565Z" }, + { url = "https://files.pythonhosted.org/packages/a7/01/9b8b983786e3ce34924e372e8b76b92b508273ab65c589fc7e88cc03ee17/ty-0.0.73-py3-none-win_amd64.whl", hash = "sha256:cedd05122ded0b5dcc55431a370e974b747f99c41c290a3d2ab8c1867f197519", size = 12693838, upload-time = "2026-08-19T03:12:39.483Z" }, + { url = "https://files.pythonhosted.org/packages/ea/88/25333bbfea6a5dc064371d2002d3d4807db90b84d5448f9106b2712b0fbc/ty-0.0.73-py3-none-win_arm64.whl", hash = "sha256:e47068f8369dea5d641a26a2ad0a947a320b02ff87099b07e95de0323245a4dc", size = 12443573, upload-time = "2026-08-19T03:12:41.449Z" }, ] [[package]]