template.py :  » Template-Engines » Mako » Mako-0.3.2 » mako » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Template Engines » Mako 
Mako » Mako 0.3.2 » mako » template.py
# template.py
# 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."""

from mako.lexer import Lexer
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
        
        :param text: textual template source, or None if a module is to be
            provided
        
        :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
        
        :param filename: filename of the source template, if any
        
        :param format_exceptions: catch exceptions and format them into an
            error display template
        """
        
        if uri:
            self.module_id = re.sub(r'\W', "_", uri)
            self.uri = uri
        elif filename:
            self.module_id = re.sub(r'\W', "_", filename)
            drive, path = os.path.splitdrive(filename)
            path = os.path.normpath(path).replace(os.path.sep, "/")
            self.uri = path
        else:
            self.module_id = "memory:" + hex(id(self))
            self.uri = self.module_id
        
        self.input_encoding = input_encoding
        self.output_encoding = output_encoding
        self.encoding_errors = encoding_errors
        self.disable_unicode = disable_unicode

        if util.py3k and disable_unicode:
            raise exceptions.UnsupportedError(
                                    "Mako for Python 3 does not "
                                    "support disabling Unicode")
        
        if default_filters is None:
            if util.py3k or self.disable_unicode:
                self.default_filters = ['str']
            else:
                self.default_filters = ['unicode']
        else:
            self.default_filters = default_filters
        self.buffer_filters = buffer_filters
            
        self.imports = imports
        self.preprocessor = preprocessor
        
        # if plain text, compile code in memory only
        if text is not None:
            (code, module) = _compile_text(self, text, filename)
            self._code = code
            self._source = text
            ModuleInfo(module, None, self, filename, code, text)
        elif filename is not None:
            # if template filename and a module directory, load
            # a filesystem-based module file, generating if needed
            if module_filename is not None:
                path = module_filename
            elif module_directory is not None:
                u = self.uri
                if u[0] == '/':
                    u = u[1:]
                path = os.path.abspath(
                        os.path.join(
                            os.path.normpath(module_directory), 
                            os.path.normpath(u) + ".py"
                            )
                        )
            else:
                path = None
                
            module = self._compile_from_file(path, filename)
        else:
            raise exceptions.RuntimeException(
                                "Template requires text or filename")

        self.module = module
        self.filename = filename
        self.callable_ = self.module.render_body
        self.format_exceptions = format_exceptions
        self.error_handler = error_handler
        self.lookup = lookup
        self.cache_type = cache_type
        self.cache_dir = cache_dir
        self.cache_url = cache_url
        self.cache_enabled = cache_enabled
    
    def _compile_from_file(self, path, filename):
        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, 
                            open(filename, 'rb').read(), 
                            filename, 
                            path)
            module = imp.load_source(self.module_id, path, open(path, 'rb'))
            del sys.modules[self.module_id]
            if module._magic_number != codegen.MAGIC_NUMBER:
                _compile_module_file(
                            self, 
                            open(filename, 'rb').read(), 
                            filename, 
                            path)
                module = imp.load_source(self.module_id, path, open(path, 'rb'))
                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, 
                                open(filename, 'rb').read(), 
                                filename)
            self._source = None
            self._code = code
            ModuleInfo(module, None, self, filename, code, None)
        return module
    @property
    def source(self):
        """return the template source code for this Template."""
        
        return _get_module_info_from_callable(self.callable_).source

    @property
    def code(self):
        """return the module source code for this Template"""
        
        return _get_module_info_from_callable(self.callable_).code
    
    @property
    def cache(self):
        return self.module._template_cache
    
    def render(self, *args, **data):
        """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.
        
        """
        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)
        
    def render_context(self, context, *args, **kwargs):
        """Render this Template with the given context.  
        
        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)
    
    def has_def(self, name):
        return hasattr(self.module, "render_%s" % name)
        
    def get_def(self, name):
        """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)
    
class ModuleTemplate(Template):
    """A Template which is constructed given an existing Python module.
    
        e.g.::
        
        t = Template("this is a template")
        f = file("mymodule.py", "w")
        f.write(t.code)
        f.close()
        
        import mymodule
        
        t = ModuleTemplate(mymodule)
        print t.render()
    
    """
    
    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
    ):
        self.module_id = re.sub(r'\W', "_", module._template_uri)
        self.uri = module._template_uri
        self.input_encoding = module._source_encoding
        self.output_encoding = output_encoding
        self.encoding_errors = encoding_errors
        self.disable_unicode = disable_unicode
        self.module = module
        self.filename = template_filename
        ModuleInfo(module, 
                        module_filename, 
                        self, 
                        template_filename, 
                        module_source, 
                        template_source)
        
        self.callable_ = self.module.render_body
        self.format_exceptions = format_exceptions
        self.error_handler = error_handler
        self.lookup = lookup
        self.cache_type = cache_type
        self.cache_dir = cache_dir
        self.cache_url = cache_url
        self.cache_enabled = cache_enabled
        
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_
        self.output_encoding = parent.output_encoding
        self.module = parent.module
        self.encoding_errors = parent.encoding_errors
        self.format_exceptions = parent.format_exceptions
        self.error_handler = parent.error_handler
        self.lookup = parent.lookup

    def get_def(self, name):
        return self.parent.get_def(name)

class ModuleInfo(object):
    """Stores information about a module currently loaded into memory,
    provides reverse lookups of template source, module source code based on
    a module's identifier.
    
    """
    _modules = weakref.WeakValueDictionary()

    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
        self.module_source = module_source
        self.template_source = template_source
        self._modules[module.__name__] = template._mmarker = self
        if module_filename:
            self._modules[module_filename] = self
    
    @property
    def code(self):
        if self.module_source is not None:
            return self.module_source
        else:
            return open(self.module_filename).read()
    
    @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)
            else:
                return self.template_source
        else:
            if self.module._source_encoding:
                return open(self.template_filename, 'rb').read().\
                                decode(self.module._source_encoding)
            else:
                return open(self.template_filename).read()
        
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)
    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_magic_comment=template.disable_unicode)

    cid = identifier
    if not util.py3k and isinstance(cid, unicode):
        cid = cid.encode()
    module = types.ModuleType(cid)
    code = compile(source, cid, 'exec')
    exec code in module.__dict__, module.__dict__
    return (source, module)

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)
                    
    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_magic_comment=True)
    (dest, name) = tempfile.mkstemp()
    
    if isinstance(source, unicode):
        source = source.encode(lexer.encoding or 'ascii')
        
    os.write(dest, source)
    os.close(dest)
    shutil.move(name, outputpath)

def _get_module_info_from_callable(callable_):
    return _get_module_info(callable_.func_globals['__name__'])
    
def _get_module_info(filename):
    return ModuleInfo._modules[filename]
        
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.