def test_exclude_depends_double_diamond(self): """Test for the ExcludeDependents for double diamond graph.""" libdeps_graph = LibdepsGraph(get_double_diamond_mock_graph()) expected_result = { "EXCLUDE_DEPENDS": { "('lib6.so', 'lib4.so')": ["lib3.so", "lib4.so", "lib5.so"] } } self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.ExcludeDependents, ['lib6.so', 'lib4.so']) expected_result = {"EXCLUDE_DEPENDS": {"('lib2.so', 'lib9.so')": []}} self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.ExcludeDependents, ['lib2.so', 'lib9.so']) expected_result = { "EXCLUDE_DEPENDS": { "('lib8.so', 'lib1.so', 'lib2.so', 'lib3.so', 'lib4.so', 'lib5.so')": ["lib5.so", "lib6.so"] } } self.run_analysis( expected_result, libdeps_graph, libdeps.analyzer.ExcludeDependents, ['lib8.so', 'lib1.so', 'lib2.so', 'lib3.so', 'lib4.so', 'lib5.so'])
def test_graph_paths_basic(self): """Test for the GraphPaths analyzer on a basic graph.""" libdeps_graph = LibdepsGraph(get_basic_mock_graph()) expected_result = { "GRAPH_PATHS": { "('lib1.so', 'lib6.so')": [["lib1.so", "lib2.so", "lib3.so", "lib6.so"], ["lib1.so", "lib2.so", "lib4.so", "lib6.so"]] } } self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.GraphPaths, 'lib1.so', 'lib6.so') expected_result = {"GRAPH_PATHS": {"('lib4.so', 'lib5.so')": []}} self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.GraphPaths, 'lib4.so', 'lib5.so') expected_result = { "GRAPH_PATHS": { "('lib2.so', 'lib5.so')": [['lib2.so', 'lib3.so', 'lib5.so']] } } self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.GraphPaths, 'lib2.so', 'lib5.so')
def test_graph_paths_double_diamond(self): """Test path algorithm on the double diamond graph.""" libdeps_graph = LibdepsGraph(get_double_diamond_mock_graph()) expected_result = { "GRAPH_PATHS": { "('lib1.so', 'lib9.so')": [["lib1.so", "lib2.so", "lib3.so", "lib5.so", "lib6.so", "lib7.so", "lib9.so"], ["lib1.so", "lib2.so", "lib3.so", "lib5.so", "lib6.so", "lib8.so", "lib9.so"], ["lib1.so", "lib2.so", "lib4.so", "lib5.so", "lib6.so", "lib7.so", "lib9.so"], ["lib1.so", "lib2.so", "lib4.so", "lib5.so", "lib6.so", "lib8.so", "lib9.so"]] } } self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.GraphPaths, 'lib1.so', 'lib9.so') expected_result = { "GRAPH_PATHS": { "('lib5.so', 'lib9.so')": [["lib5.so", "lib6.so", "lib7.so", "lib9.so"], ["lib5.so", "lib6.so", "lib8.so", "lib9.so"]] } } self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.GraphPaths, 'lib5.so', 'lib9.so') expected_result = { "GRAPH_PATHS": { "('lib2.so', 'lib6.so')": [["lib2.so", "lib3.so", "lib5.so", "lib6.so"], ["lib2.so", "lib4.so", "lib5.so", "lib6.so"]] } } self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.GraphPaths, 'lib2.so', 'lib6.so')
def test_common_depends_basic(self): """Test for the CommonDependents for basic graph.""" libdeps_graph = LibdepsGraph(get_basic_mock_graph()) expected_result = { "COMMON_DEPENDS": { "('lib6.so', 'lib5.so')": ["lib1.so", "lib2.so", "lib3.so", "lib4.so"] } } self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.CommonDependents, ['lib6.so', 'lib5.so']) expected_result = { "COMMON_DEPENDS": { "('lib5.so', 'lib6.so')": ["lib1.so", "lib2.so", "lib3.so", "lib4.so"] } } self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.CommonDependents, ['lib5.so', 'lib6.so']) expected_result = { "COMMON_DEPENDS": { "('lib5.so', 'lib6.so', 'lib2.so')": ["lib1.so"] } } self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.CommonDependents, ['lib5.so', 'lib6.so', 'lib2.so'])
def main(): """Perform graph analysis based on input args.""" args = setup_args_parser() graph = load_graph_data(args.graph_file, args.format) libdeps_graph = LibdepsGraph(graph=graph) build_dir = libdeps_graph.graph['build_dir'] if libdeps_graph.graph['graph_schema_version'] == 1: libdeps_graph = networkx.reverse_view(libdeps_graph) analysis = libdeps_analyzer.counter_factory(libdeps_graph, args.counts) for analyzer_args in args.direct_depends: analysis.append( libdeps_analyzer.DirectDependents( libdeps_graph, strip_build_dir(build_dir, analyzer_args))) for analyzer_args in args.common_depends: analysis.append( libdeps_analyzer.CommonDependents( libdeps_graph, strip_build_dirs(build_dir, analyzer_args))) for analyzer_args in args.exclude_depends: analysis.append( libdeps_analyzer.ExcludeDependents( libdeps_graph, strip_build_dirs(build_dir, analyzer_args))) for analyzer_args in args.graph_paths: analysis.append( libdeps_analyzer.GraphPaths( libdeps_graph, strip_build_dir(build_dir, analyzer_args[0]), strip_build_dir(build_dir, analyzer_args[1]))) for analyzer_args in args.critical_edges: analysis.append( libdeps_analyzer.CriticalEdges( libdeps_graph, strip_build_dir(build_dir, analyzer_args[0]), strip_build_dir(build_dir, analyzer_args[1]))) if args.indegree_one: analysis.append(libdeps_analyzer.InDegreeOne(libdeps_graph)) analysis += libdeps_analyzer.linter_factory(libdeps_graph, args.lint) if args.build_data: analysis.append(libdeps_analyzer.BuildDataReport(libdeps_graph)) ga = libdeps_analyzer.LibdepsGraphAnalysis(analysis) if args.format == 'pretty': ga_printer = libdeps_analyzer.GaPrettyPrinter(ga) elif args.format == 'json': ga_printer = libdeps_analyzer.GaJsonPrinter(ga) else: return ga_printer.print()
def get_big_graph(int_id): """Generate a big graph.""" graph = LibdepsGraph() graph.graph['build_dir'] = '.' graph.graph['graph_schema_version'] = 2 graph.graph['deptypes'] = json.dumps({ "Global": 0, "Public": 1, "Private": 2, "Interface": 3, }) graph.graph['git_hash'] = f'BIG{int_id.zfill(4)}' num_nodes = 200 for i in range(num_nodes): add_node(graph, f'lib{i}.so', 'SharedLibrary') for j in range(num_nodes - i): add_edge(graph, f'lib{i}.so', f'lib{j}.so', direct=True, visibility=graph.get_deptype('Public'), symbols='\n'.join( [f"RandomString{i+j}" * 100 for i in range(10)])) return graph
def test_counts_double_diamond(self): """Test counts on double diamond graph.""" libdeps_graph = LibdepsGraph(get_double_diamond_mock_graph()) expected_result = { "NODE": 9, "EDGE": 34, "DIR_EDGE": 10, "TRANS_EDGE": 24, "DIR_PUB_EDGE": 10, "PUB_EDGE": 34, "PRIV_EDGE": 0, "IF_EDGE": 0, "PROG": 0, "LIB": 9 } self.run_counts(expected_result, libdeps_graph)
def test_counts_basic(self): """Test counts on basic graph.""" libdeps_graph = LibdepsGraph(get_basic_mock_graph()) expected_result = { "NODE": 6, "EDGE": 13, "DIR_EDGE": 7, "TRANS_EDGE": 6, "DIR_PUB_EDGE": 6, "PUB_EDGE": 12, "PRIV_EDGE": 1, "IF_EDGE": 0, "PROG": 0, "LIB": 6 } self.run_counts(expected_result, libdeps_graph)
def test_direct_depends_double_diamond(self): """Test for the DirectDependents for double diamond graph.""" libdeps_graph = LibdepsGraph(get_double_diamond_mock_graph()) expected_result = {"DIRECT_DEPENDS": {"lib9.so": ["lib7.so", "lib8.so"]}} self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.DirectDependents, 'lib9.so') expected_result = {"DIRECT_DEPENDS": {"lib6.so": ["lib5.so"]}} self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.DirectDependents, 'lib6.so')
def test_direct_depends_basic(self): """Test for the DirectDependents for basic graph.""" libdeps_graph = LibdepsGraph(get_basic_mock_graph()) expected_result = {"DIRECT_DEPENDS": {"lib6.so": ["lib3.so", "lib4.so"]}} self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.DirectDependents, 'lib6.so') expected_result = {'DIRECT_DEPENDS': {'lib1.so': []}} self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.DirectDependents, 'lib1.so')
def test_critical_paths_double_diamond(self): """Test for the CriticalPaths for double diamond graph.""" libdeps_graph = LibdepsGraph(get_double_diamond_mock_graph()) expected_result = {"CRITICAL_EDGES": {"('lib1.so', 'lib9.so')": [["lib1.so", "lib2.so"]]}} self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.CriticalEdges, 'lib1.so', 'lib9.so') expected_result = {"CRITICAL_EDGES": {"('lib2.so', 'lib9.so')": [["lib5.so", "lib6.so"]]}} self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.CriticalEdges, 'lib2.so', 'lib9.so') expected_result = {"CRITICAL_EDGES": {"('lib7.so', 'lib8.so')": []}} self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.CriticalEdges, 'lib7.so', 'lib8.so')
def main(): """Perform graph analysis based on input args.""" args = setup_args_parser() graph = load_graph_data(args.graph_file, args.format) libdeps_graph = LibdepsGraph(graph=graph) analysis = libdeps_analyzer.counter_factory(libdeps_graph, args.counts) for analyzer_args in args.direct_depends: analysis.append( libdeps_analyzer.DirectDependents(libdeps_graph, analyzer_args)) for analyzer_args in args.common_depends: analysis.append( libdeps_analyzer.CommonDependents(libdeps_graph, analyzer_args)) for analyzer_args in args.exclude_depends: analysis.append( libdeps_analyzer.ExcludeDependents(libdeps_graph, analyzer_args)) for analyzer_args in args.graph_paths: analysis.append( libdeps_analyzer.GraphPaths(libdeps_graph, analyzer_args[0], analyzer_args[1])) for analyzer_args in args.critical_edges: analysis.append( libdeps_analyzer.CriticalEdges(libdeps_graph, analyzer_args[0], analyzer_args[1])) analysis += libdeps_analyzer.linter_factory(libdeps_graph, args.lint) if args.build_data: analysis.append(libdeps_analyzer.BuildDataReport(libdeps_graph)) ga = libdeps_analyzer.LibdepsGraphAnalysis(libdeps_graph=libdeps_graph, analysis=analysis) if args.format == 'pretty': ga_printer = libdeps_analyzer.GaPrettyPrinter(ga) elif args.format == 'json': ga_printer = libdeps_analyzer.GaJsonPrinter(ga) else: return ga_printer.print()
def test_critical_paths_basic(self): """Test for the CriticalPaths for basic graph.""" libdeps_graph = LibdepsGraph(get_basic_mock_graph()) expected_result = { "CRITICAL_EDGES": { "('lib1.so', 'lib6.so')": [["lib1.so", "lib2.so"]] } } self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.CriticalEdges, 'lib1.so', 'lib6.so') expected_result = { "CRITICAL_EDGES": { "('lib1.so', 'lib5.so')": [["lib1.so", "lib2.so"]] } } self.run_analysis(expected_result, libdeps_graph, libdeps.analyzer.CriticalEdges, 'lib1.so', 'lib5.so')
def get_simple_directory_graph(): """Construct a mock graph which covers most cases and is easy to understand.""" graph = LibdepsGraph() graph.graph['build_dir'] = '.' graph.graph['graph_schema_version'] = 2 graph.graph['deptypes'] = json.dumps({ "Global": 0, "Public": 1, "Private": 2, "Interface": 3, }) graph.graph['git_hash'] = 'TEST004' # lib2.so <- lib4.so # /∧ \∨ # lib1.so prog1 <- lib5.so # \∨ /∧ # lib3.so -> prog2 # nodes add_node(graph, 'mongo/base/lib1.so', 'SharedLibrary') add_node(graph, 'mongo/base/lib2.so', 'SharedLibrary') add_node(graph, 'mongo/db/lib3.so', 'SharedLibrary') add_node(graph, 'third_party/lib4.so', 'SharedLibrary') add_node(graph, 'third_party/lib5.so', 'SharedLibrary') add_node(graph, 'mongo/base/prog1', 'Program') add_node(graph, 'mongo/db/prog2', 'Program') # direct edges add_edge(graph, 'mongo/base/lib1.so', 'mongo/base/lib2.so', direct=True, visibility=graph.get_deptype('Public')) add_edge(graph, 'mongo/base/lib1.so', 'mongo/db/lib3.so', direct=True, visibility=graph.get_deptype('Public')) add_edge(graph, 'mongo/base/lib2.so', 'mongo/base/prog1', direct=True, visibility=graph.get_deptype('Public')) add_edge(graph, 'mongo/db/lib3.so', 'mongo/base/prog1', direct=True, visibility=graph.get_deptype('Public')) add_edge(graph, 'mongo/db/lib3.so', 'mongo/db/prog2', direct=True, visibility=graph.get_deptype('Public')) add_edge(graph, 'third_party/lib4.so', 'mongo/base/lib2.so', direct=True, visibility=graph.get_deptype('Public')) add_edge(graph, 'third_party/lib5.so', 'mongo/base/prog1', direct=True, visibility=graph.get_deptype('Public')) return graph
def get_basic_mock_directory_graph(): """Construct a mock graph which covers most cases and is easy to understand.""" graph = LibdepsGraph() graph.graph['build_dir'] = '.' graph.graph['graph_schema_version'] = 2 graph.graph['deptypes'] = json.dumps({ "Global": 0, "Public": 1, "Private": 2, "Interface": 3, }) graph.graph['git_hash'] = 'TEST003' # builds a graph of mostly public edges: # # /-lib5.so # /lib3 # | \-lib6.so # <-lib1.so--lib2 # | /-lib5.so (private) # \lib4.so # \-lib6.so # nodes add_node(graph, 'dir1/lib1.so', 'SharedLibrary') add_node(graph, 'dir1/sub1/lib2', 'Program') add_node(graph, 'dir1/sub1/lib3', 'Program') add_node(graph, 'dir1/sub2/lib4.so', 'SharedLibrary') add_node(graph, 'dir2/lib5.so', 'SharedLibrary') add_node(graph, 'dir2/lib6.so', 'SharedLibrary') # direct edges add_edge(graph, 'dir1/lib1.so', 'dir1/sub1/lib2', direct=True, visibility=graph.get_deptype('Public')) add_edge(graph, 'dir1/sub1/lib2', 'dir1/sub1/lib3', direct=True, visibility=graph.get_deptype('Public')) add_edge(graph, 'dir1/sub1/lib2', 'dir1/sub2/lib4.so', direct=True, visibility=graph.get_deptype('Public')) add_edge(graph, 'dir1/sub2/lib4.so', 'dir2/lib6.so', direct=True, visibility=graph.get_deptype('Public')) add_edge(graph, 'dir1/sub1/lib3', 'dir2/lib5.so', direct=True, visibility=graph.get_deptype('Public')) add_edge(graph, 'dir1/sub1/lib3', 'dir2/lib6.so', direct=True, visibility=graph.get_deptype('Public')) add_edge(graph, 'dir1/sub2/lib4.so', 'dir2/lib5.so', direct=True, visibility=graph.get_deptype('Private')) # trans for 3 add_edge(graph, 'dir1/lib1.so', 'dir1/sub1/lib3', direct=False, visibility=graph.get_deptype('Public')) # trans for 4 add_edge(graph, 'dir1/lib1.so', 'dir1/sub2/lib4.so', direct=False, visibility=graph.get_deptype('Public')) # trans for 5 add_edge(graph, 'dir1/sub1/lib2', 'dir2/lib5.so', direct=False, visibility=graph.get_deptype('Public')) add_edge(graph, 'dir1/lib1.so', 'dir2/lib5.so', direct=False, visibility=graph.get_deptype('Public')) # trans for 6 add_edge(graph, 'dir1/sub1/lib2', 'dir2/lib6.so', direct=False, visibility=graph.get_deptype('Public')) add_edge(graph, 'dir1/lib1.so', 'dir2/lib6.so', direct=False, visibility=graph.get_deptype('Public')) return graph
def get_double_diamond_mock_graph(): """Construct a mock graph which covers a double diamond structure.""" graph = LibdepsGraph() graph.graph['build_dir'] = '.' graph.graph['graph_schema_version'] = 2 graph.graph['deptypes'] = '''{ "Global": 0, "Public": 1, "Private": 2, "Interface": 3, "Typeinfo": 4 }''' # builds a graph of mostly public edges that looks like this: # # # /lib3.so /lib7.so # | \ | \ # <-lib1.so--lib2.so lib5.so--lib6.so lib9.so # | / | / # \lib4.so \lib8.so # add_node(graph, 'lib1.so', 'SharedLibrary') add_node(graph, 'lib2.so', 'SharedLibrary') add_node(graph, 'lib3.so', 'SharedLibrary') add_node(graph, 'lib4.so', 'SharedLibrary') add_node(graph, 'lib5.so', 'SharedLibrary') add_node(graph, 'lib6.so', 'SharedLibrary') add_node(graph, 'lib7.so', 'SharedLibrary') add_node(graph, 'lib8.so', 'SharedLibrary') add_node(graph, 'lib9.so', 'SharedLibrary') add_edge(graph, 'lib1.so', 'lib2.so', direct=True, visibility=graph.get_deptype('Public')) add_edge(graph, 'lib2.so', 'lib3.so', direct=True, visibility=graph.get_deptype('Public')) add_edge(graph, 'lib2.so', 'lib4.so', direct=True, visibility=graph.get_deptype('Public')) add_edge(graph, 'lib3.so', 'lib5.so', direct=True, visibility=graph.get_deptype('Public')) add_edge(graph, 'lib4.so', 'lib5.so', direct=True, visibility=graph.get_deptype('Public')) add_edge(graph, 'lib5.so', 'lib6.so', direct=True, visibility=graph.get_deptype('Public')) add_edge(graph, 'lib6.so', 'lib7.so', direct=True, visibility=graph.get_deptype('Public')) add_edge(graph, 'lib6.so', 'lib8.so', direct=True, visibility=graph.get_deptype('Public')) add_edge(graph, 'lib7.so', 'lib9.so', direct=True, visibility=graph.get_deptype('Public')) add_edge(graph, 'lib8.so', 'lib9.so', direct=True, visibility=graph.get_deptype('Public')) # trans for 3 and 4 add_edge(graph, 'lib1.so', 'lib3.so', direct=False, visibility=graph.get_deptype('Public')) add_edge(graph, 'lib1.so', 'lib4.so', direct=False, visibility=graph.get_deptype('Public')) # trans for 5 add_edge(graph, 'lib1.so', 'lib5.so', direct=False, visibility=graph.get_deptype('Public')) add_edge(graph, 'lib2.so', 'lib5.so', direct=False, visibility=graph.get_deptype('Public')) # trans for 6 add_edge(graph, 'lib1.so', 'lib6.so', direct=False, visibility=graph.get_deptype('Public')) add_edge(graph, 'lib2.so', 'lib6.so', direct=False, visibility=graph.get_deptype('Public')) add_edge(graph, 'lib3.so', 'lib6.so', direct=False, visibility=graph.get_deptype('Public')) add_edge(graph, 'lib4.so', 'lib6.so', direct=False, visibility=graph.get_deptype('Public')) # trans for 7 add_edge(graph, 'lib1.so', 'lib7.so', direct=False, visibility=graph.get_deptype('Public')) add_edge(graph, 'lib2.so', 'lib7.so', direct=False, visibility=graph.get_deptype('Public')) add_edge(graph, 'lib3.so', 'lib7.so', direct=False, visibility=graph.get_deptype('Public')) add_edge(graph, 'lib4.so', 'lib7.so', direct=False, visibility=graph.get_deptype('Public')) add_edge(graph, 'lib5.so', 'lib7.so', direct=False, visibility=graph.get_deptype('Public')) # trans for 8 add_edge(graph, 'lib1.so', 'lib8.so', direct=False, visibility=graph.get_deptype('Public')) add_edge(graph, 'lib2.so', 'lib8.so', direct=False, visibility=graph.get_deptype('Public')) add_edge(graph, 'lib3.so', 'lib8.so', direct=False, visibility=graph.get_deptype('Public')) add_edge(graph, 'lib4.so', 'lib8.so', direct=False, visibility=graph.get_deptype('Public')) add_edge(graph, 'lib5.so', 'lib8.so', direct=False, visibility=graph.get_deptype('Public')) # trans for 9 add_edge(graph, 'lib1.so', 'lib9.so', direct=False, visibility=graph.get_deptype('Public')) add_edge(graph, 'lib2.so', 'lib9.so', direct=False, visibility=graph.get_deptype('Public')) add_edge(graph, 'lib3.so', 'lib9.so', direct=False, visibility=graph.get_deptype('Public')) add_edge(graph, 'lib4.so', 'lib9.so', direct=False, visibility=graph.get_deptype('Public')) add_edge(graph, 'lib5.so', 'lib9.so', direct=False, visibility=graph.get_deptype('Public')) add_edge(graph, 'lib6.so', 'lib9.so', direct=False, visibility=graph.get_deptype('Public')) return graph
def get_basic_mock_graph(): """Construct a mock graph which covers most cases and is easy to understand.""" graph = LibdepsGraph() graph.graph['build_dir'] = '.' graph.graph['graph_schema_version'] = 2 graph.graph['deptypes'] = '''{ "Global": 0, "Public": 1, "Private": 2, "Interface": 3, "Typeinfo": 4 }''' # builds a graph of mostly public edges: # # /-lib5.so # /lib3.so # | \-lib6.so # <-lib1.so--lib2.so # | /-lib5.so (private) # \lib4.so # \-lib6.so # nodes add_node(graph, 'lib1.so', 'SharedLibrary') add_node(graph, 'lib2.so', 'SharedLibrary') add_node(graph, 'lib3.so', 'SharedLibrary') add_node(graph, 'lib4.so', 'SharedLibrary') add_node(graph, 'lib5.so', 'SharedLibrary') add_node(graph, 'lib6.so', 'SharedLibrary') # direct edges add_edge(graph, 'lib1.so', 'lib2.so', direct=True, visibility=graph.get_deptype('Public')) add_edge(graph, 'lib2.so', 'lib3.so', direct=True, visibility=graph.get_deptype('Public')) add_edge(graph, 'lib2.so', 'lib4.so', direct=True, visibility=graph.get_deptype('Public')) add_edge(graph, 'lib4.so', 'lib6.so', direct=True, visibility=graph.get_deptype('Public')) add_edge(graph, 'lib3.so', 'lib5.so', direct=True, visibility=graph.get_deptype('Public')) add_edge(graph, 'lib3.so', 'lib6.so', direct=True, visibility=graph.get_deptype('Public')) add_edge(graph, 'lib4.so', 'lib5.so', direct=True, visibility=graph.get_deptype('Private')) # trans for 3 add_edge(graph, 'lib1.so', 'lib3.so', direct=False, visibility=graph.get_deptype('Public')) # trans for 4 add_edge(graph, 'lib1.so', 'lib4.so', direct=False, visibility=graph.get_deptype('Public')) # trans for 5 add_edge(graph, 'lib2.so', 'lib5.so', direct=False, visibility=graph.get_deptype('Public')) add_edge(graph, 'lib1.so', 'lib5.so', direct=False, visibility=graph.get_deptype('Public')) # trans for 6 add_edge(graph, 'lib2.so', 'lib6.so', direct=False, visibility=graph.get_deptype('Public')) add_edge(graph, 'lib1.so', 'lib6.so', direct=False, visibility=graph.get_deptype('Public')) return graph