Skip to content

Commit

Permalink
- added "attr" accessor to namespaces. Returns attributes
Browse files Browse the repository at this point in the history
  configured as module level attributes, i.e. within
  <%! %> sections [ticket:62]
- removed reliance upon KeyError/AttributeError in namespace.__getattr__
  • Loading branch information
zzzeek committed Feb 15, 2008
1 parent 443f18c commit 5cfffa2
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 21 deletions.
3 changes: 3 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
0.2.0
- added "attr" accessor to namespaces. Returns attributes
configured as module level attributes, i.e. within
<%! %> sections [ticket:62]
- fixed bug in python generation when variable names are used
with identifiers like "else", "finally", etc. inside them
[ticket:68]
Expand Down
53 changes: 32 additions & 21 deletions lib/mako/runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,17 @@ def __nonzero__(self):

UNDEFINED = Undefined()

class _NSAttr(object):
def __init__(self, parent):
self.__parent = parent
def __getattr__(self, key):
ns = self.__parent
while ns:
if hasattr(ns.module, key):
return getattr(ns.module, key)
else:
ns = ns.inherits
raise AttributeError(key)

class Namespace(object):
"""provides access to collections of rendering methods, which can be local, from other templates, or from imported modules"""
Expand Down Expand Up @@ -121,11 +132,17 @@ def __init__(self, name, context, module=None, template=None, templateuri=None,
self.callables = None
if populate_self and self.template is not None:
(lclcallable, lclcontext) = _populate_self_namespace(context, self.template, self_ns=self)

module = property(lambda s:s._module or s.template.module)
filename = property(lambda s:s._module and s._module.__file__ or s.template.filename)
uri = property(lambda s:s.template.uri)

def attr(self):
if not hasattr(self, '_attr'):
self._attr = _NSAttr(self)
return self._attr
attr = property(attr)

def get_namespace(self, uri):
"""return a namespace corresponding to the given template uri.
Expand Down Expand Up @@ -164,16 +181,16 @@ def _populate(self, d, l):
d[ident] = getattr(self, ident)

def _get_star(self):
if self.callables is not None:
if self.callables:
for key in self.callables:
yield (key, self.callables[key])
if self.template is not None:
if self.template:
def get(key):
callable_ = self.template.get_def(key).callable_
return lambda *args, **kwargs:callable_(self.context, *args, **kwargs)
for k in self.template.module._exports:
yield (k, get(k))
if self._module is not None:
if self._module:
def get(key):
callable_ = getattr(self._module, key)
return lambda *args, **kwargs:callable_(self.context, *args, **kwargs)
Expand All @@ -182,23 +199,17 @@ def get(key):
yield (k, get(k))

def __getattr__(self, key):
if self.callables is not None:
try:
return self.callables[key]
except KeyError:
pass
if self.template is not None:
try:
callable_ = self.template.get_def(key).callable_
return lambda *args, **kwargs:callable_(self.context, *args, **kwargs)
except AttributeError:
pass
if self._module is not None:
try:
callable_ = getattr(self._module, key)
return lambda *args, **kwargs:callable_(self.context, *args, **kwargs)
except AttributeError:
pass
if self.callables and key in self.callables:
return self.callables[key]

if self.template and self.template.has_def(key):
callable_ = self.template.get_def(key).callable_
return lambda *args, **kwargs:callable_(self.context, *args, **kwargs)

if self._module and hasattr(self._module, key):
callable_ = getattr(self._module, key)
return lambda *args, **kwargs:callable_(self.context, *args, **kwargs)

if self.inherits is not None:
return getattr(self.inherits, key)
raise exceptions.RuntimeException("Namespace '%s' has no member '%s'" % (self.name, key))
Expand Down
3 changes: 3 additions & 0 deletions lib/mako/template.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,9 @@ def render_context(self, context, *args, **kwargs):
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 an individual Template of its own."""
Expand Down
36 changes: 36 additions & 0 deletions test/namespace.py
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,42 @@ def test_inheritance_two(self):
""")

assert result_lines(collection.get_template("front.html").render()) == ['lib.bar', 'base.foo', 'lib.foo', 'base.bat', 'base.bat']

def test_attr(self):
l = lookup.TemplateLookup()

l.put_string("foo.html", """
<%!
foofoo = "foo foo"
onlyfoo = "only foo"
%>
<%inherit file="base.html"/>
${self.attr.basefoo}
${self.attr.foofoo}
${self.attr.onlyfoo}
""")

l.put_string("base.html", """
<%!
basefoo = "base foo 1"
foofoo = "base foo 2"
%>
${self.attr.basefoo}
${self.attr.foofoo}
${self.attr.onlyfoo}
body
${self.body()}
""")

assert result_lines(l.get_template("foo.html").render()) == [
"base foo 1",
"foo foo",
"only foo",
"body",
"base foo 1",
"foo foo",
"only foo",
]

def test_ccall(self):
collection = lookup.TemplateLookup()
Expand Down

0 comments on commit 5cfffa2

Please sign in to comment.