Skip to content

Commit a9b92fd

Browse files
authored
new: use _graphs instead of nxadb_graphs (#66)
* new: use `_graphs` instead of `nxadb_graphs` * fix: lint * fix: typo * cleanup * cleanup: use `GRAPH_FIELD` * fix: env var * fix: lint * bump version
1 parent 1e7df83 commit a9b92fd

File tree

4 files changed

+77
-57
lines changed

4 files changed

+77
-57
lines changed

_nx_arangodb/VERSION

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.1.1
1+
1.2.0

nx_arangodb/classes/dict/graph.py

+33-14
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import annotations
22

3+
import os
34
from collections import UserDict
45
from typing import Any, Callable
56

@@ -39,6 +40,8 @@ def graph_attr_dict_factory(
3940
# Graph #
4041
#########
4142

43+
GRAPH_FIELD = "networkx"
44+
4245

4346
def build_graph_attr_dict_data(
4447
parent: GraphAttrDict, data: dict[str, Any]
@@ -104,7 +107,11 @@ class GraphDict(UserDict[str, Any]):
104107
Given that ArangoDB does not have a concept of graph attributes, this class
105108
stores the attributes in a collection with the graph name as the document key.
106109
107-
For now, the collection is called 'nxadb_graphs'.
110+
The default collection is called `_graphs`. However, if the
111+
`DATABASE_GRAPH_COLLECTION` environment variable is specified,
112+
then that collection will be used. This variable is useful when the
113+
database user does not have permission to access the `_graphs`
114+
system collection.
108115
109116
Parameters
110117
----------
@@ -123,31 +130,39 @@ class GraphDict(UserDict[str, Any]):
123130
>>> del G.graph['foo']
124131
"""
125132

126-
def __init__(self, db: StandardDatabase, graph: Graph, *args: Any, **kwargs: Any):
133+
def __init__(
134+
self,
135+
db: StandardDatabase,
136+
graph: Graph,
137+
*args: Any,
138+
**kwargs: Any,
139+
):
127140
super().__init__(*args, **kwargs)
128141
self.data: dict[str, Any] = {}
129142

130143
self.db = db
131144
self.adb_graph = graph
132145
self.graph_name = graph.name
133-
self.COLLECTION_NAME = "nxadb_graphs"
134-
self.graph_id = f"{self.COLLECTION_NAME}/{self.graph_name}"
146+
self.collection_name = os.environ.get("DATABASE_GRAPH_COLLECTION", "_graphs")
135147

136-
self.collection = create_collection(db, self.COLLECTION_NAME)
148+
self.graph_id = f"{self.collection_name}/{self.graph_name}"
149+
self.parent_keys = [GRAPH_FIELD]
150+
151+
self.collection = create_collection(db, self.collection_name)
137152
self.graph_attr_dict_factory = graph_attr_dict_factory(
138153
self.db, self.adb_graph, self.graph_id
139154
)
140155

141-
result = doc_get_or_insert(self.db, self.COLLECTION_NAME, self.graph_id)
142-
for k, v in result.items():
156+
result = doc_get_or_insert(self.db, self.collection_name, self.graph_id)
157+
for k, v in result.get(GRAPH_FIELD, {}).items():
143158
self.data[k] = self.__process_graph_dict_value(k, v)
144159

145160
def __process_graph_dict_value(self, key: str, value: Any) -> Any:
146161
if not isinstance(value, dict):
147162
return value
148163

149164
graph_attr_dict = self.graph_attr_dict_factory()
150-
graph_attr_dict.parent_keys = [key]
165+
graph_attr_dict.parent_keys += [key]
151166
graph_attr_dict.data = build_graph_attr_dict_data(graph_attr_dict, value)
152167

153168
return graph_attr_dict
@@ -158,7 +173,7 @@ def __contains__(self, key: str) -> bool:
158173
if key in self.data:
159174
return True
160175

161-
return aql_doc_has_key(self.db, self.graph_id, key)
176+
return aql_doc_has_key(self.db, self.graph_id, key, self.parent_keys)
162177

163178
@key_is_string
164179
def __getitem__(self, key: str) -> Any:
@@ -167,7 +182,7 @@ def __getitem__(self, key: str) -> Any:
167182
if value := self.data.get(key):
168183
return value
169184

170-
result = aql_doc_get_key(self.db, self.graph_id, key)
185+
result = aql_doc_get_key(self.db, self.graph_id, key, self.parent_keys)
171186

172187
if result is None:
173188
raise KeyError(key)
@@ -187,14 +202,17 @@ def __setitem__(self, key: str, value: Any) -> None:
187202

188203
graph_dict_value = self.__process_graph_dict_value(key, value)
189204
self.data[key] = graph_dict_value
190-
doc_update(self.db, self.graph_id, {key: value})
205+
206+
update_dict = get_update_dict(self.parent_keys, {key: value})
207+
doc_update(self.db, self.graph_id, update_dict)
191208

192209
@key_is_string
193210
@key_is_not_reserved
194211
def __delitem__(self, key: str) -> None:
195212
"""del G.graph['foo']"""
196213
self.data.pop(key, None)
197-
doc_update(self.db, self.graph_id, {key: None})
214+
update_dict = get_update_dict(self.parent_keys, {key: None})
215+
doc_update(self.db, self.graph_id, update_dict)
198216

199217
# @values_are_json_serializable # TODO?
200218
def update(self, attrs: Any) -> None: # type: ignore
@@ -208,7 +226,8 @@ def update(self, attrs: Any) -> None: # type: ignore
208226
graph_attr_dict.data = graph_attr_dict_data
209227

210228
self.data.update(graph_attr_dict_data)
211-
doc_update(self.db, self.graph_id, attrs)
229+
update_dict = get_update_dict(self.parent_keys, attrs)
230+
doc_update(self.db, self.graph_id, update_dict)
212231

213232
def clear(self) -> None:
214233
"""G.graph.clear()"""
@@ -256,7 +275,7 @@ def __init__(
256275
self.graph = graph
257276
self.graph_id: str = graph_id
258277

259-
self.parent_keys: list[str] = []
278+
self.parent_keys: list[str] = [GRAPH_FIELD]
260279
self.graph_attr_dict_factory = graph_attr_dict_factory(
261280
self.db, self.graph, self.graph_id
262281
)

tests/test.py

+38-37
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
import nx_arangodb as nxadb
1515
from nx_arangodb.classes.dict.adj import AdjListOuterDict, EdgeAttrDict, EdgeKeyDict
16+
from nx_arangodb.classes.dict.graph import GRAPH_FIELD
1617
from nx_arangodb.classes.dict.node import NodeAttrDict, NodeDict
1718

1819
from .conftest import create_grid_graph, create_line_graph, db, run_gpu_tests
@@ -1638,7 +1639,7 @@ def test_multidigraph_edges_crud(load_karate_graph: Any) -> None:
16381639
def test_graph_dict_init(load_karate_graph: Any) -> None:
16391640
G = nxadb.Graph(name="KarateGraph", default_node_type="person")
16401641
assert db.collection("_graphs").has("KarateGraph")
1641-
graph_document = db.collection("_graphs").get("KarateGraph")
1642+
graph_document = db.document(f"_graphs/{G.name}")
16421643
assert graph_document["_key"] == "KarateGraph"
16431644
assert graph_document["edgeDefinitions"] == [
16441645
{"collection": "knows", "from": ["person"], "to": ["person"]},
@@ -1655,33 +1656,31 @@ def test_graph_dict_init_extended(load_karate_graph: Any) -> None:
16551656
G = nxadb.Graph(name="KarateGraph", foo="bar", bar={"baz": True})
16561657
G.graph["foo"] = "!!!"
16571658
G.graph["bar"]["baz"] = False
1658-
assert db.document(G.graph.graph_id)["foo"] == "!!!"
1659-
assert db.document(G.graph.graph_id)["bar"]["baz"] is False
1660-
assert "baz" not in db.document(G.graph.graph_id)
1659+
assert db.document(G.graph.graph_id)[GRAPH_FIELD]["foo"] == "!!!"
1660+
assert db.document(G.graph.graph_id)[GRAPH_FIELD]["bar"]["baz"] is False
1661+
assert "baz" not in db.document(G.graph.graph_id)[GRAPH_FIELD]
16611662

16621663

16631664
def test_graph_dict_clear_will_not_remove_remote_data(load_karate_graph: Any) -> None:
1664-
G_adb = nxadb.Graph(
1665+
G = nxadb.Graph(
16651666
name="KarateGraph",
16661667
foo="bar",
16671668
bar={"a": 4},
16681669
)
16691670

1670-
G_adb.graph["ant"] = {"b": 5}
1671-
G_adb.graph["ant"]["b"] = 6
1672-
G_adb.clear()
1671+
G.graph["ant"] = {"b": 5}
1672+
G.graph["ant"]["b"] = 6
1673+
G.clear()
16731674
try:
1674-
G_adb.graph["ant"]
1675+
G.graph["ant"]
16751676
except KeyError:
16761677
raise AssertionError("Not allowed to fail.")
16771678

1678-
assert db.document(G_adb.graph.graph_id)["ant"] == {"b": 6}
1679+
assert db.document(G.graph.graph_id)[GRAPH_FIELD]["ant"] == {"b": 6}
16791680

16801681

16811682
def test_graph_dict_set_item(load_karate_graph: Any) -> None:
1682-
name = "KarateGraph"
1683-
db.collection("nxadb_graphs").delete(name, ignore_missing=True)
1684-
G = nxadb.Graph(name=name, default_node_type="person")
1683+
G = nxadb.Graph(name="KarateGraph", default_node_type="person")
16851684

16861685
json_values = [
16871686
"aString",
@@ -1699,122 +1698,124 @@ def test_graph_dict_set_item(load_karate_graph: Any) -> None:
16991698
G.graph["json"] = value
17001699

17011700
if value is None:
1702-
assert "json" not in db.document(G.graph.graph_id)
1701+
assert "json" not in db.document(G.graph.graph_id)[GRAPH_FIELD]
17031702
else:
17041703
assert G.graph["json"] == value
1705-
assert db.document(G.graph.graph_id)["json"] == value
1704+
assert db.document(G.graph.graph_id)[GRAPH_FIELD]["json"] == value
17061705

17071706

17081707
def test_graph_dict_update(load_karate_graph: Any) -> None:
17091708
G = nxadb.Graph(name="KarateGraph", default_node_type="person")
1710-
G.clear()
17111709

17121710
G.graph["a"] = "b"
17131711
to_update = {"c": "d"}
17141712
G.graph.update(to_update)
17151713

17161714
# local
1717-
assert G.graph["a"] == "b"
1718-
assert G.graph["c"] == "d"
1715+
assert G.graph.data["a"] == G.graph["a"] == "b"
1716+
assert G.graph.data["c"] == G.graph["c"] == "d"
17191717

17201718
# remote
1721-
adb_doc = db.collection("nxadb_graphs").get(G.name)
1719+
adb_doc = db.document(f"_graphs/{G.name}")[GRAPH_FIELD]
17221720
assert adb_doc["a"] == "b"
17231721
assert adb_doc["c"] == "d"
17241722

17251723

17261724
def test_graph_attr_dict_nested_update(load_karate_graph: Any) -> None:
17271725
G = nxadb.Graph(name="KarateGraph", default_node_type="person")
1728-
G.clear()
17291726

17301727
G.graph["a"] = {"b": "c"}
17311728
G.graph["a"].update({"d": "e"})
17321729
assert G.graph["a"]["b"] == "c"
17331730
assert G.graph["a"]["d"] == "e"
1734-
assert db.document(G.graph.graph_id)["a"]["b"] == "c"
1735-
assert db.document(G.graph.graph_id)["a"]["d"] == "e"
1731+
assert db.document(G.graph.graph_id)[GRAPH_FIELD]["a"]["b"] == "c"
1732+
assert db.document(G.graph.graph_id)[GRAPH_FIELD]["a"]["d"] == "e"
17361733

17371734

17381735
def test_graph_dict_nested_1(load_karate_graph: Any) -> None:
17391736
G = nxadb.Graph(name="KarateGraph", default_node_type="person")
1740-
G.clear()
17411737
icon = {"football_icon": "MJ7"}
17421738

17431739
G.graph["a"] = {"b": icon}
17441740
assert G.graph["a"]["b"] == icon
1745-
assert db.document(G.graph.graph_id)["a"]["b"] == icon
1741+
assert db.document(G.graph.graph_id)[GRAPH_FIELD]["a"]["b"] == icon
17461742

17471743

17481744
def test_graph_dict_nested_2(load_karate_graph: Any) -> None:
17491745
G = nxadb.Graph(name="KarateGraph", default_node_type="person")
1750-
G.clear()
17511746
icon = {"football_icon": "MJ7"}
17521747

17531748
G.graph["x"] = {"y": icon}
17541749
G.graph["x"]["y"]["amount_of_goals"] = 1337
17551750

17561751
assert G.graph["x"]["y"]["amount_of_goals"] == 1337
1757-
assert db.document(G.graph.graph_id)["x"]["y"]["amount_of_goals"] == 1337
1752+
assert (
1753+
db.document(G.graph.graph_id)[GRAPH_FIELD]["x"]["y"]["amount_of_goals"] == 1337
1754+
)
17581755

17591756

17601757
def test_graph_dict_empty_values(load_karate_graph: Any) -> None:
17611758
G = nxadb.Graph(name="KarateGraph", default_node_type="person")
1762-
G.clear()
17631759

17641760
G.graph["empty"] = {}
17651761
assert G.graph["empty"] == {}
1766-
assert db.document(G.graph.graph_id)["empty"] == {}
1762+
assert db.document(G.graph.graph_id)[GRAPH_FIELD]["empty"] == {}
17671763

17681764
G.graph["none"] = None
1769-
assert "none" not in db.document(G.graph.graph_id)
1765+
assert "none" not in db.document(G.graph.graph_id)[GRAPH_FIELD]
17701766
assert "none" not in G.graph
17711767

17721768

17731769
def test_graph_dict_nested_overwrite(load_karate_graph: Any) -> None:
17741770
G = nxadb.Graph(name="KarateGraph", default_node_type="person")
1775-
G.clear()
17761771
icon1 = {"football_icon": "MJ7"}
17771772
icon2 = {"basketball_icon": "MJ23"}
17781773

17791774
G.graph["a"] = {"b": icon1}
17801775
G.graph["a"]["b"]["football_icon"] = "ChangedIcon"
17811776
assert G.graph["a"]["b"]["football_icon"] == "ChangedIcon"
1782-
assert db.document(G.graph.graph_id)["a"]["b"]["football_icon"] == "ChangedIcon"
1777+
assert (
1778+
db.document(G.graph.graph_id)[GRAPH_FIELD]["a"]["b"]["football_icon"]
1779+
== "ChangedIcon"
1780+
)
17831781

17841782
# Overwrite entire nested dictionary
17851783
G.graph["a"] = {"b": icon2}
17861784
assert G.graph["a"]["b"]["basketball_icon"] == "MJ23"
1787-
assert db.document(G.graph.graph_id)["a"]["b"]["basketball_icon"] == "MJ23"
1785+
assert (
1786+
db.document(G.graph.graph_id)[GRAPH_FIELD]["a"]["b"]["basketball_icon"]
1787+
== "MJ23"
1788+
)
17881789

17891790

17901791
def test_graph_dict_complex_nested(load_karate_graph: Any) -> None:
17911792
G = nxadb.Graph(name="KarateGraph", default_node_type="person")
1792-
G.clear()
17931793

17941794
complex_structure = {"level1": {"level2": {"level3": {"key": "value"}}}}
17951795

17961796
G.graph["complex"] = complex_structure
17971797
assert G.graph["complex"]["level1"]["level2"]["level3"]["key"] == "value"
17981798
assert (
1799-
db.document(G.graph.graph_id)["complex"]["level1"]["level2"]["level3"]["key"]
1799+
db.document(G.graph.graph_id)[GRAPH_FIELD]["complex"]["level1"]["level2"][
1800+
"level3"
1801+
]["key"]
18001802
== "value"
18011803
)
18021804

18031805

18041806
def test_graph_dict_nested_deletion(load_karate_graph: Any) -> None:
18051807
G = nxadb.Graph(name="KarateGraph", default_node_type="person")
1806-
G.clear()
18071808
icon = {"football_icon": "MJ7", "amount_of_goals": 1337}
18081809

18091810
G.graph["x"] = {"y": icon}
18101811
del G.graph["x"]["y"]["amount_of_goals"]
18111812
assert "amount_of_goals" not in G.graph["x"]["y"]
1812-
assert "amount_of_goals" not in db.document(G.graph.graph_id)["x"]["y"]
1813+
assert "amount_of_goals" not in db.document(G.graph.graph_id)[GRAPH_FIELD]["x"]["y"]
18131814

18141815
# Delete top-level key
18151816
del G.graph["x"]
18161817
assert "x" not in G.graph
1817-
assert "x" not in db.document(G.graph.graph_id)
1818+
assert "x" not in db.document(G.graph.graph_id)[GRAPH_FIELD]
18181819

18191820

18201821
def test_readme(load_karate_graph: Any) -> None:

tests/test_graph.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
AdjListOuterDict,
1818
EdgeAttrDict,
1919
)
20-
from nx_arangodb.classes.dict.graph import GraphDict
20+
from nx_arangodb.classes.dict.graph import GRAPH_FIELD, GraphDict
2121
from nx_arangodb.classes.dict.node import NodeAttrDict, NodeDict
2222

2323
from .conftest import db
@@ -463,11 +463,11 @@ def test_graph_attr(self):
463463
assert isinstance(G.graph, GraphDict)
464464
assert G.graph["foo"] == "bar"
465465
del G.graph["foo"]
466-
graph_doc = get_doc(f"nxadb_graphs/{GRAPH_NAME}")
466+
graph_doc = get_doc(f"_graphs/{GRAPH_NAME}")[GRAPH_FIELD]
467467
assert G.graph == graph_doc
468468
H = self.K3Graph(foo="bar")
469469
assert H.graph["foo"] == "bar"
470-
graph_doc = get_doc(f"nxadb_graphs/{GRAPH_NAME}")
470+
graph_doc = get_doc(f"_graphs/{GRAPH_NAME}")[GRAPH_FIELD]
471471
assert H.graph == graph_doc
472472

473473
def test_node_attr(self):
@@ -1105,7 +1105,7 @@ def test_update(self):
11051105
else:
11061106
for src, dst in G.edges():
11071107
assert G.adj[dst][src] == G.adj[src][dst]
1108-
assert G.graph == get_doc(G.graph.graph_id)
1108+
assert G.graph == get_doc(G.graph.graph_id)[GRAPH_FIELD]
11091109

11101110
# no keywords -- order is edges, nodes
11111111
G = self.K3Graph()
@@ -1126,7 +1126,7 @@ def test_update(self):
11261126
else:
11271127
for src, dst in G.edges():
11281128
assert G.adj[dst][src] == G.adj[src][dst]
1129-
assert G.graph == get_doc(G.graph.graph_id)
1129+
assert G.graph == get_doc(G.graph.graph_id)[GRAPH_FIELD]
11301130

11311131
# update using only a graph
11321132
G = self.K3Graph()

0 commit comments

Comments
 (0)