如何获取jinja 2模板中所有变量的列表

Kra*_*mar 27 jinja2

我试图获取模板中所有变量和块的列表.我不想创建自己的解析器来查找变量.我尝试使用以下代码段.

from jinja2 import Environment, PackageLoader
env = Environment(loader=PackageLoader('gummi', 'templates'))
template = env.get_template('chat.html')
Run Code Online (Sandbox Code Playgroud)

template.blocks 是键是块的dict,如何获取块内的所有变量?

Kra*_*mar 52

既然没有人回答这个问题,我找到了答案

from jinja2 import Environment, PackageLoader, meta
env = Environment(loader=PackageLoader('gummi', 'templates'))
template_source = env.loader.get_source(env,   'page_content.html')[0]
parsed_content = env.parse(template_source)
meta.find_undeclared_variables(parsed_content)
Run Code Online (Sandbox Code Playgroud)

这将产生未声明变量的列表,因为这不会在运行时执行,它将产生所有变量的列表.

注意:这将产生使用include和包含的html文件extends.

  • 不幸的是没有获取变量的属性(即{{something.nested}}提供了set(['something']) (8认同)
  • 我有模板,其中包含{{properties.env}},{{proerties.sys}}等变量.当我使用上面的函数时,我得到"属性"但我有兴趣获得更深层次的属性,即properties.env或属性.SYS.有人可以建议. (6认同)

小智 9

我有同样的需求,我写了一个名为jinja2schema的工具.它提供了一种启发式算法,用于从Jinja2模板推断类型,也可用于获取所有模板变量的列表,包括嵌套变量.

这是一个简短的例子:

>>> import jinja2
>>> import jinja2schema
>>>
>>> template = '''
... {{ x }}
... {% for y in ys %}
...     {{ y.nested_field_1 }}
...     {{ y.nested_field_2 }}
... {% endfor %}
... '''
>>> variables = jinja2schema.infer(template)
>>>
>>> variables
{'x': <scalar>,
 'ys': [{'nested_field_1': <scalar>, 'nested_field_2': <scalar>}]}
>>>
>>> variables.keys()
['x', 'ys']
>>> variables['ys'].item.keys()
['nested_field_2', 'nested_field_1']
Run Code Online (Sandbox Code Playgroud)


Bru*_*elé 5

对于我的鹈鹕主题,我创建了一个工具来分析我的模板文件中的所有jinja变量.

我分享我的代码

此脚本从模板文件中存在的所有变量生成示例配置,并从我的官方pelicanconf.py中获取变量

从模板文件中提取所有变量的函数

def get_variables(filename):
    env = Environment(loader=FileSystemLoader('templates'))
    template_source = env.loader.get_source(env, filename)[0]
    parsed_content = env.parse(template_source)
Run Code Online (Sandbox Code Playgroud)

完整的脚本

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# use:
# generate_pelicanconf-sample.py my_official_blog/pelicanconf.py

import sys
import imp
import os

from jinja2 import Environment, FileSystemLoader, meta


# Search all template files
def list_html_templates():
    dirList = os.listdir('templates')

    return dirList


# get all variable in template file
def get_variables(filename):
    env = Environment(loader=FileSystemLoader('templates'))
    template_source = env.loader.get_source(env, filename)[0]
    parsed_content = env.parse(template_source)

    return meta.find_undeclared_variables(parsed_content)


# Check if the pelicanconf.py is in param
if len(sys.argv) != 2:
    print("Please indicate the pelicanconf.py file")
    sys.exit()

# Get all vars from templates files
all_vars = set()
files = list_html_templates()
for fname in files:
    variables = get_variables(fname)
    for var in variables:
        if var.isupper():
            all_vars.add(var)

m = imp.load_source('pelicanconf', sys.argv[1])

# Show pelicanconf.py vars content
for var in all_vars:
    varname = 'm.%s' % var
    if var in m.__dict__:
        print ("%s = %s" % (var, repr(m.__dict__[var])))


    return meta.find_undeclared_variables(parsed_content)
Run Code Online (Sandbox Code Playgroud)

该程序的样本结果

LINKS = ((u'Home', u'/'), (u'archives', u'/archives.html'), (u'tags', u'/tags.html'), (u'A propos', u'http://bruno.adele.im'))
SITESUBTITLE = u'Une famille compl\xe8tement 633<'
DEFAULT_LANG = u'fr'
SITEURL = u'http://blog.jesuislibre.org'
AUTHOR = u'Bruno Adel\xe9'
SITENAME = u'Famille de geeks'
SOCIAL = ((u'adele', u'http://adele.im'), (u'feed', u'http://feeds.feedburner.com/FamilleDeGeek'), (u'twitter', u'http://twitter.com/jesuislibre.org'), (u'google+', u'https://plus.google.com/100723270029692582967'), (u'blog', u'http://blog.jesuislibre.org'), (u'facebook', u'http://www.facebook.com/bruno.adele'), (u'flickr', u'http://www.flickr.com/photos/b_adele'), (u'linkedin', u'http://fr.linkedin.com/in/brunoadele'))
FEED_DOMAIN = u'http://blog.jesuislibre.org'
FEED_ALL_ATOM = u'feed.atom'
DISQUS_SITENAME = u'blogdejesuislibreorg'
DEFAULT_PAGINATION = 10
GITHUB_BLOG_SITE = u'https://github.com/badele/blog.jesuislibre.org'
Run Code Online (Sandbox Code Playgroud)

有关此脚本的更多内容,请参阅https://github.com/badele/pelican-theme-jesuislibre


Wan*_*ang 5

对于那些想要找出所有变量而不仅仅是需要从外部设置的变量的人来说。可以执行以下操作:

from jinja2 import Environment, meta
from jinja2.nodes import Name
content='''
{% set y = 1%}
show y: {{ y }}
{% if x|default(2) == 1%}
{% endif %}
{{ z|default(3) }}
{{ w }}
{% set y2 = y3|default(6)%}
we do not use y2 at all
{% for _i in mylist %}
item is {{ _i }}
{% endfor %}
{{ dict1.x }}
{{ dict1.x2.y.z }}
'''
env = Environment()
parsed_content = env.parse(content)
print("undeclared=", meta.find_undeclared_variables(parsed_content))

vars = set()
vars_internal = set()
for name in parsed_content.find_all(Name):
    if name.ctx == 'load':
        vars.add(name.name)
    else:
        vars_internal.add(name.name)
print(f"{vars=}\n{vars_internal=}")
# we can see vars also contain the value that has been used
# y2 does not show up in vars because it never gets used
print(f"vars assigned but never used: {vars_internal.difference(vars)}")
print(f"vars need to be assigned from outside: {vars.difference(vars_internal)}")
print(f"vars only used internally: {vars_internal}")

Run Code Online (Sandbox Code Playgroud)

输出是:

undeclared= {'dict1', 'x', 'z', 'mylist', 'y3', 'w'}
vars={'_i', 'dict1', 'x', 'z', 'mylist', 'y', 'y3', 'w'}
vars_internal={'_i', 'y', 'y2'}
vars assigned but never used: {'y2'}
vars need to be assigned from outside: {'dict1', 'x', 'z', 'mylist', 'y3', 'w'}
vars only used internally: {'_i', 'y', 'y2'}
Run Code Online (Sandbox Code Playgroud)

有人索要字段,也可以轻松归档:

# to obtain the nested field:
def recurse_getattr(g: Getattr):
    if isinstance(g.node, Getattr):
        return recurse_getattr(g.node) + "." + g.attr
    return g.node.name + "." + g.attr

all_fields = set()
for g in parsed_content.find_all(Getattr):
    all_fields.add(recurse_getattr(g))
print(all_fields)
# will output {'dict1.x2.y', 'dict1.x', 'dict1.x2', 'dict1.x2.y.z'}
Run Code Online (Sandbox Code Playgroud)