Files
StarPilot/scripts/lint/check_dependencies.py
T
firestar5683 694b460f80 Developer Tools
Provide laptop and device build entry points, cache compatibility checks and developer tooling. Keep distribution assets and model packaging available before runtime consumers.

Co-authored-by: Danny <dannyirwin31@yahoo.com>
Co-authored-by: Prabhaav Pillai <prabhaav@msu.edu>
Co-authored-by: dirwin31 <83434411+dirwin31@users.noreply.github.com>
Co-authored-by: firestarsdog <229254897+firestarsdog@users.noreply.github.com>

Co-authored-by: prabhaavp <prabhaav@msu.edu>
2026-10-14 20:02:39 -05:00

86 lines
3.6 KiB
Python
Executable File

#!/usr/bin/env python3
import sys
import tomllib
import importlib.metadata
from pathlib import Path
# Jetlink is shipped as pinned source and uses the existing NumPy dependency.
# One supported SDK preserves structured Bugsink crashes; transitives exist already.
DIRECT_LIMITS = {"baseline": 39, "dev": 3, "safety": 5}
TOOLING_PACKAGES = frozenset({
"colorlog", "cppcheck", "execnet", "gcovr", "iniconfig", "jinja2", "lxml", "markupsafe",
"pluggy", "pygments", "pytest", "pytest-mock", "pytest-xdist", "tree-sitter", "tree-sitter-c",
})
BASELINE_INSTALLED_LIMIT = 65
TOOLING_INSTALLED_LIMIT = 15
def direct_dependency_counts(project: dict) -> dict[str, int]:
extras = project["optional-dependencies"]
return {
"baseline": len(project["dependencies"]) + sum(len(deps) for name, deps in extras.items() if name not in ("dev", "safety")),
"dev": len(extras.get("dev", ())),
"safety": len(extras.get("safety", ())),
}
def direct_dependencies_within_limits(project: dict) -> bool:
counts = direct_dependency_counts(project)
return all(counts[name] <= limit for name, limit in DIRECT_LIMITS.items())
def installed_dependency_counts(packages: set[str], tooling_names: frozenset[str] = TOOLING_PACKAGES) -> tuple[int, int]:
tooling = len(packages & tooling_names)
return len(packages) - tooling, tooling
def installed_dependencies_within_limits(packages: set[str], tooling_names: frozenset[str] = TOOLING_PACKAGES) -> bool:
baseline, tooling = installed_dependency_counts(packages, tooling_names)
return baseline <= BASELINE_INSTALLED_LIMIT and tooling <= TOOLING_INSTALLED_LIMIT
def installed_payload_bytes(prefix: Path) -> int:
# Imports generate bytecode caches; the dependency budget measures installed
# payload consistently before and after running tests.
return sum(path.stat().st_size for path in prefix.rglob("*")
if not path.is_symlink() and path.is_file() and
not (path.suffix == ".pyc" and path.parent.name == "__pycache__"))
def main() -> int:
if sys.prefix == sys.base_prefix:
print("Dependency checks require a virtual environment. Run tools/op.sh setup first.")
return 1
project = tomllib.loads((Path(__file__).resolve().parents[2] / "pyproject.toml").read_text())["project"]
direct = direct_dependency_counts(project)
# Count each installed package once, including transitive dependencies and all extras.
packages = {dist.metadata["Name"].lower().replace("_", "-") for dist in importlib.metadata.distributions()}
installed_baseline, installed_tooling = installed_dependency_counts(packages)
# Logical file sizes avoid filesystem block-size differences. Don't follow links to the interpreter or source tree.
size = installed_payload_bytes(Path(sys.prefix))
"""
This test prevents our depency footprint from growing.
These values are *not* intended to be increased, and we
expect to strictly drive these down over time.
"""
failed = not direct_dependencies_within_limits(project) or not installed_dependencies_within_limits(packages)
for name, limit in DIRECT_LIMITS.items():
print(f"Direct dependencies ({name}): {direct[name]} (limit: {limit})")
print(f"Installed dependencies (baseline): {installed_baseline} (limit: {BASELINE_INSTALLED_LIMIT})")
print(f"Installed dependencies (CI tooling): {installed_tooling} (limit: {TOOLING_INSTALLED_LIMIT})")
for name, value, limit in (
("Venv installed payload (MiB)", size / 1024**2, 550),
):
print(f"{name}: {value:g} (limit: {limit})")
failed |= value > limit
return int(failed)
if __name__ == "__main__":
raise SystemExit(main())