简体   繁体   English

如何在 Python 中使用 pip 安装的 jinja2 过滤器

[英]How to use pip-installed jinja2 filters in Python

In my Ansible project, I have installed libraries using pip that allow me to use additional jinja2 filters.在我的 Ansible 项目中,我使用pip安装了库,允许我使用额外的 jinja2 过滤器。

Among those, I have installed the netaddr library that allows me to use the ipaddr filter, like this: <netmask>{{ interface.IP | ipaddr('netmask') }}</netmask>其中,我安装了允许我使用ipaddr过滤器的netaddr库,如下所示: <netmask>{{ interface.IP | ipaddr('netmask') }}</netmask> <netmask>{{ interface.IP | ipaddr('netmask') }}</netmask> (this works in my Ansible playbook) <netmask>{{ interface.IP | ipaddr('netmask') }}</netmask> (这适用于我的 Ansible 剧本)

The problem comes when I try to test my templates without having to run my Ansible playbook by creating a quick Python script.当我尝试通过创建一个快速的 Python 脚本来测试我的模板而不必运行我的 Ansible playbook 时,问题就出现了。 For instance:例如:

from jinja2 import Template
print Template('{{ ip | ipaddr("netmask") }}').render(ip='10.10.10.0/24')

Throws me the following exception:抛出以下异常:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python2.7/dist-packages/jinja2/environment.py", line 945, in __new__
  return env.from_string(source, template_class=cls)
File "/usr/local/lib/python2.7/dist-packages/jinja2/environment.py", line 880, in from_string
  return cls.from_code(self, self.compile(source), globals, None)
File "/usr/local/lib/python2.7/dist-packages/jinja2/environment.py", line 591, in compile
  self.handle_exception(exc_info, source_hint=source_hint)
File "/usr/local/lib/python2.7/dist-packages/jinja2/environment.py", line 780, in handle_exception
reraise(exc_type, exc_value, tb)
File "<unknown>", line 1, in template
jinja2.exceptions.TemplateAssertionError: no filter named 'ipaddr'

I can see in that last line that jinja2 can't find the 'ipaddr' filter, which is installed in /usr/lib/python2.7/dist-packages , but I can't find how to use packages installed via pip directly in my Python scripts.我可以在最后一行中看到 jinja2 找不到安装在/usr/lib/python2.7/dist-packages的“ipaddr”过滤器,但我找不到如何直接使用通过 pip 安装的包在我的 Python 脚本中。

Yes, you can do this.是的,你可以这样做。 Ansible needs to be in your python path Ansible 需要在你的 python 路径中

import jinja2
from ansible.plugins.filter import ipaddr

template_dir = 'path/to/templates'
fname = 'template.txt'

# get the filters from ansible/plugins/filter/ipaddr
f = ipaddr.FilterModule()

# for a template in your filesystem, set the loader
loader = jinja2.FileSystemLoader(template_dir)

# create the environment
env = jinja2.Environment(loader=loader)

# *** Add the ipaddr filters to the environment ***
env.filters.update(f.filters())

# Set your template
template = env.get_template(fname)

print(template.render(ip='10.10.10.0/24'))

This will make your template file (containing {{ ip | ipaddr("netmask") }} ) output这将使您的模板文件(包含{{ ip | ipaddr("netmask") }} )输出

255.255.255.0

I spent the better part of an hour trying to get this working, and it was a total nightmare.我花了一个小时的大部分时间试图让它工作,这完全是一场噩梦。 I eventually had to give up.我最终不得不放弃。 While it may still be possible, I wasn't able to get much of anywhere, even creating Environment() 's and trying to load extensions and whatnot.虽然它可能仍然是可能的,但我无法在任何地方获得太多,甚至创建Environment()并尝试加载扩展等等。

What I finally ended up doing was to use one of the solutions mentioned here: How can I test jinja2 templates in ansible?我最终做的是使用这里提到的解决方案之一: How can I test jinja2 templates in ansible?

(That solution also mentions some online Jinja2 parsers, but those seemed to suffer from the exact same problems as the interactive Python method.) (该解决方案还提到了一些在线 Jinja2 解析器,但这些解析器似乎遇到了与交互式 Python 方法完全相同的问题。)

What I finally went with was a combination of the Ansible_3 and Ansible_4 solutions -我最终采用的是Ansible_3Ansible_4解决方案的组合 -

I created a testfile called nametest.yml like this:我创建了一个名为nametest.yml如下所示:

---
- hosts: 127.0.0.1
  tasks:
  - name: Test jinja2template
    template: src=name.j2 dest=output.conf

Then I put my test Jinja2 stuff in the name.j2 file.然后我将我的测试 Jinja2 内容放在name.j2文件中。

I ran tests like this:我进行了这样的测试:

ansible-playbook nametest.yml --check --diff --connection=local -e role=api -e level=prod -e '{"item": {"private_ip": "1.2.3.4"}}' -e debug_instance=false

Those -e options each set a single variable's value.这些-e选项分别设置一个变量的值。 Mostly I just used the simple name=value construction, but for the more complex, nested object, I used the JSON version.大多数情况下,我只是使用了简单的name=value构造,但对于更复杂的嵌套对象,我使用了 JSON 版本。

Then to run with different variable values, I just twiddled the various command-line arguments to test all of the various branches of code I had set up.然后为了使用不同的变量值运行,我只是摆弄各种命令行参数来测试我设置的所有代码分支。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM