Jinja: lstrip_blocks不会在同一行的结尾块之前保留空间

创建于 2020-01-29  ·  13评论  ·  资料来源: pallets/jinja

看下面的模板代码:

set_property verilog_define {
  {%- for k, v in vlogdefine.items() %}{{ k }}={{ v|param_value_str }} {% endfor -%}
  } [get_filesets sources_1]

https://github.com/olofk/edalize/blob/bdb6c9ccc666e9f60333279ad53ed09cda88b3dc/edalize/templates/vivado/vivado-project.tcl.j2#L27 -L29

直到Jinja2 2.10.3,这都会导致类似

set_property verilog_define {vlogdefine_bool=1 vlogdefine_int=42 vlogdefine_str=hello } [get_filesets sources_1]

https://github.com/olofk/edalize/blob/bdb6c9ccc666e9f60333279ad53ed09cda88b3dc/tests/test_vivado/test_vivado_0.tcl#L10

该代码具有lstrip_blocks = True

现在,使用2.11.0时,代码将如下所示:

set_property verilog_define {vlogdefine_bool=1vlogdefine_int=42vlogdefine_str=hello} [get_filesets sources_1]

@towoe将行为更改https://github.com/pallets/jinja/commit/7d00a40465c89bee141ab5a3db545a20e7d30509 (作者@ petee-d在https://github.com/pallets/jinja/issues/857)

根据文档

lstrip_blocks
如果将其设置为True,则前导空格和制表符将从行的开头剥离到一个块。 默认为False。

我不认为应该在endfor之前删除空格,因为这不是“从行首开始”的空格。 我是不是误解了,还是新版本引入了意想不到的行为更改?

Python 3.7.3(但在CI中的3.5上也会发生)

最有用的评论

刚刚发布了2.11.2。

所有13条评论

我会进行调查,对于造成您链接的令人困惑的调试会话的事件,我们深表歉意! 乍一看,现在的行为看起来更加一致,并且我们没有对以前的行为进行测试,但是我必须进行检查。 您是否可以使用{%+ endfor -%}显式声明保留空白?

@davidism感谢您的关注。

是的,我们可以通过多种方式(使用+ ,切换到lstrip_blocks = False等等)来对edalize(使用Jinja的库)进行更改,但是我想首先确保我们对预期的行为有共同的理解。

这也以与原始海报相同的方式影响我。 对我来说,文档似乎很清楚2.11的行为是错误的。 从https://github.com/pallets/jinja/blob/2.11.x/docs/templates.rst#whitespace -control:

(如果在该块的开头之前还有其他字符,则不会删除任何内容。)

这是由于#858,它解决了解析空间中的一个很大的速度问题。 对于解决此问题,我很好,但是我不想仅还原该更改。 如果有人想在词法分析器中使用正则表达式并解决此问题,我很乐意对其进行复习。

很抱歉,该修复程序破坏了lstrip_blocks的预期行为,我记得对于应该执行的操作有点困惑,并且无法为其找到合适的文档。 我不确定Google为什么不带我去链接到文档部分的@kenyon ,这很奇怪。 因此,我最终从测试和实现中弄清了预期的行为,显然错过了这一点。

正如@davidism所说,还原该修补程序还会导致其他麻烦,因此需要设计一个新的修补程序。 我将在本周争取时间。

from jinja2 import Template

t = Template(
    "{% if x %}{{ x }} {% endif %}y",
    lstrip_blocks=True,
)
out = t.render(x="x")
assert out == "x y"

https://github.com/pallets/jinja/blob/547e6e39ec3994c9dd0c806ee7bb29353843060e/src/jinja2/lexer.py#L721 -L735

这是问题。 当此模板被标记化时, find("\n")是仅包含{{ x }}{% endif %}之间的空格的递交文本,看不到换行符,然后从文本开头删除。

"\n" in textelif会使一堆测试失败,因为模板的第一行不包含换行符,但是如果模板只有空格,则应将其删除。 如果我们变得更聪明一点并跟踪我们是否在第一行,那么如果还启用了trim_blocks ,它仍然会失败,因为这会将正则表达式中的换行符删除。

似乎{%- raw %} {% endraw -%}的行为也受到影响。 在2.11.0之前,这将在该位置强制留出空格。 现在,该空间已删除。

from jinja2 import Template

t = Template(
    "{{x}}\n{%- raw %} {% endraw -%}\n{{ y }}",
    lstrip_blocks=True,
)
out = t.render(x="x", y="y")
assert out == "x y"

@ petee-d有机会您有时间再看一遍吗? 否则,我将其还原为2.11.2。

哎呀,完全忘记了这一点。 将尝试在本周实际抽出时间,否则在副作用严重时将其恢复。

我的暂定计划是在周六放映。 让我知道您是否正在努力,如果可以,我可以将其推迟。

我想我有个解决办法。 我试图不受您先前@davidism的评论的

首先,我认为如果l_pos = text.rfind("\n") + 1没有找到任何换行符,但后来却忘记了它,我本来打算使修正的行为有所不同。 因此,如果text没有换行符,我将不再进行剥离。 然后,我还尝试解决source第一行仍然需要删除的问题,但我没有使用or pos == 0 ,而是使用了一个line_starting布尔值标记为True的布尔值。 然后,根据匹配的字符串是否以换行符结尾,在处理完每个令牌后,我就设置了该标志,并且还解决了trim_blocks问题。 请参阅#1183中的修复程序。

当前的测试套件通过了,明天我还将针对此问题以及我能想到的其他情况添加新的测试。 我还将运行有关从我的项目中收集的新收集的5GB用户创建的模板集的原始版本,第一个修复程序和第二个修复程序,比较解析树和性能。

添加了测试,性能测试没有显示降级,所以这是从我这边完成的。 :)

刚刚发布了2.11.2。

此页面是否有帮助?
0 / 5 - 0 等级