Skip to content

Commit 71ff5d7

Browse files
committed
feat: add template_searchpaths to generator config
1 parent c6793de commit 71ff5d7

File tree

4 files changed

+100
-21
lines changed

4 files changed

+100
-21
lines changed

schemas/corsair-build-schema.json

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@
1515
"additionalProperties": false,
1616
"description": "Configuration for the Markdown generator.",
1717
"properties": {
18+
"template_searchpaths": {
19+
"description": "Additional paths to search for templates.\n\nTemplates will be searched for in the given paths first.",
20+
"items": {
21+
"format": "path",
22+
"type": "string"
23+
},
24+
"title": "Template Searchpaths",
25+
"type": "array"
26+
},
1827
"extra": {
1928
"additionalProperties": true,
2029
"description": "Extra configuration parameters for the generator.",
@@ -68,6 +77,7 @@
6877
"wavedrom": {
6978
"$ref": "#/$defs/corsair___generators__wavedrom__WaveDromGenerator__Config",
7079
"default": {
80+
"template_searchpaths": [],
7181
"extra": {},
7282
"kind": "wavedrom",
7383
"vspace": 80,
@@ -92,6 +102,15 @@
92102
"additionalProperties": false,
93103
"description": "Configuration for the Verilog generator.",
94104
"properties": {
105+
"template_searchpaths": {
106+
"description": "Additional paths to search for templates.\n\nTemplates will be searched for in the given paths first.",
107+
"items": {
108+
"format": "path",
109+
"type": "string"
110+
},
111+
"title": "Template Searchpaths",
112+
"type": "array"
113+
},
95114
"extra": {
96115
"additionalProperties": true,
97116
"description": "Extra configuration parameters for the generator.",
@@ -117,6 +136,15 @@
117136
"additionalProperties": false,
118137
"description": "Configuration for the VHDL generator.",
119138
"properties": {
139+
"template_searchpaths": {
140+
"description": "Additional paths to search for templates.\n\nTemplates will be searched for in the given paths first.",
141+
"items": {
142+
"format": "path",
143+
"type": "string"
144+
},
145+
"title": "Template Searchpaths",
146+
"type": "array"
147+
},
120148
"extra": {
121149
"additionalProperties": true,
122150
"description": "Extra configuration parameters for the generator.",
@@ -142,6 +170,15 @@
142170
"additionalProperties": false,
143171
"description": "Configuration for the WaveDrom generator.",
144172
"properties": {
173+
"template_searchpaths": {
174+
"description": "Additional paths to search for templates.\n\nTemplates will be searched for in the given paths first.",
175+
"items": {
176+
"format": "path",
177+
"type": "string"
178+
},
179+
"title": "Template Searchpaths",
180+
"type": "array"
181+
},
145182
"extra": {
146183
"additionalProperties": true,
147184
"description": "Extra configuration parameters for the generator.",

src/corsair/_generators/base.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,12 @@ def __str__(self) -> str:
8181
class GeneratorConfig(BaseModel, ABC):
8282
"""Base configuration for a generator."""
8383

84+
template_searchpaths: list[Path] = Field(default_factory=list)
85+
"""Additional paths to search for templates.
86+
87+
Templates will be searched for in the given paths first.
88+
"""
89+
8490
extra: dict[str, Any] = Field(default_factory=dict)
8591
"""Extra configuration parameters for the generator."""
8692

@@ -108,14 +114,12 @@ def __init__(
108114
register_map: Map,
109115
config: GeneratorConfig,
110116
output_dir: Path,
111-
template_searchpaths: list[Path] | None = None,
112117
) -> None:
113118
"""Initialize the generator."""
114119
self.label = label
115120
self.register_map = register_map
116121
self.config = config
117122
self.output_dir = output_dir.resolve()
118-
self.template_searchpaths = template_searchpaths
119123

120124
if not isinstance(self.config, self.get_config_cls()):
121125
raise TypeError(
@@ -139,7 +143,7 @@ def __call__(self) -> TypeGenerator[Path, None, None]:
139143

140144
def _render_to_text(self, template_name: str, context: dict[str, Any]) -> str:
141145
"""Render text with Jinja2."""
142-
env = TemplateEnvironment(searchpath=self.template_searchpaths)
146+
env = TemplateEnvironment(searchpath=self.config.template_searchpaths)
143147
template = env.get_template(template_name)
144148
return template.render(context)
145149

src/corsair/_templates/env.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,9 @@ def __init__(self, searchpath: list[Path] | None = None) -> None:
6161
"""Initialize the template environment."""
6262
if not searchpath:
6363
searchpath = []
64+
6465
# Always include the directory containing the built-in templates
65-
if Path(__file__).parent not in searchpath:
66-
searchpath.append(Path(__file__).parent)
66+
searchpath.append(Path(__file__).parent)
6767

6868
super().__init__(
6969
loader=_EnhancedFileSystemLoader(searchpath=searchpath),

tests/generators/test_markdown.py

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,30 @@ def simple_regmap() -> csr.Map:
6666
)
6767

6868

69+
@pytest.fixture
70+
def custom_template(tmp_path: Path) -> Path:
71+
"""Create a custom template file directly in tmp_path and return its absolute path."""
72+
template_name = "custom_template_fixture.md.j2"
73+
template_content = (
74+
""""" \
75+
# Custom Template Fixture Test
76+
77+
Registers:
78+
{% for item in regmap.items %}
79+
- {{ item.name }}
80+
{% endfor %}
81+
82+
{% if cfg.extra['my_param'] is defined %}
83+
Custom Param: {{ cfg.extra['my_param'] }}
84+
{% endif %}
85+
"""
86+
""
87+
) # Raw string literal to handle backslashes correctly
88+
template_file = tmp_path / template_name
89+
template_file.write_text(template_content)
90+
return template_file.resolve() # Return absolute path
91+
92+
6993
def test_default_generation(tmp_path: Path, simple_regmap: csr.Map) -> None:
7094
"""Test default Markdown generation."""
7195
config = csr.MarkdownGenerator.Config()
@@ -215,25 +239,13 @@ def test_wavedrom_dump_json(tmp_path: Path, simple_regmap: csr.Map) -> None:
215239
assert {f for f in expected_data_dir.iterdir() if f.suffix == ".json"} == expected_json_files
216240

217241

218-
def test_custom_template_and_extra_param(tmp_path: Path, simple_regmap: csr.Map) -> None:
242+
def test_custom_template_and_extra_param(tmp_path: Path, simple_regmap: csr.Map, custom_template: Path) -> None:
219243
"""Test generation with a custom template and extra config parameters."""
220-
custom_template_name = "custom_template.md.j2"
221-
custom_template_content = """
222-
# Custom Template Test
223-
224-
Registers:
225-
{% for item in regmap.items %}
226-
- {{ item.name }}
227-
{% endfor %}
228-
229-
Custom Param: {{ cfg.extra['my_param'] }}
230-
"""
231-
custom_template_file = tmp_path / custom_template_name
232-
custom_template_file.write_text(custom_template_content)
244+
template_file = custom_template
233245

234246
custom_key = "my_param"
235247
custom_value = "hello_world"
236-
config = csr.MarkdownGenerator.Config(template_name=str(custom_template_file), extra={custom_key: custom_value})
248+
config = csr.MarkdownGenerator.Config(template_name=str(template_file), extra={custom_key: custom_value})
237249

238250
gen = csr.MarkdownGenerator(
239251
label="test_md_gen_custom_tmpl",
@@ -250,8 +262,34 @@ def test_custom_template_and_extra_param(tmp_path: Path, simple_regmap: csr.Map)
250262

251263
# Check the content of the generated file
252264
content = expected_file.read_text()
253-
assert "# Custom Template Test" in content
265+
assert "# Custom Template Fixture Test" in content
254266
assert "Registers:" in content
255267
assert "- reg1" in content
256268
assert "- reg2" in content
257269
assert f"Custom Param: {custom_value}" in content
270+
271+
272+
def test_custom_template_searchpath(tmp_path: Path, simple_regmap: csr.Map, custom_template: Path) -> None:
273+
"""Test generation with a custom template specified via search path."""
274+
template_file = custom_template # Fixture now returns the absolute path
275+
templates_dir = template_file.parent
276+
template_name = template_file.name
277+
278+
# Configure the generator to use the custom template directory and name
279+
config = csr.MarkdownGenerator.Config(
280+
template_searchpaths=[templates_dir],
281+
template_name=template_name,
282+
)
283+
284+
gen = csr.MarkdownGenerator(
285+
label="test_md_gen_searchpath",
286+
register_map=simple_regmap,
287+
config=config,
288+
output_dir=tmp_path,
289+
)
290+
291+
# Running the generator should succeed without TemplateNotFound
292+
try:
293+
list(gen())
294+
except csr.GeneratorTemplateError as e:
295+
pytest.fail(f"Template generation failed: {e}")

0 commit comments

Comments
 (0)