82

I'm using jinja 2 to output a yaml file but can't seem to get rid of a trailing newline and the end of a for loop. Eg the below

 - request:
        path: {{ path }}
        headers:
          origin: 'somedomain.com'
          user-agent: 'agent'
          referer: 'some.domain.com'
          authority: 'somedomain.com'
        querystring:
          {% for key, value in querystring.items() -%}
          {{ key }}: '{{ value }}'
          {% endfor %}
      response:
        content:
          file: {{ content }}

gives me the output:

- request:
    path: /some/path
    headers:
      origin: 'somedomain.com'
      user-agent: 'agent'
      referer: 'somedomain.com'
      authority: 'somedomain.com'
    querystring:
      postcode: 'xxxxxx'
      houseNo: '55'

  response:
    content:
      file: address.json

With an additional unwanted blank line after houseNo. How do I get rid of this line?

dreftymac
  • 31,404
  • 26
  • 119
  • 182
Yunti
  • 6,761
  • 12
  • 61
  • 106

6 Answers6

109

Change your loop to strip whitespace from the top AND bottom of the output (notice extra - at the for loop close):

{% for key, value in querystring.items() -%}
  {{ key }}: '{{ value }}'
{%- endfor %}

In my tests (using https://github.com/abourguignon/jinja2-live-parser), the - must come after the first {%, not before the last to achieve what you're asking for.

Docs: https://jinja.palletsprojects.com/en/latest/templates/#whitespace-control

ggorlen
  • 44,755
  • 7
  • 76
  • 106
tknickman
  • 4,285
  • 3
  • 34
  • 47
  • Yeah, you are right. Prepending the `-` instead of appending preserves the indentation and does not screw up the spaces in the next line. – alecxe Apr 26 '16 at 17:09
  • Correct, I didn't remember this detail until I played around with it again. – tknickman Apr 26 '16 at 17:11
  • 33
    For me, this puts all the key: value pairs on a single line. I don't understand why this answer was accepted. – Honza Sep 30 '16 at 09:19
  • 6
    Just because I didn't see this part of the explanation anywhere, I figured I'd add it. Putting a `-` before the second percent sign on the first line of the for loop removes newlines before the added line. Putting a `-` after the first percent sign on the last line of the for loop removes newlines after the added line. Combine them both, and you get 0 newlines. Have only one, and you only get a newline to separate a line, but not an extra newline between each line. In my case, I wanted a newline before the loop but not after each element, so I put the `-` before the `endfor`. Hope this helps – dddJewelsbbb Nov 19 '18 at 16:52
25

I think you can get rid of it using the whitespace control feature. Thus I would modify the endfor block to {% endfor -%}

See if that does it!

Josh Kelley
  • 56,064
  • 19
  • 146
  • 246
Scratch'N'Purr
  • 9,959
  • 2
  • 35
  • 51
13

For those using Flask who arrive here, these lines did the trick for me:

app = Flask(__name__)
app.jinja_env.lstrip_blocks = True
app.jinja_env.trim_blocks = True
MarredCheese
  • 17,541
  • 8
  • 92
  • 91
  • 4
    Maybe you could make your answer more generic by explaining that you can set it in the Environment object: `Environment(trim_blocks=True, lstrip_blocks=True)` – Adrien H Apr 01 '19 at 07:54
7

I found a way to solve this problem:

- request:
    path: {{ path }}
    headers:
      origin: 'somedomain.com'
      user-agent: 'agent'
      referer: 'some.domain.com'
      authority: 'somedomain.com'
    querystring: >-
      {% for key, value in querystring.items() -%}
      {{ key }}: '{{ value }}'
      {% endfor %}
  response:
    content:
      file: {{ content }}
  • >, |: "clip": keep the line feed, remove the trailing blank lines.
  • >-, |=: "strip": remove the line feed, remove the trailing blank lines.
  • >+, |+: "keep": keep the line feed, keep trailing blank lines.

Thx Steve Bennett's post: In YAML, how do I break a string over multiple lines?

Zhou Shuai-Ming
  • 113
  • 1
  • 4
  • 2
    Thanks for this, helped me fix my issue, how ever the correct operator i had to use is "|-" (pipe minus), now my multi line string is correctly transported to my json files, with all line ending except the last one. – diegeelvis_SA Aug 17 '18 at 11:06
7

The accepted answer is only half of the solution, because it removes all newlines.

You can avoid the trailing newline by first removing all newlines (using the minus signs at -%} and {%- in the for loop), and then inserting the desired newlines at the right place (using the loop.last condition).

The following templates renders a dictionary, d, to as JSON text:

{
    {% for key, value in d.items() -%}
    "{{ key }}": "{{ value }}"{{ ",
    " if not loop.last }}
    {%- endfor %}
}

For d = {'a':'1', 'b':'2'}, the template renders to

{
    "a": "1",
    "b": "2"
}
Kasper Dokter
  • 91
  • 1
  • 5
2

You can suppress rendering of the below lines:

<% for ... %>
<% endfor %>
<% if ... %>
<% endif %>

by setting trim_blocks=True and lstrip_blocks=True in your jinja2 environment. See the example below, info from their docs

context = {'querystring': querystring, 'path': path, 'content': content}    
jinja_env = jinja2.Environment(
    loader=jinja2.FileSystemLoader('templates/'),
    trim_blocks=True,
    lstrip_blocks=True
)
print(jinja_env.get_template('my_template.yaml').render(context))
spacether
  • 2,136
  • 1
  • 21
  • 28