template側で定義したmoduleをnamespaceから取り出セルようにする
template側で定義したmoduleをnamespaceから取り出セルようにする(wip)
namespaceの取り出し
通常namespaceは2通りの方法でimportできる - file経由のimport - module経由のimport
file経由のimportは以下の様なもの
<%namespace name="mf" file="<abtstract>.mako"/>
module経由のimportは以下もの
<%namespace name="mf" module="foo.bar.boo"/>
テンプレート上に<%def>
で定義したファイルについては、file経由のimportを使うのが普通。mako.lookup.LookupTemplateのdirectoriesに入っていれば相対パスで呼べるが。例えばライブラリで提供するものについてはmodule経由でimportしたい。
%defで定義したmakoモジュールをpythonモジュールから使えるようにする。
以下の様にするとcompileされた後のコードが手に入る。
# -*- coding:utf-8 -*- import os.path from mako.template import Template template = Template(""" <%def name="tag(tag)"> ${tag}${caller.body()}${tag} </%def> <%def name="hello()"> <%self:tag tag="hello"> ${caller.body()} </%self:tag> </%def> ${hello()} <%self:hello> hai </%self:hello> """) code = template.code print(code.replace(os.path.abspath(os.path.dirname(__file__)), "./"))
以下の様な出力を得る。
from mako import runtime, filters, cache UNDEFINED = runtime.UNDEFINED __M_dict_builtin = dict __M_locals_builtin = locals _magic_number = 10 _modified_time = 1427816076.348679 _enable_loop = True _template_filename = None _template_uri = 'memory:0x102e9ae10' _source_encoding = 'ascii' _exports = ['hello', 'tag'] def render_body(context,**pageargs): __M_caller = context.caller_stack._push_frame() try: __M_locals = __M_dict_builtin(pageargs=pageargs) def hello(): return render_hello(context._locals(__M_locals)) self = context.get('self', UNDEFINED) __M_writer = context.writer() __M_writer('\n') __M_writer('\n\n') __M_writer('\n\n') __M_writer(str(hello())) __M_writer('\n') def ccall(caller): def body(): __M_writer = context.writer() __M_writer('\nhai\n') return '' return [body] context.caller_stack.nextcaller = runtime.Namespace('caller', context, callables=ccall(__M_caller)) try: __M_writer(str(self.hello())) finally: context.caller_stack.nextcaller = None __M_writer('\n') return '' finally: context.caller_stack._pop_frame() def render_hello(context): __M_caller = context.caller_stack._push_frame() try: self = context.get('self', UNDEFINED) __M_writer = context.writer() __M_writer('\n') def ccall(caller): def body(): __M_writer = context.writer() __M_writer('\n') __M_writer(str(caller.body())) __M_writer('\n') return '' return [body] context.caller_stack.nextcaller = runtime.Namespace('caller', context, callables=ccall(__M_caller)) try: __M_writer(str(self.tag(tag='hello'))) finally: context.caller_stack.nextcaller = None __M_writer('\n') return '' finally: context.caller_stack._pop_frame() def render_tag(context,tag): __M_caller = context.caller_stack._push_frame() try: caller = context.get('caller', UNDEFINED) __M_writer = context.writer() __M_writer('\n') __M_writer(str(tag)) __M_writer(str(caller.body())) __M_writer(str(tag)) __M_writer('\n') return '' finally: context.caller_stack._pop_frame() """ __M_BEGIN_METADATA {"filename": null, "uri": "memory:0x102e9ae10", "source_encoding": "ascii", "line_map": {"65": 2, "34": 12, "70": 2, "71": 3, "40": 5, "73": 3, "74": 3, "45": 5, "14": 0, "80": 74, "49": 6, "50": 7, "51": 7, "20": 1, "21": 4, "22": 9, "56": 6, "72": 3, "26": 10, "59": 8, "31": 10}} __M_END_METADATA """
- 全てrenderが前置された関数に変換される
- template全体自体はrender_bodyに変換される。
${hello()}
はrender_hello()
を使った形式に変更される
このままだとまともに使えそうにないのでコードを見る
- mako.parsetree:NamespaceTagが
<%namespace .../>
に対応する - ここからNamespace objectが作られる
2つは本質的に違うもの。
# <%namespace module="foo.boo" name="boo"/> def _mako_get_namespace(context, name): try: return context.namespaces[(__name__, name)] except KeyError: _mako_generate_namespaces(context) return context.namespaces[(__name__, name)] def _mako_generate_namespaces(context): ns = runtime.ModuleNamespace('boo', context._clean_inheritance_tokens(), callables=None, calling_uri=_template_uri, module='foo.boo') context.namespaces[(__name__, 'boo')] = ns
file経由の場合はmako.runtime.TemplateNamespaceが使われる
# <%namespace file="foo.boo" name="boo"/> def _mako_get_namespace(context, name): try: return context.namespaces[(__name__, name)] except KeyError: _mako_generate_namespaces(context) return context.namespaces[(__name__, name)] def _mako_generate_namespaces(context): ns = runtime.TemplateNamespace('boo', context._clean_inheritance_tokens(), templateuri='foo.boo', callables=None, calling_uri=_template_uri) context.namespaces[(__name__, 'boo')] = ns
なんか無理そう。
追記
現状は以下のようにlookupのdirectoriesに追加できるだけ
from mako.lookup import TemplateLookup from mako.template import Template import os.path import foo lookup = TemplateLookup(directories=[os.path.dirname(foo.__file__)]) template = Template(""" <%namespace file="foo.mako" name="foo"/> <%foo:hello> hai </%foo:hello> """, lookup=lookup) print(template.render())