Jinja содержит отступы для включения или макроса
Мне интересно, есть ли способ сохранить отступ с jinja при добавлении include или макроса внутри файла. Я хотел бы использовать jinja для создания файла кода. Пример:
Файл: class.html
class MyClass:
def someOp():
pass
{% include "someOp.html" %}
Файл: someOp.html
def someOp2():
pass
Результат шаблона должен быть:
class MyClass:
def someOp():
pass
def someOp2():
pass
Если какой-либо способ сделать jinja префиксом отступа перед тегом include для каждой строки в включенном файле? Или есть ли способ настроить jinja для этого?
Ответы
Ответ 1
Один из способов заключается в том, чтобы обернуть включение в макрос, а затем, поскольку макрос является функцией, его вывод может быть передан через фильтр отступа:
class MyClass:
def someOp():
pass
{% macro someop() %}{% include "someOp.html" %}{% endmacro %}
{{ someop()|indent }}
По умолчанию "indent" отступы 4 пробела и не отступают от первой строки, вы можете использовать, например. 'indent (8)' далее, см. http://jinja.pocoo.org/docs/templates/#list-of-builtin-filters.
Если то, что вы включаете, определяется как макрос для начала, тогда дополнительный макрос оболочки не нужен, и вы можете перейти прямо к использованию фильтра отступа.
Ответ 2
Я искал в Jinja2 то же самое и пришел к выводу, что в настоящее время выравнивание многострочного отступа блока с исходным оператором Jinja невозможно.
Я опубликовал небольшой PR для Jinja, чтобы добавить новый синтаксис {%* ... %}
и {{* ... }}
, который делает именно это. Смотрите PR для деталей:
https://github.com/pallets/jinja/pull/919
Ответ 3
Было бы проще, если бы Джинджа предоставил объект, и похоже, что объект находится в стадии разработки, что очень приветствуется.
Следующий код полезен, когда код для отступа не является статическим файлом, а встроен в код. Этот другой ответ может использоваться для включения макросов, но не помогает с автоматическим отступом.
auto_indent()
обнаруживает уровень отступа переменной в шаблоне хоста, затем применяет этот отступ к фрагменту текста. Пример ниже.
import os
import itertools
import jinja2
def indent_lines(text_lines: list, indent: int):
return [' ' * indent + line for line in text_lines]
def matching_line(s, substring):
lineno = s[:s.index(substring)].count('\n')
return s.splitlines()[lineno]
def is_space(c):
return c == ' '
def indentation(line: str) -> int:
initial_spaces = ''.join(itertools.takewhile(is_space, line))
return len(initial_spaces)
def auto_indent(template: str, placeholder: str, content_to_indent: str):
placeholder_line = matching_line(template, '{{ ' + placeholder + ' }}')
indent_width = indentation(placeholder_line)
lines = content_to_indent.splitlines()
first_line = [lines[0]] # first line uses placeholder indent-- no added indent
rest = indent_lines(lines[1:], indent_width)
return os.linesep.join(first_line + rest)
Пример:
action_class = """\
class Actions:
def __init__(self):
pass
def prequel(self):
pass
{{ methods }}
def sequel(self):
pass
"""
inserted_methods = """\
def create_branch():
pass
def merge_branch():
pass
"""
if __name__ == '__main__':
indented_methods = auto_indent(action_class, 'methods', inserted_methods)
print(jinja2.Template(action_class).render(methods=indented_methods))
Пример вывода:
>>> python indent.py
class Actions:
def __init__(self):
pass
def prequel(self):
pass
def create_branch():
pass
def merge_branch():
pass
def sequel(self):
pass
Обратите внимание, что вам нужно быть точным в отношении формата вашей переменной в template--, например. {{ variable }}
работает, но {{variable}}
потерпит неудачу: auto_indent()
выполняет простое совпадение строк, чтобы найти переменную-заполнитель в шаблоне хоста.
Для версий Python до 3.6 просто удалите подсказки типа для параметров функции.
Чтобы частично отобразить шаблоны, т.е. использовать несколько проходов приведенного ниже кода для полной визуализации нескольких переменных, взгляните на этот ответ.