Conflict between arguments and local variables

9 views
Skip to first unread message

Joe

unread,
Feb 23, 2007, 10:56:38 PM2/23/07
to mako-d...@googlegroups.com
Hi,

I was getting the following error:

File "/tmp/mako/topic.html.py", line 48, in render_body
if categs[m].id != topic.categ:
UnboundLocalError: local variable 'topic' referenced before assignment

This was confusing because 'topic' is a class variable passed as an
argument to the template render() function and I wouldn't get the error
if I isolated the code to that % if section.

It turned out that after the line above there was a segment like this,
all of it in the same template scope:

% for i, (url, topic, title) in enumerate(breadcrumbs):
<a href="${site.href(topic, url)}">${title}</a>
% endfor

When I renamed this local variable, the UnboundLocalError went away.
The code was translated more or less mechanically from a Genshi template
which did not have an issue with the names.

When I looked at topic.html.py, I saw that the render_body() was doing
context.get('varname', UNDEFINED) for each variable used in the
template, but not for 'topic'. Presumably this is because the local
variable was obscuring the passed in argument. I don't know if this is
a Mako "feature" or something that could be improved with better
parsing, but it would be helpful to have a less confusing error, or
failing that, I recommend this be added to the documentation or an FAQ
of Mako gotchas.

Joe

Michael Bayer

unread,
Feb 24, 2007, 2:20:14 PM2/24/07
to mako-d...@googlegroups.com

its intentional; context variables are like "globals" - if you assign
to a variable inside a block (which all templates and defs are), it
automatically assumes local scope, and will not pull the variable
from the context automatically. during mako's development, we werent
necessarily going to do it this way, but it turned out that there
were some conditions where arbitrary context variables could
"pollute" the meaning of code within blocks (which means, code that
works with framework A would suddenly break with framework B that had
conflicting context variables), so sticking to python's tried-and-
true methodologies proved to be important.

heres the python equivalent:

foo = "hi"

def dosomething():
print foo
for foo in [1,2,3]:
print "foo:", foo

dosomething()

this is in the documentation, although it could use a more explicit
"what does this really mean": http://www.makotemplates.org/docs/
runtime.html#runtime_context_variables

"One of the first things that happens within these functions is that
all variable names that are referenced within the function which are
not defined in some other way (i.e. such as via assignment, module
level imports, etc.) are pulled from the Context object's dictionary
of variables. "

to get at context variables that are being masked in this way, just
pull them from the context explicitly (described in the following
section).


Reply all
Reply to author
Forward
0 new messages