mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 10:59:59 +00:00
fix(lint): put the cache-read markers where the rule reads them
suppressed_line_numbers matches the marker on the flagged line itself, and ruff had split two of the calls so the comment landed behind the closing paren, one line too low. The reads that can be cached now go through utils.cache.files, which the bare interpreter imports fine; the two that cannot keep a marker on a line short enough to stay whole. The parser also gains the two guards utils/install/lint/pinned.py already carries for the same bootstrap problem: its reading is cross-checked against PyYAML on both requirements files, and a subprocess with yaml made unimportable proves the module still works without it. That turns the manual venv check into a standing test. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
f0ecf3e337
commit
d4ae5cf9f0
4 files changed
+69
-7
No files matched your search
@@ -1,10 +1,41 @@
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from tempfile import TemporaryDirectory
|
||||
|
||||
from utils import PROJECT_ROOT
|
||||
from utils.cache.yaml import load_yaml_any
|
||||
from utils.install.collections import declared_pins, unsatisfied
|
||||
|
||||
_REQUIREMENTS = (
|
||||
PROJECT_ROOT / "requirements" / "requirements.galaxy.yml",
|
||||
PROJECT_ROOT / "requirements" / "requirements.git.yml",
|
||||
)
|
||||
|
||||
_BOOTSTRAP_PROBE = """
|
||||
import sys
|
||||
|
||||
|
||||
class _NoPyYAML:
|
||||
def find_spec(self, fullname, path=None, target=None):
|
||||
if fullname == "yaml" or fullname.startswith("yaml."):
|
||||
raise ImportError("PyYAML is absent during the lint bootstrap")
|
||||
return None
|
||||
|
||||
|
||||
sys.meta_path.insert(0, _NoPyYAML())
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from utils.install.lint.ansible import collections as lint_collections
|
||||
from utils.install.collections import declared_pins
|
||||
|
||||
for fqcn, version in declared_pins(Path("requirements/requirements.galaxy.yml")):
|
||||
print(fqcn, version)
|
||||
"""
|
||||
|
||||
REQUIREMENTS = """---
|
||||
collections:
|
||||
- name: community.general
|
||||
@@ -29,6 +60,36 @@ def _install(collections_dir: Path, fqcn: str, version: str) -> None:
|
||||
)
|
||||
|
||||
|
||||
class TestAgainstPyYAML(unittest.TestCase):
|
||||
def test_the_hand_parser_agrees_with_pyyaml(self):
|
||||
for path in _REQUIREMENTS:
|
||||
with self.subTest(requirements=path.name):
|
||||
declared = load_yaml_any(str(path), default_if_missing={}) or {}
|
||||
expected = [
|
||||
(str(entry.get("name")), entry.get("version"))
|
||||
for entry in declared.get("collections") or []
|
||||
if isinstance(entry, dict) and entry.get("name")
|
||||
]
|
||||
expected = [
|
||||
(name, None if version is None else str(version))
|
||||
for name, version in expected
|
||||
]
|
||||
|
||||
self.assertEqual(declared_pins(path), expected)
|
||||
|
||||
def test_the_parser_runs_with_pyyaml_unimportable(self):
|
||||
result = subprocess.run(
|
||||
[sys.executable, "-c", _BOOTSTRAP_PROBE],
|
||||
cwd=str(PROJECT_ROOT),
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False,
|
||||
)
|
||||
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
self.assertIn("community.general", result.stdout)
|
||||
|
||||
|
||||
class TestDeclaredPins(unittest.TestCase):
|
||||
def test_a_quoted_version_is_read_without_its_quotes(self):
|
||||
body = (
|
||||
|
||||
@@ -28,8 +28,8 @@ collections:
|
||||
|
||||
|
||||
def _read(root: Path, name: str) -> str:
|
||||
# nocheck: cache-read -- apply_updates rewrote this file inside the same test
|
||||
return (root / "requirements" / name).read_text(encoding="utf-8")
|
||||
path = root / "requirements" / name
|
||||
return path.read_text() # nocheck: cache-read -- rewritten by this test
|
||||
|
||||
|
||||
def _repo(root: Path) -> Path:
|
||||
|
||||
@@ -15,6 +15,8 @@ import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from utils.cache.files import read_text
|
||||
|
||||
_NAME = re.compile(r"^\s*-\s+name:\s*(?P<name>[A-Za-z0-9_.]+)\s*(?:#.*)?$")
|
||||
_VERSION = re.compile(
|
||||
r"^\s*version:\s*(?P<quote>[\"']?)(?P<version>[^\s#\"']+)(?P=quote)\s*(?:#.*)?$"
|
||||
@@ -29,7 +31,7 @@ def declared_pins(requirements_file: Path) -> list[tuple[str, str | None]]:
|
||||
"""
|
||||
pins: list[tuple[str, str | None]] = []
|
||||
try:
|
||||
lines = requirements_file.read_text(encoding="utf-8").splitlines()
|
||||
lines = read_text(str(requirements_file)).splitlines()
|
||||
except OSError:
|
||||
return pins
|
||||
|
||||
@@ -57,7 +59,7 @@ def _installed_version(collections_dir: Path, namespace: str, name: str) -> str
|
||||
collections_dir / "ansible_collections" / namespace / name / "MANIFEST.json"
|
||||
)
|
||||
try:
|
||||
payload = json.loads(manifest.read_text(encoding="utf-8"))
|
||||
payload = json.loads(read_text(str(manifest)))
|
||||
except (OSError, ValueError):
|
||||
return None
|
||||
version = payload.get("collection_info", {}).get("version")
|
||||
|
||||
@@ -57,9 +57,8 @@ def load_history(path: Path) -> list[dict[str, float | None]]:
|
||||
path: JSON file holding the rolling window.
|
||||
"""
|
||||
try:
|
||||
payload = json.loads(
|
||||
path.read_text(encoding="utf-8")
|
||||
) # nocheck: cache-read -- the history file is rewritten every run, a cached copy would go stale
|
||||
raw = path.read_text() # nocheck: cache-read -- rewritten every run
|
||||
payload = json.loads(raw)
|
||||
except (OSError, ValueError):
|
||||
return []
|
||||
return payload if isinstance(payload, list) else []
|
||||
|
||||
Reference in new issue
Block a user