Skip to content

Commit ce88bee

Browse files
committed
Fix progress bar not shown without jobId
Before we did generate a jobId but never passed it to the algorithm call. This lead to the client never being able to fetch progress unless the jobId was provided by the user
1 parent 88b9479 commit ce88bee

File tree

8 files changed

+87
-44
lines changed

8 files changed

+87
-44
lines changed

changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
* Fixed a bug, where sessions could not be created for AuraDB instances of tier `business-critical`.
1313
* Fixed a bug, where sessions would fail on write-back if the Graph was empty.
14+
* Fixed a bug, where the progress bar would not be shown unless the `jobId` parameter was set. The progress bar can be toggled on and off via `GraphDataScience::set_show_progress`.
1415

1516

1617
## Improvements

graphdatascience/algo/algo_proc_runner.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class AlgoProcRunner(IllegalAttrChecker, ABC):
1414
@graph_type_check
1515
def _run_procedure(self, G: Graph, config: dict[str, Any], with_logging: bool = True) -> DataFrame:
1616
params = CallParameters(graph_name=G.name(), config=config)
17+
params.ensure_job_id_in_config()
1718

1819
return self._query_runner.call_procedure(endpoint=self._namespace, params=params, logging=with_logging)
1920

@@ -25,6 +26,7 @@ def estimate(self, G: Graph, **config: Any) -> "Series[Any]":
2526

2627
class StreamModeRunner(AlgoProcRunner):
2728
def __call__(self, G: Graph, **config: Any) -> DataFrame:
29+
# insert job id if not existing
2830
return self._run_procedure(G, config)
2931

3032

graphdatascience/algo/single_mode_algo_endpoints.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ class SingleModeAlgoEndpoints(CallerBase):
99
@property
1010
@compatible_with("triangles", min_inclusive=ServerVersion(2, 5, 0))
1111
def triangles(self) -> StreamModeRunner:
12+
# todo insert job id
1213
return StreamModeRunner(self._query_runner, f"{self._namespace}.triangles", self._server_version)
1314

1415

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,40 @@
11
from collections import OrderedDict
2-
from typing import Any
2+
from typing import Any, Optional
3+
from uuid import uuid4
34

45

56
class CallParameters(OrderedDict[str, Any]):
67
# since Python 3.6 also initializing through CallParameters(**kwargs) is order preserving
78

89
def placeholder_str(self) -> str:
910
return ", ".join([f"${k}" for k in self.keys()])
11+
12+
def get_job_id(self) -> Optional[str]:
13+
config = self["config"] if "config" in self else {}
14+
15+
job_id = None
16+
if "jobId" in config:
17+
job_id = config["jobId"]
18+
19+
if "job_id" in config:
20+
job_id = config["job_id"]
21+
22+
if job_id is None:
23+
return None
24+
25+
return str(job_id)
26+
27+
def ensure_job_id_in_config(self) -> str:
28+
"""
29+
Ensure that a job id is present in the `config` parameter. If not, generate a new one.
30+
This enables the client to check on the progress later on.
31+
"""
32+
config = self.get("config")
33+
if not config:
34+
raise ValueError("config is not set in the parameters")
35+
36+
job_id = self.get_job_id()
37+
if job_id is None:
38+
job_id = str(uuid4())
39+
config["jobId"] = job_id
40+
return job_id

graphdatascience/graph/base_graph_proc_runner.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ def generate(self, graph_name: str, node_count: int, average_degree: int, **conf
238238
params = CallParameters(
239239
graph_name=graph_name, node_count=node_count, average_degree=average_degree, config=config
240240
)
241+
params.ensure_job_id_in_config()
241242

242243
result = self._query_runner.call_procedure(
243244
endpoint=self._namespace,
@@ -264,6 +265,8 @@ def filter(
264265
relationship_filter=relationship_filter,
265266
config=config,
266267
)
268+
params.ensure_job_id_in_config()
269+
267270
result = self._query_runner.call_procedure(
268271
endpoint=self._namespace,
269272
logging=True,

graphdatascience/query_runner/neo4j_query_runner.py

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import time
66
import warnings
77
from typing import Any, NamedTuple, Optional, Union
8-
from uuid import uuid4
98

109
import neo4j
1110
from pandas import DataFrame
@@ -222,8 +221,8 @@ def call_procedure(
222221
def run_cypher_query() -> DataFrame:
223222
return self.run_cypher(query, params, database, custom_error)
224223

225-
if self._resolve_show_progress(logging):
226-
job_id = self._extract_or_create_job_id(params)
224+
job_id = None if not params else params.get_job_id()
225+
if self._resolve_show_progress(logging) and job_id:
227226
return self._progress_logger.run_with_progress_logging(run_cypher_query, job_id, database)
228227
else:
229228
return run_cypher_query()
@@ -310,22 +309,6 @@ def create_graph_constructor(
310309
def set_show_progress(self, show_progress: bool) -> None:
311310
self._show_progress = show_progress
312311

313-
@staticmethod
314-
def _extract_or_create_job_id(params: CallParameters) -> str:
315-
config = params["config"] if "config" in params else {}
316-
317-
job_id = None
318-
if "jobId" in config:
319-
job_id = config["jobId"]
320-
321-
if "job_id" in config:
322-
job_id = config["job_id"]
323-
324-
if not job_id:
325-
return str(uuid4())
326-
327-
return str(job_id)
328-
329312
@staticmethod
330313
def handle_driver_exception(session: neo4j.Session, e: Exception) -> None:
331314
reg_gds_hit = re.search(

graphdatascience/tests/unit/query_runner/test_neo4j_query_runner.py

Lines changed: 0 additions & 24 deletions
This file was deleted.

graphdatascience/tests/unit/test_call_params.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import pytest
2+
13
from graphdatascience.call_parameters import CallParameters
24

35

@@ -14,3 +16,47 @@ def test_empty_params() -> None:
1416
params = CallParameters()
1517

1618
assert params.placeholder_str() == ""
19+
20+
21+
def test_get_job_id() -> None:
22+
# empty params
23+
params = CallParameters({})
24+
job_id = params.get_job_id()
25+
assert job_id is None
26+
27+
# empty job id
28+
params = CallParameters(config={job_id: None})
29+
job_id = params.get_job_id()
30+
assert job_id is None
31+
32+
# job_id given
33+
params = CallParameters(config={"job_id": "foo"})
34+
job_id = params.get_job_id()
35+
assert job_id == "foo"
36+
37+
# jobId given
38+
params = CallParameters(config={"jobId": "bar"})
39+
job_id = params.get_job_id()
40+
assert job_id == "bar"
41+
42+
43+
def test_ensure_job_id() -> None:
44+
# empty params
45+
params = CallParameters({})
46+
with pytest.raises(ValueError, match="config is not set"):
47+
params.ensure_job_id_in_config()
48+
49+
# empty job id
50+
params = CallParameters(config={"job_id": None})
51+
job_id = params.ensure_job_id_in_config()
52+
assert job_id is not None and job_id != ""
53+
54+
# job_id given
55+
params = CallParameters(config={"job_id": "foo"})
56+
job_id = params.ensure_job_id_in_config()
57+
assert job_id == "foo"
58+
59+
# jobId given
60+
params = CallParameters(config={"jobId": "bar"})
61+
job_id = params.ensure_job_id_in_config()
62+
assert job_id == "bar"

0 commit comments

Comments
 (0)