问题
I use Jinja2 compiled templates and a module loader to load the compiled templates (python code) from the datastore. But when my template contains a macro it does not work on app engine: TypeError: 'NoneType' object is not callable
But in the app engine SDK it works fine. And when I skip the macro call, i receive the same error.
Without the macro it works fine. Without a solution for this macro problem, I call a python function in my template to implement the functionality of the macro.
Update: This is the template source code which results in an error:
{% extends "mainpage.html" %}
{% block form %}
{% macro test_macro(name) %}
<p>{{ name }}</p>
{% endmacro %}
<div>
{{ test_macro('John Doe') }}
</div>
{% endblock %}
And this is the compiled template code (the form block part):
def block_form(context, environment=environment):
if 0: yield None
yield u'\n'
def macro(l_name):
t_1 = []
pass
t_1.extend((
u'\n<p>',
to_string(l_name),
u'</p>\n',
))
return concat(t_1)
l_test_macro = Macro(environment, macro, 'test_macro', ('name',), (), False, False, False)
yield u'\n<div>\n\t%s\n</div>\n' % (
context.call(l_test_macro, 'John Doe'),
)
Update: After some debugging it worked. But I do understand it!!! The problem: I lose my imports. And when I redefine my imports in the code. It worked.
The top of the module:
from __future__ import division
from jinja2.runtime import LoopContext, TemplateReference, Macro, Markup, TemplateRuntimeError, missing, concat, escape, markup_join, unicode_join, to_string, identity, TemplateNotFound
__jinja_template__ = None
To make it work I had to add an inline import:
from jinja2.runtime import Macro # import again ?????
l_test_macro = Macro(environment, macro, 'test_macro', ('name',), (), False, False, False)
Can somebody explain, how I can lose my imports ??? I have this problem only in app engine and NOT in the SDK ??? Is this a namespace problem?
回答1:
I was able to solve it, by adding the module to the sys.modules. But I do not understand why it worked in the SDK and not in GAE when I use a macro
Here is the code of my changed module loader.
def get_module(self, environment, template):
# Convert the path to a module name
name = template.replace('.html', '').replace('.txt','').replace('/', '.') # NO extensions
module = None
if self.package == None : # load from db and not from package
logging.info('load module : ' + name) # load module from runtimes db
if name in sys.modules : return sys.modules[name] # already imported
try :
runtime = models.Runtimes.rtimes_get_by_key_name(template)
module_code = db.Text(runtime.compiled)
module = imp.new_module(name)
exec module_code in module.__dict__
sys.modules[name] = module # add to sys modules, so no import again
return module
except (ImportError, AttributeError):
logging.error('load failed : ' + name)
else : .... # load from package
raise TemplateNotFound(template)
来源:https://stackoverflow.com/questions/13485294/compiled-templates-with-macros-do-not-work-on-app-engine