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:
kevinveenbirkenbachandClaude Opus 5 committed 2026-09-16 22:00:30 +02:00
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:
+4 -2
View File
@@ -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")
+2 -3
View File
@@ -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 []