Why is this Jinja nl2br filter escaping brs but not ps?

2024/11/18 19:55:51

I am attempting to implement this Jinja nl2br filter. It is working correctly except that the <br>'s it adds are being escaped. This is weird to me because the <p>'s are not being escaped and they are all in the same string.

I am using flask so the Jinja autoescape is enabled. I was really hopeful when I found this guy saying the autoescape and the escape(value) may have been causing double escaping, but removing the escape() did not help.

Here is my modified code and it's output:

@app.template_filter()
@evalcontextfilter
def nl2br(eval_ctx, value):_paragraph_re = re.compile(r'(?:\r\n|\r(?!\n)|\n){2,}')result = u'\n\n'.join(u'<p>%s</p>' % escape(p.replace(u'\r\n', u'<br>\n')) for p in _paragraph_re.split(value))if eval_ctx.autoescape:result = Markup(result)return result

input:

u'1\r\n2\r\n\r\n3\r\n4\r\n\r\n5\r\n6\r\n7'

output:

<p>1&lt;br&gt;
2</p><p>3&lt;br&gt;
4</p><p>5&lt;br&gt;
6&lt;br&gt;
7</p>

desired output:

<p>1<br>2</p><p>3<br>4</p><p>5<br>6<br>7</p>

What could be causing the <br>'s to be escaped but allowing the <p>'s?

Answer

The nl2br filter doesn't handle Markup objects correctly. If value is Markup, then the inserted <br> tags will be escaped. To fix it, the <br> tag must be Markup too:

@app.template_filter()
@evalcontextfilter
def nl2br(eval_ctx, value):_paragraph_re = re.compile(r'(?:\r\n|\r(?!\n)|\n){2,}')result = u'\n\n'.join(u'<p>%s</p>' % p.replace(u'\n', Markup('<br>\n'))for p in _paragraph_re.split(value))if eval_ctx.autoescape:result = Markup(result)return result

Note: I normalized line endings to \n.

Here's a longer explanation of what's happening:

Splitting Markup objects, produces many Markup objects:

>>> Markup("hello there").split()
[Markup(u'hello'), Markup(u'there')]

According to Jinja's documentation for Markup:

Operations on a markup string are markup aware which means that all arguments are passed through the escape() function.

Looking back at the main transformation of nl2br, we can see what's happening and why it didn't work:

result = u'\n\n'.join(u'<p>%s</p>' % p.replace(u'\n', u'<br>\n')for p in _paragraph_re.split(value))

u'\n\n' and u'<br>\n' are unicode strings, but p is Markup having been split from value, which is a Markup object. p.replace tries to add a unicode string to Markup object p, but the Markup object correctly intercepts and escapes the string first.

The <p> tags aren't escaped because of how Python assembles the final string, since the % formatting method is called on a unicode string, it uses the unicode representation of the elements passed to it. The Markup elements have already been declared safe, so they aren't escaped any further. result ends up as a unicode string.

https://en.xdnf.cn/q/71021.html

Related Q&A

select certain monitor for going fullscreen with gtk

I intend to change the monitor where I show a fullscreen window. This is especially interesting when having a projector hooked up.Ive tried to use fullscreen_on_monitor but that doesnt produce any visi…

Load Excel add-in using win32com from Python

Ive seen from various questions on here that if an instance of Excel is opened from Python using:xl = win32com.client.gencache.EnsureDispatch(Excel.Application) xl.Visible = True wb = xl.Workbooks.Open…

iterating through a list removing items, some items are not removed

Im trying to transfer the contents of one list to another, but its not working and I dont know why not. My code looks like this:list1 = [1, 2, 3, 4, 5, 6] list2 = []for item in list1:list2.append(item)…

Apply function to create string with multiple columns as argument

I have a dataframe like this:name . size . type . av_size_type 0 John . 23 . Qapra . 22 1 Dan . 21 . nukneH . 12 2 Monica . 12 . kahless . 15I wa…

Popping items from a list using a loop in Python [duplicate]

This question already has answers here:Strange result when removing item from a list while iterating over it in Python(12 answers)Closed 3 months ago.Im trying to write a for loop in python to pop out …

Django Admin Media prefix URL issue

i ve the following folder structuresrc\BAT\templates\admin\base.html src\BAT\media\base.css src\BAT\media\admin-media\base.csssettings.pyMEDIA_ROOT = os.path.join( APP_DIR, media ) MEDIA_URL = /media/ …

lazy processpoolexecutor in Python?

I have a large number of tasks that I want to execute and make the results available via a generator. However, using a ProcessPoolExecutor and as_completed will evaluate the results greedily and store …

error occurs when installing cryptography for scrapy in virtualenv on OS X [closed]

Closed. This question needs debugging details. It is not currently accepting answers.Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to repro…

Can Python do DI seamlessly without relying on a service locator?

Im coming from the C# world, so my views may be a little skewed. Im looking to do DI in Python, however Im noticing a trend with libraries where they all appear to rely on a service locator. That is, y…

Producing pdf report from python with bullet points

I would like to produce a dynamic pdf document from a python script that looks like the image below. Each sentence starts with a bullet point, and the text and number of lines depends on what the user …