diff --git a/project_forge/rendering/environment.py b/project_forge/rendering/environment.py index 5af9b7a..0eb7e80 100644 --- a/project_forge/rendering/environment.py +++ b/project_forge/rendering/environment.py @@ -1,5 +1,6 @@ """Tools and classes for managing the Jinja2 rendering environment.""" +import logging import re from collections import ChainMap from pathlib import Path @@ -7,6 +8,8 @@ from jinja2 import BaseLoader, Environment, TemplateNotFound, Undefined +logger = logging.getLogger(__name__) + class InheritanceMap(ChainMap[str, Path]): """Provides convenience functions for managing template inheritance.""" @@ -57,7 +60,7 @@ def __init__(self, inheritance_map: InheritanceMap): def get_source(self, environment: Environment, template: str) -> tuple[str, str | None, Callable[[], bool] | None]: """Load the template.""" # Parse the name of the template - bits = template.split("/") + bits = template.split("/", maxsplit=1) index = 0 if len(bits) == 2 and bits[0].isdigit(): index = int(bits[0]) @@ -77,6 +80,7 @@ def get_source(self, environment: Environment, template: str) -> tuple[str, str raise TemplateNotFound(template) # Maybe this wasn't one of our customized extended paths path = inheritance[index] + logger.debug(f"Loading template {template_name} from: {path}") source = path.read_text() # look for an `extends` tag diff --git a/project_forge/rendering/templates.py b/project_forge/rendering/templates.py index a7cf58b..4c6549d 100644 --- a/project_forge/rendering/templates.py +++ b/project_forge/rendering/templates.py @@ -14,14 +14,13 @@ def catalog_templates(template_dir: Path) -> Dict[str, Path]: For a file structure like: - /path-to-templates/ - {{ repo_name }}/ - file1.txt - subdir/ - file2.txt - empty-subdir/ + {{ repo_name }}/ + file1.txt + subdir/ + file2.txt + empty-subdir/ - A call to `catalog_templates(Path("/path-to-templates"))` would return: + A call to `catalog_templates(Path("/path-to-templates/{{ repo_name }}/"))` would return: { "{{ repo_name }}": Path("/path-to-templates/{{ repo_name }}"), @@ -37,14 +36,15 @@ def catalog_templates(template_dir: Path) -> Dict[str, Path]: Returns: A mapping of the relative path as a string to the full path """ - templates = {} + root_dir = template_dir.parent + templates = {template_dir.name: template_dir} for root, dirs, files in template_dir.walk(): for file in files: template_path = root / file - templates[str(template_path.relative_to(template_dir))] = template_path + templates[str(template_path.relative_to(root_dir))] = template_path for dir_ in dirs: template_path = root / dir_ - templates[str(template_path.relative_to(template_dir))] = template_path + templates[str(template_path.relative_to(root_dir))] = template_path return {key: templates[key] for key in sorted(templates)} diff --git a/tests/fixtures/python-boilerplate/pattern.toml b/tests/fixtures/python-boilerplate/pattern.toml index 175d7e0..b74619c 100644 --- a/tests/fixtures/python-boilerplate/pattern.toml +++ b/tests/fixtures/python-boilerplate/pattern.toml @@ -53,7 +53,7 @@ prompt = "What is the GitHub user name or organization?" default = "whoami" type = "str" -[[extra_context.requirements]] +[extra_context.requirements] prod = [ "environs", ] diff --git a/tests/fixtures/python-boilerplate/{{ repo_name }}/pyproject.toml b/tests/fixtures/python-boilerplate/{{ repo_name }}/pyproject.toml index cf94fa5..25f8bce 100644 --- a/tests/fixtures/python-boilerplate/{{ repo_name }}/pyproject.toml +++ b/tests/fixtures/python-boilerplate/{{ repo_name }}/pyproject.toml @@ -1,3 +1,4 @@ +{% extends "{{ repo_name }}/pyproject.toml" %} [build-system] requires = ["hatchling"] build-backend = "hatchling.build" @@ -15,25 +16,26 @@ keywords = ["{{ repo_name }}"] dynamic = ["version"] license = { file = "LICENSE" } requires-python = ">=3.9" -dependencies = [{% block dependencies %}{% for pkg, version in dependencies.items() %} - "{{ pkg }}{{ version }}", +dependencies = [{% block dependencies %}{% for pkg in requirements.prod %} + "{{ pkg }}", {%- endfor %}{% endblock dependencies %} ] [project.optional-dependencies] {% block optional_dependencies %} -dev = [{% block dev_dependencies %}{% for pkg, version in dev_requirements.items() %} - "{{ pkg }}{{ version }}", +dev = [{% block dev_dependencies %}{% for pkg in requirements.dev %} + "{{ pkg }}", {%- endfor %}{% endblock dev_dependencies %} ] -test = [{% block test_dependencies %}{% for pkg, version in test_requirements.items() %} - "{{ pkg }}{{ version }}", +test = [{% block test_dependencies %}{% for pkg in requirements.test %} + "{{ pkg }}", {%- endfor %}{% endblock test_dependencies %} ] -docs = [{% block docs_dependencies %}{% for pkg, version in docs_requirements.items() %} - "{{ pkg }}{{ version }}", +docs = [{% block docs_dependencies %}{% for pkg in requirements.docs %} + "{{ pkg }}", {%- endfor %}{% endblock docs_dependencies %} ] +{% endblock optional_dependencies %} [tool.hatch.version] path = "{{ repo_name }}/__init__.py" diff --git a/tests/fixtures/python-package/{{ repo_name }}/pyproject.toml b/tests/fixtures/python-package/{{ repo_name }}/pyproject.toml index d92cbc9..53fe2e8 100644 --- a/tests/fixtures/python-package/{{ repo_name }}/pyproject.toml +++ b/tests/fixtures/python-package/{{ repo_name }}/pyproject.toml @@ -1,5 +1 @@ -{% extends "pyproject.toml" %} - -{% block test_dependencies %}{{ super() }}{% for pkg, version in test_requirements.items() %} - "{{ pkg }}{{ version }}", -{%- endfor %}{% endblock test_dependencies %} +{% extends "{{ repo_name }}/pyproject.toml" %} diff --git a/tests/test_rendering/test_templates.py b/tests/test_rendering/test_templates.py index eed8465..b236a8f 100644 --- a/tests/test_rendering/test_templates.py +++ b/tests/test_rendering/test_templates.py @@ -34,7 +34,14 @@ def test_result_keys_are_relative_filepaths(self, tmp_path: Path): # Assemble generate_fake_templates(tmp_path) template1 = tmp_path / "template1" - expected_keys = {"subdir", "empty", "inherit.txt", "subdir/subdir.txt", "template1.txt"} + expected_keys = { + "template1/subdir", + "template1/empty", + "template1/inherit.txt", + "template1/subdir/subdir.txt", + "template1", + "template1/template1.txt", + } # Act result = catalog_templates(template1) @@ -43,14 +50,13 @@ def test_result_keys_are_relative_filepaths(self, tmp_path: Path): assert set(result.keys()) == expected_keys for key in expected_keys: - assert (template1 / key).exists() + assert (tmp_path / key).exists() def test_result_values_are_full_paths(self, tmp_path: Path): """The returned values are full filepaths as `Path`s.""" # Assemble generate_fake_templates(tmp_path) template1 = tmp_path / "template1" - expected_keys = {"subdir", "empty", "inherit.txt", "subdir/subdir.txt", "template1.txt"} # Act result = catalog_templates(template1) @@ -88,14 +94,16 @@ def test_multiple_paths_has_multiple_maps(self, tmp_path: Path): len(result.maps) == len(template_paths) + 1 ), "Number of children should match number of template paths plus 1" assert result.maps[0] == { - "inherit.txt": tmp_path / "template2/inherit.txt", - "template2.txt": tmp_path / "template2/template2.txt", + "template2/inherit.txt": tmp_path / "template2/inherit.txt", + "template2/template2.txt": tmp_path / "template2/template2.txt", + "template2": tmp_path / "template2", } assert result.maps[1] == { - "inherit.txt": tmp_path / "template1/inherit.txt", - "template1.txt": tmp_path / "template1/template1.txt", - "subdir/subdir.txt": tmp_path / "template1/subdir/subdir.txt", - "empty": tmp_path / "template1/empty", - "subdir": tmp_path / "template1/subdir", + "template1/inherit.txt": tmp_path / "template1/inherit.txt", + "template1/template1.txt": tmp_path / "template1/template1.txt", + "template1/subdir/subdir.txt": tmp_path / "template1/subdir/subdir.txt", + "template1/empty": tmp_path / "template1/empty", + "template1/subdir": tmp_path / "template1/subdir", + "template1": tmp_path / "template1", } assert result.maps[2] == {}