jiinja2 evaluation of default( "string" + var)

This works when item.send is defined and http_send is not:

{{ item.send | default(http_send) }}

This however fails when item.send is defined and item.context is not:

{{ item.send | default(‘GET /’ + item.context + ‘/healthcheck.jsp’ + ‘\\r\\n\\r\\n’) }}

Somehere the “string” + var expression gets evaluated regardless whether the default clause is used.

Does anybody know a workaround for this, or is this something patcheable in ansible, and if so any poiinters where to look at?

Thanks,

Serge

​I should have added that by 'not work' I meant on the second example I get
an error on the undefined variable in the default clause, whilst the
default clause isn't being used.​

I would expect the default to not be lazy-evaluated, so this doesn’t seem unusual to me.

​I'm sorry, not sure what you mean by lazy evaluated.
Nevertheless, how do you explain the default doesn't get evaluated when
it's just one variable,
and *does* get evaluated when it's a "string" + var construct?
In both cases where the initial variable is defined, so no default is
needed.​

Excerpts from Serge van Ginderachter's message of 2013-09-02 10:49:01 -0400:

Nevertheless, how do you explain the default doesn't get evaluated when
it's just one variable,
and *does* get evaluated when it's a "string" + var construct?
In both cases where the initial variable is defined, so no default is
needed.

Not sure why this is the case (haven't actually thought about it), but
this is actually a behavior of jinja2, not Ansible.

In Python:

    >>> import jinja2
    >>> t = jinja2.Template('''{{ foo|default("hello " + bar) }}''')

    >>> t.render(foo='yes', bar='no')
    'yes'

    >>> t.render(bar='no')
    'hello no'

    >>> t.render(foo='yes')
    *snip traceback*
    Undefined Error: 'foo' is undefined

On the other hand, and this shoudl fix Serge's problem, the following
works:

    >>> t = jinja2.Template('''{{ foo|default("hello " ~ bar) }}''')
    >>> t.render(foo='yes')
    'yes'

So using the '~' concatenation operator (which also does type coercion
and you should really just use for this generally) will allow Serge to
do what he wants.

I am not sure why the '+' operator behaves this way; we could poke in
jinja2's source or file something in its bug tracker:

    <https://github.com/mitsuhiko/jinja2/issues&gt;

Excerpts from C. Morgan Hamill's message of 2013-09-02 11:09:25 -0400:

    >>> import jinja2
    >>> t = jinja2.Template('''{{ foo|default("hello " + bar) }}''')

    >>> t.render(foo='yes', bar='no')
    'yes'

    >>> t.render(bar='no')
    'hello no'

    >>> t.render(foo='yes')
    *snip traceback*
    Undefined Error: 'foo' is undefined

Sorry, this should be "'bar' is undefined."

​Thanks! But, wWhilst this indeed works in plain Python​, unluckily it
doesn't work in ansible :frowning:

TASK: [debug msg={{var}}]

Excerpts from Serge van Ginderachter's message of 2013-09-02 15:26:30 -0400:

Thanks! But, whilst this indeed works in plain Python, unluckily it
doesn't work in ansible :frowning:

Hah, I didn't actually test it in Ansible!

That said, it's because Ansible does something like this when running
everything through jinja2:

    >>> import jinja2
    >>> e = jinja2.Environment(undefined=jinja2.StrictUndefined)
    >>> t = e.from_string('''{{ foo|default("hello " ~ bar) }}''')
    >>> t.render(foo='what up')
    *snip traceback*
    UndefinedError: 'bar' is undefined

Not sure why Ansible uses 'StrictUndefined' instead of the default
'jinja2.Undefined', but I assume it's for good reason. Perhaps someone
more familiar with the code base could jump in. That said, the jinja2
docs make it clear that 'StrictUndefined' will bark at you for
attempting to do anything with undefined variables other than testing
them to see if they are defined.

So there you go!

Exactly.

StrictUndefined is done because we want it to yell at you when variables are undefined.