Skip to content

Commit

Permalink
Add tests and implement render functionality
Browse files Browse the repository at this point in the history
Added two tests in `test_render.py` to verify the rendering of templates and directories. Implemented the `render_env` function in `render.py` to handle the template rendering logic. Also ensured `questions` field in the pattern configuration has a default factory list.
  • Loading branch information
coordt committed Nov 10, 2024
1 parent 228c06a commit 302b685
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 1 deletion.
3 changes: 2 additions & 1 deletion project_forge/configurations/pattern.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,8 @@ class Pattern(BaseModel):
"""The configuration of a pattern."""

questions: List[Question] = Field(
description="A list of question objects that define the available context variables for project generation."
default_factory=list,
description="A list of question objects that define the available context variables for project generation.",
)
template_location: Union[str, Location] = Field(
description=(
Expand Down
38 changes: 38 additions & 0 deletions project_forge/rendering/render.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"""Functions to render a composition using answered questions."""

import logging
import pprint
from io import StringIO
from pathlib import Path

from jinja2 import Environment

from project_forge.rendering.environment import InheritanceMap
from project_forge.rendering.expressions import render_expression

logger = logging.getLogger(__name__)


def render_env(env: Environment, path_list: InheritanceMap, context: dict, destination_path: Path):
"""Render the templates in path_list using context."""
context_stream = StringIO()
pprint.pprint(context, context_stream)
logger.debug(f"Rendering templates using context:\n{context_stream.getvalue()}")

for path, val in path_list.items():
dst_rel_path = render_expression(path, context)
full_path = destination_path / dst_rel_path

if not val.exists():
raise ValueError(f"Path {path} does not exist")

if val.is_file():
logger.debug(f"Writing file {dst_rel_path}")
template = env.get_template(path)
full_path.parent.mkdir(parents=True, exist_ok=True)
full_path.write_text(template.render(context))
elif val.is_dir():
logger.debug(f"Writing directory {dst_rel_path}")
full_path.mkdir(parents=True, exist_ok=True)
else:
raise ValueError(f"Path {val} does not exist")
66 changes: 66 additions & 0 deletions tests/test_rendering/test_render.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
"""Tests for project_forge.rendering.render.py."""

from pathlib import Path
from unittest.mock import MagicMock, patch

import pytest

from project_forge.configurations.composition import read_composition_file
from project_forge.rendering.environment import load_environment
from project_forge.rendering.render import render_env
from project_forge.context_builder.context import build_context
from project_forge.rendering.templates import catalog_inheritance
from project_forge.tui import ask_question


@pytest.fixture
def template(tmp_path: Path):
"""A simple template structure."""
template_dir = tmp_path / "template"
template_dir.mkdir()
template_dir.joinpath("{{ repo_name }}").mkdir()
template_dir.joinpath("{{ repo_name }}", "file.txt").write_text("{{ key }}")
pattern_content = 'template_location = "{{ repo_name }}"\n[extra_context]\nkey = "value"\n'
template_dir.joinpath("pattern.toml").write_text(pattern_content)
composition_content = (
"overlays = [\n"
'{ pattern_location = "pattern.toml" }\n'
"]\n"
"[extra_context]\n"
'repo_name = "my-project"\n'
)
template_dir.joinpath("composition.toml").write_text(composition_content)
return template_dir


def test_render_env_for_file(tmp_path: Path, template: Path):
# Assemble
composition = read_composition_file(template / "composition.toml")
context = build_context(composition, ask_question)
template_paths = [overlay.pattern.template_location.resolve() for overlay in composition.overlays]
inheritance = catalog_inheritance(template_paths)
env = load_environment(inheritance)

# Act
render_env(env, inheritance, context, tmp_path)

# Assert
file_path = tmp_path / "my-project" / "file.txt"
assert file_path.exists()
assert file_path.read_text() == "value"


def test_render_env_for_directory(tmp_path: Path, template: Path):
# Assemble
composition = read_composition_file(template / "composition.toml")
context = build_context(composition, ask_question)
template_paths = [overlay.pattern.template_location.resolve() for overlay in composition.overlays]
inheritance = catalog_inheritance(template_paths)
env = load_environment(inheritance)

# Act
render_env(env, inheritance, context, tmp_path)

# Assert
dir_path = tmp_path / "my-project"
assert dir_path.exists()

0 comments on commit 302b685

Please sign in to comment.