Skip to content

Commit 10b7202

Browse files
authored
Warn on old server version (#762)
* Warn on old server version * Remove tests for unsupported versions
1 parent 4b62391 commit 10b7202

File tree

9 files changed

+46
-133
lines changed

9 files changed

+46
-133
lines changed

changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,6 @@
2222

2323
* The database connection is now validated before a session is created.
2424
* Retry authentication requests.
25+
* Warn if client does not support given GDS server version as defined at https://neo4j.com/docs/graph-data-science-client/current/installation/#python-client-system-requirements.
2526

2627
## Other changes

graphdatascience/graph_data_science.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import annotations
22

3+
import warnings
34
from typing import Any, Dict, Optional, Tuple, Type, Union
45

56
from neo4j import Driver
@@ -15,6 +16,7 @@
1516
from .query_runner.query_runner import QueryRunner
1617
from .server_version.server_version import ServerVersion
1718
from .utils.util_proc_runner import UtilProcRunner
19+
from .version import __min_server_version__
1820

1921

2022
class GraphDataScience(DirectEndpoints, UncallableNamespace):
@@ -77,6 +79,15 @@ def __init__(
7779

7880
self._server_version = self._query_runner.server_version()
7981

82+
if self._server_version < ServerVersion.from_string(__min_server_version__):
83+
warnings.warn(
84+
DeprecationWarning(
85+
f"Client does not support the given server version `{self._server_version}`."
86+
+ " We recommend to either update the GDS server version or use a compatible version of the `graphdatascience` package."
87+
+ " Please refer to the compatibility matrix at https://neo4j.com/docs/graph-data-science-client/current/installation/#python-client-system-requirements."
88+
)
89+
)
90+
8091
arrow_info = ArrowInfo.create(self._query_runner)
8192
if arrow and arrow_info.enabled and self._server_version >= ServerVersion(2, 1, 0):
8293
self._query_runner = ArrowQueryRunner.create(

graphdatascience/tests/unit/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from graphdatascience.session.dbms_connection_info import DbmsConnectionInfo
2121

2222
# Should mirror the latest GDS server version under development.
23-
DEFAULT_SERVER_VERSION = ServerVersion(2, 6, 0)
23+
DEFAULT_SERVER_VERSION = ServerVersion(2, 10, 0)
2424

2525
QueryResult = Union[DataFrame, Exception]
2626
QueryResultMap = Dict[str, QueryResult] # Substring -> QueryResult

graphdatascience/tests/unit/test_error_handling.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
)
1616

1717

18-
@pytest.mark.parametrize("server_version", [ServerVersion(2, 2, 0)]) # Something later than 2.1.0
18+
@pytest.mark.parametrize("server_version", [ServerVersion(2, 10, 0)]) # Something later than 2.1.0
1919
def test_incompatible_server_version(runner: QueryRunner, gds: GraphDataScience) -> None:
2020
G = Graph("dummy", runner)
2121
with pytest.raises(

graphdatascience/tests/unit/test_graph_construct.py

Lines changed: 19 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,10 @@
22
from pandas import DataFrame
33

44
from graphdatascience.graph_data_science import GraphDataScience
5-
from graphdatascience.server_version.server_version import ServerVersion
65

76
from .conftest import CollectingQueryRunner
87

98

10-
@pytest.mark.parametrize("server_version", [ServerVersion(2, 1, 0)])
119
def test_graph_project_based_construct_without_arrow(runner: CollectingQueryRunner, gds: GraphDataScience) -> None:
1210
nodes = DataFrame(
1311
{
@@ -28,54 +26,22 @@ def test_graph_project_based_construct_without_arrow(runner: CollectingQueryRunn
2826
runner.add__mock_result("gds.debug.sysInfo", DataFrame([{"gdsEdition": "Unlicensed"}]))
2927
gds.graph.construct("hello", nodes, relationships, concurrency=2)
3028

31-
expected_node_query = "UNWIND $nodes as node RETURN node[0] as id, node[1] as labels, node[2] as propA"
32-
expected_relationship_query = (
33-
"UNWIND $relationships as relationship RETURN "
34-
"relationship[0] as source, relationship[1] as target, "
35-
"relationship[2] as type, relationship[3] as relPropA"
36-
)
37-
expected_proc_query = (
38-
"CALL gds.graph.project.cypher("
39-
"$graph_name, "
40-
"$node_query, "
41-
"$relationship_query, "
42-
"{readConcurrency: $read_concurrency, parameters: { nodes: $nodes, relationships: $relationships }})"
29+
expected_query = (
30+
"UNWIND $data AS data WITH data, "
31+
"CASE WHEN data[6] THEN data[5] ELSE null END AS sourceNodeLabels, "
32+
"CASE WHEN data[3] THEN data[2] ELSE null END AS relationshipType, "
33+
"CASE WHEN data[10] THEN data[9] ELSE null END AS targetNodeId, "
34+
"\nCASE WHEN data[8] THEN data[7] ELSE null END AS sourceNodeProperties, "
35+
"\nCASE WHEN data[1] THEN data[0] ELSE null END AS relationshipProperties "
36+
"RETURN gds.graph.project($graph_name, data[4], targetNodeId, {sourceNodeLabels: sourceNodeLabels, targetNodeLabels: NULL, sourceNodeProperties: sourceNodeProperties, targetNodeProperties: NULL, relationshipType: relationshipType, relationshipProperties: relationshipProperties}, $configuration)"
4337
)
4438

45-
assert runner.last_query() == expected_proc_query
46-
assert runner.last_params() == {
47-
"nodes": nodes.values.tolist(),
48-
"relationships": relationships.values.tolist(),
49-
"read_concurrency": 2,
50-
"graph_name": "hello",
51-
"node_query": expected_node_query,
52-
"relationship_query": expected_relationship_query,
53-
}
39+
assert runner.last_query() == expected_query
5440

5541

56-
@pytest.mark.parametrize(
57-
"server_version, tier, target_node_labels, target_node_properties, properties_key, in_between_configs",
58-
[
59-
(ServerVersion(2, 3, 0), ".alpha", "", "", "properties", "}, {"),
60-
(
61-
ServerVersion(2, 4, 0),
62-
"",
63-
", targetNodeLabels: NULL",
64-
", targetNodeProperties: NULL",
65-
"relationshipProperties",
66-
", ",
67-
),
68-
],
69-
ids=["2.3.0 - Alpha Cypher Aggregation", "2.4.0 - New Cypher projection"],
70-
)
7142
def test_multi_df(
7243
runner: CollectingQueryRunner,
7344
gds: GraphDataScience,
74-
tier: str,
75-
target_node_labels: str,
76-
target_node_properties: str,
77-
properties_key: str,
78-
in_between_configs: str,
7945
) -> None:
8046
nodes = [
8147
DataFrame({"nodeId": [0, 1], "labels": ["a", "a"], "property": [6.0, 7.0]}),
@@ -99,13 +65,12 @@ def test_multi_df(
9965
" CASE WHEN data[3] THEN data[2] ELSE null END AS relationshipType,"
10066
" CASE WHEN data[10] THEN data[9] ELSE null END AS targetNodeId,"
10167
" CASE WHEN data[8] THEN data[7] ELSE null END AS sourceNodeProperties,"
102-
f" CASE WHEN data[1] THEN data[0] ELSE null END AS {properties_key}"
103-
f" RETURN gds{tier}.graph.project("
68+
" CASE WHEN data[1] THEN data[0] ELSE null END AS relationshipProperties"
69+
" RETURN gds.graph.project("
10470
"$graph_name, data[4], targetNodeId, {"
105-
f"sourceNodeLabels: sourceNodeLabels{target_node_labels}, "
106-
f"sourceNodeProperties: sourceNodeProperties{target_node_properties}"
107-
f"{in_between_configs}"
108-
f"relationshipType: relationshipType, {properties_key}: {properties_key}"
71+
"sourceNodeLabels: sourceNodeLabels, targetNodeLabels: NULL, "
72+
"sourceNodeProperties: sourceNodeProperties, targetNodeProperties: NULL, "
73+
"relationshipType: relationshipType, relationshipProperties: relationshipProperties"
10974
"}, $configuration)"
11075
)
11176

@@ -131,29 +96,9 @@ def test_multi_df(
13196
}
13297

13398

134-
@pytest.mark.parametrize(
135-
"server_version, tier, target_node_labels, target_node_properties, properties_key, in_between_configs",
136-
[
137-
(ServerVersion(2, 3, 0), ".alpha", "", "", "properties", "}, {"),
138-
(
139-
ServerVersion(2, 4, 0),
140-
"",
141-
", targetNodeLabels: NULL",
142-
", targetNodeProperties: NULL",
143-
"relationshipProperties",
144-
", ",
145-
),
146-
],
147-
ids=["2.3.0 - Alpha Cypher Aggregation", "2.4.0 - New Cypher projection"],
148-
)
14999
def test_graph_aggregation_based_construct_without_arrow(
150100
runner: CollectingQueryRunner,
151101
gds: GraphDataScience,
152-
tier: str,
153-
target_node_labels: str,
154-
target_node_properties: str,
155-
properties_key: str,
156-
in_between_configs: str,
157102
) -> None:
158103
nodes = DataFrame(
159104
{
@@ -184,13 +129,12 @@ def test_graph_aggregation_based_construct_without_arrow(
184129
" CASE WHEN data[3] THEN data[2] ELSE null END AS relationshipType,"
185130
" CASE WHEN data[10] THEN data[9] ELSE null END AS targetNodeId,"
186131
" CASE WHEN data[8] THEN data[7] ELSE null END AS sourceNodeProperties,"
187-
f" CASE WHEN data[1] THEN data[0] ELSE null END AS {properties_key}"
188-
f" RETURN gds{tier}.graph.project("
132+
" CASE WHEN data[1] THEN data[0] ELSE null END AS relationshipProperties"
133+
" RETURN gds.graph.project("
189134
"$graph_name, data[4], targetNodeId, {"
190-
f"sourceNodeLabels: sourceNodeLabels{target_node_labels}, "
191-
f"sourceNodeProperties: sourceNodeProperties{target_node_properties}"
192-
f"{in_between_configs}"
193-
f"relationshipType: relationshipType, {properties_key}: {properties_key}"
135+
"sourceNodeLabels: sourceNodeLabels, targetNodeLabels: NULL, "
136+
"sourceNodeProperties: sourceNodeProperties, targetNodeProperties: NULL, "
137+
"relationshipType: relationshipType, relationshipProperties: relationshipProperties"
194138
"}, $configuration)"
195139
)
196140

@@ -213,7 +157,6 @@ def test_graph_aggregation_based_construct_without_arrow(
213157
}
214158

215159

216-
@pytest.mark.parametrize("server_version", [ServerVersion(2, 3, 0)])
217160
def test_graph_aggregation_based_construct_without_arrow_with_overlapping_property_columns(
218161
runner: CollectingQueryRunner, gds: GraphDataScience
219162
) -> None:
@@ -242,7 +185,6 @@ def test_graph_aggregation_based_construct_without_arrow_with_overlapping_proper
242185
gds.graph.construct("hello", nodes, relationships, concurrency=2)
243186

244187

245-
@pytest.mark.parametrize("server_version", [ServerVersion(2, 1, 0)])
246188
def test_graph_construct_validate_df_columns(runner: CollectingQueryRunner, gds: GraphDataScience) -> None:
247189
nodes = DataFrame({"nodeIds": [0, 1]})
248190
relationships = DataFrame({"sourceNodeId": [0, 1], "TargetNodeIds": [1, 0]})
@@ -254,7 +196,6 @@ def test_graph_construct_validate_df_columns(runner: CollectingQueryRunner, gds:
254196
gds.graph.construct("hello", nodes, relationships, concurrency=2)
255197

256198

257-
@pytest.mark.parametrize("server_version", [ServerVersion(2, 1, 0)])
258199
def test_graph_alpha_construct_backward_compat(runner: CollectingQueryRunner, gds: GraphDataScience) -> None:
259200
nodes = DataFrame(
260201
{

graphdatascience/tests/unit/test_graph_cypher.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,10 @@
33

44
from graphdatascience.graph.graph_cypher_runner import GraphCypherRunner
55
from graphdatascience.graph_data_science import GraphDataScience
6-
from graphdatascience.server_version.server_version import ServerVersion
76

87
from .conftest import CollectingQueryRunner
98

109

11-
@pytest.mark.parametrize("server_version", [ServerVersion(2, 4, 0)])
1210
def test_simple(runner: CollectingQueryRunner, gds: GraphDataScience) -> None:
1311
runner.set__mock_result(DataFrame([[{"graphName": "g", "don't squeeze": "me now"}]]))
1412

@@ -20,7 +18,6 @@ def test_simple(runner: CollectingQueryRunner, gds: GraphDataScience) -> None:
2018
assert runner.last_query() == "MATCH (s)-->(t) RETURN gds.graph.project('g', s, t)"
2119

2220

23-
@pytest.mark.parametrize("server_version", [ServerVersion(2, 4, 0)])
2421
def test_fstring(runner: CollectingQueryRunner, gds: GraphDataScience) -> None:
2522
runner.set__mock_result(DataFrame([[{"graphName": "g", "don't squeeze": "me now"}]]))
2623

@@ -33,7 +30,6 @@ def test_fstring(runner: CollectingQueryRunner, gds: GraphDataScience) -> None:
3330
assert runner.last_query() == "MATCH (s)-->(t) RETURN gds.graph.project('g', s, t)"
3431

3532

36-
@pytest.mark.parametrize("server_version", [ServerVersion(2, 4, 0)])
3733
def test_expression(runner: CollectingQueryRunner, gds: GraphDataScience) -> None:
3834
runner.set__mock_result(DataFrame([[{"graphName": "gg", "don't squeeze": "me now"}]]))
3935

@@ -45,7 +41,6 @@ def test_expression(runner: CollectingQueryRunner, gds: GraphDataScience) -> Non
4541
assert runner.last_query() == "WITH 'g' AS suffix MATCH (s)-->(t) RETURN gds.graph.project('g' + suffix, s, t)"
4642

4743

48-
@pytest.mark.parametrize("server_version", [ServerVersion(2, 4, 0)])
4944
def test_with_parameter(runner: CollectingQueryRunner, gds: GraphDataScience) -> None:
5045
runner.set__mock_result(DataFrame([[{"graphName": "g", "don't squeeze": "me now"}]]))
5146

@@ -57,7 +52,6 @@ def test_with_parameter(runner: CollectingQueryRunner, gds: GraphDataScience) ->
5752
assert runner.last_query() == "MATCH (s)-->(t) RETURN gds.graph.project($the_graph, s, t)"
5853

5954

60-
@pytest.mark.parametrize("server_version", [ServerVersion(2, 4, 0)])
6155
def test_with_lots_of_whitespace(runner: CollectingQueryRunner, gds: GraphDataScience) -> None:
6256
runner.set__mock_result(DataFrame([[{"graphName": "g", "don't squeeze": "me now"}]]))
6357

@@ -69,7 +63,6 @@ def test_with_lots_of_whitespace(runner: CollectingQueryRunner, gds: GraphDataSc
6963
assert runner.last_query() == "MATCH (s)-->(t) RETURN gds .graph. project\n(\t'g' ,s, t)"
7064

7165

72-
@pytest.mark.parametrize("server_version", [ServerVersion(2, 4, 0)])
7366
def test_extracting_graph_name(runner: CollectingQueryRunner, gds: GraphDataScience) -> None:
7467
runner.set__mock_result(DataFrame([[{"graphName": "the graph", "don't squeeze": "me now"}]]))
7568

@@ -81,7 +74,6 @@ def test_extracting_graph_name(runner: CollectingQueryRunner, gds: GraphDataScie
8174
assert runner.last_query() == "MATCH (s)-->(t) RETURN gds.graph.project('g', s, t)"
8275

8376

84-
@pytest.mark.parametrize("server_version", [ServerVersion(2, 4, 0)])
8577
def test_with_return_not_being_last(gds: GraphDataScience) -> None:
8678
with pytest.raises(
8779
ValueError,
@@ -90,7 +82,6 @@ def test_with_return_not_being_last(gds: GraphDataScience) -> None:
9082
gds.graph.cypher.project("MATCH (s)-->(t) RETURN gds.graph.project($graph_name, s, t) AS graph")
9183

9284

93-
@pytest.mark.parametrize("server_version", [ServerVersion(2, 4, 0)])
9485
def test_with_no_return(gds: GraphDataScience) -> None:
9586
with pytest.raises(
9687
ValueError,
@@ -99,7 +90,6 @@ def test_with_no_return(gds: GraphDataScience) -> None:
9990
gds.graph.cypher.project("MATCH (s)-->(t)")
10091

10192

102-
@pytest.mark.parametrize("server_version", [ServerVersion(2, 4, 0)])
10393
def test_with_multiple_returns(gds: GraphDataScience) -> None:
10494
with pytest.raises(
10595
ValueError,

0 commit comments

Comments
 (0)