Skip to content

Commit 7e555b6

Browse files
committed
Support neo4j 6.0
1 parent 0950192 commit 7e555b6

File tree

9 files changed

+55
-13
lines changed

9 files changed

+55
-13
lines changed

changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@
1515
- Add support for PyArrow 21.0.0
1616
- Drop support for PyArrow 17.0
1717
- Support numpy 1.24.0
18+
- Add support for neo4j 6.0

graphdatascience/error/cypher_warning_handler.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import re
12
import warnings
23
from functools import wraps
34
from typing import Any, Callable, TypeVar, cast
@@ -27,6 +28,13 @@ def wrapper(self: CallerBase, *args: Any, **kwargs: Any) -> Any:
2728
message=r"The query used a deprecated function. \('id'.*",
2829
)
2930

31+
# with neo4j driver 6.0.0
32+
warnings.filterwarnings(
33+
"ignore",
34+
message=r"warn: feature deprecated with replacement\. id is deprecated. It is replaced by elementId or consider using an application-generated id\."
35+
,
36+
)
37+
3038
return func(self, *args, **kwargs)
3139

3240
return cast(F, wrapper)

graphdatascience/query_runner/neo4j_query_runner.py

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -196,14 +196,12 @@ def run_cypher(
196196
df = result.to_df()
197197

198198
if self._NEO4J_DRIVER_VERSION < SemanticVersion(5, 0, 0):
199-
self._last_bookmarks = [session.last_bookmark()]
199+
self._last_bookmarks = [session.last_bookmark()] # type: ignore
200200
else:
201201
self._last_bookmarks = session.last_bookmarks()
202202

203-
notifications = result.consume().notifications
204-
if notifications:
205-
for notification in notifications:
206-
self._forward_cypher_warnings(notification)
203+
result_summary = result.consume()
204+
self._handle_notifications(result_summary)
207205

208206
return df
209207

@@ -321,7 +319,21 @@ def encrypted(self) -> bool:
321319
def driver_config(self) -> dict[str, Any]:
322320
return self._config
323321

324-
def _forward_cypher_warnings(self, notification: dict[str, Any]) -> None:
322+
def _handle_notifications(self, result_summary: neo4j.ResultSummary) -> None:
323+
if self._NEO4J_DRIVER_VERSION < SemanticVersion(6, 0, 0):
324+
notifications = result_summary.notifications
325+
if notifications:
326+
for notification in notifications:
327+
self._forward_cypher_notification(notification)
328+
if self._NEO4J_DRIVER_VERSION >= SemanticVersion(6, 0, 0):
329+
status_objects = result_summary.gql_status_objects
330+
for status in status_objects:
331+
if status.raw_classification == "DEPRECATION" and not re.match(
332+
r".*returned by the procedure.*", status.status_description
333+
):
334+
warnings.warn(DeprecationWarning(status.status_description))
335+
336+
def _forward_cypher_notification(self, notification: dict[str, Any]) -> None:
325337
# (see https://neo4j.com/docs/status-codes/current/notifications/ for more details)
326338
severity = notification["severity"]
327339
if severity == "WARNING":
@@ -434,7 +446,7 @@ def _verify_connectivity(
434446
category=neo4j.ExperimentalWarning,
435447
message=r"^The configuration may change in the future.$",
436448
)
437-
else:
449+
elif self._NEO4J_DRIVER_VERSION < SemanticVersion(6, 0, 0):
438450
warnings.filterwarnings(
439451
"ignore",
440452
category=neo4j.ExperimentalWarning,
@@ -443,6 +455,13 @@ def _verify_connectivity(
443455
"They might be changed or removed in any future version without prior notice.$"
444456
),
445457
)
458+
else:
459+
warnings.filterwarnings(
460+
"ignore",
461+
category=neo4j.warnings.PreviewWarning,
462+
message=(r"^Passing key-word arguments to verify_connectivity\(\) is a preview feature.*"),
463+
)
464+
446465
self._driver.verify_connectivity(database=database)
447466
break
448467
except neo4j.exceptions.DriverError as e:
@@ -478,6 +497,8 @@ def __configure_warnings_filter(self) -> None:
478497
warnings.filterwarnings("ignore", message=r".*The procedure has a deprecated field.*by 'gds.*")
479498
# neo4j driver 4.4
480499
warnings.filterwarnings("ignore", message=r".*The query used a deprecated field from a procedure.*by 'gds.*")
500+
# neo4j driver 6.0
501+
warnings.filterwarnings("ignore", message=r".*returned by the procedure.* is deprecated.*")
481502

482503
class ConnectivityRetriesConfig(NamedTuple):
483504
max_retries: int = 600

graphdatascience/tests/integration/conftest.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,13 @@ def is_neo4j_44(gds: GraphDataScience) -> bool:
131131
return False
132132

133133

134+
def id_warning_pattern() -> str:
135+
if neo4j.__version__.startswith("5."):
136+
return r".*The query used a deprecated function.*[`']id[`'].*"
137+
else:
138+
return r".*id is deprecated. It is replaced by elementId or consider using an application-generated id.*"
139+
140+
134141
@pytest.fixture(autouse=True)
135142
def clean_up(gds: GraphDataScience) -> Generator[None, None, None]:
136143
yield

graphdatascience/tests/integration/test_error_handling.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
from typing import Generator
22

3+
import neo4j
34
import pytest
45
from neo4j import Driver, GraphDatabase
56

67
from graphdatascience import GraphDataScience
78
from graphdatascience.server_version.server_version import ServerVersion
8-
from graphdatascience.tests.integration.conftest import AUTH, URI, is_neo4j_44
9+
from graphdatascience.tests.integration.conftest import AUTH, URI, id_warning_pattern, is_neo4j_44
910

1011
GRAPH_NAME = "g"
1112

@@ -207,7 +208,7 @@ def test_forward_server_side_warning(gds: GraphDataScience) -> None:
207208
if is_neo4j_44(gds):
208209
return
209210

210-
with pytest.raises(Warning, match="The query used a deprecated function.*[`']id[`'].*"):
211+
with pytest.raises(Warning, match=id_warning_pattern()):
211212
gds.run_cypher("MATCH (n) RETURN id(n)")
212213

213214

@@ -219,7 +220,7 @@ def test_forward_driver_configured_warning(warning_driver: Driver) -> None:
219220
if is_neo4j_44(gds):
220221
return
221222

222-
with pytest.raises(Warning, match="The query used a deprecated function.*[`']id[`'].*"):
223+
with pytest.raises(Warning, match=id_warning_pattern()):
223224
gds.run_cypher("MATCH (n) RETURN id(n)")
224225

225226

graphdatascience/tests/integration/test_graph_ops.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from graphdatascience.query_runner.arrow_query_runner import ArrowQueryRunner
1010
from graphdatascience.query_runner.query_runner import QueryRunner
1111
from graphdatascience.server_version.server_version import ServerVersion
12-
from graphdatascience.tests.integration.conftest import AUTH, DB, URI, is_neo4j_44
12+
from graphdatascience.tests.integration.conftest import AUTH, DB, URI, id_warning_pattern, is_neo4j_44
1313

1414
GRAPH_NAME = "g"
1515

@@ -844,7 +844,7 @@ def test_graph_relationships_stream_without_arrow(gds_without_arrow: GraphDataSc
844844
else:
845845
result = gds_without_arrow.beta.graph.relationships.stream(G, ["REL", "REL2"])
846846

847-
warnings.filterwarnings("ignore", category=DeprecationWarning, message="The query used a deprecated function")
847+
warnings.filterwarnings("ignore", category=DeprecationWarning, message=id_warning_pattern())
848848
expected = gds_without_arrow.run_cypher(
849849
"MATCH (n)-[r]->(m) RETURN id(n) AS src_id, id(m) AS trg_id, type(r) AS rel_type"
850850
)

graphdatascience/tests/integration/test_model_ops.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,7 @@ def test_missing_model_drop(gds: GraphDataScience) -> None:
321321

322322
@pytest.mark.model_store_location
323323
@pytest.mark.filterwarnings("ignore: The query used a deprecated procedure.")
324+
@pytest.mark.filterwarnings("ignore: feature deprecated with replacement")
324325
def test_deprecated_model_Functions_still_work(gds: GraphDataScience, gs_model: GraphSageModel) -> None:
325326
gds.beta.model.list()
326327
gds.alpha.model.store(gs_model)

graphdatascience/tests/integration/test_system_ops.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ def test_list_defaults(gds: GraphDataScience) -> None:
7070

7171

7272
@pytest.mark.filterwarnings("ignore: The query used a deprecated procedure")
73+
@pytest.mark.filterwarnings("ignore: feature deprecated with replacement")
7374
@pytest.mark.enterprise
7475
@pytest.mark.skip_on_aura
7576
def test_alpha_backup(gds: GraphDataScience) -> None:
@@ -88,6 +89,7 @@ def test_backup(gds: GraphDataScience) -> None:
8889

8990

9091
@pytest.mark.filterwarnings("ignore: The query used a deprecated procedure")
92+
@pytest.mark.filterwarnings("ignore: feature deprecated with replacement")
9193
@pytest.mark.enterprise
9294
@pytest.mark.skip_on_aura
9395
def test_alpha_restore(gds: GraphDataScience) -> None:
@@ -106,6 +108,7 @@ def test_restore(gds: GraphDataScience) -> None:
106108

107109

108110
@pytest.mark.filterwarnings("ignore: The query used a deprecated procedure")
111+
@pytest.mark.filterwarnings("ignore: .*feature deprecated with replacement.")
109112
@pytest.mark.compatible_with(min_inclusive=ServerVersion(2, 5, 0))
110113
def test_deprecated_endpoints(gds: GraphDataScience) -> None:
111114
gds.beta.listProgress()

requirements/base/base.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
multimethod >= 1.0, < 3.0
2-
neo4j >= 4.4.12, < 6.0
2+
neo4j >= 4.4.12, < 7.0
33
numpy < 2.4
44
pandas >= 1.0, < 3.0
55
pyarrow >= 17.0, < 22.0

0 commit comments

Comments
 (0)