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

Clarify unroll in _finalize #76436

Merged
merged 2 commits into from Dec 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions changelogs/fragments/clarify-unroll.yml
@@ -0,0 +1,2 @@
minor_changes:
- Clarify in a comment that unrolling an iterator in ``Templar._finalize`` is actually necessary. Also switch to using the ``_unroll_iterator`` decorator directly to deduplicate code in ``Templar._finalize``. (https://github.com/ansible/ansible/pull/76436)
33 changes: 17 additions & 16 deletions lib/ansible/template/__init__.py
Expand Up @@ -261,7 +261,7 @@ def _is_rolled(value):


def _unroll_iterator(func):
"""Wrapper function, that intercepts the result of a filter
"""Wrapper function, that intercepts the result of a templating
and auto unrolls a generator, so that users are not required to
explicitly use ``|list`` to unroll.
"""
Expand Down Expand Up @@ -916,22 +916,23 @@ def _convert_bare_variable(self, variable):
# so just return it as-is
return variable

@_unroll_iterator
def _finalize(self, thing):
'''
A custom finalize method for jinja2, which prevents None from being returned. This
avoids a string of ``"None"`` as ``None`` has no importance in YAML.

If using ANSIBLE_JINJA2_NATIVE we bypass this and return the actual value always
'''
if _is_rolled(thing):
# Auto unroll a generator, so that users are not required to
# explicitly use ``|list`` to unroll
# This only affects the scenario where the final result of templating
# is a generator, and not where a filter creates a generator in the middle
# of a template. See ``_unroll_iterator`` for the other case. This is probably
# unncessary
return list(thing)

"""A custom finalize method for jinja2, which prevents None from being
returned. This avoids a string of ``"None"`` as ``None`` has no
importance in YAML.

The method is decorated with ``_unroll_iterator`` so that users are not
required to explicitly use ``|list`` to unroll a generator. This only
affects the scenario where the final result of templating
is a generator, e.g. ``range``, ``dict.items()`` and so on. Filters
which can produce a generator in the middle of a template are already
wrapped with ``_unroll_generator`` in ``JinjaPluginIntercept``.

If using jinja2_native we bypass this and return the actual value always.
"""
# FIXME remove this special case for jinja2_native by creating separate
# _finalized methods in AnsibleEnvironment/AnsibleNativeEnvironment.
if self.jinja2_native:
return thing

Expand Down