kolypto / j2cli

Jinja2 Command-Line Tool, reworked
http://pypi.python.org/pypi/j2cli
BSD 2-Clause "Simplified" License
744 stars 82 forks source link

An option to keep undefined variables #41

Open pietervogelaar opened 5 years ago

pietervogelaar commented 5 years ago

It would be nice to support multi stage rendering as described at https://stackoverflow.com/a/53134416/948378.

from jinja2 import Environment, BaseLoader,DebugUndefined
rtemplate =Environment(loader=BaseLoader,undefined=DebugUndefined) \
           .from_string("{{ a }} is defined, but {{ b}} is undefined")

print(rtemplate.render({"a":"a"}))

# The result is:
# a is defined, but {{ b }} is undefined
kolypto commented 5 years ago

Hi @pietervogelaar , thank you for the feature request: you're not the first one asking about this :)

I wonder what the use case could be. Wouldn't it be possible in your case to merge the variables before rendering a template, instead of doing this multi-stage rendering? Isn't it prone to errors?

m000 commented 5 years ago

DebugUndefined may indeed be an unorthodox way to implement multi-stage processing. But since this a feature already implemented in Jinja2, and exposing it adds practically no cruft to j2cli, I can't see why not to expose it if someone has a use for it.

Personally, I use this behaviour in its original scope: debugging. If you are trying to render and debug 100+ templates you can generate your output using DebugUndefined. Then a grep -r '{{' output/ will help you quickly fix missing variables in the context, without going through multiple runs.

Note that I had implemented this (among other things) in #13. The patch is now outdated, but it should be straightforward to pull the relevant lines. I can send a new PR only with this part if you're too busy.

peter-evans commented 11 months ago

My use case for this is that I want to template GitHub Actions workflow files. GitHub Actions uses ${{ }} for it's own templating. I want to ignore those and just template what I pass data for.

e.g. j2cli should just ignore secrets if --undefined is set in my data.

          token: ${{ secrets.MY_TOKEN }}

But it errors:

jinja2.exceptions.UndefinedError: 'secrets' is undefined

This is quite disappointing because it means j2cli (and perhaps jinja2 altogether) is unusable for my use case. I'll need to find another templating engine if I can't figure out a way to keep undefined variables.

m000 commented 11 months ago

My use case for this is that I want to template GitHub Actions workflow files. GitHub Actions uses ${{ }} for it's own templating. I want to ignore those and just template what I pass data for.

e.g. j2cli should just ignore secrets if --undefined is set in my data.

          token: ${{ secrets.MY_TOKEN }}

But it errors:

jinja2.exceptions.UndefinedError: 'secrets' is undefined

This is quite disappointing because it means j2cli (and perhaps jinja2 altogether) is unusable for my use case. I'll need to find another templating engine if I can't figure out a way to keep undefined variables.

How about using {% raw %} blocks https://jinja.palletsprojects.com/en/3.1.x/templates/#escaping?

Or perhaps a custom filter, where you would write {{ "secrets.MY_TOKEN" | ghaction_env }} in the template, to get ${{ secrets.MY_TOKEN }} in the output?

peter-evans commented 11 months ago

{% raw %} probably would work, but I found the best workaround was just to change the start/end delimiters with --customize custom.py.

# custom.py file for j2cli

def j2_environment_params():
    return dict(
        # modify the variable delimiters to avoid conflicts with GitHub Actions templating
        variable_start_string='<<',
        variable_end_string='>>',
    )

Sorry for the noise in this issue. I still think it would be a useful feature to just ignore undefined keys, though.