如何在Jinja2宏中引发异常?

qua*_*nta 13 python jinja2 salt-stack

我有一个用于构建本地存储库的宏debmirror.

这是代码片段:

{%- set gnupghome = kwargs.pop('gnupghome', '/root/.gnupg') %}
{%- set env = { 'GNUPGHOME': gnupghome } %}
keyring_import:
  cmd:
    - run
{%- if 'keyid' in kwargs and 'keyserver' in kwargs %}
    {%- set keyid = kwargs.pop('keyid') %}
    {%- set keyserver = kwargs.pop('keyserver') %}
    - name: 'gpg --no-default-keyring --keyring {{ gnupghome }}/trustedkeys.gpg --keyserver {{ keyserver }} --recv-keys {{ keyid }}'
{%- elif 'key_url' in kwargs %}
    {%- set key_url = kwargs.pop('key_url') %}
    - name: 'wget -q -O- "{{ key_url }}" | gpg --no-default-keyring --keyring {{ gnupghome }}/trustedkeys.gpg --import'
{%- endif %}
    - require:
      - pkg: wget
      - pkg: gnupg
Run Code Online (Sandbox Code Playgroud)

endif关键字,我想else用来引发异常,例如:

要么是key_url,要么是keyserver和keyid.

可能吗?

Dea*_*evy 12

这可以在扩展中处理.来自https://github.com/duelafn/python-jinja2-apci

# FROM: https://github.com/duelafn/python-jinja2-apci/blob/master/jinja2_apci/error.py
from jinja2 import nodes
from jinja2.ext import Extension
from jinja2.exceptions import TemplateRuntimeError

class RaiseExtension(Extension):
    # This is our keyword(s):
    tags = set(['raise'])

    # See also: jinja2.parser.parse_include()
    def parse(self, parser):
        # the first token is the token that started the tag. In our case we
        # only listen to "raise" so this will be a name token with
        # "raise" as value. We get the line number so that we can give
        # that line number to the nodes we insert.
        lineno = next(parser.stream).lineno

        # Extract the message from the template
        message_node = parser.parse_expression()

        return nodes.CallBlock(
            self.call_method('_raise', [message_node], lineno=lineno),
            [], [], [], lineno=lineno
        )

    def _raise(self, msg, caller):
        raise TemplateRuntimeError(msg)
Run Code Online (Sandbox Code Playgroud)

将扩展程序传递给您的环境:jinja2.Environment(... extensions=[RaiseExtension])然后在模板中使用它:

{%- if 'keyid' in kwargs and 'keyserver' in kwargs %}
    ...
{%- else %}
    {% raise "Either key_url or both keyserver and keyid required." %}
{% endif %}
Run Code Online (Sandbox Code Playgroud)


Lee*_*Lee 10

Dean Serenevy的回答很优雅.这是一个更短的解决方案,它为jinja的环境增添了一个全球性.

def raise_helper(msg):
    raise Exception(msg)

env = jinja2.Environment(...
env.globals['raise'] = raise_helper
Run Code Online (Sandbox Code Playgroud)

然后在你的模板中:

{{ raise("uh oh...") }}
Run Code Online (Sandbox Code Playgroud)


hyp*_*not 9

超快速的解决方法,只要你不介意提出ZeroDivisionError:

{{ 0/0 }}在您要引发异常的任何位置插入.


Vin*_*eib 7

插入{{ "My error explained here"/0 }}表达式.例如

{% if not required_parameter %}
{{ "required_parameter must be defined."/0 }}
{% endif %}
Run Code Online (Sandbox Code Playgroud)

(建立在zsero的0/0答案上)

  • 这并没有真正提供有用的错误 - 对我来说它会生成错误文本:"""/"'str'和'int'""""不支持的操作数类型 (3认同)

Jiř*_*aum 6

如果这是从 Ansible 完成的,Ansible 会向 Jinja添加强制过滤器,可用于执行此操作:

{{ ('OK text' if condition_ok) | mandatory('Text of error message') }}
Run Code Online (Sandbox Code Playgroud)

给出失败:

fatal: [hostname]: FAILED! => {"msg": "Text of error message"}
Run Code Online (Sandbox Code Playgroud)

(替换condition_ok为您需要进行的检查;'OK text'可以只是''。)


小智 5

我还想从 jinja2 模板中抛出带有错误消息的异常,但没有任何外部依赖项(全局/扩展)。我最终得到了这个宏:

{% macro abort(error) %}
    {{ None['[ERROR] ' ~ error][0] }}
{% endmacro %}
Run Code Online (Sandbox Code Playgroud)

使用方法:

{{ abort("Either key_url or both keyserver and keyid required.") }}  
Run Code Online (Sandbox Code Playgroud)

其中给出了带有此异常的堆栈跟踪:

jinja2.exceptions.UndefinedError: 'None' has no attribute '[ERROR] Either key_url or both keyserver and keyid required.'
Run Code Online (Sandbox Code Playgroud)