I'm stuck in a Jinja implementation problem.
Here is my little python script:
path = Path(__file__).parent
env = Environment(
loader=FileSystemLoader(path / "templates")
)
template = env.get_template("template1.rst")
rendered = template.render(sample={"a": {"b": "c"}})
And here is my template for jinja:
.. toctree::
:maxdepth: 3
{% for k, v in sample.items() recursive %}
- {{ k }}:
{%- if v is string %}
{{ v }}
{%- else %}
{{ loop(v) }}
{%- endif -%}
{%endfor%}
The execution returns this error:
File "/home/jaja/Bureau/coding/bac_a_sable/sphinx_test/templates/template1.rst", line 5, in top-level template code
{% for k, v in sample.items() recursive %}
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/jaja/Bureau/coding/bac_a_sable/sphinx_test/templates/template1.rst", line 21, in template
{{ loop(v) }}
^^^^^^^^^^^^^^^^^^
File "/home/jaja/Bureau/coding/bac_a_sable/sphinx_test/templates/template1.rst", line 5, in template
{% for k, v in sample.items() recursive %}
^^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: not enough values to unpack (expected 2, got 1)
As the v
value of first loop is {"b": "c"}
, it must work, but it doesn't.
Is Jinja unable to recursively loop in dictionaries ?
immediate fix
When you start the loop, you use sample.items()
iterator -
{% for k, v in sample.items() recursive %}
^^^^^^^^^^^^^^
When you recur, you are passing the dict itself -
{%- else %}
{{ loop(v) }}
^
Simply change this to -
{%- else %}
{{ loop(v.items()) }}
^^^^^^^^^
naive test
An improvement to the entire loop would be to change the test to mapping, instead of string.
{% for k, v in sample.items() recursive %}
- {{ k }}:
{%- if v is mapping %}
{{ loop(v.items()) }}
{%- else %}
{{ v }}
{%- endif -%}
{%endfor%}
This ensures that you only recur on dicts. In the original code, the else
will recur any non-string input. If the data included a number, you would've encountered a different error.
nested input, nested output
Preserving the levels of nesting in the output can be challenging. Consider using the loop.depth helper to create the correct whitespace -
{% for k, v in sample.items() recursive %}
{{ " " * (loop.depth - 1) }}- {{ k }}:
{%- if v is mapping %} {{- loop(v.items()) }}
{%- else %} {{ v }}
{%- endif -%}
{%endfor%}
Given sample
input -
sample = {
'a': {
'b': 1,
'c': { 'd': 2 },
'e': 'f',
},
}
Output
- a:
- c:
- d: 2
- b: 1
- e: f