37

我想知道在文件中添加包含或宏时是否有任何方法可以保持 jinja 的缩进。我想使用 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 在包含文件中每一行的包含标记之前添加缩进?或者有什么方法可以定制 jinja 来做到这一点?

4

3 回答 3

30

一种方法是将 include 包装在一个宏中,然后因为宏是一个函数,它的输出可以通过缩进过滤器传递:

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-内置过滤器以获取更多详细信息。

如果您包含的内容被定义为开头的宏,则不需要进一步的包装宏,您可以直接跳转到使用缩进过滤器。

于 2012-06-12T13:08:05.440 回答
8

我正在寻找 Jinja2 以实现相同的目标,并得出结论,目前无法将多行块缩进与原始 Jinja 语句对齐。

我已经向 Jinja 发布了一个小 PR 以添加新语法{%* ... %},而{{* ... }}这正是这样做的。详情见 PR:

https://github.com/pallets/jinja/pull/919

于 2018-11-01T10:37:46.537 回答
2

如果 Jinja 提供设施会更容易。看起来已经完成了一些工作,但该问题目前已关闭(2019 年 11 月 20 日)并且拉取请求尚未合并。这可能是因为缩进很快就会变得很棘手(例如,想想制表符和空格。)

以下是我发现的一个简单的解决方案,它可以有效地生成 Python 代码,当然,它需要很好地处理缩进。它处理使用空格进行缩进的文件。

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
于 2019-09-20T11:33:22.237 回答