def prune_graph(graph_str, package_name): """Prune a package graph so it only contains nodes accessible from the given package. Args: graph_str (str): Dot-language graph string. package_name (str): Name of package of interest. Returns: Pruned graph, as a string. """ # find nodes of interest g = read_dot(graph_str) nodes = set() for node, attrs in g.node_attr.iteritems(): attr = [x for x in attrs if x[0] == "label"] if attr: label = attr[0][1] try: req_str = _request_from_label(label) request = PackageRequest(req_str) except PackageRequestError: continue if request.name == package_name: nodes.add(node) if not nodes: raise ValueError("The package %r does not appear in the graph." % package_name) # find nodes upstream from these nodes g_rev = g.reverse() accessible_nodes = set() access = accessibility(g_rev) for node in nodes: nodes_ = access.get(node, []) accessible_nodes |= set(nodes_) # remove inaccessible nodes inaccessible_nodes = set(g.nodes()) - accessible_nodes for node in inaccessible_nodes: g.del_node(node) return write_dot(g)
def package_depends_on(self, name_a, name_b): """Returns dependency information about two packages: 0: A does not depend, directly or indirectly, on B; 1: A depends indirectly on B; 2: A depends directly on B. """ assert self._context if self._dependency_lookup is None: self._dependency_graph = self._context.get_dependency_graph() self._dependency_lookup = accessibility(self._dependency_graph) downstream = self._dependency_lookup.get(name_a, []) accessible = (name_b in downstream) if accessible: neighbours = self._dependency_graph.neighbors(name_a) return 2 if name_b in neighbours else 1 else: return 0