From 5dc436f1e4dda4f162d30cdb6f174a51938dd862 Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Fri, 20 Feb 2026 17:28:29 -0500 Subject: [PATCH 01/10] Recursive directory parsing + ignore common YAML dirs we shouldn't check --- src/dayamlchecker/code_formatter.py | 42 +++++++++++++-- src/dayamlchecker/yaml_structure.py | 80 +++++++++++++++++++++++++++-- 2 files changed, 112 insertions(+), 10 deletions(-) diff --git a/src/dayamlchecker/code_formatter.py b/src/dayamlchecker/code_formatter.py index 437fb09..a87251e 100644 --- a/src/dayamlchecker/code_formatter.py +++ b/src/dayamlchecker/code_formatter.py @@ -17,6 +17,7 @@ import re import sys +import os from dataclasses import dataclass, field from pathlib import Path from typing import Any @@ -369,19 +370,40 @@ def format_yaml_file( return formatted, changed -def _collect_yaml_files(paths: list[Path]) -> list[Path]: +def _collect_yaml_files( + paths: list[Path], include_default_ignores: bool = True +) -> list[Path]: """ Expand paths to a list of YAML files. - Files are included if they have .yml or .yaml extension - Directories are recursively searched for YAML files """ + def _is_default_ignored_dir(dirname: str) -> bool: + return ( + dirname.startswith(".git") + or dirname.startswith(".github") + or dirname == "sources" + ) + yaml_files = [] for path in paths: if path.is_dir(): - # Recursively find all YAML files - yaml_files.extend(path.rglob("*.yml")) - yaml_files.extend(path.rglob("*.yaml")) + # Recursively find all YAML files, pruning ignored directories + for root, dirnames, filenames in os.walk(path, topdown=True): + if include_default_ignores and _is_default_ignored_dir(Path(root).name): + dirnames[:] = [] + continue + if include_default_ignores: + dirnames[:] = [ + dirname + for dirname in dirnames + if not _is_default_ignored_dir(dirname) + ] + root_path = Path(root) + for filename in filenames: + if filename.lower().endswith((".yml", ".yaml")): + yaml_files.append(root_path / filename) elif path.suffix.lower() in (".yml", ".yaml"): yaml_files.append(path) seen = set() @@ -438,6 +460,14 @@ def main() -> int: action="store_true", help="Only output errors", ) + parser.add_argument( + "--no-default-ignores", + action="store_true", + help=( + "Do not ignore default directories during recursive search " + "(.git*, .github*, sources)" + ), + ) args = parser.parse_args() @@ -447,7 +477,9 @@ def main() -> int: ) # Collect all YAML files from paths (handles directories recursively) - yaml_files = _collect_yaml_files(args.files) + yaml_files = _collect_yaml_files( + args.files, include_default_ignores=not args.no_default_ignores + ) if not yaml_files: print("No YAML files found.", file=sys.stderr) diff --git a/src/dayamlchecker/yaml_structure.py b/src/dayamlchecker/yaml_structure.py index 99729dd..7ce9d51 100644 --- a/src/dayamlchecker/yaml_structure.py +++ b/src/dayamlchecker/yaml_structure.py @@ -1,9 +1,11 @@ # Each doc, apply this to each block import ast +import argparse +import os +from pathlib import Path import re import sys -# os and Path imports were used in a short-lived implementation; the CLI filtering approach is preferred from typing import Optional import yaml from yaml.loader import SafeLoader @@ -1161,10 +1163,78 @@ def process_file(input_file): print(f"{err}") -def main(): - for input_file in sys.argv[1:]: - process_file(input_file) +def _collect_yaml_files( + paths: list[Path], include_default_ignores: bool = True +) -> list[Path]: + """Expand files/directories into a unique, sorted list of YAML files.""" + def _is_default_ignored_dir(dirname: str) -> bool: + return ( + dirname.startswith(".git") + or dirname.startswith(".github") + or dirname == "sources" + ) + + yaml_files = [] + for path in paths: + if path.is_dir(): + for root, dirnames, filenames in os.walk(path, topdown=True): + if include_default_ignores and _is_default_ignored_dir(Path(root).name): + dirnames[:] = [] + continue + if include_default_ignores: + dirnames[:] = [ + dirname + for dirname in dirnames + if not _is_default_ignored_dir(dirname) + ] + root_path = Path(root) + for filename in filenames: + if filename.lower().endswith((".yml", ".yaml")): + yaml_files.append(root_path / filename) + elif path.suffix.lower() in (".yml", ".yaml"): + yaml_files.append(path) + + seen = set() + result = [] + for file_path in yaml_files: + resolved = file_path.resolve() + if resolved not in seen: + seen.add(resolved) + result.append(file_path) + return sorted(result) + + +def main() -> int: + parser = argparse.ArgumentParser( + description="Validate Docassemble YAML files", + ) + parser.add_argument( + "files", + nargs="+", + type=Path, + help="YAML files or directories to validate (directories are searched recursively)", + ) + parser.add_argument( + "--no-default-ignores", + action="store_true", + help=( + "Do not ignore default directories during recursive search " + "(.git*, .github*, sources)" + ), + ) + args = parser.parse_args() + + yaml_files = _collect_yaml_files( + args.files, include_default_ignores=not args.no_default_ignores + ) + if not yaml_files: + print("No YAML files found.", file=sys.stderr) + return 1 + + for input_file in yaml_files: + process_file(str(input_file)) + return 0 if __name__ == "__main__": - main() + sys.exit(main()) From 3a1a6e00892280e15cee08226916fadd74a4374a Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 23 Feb 2026 10:02:37 -0500 Subject: [PATCH 02/10] Update src/dayamlchecker/code_formatter.py Co-authored-by: Bryce Willey --- src/dayamlchecker/code_formatter.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dayamlchecker/code_formatter.py b/src/dayamlchecker/code_formatter.py index a87251e..2219170 100644 --- a/src/dayamlchecker/code_formatter.py +++ b/src/dayamlchecker/code_formatter.py @@ -383,6 +383,7 @@ def _is_default_ignored_dir(dirname: str) -> bool: return ( dirname.startswith(".git") or dirname.startswith(".github") + or dirname.startswith(".venv") or dirname == "sources" ) From 5c67a9ab84063dd10bca31a896f764f31017ed2c Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 23 Feb 2026 10:02:46 -0500 Subject: [PATCH 03/10] Update src/dayamlchecker/code_formatter.py Co-authored-by: Bryce Willey --- src/dayamlchecker/code_formatter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dayamlchecker/code_formatter.py b/src/dayamlchecker/code_formatter.py index 2219170..c5fa1db 100644 --- a/src/dayamlchecker/code_formatter.py +++ b/src/dayamlchecker/code_formatter.py @@ -479,7 +479,7 @@ def main() -> int: # Collect all YAML files from paths (handles directories recursively) yaml_files = _collect_yaml_files( - args.files, include_default_ignores=not args.no_default_ignores + args.files, check_all=args.check_all ) if not yaml_files: From 44c38ad447586a1156d6832da279bd6b91dcce11 Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 23 Feb 2026 10:02:53 -0500 Subject: [PATCH 04/10] Update src/dayamlchecker/code_formatter.py Co-authored-by: Bryce Willey --- src/dayamlchecker/code_formatter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dayamlchecker/code_formatter.py b/src/dayamlchecker/code_formatter.py index c5fa1db..de99c11 100644 --- a/src/dayamlchecker/code_formatter.py +++ b/src/dayamlchecker/code_formatter.py @@ -462,7 +462,7 @@ def main() -> int: help="Only output errors", ) parser.add_argument( - "--no-default-ignores", + "--check-all", action="store_true", help=( "Do not ignore default directories during recursive search " From e772604eefa6e552b219e718ff7f09e691e396ef Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 23 Feb 2026 10:03:04 -0500 Subject: [PATCH 05/10] Update src/dayamlchecker/code_formatter.py Co-authored-by: Bryce Willey --- src/dayamlchecker/code_formatter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dayamlchecker/code_formatter.py b/src/dayamlchecker/code_formatter.py index de99c11..64bca0e 100644 --- a/src/dayamlchecker/code_formatter.py +++ b/src/dayamlchecker/code_formatter.py @@ -371,7 +371,7 @@ def format_yaml_file( def _collect_yaml_files( - paths: list[Path], include_default_ignores: bool = True + paths: list[Path], check_all: bool = False ) -> list[Path]: """ Expand paths to a list of YAML files. From 48daba2dd66ff1512284f234a0d91e2f2bab4073 Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 23 Feb 2026 10:03:11 -0500 Subject: [PATCH 06/10] Update src/dayamlchecker/code_formatter.py Co-authored-by: Bryce Willey --- src/dayamlchecker/code_formatter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dayamlchecker/code_formatter.py b/src/dayamlchecker/code_formatter.py index 64bca0e..665c51f 100644 --- a/src/dayamlchecker/code_formatter.py +++ b/src/dayamlchecker/code_formatter.py @@ -392,10 +392,10 @@ def _is_default_ignored_dir(dirname: str) -> bool: if path.is_dir(): # Recursively find all YAML files, pruning ignored directories for root, dirnames, filenames in os.walk(path, topdown=True): - if include_default_ignores and _is_default_ignored_dir(Path(root).name): + if not check_all and _is_default_ignored_dir(Path(root).name): dirnames[:] = [] continue - if include_default_ignores: + if not check_all: dirnames[:] = [ dirname for dirname in dirnames From a84b4720363bc46c1fe9cddb8fea933d02153ffb Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 23 Feb 2026 10:03:19 -0500 Subject: [PATCH 07/10] Update src/dayamlchecker/yaml_structure.py Co-authored-by: Bryce Willey --- src/dayamlchecker/yaml_structure.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dayamlchecker/yaml_structure.py b/src/dayamlchecker/yaml_structure.py index 7ce9d51..d6cbd3b 100644 --- a/src/dayamlchecker/yaml_structure.py +++ b/src/dayamlchecker/yaml_structure.py @@ -1215,7 +1215,7 @@ def main() -> int: help="YAML files or directories to validate (directories are searched recursively)", ) parser.add_argument( - "--no-default-ignores", + "--check-all", action="store_true", help=( "Do not ignore default directories during recursive search " @@ -1225,7 +1225,7 @@ def main() -> int: args = parser.parse_args() yaml_files = _collect_yaml_files( - args.files, include_default_ignores=not args.no_default_ignores + args.files, check_all=args.check_all ) if not yaml_files: print("No YAML files found.", file=sys.stderr) From b28d9c91a1a9445e10b79897a2b930a627ba02df Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 23 Feb 2026 10:03:34 -0500 Subject: [PATCH 08/10] Update src/dayamlchecker/yaml_structure.py Co-authored-by: Bryce Willey --- src/dayamlchecker/yaml_structure.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dayamlchecker/yaml_structure.py b/src/dayamlchecker/yaml_structure.py index d6cbd3b..b8ced0b 100644 --- a/src/dayamlchecker/yaml_structure.py +++ b/src/dayamlchecker/yaml_structure.py @@ -1164,7 +1164,7 @@ def process_file(input_file): def _collect_yaml_files( - paths: list[Path], include_default_ignores: bool = True + paths: list[Path], check_all: bool = False ) -> list[Path]: """Expand files/directories into a unique, sorted list of YAML files.""" def _is_default_ignored_dir(dirname: str) -> bool: From bfc85bb3bf9058a1c1fbcf016a81092df3303f5a Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 23 Feb 2026 10:03:41 -0500 Subject: [PATCH 09/10] Update src/dayamlchecker/yaml_structure.py Co-authored-by: Bryce Willey --- src/dayamlchecker/yaml_structure.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dayamlchecker/yaml_structure.py b/src/dayamlchecker/yaml_structure.py index b8ced0b..68e0e38 100644 --- a/src/dayamlchecker/yaml_structure.py +++ b/src/dayamlchecker/yaml_structure.py @@ -1178,10 +1178,10 @@ def _is_default_ignored_dir(dirname: str) -> bool: for path in paths: if path.is_dir(): for root, dirnames, filenames in os.walk(path, topdown=True): - if include_default_ignores and _is_default_ignored_dir(Path(root).name): + if not check_all and _is_default_ignored_dir(Path(root).name): dirnames[:] = [] continue - if include_default_ignores: + if not check_all: dirnames[:] = [ dirname for dirname in dirnames From c445b99ccc92035b6b20d7a1bc2781048edc4e54 Mon Sep 17 00:00:00 2001 From: Quinten Steenhuis Date: Mon, 23 Feb 2026 10:03:48 -0500 Subject: [PATCH 10/10] Update src/dayamlchecker/yaml_structure.py Co-authored-by: Bryce Willey --- src/dayamlchecker/yaml_structure.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dayamlchecker/yaml_structure.py b/src/dayamlchecker/yaml_structure.py index 68e0e38..1c1ca71 100644 --- a/src/dayamlchecker/yaml_structure.py +++ b/src/dayamlchecker/yaml_structure.py @@ -1171,6 +1171,7 @@ def _is_default_ignored_dir(dirname: str) -> bool: return ( dirname.startswith(".git") or dirname.startswith(".github") + or dirname.startswith(".venv") or dirname == "sources" )