Посмотрите на следующий код шаблона:
set_property verilog_define {
{%- for k, v in vlogdefine.items() %}{{ k }}={{ v|param_value_str }} {% endfor -%}
} [get_filesets sources_1]
До Jinja2 2.10.3 это привело бы к чему-то вроде
set_property verilog_define {vlogdefine_bool=1 vlogdefine_int=42 vlogdefine_str=hello } [get_filesets sources_1]
В коде есть 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 (но также бывает и на 3.5 в CI)
Я разберусь с этим, извините за то, что вызвал тот запутанный сеанс отладки, который вы связали! На первый взгляд, похоже, что теперь поведение более последовательное, и у нас не было теста на предыдущее поведение, но мне придется его проверить. Можно ли было бы использовать {%+ endfor -%}
для явного объявления сохранения пробелов?
@davidism, спасибо, что посмотрели.
Да, мы можем внести изменения в edalize (библиотеку, в которой используется Jinja) различными способами (добавить +
, переключиться на lstrip_blocks = False
и т. Д.), Но сначала я хотел бы убедиться, что что у нас есть общее понимание ожидаемого поведения.
Это тоже влияет на меня так же, как и на оригинальный плакат. Документация кажется мне довольно ясной, что поведение 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"
Вот в чем проблема. Когда этот шаблон токенизируется, find("\n")
передает текст, содержащий только пробел между {{ x }}
и {% endif %}
, не видит новой строки, а затем удаляет текст с начала.
Добавление "\n" in text
к elif
приводит к сбою нескольких тестов, потому что первая строка шаблона не содержит новой строки, но должна быть удалена, если в ней есть только место. Если мы станем немного умнее и отследим, находимся ли мы на первой строке, это все равно не удастся, если 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.
Ой, совсем забыл об этом. Постараюсь на самом деле найти время на этой неделе, в противном случае отмените его, если побочные эффекты будут такими серьезными, как кажется.
Мой предварительный план - выпустить в субботу. Дайте мне знать, если вы работаете над этим, я могу отодвинуть это назад, если так.
Думаю, у меня есть исправление. Я старался не поддаваться влиянию ваших предыдущих комментариев
Прежде всего, я думаю, что изначально я планировал, что мое исправление будет вести себя по-другому, если l_pos = text.rfind("\n") + 1
не нашел ни одного символа новой строки, но затем забыл об этом. Поэтому я больше не делаю зачистку, если в text
нет новой строки. Затем я также попытался решить проблему с первой строкой source
которую все равно нужно было удалить, но вместо использования or pos == 0
я использовал логический флаг line_starting
инициализированный в True. Затем я просто устанавливаю этот флаг после обработки каждого токена в зависимости от того, заканчивается ли соответствующая строка новой строкой, а также решает проблему trim_blocks. Смотрите исправление в # 1183.
Текущий набор тестов проходит, завтра я также добавлю новые тесты для случаев в этой проблеме и других, о которых я могу подумать. Я также запущу исходную версию, первое исправление и второе исправление относительно моего недавно собранного набора 5 ГБ пользовательских шаблонов, которые я собрал из своего проекта, сравню деревья синтаксического анализа и производительность.
Добавлены тесты, тесты производительности не показали деградации, так что это сделано с моей стороны. :)
Только что выпустил 2.11.2 с этим.
Самый полезный комментарий
Только что выпустил 2.11.2 с этим.