llama3 / airllm-env /lib /python3.11 /site-packages /networkx /classes /tests /dispatch_interface.py
| # This file contains utilities for testing the dispatching feature | |
| # A full test of all dispatchable algorithms is performed by | |
| # modifying the pytest invocation and setting an environment variable | |
| # NETWORKX_TEST_BACKEND=nx_loopback pytest | |
| # This is comprehensive, but only tests the `test_override_dispatch` | |
| # function in networkx.classes.backends. | |
| # To test the `_dispatchable` function directly, several tests scattered throughout | |
| # NetworkX have been augmented to test normal and dispatch mode. | |
| # Searching for `dispatch_interface` should locate the specific tests. | |
| import networkx as nx | |
| from networkx import DiGraph, Graph, MultiDiGraph, MultiGraph, PlanarEmbedding | |
| from networkx.classes.reportviews import NodeView | |
| class LoopbackGraph(Graph): | |
| __networkx_backend__ = "nx_loopback" | |
| class LoopbackDiGraph(DiGraph): | |
| __networkx_backend__ = "nx_loopback" | |
| class LoopbackMultiGraph(MultiGraph): | |
| __networkx_backend__ = "nx_loopback" | |
| class LoopbackMultiDiGraph(MultiDiGraph): | |
| __networkx_backend__ = "nx_loopback" | |
| class LoopbackPlanarEmbedding(PlanarEmbedding): | |
| __networkx_backend__ = "nx_loopback" | |
| def convert(graph): | |
| if isinstance(graph, PlanarEmbedding): | |
| return LoopbackPlanarEmbedding(graph) | |
| if isinstance(graph, MultiDiGraph): | |
| return LoopbackMultiDiGraph(graph) | |
| if isinstance(graph, MultiGraph): | |
| return LoopbackMultiGraph(graph) | |
| if isinstance(graph, DiGraph): | |
| return LoopbackDiGraph(graph) | |
| if isinstance(graph, Graph): | |
| return LoopbackGraph(graph) | |
| raise TypeError(f"Unsupported type of graph: {type(graph)}") | |
| class LoopbackBackendInterface: | |
| def __getattr__(self, item): | |
| try: | |
| return nx.utils.backends._registered_algorithms[item].orig_func | |
| except KeyError: | |
| raise AttributeError(item) from None | |
| def graph__new__(cls, incoming_graph_data=None, **attr): | |
| # LoopbackGraph.__init__ will be called next since the returned | |
| # object is an instance of an nx.Graph. For more details, see: | |
| # https://docs.python.org/3/reference/datamodel.html#object.__new__ | |
| return object.__new__(LoopbackGraph) | |
| def convert_from_nx( | |
| graph, | |
| *, | |
| edge_attrs=None, | |
| node_attrs=None, | |
| preserve_edge_attrs=None, | |
| preserve_node_attrs=None, | |
| preserve_graph_attrs=None, | |
| name=None, | |
| graph_name=None, | |
| ): | |
| if name in { | |
| # Raise if input graph changes. See test_dag.py::test_topological_sort6 | |
| "lexicographical_topological_sort", | |
| "topological_generations", | |
| "topological_sort", | |
| # Would be nice to some day avoid these cutoffs of full testing | |
| }: | |
| return graph | |
| if isinstance(graph, NodeView): | |
| # Convert to a Graph with only nodes (no edges) | |
| new_graph = Graph() | |
| new_graph.add_nodes_from(graph.items()) | |
| graph = new_graph | |
| G = LoopbackGraph() | |
| elif not isinstance(graph, Graph): | |
| raise TypeError( | |
| f"Bad type for graph argument {graph_name} in {name}: {type(graph)}" | |
| ) | |
| elif graph.__class__ in {Graph, LoopbackGraph}: | |
| G = LoopbackGraph() | |
| elif graph.__class__ in {DiGraph, LoopbackDiGraph}: | |
| G = LoopbackDiGraph() | |
| elif graph.__class__ in {MultiGraph, LoopbackMultiGraph}: | |
| G = LoopbackMultiGraph() | |
| elif graph.__class__ in {MultiDiGraph, LoopbackMultiDiGraph}: | |
| G = LoopbackMultiDiGraph() | |
| elif graph.__class__ in {PlanarEmbedding, LoopbackPlanarEmbedding}: | |
| G = LoopbackDiGraph() # or LoopbackPlanarEmbedding | |
| else: | |
| # Would be nice to handle these better some day | |
| # nx.algorithms.approximation.kcomponents._AntiGraph | |
| # nx.classes.tests.test_multidigraph.MultiDiGraphSubClass | |
| # nx.classes.tests.test_multigraph.MultiGraphSubClass | |
| G = graph.__class__() | |
| if preserve_graph_attrs: | |
| G.graph.update(graph.graph) | |
| # add nodes | |
| G.add_nodes_from(graph) | |
| if preserve_node_attrs: | |
| for n, dd in G._node.items(): | |
| dd.update(graph.nodes[n]) | |
| elif node_attrs: | |
| for n, dd in G._node.items(): | |
| dd.update( | |
| (attr, graph._node[n].get(attr, default)) | |
| for attr, default in node_attrs.items() | |
| if default is not None or attr in graph._node[n] | |
| ) | |
| # tools to build datadict and keydict | |
| if preserve_edge_attrs: | |
| def G_new_datadict(old_dd): | |
| return G.edge_attr_dict_factory(old_dd) | |
| elif edge_attrs: | |
| def G_new_datadict(old_dd): | |
| return G.edge_attr_dict_factory( | |
| (attr, old_dd.get(attr, default)) | |
| for attr, default in edge_attrs.items() | |
| if default is not None or attr in old_dd | |
| ) | |
| else: | |
| def G_new_datadict(old_dd): | |
| return G.edge_attr_dict_factory() | |
| if G.is_multigraph(): | |
| def G_new_inner(keydict): | |
| kd = G.adjlist_inner_dict_factory( | |
| (k, G_new_datadict(dd)) for k, dd in keydict.items() | |
| ) | |
| return kd | |
| else: | |
| G_new_inner = G_new_datadict | |
| # add edges keeping the same order in _adj and _pred | |
| G_adj = G._adj | |
| if G.is_directed(): | |
| for n, nbrs in graph._adj.items(): | |
| G_adj[n].update((nbr, G_new_inner(dd)) for nbr, dd in nbrs.items()) | |
| # ensure same datadict for pred and adj; and pred order of graph._pred | |
| G_pred = G._pred | |
| for n, nbrs in graph._pred.items(): | |
| G_pred[n].update((nbr, G_adj[nbr][n]) for nbr in nbrs) | |
| else: # undirected | |
| for n, nbrs in graph._adj.items(): | |
| # ensure same datadict for both ways; and adj order of graph._adj | |
| G_adj[n].update( | |
| (nbr, G_adj[nbr][n] if n in G_adj[nbr] else G_new_inner(dd)) | |
| for nbr, dd in nbrs.items() | |
| ) | |
| return G | |
| def convert_to_nx(obj, *, name=None): | |
| return obj | |
| def on_start_tests(items): | |
| # Verify that items can be xfailed | |
| for item in items: | |
| assert hasattr(item, "add_marker") | |
| def can_run(self, name, args, kwargs): | |
| # It is unnecessary to define this function if algorithms are fully supported. | |
| # We include it for illustration purposes. | |
| return hasattr(self, name) | |
| backend_interface = LoopbackBackendInterface() | |