Skip to content

Commit 6e28795

Browse files
authored
Fix edgecase when converting to networkx w/o fallback (rapidsai#118)
This fixes a (probably rare) case that I encountered when calling a function with `nxcg.Graph` and `backend="networkx"` when `nx.config.fallback_to_nx is False` and the function calls another networkx function. The `nxcg.Graph` is networkx-compatible, but it still has `__networkx_backend__ == "cugraph"`, so there are times when some behaviors may be different (but technically correct) b/c `__networkx_backend__` isn't `"networkx"`. So, we convert fully to networkx graph. An alternative would be to create a proxy graph that shares the data structures of the `nxcg.Graph` but has `G.__networkx_backend__ == "networkx"`, but the current approach is simplest and adequately covers what should be a very rare occurance. Regression test added. Authors: - Erik Welch (https://github.com/eriknw) Approvers: - Rick Ratzel (https://github.com/rlratzel) URL: rapidsai#118
1 parent 98d4e6b commit 6e28795

File tree

3 files changed

+18
-4
lines changed

3 files changed

+18
-4
lines changed

nx_cugraph/convert.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,10 @@ def to_networkx(
648648
"""
649649
if isinstance(G, nxcg.Graph):
650650
# These graphs are already NetworkX graphs :)
651+
if _nxver < (3, 4) or not nx.config.fallback_to_nx:
652+
# Convert to nx graph (so G.__networkx_backend == "networkx") for safety
653+
return G.to_networkx_class()(G)
654+
# Should be fine to duck-type as networkx graph; will cleanly fall back to nx
651655
return G
652656
rv = G.to_networkx_class()()
653657
id_to_key = G.id_to_key

nx_cugraph/interface.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@ def convert_from_nx(graph, *args, **kwargs):
3434

3535
@staticmethod
3636
def convert_to_nx(obj, *, name: str | None = None):
37-
if isinstance(obj, nxcg.CudaGraph):
38-
# Observe that this does not try to convert Graph!
37+
if isinstance(obj, nxcg.Graph | nxcg.CudaGraph):
3938
return nxcg.to_networkx(obj)
4039
return obj
4140

nx_cugraph/tests/test_convert.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2023-2024, NVIDIA CORPORATION.
1+
# Copyright (c) 2023-2025, NVIDIA CORPORATION.
22
# Licensed under the Apache License, Version 2.0 (the "License");
33
# you may not use this file except in compliance with the License.
44
# You may obtain a copy of the License at
@@ -15,7 +15,7 @@
1515
import pytest
1616

1717
import nx_cugraph as nxcg
18-
from nx_cugraph import interface
18+
from nx_cugraph import _nxver, interface
1919

2020

2121
@pytest.mark.parametrize(
@@ -267,3 +267,14 @@ def test_to_dict_of_lists():
267267
expected = nx.to_dict_of_lists(G, nodelist=[0, 3])
268268
result = nxcg.to_dict_of_lists(G, nodelist=[0, 3])
269269
assert expected == result
270+
271+
272+
@pytest.mark.skipif(_nxver < (3, 4), reason="Uses nx.config.fallback_to_nx")
273+
@pytest.mark.parametrize("fallback", [True, False])
274+
def test_convert_to_networkx_with_fallback(fallback):
275+
G = nxcg.Graph()
276+
G.add_edges_from([(0, 1), (1, 2)])
277+
assert not hasattr(nxcg, "wiener_index") # If fails, use a different function
278+
with nx.config(fallback_to_nx=fallback):
279+
# `closeness_vitality` calls `wiener_index`, which we don't yet implement
280+
nx.closeness_vitality(G, backend="networkx")

0 commit comments

Comments
 (0)