diff --git a/python/nx-cugraph/nx_cugraph/algorithms/bipartite/generators.py b/python/nx-cugraph/nx_cugraph/algorithms/bipartite/generators.py index 25b9b39554b..5a0c970c984 100644 --- a/python/nx-cugraph/nx_cugraph/algorithms/bipartite/generators.py +++ b/python/nx-cugraph/nx_cugraph/algorithms/bipartite/generators.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023, NVIDIA CORPORATION. +# Copyright (c) 2023-2024, NVIDIA CORPORATION. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -24,7 +24,7 @@ ] -@networkx_algorithm(nodes_or_number=[0, 1]) +@networkx_algorithm(nodes_or_number=[0, 1], version_added="23.12") def complete_bipartite_graph(n1, n2, create_using=None): graph_class, inplace = _create_using_class(create_using) if graph_class.is_directed(): diff --git a/python/nx-cugraph/nx_cugraph/algorithms/centrality/betweenness.py b/python/nx-cugraph/nx_cugraph/algorithms/centrality/betweenness.py index 210e1f0a2b2..ba2b3d9c895 100644 --- a/python/nx-cugraph/nx_cugraph/algorithms/centrality/betweenness.py +++ b/python/nx-cugraph/nx_cugraph/algorithms/centrality/betweenness.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023, NVIDIA CORPORATION. +# Copyright (c) 2023-2024, NVIDIA CORPORATION. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -18,11 +18,16 @@ __all__ = ["betweenness_centrality", "edge_betweenness_centrality"] -@networkx_algorithm +@networkx_algorithm( + is_incomplete=True, # weight not supported + is_different=True, # RNG with seed is different + plc="betweenness_centrality", + version_added="23.10", +) def betweenness_centrality( G, k=None, normalized=True, weight=None, endpoints=False, seed=None ): - """`weight` parameter is not yet supported.""" + """`weight` parameter is not yet supported, and RNG with seed may be different.""" if weight is not None: raise NotImplementedError( "Weighted implementation of betweenness centrality not currently supported" @@ -46,9 +51,14 @@ def _(G, k=None, normalized=True, weight=None, endpoints=False, seed=None): return weight is None -@networkx_algorithm +@networkx_algorithm( + is_incomplete=True, # weight not supported + is_different=True, # RNG with seed is different + plc="edge_betweenness_centrality", + version_added="23.10", +) def edge_betweenness_centrality(G, k=None, normalized=True, weight=None, seed=None): - """`weight` parameter is not yet supported.""" + """`weight` parameter is not yet supported, and RNG with seed may be different.""" if weight is not None: raise NotImplementedError( "Weighted implementation of betweenness centrality not currently supported" diff --git a/python/nx-cugraph/nx_cugraph/algorithms/centrality/degree_alg.py b/python/nx-cugraph/nx_cugraph/algorithms/centrality/degree_alg.py index 0b2fd24af79..a319eb3a12c 100644 --- a/python/nx-cugraph/nx_cugraph/algorithms/centrality/degree_alg.py +++ b/python/nx-cugraph/nx_cugraph/algorithms/centrality/degree_alg.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023, NVIDIA CORPORATION. +# Copyright (c) 2023-2024, NVIDIA CORPORATION. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -16,7 +16,7 @@ __all__ = ["degree_centrality", "in_degree_centrality", "out_degree_centrality"] -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def degree_centrality(G): G = _to_graph(G) if len(G) <= 1: @@ -27,7 +27,7 @@ def degree_centrality(G): @not_implemented_for("undirected") -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def in_degree_centrality(G): G = _to_directed_graph(G) if len(G) <= 1: @@ -38,7 +38,7 @@ def in_degree_centrality(G): @not_implemented_for("undirected") -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def out_degree_centrality(G): G = _to_directed_graph(G) if len(G) <= 1: diff --git a/python/nx-cugraph/nx_cugraph/algorithms/centrality/eigenvector.py b/python/nx-cugraph/nx_cugraph/algorithms/centrality/eigenvector.py index c0f02a6258e..9e615955a8b 100644 --- a/python/nx-cugraph/nx_cugraph/algorithms/centrality/eigenvector.py +++ b/python/nx-cugraph/nx_cugraph/algorithms/centrality/eigenvector.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023, NVIDIA CORPORATION. +# Copyright (c) 2023-2024, NVIDIA CORPORATION. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -26,7 +26,12 @@ @not_implemented_for("multigraph") -@networkx_algorithm(extra_params=_dtype_param) +@networkx_algorithm( + extra_params=_dtype_param, + is_incomplete=True, # nstart not supported + plc="eigenvector_centrality", + version_added="23.12", +) def eigenvector_centrality( G, max_iter=100, tol=1.0e-6, nstart=None, weight=None, *, dtype=None ): diff --git a/python/nx-cugraph/nx_cugraph/algorithms/centrality/katz.py b/python/nx-cugraph/nx_cugraph/algorithms/centrality/katz.py index b61b811b8fa..a2fb950c1aa 100644 --- a/python/nx-cugraph/nx_cugraph/algorithms/centrality/katz.py +++ b/python/nx-cugraph/nx_cugraph/algorithms/centrality/katz.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023, NVIDIA CORPORATION. +# Copyright (c) 2023-2024, NVIDIA CORPORATION. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -26,7 +26,12 @@ @not_implemented_for("multigraph") -@networkx_algorithm(extra_params=_dtype_param) +@networkx_algorithm( + extra_params=_dtype_param, + is_incomplete=True, # nstart and normalized=False not supported + plc="katz_centrality", + version_added="23.12", +) def katz_centrality( G, alpha=0.1, diff --git a/python/nx-cugraph/nx_cugraph/algorithms/community/louvain.py b/python/nx-cugraph/nx_cugraph/algorithms/community/louvain.py index 936d837dacd..d023bab1a47 100644 --- a/python/nx-cugraph/nx_cugraph/algorithms/community/louvain.py +++ b/python/nx-cugraph/nx_cugraph/algorithms/community/louvain.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023, NVIDIA CORPORATION. +# Copyright (c) 2023-2024, NVIDIA CORPORATION. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -35,7 +35,11 @@ "Upper limit of the number of macro-iterations (max: 500)." ), **_dtype_param, - } + }, + is_incomplete=True, # seed not supported; self-loops not supported + is_different=True, # RNG different + plc="louvain", + version_added="23.10", ) def louvain_communities( G, @@ -47,7 +51,7 @@ def louvain_communities( max_level=None, dtype=None, ): - """`seed` parameter is currently ignored.""" + """`seed` parameter is currently ignored, and self-loops are not yet supported.""" # NetworkX allows both directed and undirected, but cugraph only allows undirected. seed = _seed_to_int(seed) # Unused, but ensure it's valid for future compatibility G = _to_undirected_graph(G, weight) diff --git a/python/nx-cugraph/nx_cugraph/algorithms/components/connected.py b/python/nx-cugraph/nx_cugraph/algorithms/components/connected.py index 41f3457d542..cb12aed1d39 100644 --- a/python/nx-cugraph/nx_cugraph/algorithms/components/connected.py +++ b/python/nx-cugraph/nx_cugraph/algorithms/components/connected.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023, NVIDIA CORPORATION. +# Copyright (c) 2023-2024, NVIDIA CORPORATION. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -30,7 +30,7 @@ @not_implemented_for("directed") -@networkx_algorithm +@networkx_algorithm(plc="weakly_connected_components", version_added="23.12") def number_connected_components(G): return sum(1 for _ in connected_components(G)) # PREFERRED IMPLEMENTATION, BUT PLC DOES NOT HANDLE ISOLATED VERTICES WELL @@ -57,7 +57,7 @@ def _(G): @not_implemented_for("directed") -@networkx_algorithm +@networkx_algorithm(plc="weakly_connected_components", version_added="23.12") def connected_components(G): G = _to_undirected_graph(G) if G.src_indices.size == 0: @@ -86,7 +86,7 @@ def connected_components(G): @not_implemented_for("directed") -@networkx_algorithm +@networkx_algorithm(plc="weakly_connected_components", version_added="23.12") def is_connected(G): G = _to_undirected_graph(G) if len(G) == 0: @@ -110,7 +110,7 @@ def is_connected(G): @not_implemented_for("directed") -@networkx_algorithm +@networkx_algorithm(plc="weakly_connected_components", version_added="23.12") def node_connected_component(G, n): # We could also do plain BFS from n G = _to_undirected_graph(G) diff --git a/python/nx-cugraph/nx_cugraph/algorithms/core.py b/python/nx-cugraph/nx_cugraph/algorithms/core.py index c00df2d832f..e4520c2713b 100644 --- a/python/nx-cugraph/nx_cugraph/algorithms/core.py +++ b/python/nx-cugraph/nx_cugraph/algorithms/core.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023, NVIDIA CORPORATION. +# Copyright (c) 2023-2024, NVIDIA CORPORATION. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -27,7 +27,7 @@ @not_implemented_for("directed") @not_implemented_for("multigraph") -@networkx_algorithm +@networkx_algorithm(is_incomplete=True, plc="k_truss_subgraph", version_added="23.12") def k_truss(G, k): """ Currently raises `NotImplementedError` for graphs with more than one connected diff --git a/python/nx-cugraph/nx_cugraph/algorithms/dag.py b/python/nx-cugraph/nx_cugraph/algorithms/dag.py index 067cfed9101..ad5b7594aa1 100644 --- a/python/nx-cugraph/nx_cugraph/algorithms/dag.py +++ b/python/nx-cugraph/nx_cugraph/algorithms/dag.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023, NVIDIA CORPORATION. +# Copyright (c) 2023-2024, NVIDIA CORPORATION. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -45,11 +45,11 @@ def _ancestors_and_descendants(G, source, *, is_ancestors): return G._nodearray_to_set(node_ids[mask]) -@networkx_algorithm +@networkx_algorithm(plc="bfs", version_added="24.02") def descendants(G, source): return _ancestors_and_descendants(G, source, is_ancestors=False) -@networkx_algorithm +@networkx_algorithm(plc="bfs", version_added="24.02") def ancestors(G, source): return _ancestors_and_descendants(G, source, is_ancestors=True) diff --git a/python/nx-cugraph/nx_cugraph/algorithms/isolate.py b/python/nx-cugraph/nx_cugraph/algorithms/isolate.py index d32223fb3ed..c7e5d7113de 100644 --- a/python/nx-cugraph/nx_cugraph/algorithms/isolate.py +++ b/python/nx-cugraph/nx_cugraph/algorithms/isolate.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023, NVIDIA CORPORATION. +# Copyright (c) 2023-2024, NVIDIA CORPORATION. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -25,7 +25,7 @@ __all__ = ["is_isolate", "isolates", "number_of_isolates"] -@networkx_algorithm +@networkx_algorithm(version_added="23.10") def is_isolate(G, n): G = _to_graph(G) index = n if G.key_to_id is None else G.key_to_id[n] @@ -51,13 +51,13 @@ def _isolates(G) -> cp.ndarray[IndexValue]: return cp.nonzero(_mark_isolates(G))[0] -@networkx_algorithm +@networkx_algorithm(version_added="23.10") def isolates(G): G = _to_graph(G) return G._nodeiter_to_iter(iter(_isolates(G).tolist())) -@networkx_algorithm +@networkx_algorithm(version_added="23.10") def number_of_isolates(G): G = _to_graph(G) return _mark_isolates(G).sum().tolist() diff --git a/python/nx-cugraph/nx_cugraph/algorithms/link_analysis/hits_alg.py b/python/nx-cugraph/nx_cugraph/algorithms/link_analysis/hits_alg.py index 1c8a47c24b1..caa01327a56 100644 --- a/python/nx-cugraph/nx_cugraph/algorithms/link_analysis/hits_alg.py +++ b/python/nx-cugraph/nx_cugraph/algorithms/link_analysis/hits_alg.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023, NVIDIA CORPORATION. +# Copyright (c) 2023-2024, NVIDIA CORPORATION. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -32,7 +32,9 @@ "The edge attribute to use as the edge weight." ), **_dtype_param, - } + }, + plc="hits", + version_added="23.12", ) def hits( G, diff --git a/python/nx-cugraph/nx_cugraph/algorithms/link_analysis/pagerank_alg.py b/python/nx-cugraph/nx_cugraph/algorithms/link_analysis/pagerank_alg.py index 63f6e89c33a..d45d019c1b7 100644 --- a/python/nx-cugraph/nx_cugraph/algorithms/link_analysis/pagerank_alg.py +++ b/python/nx-cugraph/nx_cugraph/algorithms/link_analysis/pagerank_alg.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023, NVIDIA CORPORATION. +# Copyright (c) 2023-2024, NVIDIA CORPORATION. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -26,7 +26,12 @@ __all__ = ["pagerank"] -@networkx_algorithm(extra_params=_dtype_param) +@networkx_algorithm( + extra_params=_dtype_param, + is_incomplete=True, # dangling not supported + plc={"pagerank", "personalized_pagerank"}, + version_added="23.12", +) def pagerank( G, alpha=0.85, @@ -97,7 +102,7 @@ def pagerank( @pagerank._can_run -def pagerank( +def _( G, alpha=0.85, personalization=None, diff --git a/python/nx-cugraph/nx_cugraph/algorithms/shortest_paths/unweighted.py b/python/nx-cugraph/nx_cugraph/algorithms/shortest_paths/unweighted.py index 3413a637b32..b1032a8236b 100644 --- a/python/nx-cugraph/nx_cugraph/algorithms/shortest_paths/unweighted.py +++ b/python/nx-cugraph/nx_cugraph/algorithms/shortest_paths/unweighted.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023, NVIDIA CORPORATION. +# Copyright (c) 2023-2024, NVIDIA CORPORATION. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -21,12 +21,12 @@ __all__ = ["single_source_shortest_path_length", "single_target_shortest_path_length"] -@networkx_algorithm +@networkx_algorithm(plc="bfs", version_added="23.12") def single_source_shortest_path_length(G, source, cutoff=None): return _single_shortest_path_length(G, source, cutoff, "Source") -@networkx_algorithm +@networkx_algorithm(plc="bfs", version_added="23.12") def single_target_shortest_path_length(G, target, cutoff=None): return _single_shortest_path_length(G, target, cutoff, "Target") diff --git a/python/nx-cugraph/nx_cugraph/algorithms/traversal/breadth_first_search.py b/python/nx-cugraph/nx_cugraph/algorithms/traversal/breadth_first_search.py index e2a7d46f462..aa671bbb7d4 100644 --- a/python/nx-cugraph/nx_cugraph/algorithms/traversal/breadth_first_search.py +++ b/python/nx-cugraph/nx_cugraph/algorithms/traversal/breadth_first_search.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023, NVIDIA CORPORATION. +# Copyright (c) 2023-2024, NVIDIA CORPORATION. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -57,7 +57,7 @@ def _bfs(G, source, *, depth_limit=None, reverse=False): return distances[mask], predecessors[mask], node_ids[mask] -@networkx_algorithm +@networkx_algorithm(is_incomplete=True, plc="bfs", version_added="24.02") def generic_bfs_edges(G, source, neighbors=None, depth_limit=None, sort_neighbors=None): """`neighbors` and `sort_neighbors` parameters are not yet supported.""" return bfs_edges(source, depth_limit=depth_limit) @@ -68,7 +68,7 @@ def _(G, source, neighbors=None, depth_limit=None, sort_neighbors=None): return neighbors is None and sort_neighbors is None -@networkx_algorithm +@networkx_algorithm(is_incomplete=True, plc="bfs", version_added="24.02") def bfs_edges(G, source, reverse=False, depth_limit=None, sort_neighbors=None): """`sort_neighbors` parameter is not yet supported.""" G = _check_G_and_source(G, source) @@ -95,7 +95,7 @@ def _(G, source, reverse=False, depth_limit=None, sort_neighbors=None): return sort_neighbors is None -@networkx_algorithm +@networkx_algorithm(is_incomplete=True, plc="bfs", version_added="24.02") def bfs_tree(G, source, reverse=False, depth_limit=None, sort_neighbors=None): """`sort_neighbors` parameter is not yet supported.""" G = _check_G_and_source(G, source) @@ -149,7 +149,7 @@ def _(G, source, reverse=False, depth_limit=None, sort_neighbors=None): return sort_neighbors is None -@networkx_algorithm +@networkx_algorithm(is_incomplete=True, plc="bfs", version_added="24.02") def bfs_successors(G, source, depth_limit=None, sort_neighbors=None): """`sort_neighbors` parameter is not yet supported.""" G = _check_G_and_source(G, source) @@ -173,7 +173,7 @@ def _(G, source, depth_limit=None, sort_neighbors=None): return sort_neighbors is None -@networkx_algorithm +@networkx_algorithm(plc="bfs", version_added="24.02") def bfs_layers(G, sources): G = _to_graph(G) if sources in G: @@ -201,7 +201,7 @@ def bfs_layers(G, sources): return (G._nodearray_to_list(groups[key]) for key in range(len(groups))) -@networkx_algorithm +@networkx_algorithm(is_incomplete=True, plc="bfs", version_added="24.02") def bfs_predecessors(G, source, depth_limit=None, sort_neighbors=None): """`sort_neighbors` parameter is not yet supported.""" G = _check_G_and_source(G, source) @@ -227,7 +227,7 @@ def _(G, source, depth_limit=None, sort_neighbors=None): return sort_neighbors is None -@networkx_algorithm +@networkx_algorithm(plc="bfs", version_added="24.02") def descendants_at_distance(G, source, distance): G = _check_G_and_source(G, source) if distance is None or distance < 0: diff --git a/python/nx-cugraph/nx_cugraph/classes/function.py b/python/nx-cugraph/nx_cugraph/classes/function.py index 633e4abd7f4..435dfe37239 100644 --- a/python/nx-cugraph/nx_cugraph/classes/function.py +++ b/python/nx-cugraph/nx_cugraph/classes/function.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023, NVIDIA CORPORATION. +# Copyright (c) 2023-2024, NVIDIA CORPORATION. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -16,7 +16,7 @@ __all__ = ["number_of_selfloops"] -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def number_of_selfloops(G): G = _to_graph(G) is_selfloop = G.src_indices == G.dst_indices diff --git a/python/nx-cugraph/nx_cugraph/convert_matrix.py b/python/nx-cugraph/nx_cugraph/convert_matrix.py index 80ca0c2fa4b..1a2ecde9b8c 100644 --- a/python/nx-cugraph/nx_cugraph/convert_matrix.py +++ b/python/nx-cugraph/nx_cugraph/convert_matrix.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023, NVIDIA CORPORATION. +# Copyright (c) 2023-2024, NVIDIA CORPORATION. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -23,7 +23,8 @@ ] -@networkx_algorithm +# Value columns with string dtype is not supported +@networkx_algorithm(is_incomplete=True, version_added="23.12") def from_pandas_edgelist( df, source="source", @@ -32,7 +33,7 @@ def from_pandas_edgelist( create_using=None, edge_key=None, ): - """cudf.DataFrame inputs also supported.""" + """cudf.DataFrame inputs also supported; value columns with str is unsuppported.""" graph_class, inplace = _create_using_class(create_using) src_array = df[source].to_numpy() dst_array = df[target].to_numpy() @@ -120,7 +121,7 @@ def from_pandas_edgelist( return G -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def from_scipy_sparse_array( A, parallel_edges=False, create_using=None, edge_attribute="weight" ): diff --git a/python/nx-cugraph/nx_cugraph/generators/classic.py b/python/nx-cugraph/nx_cugraph/generators/classic.py index 4213e6dd2a0..a548beea34f 100644 --- a/python/nx-cugraph/nx_cugraph/generators/classic.py +++ b/python/nx-cugraph/nx_cugraph/generators/classic.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023, NVIDIA CORPORATION. +# Copyright (c) 2023-2024, NVIDIA CORPORATION. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -51,7 +51,7 @@ concat = itertools.chain.from_iterable -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def barbell_graph(m1, m2, create_using=None): # Like two complete graphs and a path_graph m1 = _ensure_nonnegative_int(m1) @@ -81,12 +81,12 @@ def barbell_graph(m1, m2, create_using=None): return G -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def circular_ladder_graph(n, create_using=None): return _ladder_graph(n, create_using, is_circular=True) -@networkx_algorithm(nodes_or_number=0) +@networkx_algorithm(nodes_or_number=0, version_added="23.12") def complete_graph(n, create_using=None): n, nodes = _number_and_nodes(n) if n < 3: @@ -99,7 +99,7 @@ def complete_graph(n, create_using=None): return G -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def complete_multipartite_graph(*subset_sizes): if not subset_sizes: return nxcg.Graph() @@ -142,7 +142,7 @@ def complete_multipartite_graph(*subset_sizes): ) -@networkx_algorithm(nodes_or_number=0) +@networkx_algorithm(nodes_or_number=0, version_added="23.12") def cycle_graph(n, create_using=None): n, nodes = _number_and_nodes(n) graph_class, inplace = _create_using_class(create_using) @@ -172,7 +172,7 @@ def cycle_graph(n, create_using=None): return G -@networkx_algorithm(nodes_or_number=0) +@networkx_algorithm(nodes_or_number=0, version_added="23.12") def empty_graph(n=0, create_using=None, default=nx.Graph): n, nodes = _number_and_nodes(n) graph_class, inplace = _create_using_class(create_using, default=default) @@ -234,12 +234,12 @@ def _ladder_graph(n, create_using, *, is_circular=False): return G -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def ladder_graph(n, create_using=None): return _ladder_graph(n, create_using) -@networkx_algorithm(nodes_or_number=[0, 1]) +@networkx_algorithm(nodes_or_number=[0, 1], version_added="23.12") def lollipop_graph(m, n, create_using=None): # Like complete_graph then path_graph orig_m, unused_nodes_m = m @@ -274,12 +274,12 @@ def lollipop_graph(m, n, create_using=None): return G -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def null_graph(create_using=None): return _common_small_graph(0, None, create_using) -@networkx_algorithm(nodes_or_number=0) +@networkx_algorithm(nodes_or_number=0, version_added="23.12") def path_graph(n, create_using=None): n, nodes = _number_and_nodes(n) graph_class, inplace = _create_using_class(create_using) @@ -299,7 +299,7 @@ def path_graph(n, create_using=None): return G -@networkx_algorithm(nodes_or_number=0) +@networkx_algorithm(nodes_or_number=0, version_added="23.12") def star_graph(n, create_using=None): orig_n, orig_nodes = n n, nodes = _number_and_nodes(n) @@ -323,7 +323,7 @@ def star_graph(n, create_using=None): return G -@networkx_algorithm(nodes_or_number=[0, 1]) +@networkx_algorithm(nodes_or_number=[0, 1], version_added="23.12") def tadpole_graph(m, n, create_using=None): orig_m, unused_nodes_m = m orig_n, unused_nodes_n = n @@ -361,12 +361,12 @@ def tadpole_graph(m, n, create_using=None): return G -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def trivial_graph(create_using=None): return _common_small_graph(1, None, create_using) -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def turan_graph(n, r): if not 1 <= r <= n: raise nx.NetworkXError("Must satisfy 1 <= r <= n") @@ -375,7 +375,7 @@ def turan_graph(n, r): return complete_multipartite_graph(*partitions) -@networkx_algorithm(nodes_or_number=0) +@networkx_algorithm(nodes_or_number=0, version_added="23.12") def wheel_graph(n, create_using=None): n, nodes = _number_and_nodes(n) graph_class, inplace = _create_using_class(create_using) diff --git a/python/nx-cugraph/nx_cugraph/generators/community.py b/python/nx-cugraph/nx_cugraph/generators/community.py index e5cb03e8cc0..9b0e0848de9 100644 --- a/python/nx-cugraph/nx_cugraph/generators/community.py +++ b/python/nx-cugraph/nx_cugraph/generators/community.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023, NVIDIA CORPORATION. +# Copyright (c) 2023-2024, NVIDIA CORPORATION. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -27,7 +27,7 @@ ] -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def caveman_graph(l, k): # noqa: E741 l = _ensure_int(l) # noqa: E741 k = _ensure_int(k) diff --git a/python/nx-cugraph/nx_cugraph/generators/small.py b/python/nx-cugraph/nx_cugraph/generators/small.py index b9a189c31d5..45487571cda 100644 --- a/python/nx-cugraph/nx_cugraph/generators/small.py +++ b/python/nx-cugraph/nx_cugraph/generators/small.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023, NVIDIA CORPORATION. +# Copyright (c) 2023-2024, NVIDIA CORPORATION. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -43,7 +43,7 @@ ] -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def bull_graph(create_using=None): graph_class, inplace = _create_using_class(create_using) if graph_class.is_directed(): @@ -56,7 +56,7 @@ def bull_graph(create_using=None): return G -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def chvatal_graph(create_using=None): graph_class, inplace = _create_using_class(create_using) if graph_class.is_directed(): @@ -85,7 +85,7 @@ def chvatal_graph(create_using=None): return G -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def cubical_graph(create_using=None): graph_class, inplace = _create_using_class(create_using) if graph_class.is_directed(): @@ -105,7 +105,7 @@ def cubical_graph(create_using=None): return G -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def desargues_graph(create_using=None): # This can also be defined w.r.t. LCF_graph graph_class, inplace = _create_using_class(create_using) @@ -146,7 +146,7 @@ def desargues_graph(create_using=None): return G -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def diamond_graph(create_using=None): graph_class, inplace = _create_using_class(create_using) if graph_class.is_directed(): @@ -159,7 +159,7 @@ def diamond_graph(create_using=None): return G -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def dodecahedral_graph(create_using=None): # This can also be defined w.r.t. LCF_graph graph_class, inplace = _create_using_class(create_using) @@ -200,7 +200,7 @@ def dodecahedral_graph(create_using=None): return G -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def frucht_graph(create_using=None): graph_class, inplace = _create_using_class(create_using) if graph_class.is_directed(): @@ -235,7 +235,7 @@ def frucht_graph(create_using=None): return G -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def heawood_graph(create_using=None): # This can also be defined w.r.t. LCF_graph graph_class, inplace = _create_using_class(create_using) @@ -274,7 +274,7 @@ def heawood_graph(create_using=None): return G -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def house_graph(create_using=None): graph_class, inplace = _create_using_class(create_using) if graph_class.is_directed(): @@ -287,7 +287,7 @@ def house_graph(create_using=None): return G -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def house_x_graph(create_using=None): graph_class, inplace = _create_using_class(create_using) if graph_class.is_directed(): @@ -306,7 +306,7 @@ def house_x_graph(create_using=None): return G -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def icosahedral_graph(create_using=None): graph_class, inplace = _create_using_class(create_using) if graph_class.is_directed(): @@ -337,7 +337,7 @@ def icosahedral_graph(create_using=None): return G -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def krackhardt_kite_graph(create_using=None): graph_class, inplace = _create_using_class(create_using) if graph_class.is_directed(): @@ -366,7 +366,7 @@ def krackhardt_kite_graph(create_using=None): return G -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def moebius_kantor_graph(create_using=None): # This can also be defined w.r.t. LCF_graph graph_class, inplace = _create_using_class(create_using) @@ -407,7 +407,7 @@ def moebius_kantor_graph(create_using=None): return G -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def octahedral_graph(create_using=None): graph_class, inplace = _create_using_class(create_using) if graph_class.is_directed(): @@ -428,7 +428,7 @@ def octahedral_graph(create_using=None): return G -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def pappus_graph(): # This can also be defined w.r.t. LCF_graph # fmt: off @@ -452,7 +452,7 @@ def pappus_graph(): return nxcg.Graph.from_coo(18, src_indices, dst_indices, name="Pappus Graph") -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def petersen_graph(create_using=None): graph_class, inplace = _create_using_class(create_using) if graph_class.is_directed(): @@ -479,7 +479,7 @@ def petersen_graph(create_using=None): return G -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def sedgewick_maze_graph(create_using=None): graph_class, inplace = _create_using_class(create_using) if graph_class.is_directed(): @@ -500,7 +500,7 @@ def sedgewick_maze_graph(create_using=None): return G -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def tetrahedral_graph(create_using=None): # This can also be defined w.r.t. complete_graph graph_class, inplace = _create_using_class(create_using) @@ -517,7 +517,7 @@ def tetrahedral_graph(create_using=None): return G -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def truncated_cube_graph(create_using=None): graph_class, inplace = _create_using_class(create_using) if graph_class.is_directed(): @@ -548,7 +548,7 @@ def truncated_cube_graph(create_using=None): return G -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def truncated_tetrahedron_graph(create_using=None): graph_class, inplace = _create_using_class(create_using) if graph_class.is_directed(): @@ -583,7 +583,7 @@ def truncated_tetrahedron_graph(create_using=None): return G -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def tutte_graph(create_using=None): graph_class, inplace = _create_using_class(create_using) if graph_class.is_directed(): diff --git a/python/nx-cugraph/nx_cugraph/generators/social.py b/python/nx-cugraph/nx_cugraph/generators/social.py index 3c936d07af3..07e82c63fbf 100644 --- a/python/nx-cugraph/nx_cugraph/generators/social.py +++ b/python/nx-cugraph/nx_cugraph/generators/social.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023, NVIDIA CORPORATION. +# Copyright (c) 2023-2024, NVIDIA CORPORATION. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -25,7 +25,7 @@ ] -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def davis_southern_women_graph(): # fmt: off src_indices = cp.array( @@ -88,7 +88,7 @@ def davis_southern_women_graph(): ) -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def florentine_families_graph(): # fmt: off src_indices = cp.array( @@ -114,7 +114,7 @@ def florentine_families_graph(): return nxcg.Graph.from_coo(15, src_indices, dst_indices, id_to_key=nodes) -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def karate_club_graph(): # fmt: off src_indices = cp.array( @@ -175,7 +175,7 @@ def karate_club_graph(): ) -@networkx_algorithm +@networkx_algorithm(version_added="23.12") def les_miserables_graph(): # fmt: off src_indices = cp.array( diff --git a/python/nx-cugraph/nx_cugraph/scripts/__init__.py b/python/nx-cugraph/nx_cugraph/scripts/__init__.py new file mode 100644 index 00000000000..aeae6078111 --- /dev/null +++ b/python/nx-cugraph/nx_cugraph/scripts/__init__.py @@ -0,0 +1,12 @@ +# Copyright (c) 2024, NVIDIA CORPORATION. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/python/nx-cugraph/nx_cugraph/scripts/__main__.py b/python/nx-cugraph/nx_cugraph/scripts/__main__.py new file mode 100755 index 00000000000..c0963e64cc5 --- /dev/null +++ b/python/nx-cugraph/nx_cugraph/scripts/__main__.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python +# Copyright (c) 2024, NVIDIA CORPORATION. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +if __name__ == "__main__": + import argparse + + from nx_cugraph.scripts import print_table, print_tree + + parser = argparse.ArgumentParser( + parents=[ + print_table.get_argumentparser(add_help=False), + print_tree.get_argumentparser(add_help=False), + ], + description="Print info about functions implemented by nx-cugraph", + ) + parser.add_argument("action", choices=["print_table", "print_tree"]) + args = parser.parse_args() + if args.action == "print_table": + print_table.main() + else: + print_tree.main( + by=args.by, + networkx_path=args.networkx_path, + dispatch_name=args.dispatch_name or args.dispatch_name_always, + version_added=args.version_added, + plc=args.plc, + dispatch_name_if_different=not args.dispatch_name_always, + ) diff --git a/python/nx-cugraph/nx_cugraph/scripts/print_table.py b/python/nx-cugraph/nx_cugraph/scripts/print_table.py new file mode 100755 index 00000000000..7e69de63dc1 --- /dev/null +++ b/python/nx-cugraph/nx_cugraph/scripts/print_table.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python +# Copyright (c) 2024, NVIDIA CORPORATION. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import argparse +import sys +from collections import namedtuple + +from networkx.utils.backends import _registered_algorithms as algos + +from _nx_cugraph import get_info +from nx_cugraph.interface import BackendInterface + + +def get_funcpath(func): + return f"{func.__module__}.{func.__name__}" + + +def get_path_to_name(): + return { + get_funcpath(algos[funcname]): funcname + for funcname in get_info()["functions"].keys() & algos.keys() + } + + +Info = namedtuple( + "Info", + "networkx_path, dispatch_name, version_added, plc, is_incomplete, is_different", +) + + +def get_path_to_info(path_to_name=None, version_added_sep=".", plc_sep="/"): + if path_to_name is None: + path_to_name = get_path_to_name() + rv = {} + for funcpath in sorted(path_to_name): + funcname = path_to_name[funcpath] + cufunc = getattr(BackendInterface, funcname) + plc = plc_sep.join(sorted(cufunc._plc_names)) if cufunc._plc_names else "" + version_added = cufunc.version_added.replace(".", version_added_sep) + is_incomplete = cufunc.is_incomplete + is_different = cufunc.is_different + rv[funcpath] = Info( + funcpath, funcname, version_added, plc, is_incomplete, is_different + ) + return rv + + +def main(path_to_info=None, *, file=sys.stdout): + if path_to_info is None: + path_to_info = get_path_to_info(version_added_sep=".") + lines = ["networkx_path,dispatch_name,version_added,plc,is_incomplete,is_different"] + lines.extend(",".join(info) for info in path_to_info.values()) + text = "\n".join(lines) + print(text, file=file) + return text + + +def get_argumentparser(add_help=True): + return argparse.ArgumentParser( + description="Print info about functions implemented by nx-cugraph as CSV", + add_help=add_help, + ) + + +if __name__ == "__main__": + parser = get_argumentparser() + args = parser.parse_args() + main() diff --git a/python/nx-cugraph/nx_cugraph/scripts/print_tree.py b/python/nx-cugraph/nx_cugraph/scripts/print_tree.py new file mode 100755 index 00000000000..bb75d735c31 --- /dev/null +++ b/python/nx-cugraph/nx_cugraph/scripts/print_tree.py @@ -0,0 +1,241 @@ +#!/usr/bin/env python +# Copyright (c) 2024, NVIDIA CORPORATION. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import argparse +import re +import sys + +import networkx as nx + +from nx_cugraph.scripts.print_table import get_path_to_info + + +def add_branch(G, path, extra="", *, skip=0): + branch = path.split(".") + prev = ".".join(branch[: skip + 1]) + for i in range(skip + 2, len(branch)): + cur = ".".join(branch[:i]) + G.add_edge(prev, cur) + prev = cur + if extra: + if not isinstance(extra, str): + extra = ", ".join(extra) + path += f" ({extra})" + G.add_edge(prev, path) + + +def get_extra( + info, + *, + networkx_path=False, + dispatch_name=False, + version_added=False, + plc=False, + dispatch_name_if_different=False, + incomplete=False, + different=False, +): + extra = [] + if networkx_path: + extra.append(info.networkx_path) + if dispatch_name and ( + not dispatch_name_if_different + or info.dispatch_name != info.networkx_path.rsplit(".", 1)[-1] + ): + extra.append(info.dispatch_name) + if version_added: + v = info.version_added + if len(v) != 5: + raise ValueError(f"Is there something wrong with version: {v!r}?") + extra.append(v[:2] + "." + v[-2:]) + if plc and info.plc: + extra.append(info.plc) + if incomplete and info.is_incomplete: + extra.append("is-incomplete") + if different and info.is_different: + extra.append("is-different") + return extra + + +def create_tree( + path_to_info=None, + *, + by="networkx_path", + skip=0, + networkx_path=False, + dispatch_name=False, + version_added=False, + plc=False, + dispatch_name_if_different=False, + incomplete=False, + different=False, + prefix="", +): + if path_to_info is None: + path_to_info = get_path_to_info() + if isinstance(by, str): + by = [by] + G = nx.DiGraph() + for info in sorted( + path_to_info.values(), + key=lambda x: (*(getattr(x, b) for b in by), x.networkx_path), + ): + if not all(getattr(info, b) for b in by): + continue + path = prefix + ".".join(getattr(info, b) for b in by) + extra = get_extra( + info, + networkx_path=networkx_path, + dispatch_name=dispatch_name, + version_added=version_added, + plc=plc, + dispatch_name_if_different=dispatch_name_if_different, + incomplete=incomplete, + different=different, + ) + add_branch(G, path, extra=extra, skip=skip) + return G + + +def main( + path_to_info=None, + *, + by="networkx_path", + networkx_path=False, + dispatch_name=False, + version_added=False, + plc=False, + dispatch_name_if_different=True, + incomplete=False, + different=False, + file=sys.stdout, +): + if path_to_info is None: + path_to_info = get_path_to_info(version_added_sep="-") + kwargs = { + "networkx_path": networkx_path, + "dispatch_name": dispatch_name, + "version_added": version_added, + "plc": plc, + "dispatch_name_if_different": dispatch_name_if_different, + "incomplete": incomplete, + "different": different, + } + if by == "networkx_path": + G = create_tree(path_to_info, by="networkx_path", **kwargs) + text = re.sub(r"[A-Za-z_\./]+\.", "", ("\n".join(nx.generate_network_text(G)))) + elif by == "plc": + G = create_tree( + path_to_info, by=["plc", "networkx_path"], prefix="plc-", **kwargs + ) + text = re.sub( + "plc-", + "plc.", + re.sub( + r" plc-[A-Za-z_\./]*\.", + " ", + "\n".join(nx.generate_network_text(G)), + ), + ) + elif by == "version_added": + G = create_tree( + path_to_info, + by=["version_added", "networkx_path"], + prefix="version_added-", + **kwargs, + ) + text = re.sub( + "version_added-", + "version: ", + re.sub( + r" version_added-[-0-9A-Za-z_\./]*\.", + " ", + "\n".join(nx.generate_network_text(G)), + ), + ).replace("-", ".") + else: + raise ValueError( + "`by` argument should be one of {'networkx_path', 'plc', 'version_added' " + f"got: {by}" + ) + print(text, file=file) + return text + + +def get_argumentparser(add_help=True): + parser = argparse.ArgumentParser( + "Print a tree showing NetworkX functions implemented by nx-cugraph", + add_help=add_help, + ) + parser.add_argument( + "--by", + choices=["networkx_path", "plc", "version_added"], + default="networkx_path", + help="How to group functions", + ) + parser.add_argument( + "--dispatch-name", + "--dispatch_name", + action="store_true", + help="Show the dispatch name in parentheses if different from NetworkX name", + ) + parser.add_argument( + "--dispatch-name-always", + "--dispatch_name_always", + action="store_true", + help="Always show the dispatch name in parentheses", + ) + parser.add_argument( + "--plc", + "--pylibcugraph", + action="store_true", + help="Show the used pylibcugraph function in parentheses", + ) + parser.add_argument( + "--version-added", + "--version_added", + action="store_true", + help="Show the version added in parentheses", + ) + parser.add_argument( + "--networkx-path", + "--networkx_path", + action="store_true", + help="Show the full networkx path in parentheses", + ) + parser.add_argument( + "--incomplete", + action="store_true", + help="Show which functions are incomplete", + ) + parser.add_argument( + "--different", + action="store_true", + help="Show which functions are different", + ) + return parser + + +if __name__ == "__main__": + parser = get_argumentparser() + args = parser.parse_args() + main( + by=args.by, + networkx_path=args.networkx_path, + dispatch_name=args.dispatch_name or args.dispatch_name_always, + version_added=args.version_added, + plc=args.plc, + dispatch_name_if_different=not args.dispatch_name_always, + incomplete=args.incomplete, + different=args.different, + ) diff --git a/python/nx-cugraph/nx_cugraph/utils/decorators.py b/python/nx-cugraph/nx_cugraph/utils/decorators.py index a0dbfcec890..d09a9e9617a 100644 --- a/python/nx-cugraph/nx_cugraph/utils/decorators.py +++ b/python/nx-cugraph/nx_cugraph/utils/decorators.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023, NVIDIA CORPORATION. +# Copyright (c) 2023-2024, NVIDIA CORPORATION. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -41,14 +41,25 @@ class networkx_algorithm: name: str extra_doc: str | None extra_params: dict[str, str] | None + version_added: str + is_incomplete: bool + is_different: bool + _plc_names: set[str] | None def __new__( cls, func=None, *, name: str | None = None, + # Extra parameter info that is added to NetworkX docstring extra_params: dict[str, str] | str | None = None, + # Applies `nodes_or_number` decorator compatibly across versions (3.3 changed) nodes_or_number: list[int] | int | None = None, + # Metadata (for introspection only) + version_added: str, # Required + is_incomplete: bool = False, # See self.extra_doc for details if True + is_different: bool = False, # See self.extra_doc for details if True + plc: str | set[str] | None = None, # Hidden from user, may be removed someday ): if func is None: return partial( @@ -56,6 +67,10 @@ def __new__( name=name, extra_params=extra_params, nodes_or_number=nodes_or_number, + plc=plc, + version_added=version_added, + is_incomplete=is_incomplete, + is_different=is_different, ) instance = object.__new__(cls) if nodes_or_number is not None and nx.__version__[:3] > "3.2": @@ -74,6 +89,15 @@ def __new__( f"extra_params must be dict, str, or None; got {type(extra_params)}" ) instance.extra_params = extra_params + if plc is None or isinstance(plc, set): + instance._plc_names = plc + elif isinstance(plc, str): + instance._plc_names = {plc} + else: + raise TypeError(f"plc argument must be str, set, or None; got {type(plc)}") + instance.version_added = version_added + instance.is_incomplete = is_incomplete + instance.is_different = is_different # The docstring on our function is added to the NetworkX docstring. instance.extra_doc = ( dedent(func.__doc__.lstrip("\n").rstrip()) if func.__doc__ else None @@ -91,6 +115,11 @@ def __new__( def _can_run(self, func): """Set the `can_run` attribute to the decorated function.""" + if not func.__name__.startswith("_"): + raise ValueError( + "The name of the function used by `_can_run` must begin with '_'; " + f"got: {func.__name__!r}" + ) self.can_run = func def __call__(self, /, *args, **kwargs): diff --git a/python/nx-cugraph/pyproject.toml b/python/nx-cugraph/pyproject.toml index b29578b036f..63ac115918f 100644 --- a/python/nx-cugraph/pyproject.toml +++ b/python/nx-cugraph/pyproject.toml @@ -52,12 +52,20 @@ test = [ Homepage = "https://github.com/rapidsai/cugraph" Documentation = "https://docs.rapids.ai/api/cugraph/stable/" +# "plugin" used in nx version < 3.2 [project.entry-points."networkx.plugins"] cugraph = "nx_cugraph.interface:BackendInterface" [project.entry-points."networkx.plugin_info"] cugraph = "_nx_cugraph:get_info" +# "backend" used in nx version >= 3.2 +[project.entry-points."networkx.backends"] +cugraph = "nx_cugraph.interface:BackendInterface" + +[project.entry-points."networkx.backend_info"] +cugraph = "_nx_cugraph:get_info" + [tool.setuptools] license-files = ["LICENSE"]