如何在Jinja2宏中引发异常?

时间:2014-02-14 11:32:25

标签: 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

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

  

key_url或keyserver和keyid都需要。

有可能吗?

7 个答案:

答案 0 :(得分:11)

这可以在扩展中处理。来自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)

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

{%- if 'keyid' in kwargs and 'keyserver' in kwargs %}
    ...
{%- else %}
    {% raise "Either key_url or both keyserver and keyid required." %}
{% endif %}

答案 1 :(得分:10)

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

def raise_helper(msg):
    raise Exception(msg)

env = jinja2.Environment(...
env.globals['raise'] = raise_helper

然后在你的模板中:

{{ raise("uh oh...") }}

答案 2 :(得分:9)

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

在您想要引发异常的任何地方插入{{ 0/0 }}

答案 3 :(得分:7)

插入{{ "My error explained here"/0 }}表达式。 e.g。

{% if not required_parameter %}
{{ "required_parameter must be defined."/0 }}
{% endif %}

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

答案 4 :(得分:3)

如果这是通过Ansible完成的,则Ansible将mandatory过滤器添加到Jinja,可用于执行以下操作:

{{ ('OK text' if condition_ok) | mandatory('Text of error message') }}

给出故障:

fatal: [hostname]: FAILED! => {"msg": "Text of error message"}

(用所需的支票代替condition_ok'OK text'可以只是''。)

答案 5 :(得分:1)

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

{% macro abort(error) %}
    {{ None['[ERROR] ' ~ error][0] }}
{% endmacro %}

使用:

{{ abort("Either key_url or both keyserver and keyid required.") }}  

给出了此异常的堆栈跟踪:

jinja2.exceptions.UndefinedError: 'None' has no attribute '[ERROR] Either key_url or both keyserver and keyid required.'

答案 6 :(得分:0)

打印给定值的另一个快速技巧:

func rotateLeft(d int32, arr []int32) []int32 {
    for ; d > 0 ; d-- {
        left := arr[0]
        arr = arr[1:]
        arr = append(arr, left)        
    }
    return arr
}

结果:

{% include 'error: ' ~ value_to_print %}