diff options
Diffstat (limited to 'mako/codegen.py')
-rw-r--r-- | mako/codegen.py | 448 |
1 files changed, 232 insertions, 216 deletions
diff --git a/mako/codegen.py b/mako/codegen.py index 3c0bad4..bf86d79 100644 --- a/mako/codegen.py +++ b/mako/codegen.py @@ -22,20 +22,20 @@ MAGIC_NUMBER = 10 TOPLEVEL_DECLARED = set(["UNDEFINED", "STOP_RENDERING"]) RESERVED_NAMES = set(['context', 'loop']).union(TOPLEVEL_DECLARED) -def compile(node, - uri, - filename=None, - default_filters=None, - buffer_filters=None, - imports=None, - future_imports=None, - source_encoding=None, - generate_magic_comment=True, - disable_unicode=False, - strict_undefined=False, - enable_loop=True, - reserved_names=frozenset()): +def compile(node, + uri, + filename=None, + default_filters=None, + buffer_filters=None, + imports=None, + future_imports=None, + source_encoding=None, + generate_magic_comment=True, + disable_unicode=False, + strict_undefined=False, + enable_loop=True, + reserved_names=frozenset()): """Generate module source code given a parsetree node, uri, and optional source filename""" @@ -46,40 +46,41 @@ def compile(node, if not compat.py3k and isinstance(source_encoding, compat.text_type): source_encoding = source_encoding.encode(source_encoding) - buf = util.FastEncodingBuffer() printer = PythonPrinter(buf) _GenerateRenderMethod(printer, - _CompileContext(uri, - filename, - default_filters, - buffer_filters, - imports, - future_imports, - source_encoding, - generate_magic_comment, - disable_unicode, - strict_undefined, - enable_loop, - reserved_names), - node) + _CompileContext(uri, + filename, + default_filters, + buffer_filters, + imports, + future_imports, + source_encoding, + generate_magic_comment, + disable_unicode, + strict_undefined, + enable_loop, + reserved_names), + node) return buf.getvalue() + class _CompileContext(object): + def __init__(self, - uri, - filename, - default_filters, - buffer_filters, - imports, - future_imports, - source_encoding, - generate_magic_comment, - disable_unicode, - strict_undefined, - enable_loop, - reserved_names): + uri, + filename, + default_filters, + buffer_filters, + imports, + future_imports, + source_encoding, + generate_magic_comment, + disable_unicode, + strict_undefined, + enable_loop, + reserved_names): self.uri = uri self.filename = filename self.default_filters = default_filters @@ -93,11 +94,14 @@ class _CompileContext(object): self.enable_loop = enable_loop self.reserved_names = reserved_names + class _GenerateRenderMethod(object): + """A template visitor object which generates the full module source for a template. """ + def __init__(self, printer, compiler, node): self.printer = printer self.compiler = compiler @@ -125,9 +129,9 @@ class _GenerateRenderMethod(object): args += ['**pageargs'] cached = eval(pagetag.attributes.get('cached', 'False')) self.compiler.enable_loop = self.compiler.enable_loop or eval( - pagetag.attributes.get( - 'enable_loop', 'False') - ) + pagetag.attributes.get( + 'enable_loop', 'False') + ) else: args = ['**pageargs'] cached = False @@ -138,9 +142,9 @@ class _GenerateRenderMethod(object): args = [a for a in ['context'] + args] self.write_render_callable( - pagetag or node, - name, args, - buffered, filtered, cached) + pagetag or node, + name, args, + buffered, filtered, cached) if defs is not None: for node in defs: @@ -151,7 +155,7 @@ class _GenerateRenderMethod(object): def write_metadata_struct(self): self.printer.source_map[self.printer.lineno] = \ - max(self.printer.source_map) + max(self.printer.source_map) struct = { "filename": self.compiler.filename, "uri": self.compiler.uri, @@ -182,12 +186,16 @@ class _GenerateRenderMethod(object): self.compiler.pagetag = None class FindTopLevel(object): + def visitInheritTag(s, node): inherit.append(node) + def visitNamespaceTag(s, node): namespaces[node.name] = node + def visitPageTag(s, node): self.compiler.pagetag = node + def visitCode(s, node): if node.ismodule: module_code.append(node) @@ -209,7 +217,7 @@ class _GenerateRenderMethod(object): if self.compiler.generate_magic_comment and \ self.compiler.source_encoding: self.printer.writeline("# -*- coding:%s -*-" % - self.compiler.source_encoding) + self.compiler.source_encoding) if self.compiler.future_imports: self.printer.writeline("from __future__ import %s" % @@ -223,36 +231,36 @@ class _GenerateRenderMethod(object): self.printer.writeline("_modified_time = %r" % time.time()) self.printer.writeline("_enable_loop = %r" % self.compiler.enable_loop) self.printer.writeline( - "_template_filename = %r" % self.compiler.filename) + "_template_filename = %r" % self.compiler.filename) self.printer.writeline("_template_uri = %r" % self.compiler.uri) self.printer.writeline( - "_source_encoding = %r" % self.compiler.source_encoding) + "_source_encoding = %r" % self.compiler.source_encoding) if self.compiler.imports: buf = '' for imp in self.compiler.imports: buf += imp + "\n" self.printer.writeline(imp) impcode = ast.PythonCode( - buf, - source='', lineno=0, - pos=0, - filename='template defined imports') + buf, + source='', lineno=0, + pos=0, + filename='template defined imports') else: impcode = None main_identifiers = module_identifiers.branch(self.node) module_identifiers.topleveldefs = \ module_identifiers.topleveldefs.\ - union(main_identifiers.topleveldefs) + union(main_identifiers.topleveldefs) module_identifiers.declared.update(TOPLEVEL_DECLARED) if impcode: module_identifiers.declared.update(impcode.declared_identifiers) self.compiler.identifiers = module_identifiers self.printer.writeline("_exports = %r" % - [n.name for n in - main_identifiers.topleveldefs.values()] - ) + [n.name for n in + main_identifiers.topleveldefs.values()] + ) self.printer.write_blanks(2) if len(module_code): @@ -267,7 +275,7 @@ class _GenerateRenderMethod(object): return list(main_identifiers.topleveldefs.values()) def write_render_callable(self, node, name, args, buffered, filtered, - cached): + cached): """write a top-level render callable. this could be the main render() method or that of a top-level def.""" @@ -276,30 +284,30 @@ class _GenerateRenderMethod(object): decorator = node.decorator if decorator: self.printer.writeline( - "@runtime._decorate_toplevel(%s)" % decorator) + "@runtime._decorate_toplevel(%s)" % decorator) self.printer.start_source(node.lineno) self.printer.writelines( "def %s(%s):" % (name, ','.join(args)), - # push new frame, assign current frame to __M_caller - "__M_caller = context.caller_stack._push_frame()", - "try:" + # push new frame, assign current frame to __M_caller + "__M_caller = context.caller_stack._push_frame()", + "try:" ) if buffered or filtered or cached: self.printer.writeline("context._push_buffer()") self.identifier_stack.append( - self.compiler.identifiers.branch(self.node)) + self.compiler.identifiers.branch(self.node)) if (not self.in_def or self.node.is_block) and '**pageargs' in args: self.identifier_stack[-1].argument_declared.add('pageargs') if not self.in_def and ( - len(self.identifiers.locally_assigned) > 0 or - len(self.identifiers.argument_declared) > 0 - ): + len(self.identifiers.locally_assigned) > 0 or + len(self.identifiers.argument_declared) > 0 + ): self.printer.writeline("__M_locals = __M_dict_builtin(%s)" % - ','.join([ - "%s=%s" % (x, x) for x in + ','.join([ + "%s=%s" % (x, x) for x in self.identifiers.argument_declared ])) @@ -313,9 +321,9 @@ class _GenerateRenderMethod(object): self.printer.write_blanks(2) if cached: self.write_cache_decorator( - node, name, - args, buffered, - self.identifiers, toplevel=True) + node, name, + args, buffered, + self.identifiers, toplevel=True) def write_module_code(self, module_code): """write module-level template code, i.e. that which @@ -329,26 +337,25 @@ class _GenerateRenderMethod(object): self.printer.writelines( "def _mako_inherit(template, context):", - "_mako_generate_namespaces(context)", - "return runtime._inherit_from(context, %s, _template_uri)" % - (node.parsed_attributes['file']), - None + "_mako_generate_namespaces(context)", + "return runtime._inherit_from(context, %s, _template_uri)" % + (node.parsed_attributes['file']), + None ) def write_namespaces(self, namespaces): """write the module-level namespace-generating callable.""" self.printer.writelines( "def _mako_get_namespace(context, name):", - "try:", - "return context.namespaces[(__name__, name)]", - "except KeyError:", - "_mako_generate_namespaces(context)", - "return context.namespaces[(__name__, name)]", + "try:", + "return context.namespaces[(__name__, name)]", + "except KeyError:", + "_mako_generate_namespaces(context)", + "return context.namespaces[(__name__, name)]", None, None ) self.printer.writeline("def _mako_generate_namespaces(context):") - for node in namespaces.values(): if 'import' in node.attributes: self.compiler.has_ns_imports = True @@ -358,7 +365,9 @@ class _GenerateRenderMethod(object): export = [] identifiers = self.compiler.identifiers.branch(node) self.in_def = True + class NSDefVisitor(object): + def visitDefTag(s, node): s.visitDefOrBase(node) @@ -386,39 +395,39 @@ class _GenerateRenderMethod(object): if 'file' in node.parsed_attributes: self.printer.writeline( - "ns = runtime.TemplateNamespace(%r," - " context._clean_inheritance_tokens()," - " templateuri=%s, callables=%s, " - " calling_uri=_template_uri)" % - ( - node.name, - node.parsed_attributes.get('file', 'None'), - callable_name, - ) - ) + "ns = runtime.TemplateNamespace(%r," + " context._clean_inheritance_tokens()," + " templateuri=%s, callables=%s, " + " calling_uri=_template_uri)" % + ( + node.name, + node.parsed_attributes.get('file', 'None'), + callable_name, + ) + ) elif 'module' in node.parsed_attributes: self.printer.writeline( - "ns = runtime.ModuleNamespace(%r," - " context._clean_inheritance_tokens()," - " callables=%s, calling_uri=_template_uri," - " module=%s)" % - ( - node.name, - callable_name, - node.parsed_attributes.get( - 'module', 'None') - ) - ) + "ns = runtime.ModuleNamespace(%r," + " context._clean_inheritance_tokens()," + " callables=%s, calling_uri=_template_uri," + " module=%s)" % + ( + node.name, + callable_name, + node.parsed_attributes.get( + 'module', 'None') + ) + ) else: self.printer.writeline( - "ns = runtime.Namespace(%r," - " context._clean_inheritance_tokens()," - " callables=%s, calling_uri=_template_uri)" % - ( - node.name, - callable_name, - ) - ) + "ns = runtime.Namespace(%r," + " context._clean_inheritance_tokens()," + " callables=%s, calling_uri=_template_uri)" % + ( + node.name, + callable_name, + ) + ) if eval(node.attributes.get('inheritable', "False")): self.printer.writeline("context['self'].%s = ns" % (node.name)) @@ -459,7 +468,7 @@ class _GenerateRenderMethod(object): # write closure functions for closures that we define # right here to_write = to_write.union( - [c.funcname for c in identifiers.closuredefs.values()]) + [c.funcname for c in identifiers.closuredefs.values()]) # remove identifiers that are declared in the argument # signature of the callable @@ -489,12 +498,12 @@ class _GenerateRenderMethod(object): for ident, ns in self.compiler.namespaces.items(): if 'import' in ns.attributes: self.printer.writeline( - "_mako_get_namespace(context, %r)." - "_populate(_import_ns, %r)" % - ( - ident, - re.split(r'\s*,\s*', ns.attributes['import']) - )) + "_mako_get_namespace(context, %r)." + "_populate(_import_ns, %r)" % + ( + ident, + re.split(r'\s*,\s*', ns.attributes['import']) + )) if has_loop: self.printer.writeline( @@ -517,35 +526,36 @@ class _GenerateRenderMethod(object): elif ident in self.compiler.namespaces: self.printer.writeline( - "%s = _mako_get_namespace(context, %r)" % - (ident, ident) - ) + "%s = _mako_get_namespace(context, %r)" % + (ident, ident) + ) else: if getattr(self.compiler, 'has_ns_imports', False): if self.compiler.strict_undefined: self.printer.writelines( - "%s = _import_ns.get(%r, UNDEFINED)" % - (ident, ident), - "if %s is UNDEFINED:" % ident, + "%s = _import_ns.get(%r, UNDEFINED)" % + (ident, ident), + "if %s is UNDEFINED:" % ident, "try:", - "%s = context[%r]" % (ident, ident), + "%s = context[%r]" % (ident, ident), "except KeyError:", - "raise NameError(\"'%s' is not defined\")" % - ident, + "raise NameError(\"'%s' is not defined\")" % + ident, None, None ) else: self.printer.writeline( - "%s = _import_ns.get(%r, context.get(%r, UNDEFINED))" % - (ident, ident, ident)) + "%s = _import_ns.get" + "(%r, context.get(%r, UNDEFINED))" % + (ident, ident, ident)) else: if self.compiler.strict_undefined: self.printer.writelines( "try:", - "%s = context[%r]" % (ident, ident), + "%s = context[%r]" % (ident, ident), "except KeyError:", - "raise NameError(\"'%s' is not defined\")" % - ident, + "raise NameError(\"'%s' is not defined\")" % + ident, None ) else: @@ -562,14 +572,14 @@ class _GenerateRenderMethod(object): nameargs = node.get_argument_expressions(as_call=True) if not self.in_def and ( - len(self.identifiers.locally_assigned) > 0 or - len(self.identifiers.argument_declared) > 0): + len(self.identifiers.locally_assigned) > 0 or + len(self.identifiers.argument_declared) > 0): nameargs.insert(0, 'context._locals(__M_locals)') else: nameargs.insert(0, 'context') self.printer.writeline("def %s(%s):" % (funcname, ",".join(namedecls))) self.printer.writeline( - "return render_%s(%s)" % (funcname, ",".join(nameargs))) + "return render_%s(%s)" % (funcname, ",".join(nameargs))) self.printer.writeline(None) def write_inline_def(self, node, identifiers, nested): @@ -580,9 +590,9 @@ class _GenerateRenderMethod(object): decorator = node.decorator if decorator: self.printer.writeline( - "@runtime._decorate_inline(context, %s)" % decorator) + "@runtime._decorate_inline(context, %s)" % decorator) self.printer.writeline( - "def %s(%s):" % (node.funcname, ",".join(namedecls))) + "def %s(%s):" % (node.funcname, ",".join(namedecls))) filtered = len(node.filter_args.args) > 0 buffered = eval(node.attributes.get('buffered', 'False')) cached = eval(node.attributes.get('cached', 'False')) @@ -609,11 +619,11 @@ class _GenerateRenderMethod(object): self.printer.writeline(None) if cached: self.write_cache_decorator(node, node.funcname, - namedecls, False, identifiers, - inline=True, toplevel=False) + namedecls, False, identifiers, + inline=True, toplevel=False) def write_def_finish(self, node, buffered, filtered, cached, - callstack=True): + callstack=True): """write the end section of a rendering function, either outermost or inline. @@ -627,7 +637,7 @@ class _GenerateRenderMethod(object): if callstack: self.printer.writelines( "finally:", - "context.caller_stack._pop_frame()", + "context.caller_stack._pop_frame()", None ) @@ -639,7 +649,7 @@ class _GenerateRenderMethod(object): # extra buffers self.printer.writelines( "finally:", - "__M_buf = context._pop_buffer()" + "__M_buf = context._pop_buffer()" ) else: self.printer.writelines( @@ -667,8 +677,8 @@ class _GenerateRenderMethod(object): ) def write_cache_decorator(self, node_or_pagetag, name, - args, buffered, identifiers, - inline=False, toplevel=False): + args, buffered, identifiers, + inline=False, toplevel=False): """write a post-function decorator to replace a rendering callable with a cached version of itself.""" @@ -700,40 +710,40 @@ class _GenerateRenderMethod(object): # form "arg1, arg2, arg3=arg3, arg4=arg4", etc. pass_args = [ - "%s=%s" % ((a.split('=')[0],) * 2) if '=' in a else a - for a in args - ] + "%s=%s" % ((a.split('=')[0],) * 2) if '=' in a else a + for a in args + ] self.write_variable_declares( - identifiers, - toplevel=toplevel, - limit=node_or_pagetag.undeclared_identifiers() - ) + identifiers, + toplevel=toplevel, + limit=node_or_pagetag.undeclared_identifiers() + ) if buffered: s = "context.get('local')."\ "cache._ctx_get_or_create("\ "%s, lambda:__M_%s(%s), context, %s__M_defname=%r)" % ( - cachekey, name, ','.join(pass_args), - ''.join(["%s=%s, " % (k, v) - for k, v in cache_args.items()]), - name - ) + cachekey, name, ','.join(pass_args), + ''.join(["%s=%s, " % (k, v) + for k, v in cache_args.items()]), + name + ) # apply buffer_filters s = self.create_filter_callable(self.compiler.buffer_filters, s, False) self.printer.writelines("return " + s, None) else: self.printer.writelines( - "__M_writer(context.get('local')." - "cache._ctx_get_or_create(" - "%s, lambda:__M_%s(%s), context, %s__M_defname=%r))" % - ( - cachekey, name, ','.join(pass_args), - ''.join(["%s=%s, " % (k, v) - for k, v in cache_args.items()]), - name, - ), - "return ''", + "__M_writer(context.get('local')." + "cache._ctx_get_or_create(" + "%s, lambda:__M_%s(%s), context, %s__M_defname=%r))" % + ( + cachekey, name, ','.join(pass_args), + ''.join(["%s=%s, " % (k, v) + for k, v in cache_args.items()]), + name, + ), + "return ''", None ) @@ -777,7 +787,7 @@ class _GenerateRenderMethod(object): ( self.compiler.pagetag is not None and len(self.compiler.pagetag.filter_args.args) - ) or \ + ) or \ len(self.compiler.default_filters): s = self.create_filter_callable(node.escapes_code.args, @@ -808,11 +818,11 @@ class _GenerateRenderMethod(object): # 3) any control line with no content other than comments if not children or ( compat.all(isinstance(c, (parsetree.Comment, - parsetree.ControlLine)) - for c in children) and + parsetree.ControlLine)) + for c in children) and compat.all((node.is_ternary(c.keyword) or c.isend) - for c in children - if isinstance(c, parsetree.ControlLine))): + for c in children + if isinstance(c, parsetree.ControlLine))): self.printer.writeline("pass") def visitText(self, node): @@ -834,9 +844,9 @@ class _GenerateRenderMethod(object): "__M_buf, __M_writer = context._pop_buffer_and_writer()", "__M_writer(%s)" % self.create_filter_callable( - node.filter_args.args, - "__M_buf.getvalue()", - False), + node.filter_args.args, + "__M_buf.getvalue()", + False), None ) @@ -863,12 +873,12 @@ class _GenerateRenderMethod(object): args = node.attributes.get('args') if args: self.printer.writeline( - "runtime._include_file(context, %s, _template_uri, %s)" % - (node.parsed_attributes['file'], args)) + "runtime._include_file(context, %s, _template_uri, %s)" % + (node.parsed_attributes['file'], args)) else: self.printer.writeline( - "runtime._include_file(context, %s, _template_uri)" % - (node.parsed_attributes['file'])) + "runtime._include_file(context, %s, _template_uri)" % + (node.parsed_attributes['file'])) def visitNamespaceTag(self, node): pass @@ -882,9 +892,10 @@ class _GenerateRenderMethod(object): else: nameargs = node.get_argument_expressions(as_call=True) nameargs += ['**pageargs'] - self.printer.writeline("if 'parent' not in context._data or " - "not hasattr(context._data['parent'], '%s'):" - % node.funcname) + self.printer.writeline( + "if 'parent' not in context._data or " + "not hasattr(context._data['parent'], '%s'):" + % node.funcname) self.printer.writeline( "context['self'].%s(%s)" % (node.funcname, ",".join(nameargs))) self.printer.writeline("\n") @@ -907,7 +918,9 @@ class _GenerateRenderMethod(object): body_identifiers.add_declared('caller') self.identifier_stack.append(body_identifiers) + class DefVisitor(object): + def visitDefTag(s, node): s.visitDefOrBase(node) @@ -956,19 +969,21 @@ class _GenerateRenderMethod(object): self.printer.writelines( # push on caller for nested call "context.caller_stack.nextcaller = " - "runtime.Namespace('caller', context, " - "callables=ccall(__M_caller))", + "runtime.Namespace('caller', context, " + "callables=ccall(__M_caller))", "try:") self.printer.start_source(node.lineno) self.printer.writelines( - "__M_writer(%s)" % self.create_filter_callable( - [], node.expression, True), + "__M_writer(%s)" % self.create_filter_callable( + [], node.expression, True), "finally:", - "context.caller_stack.nextcaller = None", + "context.caller_stack.nextcaller = None", None ) + class _Identifiers(object): + """tracks the status of identifier names as template code is rendered.""" def __init__(self, compiler, node=None, parent=None, nested=False): @@ -982,9 +997,9 @@ class _Identifiers(object): # things that have already been declared # in an enclosing namespace (i.e. names we can just use) self.declared = set(parent.declared).\ - union([c.name for c in parent.closuredefs.values()]).\ - union(parent.locally_declared).\ - union(parent.argument_declared) + union([c.name for c in parent.closuredefs.values()]).\ + union(parent.locally_declared).\ + union(parent.argument_declared) # if these identifiers correspond to a "nested" # scope, it means whatever the parent identifiers @@ -1028,13 +1043,12 @@ class _Identifiers(object): node.accept_visitor(self) illegal_names = self.compiler.reserved_names.intersection( - self.locally_declared) + self.locally_declared) if illegal_names: raise exceptions.NameConflictError( "Reserved words declared in template: %s" % ", ".join(illegal_names)) - def branch(self, node, **kwargs): """create a new Identifiers for a new Node, with this Identifiers as the parent.""" @@ -1047,15 +1061,15 @@ class _Identifiers(object): def __repr__(self): return "Identifiers(declared=%r, locally_declared=%r, "\ - "undeclared=%r, topleveldefs=%r, closuredefs=%r, "\ - "argumentdeclared=%r)" %\ - ( - list(self.declared), - list(self.locally_declared), - list(self.undeclared), - [c.name for c in self.topleveldefs.values()], - [c.name for c in self.closuredefs.values()], - self.argument_declared) + "undeclared=%r, topleveldefs=%r, closuredefs=%r, "\ + "argumentdeclared=%r)" %\ + ( + list(self.declared), + list(self.locally_declared), + list(self.undeclared), + [c.name for c in self.topleveldefs.values()], + [c.name for c in self.closuredefs.values()], + self.argument_declared) def check_declared(self, node): """update the state of this Identifiers with the undeclared @@ -1083,7 +1097,7 @@ class _Identifiers(object): if not node.ismodule: self.check_declared(node) self.locally_assigned = self.locally_assigned.union( - node.declared_identifiers()) + node.declared_identifiers()) def visitNamespaceTag(self, node): # only traverse into the sub-elements of a @@ -1097,12 +1111,12 @@ class _Identifiers(object): existing = collection.get(node.funcname) collection[node.funcname] = node if existing is not None and \ - existing is not node and \ - (node.is_block or existing.is_block): + existing is not node and \ + (node.is_block or existing.is_block): raise exceptions.CompileException( - "%%def or %%block named '%s' already " - "exists in this template." % - node.funcname, **node.exception_kwargs) + "%%def or %%block named '%s' already " + "exists in this template." % + node.funcname, **node.exception_kwargs) def visitDefTag(self, node): if node.is_root() and not node.is_anonymous: @@ -1128,13 +1142,13 @@ class _Identifiers(object): if isinstance(self.node, parsetree.DefTag): raise exceptions.CompileException( - "Named block '%s' not allowed inside of def '%s'" - % (node.name, self.node.name), **node.exception_kwargs) + "Named block '%s' not allowed inside of def '%s'" + % (node.name, self.node.name), **node.exception_kwargs) elif isinstance(self.node, (parsetree.CallTag, parsetree.CallNamespaceTag)): raise exceptions.CompileException( - "Named block '%s' not allowed inside of <%%call> tag" - % (node.name, ), **node.exception_kwargs) + "Named block '%s' not allowed inside of <%%call> tag" + % (node.name, ), **node.exception_kwargs) for ident in node.undeclared_identifiers(): if ident != 'context' and \ @@ -1173,7 +1187,7 @@ class _Identifiers(object): for ident in node.undeclared_identifiers(): if ident != 'context' and \ ident not in self.declared.union( - self.locally_declared): + self.locally_declared): self.undeclared.add(ident) for ident in node.declared_identifiers(): self.argument_declared.add(ident) @@ -1183,15 +1197,16 @@ class _Identifiers(object): for ident in node.undeclared_identifiers(): if ident != 'context' and \ ident not in self.declared.union( - self.locally_declared): + self.locally_declared): self.undeclared.add(ident) _FOR_LOOP = re.compile( - r'^for\s+((?:\(?)\s*[A-Za-z_][A-Za-z_0-9]*' - r'(?:\s*,\s*(?:[A-Za-z_][A-Za-z0-9_]*),??)*\s*(?:\)?))\s+in\s+(.*):' + r'^for\s+((?:\(?)\s*[A-Za-z_][A-Za-z_0-9]*' + r'(?:\s*,\s*(?:[A-Za-z_][A-Za-z0-9_]*),??)*\s*(?:\)?))\s+in\s+(.*):' ) + def mangle_mako_loop(node, printer): """converts a for loop into a context manager wrapped around a for loop when access to the `loop` variable has been detected in the for loop body @@ -1203,9 +1218,9 @@ def mangle_mako_loop(node, printer): match = _FOR_LOOP.match(node.text) if match: printer.writelines( - 'loop = __M_loop._enter(%s)' % match.group(2), - 'try:' - #'with __M_loop(%s) as loop:' % match.group(2) + 'loop = __M_loop._enter(%s)' % match.group(2), + 'try:' + # 'with __M_loop(%s) as loop:' % match.group(2) ) text = 'for %s in loop:' % match.group(1) else: @@ -1216,6 +1231,7 @@ def mangle_mako_loop(node, printer): class LoopVariable(object): + """A node visitor which looks for the name 'loop' within undeclared identifiers.""" |