From 86411ebded5f62970eaa2b119a215a71212cb492 Mon Sep 17 00:00:00 2001 From: Mike Bayer <mike_mp@zzzcomputing.com> Date: Fri, 5 Feb 2010 00:04:55 +0000 Subject: [PATCH] - update copyright for 2010 - start work on #98 --- CHANGES | 4 + LICENSE | 4 +- lib/mako/__init__.py | 2 +- lib/mako/ast.py | 2 +- lib/mako/codegen.py | 97 +++++++++++++----- lib/mako/exceptions.py | 2 +- lib/mako/filters.py | 2 +- lib/mako/lexer.py | 2 +- lib/mako/lookup.py | 127 ++++++++++++++++------- lib/mako/parsetree.py | 2 +- lib/mako/pygen.py | 2 +- lib/mako/runtime.py | 2 +- lib/mako/template.py | 225 ++++++++++++++++++++++++++++++----------- lib/mako/util.py | 10 +- 14 files changed, 352 insertions(+), 131 deletions(-) diff --git a/CHANGES b/CHANGES index 46aa4da..96fedad 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +0.3 +- Python 2.3 support is dropped (who can resist + @decorators) + 0.2.6 - Fix mako function decorators to preserve the diff --git a/LICENSE b/LICENSE index 9df31e9..86d4196 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ This is the MIT license: http://www.opensource.org/licenses/mit-license.php -Copyright (C) 2006, 2007, 2008, 2009 Michael Bayer and contributors. Mako is a trademark of Michael -Bayer. +Copyright (C) 2006, 2007, 2008, 2009, 2010 Michael Bayer and contributors. +Mako is a trademark of Michael Bayer. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software diff --git a/lib/mako/__init__.py b/lib/mako/__init__.py index c08bf6c..6a30418 100644 --- a/lib/mako/__init__.py +++ b/lib/mako/__init__.py @@ -1,5 +1,5 @@ # __init__.py -# Copyright (C) 2006, 2007, 2008, 2009 Michael Bayer mike_mp@zzzcomputing.com +# Copyright (C) 2006, 2007, 2008, 2009, 2010 Michael Bayer mike_mp@zzzcomputing.com # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php diff --git a/lib/mako/ast.py b/lib/mako/ast.py index 3ba4532..3b9f3ed 100644 --- a/lib/mako/ast.py +++ b/lib/mako/ast.py @@ -1,5 +1,5 @@ # ast.py -# Copyright (C) 2006, 2007, 2008, 2009 Michael Bayer mike_mp@zzzcomputing.com +# Copyright (C) 2006, 2007, 2008, 2009, 2010 Michael Bayer mike_mp@zzzcomputing.com # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php diff --git a/lib/mako/codegen.py b/lib/mako/codegen.py index 7df2473..b3074f0 100644 --- a/lib/mako/codegen.py +++ b/lib/mako/codegen.py @@ -1,5 +1,5 @@ # codegen.py -# Copyright (C) 2006, 2007, 2008, 2009 Michael Bayer mike_mp@zzzcomputing.com +# Copyright (C) 2006, 2007, 2008, 2009, 2010 Michael Bayer mike_mp@zzzcomputing.com # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php @@ -13,18 +13,41 @@ from mako import util, ast, parsetree, filters MAGIC_NUMBER = 5 - -def compile(node, uri, filename=None, default_filters=None, buffer_filters=None, imports=None, source_encoding=None, generate_unicode=True): - """generate module source code given a parsetree node, uri, and optional source filename""" +def compile(node, + uri, + filename=None, + default_filters=None, + buffer_filters=None, + imports=None, + source_encoding=None, + generate_unicode=True): + + """Generate module source code given a parsetree node, + uri, and optional source filename""" buf = util.FastEncodingBuffer(unicode=generate_unicode) printer = PythonPrinter(buf) - _GenerateRenderMethod(printer, _CompileContext(uri, filename, default_filters, buffer_filters, imports, source_encoding, generate_unicode), node) + _GenerateRenderMethod(printer, + _CompileContext(uri, + filename, + default_filters, + buffer_filters, + imports, + source_encoding, + generate_unicode), + node) return buf.getvalue() class _CompileContext(object): - def __init__(self, uri, filename, default_filters, buffer_filters, imports, source_encoding, generate_unicode): + def __init__(self, + uri, + filename, + default_filters, + buffer_filters, + imports, + source_encoding, + generate_unicode): self.uri = uri self.filename = filename self.default_filters = default_filters @@ -34,7 +57,10 @@ class _CompileContext(object): self.generate_unicode = generate_unicode class _GenerateRenderMethod(object): - """a template visitor object which generates the full module source for a template.""" + """A template visitor object which generates the + full module source for a template. + + """ def __init__(self, printer, compiler, node): self.printer = printer self.last_source_line = -1 @@ -70,17 +96,24 @@ class _GenerateRenderMethod(object): else: args = [a for a in ['context'] + args] - self.write_render_callable(pagetag or node, name, args, buffered, filtered, cached) + self.write_render_callable( + pagetag or node, + name, args, + buffered, filtered, cached) if defs is not None: for node in defs: _GenerateRenderMethod(printer, compiler, node) - identifiers = property(lambda self:self.identifier_stack[-1]) + @property + def identifiers(self): + return self.identifier_stack[-1] def write_toplevel(self): - """traverse a template structure for module-level directives and generate the - start of module-level code.""" + """Traverse a template structure for module-level directives and + generate the start of module-level code. + + """ inherit = [] namespaces = {} module_code = [] @@ -113,36 +146,50 @@ class _GenerateRenderMethod(object): module_identifiers.declared = module_ident # module-level names, python code - if not self.compiler.generate_unicode and self.compiler.source_encoding: - self.printer.writeline("# -*- encoding:%s -*-" % self.compiler.source_encoding) + if not self.compiler.generate_unicode and \ + self.compiler.source_encoding: + self.printer.writeline("# -*- encoding:%s -*-" % + self.compiler.source_encoding) self.printer.writeline("from mako import runtime, filters, cache") self.printer.writeline("UNDEFINED = runtime.UNDEFINED") self.printer.writeline("__M_dict_builtin = dict") self.printer.writeline("__M_locals_builtin = locals") - 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)") - self.printer.writeline("_source_encoding=%s" % repr(self.compiler.source_encoding)) + self.printer.writeline("_magic_number = %r" % MAGIC_NUMBER) + self.printer.writeline("_modified_time = %r" % time.time()) + self.printer.writeline( + "_template_filename=%r" % self.compiler.filename) + self.printer.writeline("_template_uri=%r" % self.compiler.uri) + self.printer.writeline( + "_template_cache=cache.Cache(__name__, _modified_time)") + self.printer.writeline( + "_source_encoding=%r" % self.compiler.source_encoding) if self.compiler.imports: buf = '' for imp in self.compiler.imports: buf += imp + "\n" self.printer.writeline(imp) - impcode = ast.PythonCode(buf, source='', lineno=0, pos=0, filename='template defined imports') + impcode = ast.PythonCode( + buf, + source='', lineno=0, + pos=0, + filename='template defined imports') else: impcode = None main_identifiers = module_identifiers.branch(self.node) - module_identifiers.topleveldefs = module_identifiers.topleveldefs.union(main_identifiers.topleveldefs) - [module_identifiers.declared.add(x) for x in ["UNDEFINED"]] + module_identifiers.topleveldefs = \ + module_identifiers.topleveldefs.\ + union(main_identifiers.topleveldefs) + module_identifiers.declared.add("UNDEFINED") if impcode: - [module_identifiers.declared.add(x) for x in impcode.declared_identifiers] + module_identifiers.declared.update(impcode.declared_identifiers) self.compiler.identifiers = module_identifiers - self.printer.writeline("_exports = %s" % repr([n.name for n in main_identifiers.topleveldefs.values()])) + self.printer.writeline("_exports = %r" % + [n.name for n in + main_identifiers.topleveldefs.values()] + ) self.printer.write("\n\n") if len(module_code): @@ -156,6 +203,8 @@ class _GenerateRenderMethod(object): return main_identifiers.topleveldefs.values() +##### continue [ticket:98] below #### + def write_render_callable(self, node, name, args, buffered, filtered, cached): """write a top-level render callable. diff --git a/lib/mako/exceptions.py b/lib/mako/exceptions.py index aa529d7..dcd6a64 100644 --- a/lib/mako/exceptions.py +++ b/lib/mako/exceptions.py @@ -1,5 +1,5 @@ # exceptions.py -# Copyright (C) 2006, 2007, 2008, 2009 Michael Bayer mike_mp@zzzcomputing.com +# Copyright (C) 2006, 2007, 2008, 2009, 2010 Michael Bayer mike_mp@zzzcomputing.com # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php diff --git a/lib/mako/filters.py b/lib/mako/filters.py index 13ac622..9a5b21d 100644 --- a/lib/mako/filters.py +++ b/lib/mako/filters.py @@ -1,5 +1,5 @@ # filters.py -# Copyright (C) 2006, 2007, 2008, 2009 Geoffrey T. Dairiki <dairiki@dairiki.org> and Michael Bayer <mike_mp@zzzcomputing.com> +# Copyright (C) 2006, 2007, 2008, 2009, 2010 Geoffrey T. Dairiki <dairiki@dairiki.org> and Michael Bayer <mike_mp@zzzcomputing.com> # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php diff --git a/lib/mako/lexer.py b/lib/mako/lexer.py index de562cc..52a4b6d 100644 --- a/lib/mako/lexer.py +++ b/lib/mako/lexer.py @@ -1,5 +1,5 @@ # lexer.py -# Copyright (C) 2006, 2007, 2008, 2009 Michael Bayer mike_mp@zzzcomputing.com +# Copyright (C) 2006, 2007, 2008, 2009, 2010 Michael Bayer mike_mp@zzzcomputing.com # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php diff --git a/lib/mako/lookup.py b/lib/mako/lookup.py index a213973..0398c5e 100644 --- a/lib/mako/lookup.py +++ b/lib/mako/lookup.py @@ -1,5 +1,6 @@ # lookup.py -# Copyright (C) 2006, 2007, 2008, 2009 Michael Bayer mike_mp@zzzcomputing.com +# Copyright (C) 2006, 2007, 2008, 2009, 2010 Michael Bayer +# mike_mp@zzzcomputing.com # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php @@ -18,35 +19,59 @@ class TemplateCollection(object): try: self.get_template(uri) return True - except exceptions.TemplateLookupException, e: + except exceptions.TemplateLookupException: return False + def get_template(self, uri, relativeto=None): raise NotImplementedError() + def filename_to_uri(self, uri, filename): - """convert the given filename to a uri relative to this TemplateCollection.""" + """Convert the given filename to a uri relative to + this TemplateCollection.""" + return uri def adjust_uri(self, uri, filename): - """adjust the given uri based on the calling filename. + """Adjust the given uri based on the calling filename. + + When this method is called from the runtime, the 'filename' parameter + is taken directly to the 'filename' attribute of the calling template. + Therefore a custom TemplateCollection subclass can place any string + identifier desired in the "filename" parameter of the Template objects + it constructs and have them come back here. - when this method is called from the runtime, the 'filename' parameter - is taken directly to the 'filename' attribute of the calling - template. Therefore a custom TemplateCollection subclass can place any string - identifier desired in the "filename" parameter of the Template objects it constructs - and have them come back here.""" + """ return uri class TemplateLookup(TemplateCollection): - def __init__(self, directories=None, module_directory=None, filesystem_checks=True, collection_size=-1, format_exceptions=False, - error_handler=None, disable_unicode=False, output_encoding=None, encoding_errors='strict', cache_type=None, cache_dir=None, cache_url=None, - cache_enabled=True, modulename_callable=None, default_filters=None, buffer_filters=[], imports=None, input_encoding=None, preprocessor=None): - if isinstance(directories, basestring): - directories = [directories] - self.directories = [posixpath.normpath(d) for d in directories or []] + def __init__(self, + directories=None, + module_directory=None, + filesystem_checks=True, + collection_size=-1, + format_exceptions=False, + error_handler=None, + disable_unicode=False, + output_encoding=None, + encoding_errors='strict', + cache_type=None, + cache_dir=None, cache_url=None, + cache_enabled=True, + modulename_callable=None, + default_filters=None, + buffer_filters=(), + imports=None, + input_encoding=None, + preprocessor=None): + + self.directories = [posixpath.normpath(d) for d in + util.to_list(directories, ()) + ] self.module_directory = module_directory self.modulename_callable = modulename_callable self.filesystem_checks = filesystem_checks self.collection_size = collection_size + self.template_args = { 'format_exceptions':format_exceptions, 'error_handler':error_handler, @@ -63,28 +88,30 @@ class TemplateLookup(TemplateCollection): 'buffer_filters':buffer_filters, 'imports':imports, 'preprocessor':preprocessor} + if collection_size == -1: - self.__collection = {} + self._collection = {} self._uri_cache = {} else: - self.__collection = util.LRUCache(collection_size) + self._collection = util.LRUCache(collection_size) self._uri_cache = util.LRUCache(collection_size) self._mutex = threading.Lock() def get_template(self, uri): try: if self.filesystem_checks: - return self.__check(uri, self.__collection[uri]) + return self._check(uri, self._collection[uri]) else: - return self.__collection[uri] + return self._collection[uri] except KeyError: u = re.sub(r'^\/+', '', uri) for dir in self.directories: srcfile = posixpath.normpath(posixpath.join(dir, u)) if os.path.exists(srcfile): - return self.__load(srcfile, uri) + return self._load(srcfile, uri) else: - raise exceptions.TopLevelLookupException("Cant locate template for uri '%s'" % uri) + raise exceptions.TopLevelLookupException( + "Cant locate template for uri %r" % uri) def adjust_uri(self, uri, relativeto): """adjust the given uri based on the calling filename.""" @@ -102,12 +129,16 @@ class TemplateLookup(TemplateCollection): try: return self._uri_cache[filename] except KeyError: - value = self.__relativeize(filename) + value = self._relativeize(filename) self._uri_cache[filename] = value return value - def __relativeize(self, filename): - """return the portion of a filename that is 'relative' to the directories in this lookup.""" + def _relativeize(self, filename): + """Return the portion of a filename that is 'relative' + to the directories in this lookup. + + """ + filename = posixpath.normpath(filename) for dir in self.directories: if filename[0:len(dir)] == dir: @@ -115,37 +146,57 @@ class TemplateLookup(TemplateCollection): else: return None - def __load(self, filename, uri): + def _load(self, filename, uri): self._mutex.acquire() try: try: - # try returning from collection one more time in case concurrent thread already loaded - return self.__collection[uri] + # try returning from collection one + # more time in case concurrent thread already loaded + return self._collection[uri] except KeyError: pass try: - self.__collection[uri] = Template(uri=uri, filename=posixpath.normpath(filename), lookup=self, module_filename=(self.modulename_callable is not None and self.modulename_callable(filename, uri) or None), **self.template_args) - return self.__collection[uri] + if self.modulename_callable is not None: + module_filename = self.modulename_callable(filename, uri) + else: + module_filename = None + self._collection[uri] = template = Template( + uri=uri, + filename=posixpath.normpath(filename), + lookup=self, + module_filename=module_filename, + **self.template_args) + return template except: - self.__collection.pop(uri, None) + # if compilation fails etc, ensure + # template is removed from collection, + # re-raise + self._collection.pop(uri, None) raise finally: self._mutex.release() - def __check(self, uri, template): + def _check(self, uri, template): if template.filename is None: return template if not os.path.exists(template.filename): - self.__collection.pop(uri, None) - raise exceptions.TemplateLookupException("Cant locate template for uri '%s'" % uri) - elif template.module._modified_time < os.stat(template.filename)[stat.ST_MTIME]: - self.__collection.pop(uri, None) - return self.__load(template.filename, uri) + self._collection.pop(uri, None) + raise exceptions.TemplateLookupException( + "Cant locate template for uri %r" % uri) + elif template.module._modified_time < \ + os.stat(template.filename)[stat.ST_MTIME]: + self._collection.pop(uri, None) + return self._load(template.filename, uri) else: return template def put_string(self, uri, text): - self.__collection[uri] = Template(text, lookup=self, uri=uri, **self.template_args) + self._collection[uri] = Template( + text, + lookup=self, + uri=uri, + **self.template_args) + def put_template(self, uri, template): - self.__collection[uri] = template + self._collection[uri] = template diff --git a/lib/mako/parsetree.py b/lib/mako/parsetree.py index fd588c1..347c31a 100644 --- a/lib/mako/parsetree.py +++ b/lib/mako/parsetree.py @@ -1,5 +1,5 @@ # parsetree.py -# Copyright (C) 2006, 2007, 2008, 2009 Michael Bayer mike_mp@zzzcomputing.com +# Copyright (C) 2006, 2007, 2008, 2009, 2010 Michael Bayer mike_mp@zzzcomputing.com # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php diff --git a/lib/mako/pygen.py b/lib/mako/pygen.py index 76e6e87..914443b 100644 --- a/lib/mako/pygen.py +++ b/lib/mako/pygen.py @@ -1,5 +1,5 @@ # pygen.py -# Copyright (C) 2006, 2007, 2008, 2009 Michael Bayer mike_mp@zzzcomputing.com +# Copyright (C) 2006, 2007, 2008, 2009, 2010 Michael Bayer mike_mp@zzzcomputing.com # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php diff --git a/lib/mako/runtime.py b/lib/mako/runtime.py index ee6c5be..a475b71 100644 --- a/lib/mako/runtime.py +++ b/lib/mako/runtime.py @@ -1,5 +1,5 @@ # runtime.py -# Copyright (C) 2006, 2007, 2008, 2009 Michael Bayer mike_mp@zzzcomputing.com +# Copyright (C) 2006, 2007, 2008, 2009, 2010 Michael Bayer mike_mp@zzzcomputing.com # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php diff --git a/lib/mako/template.py b/lib/mako/template.py index 45b5403..4bf01e0 100644 --- a/lib/mako/template.py +++ b/lib/mako/template.py @@ -1,34 +1,55 @@ # template.py -# Copyright (C) 2006, 2007, 2008, 2009 Michael Bayer mike_mp@zzzcomputing.com +# Copyright (C) 2006, 2007, 2008, 2009, 2010 Michael Bayer +# mike_mp@zzzcomputing.com # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php -"""provides the Template class, a facade for parsing, generating and executing template strings, -as well as template runtime operations.""" +"""Provides the Template class, a facade for parsing, generating and executing +template strings, as well as template runtime operations.""" from mako.lexer import Lexer -from mako import codegen -from mako import runtime, util, exceptions +from mako import runtime, util, exceptions, codegen import imp, os, re, shutil, stat, sys, tempfile, time, types, weakref class Template(object): """a compiled template""" - def __init__(self, text=None, filename=None, uri=None, format_exceptions=False, error_handler=None, - lookup=None, output_encoding=None, encoding_errors='strict', module_directory=None, cache_type=None, - cache_dir=None, cache_url=None, module_filename=None, input_encoding=None, disable_unicode=False, default_filters=None, - buffer_filters=[], imports=None, preprocessor=None, cache_enabled=True): - """construct a new Template instance using either literal template text, or a previously loaded template module + def __init__(self, + text=None, + filename=None, + uri=None, + format_exceptions=False, + error_handler=None, + lookup=None, + output_encoding=None, + encoding_errors='strict', + module_directory=None, + cache_type=None, + cache_dir=None, + cache_url=None, + module_filename=None, + input_encoding=None, + disable_unicode=False, + default_filters=None, + buffer_filters=(), + imports=None, + preprocessor=None, + cache_enabled=True): + """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 + :param text: textual template source, or None if a module is to be + provided - 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 + :param 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 + :param filename: filename of the source template, if any - format_exceptions - catch exceptions and format them into an error display template + :param format_exceptions: catch exceptions and format them into an + error display template """ if uri: @@ -72,30 +93,48 @@ class Template(object): u = self.uri if u[0] == '/': u = u[1:] - path = os.path.abspath(os.path.join(module_directory.replace('/', os.path.sep), u + ".py")) + path = os.path.abspath( + os.path.join( + module_directory.replace('/', os.path.sep), + u + ".py" + ) + ) else: path = None if path is not None: util.verify_directory(os.path.dirname(path)) filemtime = os.stat(filename)[stat.ST_MTIME] - if not os.path.exists(path) or os.stat(path)[stat.ST_MTIME] < filemtime: - _compile_module_file(self, file(filename).read(), filename, path) + if not os.path.exists(path) or \ + os.stat(path)[stat.ST_MTIME] < filemtime: + _compile_module_file( + self, + file(filename).read(), + filename, + path) module = imp.load_source(self.module_id, path, file(path)) del sys.modules[self.module_id] if module._magic_number != codegen.MAGIC_NUMBER: - _compile_module_file(self, file(filename).read(), filename, path) + _compile_module_file( + self, + file(filename).read(), + filename, + path) module = imp.load_source(self.module_id, path, file(path)) del sys.modules[self.module_id] ModuleInfo(module, path, self, filename, None, None) else: # template filename and no module directory, compile code # in memory - (code, module) = _compile_text(self, file(filename).read(), filename) + (code, module) = _compile_text( + self, + file(filename).read(), + filename) self._source = None self._code = code ModuleInfo(module, None, self, filename, code, None) else: - raise exceptions.RuntimeException("Template requires text or filename") + raise exceptions.RuntimeException( + "Template requires text or filename") self.module = module self.filename = filename @@ -107,54 +146,71 @@ class Template(object): self.cache_dir = cache_dir self.cache_url = cache_url self.cache_enabled = cache_enabled - + + @property def source(self): """return the template source code for this Template.""" + return _get_module_info_from_callable(self.callable_).source - source = property(source) - + + @property def code(self): """return the module source code for this Template""" + return _get_module_info_from_callable(self.callable_).code - code = property(code) + @property def cache(self): return self.module._template_cache - cache = property(cache) def render(self, *args, **data): - """render the output of this template as a string. + """Render the output of this template as a string. + + if the template specifies an output encoding, the string will be + encoded accordingly, else the output is raw (raw output uses cStringIO + and can't handle multibyte characters). a Context object is created + corresponding to the given data. Arguments that are explictly declared + by this template's internal rendering method are also pulled from the + given \*args, \**data members. - if the template specifies an output encoding, the string will be encoded accordingly, else the output - is raw (raw output uses cStringIO and can't handle multibyte characters). - a Context object is created corresponding to the given data. Arguments that are explictly - declared by this template's internal rendering method are also pulled from the given *args, **data - members.""" + """ return runtime._render(self, self.callable_, args, data) def render_unicode(self, *args, **data): """render the output of this template as a unicode object.""" - return runtime._render(self, self.callable_, args, data, as_unicode=True) + return runtime._render(self, + self.callable_, + args, + data, + as_unicode=True) def render_context(self, context, *args, **kwargs): - """render this Template with the given context. + """Render this Template with the given context. - the data is written to the context's buffer.""" + the data is written to the context's buffer. + + """ if getattr(context, '_with_template', None) is None: context._with_template = self - runtime._render_context(self, self.callable_, context, *args, **kwargs) + runtime._render_context(self, + self.callable_, + context, + *args, + **kwargs) def has_def(self, name): return hasattr(self.module, "render_%s" % name) def get_def(self, name): - """return a def of this template as an individual Template of its own.""" + """Return a def of this template as a DefTemplate.""" + return DefTemplate(self, getattr(self.module, "render_%s" % name)) def _get_def_callable(self, name): return getattr(self.module, "render_%s" % name) + @property def last_modified(self): return self.module._modified_time last_modified = property(last_modified) @@ -177,11 +233,21 @@ class ModuleTemplate(Template): """ def __init__(self, module, - module_filename=None, - template=None, template_filename=None, - module_source=None, template_source=None, - output_encoding=None, encoding_errors='strict', disable_unicode=False, format_exceptions=False, - error_handler=None, lookup=None, cache_type=None, cache_dir=None, cache_url=None, cache_enabled=True + module_filename=None, + template=None, + template_filename=None, + module_source=None, + template_source=None, + output_encoding=None, + encoding_errors='strict', + disable_unicode=False, + format_exceptions=False, + error_handler=None, + lookup=None, + cache_type=None, + cache_dir=None, + cache_url=None, + cache_enabled=True ): self.module_id = re.sub(r'\W', "_", module._template_uri) self.uri = module._template_uri @@ -191,7 +257,12 @@ class ModuleTemplate(Template): self.disable_unicode = disable_unicode self.module = module self.filename = template_filename - ModuleInfo(module, module_filename, self, template_filename, module_source, template_source) + ModuleInfo(module, + module_filename, + self, + template_filename, + module_source, + template_source) self.callable_ = self.module.render_body self.format_exceptions = format_exceptions @@ -204,6 +275,7 @@ class ModuleTemplate(Template): class DefTemplate(Template): """a Template which represents a callable def in a parent template.""" + def __init__(self, parent, callable_): self.parent = parent self.callable_ = callable_ @@ -218,12 +290,20 @@ class DefTemplate(Template): return self.parent.get_def(name) class ModuleInfo(object): - """stores information about a module currently loaded into memory, + """Stores information about a module currently loaded into memory, provides reverse lookups of template source, module source code based on - a module's identifier.""" + a module's identifier. + + """ _modules = weakref.WeakValueDictionary() - def __init__(self, module, module_filename, template, template_filename, module_source, template_source): + def __init__(self, + module, + module_filename, + template, + template_filename, + module_source, + template_source): self.module = module self.module_filename = module_filename self.template_filename = template_filename @@ -232,31 +312,48 @@ class ModuleInfo(object): self._modules[module.__name__] = template._mmarker = self if module_filename: self._modules[module_filename] = self - def _get_code(self): + + @property + def code(self): if self.module_source is not None: return self.module_source else: return file(self.module_filename).read() - code = property(_get_code) - def _get_source(self): + + @property + def source(self): if self.template_source is not None: - if self.module._source_encoding and not isinstance(self.template_source, unicode): - return self.template_source.decode(self.module._source_encoding) + if self.module._source_encoding and \ + not isinstance(self.template_source, unicode): + return self.template_source.decode( + self.module._source_encoding) else: return self.template_source else: if self.module._source_encoding: - return file(self.template_filename).read().decode(self.module._source_encoding) + return file(self.template_filename).read().\ + decode(self.module._source_encoding) else: return file(self.template_filename).read() - source = property(_get_source) def _compile_text(template, text, filename): identifier = template.module_id - lexer = Lexer(text, filename, disable_unicode=template.disable_unicode, input_encoding=template.input_encoding, preprocessor=template.preprocessor) + lexer = Lexer(text, + filename, + disable_unicode=template.disable_unicode, + input_encoding=template.input_encoding, + preprocessor=template.preprocessor) node = lexer.parse() - source = codegen.compile(node, template.uri, filename, default_filters=template.default_filters, buffer_filters=template.buffer_filters, imports=template.imports, source_encoding=lexer.encoding, generate_unicode=not template.disable_unicode) - #print source + + source = codegen.compile(node, + template.uri, + filename, + default_filters=template.default_filters, + buffer_filters=template.buffer_filters, + imports=template.imports, + source_encoding=lexer.encoding, + generate_unicode=not template.disable_unicode) + cid = identifier if isinstance(cid, unicode): cid = cid.encode() @@ -267,9 +364,21 @@ def _compile_text(template, text, filename): def _compile_module_file(template, text, filename, outputpath): identifier = template.module_id - lexer = Lexer(text, filename, disable_unicode=template.disable_unicode, input_encoding=template.input_encoding, preprocessor=template.preprocessor) + lexer = Lexer(text, + filename, + disable_unicode=template.disable_unicode, + input_encoding=template.input_encoding, + preprocessor=template.preprocessor) + node = lexer.parse() - source = codegen.compile(node, template.uri, filename, default_filters=template.default_filters, buffer_filters=template.buffer_filters, imports=template.imports, source_encoding=lexer.encoding, generate_unicode=not template.disable_unicode) + source = codegen.compile(node, + template.uri, + filename, + default_filters=template.default_filters, + buffer_filters=template.buffer_filters, + imports=template.imports, + source_encoding=lexer.encoding, + generate_unicode=not template.disable_unicode) (dest, name) = tempfile.mkstemp() os.write(dest, source) os.close(dest) diff --git a/lib/mako/util.py b/lib/mako/util.py index ed308f6..1f9f3d4 100644 --- a/lib/mako/util.py +++ b/lib/mako/util.py @@ -1,5 +1,5 @@ # util.py -# Copyright (C) 2006, 2007, 2008, 2009 Michael Bayer mike_mp@zzzcomputing.com +# Copyright (C) 2006, 2007, 2008, 2009, 2010 Michael Bayer mike_mp@zzzcomputing.com # # This module is part of Mako and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php @@ -43,6 +43,14 @@ def verify_directory(dir): if tries > 5: raise +def to_list(x, default=None): + if x is None: + return default + if not isinstance(x, (list, tuple)): + return [x] + else: + return x + class SetLikeDict(dict): """a dictionary that has some setlike methods on it""" def union(self, other): -- GitLab