Компиляция подраздела Jinja2 AST

Можно ли скомпилировать или вернуть часть Jinja2 AST?

Например, можно ли вызвать функцию или метод из jinja2.environment или jinja2.compiler.generate или эквивалент в списке узлов, извлеченных из шаблона?

Например, для шаблона y.html:

avant-tag
{% xyz %}
tag content {{ 3 + 5 }}
{% endxyz %}
apres-tag

и расширение y.py:

# -*- coding: utf-8 -*-
from jinja2 import nodes, Environment, FileSystemLoader
from jinja2.ext import Extension

class YExtension(Extension):
    tags = set(['y'])

    def __init__(self, environment):
        super(YExtension, self).__init__(environment)

    def parse(self, parser):
        tag = parser.stream.next()
        body = parser.parse_statements(['name:endy'], drop_needle=True)
        return nodes.Const("<!-- slurping: %s -->" % str(body))

env = Environment(
    loader      = FileSystemLoader('.'),
    extensions  = [YExtension],
    )

print env.get_template('x.html').render()

Запуск python y.py приводит к ожидаемому результату:

avant-tag
 <!-- slurping: [Output(nodes=[TemplateData(data=u'\n    tag-content '),
   Add(left=Const(value=3), right=Const(value=5)),
   TemplateData(data=u'\n ')])] -->
sous-tag

В методе parse как можно:

  1. скомпилировать body в юникод (т.е. tag-content 8); или, альтернативно
  2. вернуть body к исходному источнику (т.е. tag-content {{ 3 + 5 }}).

С точки зрения предыстории этот вопрос связан с двумя предыдущими вопросами:

  1. Расширение компиляции Jinja2 после включения; и
  2. Вставить javascript поверх включения файла в Jinja 2

Спасибо за чтение.

Брайан


person Brian M. Hunt    schedule 29.11.2010    source источник


Ответы (1)


Компиляция в Unicode пока невозможна в методе parse(), так как у вас нет контекста, доступного в этот момент. Конечно, вы можете обойти это, но это, вероятно, не лучший способ.

Обратите внимание, что шаг parse() обычно выполняется только один раз в html-файле, после чего он будет использовать проанализированный байт-код для отображения шаблона. Результаты шага синтаксического анализа могут быть отображены с учетом среды.

У вас просто нет контекста, доступного там, и получить контекст там... довольно сложно;)

Однако получить первоисточник ... не намного проще без взлома, но взлом не так уж и плох;)

class YExtension(Extension):
    tags = set(['y'])

    def preprocess(self, source, name, filename=None):
        # insert some code here that replaces '{% xyz %}foo bar{% endxyz %}'
        # with something like: '{% xyz %}foo bar{% raw %}foo bar{% endraw %}{% endxyz %}'
        return source

После этого вы можете прочитать текст как value из узла {% raw %}. Обязательно удалите его после этого, иначе он будет отображаться в вашем шаблоне.

person Wolph    schedule 30.11.2010
comment
Спасибо WoLpH. Думаю, это ответ на мой вопрос. Я думаю, что единственный остаточный вопрос заключается в том, есть ли способ отобразить извлеченные результаты в заданной среде. - person Brian M. Hunt; 30.11.2010
comment
@ Брайан М. Хант: это не проблема, поскольку вы можете отображать любую строку в любом случае. Вы можете использовать Environment.from_string() или Template(nodes) со всем, что вы обычно возвращаете. - person Wolph; 30.11.2010
comment
О верно! Извините, я выразился неясно... Единственный остаточный вопрос, я думаю, заключается в том, есть ли способ отобразить извлеченные узлы (не текст) с учетом среды. - person Brian M. Hunt; 30.11.2010
comment
@ Брайан М. Хант: Разве Template(nodes).render() не сделал бы это для тебя? Если нет, то я могу вас неправильно понять. - person Wolph; 30.11.2010
comment
@WoLpH: я так и думал раньше, но выдает ошибку RuntimeError: maximum recursion depth exceeded. - person Brian M. Hunt; 30.11.2010
comment
@ Брайан М. Хант: ты прав, это не работает. И примерно через час попыток/тестирования я не могу найти способ заставить его работать напрямую. - person Wolph; 30.11.2010
comment
@WoLpH: Спасибо за попытку. Я считаю, что в nodes.Template есть некоторый код сборки/разборки, который должен присутствовать (поэтому может быть скомпилирован только nodes.Template), но опять же, это может быть вообще не проблема. :) Я не уверен, в чем проблема, но, возможно, что-то решение придет. - person Brian M. Hunt; 30.11.2010
comment
@ Брайан М. Хант: вы можете по крайней мере сделать template = nodes.Template(nodes); templates.set_environment(env); templates.set_ctx(context), но это еще не рендеринг. После этого можно будет вызвать env.from_string или что-то подобное. Но я застрял там ;) - person Wolph; 30.11.2010
comment
@WoLpH: в моем последнем редактировании stackoverflow.com/questions/4292630/ вопрос, вы можете увидеть, как nodes.CallBlock можно использовать для получения скомпилированного вывода. - person Brian M. Hunt; 02.12.2010