Skip to content
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

Allow passing multiple templates to import, just like include #1862

Open
pawamoy opened this issue Jun 21, 2023 · 4 comments
Open

Allow passing multiple templates to import, just like include #1862

pawamoy opened this issue Jun 21, 2023 · 4 comments

Comments

@pawamoy
Copy link
Sponsor

pawamoy commented Jun 21, 2023

Just like include, I would like to be able to pass multiple template paths/names to the import tag, so that, quoting the docs, each will be tried in order until one is not missing.

This would help in the following case, where instead of defining and adding a test to the env, then conditions inside templates, we could just list the two paths in a single import tag:

Before:

self.env.tests["existing_template"] = lambda template_name: template_name in self.env.list_templates()
{% set lang_pth = "languages/" ~ locale ~ ".html" %}
{% if lang_pth is existing_template %}
    {% import lang_pth as lang %}
{% else %}
    {% import "languages/en.html" as lang %}
{% endif %}

{% import "_base/languages/en.html" as fallback %}

{% macro t(key) %}{{ lang.t(key) or fallback.t(key) }}{% endmacro %}

After:

{% import ["languages/" ~ locale ~ ".html", "_base/languages/en.html"] as lang %}
{% macro t(key) %}{{ lang.t(key) }}{% endmacro %}

I guess it would need to support the from ... import ... syntax too:

{% from ["languages/" ~ locale ~ ".html", "_base/languages/en.html"] import t as translate %}
{% macro t(key) %}{{ translate(key) }}{% endmacro %}
@pawamoy
Copy link
Sponsor Author

pawamoy commented Jun 23, 2023

Note to myself:

def _import_common(self, node: t.Union[nodes.Import, nodes.FromImport], frame: Frame) -> None:
    func_name = "get_or_select_template"
    if isinstance(node.template, nodes.Const):
        if isinstance(node.template.value, str):
            func_name = "get_template"
        elif isinstance(node.template.value, (tuple, list)):
            func_name = "select_template"
    elif isinstance(node.template, (nodes.Tuple, nodes.List)):
        func_name = "select_template"

    self.write(f"{self.choose_async('await ')}environment.{func_name}(")
    self.visit(node.template, frame)
    self.write(f", {self.name!r}).")

    if node.with_context:
        f_name = f"make_module{self.choose_async('_async')}"
        self.write(f"{f_name}(context.get_all(), True, {self.dump_local_context(frame)})")
    else:
        self.write(f"_get_default_module{self.choose_async('_async')}(context)")

@pawamoy
Copy link
Sponsor Author

pawamoy commented Jul 2, 2023

If this feature request is accepted I'm willing to send a PR 🙂

@davidism
Copy link
Member

davidism commented Jul 2, 2023

I'm not sure how this might interact with the caching that Jinja does when compiling templates. import isn't exactly the same mechanism as extends/include. I'm also not sure if it would hinder reasoning about what a given template is going to do, since the import could completely change the behavior of calls rather than only the appearance of blocks.

The behavior and caching of imports already has a lot of old open issues. I'd like old issues like #14, #253, #695, and #916 to be investigated before we decide on adding more complexity to the existing behavior. I'd welcome help with those.

@pawamoy
Copy link
Sponsor Author

pawamoy commented Jul 3, 2023

since the import could completely change the behavior of calls rather than only the appearance of blocks

I think there are many ways a Jinja template can become dynamic enough to make it harder to reason about what it does 😄 Surely two templates included in a single include could import and use different macros for example 🤷

But anyway, I totally understand your points. It's very easy for me to land here, send a PR with a test, and just enjoy a new release, but I completely lack the history behind the features, the complexity in supporting them, and the maintenance cost. So not so easy or enjoyable for you, the maintainer(s) 😅

I'll take a look at the issues you mention, and will try to help if I feel I'm capable and have some time to spare!
Thank you for your honest answer and for your time maintaining this amazing library. Jinja is one of the project I enjoy using most (and it's everywhere!) 🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants