Jinja: lstrip_blocks não preserva espaço antes do bloco final na mesma linha

Criado em 29 jan. 2020  ·  13Comentários  ·  Fonte: pallets/jinja

Observe o seguinte código de modelo:

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

Até Jinja2 2.10.3, isso resultaria em algo como

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

O código tem lstrip_blocks = True .

Agora, com 2.11.0, o código é renderizado assim:

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

@towoe dividiu a mudança de comportamento em https://github.com/pallets/jinja/commit/7d00a40465c89bee141ab5a3db545a20e7d30509 (por @ petee-d em https://github.com/pallets/jinja/issues/857)

De acordo com a documentação

lstrip_blocks
Se for definido como True, os espaços e tabulações à esquerda são removidos do início de uma linha para um bloco. O padrão é False.

Não acho que o espaço em branco deva ser removido antes de endfor , já que esse não é o espaço em branco "do início da linha". Estou entendendo mal isso ou a nova versão introduz uma mudança inesperada de comportamento?

Python 3.7.3 (mas também acontece no 3.5 em CI)

bug

Comentários muito úteis

Acabei de lançar 2.11.2 com isso.

Todos 13 comentários

Vou dar uma olhada nisso, desculpe por causar aquela sessão de depuração confusa que você vinculou! À primeira vista, parece que o comportamento está mais consistente agora e não tínhamos um teste para o comportamento anterior, mas terei que verificar. Seria possível usar {%+ endfor -%} para declarar explicitamente a preservação dos espaços em branco?

@davidism, obrigado por dar uma olhada.

Sim, podemos fazer alterações em edalize (a biblioteca onde Jinja é usado) de várias maneiras (adicione o + , mude para lstrip_blocks = False , etc.), mas eu gostaria primeiro de garantir que temos uma compreensão compartilhada do comportamento esperado.

Isso também me afeta da mesma forma que o pôster original. A documentação parece muito clara para mim que o comportamento do 2.11 está errado. De https://github.com/pallets/jinja/blob/2.11.x/docs/templates.rst#whitespace -control:

(Nada será removido se houver outros caracteres antes do início do bloco.)

Isso se deve ao # 858, que corrigiu um grande problema de velocidade com a análise do espaço. Posso corrigir o problema que isso causou, mas não quero apenas reverter essa alteração. Se alguém quiser brincar com a regex no lexer e corrigir isso, será um prazer revisá-la.

Desculpe pela correção que quebrou o comportamento pretendido de lstrip_blocks, lembro-me de ficar um pouco confuso sobre o que exatamente ele deveria fazer e de não ser capaz de encontrar a documentação adequada para ele. Não sei por que o Google não me levou para a parte de documentos vinculada ao @kenyon , muito estranho. Então, acabei descobrindo o comportamento pretendido a partir dos testes e da implementação e aparentemente não percebi isso.

Como @davidism disse, reverter a correção causaria outros problemas, então uma nova correção precisa ser desenvolvida. Vou tentar arranjar tempo para isso esta semana.

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

Aqui está o problema. Quando este modelo está sendo tokenizado, find("\n") recebe um texto contendo apenas o espaço entre {{ x }} e {% endif %} , não vê nova linha e remove o início do texto.

Adicionar "\n" in text a elif faz com que vários testes falhem porque a primeira linha de um modelo não contém uma nova linha, mas deve ser removida se houver apenas espaço. Se ficarmos um pouco mais inteligentes e rastrearmos se estamos na primeira linha, ainda falhará se trim_blocks também estiver habilitado, pois isso remove a nova linha como parte da regex.

Parece também que o comportamento de {%- raw %} {% endraw -%} foi afetado. Antes de 2.11.0, isso forçará um espaço neste lugar. Agora este espaço foi removido.

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 alguma chance de você ter algum tempo para dar uma olhada nisso de novo? Vou reverter para 2.11.2 caso contrário.

Ai, esqueci totalmente disso. Tentarei realmente reservar um tempo esta semana, caso contrário, reverta se os efeitos colaterais forem tão ruins quanto parecem.

Meu plano provisório é lançar no sábado. Deixe-me saber se você está trabalhando nisso, posso adiar se estiver.

Acho que tenho uma solução. Tentei não ser influenciado em minha correção por seus comentários anteriores @davidism e ainda assim cheguei à mesma solução que você tentou, apenas fui um pouco mais longe.

Em primeiro lugar, acho que originalmente pretendia que minha correção se comportasse de maneira diferente se l_pos = text.rfind("\n") + 1 não encontrasse nenhum caractere de nova linha, mas esquecesse-o. Portanto, não faço mais a remoção se não houver nova linha em text . Então também tentei resolver o problema com a source primeira linha que precisava ser removida de qualquer maneira, mas em vez de usar or pos == 0 , usei um sinalizador booleano line_starting inicializado em True. Então, eu apenas configuro este sinalizador após processar cada token com base em se a string correspondente termina com uma nova linha e também resolve o problema de trim_blocks. Veja a correção em # 1183.

O conjunto de testes atual passa, amanhã também adicionarei novos testes para os casos nesta edição e outros que eu possa pensar. Também executarei a versão original, a primeira correção e a segunda correção sobre meu conjunto de 5 GB recém-coletado de modelos criados pelo usuário que coletei em meu projeto, compararei as árvores de análise e o desempenho.

Testes adicionados, os testes de desempenho não mostraram degradação, então são feitos do meu lado. :)

Acabei de lançar 2.11.2 com isso.

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

mtrstudio picture mtrstudio  ·  5Comentários

priestc picture priestc  ·  5Comentários

glasserc picture glasserc  ·  4Comentários

hvnsweeting picture hvnsweeting  ·  4Comentários

AMDmi3 picture AMDmi3  ·  4Comentários