text: '''
  Created on Jul 15, 2011
  
  @author: sean
  '''
  from __future__ import print_function
  import _ast
  from meta.asttools import Visitor
  from string import Formatter
  import sys
  from meta.utils import py3op, py2op
  from contextlib import contextmanager
  
  if sys.version_info.major < 3:
      from StringIO import StringIO
  else:
      from io import StringIO
  
  @contextmanager
  def noctx():
      yield
  class ASTFormatter(Formatter):
  
      def format_field(self, value, format_spec):
          if format_spec == 'node':
              gen = ExprSourceGen()
              gen.visit(value)
              return gen.dumps()
          elif value == '':
              return value
          else:
              return super(ASTFormatter, self).format_field(value, format_spec)
  
      def get_value(self, key, args, kwargs):
          if key == '':
              return args[0]
          elif key in kwargs:
              return kwargs[key]
          elif isinstance(key, int):
              return args[key]
  
          key = int(key)
          return args[key]
  
          raise Exception
  
  def str_node(node):
      gen = ExprSourceGen()
      gen.visit(node)
      return gen.dumps()
  
  def simple_string(value):
      def visitNode(self, node):
          self.print(value, **node.__dict__)
      return visitNode
  
  class ExprSourceGen(Visitor):
      def __init__(self):
          self.out = StringIO()
          self.formatter = ASTFormatter()
          self.indent = '    '
          self.level = 0
  
  
      @property
      def indenter(self):
          return Indenter(self)
  
      @property
      def no_indent(self):
          return NoIndent(self)
  
      def dump(self, file=sys.stdout):
          self.out.seek(0)
          print(self.out.read(), file=file)
  
      def dumps(self):
          self.out.seek(0)
          value = self.out.read()
          return value
  
      def print(self, line, *args, **kwargs):
          line = self.formatter.format(line, *args, **kwargs)
  
          level = kwargs.get('level')
          prx = self.indent * (level if level else self.level)
          print(prx, line, sep='', end='', file=self.out)
  
      def print_lines(self, lines,):
          prx = self.indent * self.level
          for line in lines:
              print(prx, line, sep='', file=self.out)
  
      def visitName(self, node):
          self.print(node.id)
      
      @py2op
      def visitarguments(self, node):
          # ('args', 'vararg', 'kwarg', 'defaults')
          defaults = [None] * (len(node.args) - len(node.defaults))
          defaults.extend(node.defaults)
  
          i = 0
          args = list(node.args)
          if args:
              i += 1
              arg = args.pop(0)
              default = defaults.pop(0)
              self.visit(arg)
              if default is not None:
                  self.print('={:node}', default)
  
          while args:
              arg = args.pop(0)
              default = defaults.pop(0)
              self.print(', ')
              self.visit(arg)
              if default is not None:
                  self.print('={:node}', default)
  
          if node.vararg:
              self.print('{0}*{1}', ', ' if i else '', node.vararg)
          if node.kwarg:
              self.print('{0}**{1}', ', ' if i else '', node.kwarg)
  
      @visitarguments.py3op
      def visitarguments(self, node):
          # ('args', 'vararg', 'kwarg', 'defaults')
          defaults = [None] * (len(node.args) - len(node.defaults))
          defaults.extend(node.defaults)
  
          i = 0
          args = list(node.args)
          if args:
              i += 1
              arg = args.pop(0)
              default = defaults.pop(0)
              self.visit(arg)
              if default is not None:
                  self.print('={:node}', default)
  
          while args:
              arg = args.pop(0)
              default = defaults.pop(0)
              self.print(', ')
              self.visit(arg)
              if default is not None:
                  self.print('={:node}', default)
  
          if node.vararg:
              self.print('{0}*{1}', ', ' if i else '', node.vararg)
              if node.varargannotation:
                  self.print(':{:node}', node.varargannotation)
          elif node.kwonlyargs:
              self.print('{0}*', ', ' if i else '')
          
          kwonlyargs = list(node.kwonlyargs)
          
          if kwonlyargs:
              i += 1
              kw_defaults = [None] * (len(kwonlyargs) - len(node.kw_defaults))
              kw_defaults.extend(node.kw_defaults)
              
          while kwonlyargs:
              kw_arg = kwonlyargs.pop(0)
              kw_default = kw_defaults.pop(0)
              self.print(', ')
              self.visit(kw_arg)
              if kw_default is not None:
                  self.print('={:node}', kw_default)
          
          if node.kwarg:
              self.print('{0}**{1}', ', ' if i else '', node.kwarg)
              if node.varargannotation:
                  self.print(':{:node}', node.kwargannotation)
  
      def visitNum(self, node):
          self.print(repr(node.n))
  
      def visitBinOp(self, node):
          self.print('({left:node} {op:node} {right:node})', left=node.left, op=node.op, right=node.right)
  
      def visitAdd(self, node):
          self.print('+')
  
      def visitalias(self, node):
          if node.asname is None:
              self.print("{0}", node.name)
          else:
              self.print("{0} as {1}", node.name, node.asname)
  
      def visitCall(self, node):
  
          self.print('{func:node}(' , func=node.func)
          i = 0
  
          print_comma = lambda i: self.print(", ") if i > 0 else None
          with self.no_indent:
  
              for arg in node.args:
                  print_comma(i)
                  self.print('{:node}', arg)
                  i += 1
  
              for kw in node.keywords:
                  print_comma(i)
                  self.print('{:node}', kw)
                  i += 1
  
              if node.starargs:
                  print_comma(i)
                  self.print('*{:node}', node.starargs)
                  i += 1
  
              if node.kwargs:
                  print_comma(i)
                  self.print('**{:node}', node.kwargs)
                  i += 1
  
              self.print(')')
  
      def visitkeyword(self, node):
          self.print("{0}={1:node}", node.arg, node.value)
  
      def visitStr(self, node):
          self.print(repr(node.s))
  
      def visitMod(self, node):
          self.print('%')
  
      def visitTuple(self, node, brace='()'):
          self.print(brace[0])
  
          print_comma = lambda i: self.print(", ") if i > 0 else None
  
          i = 0
          with self.no_indent:
              for elt in  node.elts:
                  print_comma(i)
                  self.print('{:node}', elt)
                  i += 1
                  
              if len(node.elts) == 1:
                  self.print(',')
  
              self.print(brace[1])
  
      def visitCompare(self, node):
          self.print('({0:node}', node.left)
          with self.no_indent:
              for (op, right) in zip(node.ops, node.comparators):
                  self.print(' {0:node} {1:node}' , op, right)
              self.print(')')
  
      @py2op
      def visitRaise(self, node):
          self.print('raise ')
          with self.no_indent:
              if node.type:
                  self.print('{:node}' , node.type)
              if node.inst:
                  self.print(', {:node}' , node.inst)
              if node.tback:
                  self.print(', {:node}' , node.tback)
                  
      @visitRaise.py3op
      def visitRaise(self, node):
          self.print('raise ')
          with self.no_indent:
              if node.exc:
                  self.print('{:node}' , node.exc)
              if node.cause:
                  self.print(' from {:node}' , node.cause)
  
      def visitAttribute(self, node):
          self.print('{:node}.{attr}', node.value, attr=node.attr)
  
      def visitDict(self, node):
          self.print('{{')
  
          items = zip(node.keys, node.values)
  
          with self.no_indent:
              i = 0
              pc = lambda : self.print(", ") if i > 0 else None
  
              for key, value in items:
                  pc()
                  self.print('{0:node}:{1:node}', key, value)
                  i += 1
  
              self.print('}}')
  
      def visitSet(self, node):
          self.print('{{')
  
          items = node.elts
  
          with self.no_indent:
              i = 0
              pc = lambda : self.print(", ") if i > 0 else None
  
              for value in items:
                  pc()
                  self.print('{0:node}', value)
                  i += 1
  
              self.print('}}')
  
      def visitList(self, node):
          self.print('[')
  
          with self.no_indent:
              i = 0
              pc = lambda : self.print(", ") if i > 0 else None
  
              for item in node.elts:
                  pc()
                  self.print('{:node}', item)
                  i += 1
              self.print(']')
  
      def visitSubscript(self, node):
  
          self.print('{0:node}[{1:node}]', node.value, node.slice)
  
      def visitIndex(self, node):
          if isinstance(node.value, _ast.Tuple):
              with self.no_indent:
                  self.visit(node.value, brace=['', ''])
          else:
              self.print('{:node}', node.value)
  
      def visitSlice(self, node):
          with self.no_indent:
              if node.lower is not None:
                  self.print('{:node}', node.lower)
              self.print(':')
              if node.upper is not None:
                  self.print('{:node}', node.upper)
  
              if node.step is not None:
                  self.print(':')
                  self.print('{:node}', node.step)
  
      def visitExtSlice(self, node):
  
          dims = list(node.dims)
          with self.no_indent:
              dim = dims.pop(0)
              self.print('{0:node}', dim)
              
              while dims:
                  dim = dims.pop(0)
                  self.print(', {0:node}', dim)
  
      def visitUnaryOp(self, node):
          self.print('({0:node}{1:node})', node.op, node.operand)
  
      def visitAssert(self, node):
          self.print('assert {0:node}', node.test)
  
          if node.msg:
              with self.no_indent:
                  self.print(', {0:node}', node.msg)
  
      visitUSub = simple_string('-')
      visitUAdd = simple_string('+')
      visitNot = simple_string('not ')
      visitInvert = simple_string('~')
  
      visitAnd = simple_string('and')
      visitOr = simple_string('or')
  
      visitSub = simple_string('-')
      visitFloorDiv = simple_string('//')
      visitDiv = simple_string('/')
      visitMod = simple_string('%')
      visitMult = simple_string('*')
      visitPow = simple_string('**')
  
      visitEq = simple_string('==')
      visitNotEq = simple_string('!=')
  
      visitLt = simple_string('<')
      visitGt = simple_string('>')
  
      visitLtE = simple_string('<=')
      visitGtE = simple_string('>=')
  
      visitLShift = simple_string('<<')
      visitRShift = simple_string('>>')
  
      visitIn = simple_string('in')
      visitNotIn = simple_string('not in')
  
      visitIs = simple_string('is')
      visitIsNot = simple_string('is not')
  
      visitBitAnd = simple_string('&')
      visitBitOr = simple_string('|')
      visitBitXor = simple_string('^')
  
      visitEllipsis = simple_string('...')
  
      visitYield = simple_string('yield {value:node}')
  
      def visitBoolOp(self, node):
  
          with self.no_indent:
              values = list(node.values)
              left = values.pop(0)
  
              self.print('({:node}', left)
              while values:
                  left = values.pop(0)
                  self.print(' {0:node} {1:node}', node.op, left)
              self.print(')')
  
      def visitIfExp(self, node):
          self.print('{body:node} if {test:node} else {orelse:node}', **node.__dict__)
  
      def visitLambda(self, node):
          self.print('lambda {0:node}: {1:node}', node.args, node.body)
  
      def visitListComp(self, node):
          self.print('[{0:node}', node.elt)
  
  
          generators = list(node.generators)
          with self.no_indent:
              while generators:
                  generator = generators.pop(0)
                  self.print('{0:node}', generator)
  
              self.print(']')
  
      def visitSetComp(self, node):
          self.print('{{{0:node}', node.elt)
  
  
          generators = list(node.generators)
          with self.no_indent:
              while generators:
                  generator = generators.pop(0)
                  self.print('{0:node}', generator)
  
              self.print('}}')
  
      def visitDictComp(self, node):
          self.print('{{{0:node}:{1:node}', node.key, node.value)
  
  
          generators = list(node.generators)
          with self.no_indent:
              while generators:
                  generator = generators.pop(0)
                  self.print('{0:node}', generator)
  
              self.print('}}')
  
  
      def visitcomprehension(self, node):
          self.print(' for {0:node} in {1:node}', node.target, node.iter)
  
          ifs = list(node.ifs)
          while ifs:
              if_ = ifs.pop(0)
              self.print(" if {0:node}", if_)
  
      @py3op
      def visitarg(self, node):
          self.print(node.arg)
          
          if node.annotation:
              with self.no_indent:
                  self.print(':{0:node}', node.annotation)
      
  def visit_expr(node):
      gen = ExprSourceGen()
      gen.visit(node)
      return gen.dumps()
  
  class NoIndent(object):
      def __init__(self, gen):
          self.gen = gen
  
      def __enter__(self):
          self.level = self.gen.level
          self.gen.level = 0
  
      def __exit__(self, *args):
          self.gen.level = self.level
  
  class Indenter(object):
      def __init__(self, gen):
          self.gen = gen
  
      def __enter__(self):
          self.gen.print('\n', level=0)
          self.gen.level += 1
  
      def __exit__(self, *args):
          self.gen.level -= 1
  
  class SourceGen(ExprSourceGen):
  
      def __init__(self, header=''):
          super(SourceGen, self).__init__()
          print(header, file=self.out)
  
      def visitModule(self, node):
  
          children = list(self.children(node))
          if children and isinstance(children[0], _ast.Expr):
              if isinstance(children[0].value, _ast.Str):
                  doc = children.pop(0).value
                  self.print("'''")
                  self.print_lines(doc.s.split('\n'))
                  self.print_lines(["'''", '\n', '\n'])
  
          for node in children:
              self.visit(node)
  
      def visitFor(self, node):
          self.print('for {0:node} in {1:node}:', node.target, node.iter)
          with self.indenter:
              for stmnt in node.body:
                  self.visit(stmnt)
  
          if node.orelse:
              self.print('else:')
              with self.indenter:
                  for stmnt in node.orelse:
                      self.visit(stmnt)
  
      @py2op
      def visitFunctionDef(self, node):
          # fields = ('name', 'args', 'body', 'decorator_list')
  
          for decorator in node.decorator_list:
              self.print('@{decorator:node}\n', decorator=decorator)
  
          args = visit_expr(node.args)
          self.print('def {name}({args}):' , name=node.name, args=args)
  
          with self.indenter:
              for child in node.body:
                  self.visit(child)
          return
      
      @visitFunctionDef.py3op
      def visitFunctionDef(self, node):
  
          for decorator in node.decorator_list:
              self.print('@{decorator:node}\n', decorator=decorator)
  
          args = visit_expr(node.args)
          self.print('def {name}({args})' , name=node.name, args=args)
          
          with self.no_indent:
              if node.returns:
                  self.print(' -> {:node}:', node.returns)
              else:
                  self.print(':', node.returns)
              
          with self.indenter:
              for child in node.body:
                  self.visit(child)
          return
  
      def visitAssign(self, node):
          targets = [visit_expr(target) for target in node.targets]
  
          self.print('{targets} = {value:node}\n', targets=' = '.join(targets), value=node.value)
  
      def visitAugAssign(self, node):
          self.print('{target:node} {op:node}= {value:node}\n', **node.__dict__)
  
      def visitIf(self, node, indent_first=True):
          with noctx() if indent_first else self.no_indent:
              self.print('if {:node}:', node.test)
  
          with self.indenter:
              if node.body:
                  for expr in node.body:
                      self.visit(expr)
              else:
                  self.print('pass')
                      
  
          if node.orelse and len(node.orelse) == 1 and isinstance(node.orelse[0], _ast.If):
              self.print('el'); self.visit(node.orelse[0], indent_first=False)
          elif node.orelse:
              self.print('else:')
              with self.indenter:
                  for expr in node.orelse:
                      self.visit(expr)
          self.print('\n')
  
      def visitImportFrom(self, node):
          for name in node.names:
              self.print("from {0} import {1:node}\n", node.module, name)
  
      def visitImport(self, node):
          for name in node.names:
              self.print("import {:node}\n", name)
  
      def visitPrint(self, node):
          self.print("print ")
  
          with self.no_indent:
              if node.dest:
                  self.print(">> {:node}" , node.dest)
                  if not node.values and node.nl:
                      self.print("\n")
                      return
  
                  self.print(", ")
  
              i = 0
              pc = lambda : self.print(", ") if i > 0 else None
              for value in  node.values:
                  pc()
                  self.print("{:node}" , value)
  
              if not node.nl:
                  self.print(",")
  
              self.print("\n")
  
      def visitExec(self, node):
          self.print('exec {0:node} in {1}, {2}\n', node.body,
                     'None' if node.globals is None else str_node(node.globals),
                     'None' if node.locals is None else str_node(node.locals))
  
      def visitWith(self, node):
          self.print('with {0:node}', node.context_expr)
          if node.optional_vars is not None:
              self.print(' as {0:node}', node.optional_vars, level=0)
          self.print(':', level=0)
  
          with self.indenter:
              if node.body:
                  for expr in node.body:
                      self.visit(expr)
              else:
                  self.print('pass\n')
  
      def visitGlobal(self, node):
          self.print('global ')
          with self.no_indent:
              names = list(node.names)
              if names:
                  name = names.pop(0)
                  self.print(name)
              while names:
                  name = names.pop(0)
                  self.print(', {0}', name)
              self.print('\n')
  
  
      def visitDelete(self, node):
          self.print('del ')
  
          targets = list(node.targets)
  
          with self.no_indent:
              target = targets.pop(0)
              self.print('{0:node}', target)
              while targets:
                  target = targets.pop(0)
                  self.print(', {0:node}', target)
              self.print('\n')
  
      def visitWhile(self, node):
          self.print('while {0:node}:', node.test)
  
          with self.indenter:
              if node.body:
                  for expr in node.body:
                      self.visit(expr)
              else:
                  self.print("pass")
                      
  
          if node.orelse:
              self.print('else:')
              with self.indenter:
                  for expr in node.orelse:
                      self.visit(expr)
              self.print('\n')
          self.print('\n')
  
  
      def visitExpr(self, node):
          self.print('{:node}\n', node.value)
  
      visitBreak = simple_string('break\n')
      visitPass = simple_string('pass\n')
      visitContinue = simple_string('continue\n')
  
      def visitReturn(self, node):
          if node.value is not None:
              self.print('return {:node}\n', node.value)
  
      def visitTryExcept(self, node):
          self.print('try:')
  
          with self.indenter:
              if node.body:
                  for stmnt in node.body:
                      self.visit(stmnt)
              else:
                  self.print('pass')
                      
          for hndlr in node.handlers:
              self.visit(hndlr)
  
          if node.orelse:
              self.print('else:')
              with self.indenter:
                  for stmnt in node.orelse:
                      self.visit(stmnt)
      @py2op
      def visitExceptHandler(self, node):
  
          self.print('except')
  
          with self.no_indent:
              if node.type:
                  self.print(" {0:node}", node.type)
              if node.name:
                  self.print(" as {0:node}", node.name)
  
              self.print(":")
  
          with self.indenter:
              if node.body:
                  for stmnt in node.body:
                      self.visit(stmnt)
              else:
                  self.print('pass')
                  
      @visitExceptHandler.py3op
      def visitExceptHandler(self, node):
          self.print('except')
  
          with self.no_indent:
              if node.type:
                  self.print(" {0:node}", node.type)
              if node.name:
                  self.print(" as {0}", node.name)
  
              self.print(":")
  
          with self.indenter:
              for stmnt in node.body:
                  self.visit(stmnt)
                  
                  
      def visitTryFinally(self, node):
          for item in node.body:
              self.visit(item)
  
          self.print('finally:')
  
          with self.indenter:
              for item in node.finalbody:
                  self.visit(item)
      
      @py2op
      def visitClassDef(self, node):
  
          for decorator in node.decorator_list:
              self.print('@{0:node}\n', decorator)
  
          self.print('class {0}', node.name)
  
          with self.no_indent:
              self.print('(')
              bases = list(node.bases)
              if bases:
                  base = bases.pop(0)
                  self.print("{0:node}", base)
                  while bases:
                      base = bases.pop(0)
                      self.print(", {0:node}", base)
              self.print(')')
  
              self.print(":")
  
          with self.indenter:
              if node.body:
                  for stmnt in node.body:
                      self.visit(stmnt)
              else:
                  self.print("pass\n\n")
  
      @visitClassDef.py3op
      def visitClassDef(self, node):
  
          for decorator in node.decorator_list:
              self.print('@{0:node}\n', decorator)
  
          self.print('class {0}', node.name)
  
          with self.no_indent:
              self.print('(')
              bases = list(node.bases)
              i = 0
              if bases:
                  i += 1
                  base = bases.pop(0)
                  self.print("{0:node}", base)
                  while bases:
                      base = bases.pop(0)
                      self.print(", {0:node}", base)
              keywords = list(node.keywords)
              
              if keywords:
                  if i: self.print(', ')
                  i += 1
                  keyword = keywords.pop(0)
                  self.print("{0:node}", keyword)
                  while keywords:
                      base = keywords.pop(0)
                      self.print(", {0:node}", keyword)
              
              if node.starargs:
                  if i: self.print(', ')
                  i += 1
                  self.print("*{0:node}", node.starargs)
  
              if node.kwargs:
                  if i: self.print(', ')
                  i += 1
                  self.print("*{0:node}", node.kwargs)
                  
              self.print(')')
  
              self.print(":")
  
          with self.indenter:
              if node.body:
                  for stmnt in node.body:
                      self.visit(stmnt)
              else:
                  self.print("pass\n\n")
  
  def python_source(ast, file=sys.stdout):
      '''
      Generate executable python source code from an ast node.
        
      :param ast: ast node
      :param file: file to write output to.
      '''
      gen = SourceGen()
      gen.visit(ast)
      gen.dump(file)
  
  def dump_python_source(ast):
      '''
      :return: a string containing executable python source code from an ast node.
        
      :param ast: ast node
      :param file: file to write output to.
      '''
      gen = SourceGen()
      gen.visit(ast)
      return gen.dumps()
  
  
  
  