def create_pyan_graph(path, keep_undefined=False, content="default"): converter = _converter(content) from pyan.analyzer import CallGraphVisitor from pyan.analyzer import Flavor visitor = CallGraphVisitor(_path2files(path)) visited_nodes = [ node for name in visitor.nodes for node in visitor.nodes[name] if node.defined or keep_undefined ] #visited_nodes.sort(key=lambda x: (x.namespace, x.name)) logger.log("Found", len(visited_nodes), "entities") G = nx.DiGraph() modules = {} for node in visited_nodes: if (node.flavor == Flavor.MODULE or node.flavor == Flavor.CLASS) and node in visitor.defines_edges: modules[node] = [ cdefined for defined in visitor.defines_edges[node] if defined.defined or keep_undefined for cdefined in converter(defined) ] + [cnode for cnode in converter(node)] if node in visitor.uses_edges: for cnode in converter(node): G.add_node(cnode) for called in visitor.uses_edges[node]: if (called.defined or keep_undefined) and ( called.flavor == Flavor.FUNCTION or called.flavor == Flavor.CLASSMETHOD or called.flavor == Flavor.METHOD): for cnode in converter(node): for ccalled in converter(called): G.add_edge(cnode, ccalled) G.add_edge(ccalled, cnode) return G, modules
def test_resolve_package_with_known_root(): dirname = os.path.dirname(__file__) filenames = glob(os.path.join(dirname, "test_code/**/*.py"), recursive=True) callgraph = CallGraphVisitor(filenames, logger=logging.getLogger(), root=dirname) dirname_base = os.path.basename(dirname) defines = get_in_dict(callgraph.defines_edges, f"{dirname_base}.test_code.subpackage2.submodule_hidden1") get_node(defines, f"{dirname_base}.test_code.subpackage2.submodule_hidden1.test_func1")
def main(): repo_paths = ['ecosystem\\**\\*.py'] filenames = [ fn for repo_path in repo_paths for fn in glob(repo_path, recursive=True) ] filenames = list( filter( lambda filename: (os.path.sep + 'tests' + os.path.sep) not in filename and (os.path.sep + 'testing' + os.path.sep) not in filename, filenames)) v = CallGraphVisitor(filenames) graph = VisualGraph.dump_callgraph(v)
def main(): start = time.clock() repo_paths = [ 'C:\\Users\\njdx\\Desktop\\CG_Python\\pro\\matplotlib\\**\\*.py' ] filenames = [ fn for repo_path in repo_paths for fn in glob(repo_path, recursive=True) ] all_graph = defaultdict(list) v = CallGraphVisitor(filenames, logger=[]) all_graph = VisualGraph.dump_callgraph(v) json_str = json.dumps(all_graph, indent=4) end = time.clock()
def main(): usage = """usage: %prog FILENAME... [--dot|--tgf|--yed]""" desc = ('Analyse one or more Python source files and generate an' 'approximate call graph of the modules, classes and functions' ' within them.') parser = OptionParser(usage=usage, description=desc) parser.add_option("--dot", action="store_true", default=False, help="output in GraphViz dot format") parser.add_option("--tgf", action="store_true", default=False, help="output in Trivial Graph Format") parser.add_option("--yed", action="store_true", default=False, help="output in yEd GraphML Format") parser.add_option("-f", "--file", dest="filename", help="write graph to FILE", metavar="FILE", default=None) parser.add_option("-l", "--log", dest="logname", help="write log to LOG", metavar="LOG") parser.add_option("-v", "--verbose", action="store_true", default=False, dest="verbose", help="verbose output") parser.add_option("-V", "--very-verbose", action="store_true", default=False, dest="very_verbose", help="even more verbose output (mainly for debug)") parser.add_option("-d", "--defines", action="store_true", default=True, dest="draw_defines", help="add edges for 'defines' relationships [default]") parser.add_option("-n", "--no-defines", action="store_false", default=True, dest="draw_defines", help="do not add edges for 'defines' relationships") parser.add_option("-u", "--uses", action="store_true", default=True, dest="draw_uses", help="add edges for 'uses' relationships [default]") parser.add_option("-N", "--no-uses", action="store_false", default=True, dest="draw_uses", help="do not add edges for 'uses' relationships") parser.add_option("-c", "--colored", action="store_true", default=False, dest="colored", help="color nodes according to namespace [dot only]") parser.add_option( "-G", "--grouped-alt", action="store_true", default=False, dest="grouped_alt", help= "suggest grouping by adding invisible defines edges [only useful with --no-defines]" ) parser.add_option( "-g", "--grouped", action="store_true", default=False, dest="grouped", help="group nodes (create subgraphs) according to namespace [dot only]" ) parser.add_option( "-e", "--nested-groups", action="store_true", default=False, dest="nested_groups", help= "create nested groups (subgraphs) for nested namespaces (implies -g) [dot only]" ) parser.add_option("--dot-rankdir", default="TB", dest="rankdir", help=("specifies the dot graph 'rankdir' property for " "controlling the direction of the graph. " "Allowed values: ['TB', 'LR', 'BT', 'RL']. " "[dot only]")) parser.add_option("-a", "--annotated", action="store_true", default=False, dest="annotated", help="annotate with module and source line number") parser.add_option("--make-svg", action="store_true", default=False, dest="make_svg", help="try to run dot to make svg automatically") options, args = parser.parse_args() filenames = [fn2 for fn in args for fn2 in glob(fn)] if len(args) == 0: parser.error('Need one or more filenames to process') if options.nested_groups: options.grouped = True graph_options = { 'draw_defines': options.draw_defines, 'draw_uses': options.draw_uses, 'colored': options.colored, 'grouped_alt': options.grouped_alt, 'grouped': options.grouped, 'nested_groups': options.nested_groups, 'annotated': options.annotated } # TODO: use an int argument for verbosity logger = logging.getLogger(__name__) if options.very_verbose: logger.setLevel(logging.DEBUG) elif options.verbose: logger.setLevel(logging.INFO) else: logger.setLevel(logging.WARN) logger.addHandler(logging.StreamHandler()) if options.logname: handler = logging.FileHandler(options.logname) logger.addHandler(handler) v = CallGraphVisitor(filenames, logger) graph = VisualGraph.from_visitor(v, options=graph_options, logger=logger) if options.dot: writer = DotWriter(graph, options=['rankdir=' + options.rankdir], output=options.filename, logger=logger) writer.run() if options.make_svg: base, _ = os.path.splitext(options.filename) svg = base + ".svg" subprocess.run("dot -Tsvg {dot} > {svg}".format( dot=options.filename, svg=svg), shell=True) if options.tgf: writer = TgfWriter(graph, output=options.filename, logger=logger) writer.run() if options.yed: writer = YedWriter(graph, output=options.filename, logger=logger) writer.run()
def callgraph(): filenames = glob(os.path.join(os.path.dirname(__file__), "test_code/**/*.py"), recursive=True) v = CallGraphVisitor(filenames, logger=logging.getLogger()) return v
def main(): args = process_command_line(sys.argv) filenames = [y for x in args.filename for y in glob(x)] if args.nested_groups: args.grouped = True graph_options = { "draw_defines": args.draw_defines, "draw_uses": args.draw_uses, "colored": args.colored, "grouped_alt": args.grouped_alt, "grouped": args.grouped, "nested_groups": args.nested_groups, "annotated": args.annotated, } out_format = args.format if args.outfilename and not args.format: out_format = os.path.splitext(args.outfilename)[1][1:] if not out_format: out_format = "dot" logger = logging.getLogger(__name__) if args.verbose >= 2: logger.setLevel(logging.DEBUG) elif args.verbose == 1: logger.setLevel(logging.INFO) else: logger.setLevel(logging.WARN) logger.addHandler(logging.StreamHandler()) if args.logname: handler = logging.FileHandler(args.logname) logger.addHandler(handler) v = CallGraphVisitor(filenames, logger) graph = VisualGraph.from_visitor(v, options=graph_options, logger=logger) if out_format == "dot": writer = DotWriter( graph, options=["rankdir=" + args.rankdir], output=args.outfilename, logger=logger, ) elif out_format == "tgf": writer = TgfWriter(graph, output=args.outfilename, logger=logger) elif out_format == "yed": writer = YedWriter(graph, output=args.outfilename, logger=logger) elif out_format in ["svg", "png", "eps", "pdf", "ps", "webp"]: try: writer = DotRenderer( graph, options=["rankdir=" + args.rankdir], output=args.outfilename, output_format=out_format, logger=logger, ) except NoDotError: print( "No executable 'dot' found in PATH. Stopping without creating" " any output." ) print( "To enable this functionality, install Graphviz's dot utility" " to your path." ) return else: print("Cannot determine output format. Stopping without creating any output.") return # actually write file output writer.run()