如何解决实现 f-string like magic 来拉皮条 Django 的 format_html()
我想拉皮条客 Django 的 format_html()
。
它已经很好地工作了,但是我的 IDE (PyCharm) 认为变量没有被使用,并以浅灰色绘制它们:
AFAIK f-strings 使用了一些神奇的重写。
有没有办法实现这一点,以便 IDE 知道变量被使用了?
相关:Implement f-string like syntax,with Django SafeString support
这是我目前的实现:
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))
有人提出安全问题:我不打算创建用户可以编辑这些模板的 CMS。这些模板 h 字符串仅供开发人员方便地创建 HTML。
在写答案之前,请确保您了解conditional_escape()
解决方法
由于您似乎并没有使用肮脏的黑客,这里有一个比问题中的更肮脏的黑客:
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 = None
if 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())
h
接受一个闭包,对于每个关闭的变量,它会创建另一个变量的转义副本,并修改闭包以捕获该副本。 globals dict 也被包装以确保对 globals 的引用同样被转义。然后立即执行修改后的闭包,其返回值被标记为安全并返回。因此,您必须传递 h
一个不接受任何参数的普通函数(例如,没有绑定方法),最好是返回 f 字符串的 lambda。
你的例子变成了:
foo = '&'
bar = h(lambda: f'<span>{foo}</span>')
assert h(lambda: f'<div>{bar}</div>') == '<div><span>&</span></div>'
不过,有一件事。由于这是如何实现的,您只能直接引用插值点内的变量;没有属性访问,没有项目查找,没有别的。 (你也不应该在插值点放置字符串文字。)否则,它可以在 CPython 3.9.2 甚至 PyPy 7.3.3 中工作。我没有声称它曾经在任何其他环境中工作过,或者以任何方式面向未来。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。