def splitdocfor(path): """split the docstring for a path valid paths are:: ./path/to/module.py ./path/to/module.py:SomeClass.method returns (description, long_description) from the docstring for path or (None, None) if there isn't a docstring. Example:: >>> splitdocfor("./wsgi_intercept/__init__.py")[0] 'installs a WSGI application in place of a real URI for testing.' >>> splitdocfor("./wsgi_intercept/__init__.py:WSGI_HTTPConnection.get_app")[0] 'Return the app object for the given (host, port).' >>> """ if ":" in path: filename, objpath = path.split(':') else: filename, objpath = path, None inspector = DocInspector(filename) visitor.walk(compiler.parseFile(filename), inspector) if objpath is None: if inspector.top_level_doc is None: return None, None return pydoc.splitdoc(inspector.top_level_doc) else: if inspector[objpath] is None: return None, None return pydoc.splitdoc(inspector[objpath])
def parse(buf, mode="exec"): context = CompilerContext() parser = Parser.FromString(sys, context, buf) node = parser.ParseFileInput() tree = Transformer().parsefile(node) walk(tree, FlattenVisitor()) return tree
def parse(buf, mode='exec'): context = CompilerContext() parser = Parser.FromString(sys, context, buf) node = parser.ParseFileInput() tree = Transformer().parsefile(node) walk(tree, FlattenVisitor()) return tree
def visitCode(self, node): gen = self.BlockGen(node, self.scopes, self.get_module(), node.lazy) visitor.walk(node.code, gen) gen.finish() self.set_lineno(node) #self.emit('LOAD_CONST', node.name) frees = gen.scope.get_free_vars() #print node.name, 'free', frees gen.scope.DEBUG() self.makeClosure(gen, 0, frees) self.emit('LOAD_CONST', gen) if not node.lazy: if frees: self.emit('MAKE_CLOSURE', 0) else: self.emit('MAKE_FUNCTION', 0) #self.emit('CALL_FUNCTION', 0) self.storeName(node.name) if node.wrapper is not None: # load wrapper callable to TOS self.visit(node.wrapper) # load pattern name to TOS self.emit('LOAD_CONST', node.name) # load pattern to TOS self.loadName(node.name) # call wrapper(name, pattern) self.emit('CALL_FUNCTION', 2) # store it back self.storeName(node.name)
def __init__(self, code, **exception_kwargs): self.codeargs = [] self.args = [] self.declared_identifiers = util.Set() self.undeclared_identifiers = util.Set() class FindTuple(object): def visitTuple(s, node, *args): for n in node.nodes: p = PythonCode(n, **exception_kwargs) self.codeargs.append(p) self.args.append(ExpressionGenerator(n).value()) self.declared_identifiers = self.declared_identifiers.union(p.declared_identifiers) self.undeclared_identifiers = self.undeclared_identifiers.union(p.undeclared_identifiers) if isinstance(code, basestring): if re.match(r"\S", code) and not re.match(r",\s*$", code): # if theres text and no trailing comma, insure its parsed # as a tuple by adding a trailing comma code += "," expr = parse(code, "exec", **exception_kwargs) else: expr = code f = FindTuple() visitor.walk(expr, f)
def __init__(self, code, **exception_kwargs): self.codeargs = [] self.args = [] self.declared_identifiers = util.Set() self.undeclared_identifiers = util.Set() class FindTuple(object): def visitTuple(s, node, *args): for n in node.nodes: p = PythonCode(n, **exception_kwargs) self.codeargs.append(p) self.args.append(ExpressionGenerator(n).value()) self.declared_identifiers = self.declared_identifiers.union( p.declared_identifiers) self.undeclared_identifiers = self.undeclared_identifiers.union( p.undeclared_identifiers) if isinstance(code, basestring): if re.match(r"\S", code) and not re.match(r",\s*$", code): # if theres text and no trailing comma, insure its parsed # as a tuple by adding a trailing comma code += "," expr = parse(code, "exec", **exception_kwargs) else: expr = code f = FindTuple() visitor.walk(expr, f)
def processModuleAst(ast, name, system): mv = system.ModuleVistor(system, name) walk(ast, mv) while mv.morenodes: obj, node = mv.morenodes.pop(0) system.push(obj, node) mv.visit(node) system.pop(obj)
def _visitOp(self, node, fn): """Traverse binary operators like '+', '-', '/', etc. fn - function which abstract representation of particular operation. """ (left, right) = node.getChildren() visitor = FunctionVisitor() walk(left, visitor, visitor) walk(right, visitor, visitor) self.children.append(fn(*visitor.children))
def get_module_meta(modfile): ast = compiler.parseFile(modfile) modnode = ModuleVisitor() visitor.walk(ast, modnode) if modnode.mod_doc is None: raise RuntimeError("could not parse doc string from %s" % modfile) if modnode.mod_version is None: raise RuntimeError("could not parse __version__ from %s" % modfile) return (modnode.mod_version, ) + pydoc.splitdoc(modnode.mod_doc)
def get_module_meta(modfile): ast = compiler.parseFile(modfile) modnode = ModuleVisitor() visitor.walk(ast, modnode) if modnode.mod_doc is None: raise RuntimeError( "could not parse doc string from %s" % modfile) if modnode.mod_version is None: raise RuntimeError( "could not parse __version__ from %s" % modfile) return (modnode.mod_version,) + pydoc.splitdoc(modnode.mod_doc)
def normalize_file(filename, *args): """ Import-normalize a file. If the file is not parseable, an empty filelike object will be returned. """ try: ast = compiler.parseFile(filename) except Exception as e: return StringIO('') ip = ImportPuller() walk(ast, ip) return StringIO(ip.as_string())
def findImportStars(system): assert system.state in ['preparse'] modlist = list(system.objectsOfType(Module)) for mod in modlist: system.push(mod.parent) isf = ImportStarFinder(system, mod.fullName()) try: ast = parseFile(mod.filepath) except (SyntaxError, ValueError): system.warning("cannot parse", mod.filepath) walk(ast, isf) system.pop(mod.parent) system.state = 'importstarred'
def visitFunction(self, node): """Create export attribute and start traverse function body (depth-first search)""" # (decorators, name, argnames, defaults, flags, docs, code) cn = node.getChildren() fn_name = cn[1] argnames = cn[2] code = cn[-1] visitor = FunctionVisitor() walk(code, visitor, visitor) self.functions.append(erl.function_af(fn_name, argnames, visitor.children)) self.exports.append(erl.export_af(fn_name, argnames))
def visitPrintnl(self, node): """Print to io:format. Print has several forms: print 'test' print 'test', var print 'test %s' % var print 'test {0}'.format(var) """ # node children format: ([node1, node2, ...,] dist) nodes = node.getChildren() nodes = nodes[0] visitor = FunctionVisitor() for n in nodes: walk(nodes, visitor, visitor) visitor.children.append(erl.nil_af()) self.children.append(erl.io_format_af(visitor.children))
def __init__(self, code, allow_kwargs=True, **exception_kwargs): self.code = code expr = parse(code, "exec", **exception_kwargs) class ParseFunc(object): def visitFunction(s, node, *args): self.funcname = node.name self.argnames = node.argnames self.defaults = node.defaults self.varargs = node.varargs self.kwargs = node.kwargs f = ParseFunc() visitor.walk(expr, f) if not hasattr(self, 'funcname'): raise exceptions.CompileException("Code '%s' is not a function declaration" % code, **exception_kwargs) if not allow_kwargs and self.kwargs: raise exceptions.CompileException("'**%s' keyword argument not allowed here" % self.argnames[-1], **exception_kwargs)
def __init__(self, block, scopes, module): self.block_name = block.name self.module = module self.graph = pyassem.PyFlowGraph(block.name, block.filename, optimized=0) self.super_init() lnf = visitor.walk(block.code, self.NameFinder(), verbose=0) self.locals.push(lnf.getLocals()) if not self.lazy: self.graph.setFlag(CO_NEWLOCALS) if block.doc: self.setDocstring(block.doc)
def __init__(self, code, allow_kwargs=True, **exception_kwargs): self.code = code expr = parse(code, "exec", **exception_kwargs) class ParseFunc(object): def visitFunction(s, node, *args): self.funcname = node.name self.argnames = node.argnames self.defaults = node.defaults self.varargs = node.varargs self.kwargs = node.kwargs f = ParseFunc() visitor.walk(expr, f) if not hasattr(self, 'funcname'): raise exceptions.CompileException( "Code '%s' is not a function declaration" % code, **exception_kwargs) if not allow_kwargs and self.kwargs: raise exceptions.CompileException( "'**%s' keyword argument not allowed here" % self.argnames[-1], **exception_kwargs)
def parseSymbols(self, tree): s = ptpysymbols.PtpySymbolVisitor() visitor.walk(tree, s) return s.scopes
def parseSymbols(self, tree): s = lucysymbols.LucySymbolVisitor() visitor.walk(tree, s) return s.scopes
def __init__(self, tree): self.graph = pyassem.PyFlowGraph("<module>", tree.filename) self.futures = future.find_futures(tree) self.__super_init() visitor.walk(tree, self)
return os.path.basename(os.path.splitext(file_name)[0]) COMPILER = 'compile_forms' if __name__ == '__main__': if len(sys.argv) == 2: fname = sys.argv[1] erl_out = None try: module_tree = compiler.parseFile(fname) if isinstance(module_tree, compiler.ast.Module): doc, module_body = module_tree.getChildren() visitor = ModuleVisitor() walk(module_body, visitor, visitor) forms = erl.full_af(erl.module_af(module_name(fname)), visitor.exports, visitor.functions) retcode = subprocess.call(['erlc', 'py2erl/erl/{compiler}.erl'.format(compiler=COMPILER)]) if not retcode: retcode = subprocess.call(['erl', '-noshell', '-eval', "code:load_file('{compiler}'),"\ "{compiler}:compile({forms}),"\ "erlang:halt()".format(forms=forms, compiler=COMPILER)]) if not retcode: logging.info('Successfully compiled') else: logging.error('Can not compile abstract forms') else:
def __init__(self, code, **exception_kwargs): self.code = code # represents all identifiers which are assigned to at some point in the code self.declared_identifiers = util.Set() # represents all identifiers which are referenced before their assignment, if any self.undeclared_identifiers = util.Set() # note that an identifier can be in both the undeclared and declared lists. # using AST to parse instead of using code.co_varnames, code.co_names has several advantages: # - we can locate an identifier as "undeclared" even if its declared later in the same block of code # - AST is less likely to break with version changes (for example, the behavior of co_names changed a little bit # in python version 2.5) if isinstance(code, basestring): expr = parse(code.lstrip(), "exec", **exception_kwargs) else: expr = code class FindIdentifiers(object): def __init__(self): self.in_function = False self.local_ident_stack = {} def _add_declared(s, name): if not s.in_function: self.declared_identifiers.add(name) def visitClass(self, node, *args): self._add_declared(node.name) def visitAssName(self, node, *args): self._add_declared(node.name) def visitAssign(self, node, *args): # flip around the visiting of Assign so the expression gets evaluated first, # in the case of a clause like "x=x+5" (x is undeclared) self.visit(node.expr, *args) for n in node.nodes: self.visit(n, *args) def visitFunction(self, node, *args): self._add_declared(node.name) # push function state onto stack. dont log any # more identifiers as "declared" until outside of the function, # but keep logging identifiers as "undeclared". # track argument names in each function header so they arent counted as "undeclared" saved = {} inf = self.in_function self.in_function = True for arg in node.argnames: if arg in self.local_ident_stack: saved[arg] = True else: self.local_ident_stack[arg] = True for n in node.getChildNodes(): self.visit(n, *args) self.in_function = inf for arg in node.argnames: if arg not in saved: del self.local_ident_stack[arg] def visitFor(self, node, *args): # flip around visit self.visit(node.list, *args) self.visit(node.assign, *args) self.visit(node.body, *args) def visitName(s, node, *args): if node.name not in __builtins__ and node.name not in self.declared_identifiers and node.name not in s.local_ident_stack: self.undeclared_identifiers.add(node.name) def visitImport(self, node, *args): for (mod, alias) in node.names: if alias is not None: self._add_declared(alias) else: self._add_declared(mod.split('.')[0]) def visitFrom(self, node, *args): for (mod, alias) in node.names: if alias is not None: self._add_declared(alias) else: if mod == '*': raise exceptions.CompileException( "'import *' is not supported, since all identifier names must be explicitly declared. Please use the form 'from <modulename> import <name1>, <name2>, ...' instead.", **exception_kwargs) self._add_declared(mod) f = FindIdentifiers() visitor.walk(expr, f) #, walker=walker())
""" Concatenate all of the 'import' and 'from' statements. """ return ''.join(self.statements) def normalize_file(filename, *args): """ Import-normalize a file. If the file is not parseable, an empty filelike object will be returned. """ try: ast = compiler.parseFile(filename) except Exception, e: return StringIO('') ip = ImportPuller() walk(ast, ip) return StringIO(ip.as_string()) def get_grinimports_arg_parser(parser=None): """ Create the command-line parser. """ parser = grin.get_grin_arg_parser(parser) parser.set_defaults(include='*.py') parser.description = ("Extract, normalize and search import statements " "from Python files.") parser.epilog = """ For example, if I have a file example.py with a bunch of imports: $ cat example.py import foo
def __init__(self, astnode): self.buf = StringIO() visitor.walk(astnode, self) #, walker=walker())
def visit(self, expr): visitor.walk(expr, self)
def processModuleAST(self, ast, mod): findAll(ast, mod) visitor.walk(ast, self.ModuleVistor(self, mod))
def ast2hir(ast): v = HIRASTVisitor() visitor.walk(ast, v) return v.top()
"""Package for compiling Python source code There are several functions defined at the top level that are imported from modules contained in the package. walk(ast, visitor, verbose=None) Does a pre-order walk over the ast using the visitor instance. See compiler.visitor for details. compile(source, filename, mode, flags=None, dont_inherit=None) Returns a code object. A replacement for the builtin compile() function. compileFile(filename) Generates a .pyc file by compiling filename. """ from compiler.visitor import walk from compiler.pycodegen import compile, compileFile
def testSymbolVisitor(): def PrintScopes(scopes): result = [] for i in sorted(scopes, key=lambda x:x.name): result.append('- %s' % i) for j in sorted(i.uses): result.append(' - %s' % j) return '\n'.join(result) source_code = Dedent( ''' from alpha import Alpha import coilib50 class Zulu(Alpha): """ Zulu class docs. """ def __init__(self, name): """ Zulu.__init__ docs. """ self._name = name alpha = bravo coilib50.Charlie() f = coilib50.Delta(echo, foxtrot) ''' ) from terraformer._visitor import ASTVisitor code = TerraFormer._Parse(source_code) visitor = ASTVisitor() visitor.Visit(code) assert visitor._module.AsString() == Dedent( ''' module (1, 0) module IMPORT-BLOCK (1, 0) import-block #0 IMPORT-FROM (0, 0) alpha IMPORT (1, 0) alpha.Alpha IMPORT (2, 0) coilib50 USE (3, 0) Alpha class (0, 0) Zulu def (8, 4) __init__ ARG (9, 17) self ARG (9, 23) name DEF (13, 8) self._name USE (13, 21) name DEF (14, 8) alpha USE (14, 16) bravo USE (15, 8) coilib50.Charlie DEF (16, 8) f USE (16, 12) coilib50.Delta USE (16, 27) echo USE (16, 33) foxtrot ''' ) # Compares the results with the one given by compiler.symbols.SymbolVisitor, our inspiration. from compiler.symbols import SymbolVisitor from compiler.transformer import parse from compiler.visitor import walk code = parse(source_code) symbol_visitor = SymbolVisitor() walk(code, symbol_visitor) assert PrintScopes(symbol_visitor.scopes.values()) == Dedent( ''' - <ClassScope: Zulu> - <FunctionScope: __init__> - bravo - coilib50 - echo - foxtrot - name - self - <ModuleScope: global> - Alpha ''' )
""" Concatenate all of the 'import' and 'from' statements. """ return ''.join(self.statements) def normalize_file(filename, *args): """ Import-normalize a file. If the file is not parseable, an empty filelike object will be returned. """ try: ast = compiler.parseFile(filename) except Exception, e: return StringIO('') ip = ImportPuller() walk(ast, ip) return StringIO(ip.as_string()) def get_grinimports_arg_parser(parser=None): """ Create the command-line parser. """ parser = grin.get_grin_arg_parser(parser) parser.set_defaults(include='*.py') parser.description = ("Extract, normalize and search import statements " "from Python files.") parser.epilog = """ For example, if I have a file example.py with a bunch of imports: $ cat example.py import foo import foo.baz as blah
def visitReturn(self, node): """Continue traversing in depth""" (value,) = node.getChildren() walk(value, self, self)
def visitStmt(self, node): """Continue traversing in depth""" for n in node.getChildren(): walk(n, self, self)
def __init__(self, code, **exception_kwargs): self.code = code # represents all identifiers which are assigned to at some point in the code self.declared_identifiers = util.Set() # represents all identifiers which are referenced before their assignment, if any self.undeclared_identifiers = util.Set() # note that an identifier can be in both the undeclared and declared lists. # using AST to parse instead of using code.co_varnames, code.co_names has several advantages: # - we can locate an identifier as "undeclared" even if its declared later in the same block of code # - AST is less likely to break with version changes (for example, the behavior of co_names changed a little bit # in python version 2.5) if isinstance(code, basestring): expr = parse(code.lstrip(), "exec", **exception_kwargs) else: expr = code class FindIdentifiers(object): def __init__(self): self.in_function = False self.local_ident_stack = {} def _add_declared(s, name): if not s.in_function: self.declared_identifiers.add(name) def visitClass(self, node, *args): self._add_declared(node.name) def visitAssName(self, node, *args): self._add_declared(node.name) def visitAssign(self, node, *args): # flip around the visiting of Assign so the expression gets evaluated first, # in the case of a clause like "x=x+5" (x is undeclared) self.visit(node.expr, *args) for n in node.nodes: self.visit(n, *args) def visitFunction(self,node, *args): self._add_declared(node.name) # push function state onto stack. dont log any # more identifiers as "declared" until outside of the function, # but keep logging identifiers as "undeclared". # track argument names in each function header so they arent counted as "undeclared" saved = {} inf = self.in_function self.in_function = True for arg in node.argnames: if arg in self.local_ident_stack: saved[arg] = True else: self.local_ident_stack[arg] = True for n in node.getChildNodes(): self.visit(n, *args) self.in_function = inf for arg in node.argnames: if arg not in saved: del self.local_ident_stack[arg] def visitFor(self, node, *args): # flip around visit self.visit(node.list, *args) self.visit(node.assign, *args) self.visit(node.body, *args) def visitName(s, node, *args): if node.name not in __builtins__ and node.name not in self.declared_identifiers and node.name not in s.local_ident_stack: self.undeclared_identifiers.add(node.name) def visitImport(self, node, *args): for (mod, alias) in node.names: if alias is not None: self._add_declared(alias) else: self._add_declared(mod.split('.')[0]) def visitFrom(self, node, *args): for (mod, alias) in node.names: if alias is not None: self._add_declared(alias) else: if mod == '*': raise exceptions.CompileException("'import *' is not supported, since all identifier names must be explicitly declared. Please use the form 'from <modulename> import <name1>, <name2>, ...' instead.", **exception_kwargs) self._add_declared(mod) f = FindIdentifiers() visitor.walk(expr, f) #, walker=walker())
def visit(self, expr): visitor.walk(expr, self) # , walker=walker())
def visit(self, expr): visitor.walk(expr, self) #, walker=walker())
def __init__(self, astnode): self.buf = StringIO() visitor.walk(astnode, self) # , walker=walker())
def testSymbolVisitor(): def PrintScopes(scopes): result = [] for i in sorted(scopes, key=lambda x:x.name): result.append('- %s' % i) for j in sorted(i.uses): result.append(' - %s' % j) return '\n'.join(result) source_code = dedent( ''' from alpha import Alpha import coilib50 class Zulu(Alpha): """ Zulu class docs. """ def __init__(self, name): """ Zulu.__init__ docs. """ self._name = name alpha = bravo coilib50.Charlie() f = coilib50.Delta(echo, foxtrot) ''' ) from zerotk.terraformer._visitor import ASTVisitor code = TerraFormer._Parse(source_code) visitor = ASTVisitor() visitor.Visit(code) assert visitor._module.AsString() == dedent( ''' module (1, 0) module IMPORT-BLOCK (1, 0) import-block #0 IMPORT-FROM (0, 0) alpha IMPORT (1, 0) alpha.Alpha IMPORT (2, 0) coilib50 USE (3, 0) Alpha class (0, 0) Zulu def (8, 4) __init__ ARG (9, 17) self ARG (9, 23) name DEF (13, 8) self._name USE (13, 21) name DEF (14, 8) alpha USE (14, 16) bravo USE (15, 8) coilib50.Charlie DEF (16, 8) f USE (16, 12) coilib50.Delta USE (16, 27) echo USE (16, 33) foxtrot ''' ) # Compares the results with the one given by compiler.symbols.SymbolVisitor, our inspiration. from compiler.symbols import SymbolVisitor from compiler.transformer import parse from compiler.visitor import walk code = parse(source_code) symbol_visitor = SymbolVisitor() walk(code, symbol_visitor) assert PrintScopes(symbol_visitor.scopes.values()) == dedent( ''' - <ClassScope: Zulu> - <FunctionScope: __init__> - bravo - coilib50 - echo - foxtrot - name - self - <ModuleScope: global> - Alpha ''' )