root/galaxy-central/eggs/Mako-0.2.5-py2.6.egg/mako/runtime.py @ 3

リビジョン 3, 15.7 KB (コミッタ: kohda, 14 年 前)

Install Unix tools  http://hannonlab.cshl.edu/galaxy_unix_tools/galaxy.html

行番号 
1# runtime.py
2# Copyright (C) 2006, 2007, 2008, 2009 Michael Bayer mike_mp@zzzcomputing.com
3#
4# This module is part of Mako and is released under
5# the MIT License: http://www.opensource.org/licenses/mit-license.php
6
7"""provides runtime services for templates, including Context, Namespace, and various helper functions."""
8
9from mako import exceptions, util
10import __builtin__, inspect, sys
11
12class Context(object):
13    """provides runtime namespace, output buffer, and various callstacks for templates."""
14    def __init__(self, buffer, **data):
15        self._buffer_stack = [buffer]
16        self._orig = data  # original data, minus the builtins
17        self._data = __builtin__.__dict__.copy() # the context data which includes builtins
18        self._data.update(data)
19        self._kwargs = data.copy()
20        self._with_template = None
21        self.namespaces = {}
22       
23        # "capture" function which proxies to the generic "capture" function
24        self._data['capture'] = lambda x, *args, **kwargs: capture(self, x, *args, **kwargs)
25       
26        # "caller" stack used by def calls with content
27        self.caller_stack = self._data['caller'] = CallerStack()
28       
29    lookup = property(lambda self:self._with_template.lookup)
30    kwargs = property(lambda self:self._kwargs.copy())
31   
32    def push_caller(self, caller):
33        self.caller_stack.append(caller)
34       
35    def pop_caller(self):
36        del self.caller_stack[-1]
37       
38    def keys(self):
39        return self._data.keys()
40       
41    def __getitem__(self, key):
42        return self._data[key]
43
44    def _push_writer(self):
45        """push a capturing buffer onto this Context and return the new Writer function."""
46       
47        buf = util.FastEncodingBuffer()
48        self._buffer_stack.append(buf)
49        return buf.write
50
51    def _pop_buffer_and_writer(self):
52        """pop the most recent capturing buffer from this Context
53        and return the current writer after the pop.
54       
55        """
56
57        buf = self._buffer_stack.pop()
58        return buf, self._buffer_stack[-1].write
59       
60    def _push_buffer(self):
61        """push a capturing buffer onto this Context."""
62       
63        self._push_writer()
64       
65    def _pop_buffer(self):
66        """pop the most recent capturing buffer from this Context."""
67       
68        return self._buffer_stack.pop()
69       
70    def get(self, key, default=None):
71        return self._data.get(key, default)
72       
73    def write(self, string):
74        """write a string to this Context's underlying output buffer."""
75       
76        self._buffer_stack[-1].write(string)
77       
78    def writer(self):
79        """return the current writer function"""
80
81        return self._buffer_stack[-1].write
82
83    def _copy(self):
84        c = Context.__new__(Context)
85        c._buffer_stack = self._buffer_stack
86        c._data = self._data.copy()
87        c._orig = self._orig
88        c._kwargs = self._kwargs
89        c._with_template = self._with_template
90        c.namespaces = self.namespaces
91        c.caller_stack = self.caller_stack
92        return c
93    def locals_(self, d):
94        """create a new Context with a copy of this Context's current state, updated with the given dictionary."""
95        if len(d) == 0:
96            return self
97        c = self._copy()
98        c._data.update(d)
99        return c
100    def _clean_inheritance_tokens(self):
101        """create a new copy of this Context with tokens related to inheritance state removed."""
102        c = self._copy()
103        x = c._data
104        x.pop('self', None)
105        x.pop('parent', None)
106        x.pop('next', None)
107        return c
108
109class CallerStack(list):
110    def __init__(self):
111        self.nextcaller = None
112    def __nonzero__(self):
113        return self._get_caller() and True or False
114    def _get_caller(self):
115        return self[-1]
116    def __getattr__(self, key):
117        return getattr(self._get_caller(), key)
118    def _push_frame(self):
119        self.append(self.nextcaller or None)
120        self.nextcaller = None
121    def _pop_frame(self):
122        self.nextcaller = self.pop()
123       
124       
125class Undefined(object):
126    """represents an undefined value in a template."""
127    def __str__(self):
128        raise NameError("Undefined")
129    def __nonzero__(self):
130        return False
131
132UNDEFINED = Undefined()
133
134class _NSAttr(object):
135    def __init__(self, parent):
136        self.__parent = parent
137    def __getattr__(self, key):
138        ns = self.__parent
139        while ns:
140            if hasattr(ns.module, key):
141                return getattr(ns.module, key)
142            else:
143                ns = ns.inherits
144        raise AttributeError(key)   
145   
146class Namespace(object):
147    """provides access to collections of rendering methods, which can be local, from other templates, or from imported modules"""
148    def __init__(self, name, context, module=None, template=None, templateuri=None, callables=None, inherits=None, populate_self=True, calling_uri=None):
149        self.name = name
150        if module is not None:
151            mod = __import__(module)
152            for token in module.split('.')[1:]:
153                mod = getattr(mod, token)
154            self._module = mod
155        else:
156            self._module = None
157        if templateuri is not None:
158            self.template = _lookup_template(context, templateuri, calling_uri)
159            self._templateuri = self.template.module._template_uri
160        else:
161            self.template = template
162            if self.template is not None:
163                self._templateuri = self.template.module._template_uri
164        self.context = context
165        self.inherits = inherits
166        if callables is not None:
167            self.callables = dict([(c.func_name, c) for c in callables])
168        else:
169            self.callables = None
170        if populate_self and self.template is not None:
171            (lclcallable, lclcontext) = _populate_self_namespace(context, self.template, self_ns=self)
172       
173    module = property(lambda s:s._module or s.template.module)
174    filename = property(lambda s:s._module and s._module.__file__ or s.template.filename)
175    uri = property(lambda s:s.template.uri)
176   
177    def attr(self):
178        if not hasattr(self, '_attr'):
179            self._attr = _NSAttr(self)
180        return self._attr
181    attr = property(attr)
182
183    def get_namespace(self, uri):
184        """return a namespace corresponding to the given template uri.
185       
186        if a relative uri, it is adjusted to that of the template of this namespace"""
187        key = (self, uri)
188        if self.context.namespaces.has_key(key):
189            return self.context.namespaces[key]
190        else:
191            ns = Namespace(uri, self.context._copy(), templateuri=uri, calling_uri=self._templateuri)
192            self.context.namespaces[key] = ns
193            return ns
194   
195    def get_template(self, uri):
196        return _lookup_template(self.context, uri, self._templateuri)
197       
198    def get_cached(self, key, **kwargs):
199        if self.template:
200            if not self.template.cache_enabled:
201                createfunc = kwargs.get('createfunc', None)
202                if createfunc:
203                    return createfunc()
204                else:
205                    return None
206               
207            if self.template.cache_dir:
208                kwargs.setdefault('data_dir', self.template.cache_dir)
209            if self.template.cache_type:
210                kwargs.setdefault('type', self.template.cache_type)
211            if self.template.cache_url:
212                kwargs.setdefault('url', self.template.cache_url)
213        return self.cache.get(key, **kwargs)
214   
215    def cache(self):
216        return self.template.cache
217    cache = property(cache)
218   
219    def include_file(self, uri, **kwargs):
220        """include a file at the given uri"""
221        _include_file(self.context, uri, self._templateuri, **kwargs)
222       
223    def _populate(self, d, l):
224        for ident in l:
225            if ident == '*':
226                for (k, v) in self._get_star():
227                    d[k] = v
228            else:
229                d[ident] = getattr(self, ident)
230   
231    def _get_star(self):
232        if self.callables:
233            for key in self.callables:
234                yield (key, self.callables[key])
235        if self.template:
236            def get(key):
237                callable_ = self.template._get_def_callable(key)
238                return lambda *args, **kwargs:callable_(self.context, *args, **kwargs)
239            for k in self.template.module._exports:
240                yield (k, get(k))
241        if self._module:
242            def get(key):
243                callable_ = getattr(self._module, key)
244                return lambda *args, **kwargs:callable_(self.context, *args, **kwargs)
245            for k in dir(self._module):
246                if k[0] != '_':
247                    yield (k, get(k))
248                           
249    def __getattr__(self, key):
250        if self.callables and key in self.callables:
251            return self.callables[key]
252
253        if self.template and self.template.has_def(key):
254            callable_ = self.template._get_def_callable(key)
255            return lambda *args, **kwargs:callable_(self.context, *args, **kwargs)
256
257        if self._module and hasattr(self._module, key):
258            callable_ = getattr(self._module, key)
259            return lambda *args, **kwargs:callable_(self.context, *args, **kwargs)
260
261        if self.inherits is not None:
262            return getattr(self.inherits, key)
263        raise AttributeError("Namespace '%s' has no member '%s'" % (self.name, key))
264
265def supports_caller(func):
266    """apply a caller_stack compatibility decorator to a plain Python function."""
267    def wrap_stackframe(context,  *args, **kwargs):
268        context.caller_stack._push_frame()
269        try:
270            return func(context, *args, **kwargs)
271        finally:
272            context.caller_stack._pop_frame()
273    return wrap_stackframe
274       
275def capture(context, callable_, *args, **kwargs):
276    """execute the given template def, capturing the output into a buffer."""
277    if not callable(callable_):
278        raise exceptions.RuntimeException("capture() function expects a callable as its argument (i.e. capture(func, *args, **kwargs))")
279    context._push_buffer()
280    try:
281        callable_(*args, **kwargs)
282    finally:
283        buf = context._pop_buffer()
284    return buf.getvalue()
285
286def _decorate_toplevel(fn):
287    def decorate_render(render_fn):
288        def go(context, *args, **kw):
289            def y(*args, **kw):
290                return render_fn(context, *args, **kw)
291            return fn(y)(context, *args, **kw)
292        return go
293    return decorate_render
294   
295def _decorate_inline(context, fn):
296    def decorate_render(render_fn):
297        dec = fn(render_fn)
298        def go(*args, **kw):
299            return dec(context, *args, **kw)
300        return go
301    return decorate_render
302           
303def _include_file(context, uri, calling_uri, **kwargs):
304    """locate the template from the given uri and include it in the current output."""
305    template = _lookup_template(context, uri, calling_uri)
306    (callable_, ctx) = _populate_self_namespace(context._clean_inheritance_tokens(), template)
307    callable_(ctx, **_kwargs_for_callable(callable_, context._orig, **kwargs))
308       
309def _inherit_from(context, uri, calling_uri):
310    """called by the _inherit method in template modules to set up the inheritance chain at the start
311    of a template's execution."""
312    if uri is None:
313        return None
314    template = _lookup_template(context, uri, calling_uri)
315    self_ns = context['self']
316    ih = self_ns
317    while ih.inherits is not None:
318        ih = ih.inherits
319    lclcontext = context.locals_({'next':ih})
320    ih.inherits = Namespace("self:%s" % template.uri, lclcontext, template = template, populate_self=False)
321    context._data['parent'] = lclcontext._data['local'] = ih.inherits
322    callable_ = getattr(template.module, '_mako_inherit', None)
323    if callable_ is not None:
324        ret = callable_(template, lclcontext)
325        if ret:
326            return ret
327
328    gen_ns = getattr(template.module, '_mako_generate_namespaces', None)
329    if gen_ns is not None:
330        gen_ns(context)
331    return (template.callable_, lclcontext)
332
333def _lookup_template(context, uri, relativeto):
334    lookup = context._with_template.lookup
335    if lookup is None:
336        raise exceptions.TemplateLookupException("Template '%s' has no TemplateLookup associated" % context._with_template.uri)
337    uri = lookup.adjust_uri(uri, relativeto)
338    try:
339        return lookup.get_template(uri)
340    except exceptions.TopLevelLookupException, e:
341        raise exceptions.TemplateLookupException(str(e))
342
343def _populate_self_namespace(context, template, self_ns=None):
344    if self_ns is None:
345        self_ns = Namespace('self:%s' % template.uri, context, template=template, populate_self=False)
346    context._data['self'] = context._data['local'] = self_ns
347    if hasattr(template.module, '_mako_inherit'):
348        ret = template.module._mako_inherit(template, context)
349        if ret:
350            return ret
351    return (template.callable_, context)
352
353def _render(template, callable_, args, data, as_unicode=False):
354    """create a Context and return the string output of the given template and template callable."""
355
356    if as_unicode:
357        buf = util.FastEncodingBuffer(unicode=True)
358    elif template.output_encoding:
359        buf = util.FastEncodingBuffer(unicode=as_unicode, encoding=template.output_encoding, errors=template.encoding_errors)
360    else:
361        buf = util.StringIO()
362    context = Context(buf, **data)
363    context._with_template = template
364    _render_context(template, callable_, context, *args, **_kwargs_for_callable(callable_, data))
365    return context._pop_buffer().getvalue()
366
367def _kwargs_for_callable(callable_, data, **kwargs):
368    argspec = inspect.getargspec(callable_)
369    namedargs = argspec[0] + [v for v in argspec[1:3] if v is not None]
370    for arg in namedargs:
371        if arg != 'context' and arg in data and arg not in kwargs:
372            kwargs[arg] = data[arg]
373    return kwargs
374   
375def _render_context(tmpl, callable_, context, *args, **kwargs):
376    import mako.template as template
377    # create polymorphic 'self' namespace for this template with possibly updated context
378    if not isinstance(tmpl, template.DefTemplate):
379        # if main render method, call from the base of the inheritance stack
380        (inherit, lclcontext) = _populate_self_namespace(context, tmpl)
381        _exec_template(inherit, lclcontext, args=args, kwargs=kwargs)
382    else:
383        # otherwise, call the actual rendering method specified
384        (inherit, lclcontext) = _populate_self_namespace(context, tmpl.parent)
385        _exec_template(callable_, context, args=args, kwargs=kwargs)
386       
387def _exec_template(callable_, context, args=None, kwargs=None):
388    """execute a rendering callable given the callable, a Context, and optional explicit arguments
389
390    the contextual Template will be located if it exists, and the error handling options specified
391    on that Template will be interpreted here.
392    """
393    template = context._with_template
394    if template is not None and (template.format_exceptions or template.error_handler):
395        error = None
396        try:
397            callable_(context, *args, **kwargs)
398        except Exception, e:
399            error = e
400        except:               
401            e = sys.exc_info()[0]
402            error = e
403        if error:
404            if template.error_handler:
405                result = template.error_handler(context, error)
406                if not result:
407                    raise error
408            else:
409                error_template = exceptions.html_error_template()
410                context._buffer_stack[:] = [util.FastEncodingBuffer(error_template.output_encoding, error_template.encoding_errors)]
411                context._with_template = error_template
412                error_template.render_context(context, error=error)
413    else:
414        callable_(context, *args, **kwargs)
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。