Skip to content

0.53 prefix changes may break rendering JinjaX components in Jinja2 templates #114

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
jodal opened this issue Apr 9, 2025 · 4 comments
Labels

Comments

@jodal
Copy link
Contributor

jodal commented Apr 9, 2025

I'm sorry I don't have the time to make a minimal reproduction, so feel free to close this if you cannot reproduce or believe the error is elsewhere.

I suspect that the prefix changes in 0.53 breaks for projects where the Jinja2 env is configured with:

jinja2.Environment(
  ...
  undefined=jinja2.StrictUndefined,
  ...
)

Here's the output from one of our test cases when using JinjaX 0.54 (the test passes on 0.52):

.venv/lib/python3.13/site-packages/jinja2/environment.py:1295: in render
    self.environment.handle_exception()
.venv/lib/python3.13/site-packages/jinja2/environment.py:942: in handle_exception
    raise rewrite_traceback_stack(source=source)
<template>:1: in top-level template code
    ???
src/common/jinjax.py:33: in irender
    return super().irender(  # pyright: ignore[reportUnknownMemberType]
.venv/lib/python3.13/site-packages/jinjax/catalog.py:434: in irender
    component = self._get_component(__name, **kw)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <common.jinjax.Catalog object at 0x7f0e3ec51bd0>, cname = 'Py.Tests.Card', kw = {'title': 'my-title'}, source = ''
file_ext = '.j2', caller_prefix = Undefined, prefix = '', name = 'Py.Tests.Card', component = None
get_from = <bound method Catalog._get_from_cache of <common.jinjax.Catalog object at 0x7f0e3ec51bd0>>

    def _get_component(self, cname: str, **kw) -> Component:
        source = kw.pop("_source", kw.pop("__source", ""))
        file_ext = kw.pop("_file_ext", kw.pop("__file_ext", "")) or self.file_ext
        caller_prefix = kw.pop("__prefix", "")

        prefix, name = self._split_name(cname)
        component = None

        if source:
            logger.debug("Rendering from source %s", cname)
            self.jinja_env.loader = self.prefixes[prefix]
            return self._get_from_source(prefix=prefix, name=name, source=source)

        logger.debug("Rendering from cache or file %s", cname)
        get_from = self._get_from_cache if self.use_cache else self._get_from_file
>       if caller_prefix:
E       jinja2.exceptions.UndefinedError: '__prefix' is undefined

.venv/lib/python3.13/site-packages/jinjax/catalog.py:620: UndefinedError
@jpsca jpsca added the triage label Apr 11, 2025
@jpsca
Copy link
Owner

jpsca commented Apr 11, 2025

@jodal Sorry I'm unable to replicate this error with any end-to-end test, maybe is the way your test is written?

In the latest release (0.55) I've moved the __prefix injection to the Component.render method (https://github.com/jpsca/jinjax/blob/main/src/jinjax/component.py#L257), could you test if that solves the issue?

@jodal
Copy link
Contributor Author

jodal commented Apr 13, 2025

I'm on vacation with spotty internet access now, but I'll try it out before next weekend. Thanks!

@JakobGM
Copy link
Contributor

JakobGM commented Apr 14, 2025

@jodal Sorry I'm unable to replicate this error with any end-to-end test, maybe is the way your test is written?

In the latest release (0.55) I've moved the __prefix injection to the Component.render method (main/src/jinjax/component.py#L257), could you test if that solves the issue?

The issue seems to persist in jinjax==0.55, unfortunately.

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.venv/lib/python3.13/site-packages/jinja2/environment.py:1295: in render
    self.environment.handle_exception()
.venv/lib/python3.13/site-packages/jinja2/environment.py:942: in handle_exception
    raise rewrite_traceback_stack(source=source)
<template>:1: in top-level template code
    ???
.venv/lib/python3.13/site-packages/jinjax/catalog.py:443: in irender
    component = self._get_component(__name, **kw)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <common.jinjax.Catalog object at 0x7adf5ae872d0>, cname = 'Py.Tests.Card', kw = {'title': 'my-title'}, source = '', file_ext = '.j2', caller_prefix = Undefined, prefix = '', name = 'Py.Tests.Card', component = None, get_from = <bound method Catalog._get_from_cache of <common.jinjax.Catalog object at 0x7adf5ae872d0>>

    def _get_component(self, cname: str, **kw) -> Component:
        source = kw.pop("_source", kw.pop("__source", ""))
        file_ext = kw.pop("_file_ext", kw.pop("__file_ext", "")) or self.file_ext
        caller_prefix = kw.pop(ARGS_PREFIX, "")
    
        prefix, name = self._split_name(cname)
        component = None
    
        if source:
            logger.debug("Rendering from source %s", cname)
            self.jinja_env.loader = self.prefixes[prefix]
            return self._get_from_source(prefix=prefix, name=name, source=source)
    
        logger.debug("Rendering from cache or file %s", cname)
        get_from = self._get_from_cache if self.use_cache else self._get_from_file
>       if caller_prefix:
E       jinja2.exceptions.UndefinedError: '__prefix' is undefined

.venv/lib/python3.13/site-packages/jinjax/catalog.py:628: UndefinedError
=================================================================================================================================================================================== short test summary info ====================================================================================================================================================================================
FAILED tests/hub/core/test_htpy.py::test_jinjax_rendering_of_component_with_children - jinja2.exceptions.UndefinedError: '__prefix' is undefined

@jodal
Copy link
Contributor Author

jodal commented Apr 16, 2025

I tried hunting down the issue for a while longer, but I don't know enough Jinja2 and JinjaX internals to understand everything I'm looking at.

I can at least confirm that jinja2.StrictUndefined does not seem to be related in any way.

In the end I ended up rewriting a part of our test from rendering a Jinja2 template with a JinjaX component:

    template = catalog.jinja_env.from_string(
        '<Py.Tests.MyComponent title="my-title">my-content</Py.Tests.MyComponent>'
    )

    assert template.render() == "..."

To rendering the JinjaX component directly:

    result = catalog.render(
        "Py.Tests.MyComponent",
        title="my-title",
        _content="my-content",
    )

    assert result == "..."

This is good enough for our test case to cover what we need it to cover. I have not found any other issues through manual testing with JinjaX 0.53-0.55.

Unless you immediately see the issue here and this is something you want to keep working as it used to do, feel free to close this issue.

@jodal jodal changed the title 0.53 prefix changes may break with jinja2.StrictUndefined 0.53 prefix changes may break rendering JinjaX components in Jinja2 templates Apr 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants