2012-12-30 14 views
12

La saga continua, estesa da original thread.NamedTuples in macro modello Jinja2

Così, ho un qualcosa per rendere le macro nel codice 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) 

Quale passo namedtuples singolarmente, come liste, o come dicts. Funziona quando si passa una lista (non ancora completamente testata come dict) ma non funziona quando si passa un singolo namedtuple. Non importa quale, finora, il namedtuple viene scappato come unicode.

Quindi dato:

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

test_macro.return_callable(Anamedtuple) 

rendimenti:

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

:

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

Se faccio questo come lista, .var ottenere chiamato normalmente.

Cosa sta succedendo che mi manca e come posso aggirare questo? Il singolo namedtuple viene sfuggito, ma un elenco non lo fa. Potrei fare l'unico come una lista e solo il primo, forse mi sembra impuro. Qualche suggerimento su come migliorare questo apprezzato pure.

EDIT:

Soluzione semplice era quello di ridurre proprio tutto ad un passato in lista, eliminare le singole opzioni e dict, basta passare in un elenco di 1. Ancora mi piacerebbe capire cosa sta succedendo lì Esattamente.

EDIT2:

una più profonda esplorare ha mostrato che l'uscita modo in cui ho la namedtuple ha generato i risultati che stavo vedendo cioè -

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

risultati in:

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

mentre:

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

risultati in

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

Credo che la namedtuples ottenere leggere una o .... bene qualsiasi spiegazione dettagliata apprezzato.

+0

Ho un debugger simbolico per Python e un sacco di tempo libero, si può inviare un file di esempio completo 1 (compreso il nome tupla) e gli darò un giro. – David

risposta

1

Forse non quello che volete, ma ...

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"/div >

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

I' m usando Python 2.7 con Flask 0.10.1 (è passato un po 'di tempo).

Il tip off era l'aspettativa di qualcosa che non è esplicitamente definito. A meno che non me ne sia perso, non c'è alcuna discriminazione tra i tipi di base (int, str, ecc.) E gli oggetti di classe in qualsiasi posizione nella proprietà is_tuple() di InternalMarco.Anche per un is_tuple, tutto è messo insieme in una stringa e viene stampato nel buffer.

Il comportamento è diverso da for i in items che scarica ciascuno per corpo del ciclo {i} (supponendo che sia un errore di battitura mettere un {1}) e non fa qualsiasi stringa aggiunge.

env/Python27/lib/site-packages/jinja2/parser.py è dove credo che questo accade

linea # 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') 
Problemi correlati