Skip to content

GA-163 | test_multidigraph #45

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 30, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 29 additions & 18 deletions nx_arangodb/classes/dict/adj.py
Original file line number Diff line number Diff line change
Expand Up @@ -775,19 +775,20 @@ def __init__(

self.__getitem_helper_db: Callable[[str, str], EdgeAttrDict | EdgeKeyDict]
self.__setitem_helper: Callable[[EdgeAttrDict | EdgeKeyDict, str, str], None]
self.__delitem_helper: Callable[[str | list[str]], None]
if self.is_multigraph:
self.__contains_helper = self.__contains__multigraph
self.__getitem_helper_db = self.__getitem__multigraph_db
self.__getitem_helper_cache = self.__getitem__multigraph_cache
self.__setitem_helper = self.__setitem__multigraph # type: ignore[assignment]
self.__delitem_helper = self.__delitem__multigraph
self.__setitem_helper = self.__setitem__multigraph # type: ignore[assignment] # noqa
self.__delitem_helper = self.__delitem__multigraph # type: ignore[assignment] # noqa
self.__fetch_all_helper = self.__fetch_all_multigraph
else:
self.__contains_helper = self.__contains__graph
self.__getitem_helper_db = self.__getitem__graph_db
self.__getitem_helper_cache = self.__getitem__graph_cache
self.__setitem_helper = self.__setitem__graph # type: ignore[assignment] # noqa
self.__delitem_helper = self.__delitem__graph
self.__setitem_helper = self.__setitem__graph # type: ignore[assignment]
self.__delitem_helper = self.__delitem__graph # type: ignore[assignment]
self.__fetch_all_helper = self.__fetch_all_graph

@property
Expand Down Expand Up @@ -1104,6 +1105,7 @@ def __delitem__(self, key: str) -> None:
dst_node_id,
self.graph.name,
direction=self.traversal_direction.name,
can_return_multiple=self.is_multigraph,
)

if not result:
Expand All @@ -1112,12 +1114,14 @@ def __delitem__(self, key: str) -> None:

self.__delitem_helper(result)

@key_is_string
def __delitem__graph(self, edge_id: str) -> None:
"""Helper function for __delitem__ in Graphs."""
self.graph.delete_edge(edge_id)
try:
self.graph.delete_edge(edge_id)
except DocumentDeleteError as e:
m = f"Failed to delete edge '{edge_id}' from Graph: {e}."
raise KeyError(m)

@key_is_string
def __delitem__multigraph(self, edge_ids: list[str]) -> None:
"""Helper function for __delitem__ in MultiGraphs."""
# TODO: Consider separating **edge_ids** by edge collection,
Expand Down Expand Up @@ -1641,7 +1645,6 @@ def propagate_edge_directed(
dst_node_id: str,
edge_key_or_attr_dict: EdgeKeyDict | EdgeAttrDict,
) -> None:
self.__set_adj_inner_dict(self.mirror, dst_node_id)
self.mirror.data[dst_node_id].data[src_node_id] = edge_key_or_attr_dict

def propagate_edge_directed_symmetric(
Expand All @@ -1651,7 +1654,6 @@ def propagate_edge_directed_symmetric(
) -> None:
propagate_edge_directed(src_node_id, dst_node_id, edge_key_or_attr_dict)
propagate_edge_undirected(src_node_id, dst_node_id, edge_key_or_attr_dict)
self.__set_adj_inner_dict(self.mirror, src_node_id)
self.mirror.data[src_node_id].data[dst_node_id] = edge_key_or_attr_dict

propagate_edge_func = (
Expand All @@ -1664,37 +1666,46 @@ def propagate_edge_directed_symmetric(
)
)

set_adj_inner_dict_mirror = (
self.mirror.__set_adj_inner_dict if self.is_directed else lambda *args: None
)

if node_dict is not None:
for node_id in node_dict.keys():
self.__set_adj_inner_dict(self, node_id)
self.__set_adj_inner_dict(node_id)
set_adj_inner_dict_mirror(node_id)

for src_node_id, inner_dict in adj_dict.items():
for dst_node_id, edge_or_edges in inner_dict.items():

self.__set_adj_inner_dict(self, src_node_id)
self.__set_adj_inner_dict(self, dst_node_id)
self.__set_adj_inner_dict(src_node_id)
self.__set_adj_inner_dict(dst_node_id)

set_adj_inner_dict_mirror(src_node_id)
set_adj_inner_dict_mirror(dst_node_id)

edge_attr_or_key_dict = set_edge_func( # type: ignore[operator]
src_node_id, dst_node_id, edge_or_edges
)

propagate_edge_func(src_node_id, dst_node_id, edge_attr_or_key_dict)

def __set_adj_inner_dict(
self, adj_outer_dict: AdjListOuterDict, node_id: str
) -> AdjListInnerDict:
if node_id in adj_outer_dict.data:
return adj_outer_dict.data[node_id]
def __set_adj_inner_dict(self, node_id: str) -> AdjListInnerDict:
if node_id in self.data:
return self.data[node_id]

adj_inner_dict = self.adjlist_inner_dict_factory()
adj_inner_dict.src_node_id = node_id
adj_inner_dict.FETCHED_ALL_DATA = True
adj_inner_dict.FETCHED_ALL_IDS = True
adj_outer_dict.data[node_id] = adj_inner_dict
self.data[node_id] = adj_inner_dict

return adj_inner_dict

def _fetch_all(self) -> None:
self.clear()
if self.is_directed:
self.mirror.clear()

(
node_dict,
Expand Down
7 changes: 7 additions & 0 deletions nx_arangodb/classes/digraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ def __init__(
self.clear_edges = self.clear_edges_override
self.add_node = self.add_node_override
self.remove_node = self.remove_node_override
self.reverse = self.reverse_override

if (
not self.is_multigraph()
Expand All @@ -86,6 +87,12 @@ def __init__(
# def out_edges(self):
# pass

def reverse_override(self, copy: bool = True) -> Any:
if copy is False:
raise NotImplementedError("In-place reverse is not supported yet.")

return super().reverse(copy=True)

def clear_edges_override(self):
logger.info("Note that clearing edges ony erases the edges in the local cache")
for predecessor_dict in self._pred.data.values():
Expand Down
9 changes: 9 additions & 0 deletions nx_arangodb/classes/multidigraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,19 @@ def __init__(
**kwargs,
)

if self.graph_exists_in_db:
self.reverse = self.reverse_override

#######################
# Init helper methods #
#######################

##########################
# nx.MultiGraph Overides #
##########################

def reverse_override(self, copy: bool = True) -> Any:
if copy is False:
raise NotImplementedError("In-place reverse is not supported yet.")

return super().reverse(copy=True)
45 changes: 23 additions & 22 deletions tests/test_digraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,10 @@
from .conftest import db

# from .test_graph import TestEdgeSubgraph as _TestGraphEdgeSubgraph
from .test_graph import BaseAttrGraphTester, BaseGraphTester
from .test_graph import GRAPH_NAME, BaseAttrGraphTester, BaseGraphTester
from .test_graph import TestGraph as _TestGraph
from .test_graph import get_doc

GRAPH_NAME = "test_graph"


class BaseDiGraphTester(BaseGraphTester):
def test_has_successor(self):
Expand Down Expand Up @@ -197,11 +195,26 @@ def test_size(self):

def test_to_undirected_reciprocal(self):
G = self.EmptyGraph()
assert G.number_of_edges() == 0
G.add_edge(1, 2)
assert G.to_undirected().has_edge("test_graph_node/1", "test_graph_node/2")
assert not G.to_undirected(reciprocal=True).has_edge(1, 2)
G.add_edge(2, 1)
assert G.to_undirected(reciprocal=True).has_edge(
assert G.number_of_edges() == 1

G_undirected = G.to_undirected()
assert G_undirected.number_of_edges() == 1
assert G_undirected.has_edge("test_graph_node/1", "test_graph_node/2")
assert G_undirected.has_edge("test_graph_node/2", "test_graph_node/1")

G_undirected_reciprocal = G.to_undirected(reciprocal=True)
assert G_undirected_reciprocal.number_of_edges() == 1 # NOTE: This is failing
assert not G_undirected_reciprocal.has_edge(
"test_graph_node/1", "test_graph_node/2"
)

G.add_edge("test_graph_node/2", "test_graph_node/1")
assert G.number_of_edges() == 2
G_undirected_reciprocal = G.to_undirected(reciprocal=True)
assert G_undirected_reciprocal.number_of_edges() == 2
assert G_undirected_reciprocal.has_edge(
"test_graph_node/1", "test_graph_node/2"
)

Expand All @@ -221,21 +234,9 @@ def test_reverse_copy(self):

def test_reverse_nocopy(self):
G = self.EmptyGraph(incoming_graph_data=[(0, 1), (1, 2)])
R = G.reverse(copy=False)
assert R[1][0]
assert R[2][1]
assert R._pred[0][1]
assert R._pred[1][2]
with pytest.raises(KeyError):
R[0][1]
with pytest.raises(KeyError):
R[1][2]
with pytest.raises(KeyError):
R._pred[1][0]
with pytest.raises(KeyError):
R._pred[2][1]
with pytest.raises(nx.NetworkXError):
R.remove_edge(1, 0)
with pytest.raises(NotImplementedError):
G.reverse(copy=False)
pytest.skip("NotImplementedError: In-place reverse is not supported yet.")

def test_reverse_hashable(self):
pytest.skip("Class-based nodes are not supported in ArangoDB.")
Expand Down
3 changes: 2 additions & 1 deletion tests/test_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -1044,9 +1044,10 @@ def test_clear_edges(self):
G = self.Graph()
G.graph["name"] = "K3"
nodes = list(G.nodes)
assert G.number_of_edges() > 0
G.clear_edges() # clearing only removes local cache!
assert list(G.nodes) == nodes
assert G.number_of_edges() == 3
assert G.number_of_edges() > 0
assert G.graph["name"] == "K3"

def test_edges_data(self):
Expand Down
Loading