Discussion:
[Mako] more verbose - exceptions.NameError: Undefined
Alexandre CONRAD
2007-05-24 13:49:25 UTC
Permalink
Hello,

exceptions.NameError: Undefined

Okay, this error has happend to me more than once (way more). I know
that this means something similar to "you're trying to access a variable
that has not yet been declared".
Luckly, I usually knew where it came from because it was obvious enough
to find the problem after some code change. But I've wasted so much time
trying to figure out where this came from.

Would it be possible to make it more verbose somehow ? Like showing the
original name of the variable and it's line number in the template
itself ? How am I supposed to know where this comes from with such a
traceback ?

So I digged into the code and modified it as followed to fit my needs.

-- mako/runtime.py --
class Undefined(object):
"""represents an undefined value in a template."""
def __init__(self, name, filename):
self.name = name
self.filename = filename
def __str__(self):
# raise NameError("Undefined")
raise NameError("Undefined name '%s' in file '%s'" %
(self.name, self.filename))
def __nonzero__(self):
return False

UNDEFINED = Undefined # Not initialized !
--------------------

-- mako/codegen.py around line 292 --
if getattr(self.compiler, 'has_ns_imports', False):
# self.printer.writeline("%s = _import_ns.get(%s,
context.get(%s, UNDEFINED))" % (ident, repr(ident), repr(ident)))
self.printer.writeline("%s = _import_ns.get(%s,
context.get(%s, UNDEFINED(%s, %s)))" % (ident, repr(ident), repr(ident),
repr(ident), repr(self.compiler.filename)))
else:
# self.printer.writeline("%s = context.get(%s,
UNDEFINED)" % (ident, repr(ident)))
self.printer.writeline("%s = context.get(%s,
UNDEFINED(%s, %s))" % (ident, repr(ident), repr(ident),
repr(self.compiler.filename)))
---------------

Same here for readability: http://rafb.net/p/0VKRMH87.html

${i_dont_exist} raises:

exceptions.NameError: Undefined name 'i_dont_exist' in file
'/path/to/erroneous/file.mako'

I couldn't figure out how to put the line number in here, but at least
this helps me _much_ more.

Anyway, my application seems to run fine like this but I suppose this
won't work as it will break the following (from mako documentation):

"""Since UNDEFINED is a singleton object just like Python's True or
False, you can use the is operator to check for it"""

Regards,
--
Alexandre CONRAD
Michael Bayer
2007-05-24 15:25:41 UTC
Permalink
Post by Alexandre CONRAD
Hello,
exceptions.NameError: Undefined
Okay, this error has happend to me more than once (way more). I know
that this means something similar to "you're trying to access a variable
that has not yet been declared".
Luckly, I usually knew where it came from because it was obvious enough
to find the problem after some code change. But I've wasted so much time
trying to figure out where this came from.
Would it be possible to make it more verbose somehow ? Like showing the
original name of the variable and it's line number in the template
itself ? How am I supposed to know where this comes from with such a
traceback ?
Python itself has the same issue if you pass None somewhere and later
on someone tries to access an attribute off of it (as does javascript
with undefineds).
Post by Alexandre CONRAD
So I digged into the code and modified it as followed to fit my needs.
-- mako/runtime.py --
"""represents an undefined value in a template."""
self.name = name
self.filename = filename
# raise NameError("Undefined")
raise NameError("Undefined name '%s' in file '%s'" %
(self.name, self.filename))
return False
UNDEFINED = Undefined # Not initialized !
--------------------
-- mako/codegen.py around line 292 --
# self.printer.writeline("%s = _import_ns.get(%s,
context.get(%s, UNDEFINED))" % (ident, repr(ident), repr(ident)))
self.printer.writeline("%s = _import_ns.get(%s,
context.get(%s, UNDEFINED(%s, %s)))" % (ident, repr(ident), repr
(ident),
repr(ident), repr(self.compiler.filename)))
# self.printer.writeline("%s = context.get(%s,
UNDEFINED)" % (ident, repr(ident)))
self.printer.writeline("%s = context.get(%s,
UNDEFINED(%s, %s))" % (ident, repr(ident), repr(ident),
repr(self.compiler.filename)))
---------------
yeah but that breaks:

if x is UNDEFINED:
foo

also is a slight performance hit.

I would rather add a template compiler option that disables the usage
of UNDEFINED in the first place - any variable you reference in the
template has to exist or you get the error immediately. or
UNDEFINED doesnt raise an error on __str__(), it just prints
"undefined".
Alexandre CONRAD
2007-05-24 16:37:48 UTC
Permalink
Post by Michael Bayer
I would rather add a template compiler option that disables the usage
of UNDEFINED in the first place - any variable you reference in the
template has to exist or you get the error immediately. or
UNDEFINED doesnt raise an error on __str__(), it just prints
"undefined".
I thought about having such an option for mako, to raise the exception
right away.

For me a template is just like a python function to which you can pass
args and so on. A Python programmer has enough tools to test and deal
with undefined variables. Like setting defaults values for example.

I'm not a template expert and I probably don't have enough templating
experience, but I don't really understand the need of replacing missing
variables with UNDEFINED. I *could* imagine it would be handy in some
situations, but that's clearly not something that I'd want and I'd want
to be informed about that missing variable. This happens implicitly,
which is not pythonic.

Any concrete example where the usage of UNDEFINED would make sens ?

Regards,
--
Alexandre CONRAD
Michael Bayer
2007-05-24 17:18:07 UTC
Permalink
Post by Alexandre CONRAD
I'm not a template expert and I probably don't have enough templating
experience, but I don't really understand the need of replacing missing
variables with UNDEFINED. I *could* imagine it would be handy in some
situations, but that's clearly not something that I'd want and I'd want
to be informed about that missing variable. This happens implicitly,
which is not pythonic.
what would they be replaced with ? you want just an immediate error ?
Post by Alexandre CONRAD
Any concrete example where the usage of UNDEFINED would make sens ?
anywhere youd use **kwargs in python for optional keyword arguments.
Alexandre CONRAD
2007-05-28 11:27:34 UTC
Permalink
Post by Michael Bayer
Post by Alexandre CONRAD
I'm not a template expert and I probably don't have enough templating
experience, but I don't really understand the need of replacing missing
variables with UNDEFINED. I *could* imagine it would be handy in some
situations, but that's clearly not something that I'd want and I'd want
to be informed about that missing variable. This happens implicitly,
which is not pythonic.
what would they be replaced with ? you want just an immediate error ?
Yes. At least that's my POV.
Post by Michael Bayer
Post by Alexandre CONRAD
Any concrete example where the usage of UNDEFINED would make sens ?
anywhere youd use **kwargs in python for optional keyword arguments.
You could just test before calling the variable:

% if foo in kwargs:
...
% endif

Again, I think python is agile enough to let the programmer test these
kinds of things. Mako adds this extra UNDEFINED object, which I think
python doesn't lack of.

So I hardly see the motivation of UNDEFINED, but again, I may not have
the skills of a template expert and there may be situation where it
would be useful. I'm arguing about something I'm not even using, so I
could just leave it aside. It's just that it's makes the traceback
useless about what's missing for your template.

Regards,
--
Alexandre CONRAD
Michael Bayer
2007-05-28 20:28:32 UTC
Permalink
Post by Alexandre CONRAD
Post by Michael Bayer
Post by Alexandre CONRAD
I'm not a template expert and I probably don't have enough
templating
experience, but I don't really understand the need of replacing missing
variables with UNDEFINED. I *could* imagine it would be handy in some
situations, but that's clearly not something that I'd want and I'd want
to be informed about that missing variable. This happens implicitly,
which is not pythonic.
what would they be replaced with ? you want just an immediate error ?
Yes. At least that's my POV.
well with a system like Django, which I did want to have some
emulation of considering its "guido's favorite template language",
would never throw an error for this case, at least is my
understanding. it just silently prints a blank string.
Post by Alexandre CONRAD
Post by Michael Bayer
Post by Alexandre CONRAD
Any concrete example where the usage of UNDEFINED would make sens ?
anywhere youd use **kwargs in python for optional keyword arguments.
...
% endif
Again, I think python is agile enough to let the programmer test these
kinds of things. Mako adds this extra UNDEFINED object, which I think
python doesn't lack of.
well then again Python also doesnt have "magically available
variables" either the way Mako does. if we were totally Python, youd
just have to pull everything yourself from "context". If you used
context explicitly for everything, you'd never see an UNDEFINED
anywhere. Id almost rather make an option, "dont pull anything from
context automatically". which is more severe but then eliminates all
the decisions mako has made in this area.
Post by Alexandre CONRAD
So I hardly see the motivation of UNDEFINED, but again, I may not have
the skills of a template expert and there may be situation where it
would be useful. I'm arguing about something I'm not even using, so I
could just leave it aside. It's just that it's makes the traceback
useless about what's missing for your template.
well i dont see it as *too* different from any other python
application where a None gets passed all the way through to something
that suddenly cant work with it. Ive noticed Makos stack trace
conversion utility doesnt track lines 100% perfectly so may thats
whats making the stack trace difficult for you, or your framework
isnt even using the tracing utility in the first place, in which case
any runtime stack trace is a total inconvenience.
Alexandre CONRAD
2007-05-29 10:17:31 UTC
Permalink
Post by Michael Bayer
Post by Alexandre CONRAD
Post by Michael Bayer
what would they be replaced with ? you want just an immediate error ?
Yes. At least that's my POV.
well with a system like Django, which I did want to have some
emulation of considering its "guido's favorite template language",
would never throw an error for this case, at least is my
understanding. it just silently prints a blank string.
Which is probably not we're looking for, for explicitness.
Post by Michael Bayer
Post by Alexandre CONRAD
Again, I think python is agile enough to let the programmer test these
kinds of things. Mako adds this extra UNDEFINED object, which I think
python doesn't lack of.
well then again Python also doesnt have "magically available
variables" either the way Mako does. if we were totally Python, youd
just have to pull everything yourself from "context". If you used
context explicitly for everything, you'd never see an UNDEFINED
anywhere. Id almost rather make an option, "dont pull anything from
context automatically". which is more severe but then eliminates all
the decisions mako has made in this area.
We want to keep Mako naturally close to Python to make the
learning/adaptation curve gentle. But it is still a different language.
And having to pull everything from "context" would be a pain that Mako
handles for us, which is good.
Post by Michael Bayer
Post by Alexandre CONRAD
So I hardly see the motivation of UNDEFINED, but again, I may not have
the skills of a template expert and there may be situation where it
would be useful. I'm arguing about something I'm not even using, so I
could just leave it aside. It's just that it's makes the traceback
useless about what's missing for your template.
well i dont see it as *too* different from any other python
application where a None gets passed all the way through to something
that suddenly cant work with it. Ive noticed Makos stack trace
conversion utility doesnt track lines 100% perfectly so may thats
whats making the stack trace difficult for you, or your framework
isnt even using the tracing utility in the first place, in which case
any runtime stack trace is a total inconvenience.
Well, the hardest to debug is when one of your variables is UNDEFINED
and that variable is sent to a function like the Pylons' WebHelpers
(HTML code gen) and then crashes because it hits the var's __str__. It's
now lost into some code you have not written yourself:

File '<string>', line 1 in <lambda>
File '/var/www/html/dev/tlv/mp/mp/lib/base.py', line 24 in wrapper
return check(func, *args, **kwargs)
File '/var/www/html/dev/tlv/mp/mp/lib/base.py', line 20 in check
return func(*args, **kwargs)
File '/var/www/html/dev/tlv/mp/mp/controllers/clients.py', line 17 in index
return render_response("browser/tab_%s.mako" % c.tab_name)
File
'/usr/lib/python2.4/site-packages/Pylons-0.9.5-py2.4.egg/pylons/templating.py',
line 314 in render_response
response = pylons.Response(render(*args, **kargs))
File
'/usr/lib/python2.4/site-packages/Pylons-0.9.5-py2.4.egg/pylons/templating.py',
line 300 in render
format=format, namespace=kargs, **cache_args)
File
'/usr/lib/python2.4/site-packages/Pylons-0.9.5-py2.4.egg/pylons/templating.py',
line 206 in render
return engine_config['engine'].render(namespace, template=full_path,
File
'/usr/lib/python2.4/site-packages/Mako-0.1.6dev_r273-py2.4.egg/mako/ext/turbogears.py',
line 43 in render
return template.render(**info)
File
'/usr/lib/python2.4/site-packages/Mako-0.1.6dev_r273-py2.4.egg/mako/template.py',
line 110 in render
return runtime._render(self, self.callable_, args, data)
File
'/usr/lib/python2.4/site-packages/Mako-0.1.6dev_r273-py2.4.egg/mako/runtime.py',
line 287 in _render
_render_context(template, callable_, context, *args,
**_kwargs_for_callable(callable_, data))
File
'/usr/lib/python2.4/site-packages/Mako-0.1.6dev_r273-py2.4.egg/mako/runtime.py',
line 304 in _render_context
_exec_template(inherit, lclcontext, args=args, kwargs=kwargs)
File
'/usr/lib/python2.4/site-packages/Mako-0.1.6dev_r273-py2.4.egg/mako/runtime.py',
line 337 in _exec_template
callable_(context, *args, **kwargs)
File '/var/www/html/dev/tlv/mp/data/templates/base.mako.py', line 44 in
render_body
context.write(unicode(next.body()))
File
'/usr/lib/python2.4/site-packages/Mako-0.1.6dev_r273-py2.4.egg/mako/runtime.py',
line 193 in <lambda>
return lambda *args, **kwargs:callable_(self.context, *args, **kwargs)
File '/var/www/html/dev/tlv/mp/data/templates/browser/base.mako.py',
line 31 in render_body
context.write(unicode(next.body()))
File
'/usr/lib/python2.4/site-packages/Mako-0.1.6dev_r273-py2.4.egg/mako/runtime.py',
line 193 in <lambda>
return lambda *args, **kwargs:callable_(self.context, *args, **kwargs)
File '/var/www/html/dev/tlv/mp/data/templates/browser/index.mako.py',
line 34 in render_body
context.write(unicode(next.body()))
File
'/usr/lib/python2.4/site-packages/Mako-0.1.6dev_r273-py2.4.egg/mako/runtime.py',
line 193 in <lambda>
return lambda *args, **kwargs:callable_(self.context, *args, **kwargs)
File
'/var/www/html/dev/tlv/mp/data/templates/browser/tab_clients.mako.py',
line 37 in render_body
runtime._include_file(context, u'client/list.mako', _template_uri)
File
'/usr/lib/python2.4/site-packages/Mako-0.1.6dev_r273-py2.4.egg/mako/runtime.py',
line 231 in _include_file
callable_(ctx, **_kwargs_for_callable(callable_, context._data,
**kwargs))
File
'/var/www/html/dev/tlv/mp/data/templates/browser/client/list.mako.py',
line 47 in render_body
method='get'))))
File
'/usr/lib/python2.4/site-packages/WebHelpers-0.3-py2.4.egg/webhelpers/rails/prototype.py',
line 141 in link_to_remote
return link_to_function(name, remote_function(**options), **html_options)
File
'/usr/lib/python2.4/site-packages/WebHelpers-0.3-py2.4.egg/webhelpers/rails/javascript.py',
line 30 in link_to_function
return content_tag("a", name, **options)
File
'/usr/lib/python2.4/site-packages/WebHelpers-0.3-py2.4.egg/webhelpers/rails/tags.py',
line 66 in content_tag
tag = '<%s%s>%s</%s>' % (name, (options and tag_options(**options))
or '', content, name)
File
'/usr/lib/python2.4/site-packages/Mako-0.1.6dev_r273-py2.4.egg/mako/runtime.py',
line 91 in __str__
raise NameError("Undefined")
NameError: Undefined

That's why I think raising a immediate error would help, and as you
said, it could be passed as an option to Mako.

Regards,
--
Alexandre CONRAD
Michael Bayer
2007-05-29 21:33:03 UTC
Permalink
Post by Alexandre CONRAD
Well, the hardest to debug is when one of your variables is UNDEFINED
and that variable is sent to a function like the Pylons' WebHelpers
(HTML code gen) and then crashes because it hits the var's __str__. It's
File
'/var/www/html/dev/tlv/mp/data/templates/browser/tab_clients.mako.py',
line 37 in render_body
runtime._include_file(context, u'client/list.mako', _template_uri)
File
File
'/var/www/html/dev/tlv/mp/data/templates/browser/client/list.mako.py',
line 47 in render_body
method='get'))))
File
this is what im getting at: youre not making usage of Mako's
exception reporting utiltiies, and id rather TG integrate those.
then you would not see the mako generated files in your stack trace,
youd see your template:

http://www.makotemplates.org/docs/usage.html#usage_handling

Loading...