最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

python - How to strip indents (not just lines) from inner Jinja2 blocks? - Stack Overflow

programmeradmin1浏览0评论

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.

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.

Share Improve this question edited Feb 11 at 1:07 avibrazil asked Feb 9 at 11:35 avibrazilavibrazil 3302 silver badges12 bronze badges 7
  • I've seen that question and answer before and it does not cover my problem, so thats why I submitted a new question. Reading the content of both questions, and more carefully the titles, shows the difference. The other question covers extra lines only, while my questions concerns indentation space inside Jinja blocks. Two different kinds of spaces. – avibrazil Commented Feb 9 at 11:53
  • I don't follow what's different between this question and the suggested dupe – roganjosh Commented Feb 9 at 12:07
  • Also, this isn't an minimal reproducible example because I can't actually run it exactly as you have it and I'm not sure why you haven't included playlist – roganjosh Commented Feb 9 at 12:13
  • 1 I agree with the OP, the dupe target doesn't cover their use case. – snakecharmerb Commented Feb 9 at 13:49
  • An idea, not sure if functional, might be to use a carriage return \r. But it wouldn't work for a file opened in a web browser most likely, even if it might to the job in some text editors. – FLAK-ZOSO Commented Feb 9 at 14:04
 |  Show 2 more comments

4 Answers 4

Reset to default 0

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"}
            ]
        )
    )
)

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)

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
    )
    

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 %}
    """)
)
发布评论

评论列表(0)

  1. 暂无评论