I tried a very similar thing, but not using with statements:
http://mail.python.org/pipermail/python-list/2010-March/1239577.html Dan On 04/05/2010 22:36, Terry Reedy wrote:
In a current thread, people have claimed that generating properly indented nested blocks is a pain because of the need to keep track of indent levels. Someone countered with the now rather ancient http://effbot.org/zone/python-code-generator.htm The usage example c = CodeGeneratorBackend() c.begin(tab=" ") c.write("for i in range(1000):\n") c.indent() c.write("print 'code generation is trivial'") c.dedent() illustrates three problems with the CodeGeneratorBackend class. 1) it requires explicit \n on all lines (which the second omits, though it is non-fatal since it is also the last) 2) the user still has to manually match indents and dedents, and 3) the user *cannot* indent lines that produce indented code. The relatively new with statement and associated context managers are designed, among other things, for this situation, where one needs to alter and restore a global context. So here is my updated (3.1) proof-of-concept version. class PyCodeGen: def __init__(self, tab=" "): self.code = [] self.tab = tab self.level = 0 # all attributes should be treated as read-only def end(self): return '\n'.join(self.code) def line(self, string): # new line self.code.append(self.tab * self.level + string) class For: def __init__(self, target, in_expression): target.line('for ' + in_expression + ':') self.target = target def __enter__(self): self.target.level += 1 def __exit__(self, t, v, tb): self.target.level -= 1 c = PyCodeGen() with For(c, 'i in range(1000)'): c.line('print("Code gen is easy")') c.line('# done') print(c.end()) # prints for i in range(1000): print("Code gen is easy") # done Note that the absence of .indent and .dedent is intentional. In a fleshed out system, there would be a context manager for each compound statement and these would handle all indents and dedents. If one really preferred to write, for instance, 'c.For(s); instead of 'For(c,s)' in the with statement, one could add a wrapper method like def For(self, s): return For(self, s) for each context manager. I left that out. Similar methods can be used to auto-match C braces and other open/close pairs. Terry Jan Reedy
-- http://mail.python.org/mailman/listinfo/python-list