Jinja: lstrip_blocks bewahrt keinen Platz vor dem Endblock in derselben Zeile

Erstellt am 29. Jan. 2020  ·  13Kommentare  ·  Quelle: pallets/jinja

Sehen Sie sich den folgenden Vorlagencode an:

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

Bis zu Jinja2 2.10.3 würde dies zu so etwas führen

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

Der Code hat lstrip_blocks = True .

Jetzt mit 2.11.0 wird der Code wie folgt gerendert:

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

@towoe halbierte die Verhaltensänderung auf https://github.com/pallets/jinja/commit/7d00a40465c89bee141ab5a3db545a20e7d30509 (von @ petee-d in https://github.com/pallets/jinja/issues/857)

Nach der Dokumentation

lstrip_blocks
Wenn dies auf True gesetzt ist, werden führende Leerzeichen und Tabulatoren vom Zeilenanfang bis zu einem Block entfernt. Der Standardwert ist False.

Ich denke nicht, dass das Leerzeichen vor dem endfor , da dies kein Leerzeichen "vom Anfang der Zeile" ist. Verstehe ich das falsch oder führt die neue Version zu einer unerwarteten Verhaltensänderung?

Python 3.7.3 (kommt aber auch unter 3.5 in CI vor)

bug

Hilfreichster Kommentar

Gerade 2.11.2 damit veröffentlicht.

Alle 13 Kommentare

Ich werde mich darum kümmern, entschuldigen Sie die Ursache für diese verwirrende Debugging-Sitzung, die Sie verlinkt haben! Auf den ersten Blick sieht es so aus, als ob das Verhalten jetzt konsistenter ist, und wir hatten keinen Test für das vorherige Verhalten, aber ich muss es überprüfen. Wäre es Ihnen möglich, mit {%+ endfor -%} explizit die Beibehaltung des Leerzeichens zu deklarieren?

@ Davididismus danke für den Blick.

Ja, wir können Änderungen an edalize (der Bibliothek, in der Jinja verwendet wird) auf verschiedene Weise vornehmen ( + hinzufügen, zu lstrip_blocks = False wechseln usw.), aber ich möchte zunächst sicherstellen, dass dies der Fall ist dass wir ein gemeinsames Verständnis des erwarteten Verhaltens haben.

Das betrifft mich genauso wie das Originalplakat. Die Dokumentation scheint mir ziemlich klar zu sein, dass das 2.11-Verhalten falsch ist. Von https://github.com/pallets/jinja/blob/2.11.x/docs/templates.rst#whitespace -control:

(Nichts wird entfernt, wenn vor dem Beginn des Blocks andere Zeichen vorhanden sind.)

Dies liegt an # 858, das ein ziemlich großes Geschwindigkeitsproblem beim Parsen des Speicherplatzes behoben hat. Ich bin in Ordnung mit der Behebung dieses Problems, das es verursacht hat, aber ich möchte diese Änderung nicht einfach rückgängig machen. Wenn jemand mit dem regulären Ausdruck im Lexer herumspielen und dies beheben möchte, kann ich ihn gerne überprüfen.

Es tut mir leid, dass das Update das beabsichtigte Verhalten von lstrip_blocks verletzt hat. Ich erinnere mich, dass ich etwas verwirrt darüber war, was genau es tun soll, und nicht in der Lage war, die richtige Dokumentation dafür zu finden. Ich bin mir nicht sicher, warum Google mich nicht zum Dokumententeil @kenyon geführt hat, mit dem verlinkt ist, sehr seltsam. Also habe ich das beabsichtigte Verhalten aus den Tests und der Implementierung herausgefunden und dies anscheinend verpasst.

Wie @davidism sagte, würde das

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

Hier ist das Problem. Wenn diese Vorlage mit einem Token versehen wird, wird find("\n") Text übergeben, der nur das Leerzeichen zwischen {{ x }} und {% endif %} , keine neue Zeile sieht und dann vom Anfang des Textes entfernt wird.

Durch Hinzufügen von "\n" in text zu elif schlagen eine Reihe von Tests fehl, da die erste Zeile einer Vorlage keine neue Zeile enthält, sondern entfernt werden sollte, wenn nur Platz vorhanden ist. Wenn wir ein bisschen schlauer werden und verfolgen, ob wir uns in der ersten Zeile befinden, schlägt dies immer noch fehl, wenn trim_blocks ebenfalls aktiviert ist, da dadurch die neue Zeile als Teil des regulären Ausdrucks entfernt wird.

Es scheint auch, dass das Verhalten von {%- raw %} {% endraw -%} betroffen ist. Vor 2.11.0 wird an dieser Stelle ein Leerzeichen erzwungen. Jetzt wird dieser Platz entfernt.

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 Hast du eine Chance, dir das noch einmal anzuschauen? Ich werde es sonst für 2.11.2 zurücksetzen.

Autsch, total vergessen. Ich werde versuchen, die Zeit in dieser Woche tatsächlich zu bestimmen, andernfalls werde ich sie zurücksetzen, wenn die Nebenwirkungen so schlimm sind, wie es scheint.

Mein vorläufiger Plan ist die Veröffentlichung am Samstag. Lassen Sie mich wissen, wenn Sie daran arbeiten. Wenn ja, kann ich das zurückschieben.

Ich glaube, ich habe eine Lösung. Ich habe versucht, mich in meinem Fix nicht von Ihren vorherigen Kommentaren @davidism beeinflussen zu lassen, und

Zunächst denke ich, dass ich ursprünglich beabsichtigt hatte, dass sich mein Fix anders verhält, wenn l_pos = text.rfind("\n") + 1 kein Zeilenumbruchzeichen gefunden hat, es dann aber vergessen hat. Also mache ich das Strippen nicht mehr, wenn es in text keinen Zeilenumbruch gibt. Dann habe ich auch versucht, das Problem zu lösen, indem die erste Zeile source ohnehin entfernt werden musste, aber anstatt or pos == 0 , habe ich ein boolesches Flag line_starting verwendet, das bei True initialisiert wurde. Dann setze ich dieses Flag einfach, nachdem ich jedes Token verarbeitet habe, basierend darauf, ob die übereinstimmende Zeichenfolge mit einer neuen Zeile endet, und es löst auch das Problem trim_blocks. Siehe den Fix in # 1183.

Die aktuelle Testsuite besteht, morgen werde ich auch neue Tests für die Fälle in dieser und anderen Ausgaben hinzufügen, die mir einfallen. Ich werde auch die Originalversion, den ersten Fix und den zweiten Fix für meine frisch gesammelten 5 GB benutzerdefinierten Vorlagen ausführen, die ich aus meinem Projekt gesammelt habe, und die Analysebäume und die Leistung vergleichen.

Tests hinzugefügt, Perf-Tests zeigten keine Verschlechterung, so ist es von meiner Seite gemacht. :) :)

Gerade 2.11.2 damit veröffentlicht.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen