From: Armin Ronacher Date: Tue, 8 Apr 2008 16:49:56 +0000 (+0200) Subject: updated macro stuff X-Git-Tag: 2.0rc1~206^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9706fabba85539bf0a368828a8ac47305036ed38;p=thirdparty%2Fjinja.git updated macro stuff --HG-- branch : trunk --- diff --git a/jinja2/compiler.py b/jinja2/compiler.py index 5c64699d..bdf195f1 100644 --- a/jinja2/compiler.py +++ b/jinja2/compiler.py @@ -381,7 +381,7 @@ class CodeGenerator(NodeVisitor): for arg in node.defaults: self.visit(arg) self.write(', ') - self.write('), %r)' % accesses_arguments) + self.write('), %r, make_undefined)' % accesses_arguments) def visit_ExprStmt(self, node, frame): self.newline(node) @@ -447,6 +447,8 @@ class CodeGenerator(NodeVisitor): self.visit(node.target, assignment_frame) self.write(' = ') self.visit(node.node, frame) + + # make sure toplevel assignments are added to the context. if frame.toplevel: for name in assignment_frame.assigned_names: self.writeline('context[%r] = l_%s' % (name, name)) diff --git a/jinja2/runtime.py b/jinja2/runtime.py index 7af5c4ab..c1c34e18 100644 --- a/jinja2/runtime.py +++ b/jinja2/runtime.py @@ -14,7 +14,7 @@ except ImportError: defaultdict = None -__all__ = ['extends', 'subscribe', 'TemplateContext'] +__all__ = ['extends', 'subscribe', 'TemplateContext', 'Macro'] def extends(template, namespace): @@ -33,44 +33,79 @@ def subscribe(obj, argument, undefined_factory): class TemplateContext(dict): + """ + Holds the variables of the local template or of the global one. It's + not save to use this class outside of the compiled code. For example + update and other methods will not work as they seem (they don't update + the exported variables for example). + """ def __init__(self, globals, undefined_factory, filename): - dict.__init__(self) - self.globals = globals + dict.__init__(self, globals) + self.exported = set() self.undefined_factory = undefined_factory self.filename = filename self.filters = {} self.tests = {} + def __setitem__(self, key, value): + """If we set items to the dict we track the variables set so + that includes can access the exported variables.""" + dict.__setitem__(self, key, value) + self.exported.add(key) + + def __delitem__(self, key): + """On delete we no longer export it.""" + dict.__delitem__(self, key) + self.exported.dicard(key) + + def get_exported(self): + """Get a dict of all exported variables.""" + return dict((k, self[k]) for k in self.exported) + # if there is a default dict, dict has a __missing__ method we can use. if defaultdict is None: def __getitem__(self, name): if name in self: return self[name] - elif name in self.globals: - return self.globals[name] return self.undefined_factory(name) else: def __missing__(self, key): - try: - return self.globals[key] - except: - return self.undefined_factory(key) + return self.undefined_factory(key) class Macro(object): + """ + Wraps a macor + """ - def __init__(self, func, name, arguments, defaults, catch_all): + def __init__(self, func, name, arguments, defaults, catch_all, \ + undefined_factory): self.func = func self.name = name self.arguments = arguments self.defaults = defaults self.catch_all = catch_all + self.undefined_factory = undefined_factory def __call__(self, *args, **kwargs): - if len(args) > len(self.arguments): + arg_count = len(self.arguments) + if len(args) > arg_count: raise TypeError('macro %r takes not more than %d argument(s).' % (self.name, len(self.arguments))) arguments = {} - # XXX: assemble arguments - return u''.join(self.func(*args, **kwargs)) + for idx, name in enumerate(self.arguments): + try: + value = args[idx] + except IndexError: + try: + value = kwargs.pop(name) + except KeyError: + try: + value = self.defaults[idx - arg_count] + except IndexError: + value = self.undefined_factory(name) + arguments['l_' + name] = arg + if self.catch_all: + arguments['l_arguments'] = kwargs + return u''.join(self.func(**arguments))