From 7722cead3bf215ca8086eed5e62e405474a321c4 Mon Sep 17 00:00:00 2001 From: Predrag Radenkovic Date: Wed, 8 Jul 2026 15:39:05 +0200 Subject: [PATCH] Resolve modules in subdirectories via caller-side basename The top module's directory is already folded into template_dirs by get_template_directories, so passing the full filename to plain_file_parser double-counted the directory (relative subdirectory paths failed with 'Module does not exist'). Normalize the top module to its basename at the call sites in plain2code.py; plain_file_parser keeps preserving relative subdirectory prefixes so required/imported modules (e.g. 'dir_name/b') resolve. Add PlainModule-tree and parser-level regression tests. --- plain2code.py | 2 +- .../data/requires_subdir/main_in_subdir.plain | 12 +++++++++ tests/data/requires_subdir/nested/leaf.plain | 7 +++++ tests/test_plainfileparser.py | 26 +++++++++++++++++++ 4 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 tests/data/requires_subdir/main_in_subdir.plain create mode 100644 tests/data/requires_subdir/nested/leaf.plain diff --git a/plain2code.py b/plain2code.py index 37a20f3..a0da2f2 100644 --- a/plain2code.py +++ b/plain2code.py @@ -355,7 +355,7 @@ def main(): # noqa: C901 # Parse the plain file (and its required modules) once; reused by dry-run and rendering. try: plain_module = plain_modules.PlainModule( - args.filename, + os.path.basename(args.filename), args.build_folder, args.conformance_tests_folder, template_dirs, diff --git a/tests/data/requires_subdir/main_in_subdir.plain b/tests/data/requires_subdir/main_in_subdir.plain new file mode 100644 index 0000000..550ff6e --- /dev/null +++ b/tests/data/requires_subdir/main_in_subdir.plain @@ -0,0 +1,12 @@ +--- +requires: + - nested/leaf +--- + +***implementation reqs*** + +- Main implementation requirement. + +***functional specs*** + +- Display "hello, world" diff --git a/tests/data/requires_subdir/nested/leaf.plain b/tests/data/requires_subdir/nested/leaf.plain new file mode 100644 index 0000000..fd191b9 --- /dev/null +++ b/tests/data/requires_subdir/nested/leaf.plain @@ -0,0 +1,7 @@ +***implementation reqs*** + +- Base implementation requirement for the leaf. + +***functional specs*** + +- A base functionality from the leaf. diff --git a/tests/test_plainfileparser.py b/tests/test_plainfileparser.py index 9ebdee6..ef0b8bf 100644 --- a/tests/test_plainfileparser.py +++ b/tests/test_plainfileparser.py @@ -27,6 +27,32 @@ def test_regular_plain_source(get_test_data_path): } +def test_parser_keeps_subdirectory_in_module_name(get_test_data_path): + # A template-relative filename with a subdirectory (as passed for required/imported modules) + # must keep its subdirectory prefix in the module name so it resolves under template_dirs. + data_dir = get_test_data_path("data/requires_subdir") + + module_name, _, required = plain_file.plain_file_parser("nested/leaf.plain", [data_dir]) + + assert module_name == "nested/leaf" + assert required == [] + + +def test_requires_module_in_subdirectory_resolves(get_test_data_path): + # Regression: rendering a top module (referenced by basename, its dir supplied via + # template_dirs) that `requires` a module in a subdirectory must build the full PlainModule + # tree without a "Module does not exist" error, preserving the subdirectory in build paths. + import plain_modules + + data_dir = get_test_data_path("data/requires_subdir") + + module = plain_modules.PlainModule("main_in_subdir.plain", "build", "conformance", [data_dir]) + + assert module.module_name == "main_in_subdir" + assert [m.module_name for m in module.required_modules] == ["nested/leaf"] + assert [m.module_build_folder for m in module.required_modules] == [os.path.join("build", "nested/leaf")] + + def test_unknown_section(): plain_source = """ ***definitions***