Implement f-string like magic to pimp Djangos format_html()

2024/11/14 23:44:19

I would like to pimp format_html() of Django.

It already works quite nicely, but my IDE (PyCharm) thinks the variables are not used and paints them in light-gray color:

pycharm-variable-gray

AFAIK f-strings use some magic rewriting.

Is there a way to implement this, so that the IDE knows that the variables get used?

Related: Implement f-string like syntax, with Django SafeString support

Here is my current implementation:

def h(html):"""Django's format_html() on steroids"""def replacer(match):call_frame = sys._getframe(3)return conditional_escape(eval(match.group(1), call_frame.f_globals, call_frame.f_locals))return mark_safe(re.sub(r'{(.*?)}', replacer, html))

Somebody raised security concerns: I don't plan to create CMS where a user can edit these templates. These template h-strings are only for developers to have a convenient way to create HTML.

Before writing an answer, be sure you know the magic of conditional_escape()

Answer

Since you don’t seem above using dirty hacks, here’s a hack even dirtier than the one in the question:

class _escaper(dict):def __init__(self, other):super().__init__(other)def __getitem__(self, name):return conditional_escape(super().__getitem__(name))_C = lambda value: (lambda: value).__closure__[0]
_F = type(_C)
try:type(_C(None))(None)
except:pass
else:_C = type(_C(None))def h(f):if not isinstance(f, _F):raise TypeError(f"expected a closure, a {type(f).__name__} was given")closure = Noneif f.__closure__:closure = tuple(_C(conditional_escape(cell.cell_contents))for cell in f.__closure__)fp = _F(f.__code__, _escaper(f.__globals__),f.__name__, f.__defaults__, closure)return mark_safe(fp())

The h function takes a closure, and for each variable closed over, it creates another, escaped copy of the variable, and modifies the closure to capture that copy instead. The globals dict is also wrapped to ensure references to globals are likewise escaped. The modified closure is then immediately executed, its return value is marked safe and returned. So you must pass h an ordinary function (no bound methods, for example) which accepts no arguments, preferably a lambda returning an f-string.

Your example then becomes:

foo = '&'
bar = h(lambda: f'<span>{foo}</span>')
assert h(lambda: f'<div>{bar}</div>') == '<div><span>&amp;</span></div>'

There’s one thing, though. Due to how this has been implemented, you can only ever refer directly to variables inside interpolation points; no attribute accesses, no item lookups, nothing else. (You shouldn’t put string literals at interpolation points either.) Otherwise though, it works in CPython 3.9.2 and even in PyPy 7.3.3. I make no claims about it ever working in any other environment, or being in any way future-proof.

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

Related Q&A

Selecting a set of numbers from a list which add up to a given value [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.Want to improve this question? Update the question so it focuses on one problem only by editing this post.Closed 9…

List of even numbers at even number indexes using list comprehension [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.Want to improve this question? Update the question so it focuses on one problem only by editing this post.Closed 9…

How do I check if a list of lists exists in a list of lists?

I got a list of lists b and I want to check if they exist in list a which is also a list of lists. Im currently using the following method which is quite time-consuming. Is there a faster way? b = [[…

How do i print out a number triangle in python? [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…

Real time clock display in Tkinter

I want to create real time clock using Tkinter and time library. I have created a class but somehow I am not able to figure out my problem.My codefrom tkinter import *import timeroot = Tk()class Clock:…

cffi export python code to dll , how to read image object in @ffi.def_extern()

i am trying to convert my python code to dll using cffi so i can access this code in my c# apllication, and i am trying to send image my c# code to python function, below is my code to read the file an…

Python 2.7.5 and Python 3.6.5

I have installed Python 3.6.5 however when i type Python it shows Python 2.7.5. Id like to use Python 3.[aravind@aravind05 Python-3.6.5]$ python3 --version Python 3.6.5[aravind@aravind05 Python-3.6.5]$…

How use creating polynomial expression like function in Python?

Id like to write a program in Python where user define a deegre of polynomial and coefficients (a,b,c). When program create a polynomial expression with this data Id like to use it like function becaus…

how to merge two sublists sharing any number in common? [duplicate]

This question already has an answer here:Using sublists to create new lists where numbers dont repeat(1 answer)Closed 9 years ago.Given thatg=[[1,2,3,4],[4,5,6],[6,7],[10,11]]What code should I use to …

\n is treated as \ and n [duplicate]

This question already has an answer here:Compiler error "error: stray \ in program" in macro definition(1 answer)Closed 10 years ago.The following python codeenv.Command(versionFile, allSrcs …