mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 19:01:54 +00:00
Modules imported by tests run inside the same pytest process as the tests themselves. Raw ``path.read_text(...)`` calls in those modules bypass the cache the tests just populated. ``roles/`` stays excluded (deployed scripts have no ``utils/`` on PYTHONPATH); ``utils/cache/`` stays excluded (cache implementation itself). Five conversions to ``utils.cache.files.read_text``: - ``utils/handler/yaml.py`` (YAML loader, read-only) - ``utils/annotations/summarize.py`` (CI log scanner, with ``UnicodeDecodeError`` fallback replacing ``errors="replace"``) - ``cli/meta/roles/applications/resolution/combined/__main__.py`` (single-shot CLI JSON input) - ``cli/core/help.py`` (read_folder_title + read_folder_description; same README is read many times across CLI help iteration) Eight ``# nocheck: cache-read`` markers, each annotated inline: - ``utils/claude/settings_sort.py`` (read then rewrite sorted) - ``utils/docker/version_updater.py`` (read then rewrite config) - ``cli/administration/deploy/development/network.py`` (tests mock ``Path.read_text`` directly; caching would bypass the mock) - ``cli/administration/deploy/development/log_utils.py`` (append flow) - ``cli/contributing/changelog/archive/changelog_md.py``, ``__main__.py``, ``package_mirror.py`` (file mutated in same flow) Two callers refactored to variable extraction so ruff's 88-char wrap keeps the ``# nocheck`` marker on the ``read_text(...)`` AST span line (``cli/.../network.py`` and ``package_mirror.py:105``). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
30 lines
1.1 KiB
Python
30 lines
1.1 KiB
Python
from typing import Any
|
|
|
|
import yaml
|
|
from yaml.loader import SafeLoader
|
|
|
|
from utils.cache.files import read_text
|
|
from utils.handler.vault import VaultScalar
|
|
|
|
|
|
class YamlHandler:
|
|
@staticmethod
|
|
def load_yaml(path) -> dict:
|
|
"""Load the YAML file and wrap existing !vault entries."""
|
|
text = read_text(str(path))
|
|
# Custom Loader subclass wraps !vault scalars; the path-keyed
|
|
# cache cannot preserve that wrapping, so go direct here.
|
|
data = yaml.load(text, Loader=SafeLoader) or {} # nocheck: direct-yaml
|
|
return YamlHandler.wrap_existing_vaults(data)
|
|
|
|
@staticmethod
|
|
def wrap_existing_vaults(node: Any) -> Any:
|
|
"""Recursively wrap any str that begins with '$ANSIBLE_VAULT' in a VaultScalar so it dumps as a literal block."""
|
|
if isinstance(node, dict):
|
|
return {k: YamlHandler.wrap_existing_vaults(v) for k, v in node.items()}
|
|
if isinstance(node, list):
|
|
return [YamlHandler.wrap_existing_vaults(v) for v in node]
|
|
if isinstance(node, str) and node.lstrip().startswith("$ANSIBLE_VAULT"):
|
|
return VaultScalar(node)
|
|
return node
|