diff --git a/mako/codegen.py b/mako/codegen.py index e26f7f72b15beabe12397cb21552cba7ee470313..2af1eac7759a91adb7ce28f1842971312e8d6b7e 100644 --- a/mako/codegen.py +++ b/mako/codegen.py @@ -11,7 +11,7 @@ import re from mako.pygen import PythonPrinter from mako import util, ast, parsetree, filters -MAGIC_NUMBER = 5 +MAGIC_NUMBER = 6 def compile(node, uri, @@ -319,14 +319,35 @@ class _GenerateRenderMethod(object): callable_name = "make_namespace()" else: callable_name = "None" - self.printer.writeline( - "ns = runtime.Namespace(%r, context._clean_inheritance_tokens()," - " templateuri=%s, callables=%s, calling_uri=_template_uri, module=%s)" % - ( - node.name, - node.parsed_attributes.get('file', 'None'), - callable_name, - node.parsed_attributes.get('module', 'None')) + + if 'file' in node.parsed_attributes: + self.printer.writeline( + "ns = runtime.TemplateNamespace(%r, context._clean_inheritance_tokens()," + " templateuri=%s, callables=%s, calling_uri=_template_uri)" % + ( + node.name, + node.parsed_attributes.get('file', 'None'), + callable_name, + ) + ) + elif 'module' in node.parsed_attributes: + self.printer.writeline( + "ns = runtime.ModuleNamespace(%r, context._clean_inheritance_tokens()," + " callables=%s, calling_uri=_template_uri, module=%s)" % + ( + node.name, + callable_name, + node.parsed_attributes.get('module', 'None') + ) + ) + else: + self.printer.writeline( + "ns = runtime.Namespace(%r, context._clean_inheritance_tokens()," + " callables=%s, calling_uri=_template_uri)" % + ( + node.name, + callable_name, + ) ) if eval(node.attributes.get('inheritable', "False")): self.printer.writeline("context['self'].%s = ns" % (node.name)) diff --git a/mako/runtime.py b/mako/runtime.py index 78c209f563ad2db8acc55f2ad1519577d52735e6..60c15520bcb99d0dfae342d4efa4e50cd2af5e2a 100644 --- a/mako/runtime.py +++ b/mako/runtime.py @@ -210,35 +210,19 @@ class Namespace(object): """ - def __init__(self, name, context, module=None, - template=None, templateuri=None, + def __init__(self, name, context, callables=None, inherits=None, populate_self=True, calling_uri=None): self.name = name - if module is not None: - mod = __import__(module) - for token in module.split('.')[1:]: - mod = getattr(mod, token) - self._module = mod - else: - self._module = None - if templateuri is not None: - self.template = _lookup_template(context, templateuri, calling_uri) - self._templateuri = self.template.module._template_uri - else: - self.template = template - if self.template is not None: - self._templateuri = self.template.module._template_uri self.context = context self.inherits = inherits if callables is not None: self.callables = dict([(c.func_name, c) for c in callables]) - else: - self.callables = None - if populate_self and self.template is not None: - lclcallable, lclcontext = \ - _populate_self_namespace(context, self.template, self_ns=self) - + + callables = None + + _module = None + template = None """The :class:`.Template` object referenced by this :class:`.Namespace`, if any. @@ -333,7 +317,7 @@ class Namespace(object): if self.context.namespaces.has_key(key): return self.context.namespaces[key] else: - ns = Namespace(uri, self.context._copy(), + ns = TemplateNamespace(uri, self.context._copy(), templateuri=uri, calling_uri=self._templateuri) self.context.namespaces[key] = ns @@ -433,6 +417,47 @@ class Namespace(object): "Namespace '%s' has no member '%s'" % (self.name, key)) +class TemplateNamespace(Namespace): + def __init__(self, name, context, template=None, templateuri=None, + callables=None, inherits=None, + populate_self=True, calling_uri=None): + self.name = name + self.context = context + self.inherits = inherits + if callables is not None: + self.callables = dict([(c.func_name, c) for c in callables]) + + if templateuri is not None: + self.template = _lookup_template(context, templateuri, + calling_uri) + self._templateuri = self.template.module._template_uri + elif template is not None: + self.template = template + self._templateuri = template.module._template_uri + else: + raise TypeError("'template' argument is required.") + + if populate_self: + lclcallable, lclcontext = \ + _populate_self_namespace(context, self.template, + self_ns=self) + +class ModuleNamespace(Namespace): + def __init__(self, name, context, module, + callables=None, inherits=None, + populate_self=True, calling_uri=None): + self.name = name + self.context = context + self.inherits = inherits + if callables is not None: + self.callables = dict([(c.func_name, c) for c in callables]) + + mod = __import__(module) + for token in module.split('.')[1:]: + mod = getattr(mod, token) + self._module = mod + + def supports_caller(func): """Apply a caller_stack compatibility decorator to a plain Python function. @@ -514,7 +539,7 @@ def _inherit_from(context, uri, calling_uri): while ih.inherits is not None: ih = ih.inherits lclcontext = context.locals_({'next':ih}) - ih.inherits = Namespace("self:%s" % template.uri, + ih.inherits = TemplateNamespace("self:%s" % template.uri, lclcontext, template = template, populate_self=False) @@ -544,7 +569,7 @@ def _lookup_template(context, uri, relativeto): def _populate_self_namespace(context, template, self_ns=None): if self_ns is None: - self_ns = Namespace('self:%s' % template.uri, + self_ns = TemplateNamespace('self:%s' % template.uri, context, template=template, populate_self=False) context._data['self'] = context._data['local'] = self_ns