#!/usr/bin/env python3 """Record the isolated Netron/Playwright/Chromium environment and release provenance.""" from __future__ import annotations import hashlib import importlib.metadata import json import os import platform import subprocess import sys import tempfile import urllib.request from pathlib import Path from typing import Any ROOT = Path(__file__).resolve().parents[1] ENV_DIR = ROOT / "environment/visualization/netron" def sha256(path: Path) -> str: digest = hashlib.sha256() with path.open("rb") as handle: for chunk in iter(lambda: handle.read(1024 * 1024), b""): digest.update(chunk) return digest.hexdigest() def atomic_text(path: Path, text: str) -> None: path.parent.mkdir(parents=True, exist_ok=True) with tempfile.NamedTemporaryFile("w", encoding="utf-8", dir=path.parent, delete=False) as handle: handle.write(text) temporary = Path(handle.name) os.replace(temporary, path) def atomic_json(path: Path, value: Any) -> None: atomic_text(path, json.dumps(value, indent=2, sort_keys=True, ensure_ascii=False) + "\n") def pypi_artifact(package: str, version: str, matcher: str) -> dict[str, Any]: with urllib.request.urlopen(f"https://pypi.org/pypi/{package}/{version}/json", timeout=30) as response: value = json.load(response) matches = [item for item in value["urls"] if matcher in item["filename"]] if len(matches) != 1: raise ValueError(f"expected one PyPI artifact for {package} {matcher}, found {[item['filename'] for item in matches]}") item = matches[0] return { "package": package, "version": version, "filename": item["filename"], "url": item["url"], "bytes": item["size"], "sha256": item["digests"]["sha256"], "upload_time_iso_8601": item["upload_time_iso_8601"], } def main() -> int: os.environ.setdefault("PLAYWRIGHT_BROWSERS_PATH", str(ENV_DIR / "browsers")) from playwright.sync_api import sync_playwright netron_bin = ENV_DIR / ".venv/bin/netron" version_result = subprocess.run([str(netron_bin), "--version"], capture_output=True, text=True, check=False) netron_version = (version_result.stdout + version_result.stderr).strip() packages = sorted( (distribution.metadata["Name"], distribution.version) for distribution in importlib.metadata.distributions() if distribution.metadata["Name"] ) atomic_text(ENV_DIR / "installed-packages.txt", "".join(f"{name}=={version}\n" for name, version in packages)) with sync_playwright() as playwright: browser = playwright.chromium.launch(headless=True) chromium_version = browser.version browser.close() executable = Path(playwright.chromium.executable_path) releases = { "schema_version": "1.0", "source": "PyPI JSON API", "artifacts": [ pypi_artifact("netron", netron_version, "py3-none-any.whl"), pypi_artifact("playwright", importlib.metadata.version("playwright"), "manylinux1_x86_64.whl"), ], "official_release_tags": { "netron": f"https://github.com/lutzroeder/netron/releases/tag/v{netron_version}", "playwright_python": f"https://github.com/microsoft/playwright-python/releases/tag/v{importlib.metadata.version('playwright')}", }, } atomic_json(ENV_DIR / "pypi_release_artifacts.json", releases) tool_versions = { "schema_version": "1.0", "python": platform.python_version(), "python_executable": sys.executable, "netron": netron_version, "playwright": importlib.metadata.version("playwright"), "chromium": chromium_version, "chromium_executable": str(executable), "chromium_executable_bytes": executable.stat().st_size, "chromium_executable_sha256": sha256(executable), "capture_method": "official Netron browser Export as PNG via Control+Shift+E", "converter": "NOT_RUN", "model_conversion_performed": False, } atomic_json(ENV_DIR / "tool_versions.json", tool_versions) environment_files = [ ENV_DIR / "README.md", ENV_DIR / "bootstrap.sh", ENV_DIR / "requirements.in", ENV_DIR / "requirements.lock", ENV_DIR / "installed-packages.txt", ENV_DIR / "pypi_release_artifacts.json", ENV_DIR / "tool_versions.json", ] atomic_text( ENV_DIR / "environment_files.sha256", "".join(f"{sha256(path)} {path.relative_to(ROOT)}\n" for path in environment_files), ) print(json.dumps({"status": "PASS", **tool_versions}, sort_keys=True)) return 0 if __name__ == "__main__": raise SystemExit(main())