avibrazil
avibrazil

Reputation: 330

How to strip indents (not just lines) from inner Jinja2 blocks?

Using Python’s Jinja, I’m concerned with both code readability and correct output. Here is my Jinja template:

M3U_TEMPLATE = jinja2.Template(
    textwrap.dedent("""\
        #EXTM3U
        
        {% for item in playlist %}
            #EXTALB:{{ item.strAlbum }} ({{ item.release }})
            #EXTART:{{ item.strAlbumArtists }}
            #EXTINF:{{ item.iDuration }},{{ item.strArtists }} - {{ item.strTitle }}
            {{ item.path }}
        {% endfor %}
    """)
)

Python’s textwrap.dedent() takes care of removing most of indent from the text. But I want to remove also the indents from the block of text inside the {% for %} loop. I want this kind of result:

#EXTM3U

#EXTALB:Offramp (1982)
#EXTART:Pat Metheny Group
#EXTINF:408,Pat Metheny Group - James
/media/Jazz, Fusion etc/Pat Metheny Group/1982 • Offramp/06 James.m4a

#EXTALB:Blue Moon (1961)
#EXTART:The Marcels
#EXTINF:133,The Marcels - Blue Moon
/media/Pop/The Marcels/1961 • Blue Moon/01 Blue Moon.m4a

But I’m getting this:

#EXTM3U

    #EXTALB:Offramp (1982)
    #EXTART:Pat Metheny Group
    #EXTINF:408,Pat Metheny Group - James
    /media/Jazz, Fusion etc/Pat Metheny Group/1982 • Offramp/06 James.m4a

    #EXTALB:Blue Moon (1961)
    #EXTART:The Marcels
    #EXTINF:133,The Marcels - Blue Moon
    /media/Pop/The Marcels/1961 • Blue Moon/01 Blue Moon.m4a

I want the item’s block indentation in code, but not in final result. So how to get rid of this? Can’t find a Jinja example that covers my case.

Upvotes: 0

Views: 82

Answers (4)

Sean Vieira
Sean Vieira

Reputation: 160043

Fortunately, Jinja already supports this quite handily in several different ways:

  1. By adding a trailing - to the directive - "You can also strip whitespace in templates by hand. If you add a minus sign (-) to the start or end of a block (e.g. a For tag), a comment, or a variable expression, the whitespaces before or after that block will be removed"

    {% for item in playlist -%}
    

    In your case, since you have multiple lines within the block that are prefixed with "raw" characters, this option will not work (subsequent lines in the loop will still have the wrong indentation).

  2. Use the keyword arguments to jinja2.Template that control this behavior for the entire template / Environment, namely trim_blocks and lstrip_blocks:

    M3U_TEMPLATE = jinja2.Template(
        textwrap.dedent("""
        {% for item in playlist %}
            #EXTALB:{{ item.strAlbum }} ({{ item.release }})
            #EXTART:{{ item.strAlbumArtists }}
            #EXTINF:{{ item.iDuration }},{{ item.strArtists }} - {{ item.strTitle }}
            {{ item.path }}
        {% endfor %}
        """),
        trim_blocks=True,
        lstrip_blocks=True
    )
    

Upvotes: 0

KamilCuk
KamilCuk

Reputation: 141698

You can just preprocess the template to remove leading spaces from each line.

template = textwrap.dedent("""\
        #EXTM3U
        
        {% for item in playlist %}
            #EXTALB:{{ item.strAlbum }} ({{ item.release }})
            #EXTART:{{ item.strAlbumArtists }}
            #EXTINF:{{ item.iDuration }},{{ item.strArtists }} - {{ item.strTitle }}
            {{ item.path }}
        {% endfor %}
""")
template_no_leading_spaces = "\n".join(line.lstrip() for line in template.splitlines())
M3U_TEMPLATE = jinja2.Template(template_no_leading_spaces)

Upvotes: 0

Georgina Skibinski
Georgina Skibinski

Reputation: 13397

You can just dedent post-rendering. The thing is also - you don't want to dedent template, because template should remain readable - that's why indents on loops, assignment clauses etc. Also - one of the variables coming from rendering might include any spacing character that will break your assumptions.

M3U_TEMPLATE = jinja2.Template(
    """
        {% for item in playlist %}
            #EXTALB:{{ item.strAlbum }} ({{ item.release }})
            #EXTART:{{ item.strAlbumArtists }}
            #EXTINF:{{ item.iDuration }},{{ item.strArtists }} - {{ item.strTitle }}
            {{ item.path }}
        {% endfor %}
    """
)

print(
    textwrap.dedent(
        M3U_TEMPLATE.render(
            playlist=[
                {"strAlbum": "album", "release": "v1.0", "strAlbumArtists": "artist", "iDuration": "tooLong", "strArtists": "AnotherArtist", "strTitle": "title", "path": "path"},
                {"strAlbum": "album1", "release": "v2.0", "strAlbumArtists": "artist1", "iDuration": "tooLong1", "strArtists": "AnotherArtist1", "strTitle": "title1", "path": "path1"}
            ]
        )
    )
)

Upvotes: 0

Bernietechy
Bernietechy

Reputation: 328

Can you please try this code:

I just introduced an hypen at the end of for loop item object.

M3U_TEMPLATE = jinja2.Template(
    textwrap.dedent("""\
        #EXTM3U
        
        {% for item in playlist -%}
        #EXTALB:{{ item.strAlbum }} ({{ item.release }})
        #EXTART:{{ item.strAlbumArtists }}
        #EXTINF:{{ item.iDuration }},{{ item.strArtists }} - {{ item.strTitle }}
        {{ item.path }}
        {% endfor %}
    """)
)

Upvotes: -1

Related Questions