Подтвердить что ты не робот

NamedTuples в макросах шаблонов Jinja2

Сага продолжается, расширяется от исходного потока.

Итак, у меня есть что-то, чтобы сделать макросы в коде python:

from flask import get_template_attribute
from jinja2 import Template

    class InternalMacro(object):
        """
        Creates a macro given a name, internal macro text, and content to fill(as namedtuple(t.var), dict(k,v), list(i), or other)
        """
        def __init__(self, name = None,
                           text = None,
                           content_is = None):
            self.name = name
            self.macro_name = "{}_template".format(self.name)
            self.macro_var = "{}_macro".format(self.name)
            self.text = text
            self.content_is = content_is
            self.macro_txt = self.format_text

        @property
        def is_tuple(self):
            return "{{% macro {0}(t) %}}{1}{{% endmacro %}}".format(self.macro_var, self.text)

        @property
        def is_dict(self):
            return "{{% macro {0}(items) %}}{{% for k,v in items.iteritems() %}}{1}{{% endfor %}}{{% endmacro %}}".format(self.macro_var, self.text)

        @property
        def is_list(self):
            return "{{% macro {0}(items) %}}{{% for i in items %}}{1}{{% endfor %}}{{% endmacro %}}".format(self.macro_var, self.text)

        @property
        def format_text(self):
            return getattr(self, self.content_is)

        @property
        def return_template(self):
            return Template(self.macro_txt)

        @property
        def return_callable(self):
            return get_template_attribute(self.return_template, self.macro_var)

Я передаю namedtuples отдельно, как списки, или как dicts. Это работает при передаче списка (еще не полностью протестированного как dict, но), но не работает при передаче одного именованного элемента. Независимо от того, до сих пор, namedtuple получает экранированный как unicode.

Итак, дано:

test_macro = InternalMacro('test', '{{ t }} <div id="divvy">{{ t.var }}</div>', 'is_tuple')

test_macro.return_callable(Anamedtuple)

возвращает:

u'Anamedtuple(var="A VAR VALUE") <div id="divvy"></div>'

не

u'Anamedtuple(var="A VAR VALUE")' <div id="divvy">A VAR VALUE</div>

Если я делаю это как список,.var вызывается нормально.

Что происходит, что мне не хватает, и как мне обойти это? Единственный namedtuple получает escape-код, но список нет. Я мог бы сделать единственный в списке и просто поплю первым, может быть, мне кажется нечистым. Любые предложения по улучшению этого оценили также.

ИЗМЕНИТЬ:

Простое решение заключалось в том, чтобы просто свести все к переданному списку, устранить одиночные и dict-параметры, просто перейдите в список из 1. Еще я хотел бы выяснить, что там происходит.

EDIT2:

Более глубокое исследование показало, что способ, которым я выводил namedtuple, генерировал результаты, которые я видел, т.е. -

test_macro = InternalMacro('test', '{{ t }} <div id="divvy">{{ t.var }}</div>', 'is_tuple')

приводит к:

u'Anamedtuple(var="A VAR VALUE") <div id="divvy"></div>'

тогда:

test_macro = InternalMacro('test', '<div id="divvy">{{ t.var }}</div>', 'is_tuple')

приводит к

'<div id="divvy">A VAR VALUE</div>'

Я думаю, что namedtuples читаются один раз или... ну, какое-либо подробное объяснение оценивается.

4b9b3361

Ответ 1

Возможно, не то, что вы хотите, но...

from collections import namedtuple

x = namedtuple("Foo", "var")
z = x(var = 123)
with app.app_context():
    test_macro = InternalMacro('test', "'{{ t }}' <div id=\"divvy\">{{ t.var }}</div>", 'is_tuple')
    returnVal = test_macro.return_callable(z)

print returnVal
#'Foo(var=123)' &lt;div id="divvy"&gt;123&lt;/div&gt;

'Foo (var = 123)' < div id = "divvy" > 123 </div>

repr(returnVal)
'u\'\\\'Foo(var=123)\\\' <div id="divvy">123</div>\''

Я использую Python 2.7 с Flask 0.10.1 (это было время).

Кончиком было ожидание чего-то, что явно не определено. Если я не пропустил это, не было никакой дискриминации между основными типами (int, str и т.д.) И объектами класса в любом месте свойства InternalMarco is_tuple(). Также для is_tuple все объединяется в одну строку и печатается в буфер.

Поведение отличается от for i in items, которое сбрасывает каждый элемент цикла {i} (предполагая, что это была опечатка, положив {1}) и не добавляет никаких строк.

env/Python27/lib/site-packages/jinja2/parser.py, где я считаю, что это происходит

Линия # 869

elif token.type == 'block_begin':
  flush_data()
  next(self.stream)
  if end_tokens is not None and \
                   self.stream.current.test_any(*end_tokens):
     return body
  rv = self.parse_statement()
  if isinstance(rv, list):
     body.extend(rv)
  else:
     body.append(rv)
  self.stream.expect('block_end')