graphdatascience 1.15.1__tar.gz → 1.16__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {graphdatascience-1.15.1/graphdatascience.egg-info → graphdatascience-1.16}/PKG-INFO +2 -2
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/error/cypher_warning_handler.py +4 -7
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/graph/graph_cypher_runner.py +4 -2
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/graph/graph_entity_ops_runner.py +9 -6
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/graph_data_science.py +6 -1
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/query_runner/arrow_query_runner.py +17 -3
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/query_runner/cypher_graph_constructor.py +4 -4
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/query_runner/neo4j_query_runner.py +89 -25
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/query_runner/protocol/project_protocols.py +21 -5
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/query_runner/protocol/write_protocols.py +16 -10
- graphdatascience-1.16/graphdatascience/query_runner/query_mode.py +16 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/query_runner/query_runner.py +15 -1
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/query_runner/session_query_runner.py +22 -5
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/query_runner/standalone_session_query_runner.py +16 -2
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/retry_utils/retry_utils.py +1 -1
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/session/aura_graph_data_science.py +2 -2
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/session/dbms/protocol_resolver.py +2 -2
- graphdatascience-1.16/graphdatascience/session/dbms_connection_info.py +57 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/session/dedicated_sessions.py +8 -4
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/session/gds_sessions.py +25 -3
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/session/session_info.py +1 -1
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/session/session_sizes.py +1 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/topological_lp/topological_lp_alpha_runner.py +2 -2
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/utils/direct_util_endpoints.py +2 -2
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/utils/util_proc_runner.py +2 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/utils/util_remote_proc_runner.py +2 -2
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/version.py +1 -1
- {graphdatascience-1.15.1 → graphdatascience-1.16/graphdatascience.egg-info}/PKG-INFO +2 -2
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience.egg-info/SOURCES.txt +1 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience.egg-info/requires.txt +1 -1
- {graphdatascience-1.15.1 → graphdatascience-1.16}/requirements/base/base.txt +1 -1
- graphdatascience-1.15.1/graphdatascience/session/dbms_connection_info.py +0 -25
- {graphdatascience-1.15.1 → graphdatascience-1.16}/LICENSE +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/MANIFEST.in +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/README.md +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/__init__.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/algo/__init__.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/algo/algo_endpoints.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/algo/algo_proc_runner.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/algo/single_mode_algo_endpoints.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/call_builder.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/call_parameters.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/caller_base.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/endpoints.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/error/__init__.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/error/client_only_endpoint.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/error/endpoint_suggester.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/error/gds_not_installed.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/error/illegal_attr_checker.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/error/unable_to_connect.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/error/uncallable_namespace.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/graph/__init__.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/graph/base_graph_proc_runner.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/graph/graph_alpha_proc_runner.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/graph/graph_beta_proc_runner.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/graph/graph_create_result.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/graph/graph_endpoints.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/graph/graph_export_runner.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/graph/graph_object.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/graph/graph_proc_runner.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/graph/graph_project_runner.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/graph/graph_remote_proc_runner.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/graph/graph_remote_project_runner.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/graph/graph_sample_runner.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/graph/graph_type_check.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/graph/nx_loader.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/graph/ogb_loader.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/ignored_server_endpoints.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/model/__init__.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/model/graphsage_model.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/model/link_prediction_model.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/model/model.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/model/model_alpha_proc_runner.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/model/model_beta_proc_runner.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/model/model_endpoints.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/model/model_proc_runner.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/model/model_resolver.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/model/node_classification_model.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/model/node_regression_model.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/model/pipeline_model.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/model/simple_rel_embedding_model.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/pipeline/__init__.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/pipeline/classification_training_pipeline.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/pipeline/lp_pipeline_create_runner.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/pipeline/lp_training_pipeline.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/pipeline/nc_pipeline_create_runner.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/pipeline/nc_training_pipeline.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/pipeline/nr_pipeline_create_runner.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/pipeline/nr_training_pipeline.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/pipeline/pipeline_alpha_proc_runner.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/pipeline/pipeline_beta_proc_runner.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/pipeline/pipeline_endpoints.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/pipeline/pipeline_proc_runner.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/pipeline/training_pipeline.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/py.typed +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/query_runner/__init__.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/query_runner/arrow_authentication.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/query_runner/arrow_endpoint_version.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/query_runner/arrow_graph_constructor.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/query_runner/arrow_info.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/query_runner/gds_arrow_client.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/query_runner/graph_constructor.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/query_runner/progress/__init__.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/query_runner/progress/progress_provider.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/query_runner/progress/query_progress_logger.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/query_runner/progress/query_progress_provider.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/query_runner/progress/static_progress_provider.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/query_runner/protocol/__init__.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/query_runner/protocol/status.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/query_runner/termination_flag.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/resources/__init__.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/resources/cora/__init__.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/resources/cora/cora_nodes.parquet.gzip +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/resources/cora/cora_rels.parquet.gzip +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/resources/cora/serialize_cora.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/resources/imdb/__init__.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/resources/imdb/imdb_acted_in.parquet.gzip +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/resources/imdb/imdb_actors.parquet.gzip +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/resources/imdb/imdb_directed_in.parquet.gzip +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/resources/imdb/imdb_directors.parquet.gzip +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/resources/imdb/imdb_movies_with_genre.parquet.gzip +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/resources/imdb/imdb_movies_without_genre.parquet.gzip +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/resources/imdb/serialize_imdb.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/resources/karate/__init__.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/resources/karate/karate_club.parquet.gzip +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/resources/lastfm/__init__.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/resources/lastfm/artist_nodes.parquet.gzip +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/resources/lastfm/serialize_lastfm.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/resources/lastfm/user_friend_df_directed.parquet.gzip +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/resources/lastfm/user_listen_artist_rels.parquet.gzip +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/resources/lastfm/user_nodes.parquet.gzip +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/resources/lastfm/user_tag_artist_rels.parquet.gzip +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/retry_utils/__init__.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/retry_utils/retry_config.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/semantic_version/__init__.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/semantic_version/semantic_version.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/server_version/__init__.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/server_version/compatible_with.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/server_version/server_version.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/session/__init__.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/session/algorithm_category.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/session/aura_api.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/session/aura_api_responses.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/session/aura_api_token_authentication.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/session/aurads_sessions.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/session/cloud_location.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/session/dbms/__init__.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/session/dbms/protocol_version.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/session/region_suggester.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/system/__init__.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/system/config_endpoints.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/system/system_endpoints.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/topological_lp/__init__.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/topological_lp/topological_lp_endpoints.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/utils/__init__.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/utils/util_node_property_func_runner.py +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience.egg-info/dependency_links.txt +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience.egg-info/not-zip-safe +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience.egg-info/top_level.txt +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/pyproject.toml +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/requirements/base/networkx.txt +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/requirements/base/ogb.txt +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/requirements/base/rust-ext.txt +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/setup.cfg +0 -0
- {graphdatascience-1.15.1 → graphdatascience-1.16}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: graphdatascience
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.16
|
|
4
4
|
Summary: A Python client for the Neo4j Graph Data Science (GDS) library
|
|
5
5
|
Home-page: https://neo4j.com/product/graph-data-science/
|
|
6
6
|
Author: Neo4j
|
|
@@ -32,7 +32,7 @@ Requires-Dist: multimethod<3.0,>=1.0
|
|
|
32
32
|
Requires-Dist: neo4j<6.0,>=4.4.12
|
|
33
33
|
Requires-Dist: numpy<2.3
|
|
34
34
|
Requires-Dist: pandas<3.0,>=1.0
|
|
35
|
-
Requires-Dist: pyarrow<
|
|
35
|
+
Requires-Dist: pyarrow<21.0,>=17.0
|
|
36
36
|
Requires-Dist: textdistance<5.0,>=4.0
|
|
37
37
|
Requires-Dist: tqdm<5.0,>=4.0
|
|
38
38
|
Requires-Dist: typing-extensions<5.0,>=4.0
|
{graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/error/cypher_warning_handler.py
RENAMED
|
@@ -19,15 +19,12 @@ def filter_id_func_deprecation_warning() -> Callable[[F], F]:
|
|
|
19
19
|
message=r"^The query used a deprecated function: `id`\.",
|
|
20
20
|
)
|
|
21
21
|
|
|
22
|
+
# previously The query used a deprecated function. ('id' is no longer supported)
|
|
23
|
+
# since 2025.04.0 The query used a deprecated function. ('id' has been replaced by 'elementId or an application-generated id')
|
|
24
|
+
# since 2025.06 The query used a deprecated function. ('id' has been replaced by 'elementId or consider using an application-generated id')
|
|
22
25
|
warnings.filterwarnings(
|
|
23
26
|
"ignore",
|
|
24
|
-
message=r"
|
|
25
|
-
)
|
|
26
|
-
|
|
27
|
-
# since 2025.04.0
|
|
28
|
-
warnings.filterwarnings(
|
|
29
|
-
"ignore",
|
|
30
|
-
message=r"^The query used a deprecated function. \('id' has been replaced by 'elementId or an application-generated id'\)",
|
|
27
|
+
message=r"The query used a deprecated function. \('id'.*",
|
|
31
28
|
)
|
|
32
29
|
|
|
33
30
|
return func(self, *args, **kwargs)
|
{graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/graph/graph_cypher_runner.py
RENAMED
|
@@ -45,7 +45,9 @@ class GraphCypherRunner(CallerBase):
|
|
|
45
45
|
|
|
46
46
|
GraphCypherRunner._verify_query_ends_with_return_clause(self._namespace, query)
|
|
47
47
|
|
|
48
|
-
result: Optional[dict[str, Any]] = self._query_runner.
|
|
48
|
+
result: Optional[dict[str, Any]] = self._query_runner.run_retryable_cypher(
|
|
49
|
+
query, params, database, custom_error=False
|
|
50
|
+
).squeeze()
|
|
49
51
|
|
|
50
52
|
if not result:
|
|
51
53
|
raise ValueError("Projected graph cannot be empty.")
|
|
@@ -101,7 +103,7 @@ class GraphCypherRunner(CallerBase):
|
|
|
101
103
|
at_end = True
|
|
102
104
|
break
|
|
103
105
|
|
|
104
|
-
if query_token == "RETURN":
|
|
106
|
+
if query_token.upper() == "RETURN":
|
|
105
107
|
# State 1: We found the start of a `RETURN` clause.
|
|
106
108
|
# Check if it is the `RETURN gds.graph.project` call.
|
|
107
109
|
# We split tokens on `__separators` and flatten the nested iters.
|
{graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/graph/graph_entity_ops_runner.py
RENAMED
|
@@ -158,12 +158,13 @@ class GraphNodePropertiesRunner(GraphEntityOpsBaseRunner):
|
|
|
158
158
|
duplicate_properties = set(db_node_properties).intersection(set(node_properties))
|
|
159
159
|
if duplicate_properties:
|
|
160
160
|
raise ValueError(
|
|
161
|
-
f"Duplicate property keys '{duplicate_properties}' in db_node_properties and
|
|
161
|
+
f"Duplicate property keys '{duplicate_properties}' in db_node_properties and node_properties."
|
|
162
162
|
)
|
|
163
163
|
|
|
164
164
|
unique_node_ids = result["nodeId"].drop_duplicates().tolist()
|
|
165
|
-
|
|
166
|
-
|
|
165
|
+
|
|
166
|
+
db_properties_df = query_runner.run_retryable_cypher(
|
|
167
|
+
GraphNodePropertiesRunner._build_query(db_node_properties), params={"ids": unique_node_ids}
|
|
167
168
|
)
|
|
168
169
|
|
|
169
170
|
if "propertyValue" not in result.keys():
|
|
@@ -342,7 +343,7 @@ class GraphRelationshipsRunner(GraphEntityOpsBaseRunner):
|
|
|
342
343
|
def stream(self, G: Graph, relationship_types: list[str] = ["*"], **config: Any) -> TopologyDataFrame:
|
|
343
344
|
self._namespace += ".stream"
|
|
344
345
|
params = CallParameters(graph_name=G.name(), relationship_types=relationship_types, config=config)
|
|
345
|
-
result = self._query_runner.call_procedure(endpoint=self._namespace, params=params)
|
|
346
|
+
result = self._query_runner.call_procedure(endpoint=self._namespace, params=params, retryable=True)
|
|
346
347
|
|
|
347
348
|
return TopologyDataFrame(result)
|
|
348
349
|
|
|
@@ -360,7 +361,9 @@ class GraphRelationshipsBetaRunner(GraphEntityOpsBaseRunner):
|
|
|
360
361
|
self._namespace += ".stream"
|
|
361
362
|
params = CallParameters(graph_name=G.name(), relationship_types=relationship_types, config=config)
|
|
362
363
|
|
|
363
|
-
return TopologyDataFrame(
|
|
364
|
+
return TopologyDataFrame(
|
|
365
|
+
self._query_runner.call_procedure(endpoint=self._namespace, params=params, retryable=True)
|
|
366
|
+
)
|
|
364
367
|
|
|
365
368
|
@property
|
|
366
369
|
@compatible_with("toUndirected", min_inclusive=ServerVersion(2, 3, 0))
|
|
@@ -381,7 +384,7 @@ class GraphPropertyRunner(UncallableNamespace, IllegalAttrChecker):
|
|
|
381
384
|
self._namespace += ".stream"
|
|
382
385
|
params = CallParameters(graph_name=G.name(), graph_property=graph_property, config=config)
|
|
383
386
|
|
|
384
|
-
return self._query_runner.call_procedure(endpoint=self._namespace, params=params)
|
|
387
|
+
return self._query_runner.call_procedure(endpoint=self._namespace, params=params, retryable=True)
|
|
385
388
|
|
|
386
389
|
@compatible_with("drop", min_inclusive=ServerVersion(2, 2, 0))
|
|
387
390
|
@graph_type_check
|
|
@@ -4,6 +4,7 @@ import warnings
|
|
|
4
4
|
from types import TracebackType
|
|
5
5
|
from typing import Any, Optional, Type, Union
|
|
6
6
|
|
|
7
|
+
import neo4j
|
|
7
8
|
from neo4j import Driver
|
|
8
9
|
from pandas import DataFrame
|
|
9
10
|
|
|
@@ -78,8 +79,11 @@ class GraphDataScience(DirectEndpoints, UncallableNamespace):
|
|
|
78
79
|
if isinstance(endpoint, QueryRunner):
|
|
79
80
|
self._query_runner = endpoint
|
|
80
81
|
else:
|
|
82
|
+
db_auth = None
|
|
83
|
+
if auth:
|
|
84
|
+
db_auth = neo4j.basic_auth(*auth)
|
|
81
85
|
self._query_runner = Neo4jQueryRunner.create_for_db(
|
|
82
|
-
endpoint,
|
|
86
|
+
endpoint, db_auth, aura_ds, database, bookmarks, show_progress
|
|
83
87
|
)
|
|
84
88
|
|
|
85
89
|
self._server_version = self._query_runner.server_version()
|
|
@@ -218,6 +222,7 @@ class GraphDataScience(DirectEndpoints, UncallableNamespace):
|
|
|
218
222
|
if isinstance(self._query_runner, ArrowQueryRunner):
|
|
219
223
|
qr = self._query_runner.fallback_query_runner()
|
|
220
224
|
|
|
225
|
+
# not using qr.run_retryable_cypher as we dont know if it can be retried
|
|
221
226
|
return qr.run_cypher(query, params, database, False)
|
|
222
227
|
|
|
223
228
|
def driver_config(self) -> dict[str, Any]:
|
|
@@ -6,6 +6,7 @@ from typing import Any, Optional
|
|
|
6
6
|
from pandas import DataFrame
|
|
7
7
|
|
|
8
8
|
from graphdatascience.query_runner.arrow_authentication import ArrowAuthentication
|
|
9
|
+
from graphdatascience.query_runner.query_mode import QueryMode
|
|
9
10
|
from graphdatascience.retry_utils.retry_config import RetryConfig
|
|
10
11
|
|
|
11
12
|
from ..call_parameters import CallParameters
|
|
@@ -68,6 +69,15 @@ class ArrowQueryRunner(QueryRunner):
|
|
|
68
69
|
) -> DataFrame:
|
|
69
70
|
return self._fallback_query_runner.run_cypher(query, params, database, custom_error)
|
|
70
71
|
|
|
72
|
+
def run_retryable_cypher(
|
|
73
|
+
self,
|
|
74
|
+
query: str,
|
|
75
|
+
params: Optional[dict[str, Any]] = None,
|
|
76
|
+
database: Optional[str] = None,
|
|
77
|
+
custom_error: bool = True,
|
|
78
|
+
) -> DataFrame:
|
|
79
|
+
return self._fallback_query_runner.run_retryable_cypher(query, params, database, custom_error=custom_error)
|
|
80
|
+
|
|
71
81
|
def call_function(self, endpoint: str, params: Optional[CallParameters] = None) -> Any:
|
|
72
82
|
return self._fallback_query_runner.call_function(endpoint, params)
|
|
73
83
|
|
|
@@ -77,7 +87,9 @@ class ArrowQueryRunner(QueryRunner):
|
|
|
77
87
|
params: Optional[CallParameters] = None,
|
|
78
88
|
yields: Optional[list[str]] = None,
|
|
79
89
|
database: Optional[str] = None,
|
|
90
|
+
mode: QueryMode = QueryMode.READ,
|
|
80
91
|
logging: bool = False,
|
|
92
|
+
retryable: bool = False,
|
|
81
93
|
custom_error: bool = True,
|
|
82
94
|
) -> DataFrame:
|
|
83
95
|
if params is None:
|
|
@@ -171,7 +183,9 @@ class ArrowQueryRunner(QueryRunner):
|
|
|
171
183
|
graph_name, self._database_or_throw(), relationship_types, concurrency
|
|
172
184
|
)
|
|
173
185
|
|
|
174
|
-
return self._fallback_query_runner.call_procedure(
|
|
186
|
+
return self._fallback_query_runner.call_procedure(
|
|
187
|
+
endpoint, params, yields, database, logging=logging, retryable=retryable, custom_error=custom_error
|
|
188
|
+
)
|
|
175
189
|
|
|
176
190
|
def server_version(self) -> ServerVersion:
|
|
177
191
|
return self._fallback_query_runner.server_version()
|
|
@@ -211,10 +225,10 @@ class ArrowQueryRunner(QueryRunner):
|
|
|
211
225
|
self._fallback_query_runner.close()
|
|
212
226
|
self._gds_arrow_client.close()
|
|
213
227
|
|
|
214
|
-
def
|
|
228
|
+
def cloneWithoutRouting(self, host: str, port: int) -> "QueryRunner":
|
|
215
229
|
return ArrowQueryRunner(
|
|
216
230
|
self._gds_arrow_client,
|
|
217
|
-
self._fallback_query_runner.
|
|
231
|
+
self._fallback_query_runner.cloneWithoutRouting(host, port),
|
|
218
232
|
self._server_version,
|
|
219
233
|
)
|
|
220
234
|
|
|
@@ -104,15 +104,14 @@ class CypherGraphConstructor(GraphConstructor):
|
|
|
104
104
|
|
|
105
105
|
def _should_warn_about_arrow_missing(self) -> bool:
|
|
106
106
|
try:
|
|
107
|
-
license: str = self._query_runner.
|
|
107
|
+
license: str = self._query_runner.run_retryable_cypher(
|
|
108
108
|
"CALL gds.debug.sysInfo() YIELD key, value WHERE key = 'gdsEdition' RETURN value", custom_error=False
|
|
109
109
|
).squeeze()
|
|
110
110
|
should_warn = license == "Licensed"
|
|
111
111
|
except Exception as e:
|
|
112
112
|
# It's not a user's concern whether Arrow is set up or not in AuraDS.
|
|
113
|
-
if (
|
|
114
|
-
|
|
115
|
-
"registered for this database instance." in str(e)
|
|
113
|
+
if "There is no procedure with the name `gds.debug.sysInfo` registered for this database instance." in str(
|
|
114
|
+
e
|
|
116
115
|
):
|
|
117
116
|
should_warn = False
|
|
118
117
|
else:
|
|
@@ -210,6 +209,7 @@ class CypherGraphConstructor(GraphConstructor):
|
|
|
210
209
|
"undirectedRelationshipTypes": self._undirected_relationship_types,
|
|
211
210
|
}
|
|
212
211
|
|
|
212
|
+
# not using retryable here as gds.graph.project adds a graph to the gds graph catalog
|
|
213
213
|
self._query_runner.run_cypher(
|
|
214
214
|
query,
|
|
215
215
|
{
|
|
@@ -9,6 +9,8 @@ from typing import Any, NamedTuple, Optional, Union
|
|
|
9
9
|
import neo4j
|
|
10
10
|
from pandas import DataFrame
|
|
11
11
|
|
|
12
|
+
from graphdatascience.query_runner.query_mode import QueryMode
|
|
13
|
+
|
|
12
14
|
from ..call_parameters import CallParameters
|
|
13
15
|
from ..error.endpoint_suggester import generate_suggestive_error_message
|
|
14
16
|
from ..error.gds_not_installed import GdsNotFound
|
|
@@ -30,14 +32,18 @@ class Neo4jQueryRunner(QueryRunner):
|
|
|
30
32
|
@staticmethod
|
|
31
33
|
def create_for_db(
|
|
32
34
|
endpoint: Union[str, neo4j.Driver],
|
|
33
|
-
auth:
|
|
35
|
+
auth: Union[tuple[str, str], neo4j.Auth, None] = None,
|
|
34
36
|
aura_ds: bool = False,
|
|
35
37
|
database: Optional[str] = None,
|
|
36
38
|
bookmarks: Optional[Any] = None,
|
|
37
39
|
show_progress: bool = True,
|
|
40
|
+
config: Optional[dict[str, Any]] = None,
|
|
38
41
|
) -> Neo4jQueryRunner:
|
|
39
42
|
if isinstance(endpoint, str):
|
|
40
|
-
config
|
|
43
|
+
if config is None:
|
|
44
|
+
config = {}
|
|
45
|
+
|
|
46
|
+
config["user_agent"] = f"neo4j-graphdatascience-v{__version__}"
|
|
41
47
|
|
|
42
48
|
if aura_ds:
|
|
43
49
|
Neo4jQueryRunner._configure_aura(config)
|
|
@@ -73,7 +79,7 @@ class Neo4jQueryRunner(QueryRunner):
|
|
|
73
79
|
@staticmethod
|
|
74
80
|
def create_for_session(
|
|
75
81
|
endpoint: str,
|
|
76
|
-
auth:
|
|
82
|
+
auth: Union[tuple[str, str], neo4j.Auth, None] = None,
|
|
77
83
|
show_progress: bool = True,
|
|
78
84
|
) -> Neo4jQueryRunner:
|
|
79
85
|
driver_config: dict[str, Any] = {"user_agent": f"neo4j-graphdatascience-v{__version__}"}
|
|
@@ -100,9 +106,13 @@ class Neo4jQueryRunner(QueryRunner):
|
|
|
100
106
|
|
|
101
107
|
@staticmethod
|
|
102
108
|
def _configure_aura(config: dict[str, Any]) -> None:
|
|
103
|
-
|
|
104
|
-
config
|
|
105
|
-
config
|
|
109
|
+
# defaults as documented in https://support.neo4j.com/s/article/1500001173021-How-to-handle-Session-Expired-Errors-while-connecting-to-Neo4j-Aura
|
|
110
|
+
config.setdefault("max_connection_lifetime", 60 * 50) # 50 minutes
|
|
111
|
+
config.setdefault("keep_alive", True)
|
|
112
|
+
config.setdefault("max_connection_pool_size", 50)
|
|
113
|
+
|
|
114
|
+
if Neo4jQueryRunner._NEO4J_DRIVER_VERSION >= SemanticVersion(5, 16, 0):
|
|
115
|
+
config.setdefault("liveness_check_timeout", 60 * 5) # 5 minutes
|
|
106
116
|
|
|
107
117
|
@staticmethod
|
|
108
118
|
def parse_protocol(endpoint: str) -> str:
|
|
@@ -115,7 +125,7 @@ class Neo4jQueryRunner(QueryRunner):
|
|
|
115
125
|
self,
|
|
116
126
|
driver: neo4j.Driver,
|
|
117
127
|
protocol: str,
|
|
118
|
-
auth:
|
|
128
|
+
auth: Union[tuple[str, str], neo4j.Auth, None] = None,
|
|
119
129
|
config: dict[str, Any] = {},
|
|
120
130
|
database: Optional[str] = neo4j.DEFAULT_DATABASE,
|
|
121
131
|
auto_close: bool = False,
|
|
@@ -142,8 +152,10 @@ class Neo4jQueryRunner(QueryRunner):
|
|
|
142
152
|
def __run_cypher_simplified_for_query_progress_logger(self, query: str, database: Optional[str]) -> DataFrame:
|
|
143
153
|
# progress logging should not retry a lot as it perodically fetches the latest progress anyway
|
|
144
154
|
connectivity_retry_config = Neo4jQueryRunner.ConnectivityRetriesConfig(max_retries=2)
|
|
155
|
+
# not using retryable cypher as failing is okay
|
|
145
156
|
return self.run_cypher(query=query, database=database, connectivity_retry_config=connectivity_retry_config)
|
|
146
157
|
|
|
158
|
+
# only use for user defined queries
|
|
147
159
|
def run_cypher(
|
|
148
160
|
self,
|
|
149
161
|
query: str,
|
|
@@ -187,12 +199,50 @@ class Neo4jQueryRunner(QueryRunner):
|
|
|
187
199
|
|
|
188
200
|
return df
|
|
189
201
|
|
|
190
|
-
|
|
202
|
+
# better retry mechanism than run_cypher. The neo4j driver handles retryable errors internally
|
|
203
|
+
def run_retryable_cypher(
|
|
204
|
+
self,
|
|
205
|
+
query: str,
|
|
206
|
+
params: Optional[dict[str, Any]] = None,
|
|
207
|
+
database: Optional[str] = None,
|
|
208
|
+
custom_error: bool = True,
|
|
209
|
+
mode: Optional[QueryMode] = None,
|
|
210
|
+
connectivity_retry_config: Optional[ConnectivityRetriesConfig] = None,
|
|
211
|
+
) -> DataFrame:
|
|
212
|
+
if not database:
|
|
213
|
+
database = self._database
|
|
214
|
+
|
|
215
|
+
if self._NEO4J_DRIVER_VERSION < SemanticVersion(5, 5, 0):
|
|
216
|
+
return self.run_cypher(query, params, database, custom_error, connectivity_retry_config)
|
|
217
|
+
|
|
218
|
+
if not mode:
|
|
219
|
+
routing = neo4j.RoutingControl.READ
|
|
220
|
+
else:
|
|
221
|
+
routing = mode.neo4j_routing()
|
|
222
|
+
|
|
223
|
+
try:
|
|
224
|
+
return self._driver.execute_query(
|
|
225
|
+
query_=query,
|
|
226
|
+
parameters_=params,
|
|
227
|
+
database_=database,
|
|
228
|
+
result_transformer_=neo4j.Result.to_df,
|
|
229
|
+
bookmark_manager_=self.bookmarks(),
|
|
230
|
+
routing_=routing,
|
|
231
|
+
)
|
|
232
|
+
except Exception as e:
|
|
233
|
+
if custom_error:
|
|
234
|
+
Neo4jQueryRunner.handle_driver_exception(self._driver, e)
|
|
235
|
+
raise e
|
|
236
|
+
else:
|
|
237
|
+
raise e
|
|
238
|
+
|
|
239
|
+
def call_function(self, endpoint: str, params: Optional[CallParameters] = None, custom_error: bool = True) -> Any:
|
|
191
240
|
if params is None:
|
|
192
241
|
params = CallParameters()
|
|
193
242
|
query = f"RETURN {endpoint}({params.placeholder_str()})"
|
|
194
243
|
|
|
195
|
-
|
|
244
|
+
# we can use retryable cypher as we expect all gds functions to be idempotent
|
|
245
|
+
return self.run_retryable_cypher(query, params, custom_error=custom_error, mode=QueryMode.READ).squeeze()
|
|
196
246
|
|
|
197
247
|
def call_procedure(
|
|
198
248
|
self,
|
|
@@ -200,7 +250,9 @@ class Neo4jQueryRunner(QueryRunner):
|
|
|
200
250
|
params: Optional[CallParameters] = None,
|
|
201
251
|
yields: Optional[list[str]] = None,
|
|
202
252
|
database: Optional[str] = None,
|
|
253
|
+
mode: QueryMode = QueryMode.READ,
|
|
203
254
|
logging: bool = False,
|
|
255
|
+
retryable: bool = False,
|
|
204
256
|
custom_error: bool = True,
|
|
205
257
|
) -> DataFrame:
|
|
206
258
|
if params is None:
|
|
@@ -210,7 +262,10 @@ class Neo4jQueryRunner(QueryRunner):
|
|
|
210
262
|
query = f"CALL {endpoint}({params.placeholder_str()}){yields_clause}"
|
|
211
263
|
|
|
212
264
|
def run_cypher_query() -> DataFrame:
|
|
213
|
-
|
|
265
|
+
if retryable:
|
|
266
|
+
return self.run_retryable_cypher(query, params, database, custom_error, mode=mode)
|
|
267
|
+
else:
|
|
268
|
+
return self.run_cypher(query, params, database, custom_error)
|
|
214
269
|
|
|
215
270
|
job_id = None if not params else params.get_job_id()
|
|
216
271
|
if self._resolve_show_progress(logging) and job_id:
|
|
@@ -226,7 +281,7 @@ class Neo4jQueryRunner(QueryRunner):
|
|
|
226
281
|
return self._server_version
|
|
227
282
|
|
|
228
283
|
try:
|
|
229
|
-
server_version_string = self.
|
|
284
|
+
server_version_string = self.call_function("gds.version", custom_error=False)
|
|
230
285
|
server_version = ServerVersion.from_string(server_version_string)
|
|
231
286
|
self._server_version = server_version
|
|
232
287
|
return server_version
|
|
@@ -300,24 +355,25 @@ class Neo4jQueryRunner(QueryRunner):
|
|
|
300
355
|
def set_show_progress(self, show_progress: bool) -> None:
|
|
301
356
|
self._show_progress = show_progress
|
|
302
357
|
|
|
303
|
-
def
|
|
304
|
-
|
|
358
|
+
def cloneWithoutRouting(self, host: str, port: int) -> QueryRunner:
|
|
359
|
+
protocol = self._protocol.replace("neo4j", "bolt")
|
|
360
|
+
endpoint = "{}://{}:{}".format(protocol, host, port)
|
|
305
361
|
driver = neo4j.GraphDatabase.driver(endpoint, auth=self._auth, **self.driver_config())
|
|
306
362
|
|
|
307
363
|
return Neo4jQueryRunner(
|
|
308
|
-
driver,
|
|
309
|
-
|
|
310
|
-
self._auth,
|
|
311
|
-
self._config,
|
|
312
|
-
self._database,
|
|
313
|
-
self._auto_close,
|
|
314
|
-
self._bookmarks,
|
|
315
|
-
self._show_progress,
|
|
316
|
-
self._instance_description,
|
|
364
|
+
driver=driver,
|
|
365
|
+
protocol=protocol,
|
|
366
|
+
auth=self._auth,
|
|
367
|
+
config=self._config,
|
|
368
|
+
database=self._database,
|
|
369
|
+
auto_close=self._auto_close,
|
|
370
|
+
bookmarks=self._bookmarks,
|
|
371
|
+
show_progress=self._show_progress,
|
|
372
|
+
instance_description=self._instance_description,
|
|
317
373
|
)
|
|
318
374
|
|
|
319
375
|
@staticmethod
|
|
320
|
-
def handle_driver_exception(
|
|
376
|
+
def handle_driver_exception(cypher_executor: Union[neo4j.Session, neo4j.Driver], e: Exception) -> None:
|
|
321
377
|
reg_gds_hit = re.search(
|
|
322
378
|
r"There is no procedure with the name `(gds(?:\.\w+)+)` registered for this database instance",
|
|
323
379
|
str(e),
|
|
@@ -327,8 +383,16 @@ class Neo4jQueryRunner(QueryRunner):
|
|
|
327
383
|
|
|
328
384
|
requested_endpoint = reg_gds_hit.group(1)
|
|
329
385
|
|
|
330
|
-
|
|
331
|
-
|
|
386
|
+
if isinstance(cypher_executor, neo4j.Session):
|
|
387
|
+
list_result = cypher_executor.run("CALL gds.list() YIELD name")
|
|
388
|
+
all_endpoints = list_result.to_df()["name"].tolist()
|
|
389
|
+
elif isinstance(cypher_executor, neo4j.Driver):
|
|
390
|
+
result = cypher_executor.execute_query("CALL gds.list() YIELD name", result_transformer_=neo4j.Result.to_df)
|
|
391
|
+
all_endpoints = result["name"].tolist()
|
|
392
|
+
else:
|
|
393
|
+
raise TypeError(
|
|
394
|
+
f"Expected cypher_executor to be a neo4j.Session or neo4j.Driver, got {type(cypher_executor)}"
|
|
395
|
+
)
|
|
332
396
|
|
|
333
397
|
raise SyntaxError(generate_suggestive_error_message(requested_endpoint, all_endpoints)) from e
|
|
334
398
|
|
|
@@ -68,7 +68,9 @@ class ProjectProtocolV1(ProjectProtocol):
|
|
|
68
68
|
logging: bool = False,
|
|
69
69
|
) -> DataFrame:
|
|
70
70
|
versioned_endpoint = ProtocolVersion.V1.versioned_procedure_name(endpoint)
|
|
71
|
-
return query_runner.call_procedure(
|
|
71
|
+
return query_runner.call_procedure(
|
|
72
|
+
versioned_endpoint, params, yields, database=database, logging=logging, retryable=False, custom_error=False
|
|
73
|
+
)
|
|
72
74
|
|
|
73
75
|
|
|
74
76
|
class ProjectProtocolV2(ProjectProtocol):
|
|
@@ -97,7 +99,9 @@ class ProjectProtocolV2(ProjectProtocol):
|
|
|
97
99
|
logging: bool = False,
|
|
98
100
|
) -> DataFrame:
|
|
99
101
|
versioned_endpoint = ProtocolVersion.V2.versioned_procedure_name(endpoint)
|
|
100
|
-
return query_runner.call_procedure(
|
|
102
|
+
return query_runner.call_procedure(
|
|
103
|
+
versioned_endpoint, params, yields, database=database, logging=logging, retryable=False, custom_error=False
|
|
104
|
+
)
|
|
101
105
|
|
|
102
106
|
|
|
103
107
|
class ProjectProtocolV3(ProjectProtocol):
|
|
@@ -134,11 +138,17 @@ class ProjectProtocolV3(ProjectProtocol):
|
|
|
134
138
|
|
|
135
139
|
# We need to pin the driver to a specific cluster member
|
|
136
140
|
response = query_runner.call_procedure(
|
|
137
|
-
ProtocolVersion.V3.versioned_procedure_name(endpoint),
|
|
141
|
+
ProtocolVersion.V3.versioned_procedure_name(endpoint),
|
|
142
|
+
params,
|
|
143
|
+
yields,
|
|
144
|
+
database,
|
|
145
|
+
logging=logging,
|
|
146
|
+
custom_error=False,
|
|
147
|
+
retryable=True,
|
|
138
148
|
).squeeze()
|
|
139
149
|
member_host = response["host"]
|
|
140
150
|
member_port = response["port"] if ("port" in response.index) else 7687
|
|
141
|
-
projection_query_runner = query_runner.
|
|
151
|
+
projection_query_runner = query_runner.cloneWithoutRouting(member_host, member_port)
|
|
142
152
|
|
|
143
153
|
@retry(
|
|
144
154
|
reraise=True,
|
|
@@ -149,7 +159,13 @@ class ProjectProtocolV3(ProjectProtocol):
|
|
|
149
159
|
def project_fn() -> DataFrame:
|
|
150
160
|
termination_flag.assert_running()
|
|
151
161
|
return projection_query_runner.call_procedure(
|
|
152
|
-
ProtocolVersion.V3.versioned_procedure_name(endpoint),
|
|
162
|
+
ProtocolVersion.V3.versioned_procedure_name(endpoint),
|
|
163
|
+
params,
|
|
164
|
+
yields,
|
|
165
|
+
database=database,
|
|
166
|
+
logging=logging,
|
|
167
|
+
retryable=True,
|
|
168
|
+
custom_error=False,
|
|
153
169
|
)
|
|
154
170
|
|
|
155
171
|
projection_result = project_fn()
|
|
@@ -5,9 +5,10 @@ from typing import Any, Optional
|
|
|
5
5
|
from pandas import DataFrame
|
|
6
6
|
from tenacity import retry, retry_if_result, wait_incrementing
|
|
7
7
|
|
|
8
|
-
from graphdatascience import QueryRunner
|
|
9
8
|
from graphdatascience.call_parameters import CallParameters
|
|
10
9
|
from graphdatascience.query_runner.protocol.status import Status
|
|
10
|
+
from graphdatascience.query_runner.query_mode import QueryMode
|
|
11
|
+
from graphdatascience.query_runner.query_runner import QueryRunner
|
|
11
12
|
from graphdatascience.query_runner.termination_flag import TerminationFlag
|
|
12
13
|
from graphdatascience.retry_utils.retry_utils import before_log
|
|
13
14
|
from graphdatascience.session.dbms.protocol_version import ProtocolVersion
|
|
@@ -73,9 +74,11 @@ class RemoteWriteBackV1(WriteProtocol):
|
|
|
73
74
|
ProtocolVersion.V1.versioned_procedure_name("gds.arrow.write"),
|
|
74
75
|
parameters,
|
|
75
76
|
yields,
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
False,
|
|
77
|
+
retryable=False,
|
|
78
|
+
database=None,
|
|
79
|
+
logging=False,
|
|
80
|
+
mode=QueryMode.WRITE,
|
|
81
|
+
custom_error=False,
|
|
79
82
|
)
|
|
80
83
|
|
|
81
84
|
|
|
@@ -111,9 +114,11 @@ class RemoteWriteBackV2(WriteProtocol):
|
|
|
111
114
|
ProtocolVersion.V2.versioned_procedure_name("gds.arrow.write"),
|
|
112
115
|
parameters,
|
|
113
116
|
yields,
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
False,
|
|
117
|
+
retryable=False,
|
|
118
|
+
database=None,
|
|
119
|
+
logging=False,
|
|
120
|
+
mode=QueryMode.WRITE,
|
|
121
|
+
custom_error=False,
|
|
117
122
|
)
|
|
118
123
|
|
|
119
124
|
|
|
@@ -157,9 +162,10 @@ class RemoteWriteBackV3(WriteProtocol):
|
|
|
157
162
|
ProtocolVersion.V3.versioned_procedure_name("gds.arrow.write"),
|
|
158
163
|
parameters,
|
|
159
164
|
yields,
|
|
160
|
-
|
|
161
|
-
False,
|
|
162
|
-
|
|
165
|
+
retryable=True,
|
|
166
|
+
logging=False,
|
|
167
|
+
mode=QueryMode.WRITE,
|
|
168
|
+
custom_error=False,
|
|
163
169
|
)
|
|
164
170
|
|
|
165
171
|
return write_fn()
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
import neo4j
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class QueryMode(str, Enum):
|
|
7
|
+
READ = "read"
|
|
8
|
+
WRITE = "write"
|
|
9
|
+
|
|
10
|
+
def neo4j_routing(self) -> "neo4j.RoutingControl":
|
|
11
|
+
if self == QueryMode.READ:
|
|
12
|
+
return neo4j.RoutingControl.READ
|
|
13
|
+
elif self == QueryMode.WRITE:
|
|
14
|
+
return neo4j.RoutingControl.WRITE
|
|
15
|
+
else:
|
|
16
|
+
raise ValueError(f"Unknown query mode: {self}")
|
{graphdatascience-1.15.1 → graphdatascience-1.16}/graphdatascience/query_runner/query_runner.py
RENAMED
|
@@ -3,6 +3,8 @@ from typing import Any, Optional
|
|
|
3
3
|
|
|
4
4
|
from pandas import DataFrame
|
|
5
5
|
|
|
6
|
+
from graphdatascience.query_runner.query_mode import QueryMode
|
|
7
|
+
|
|
6
8
|
from ..call_parameters import CallParameters
|
|
7
9
|
from ..server_version.server_version import ServerVersion
|
|
8
10
|
from .graph_constructor import GraphConstructor
|
|
@@ -16,7 +18,9 @@ class QueryRunner(ABC):
|
|
|
16
18
|
params: Optional[CallParameters] = None,
|
|
17
19
|
yields: Optional[list[str]] = None,
|
|
18
20
|
database: Optional[str] = None,
|
|
21
|
+
mode: QueryMode = QueryMode.READ,
|
|
19
22
|
logging: bool = False,
|
|
23
|
+
retryable: bool = False,
|
|
20
24
|
custom_error: bool = True,
|
|
21
25
|
) -> DataFrame:
|
|
22
26
|
pass
|
|
@@ -35,6 +39,16 @@ class QueryRunner(ABC):
|
|
|
35
39
|
) -> DataFrame:
|
|
36
40
|
pass
|
|
37
41
|
|
|
42
|
+
@abstractmethod
|
|
43
|
+
def run_retryable_cypher(
|
|
44
|
+
self,
|
|
45
|
+
query: str,
|
|
46
|
+
params: Optional[dict[str, Any]] = None,
|
|
47
|
+
database: Optional[str] = None,
|
|
48
|
+
custom_error: bool = True,
|
|
49
|
+
) -> DataFrame:
|
|
50
|
+
pass
|
|
51
|
+
|
|
38
52
|
@abstractmethod
|
|
39
53
|
def server_version(self) -> ServerVersion:
|
|
40
54
|
pass
|
|
@@ -81,7 +95,7 @@ class QueryRunner(ABC):
|
|
|
81
95
|
pass
|
|
82
96
|
|
|
83
97
|
@abstractmethod
|
|
84
|
-
def
|
|
98
|
+
def cloneWithoutRouting(self, host: str, port: int) -> "QueryRunner":
|
|
85
99
|
pass
|
|
86
100
|
|
|
87
101
|
def set_server_version(self, _: ServerVersion) -> None:
|