converted templates to base filesystem operations on their original uri; module writing occurs in a directory hierarchy resembling uri scheme
diff --git a/lib/mako/codegen.py b/lib/mako/codegen.py index 44f4c7c..2c9bd55 100644 --- a/lib/mako/codegen.py +++ b/lib/mako/codegen.py
@@ -13,15 +13,16 @@ MAGIC_NUMBER = 1 -class Compiler(object): - def __init__(self, node, filename=None): - self.node = node +def compile(node, uri, filename=None): + buf = util.FastEncodingBuffer() + printer = PythonPrinter(buf) + _GenerateRenderMethod(printer, _CompileContext(uri, filename), node) + return buf.getvalue() + +class _CompileContext(object): + def __init__(self, uri, filename): + self.uri = uri self.filename = filename - def render(self): - buf = util.FastEncodingBuffer() - printer = PythonPrinter(buf) - _GenerateRenderMethod(printer, self, self.node) - return buf.getvalue() class _GenerateRenderMethod(object): """a template visitor object which generates the full module source for a template.""" @@ -101,6 +102,7 @@ self.printer.writeline("_magic_number = %s" % repr(MAGIC_NUMBER)) self.printer.writeline("_modified_time = %s" % repr(time.time())) self.printer.writeline("_template_filename=%s" % repr(self.compiler.filename)) + self.printer.writeline("_template_uri=%s" % repr(self.compiler.uri)) self.printer.writeline("_template_cache=cache.Cache(__name__, _modified_time)") main_identifiers = module_identifiers.branch(self.node) @@ -157,7 +159,7 @@ """write the module-level inheritance-determination callable.""" self.printer.writeline("def _mako_inherit(template, context):") self.printer.writeline("_mako_generate_namespaces(context)") - self.printer.writeline("return runtime.inherit_from(context, %s, _template_filename)" % (node.parsed_attributes['file'])) + self.printer.writeline("return runtime.inherit_from(context, %s, _template_uri)" % (node.parsed_attributes['file'])) self.printer.writeline(None) def write_namespaces(self, namespaces): @@ -192,7 +194,7 @@ callable_name = "make_namespace()" else: callable_name = "None" - self.printer.writeline("ns = runtime.Namespace(%s, context.clean_inheritance_tokens(), templateuri=%s, callables=%s, calling_filename=_template_filename)" % (repr(node.name), node.parsed_attributes.get('file', 'None'), callable_name)) + self.printer.writeline("ns = runtime.Namespace(%s, context.clean_inheritance_tokens(), templateuri=%s, callables=%s, calling_uri=_template_uri)" % (repr(node.name), node.parsed_attributes.get('file', 'None'), callable_name)) if eval(node.attributes.get('inheritable', "False")): self.printer.writeline("context['self'].%s = ns" % (node.name)) self.printer.writeline("context.namespaces[(render, %s)] = ns" % repr(node.name)) @@ -401,7 +403,7 @@ def visitIncludeTag(self, node): self.write_source_comment(node) - self.printer.writeline("runtime.include_file(context, %s, _template_filename)" % (node.parsed_attributes['file'])) + self.printer.writeline("runtime.include_file(context, %s, _template_uri)" % (node.parsed_attributes['file'])) def visitNamespaceTag(self, node): pass
diff --git a/lib/mako/ext/autohandler.py b/lib/mako/ext/autohandler.py index 9fb2194..4dd6b6c 100644 --- a/lib/mako/ext/autohandler.py +++ b/lib/mako/ext/autohandler.py
@@ -23,20 +23,19 @@ def autohandler(template, context, name='autohandler'): lookup = context.lookup - _template_filename = template.module._template_filename + _template_uri = template.module._template_uri if not lookup.filesystem_checks: try: - return lookup._uri_cache[(autohandler, _template_filename, name)] + return lookup._uri_cache[(autohandler, _template_uri, name)] except KeyError: pass - uri = lookup.filename_to_uri(_template_filename) - tokens = re.findall(r'([^/]+)', posixpath.dirname(uri)) + [name] + tokens = re.findall(r'([^/]+)', posixpath.dirname(_template_uri)) + [name] while len(tokens): path = '/' + '/'.join(tokens) - if path != uri and _file_exists(lookup, path): + if path != _template_uri and _file_exists(lookup, path): if not lookup.filesystem_checks: - return lookup._uri_cache.setdefault((autohandler, _template_filename, name), path) + return lookup._uri_cache.setdefault((autohandler, _template_uri, name), path) else: return path if len(tokens) == 1: @@ -44,7 +43,7 @@ tokens[-2:] = [name] if not lookup.filesystem_checks: - return lookup._uri_cache.setdefault((autohandler, _template_filename, name), None) + return lookup._uri_cache.setdefault((autohandler, _template_uri, name), None) else: return None
diff --git a/lib/mako/lookup.py b/lib/mako/lookup.py index ae9eabe..76c80e7 100644 --- a/lib/mako/lookup.py +++ b/lib/mako/lookup.py
@@ -66,22 +66,17 @@ else: raise exceptions.TopLevelLookupException("Cant locate template for uri '%s'" % uri) - def adjust_uri(self, uri, filename): + def adjust_uri(self, uri, relativeto): """adjust the given uri based on the calling filename.""" - try: - return self._uri_cache[(uri, filename)] - except KeyError: - if uri[0] != '/': - u = posixpath.normpath(uri) - if filename is not None: - rr = self.__relativeize(filename) - if rr is not None: - u = posixpath.join(posixpath.dirname(rr), u) - else: - u = posixpath.join('/', u) - return self._uri_cache.setdefault((uri, filename), u) + + if uri[0] != '/': + if relativeto is not None: + return posixpath.join(posixpath.dirname(relativeto), uri) else: - return self._uri_cache.setdefault((uri, filename), uri) + return '/' + uri + else: + return uri + def filename_to_uri(self, filename): try: @@ -109,7 +104,7 @@ except KeyError: pass try: - self.__collection[uri] = Template(identifier=self.__relativeize(filename), uri=uri, filename=posixpath.normpath(filename), lookup=self, **self.template_args) + self.__collection[uri] = Template(uri=uri, filename=posixpath.normpath(filename), lookup=self, **self.template_args) return self.__collection[uri] except: self.__collection.pop(uri, None)
diff --git a/lib/mako/runtime.py b/lib/mako/runtime.py index a5189ea..3fdd70e 100644 --- a/lib/mako/runtime.py +++ b/lib/mako/runtime.py
@@ -86,11 +86,11 @@ class Namespace(object): """provides access to collections of rendering methods, which can be local, from other templates, or from imported modules""" - def __init__(self, name, context, module=None, template=None, templateuri=None, callables=None, inherits=None, populate_self=True, calling_filename=None): + def __init__(self, name, context, module=None, template=None, templateuri=None, callables=None, inherits=None, populate_self=True, calling_uri=None): self.name = name self._module = module if templateuri is not None: - self.template = _lookup_template(context, templateuri, calling_filename) + self.template = _lookup_template(context, templateuri, calling_uri) else: self.template = template self.context = context @@ -165,18 +165,18 @@ buf = context.pop_buffer() return buf.getvalue() -def include_file(context, uri, calling_filename): +def include_file(context, uri, calling_uri): """locate the template from the given uri and include it in the current output.""" - template = _lookup_template(context, uri, calling_filename) + template = _lookup_template(context, uri, calling_uri) (callable_, ctx) = _populate_self_namespace(context.clean_inheritance_tokens(), template) callable_(ctx) -def inherit_from(context, uri, calling_filename): +def inherit_from(context, uri, calling_uri): """called by the _inherit method in template modules to set up the inheritance chain at the start of a template's execution.""" if uri is None: return None - template = _lookup_template(context, uri, calling_filename) + template = _lookup_template(context, uri, calling_uri) self_ns = context['self'] ih = self_ns while ih.inherits is not None:
diff --git a/lib/mako/template.py b/lib/mako/template.py index c213f49..fa102d3 100644 --- a/lib/mako/template.py +++ b/lib/mako/template.py
@@ -8,7 +8,7 @@ as well as template runtime operations.""" from mako.lexer import Lexer -from mako.codegen import Compiler +from mako import codegen from mako import runtime, util, exceptions import imp, time, weakref, tempfile, shutil, os, stat, posixpath, sys, re @@ -16,42 +16,49 @@ class Template(object): """a compiled template""" - def __init__(self, text=None, identifier=None, filename=None, uri=None, format_exceptions=False, error_handler=None, lookup=None, output_encoding=None, module_directory=None): + def __init__(self, text=None, filename=None, uri=None, format_exceptions=False, error_handler=None, lookup=None, output_encoding=None, module_directory=None): """construct a new Template instance using either literal template text, or a previously loaded template module text - textual template source, or None if a module is to be provided - identifier - the "id" of this template. defaults to the + uri - the uri of this template, or some identifying string. defaults to the full filename given, or "memory:(hex id of this Template)" if no filename filename - filename of the source template, if any format_exceptions - catch exceptions and format them into an error display template """ - if identifier: - self.identifier = re.sub(r'\W', "_", identifier) + if uri: + self.module_id = re.sub(r'\W', "_", uri) + self.uri = uri elif filename: - self.identifier = re.sub(r'\W', "_", filename) + self.module_id = re.sub(r'\W', "_", filename) + self.uri = filename else: - self.identifier = "memory:" + hex(id(self)) + self.module_id = "memory:" + hex(id(self)) + self.uri = self.module_id if text is not None: - (code, module) = _compile_text(text, self.identifier, filename) + (code, module) = _compile_text(text, self.module_id, filename, self.uri) self._code = code self._source = text ModuleInfo(module, None, self, filename, code, text) elif filename is not None: if module_directory is not None: - path = posixpath.join(module_directory, self.identifier + ".py") + u = self.uri + if u[0] == '/': + u = u[1:] + path = posixpath.join(module_directory, u + ".py") + util.verify_directory(posixpath.dirname(path)) filemtime = os.stat(filename)[stat.ST_MTIME] if not os.access(path, os.F_OK) or os.stat(path)[stat.ST_MTIME] < filemtime: util.verify_directory(module_directory) - _compile_module_file(file(filename).read(), identifier, filename, path) - module = imp.load_source(self.identifier, path, file(path)) - del sys.modules[self.identifier] + _compile_module_file(file(filename).read(), self.module_id, filename, path, self.uri) + module = imp.load_source(self.module_id, path, file(path)) + del sys.modules[self.module_id] ModuleInfo(module, path, self, filename, None, None) else: - (code, module) = _compile_text(file(filename).read(), self.identifier, filename) + (code, module) = _compile_text(file(filename).read(), self.module_id, filename, self.uri) self._source = None self._code = code ModuleInfo(module, None, self, filename, code, None) @@ -60,7 +67,6 @@ self.module = module self.filename = filename - self.uri = uri self.callable_ = self.module.render self.format_exceptions = format_exceptions self.error_handler = error_handler @@ -130,19 +136,19 @@ return file(self.template_filename).read() source = property(_get_source) -def _compile_text(text, identifier, filename): +def _compile_text(text, identifier, filename, uri): node = Lexer(text, filename).parse() - source = Compiler(node, filename).render() + source = codegen.compile(node, uri, filename) cid = identifier module = imp.new_module(cid) code = compile(source, cid, 'exec') exec code in module.__dict__, module.__dict__ return (source, module) -def _compile_module_file(text, identifier, filename, outputpath): +def _compile_module_file(text, identifier, filename, outputpath, uri): (dest, name) = tempfile.mkstemp() node = Lexer(text, filename).parse() - source = Compiler(node, filename).render() + source = codegen.compile(node, uri, filename) os.write(dest, source) os.close(dest) shutil.move(name, outputpath)
diff --git a/test/lookup.py b/test/lookup.py index 5986f64..bb56a70 100644 --- a/test/lookup.py +++ b/test/lookup.py
@@ -34,7 +34,7 @@ ] - assert tl.get_template('/subdir/index.html').identifier == '_subdir_index_html' + assert tl.get_template('/subdir/index.html').module_id == '_subdir_index_html' def test_uri_adjust(self): tl = lookup.TemplateLookup(directories=['/foo/bar'])