Coverage for plugin/scripts/_validate_log.py: 100%

24 statements  

« prev     ^ index     » next       coverage.py v7.16.1, created at 2026-09-15 14:46 +0000

1#!/usr/bin/env python3 

2"""The reporting sink every `validate.py` check writes to. 

3 

4Its own module because all three halves of the validator need it — the structure checks, 

5the field checks, and the orchestration — and a shim they all import cannot live in the 

6module that imports them. 

7 

8Two audiences from one call: a human reading symbol-prefixed lines on stderr, and 

9``--json``, which needs the ERROR and WARNING messages as data. That is the whole reason 

10this is a class and not `print`. 

11""" 

12 

13from __future__ import annotations 

14 

15import sys 

16 

17 

18class Log: 

19 """Tiny stand-in for the CLI's loguru sink. 

20 

21 Prints human-readable, symbol-prefixed lines to stderr and, so `--json` 

22 can report a structured verdict, accumulates the ERROR/WARNING messages. 

23 """ 

24 

25 _SYMBOLS = {"error": "✗", "warning": "!", "success": "✓", "info": " ", "debug": " "} 

26 

27 def __init__(self, *, verbose: bool = False) -> None: 

28 """Start the sink with empty error/warning buffers.""" 

29 self.errors: list[str] = [] 

30 self.warnings: list[str] = [] 

31 self._verbose = verbose 

32 

33 def _emit(self, level: str, message: str) -> None: 

34 """Print a symbol-prefixed line (debug only when verbose).""" 

35 if level == "debug" and not self._verbose: 

36 return 

37 print(f"{self._SYMBOLS[level]} {message}", file=sys.stderr) 

38 

39 def error(self, message: str) -> None: 

40 """Record and print an error.""" 

41 self.errors.append(message) 

42 self._emit("error", message) 

43 

44 def warning(self, message: str) -> None: 

45 """Record and print a warning.""" 

46 self.warnings.append(message) 

47 self._emit("warning", message) 

48 

49 def success(self, message: str) -> None: 

50 """Print a success line.""" 

51 self._emit("success", message) 

52 

53 def info(self, message: str) -> None: 

54 """Print an info line.""" 

55 self._emit("info", message) 

56 

57 def debug(self, message: str) -> None: 

58 """Print a debug line (verbose only).""" 

59 self._emit("debug", message)