Skip to content

Commit a451f05

Browse files
thirtytwobitsScott Dixon
andauthored
Fix for #312 , support generators no longer have access to code gener… (#387)
…ator filters This change ensures that unsupported filters are not made available to the support generators Co-authored-by: Scott Dixon <thirtytwobits@Scotts-MacBook-Pro.local>
1 parent 9470429 commit a451f05

3 files changed

Lines changed: 116 additions & 5 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ out
3333
venv*
3434
*.bkp
3535
*.bak
36+
*.profraw
3637

3738
# Eclipse
3839
.metadata

src/nunavut/jinja/__init__.py

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,23 @@ def __init__(
204204
env_builder.add_globals(**additional_globals)
205205
env_builder.set_embed_auditing_info(embed_auditing_info)
206206

207-
self._env = env_builder.create(language_context)
207+
self._env = self._create_environment(env_builder, language_context)
208+
209+
def _create_environment(
210+
self, env_builder: CodeGenEnvironmentBuilder, language_context: nunavut.lang.LanguageContext
211+
) -> CodeGenEnvironment:
212+
"""
213+
Create the code generation environment for this generator.
214+
215+
This is a template method that subclasses can override to customize the environment
216+
with generator-specific filters, tests, and globals. The base implementation creates
217+
an environment with language-specific filters only.
218+
219+
:param env_builder: The environment builder with basic configuration already set.
220+
:param language_context: The language context for this generator.
221+
:return: A configured CodeGenEnvironment instance.
222+
"""
223+
return env_builder.create(language_context)
208224

209225
@property
210226
def dsdl_loader(self) -> DSDLTemplateLoader:
@@ -772,9 +788,31 @@ def is_deprecated(instance: pydsdl.Any) -> bool:
772788

773789
def __init__(self, namespace: nunavut.Namespace, resource_types: int = ResourceType.ANY.value, **kwargs: Any):
774790
super().__init__(namespace, resource_types=resource_types, **kwargs)
791+
792+
def _create_environment(
793+
self, env_builder: CodeGenEnvironmentBuilder, language_context: nunavut.lang.LanguageContext
794+
) -> CodeGenEnvironment:
795+
"""
796+
Create the environment with DSDL-specific filters and tests.
797+
798+
This override adds DSDL-specific functionality like type_to_template, type_to_include_path,
799+
and DSDL tests (is_service_request, is_service_response, etc.) that should only be
800+
available in DSDL type templates, not in support templates.
801+
802+
:param env_builder: The environment builder with basic configuration already set.
803+
:param language_context: The language context for this generator.
804+
:return: A configured CodeGenEnvironment with DSDL-specific additions.
805+
"""
806+
env = super()._create_environment(env_builder, language_context)
807+
808+
# Add DSDL-specific tests (is_service_request, is_service_response, etc.)
775809
for test_name, test in self._create_all_dsdl_tests().items():
776-
self._env.add_test(test_name, test)
777-
self._env.add_conventional_methods_to_environment(self)
810+
env.add_test(test_name, test)
811+
812+
# Add DSDL-specific filters (type_to_template, type_to_include_path, etc.)
813+
env.add_conventional_methods_to_environment(self)
814+
815+
return env
778816

779817
# +-----------------------------------------------------------------------+
780818
# | AbstractGenerator

test/gentest_filters/test_filters.py

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414

1515
from nunavut import Namespace
1616
from nunavut._namespace import build_namespace_tree # deprecated
17-
from nunavut.jinja import DSDLCodeGenerator
18-
from nunavut.jinja.jinja2.exceptions import TemplateAssertionError
17+
from nunavut.jinja import DSDLCodeGenerator, SupportGenerator
18+
from nunavut.jinja.jinja2.exceptions import TemplateAssertionError, UndefinedError
1919
from nunavut.lang import Language, LanguageClassLoader, LanguageContextBuilder
2020

2121

@@ -448,3 +448,75 @@ def test_filter_to_template_unique(gen_paths):
448448
actual = foo_file.read()
449449

450450
assert expected == actual
451+
452+
453+
def test_support_generator_filter_isolation(gen_paths): # type: ignore
454+
"""
455+
Test that DSDL-specific filters are not available in SupportGenerator templates.
456+
This verifies that suggestion #2 (creating different environment objects per generator)
457+
is properly implemented, preventing filter leaking between generators.
458+
"""
459+
root_path = str(gen_paths.dsdl_dir / Path("uavcan"))
460+
output_path = gen_paths.out_dir / "filter_isolation"
461+
compound_types = read_namespace(root_path, [])
462+
language_context = LanguageContextBuilder().set_target_language("c").create()
463+
namespace = build_namespace_tree(compound_types, root_path, output_path, language_context)
464+
465+
# Create a template that tries to use a DSDL-specific filter
466+
template_dir = gen_paths.out_dir / "filter_isolation_templates"
467+
template_dir.mkdir(parents=True, exist_ok=True)
468+
template_file = template_dir / "serialization.j2"
469+
470+
# This template tries to use type_to_template, which should only be available in DSDLCodeGenerator
471+
with open(template_file, "w", encoding="utf-8") as f:
472+
f.write("{{ 'test' | type_to_template }}")
473+
474+
# Create a SupportGenerator with this template
475+
from nunavut._utilities import ResourceType
476+
support_generator = SupportGenerator(
477+
namespace,
478+
resource_types=ResourceType.SERIALIZATION_SUPPORT.value,
479+
templates_dir=template_dir
480+
)
481+
482+
# Attempting to generate should fail because type_to_template filter is not available
483+
# in SupportGenerator's environment
484+
with pytest.raises((TemplateAssertionError, UndefinedError, AttributeError)) as exc_info:
485+
list(support_generator.generate_all())
486+
487+
# Verify the error message mentions the missing filter
488+
error_message = str(exc_info.value)
489+
assert "type_to_template" in error_message.lower() or "no filter" in error_message.lower()
490+
491+
492+
def test_dsdl_generator_has_dsdl_filters(gen_paths): # type: ignore
493+
"""
494+
Test that DSDL-specific filters ARE available in DSDLCodeGenerator templates.
495+
This is the positive test case for filter isolation.
496+
"""
497+
root_path = str(gen_paths.dsdl_dir / Path("uavcan"))
498+
output_path = gen_paths.out_dir / "dsdl_filter_test"
499+
compound_types = read_namespace(root_path, [])
500+
language_context = LanguageContextBuilder().set_target_language("c").create()
501+
namespace = build_namespace_tree(compound_types, root_path, output_path, language_context)
502+
503+
# Create a template that uses DSDL-specific filters
504+
template_dir = gen_paths.out_dir / "dsdl_filter_test_templates"
505+
template_dir.mkdir(parents=True, exist_ok=True)
506+
template_file = template_dir / "Any.j2"
507+
508+
# This template uses type_to_template, which should be available in DSDLCodeGenerator
509+
with open(template_file, "w", encoding="utf-8") as f:
510+
f.write("{{ T | type_to_template }}")
511+
512+
# Create a DSDLCodeGenerator with this template
513+
dsdl_generator = DSDLCodeGenerator(
514+
namespace,
515+
templates_dir=template_dir
516+
)
517+
518+
# This should work without errors
519+
generated_files = list(dsdl_generator.generate_all())
520+
521+
# Verify that files were generated successfully
522+
assert len(generated_files) > 0

0 commit comments

Comments
 (0)