utils.templating package

Submodules

utils.templating.ansible module

utils.templating.ansible.render_ansible_strict(*, templar: Any, raw: Any, var_name: str, err_prefix: str, variables: dict, max_rounds: int = 6) → str

Strict rendering helper for lookup/filter plugins.

  • Renders via Ansible templar when possible (lookup(), filters, vars).

  • Automatic fallback is enabled for a SAFE subset (env lookup + varpaths + simple filters) only when templar can’t/won’t render and NO non-env lookup(…) is present.

  • Re-renders multiple rounds because intermediate results can still contain Jinja.

  • Hard-fails if output is empty or still contains unresolved Jinja markers.

utils.templating.ansible.to_plain(obj: Any) → Any

Convert Ansible/Jinja proxy types into plain Python so PyYAML can serialize.

utils.templating.expr module

Quote/paren-aware string splitters for the fallback expression evaluator.

Split out from utils.templating.ansible to keep that module under the per-file line budget.

utils.templating.expr.find_top_level_op(s: str, op: str) → int

Index of the first op at paren-depth 0 and outside quotes, else -1.

op is matched literally; callers pad word operators with spaces (e.g. " if ") so they don’t match inside identifiers.

utils.templating.expr.is_paren_wrapped(s: str) → bool

True iff the outer parentheses wrap the whole expression.

utils.templating.expr.split_list_items(s: str) → list[str]

Split list-literal inner content: "A, 'b'" -> ["A", "'b'"].

utils.templating.expr.split_top_level(s: str, sep: str) → list[str]

Split s on single-char sep at paren-depth 0 outside quotes.

utils.templating.jinja module

utils.templating.jinja.as_str(v: Any) → str
utils.templating.jinja.build_render_context(variables: dict[str, Any]) → tuple[dict, str]

Build a robust context for rendering Jinja-in-strings.

We intentionally do NOT rely on Ansible’s Templar here because in some lookup evaluation contexts it can silently keep Jinja markers untouched.

Context priority:
  1. variables dict

  2. hostvars[inventory_hostname] overlays variables (wins on conflicts)

utils.templating.jinja.looks_like_jinja(s: str) → bool
utils.templating.jinja.render_jinja2_strict_once(raw: str, *, ctx: dict, inv_host: str, var_name: str, err_prefix: str) → str

Render ONE pass using plain Jinja2 with StrictUndefined. Missing vars fail hard.

utils.templating.jinja.render_jinja2_strict_recursive(raw: str, *, ctx: dict, inv_host: str, var_name: str, err_prefix: str, max_passes: int = 5) → str
Render using strict Jinja2 repeatedly until:
  • no Jinja markers remain, OR

  • output stops changing, OR

  • max_passes is reached

Hard-fail if markers remain after max_passes / stabilization.

utils.templating.jinja.render_strict(value: Any, *, variables: dict[str, Any], var_name: str, err_prefix: str, max_passes: int = 5) → str

Convenience wrapper: - converts to string - if Jinja markers exist => render via strict Jinja2 using a robust context

(recursive with depth limit)

  • hard-fail if Jinja markers remain

Module contents