#!/usr/bin/env bash set -euo pipefail META_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" ROOT="${GOVOPLAN_CORE_ROOT:-$META_ROOT/../govoplan-core}" ROOT="$(cd "$ROOT" && pwd)" VENV_ROOT="${GOVOPLAN_VENV_ROOT:-$META_ROOT/.venv}" PYTHON="${PYTHON:-$VENV_ROOT/bin/python}" CHECK_TESTCLIENT_DEPRECATIONS="${CHECK_TESTCLIENT_DEPRECATIONS:-auto}" if [[ ! -x "$PYTHON" ]]; then PYTHON=python fi cd "$ROOT" "$PYTHON" - <<'PY' import importlib.util import sys if importlib.util.find_spec("pip") is None: print("Dependency hygiene failed: this Python environment cannot import pip.", file=sys.stderr) print("Recreate or repair the venv, then reinstall requirements:", file=sys.stderr) print(" cd /mnt/DATA/git/govoplan", file=sys.stderr) print(" python3 -m venv .venv", file=sys.stderr) print(" ./.venv/bin/python -m pip install --upgrade pip", file=sys.stderr) print(" ./.venv/bin/python -m pip install -r requirements-dev.txt", file=sys.stderr) raise SystemExit(127) PY "$PYTHON" -m pip check "$PYTHON" - <<'PY' from __future__ import annotations import pathlib import sys root = pathlib.Path.cwd() scan_roots = [ root / "src", root / "tests", root.parent / "govoplan-access" / "src", root.parent / "govoplan-admin" / "src", root.parent / "govoplan-addresses" / "src", root.parent / "govoplan-audit" / "src", root.parent / "govoplan-calendar" / "src", root.parent / "govoplan-campaign" / "src", root.parent / "govoplan-dashboard" / "src", root.parent / "govoplan-files" / "src", root.parent / "govoplan-identity" / "src", root.parent / "govoplan-mail" / "src", root.parent / "govoplan-ops" / "src", root.parent / "govoplan-organizations" / "src", root.parent / "govoplan-policy" / "src", root.parent / "govoplan-tenancy" / "src", ] deprecated_tokens = { "HTTP_422_UNPROCESSABLE_ENTITY": "Use HTTP_422_UNPROCESSABLE_CONTENT; the numeric status remains 422.", } hits: list[str] = [] for scan_root in scan_roots: if not scan_root.exists(): continue for path in scan_root.rglob("*.py"): try: text = path.read_text(encoding="utf-8") except UnicodeDecodeError: continue for token, replacement in deprecated_tokens.items(): if token in text: hits.append(f"{path}: deprecated {token}. {replacement}") if hits: print("Dependency hygiene failed: deprecated framework constants are still used.", file=sys.stderr) print("\n".join(hits), file=sys.stderr) raise SystemExit(1) print("Deprecated framework constant scan passed.") PY RUN_TESTCLIENT_DEPRECATION_SMOKE=0 case "$CHECK_TESTCLIENT_DEPRECATIONS" in 0|false|False|no|No) echo "TestClient deprecation smoke skipped by CHECK_TESTCLIENT_DEPRECATIONS=$CHECK_TESTCLIENT_DEPRECATIONS" ;; auto) if "$PYTHON" - <<'PY' import importlib.util raise SystemExit(0 if importlib.util.find_spec("fastapi") and importlib.util.find_spec("starlette") and importlib.util.find_spec("httpx2") else 1) PY then RUN_TESTCLIENT_DEPRECATION_SMOKE=1 else echo "TestClient deprecation smoke skipped; install dev requirements to enable it." fi ;; *) RUN_TESTCLIENT_DEPRECATION_SMOKE=1 ;; esac if [[ "$RUN_TESTCLIENT_DEPRECATION_SMOKE" -eq 1 ]]; then "$PYTHON" - <<'PY' import warnings from starlette.exceptions import StarletteDeprecationWarning warnings.simplefilter("error", StarletteDeprecationWarning) from fastapi import FastAPI from fastapi.testclient import TestClient app = FastAPI() @app.get("/dependency-hygiene-ping") def ping() -> dict[str, bool]: return {"ok": True} with TestClient(app) as client: response = client.get("/dependency-hygiene-ping") assert response.status_code == 200 assert response.json() == {"ok": True} print("TestClient deprecation smoke passed.") PY fi echo "Dependency hygiene check passed."