graphdatascience 1.15a1__tar.gz → 1.15a2__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.15a1/graphdatascience.egg-info → graphdatascience-1.15a2}/PKG-INFO +1 -1
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/error/cypher_warning_handler.py +6 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/graph_data_science.py +8 -1
- graphdatascience-1.15a2/graphdatascience/query_runner/arrow_authentication.py +18 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/query_runner/arrow_query_runner.py +3 -2
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/query_runner/gds_arrow_client.py +20 -14
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/query_runner/neo4j_query_runner.py +29 -39
- graphdatascience-1.15a2/graphdatascience/query_runner/standalone_session_query_runner.py +76 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/session/__init__.py +3 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/session/aura_api.py +61 -40
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/session/aura_api_responses.py +43 -16
- graphdatascience-1.15a2/graphdatascience/session/aura_api_token_authentication.py +10 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/session/aura_graph_data_science.py +37 -28
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/session/dedicated_sessions.py +78 -50
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/session/gds_sessions.py +7 -7
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/session/session_info.py +8 -4
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/version.py +1 -1
- {graphdatascience-1.15a1 → graphdatascience-1.15a2/graphdatascience.egg-info}/PKG-INFO +1 -1
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience.egg-info/SOURCES.txt +3 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/LICENSE +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/MANIFEST.in +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/README.md +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/__init__.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/algo/__init__.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/algo/algo_endpoints.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/algo/algo_proc_runner.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/algo/single_mode_algo_endpoints.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/call_builder.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/call_parameters.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/caller_base.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/endpoints.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/error/__init__.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/error/client_only_endpoint.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/error/endpoint_suggester.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/error/gds_not_installed.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/error/illegal_attr_checker.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/error/unable_to_connect.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/error/uncallable_namespace.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/graph/__init__.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/graph/base_graph_proc_runner.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/graph/graph_alpha_proc_runner.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/graph/graph_beta_proc_runner.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/graph/graph_create_result.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/graph/graph_cypher_runner.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/graph/graph_endpoints.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/graph/graph_entity_ops_runner.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/graph/graph_export_runner.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/graph/graph_object.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/graph/graph_proc_runner.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/graph/graph_project_runner.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/graph/graph_remote_proc_runner.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/graph/graph_remote_project_runner.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/graph/graph_sample_runner.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/graph/graph_type_check.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/graph/nx_loader.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/graph/ogb_loader.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/ignored_server_endpoints.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/model/__init__.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/model/graphsage_model.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/model/link_prediction_model.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/model/model.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/model/model_alpha_proc_runner.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/model/model_beta_proc_runner.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/model/model_endpoints.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/model/model_proc_runner.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/model/model_resolver.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/model/node_classification_model.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/model/node_regression_model.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/model/pipeline_model.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/model/simple_rel_embedding_model.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/pipeline/__init__.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/pipeline/classification_training_pipeline.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/pipeline/lp_pipeline_create_runner.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/pipeline/lp_training_pipeline.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/pipeline/nc_pipeline_create_runner.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/pipeline/nc_training_pipeline.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/pipeline/nr_pipeline_create_runner.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/pipeline/nr_training_pipeline.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/pipeline/pipeline_alpha_proc_runner.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/pipeline/pipeline_beta_proc_runner.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/pipeline/pipeline_endpoints.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/pipeline/pipeline_proc_runner.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/pipeline/training_pipeline.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/py.typed +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/query_runner/__init__.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/query_runner/arrow_endpoint_version.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/query_runner/arrow_graph_constructor.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/query_runner/arrow_info.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/query_runner/cypher_graph_constructor.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/query_runner/graph_constructor.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/query_runner/progress/__init__.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/query_runner/progress/progress_provider.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/query_runner/progress/query_progress_logger.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/query_runner/progress/query_progress_provider.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/query_runner/progress/static_progress_provider.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/query_runner/protocol/__init__.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/query_runner/protocol/project_protocols.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/query_runner/protocol/status.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/query_runner/protocol/write_protocols.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/query_runner/query_runner.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/query_runner/session_query_runner.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/query_runner/termination_flag.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/resources/__init__.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/resources/cora/__init__.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/resources/cora/cora_nodes.parquet.gzip +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/resources/cora/cora_rels.parquet.gzip +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/resources/cora/serialize_cora.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/resources/imdb/__init__.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/resources/imdb/imdb_acted_in.parquet.gzip +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/resources/imdb/imdb_actors.parquet.gzip +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/resources/imdb/imdb_directed_in.parquet.gzip +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/resources/imdb/imdb_directors.parquet.gzip +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/resources/imdb/imdb_movies_with_genre.parquet.gzip +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/resources/imdb/imdb_movies_without_genre.parquet.gzip +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/resources/imdb/serialize_imdb.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/resources/karate/__init__.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/resources/karate/karate_club.parquet.gzip +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/resources/lastfm/__init__.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/resources/lastfm/artist_nodes.parquet.gzip +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/resources/lastfm/serialize_lastfm.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/resources/lastfm/user_friend_df_directed.parquet.gzip +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/resources/lastfm/user_listen_artist_rels.parquet.gzip +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/resources/lastfm/user_nodes.parquet.gzip +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/resources/lastfm/user_tag_artist_rels.parquet.gzip +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/retry_utils/__init__.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/retry_utils/retry_config.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/retry_utils/retry_utils.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/semantic_version/__init__.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/semantic_version/semantic_version.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/server_version/__init__.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/server_version/compatible_with.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/server_version/server_version.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/session/algorithm_category.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/session/aurads_sessions.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/session/cloud_location.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/session/dbms/__init__.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/session/dbms/protocol_resolver.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/session/dbms/protocol_version.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/session/dbms_connection_info.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/session/region_suggester.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/session/session_sizes.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/system/__init__.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/system/config_endpoints.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/system/system_endpoints.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/topological_lp/__init__.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/topological_lp/topological_lp_alpha_runner.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/topological_lp/topological_lp_endpoints.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/utils/__init__.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/utils/direct_util_endpoints.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/utils/util_node_property_func_runner.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/utils/util_proc_runner.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/utils/util_remote_proc_runner.py +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience.egg-info/dependency_links.txt +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience.egg-info/not-zip-safe +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience.egg-info/requires.txt +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience.egg-info/top_level.txt +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/pyproject.toml +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/requirements/base/base.txt +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/requirements/base/networkx.txt +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/requirements/base/ogb.txt +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/requirements/base/rust-ext.txt +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/setup.cfg +0 -0
- {graphdatascience-1.15a1 → graphdatascience-1.15a2}/setup.py +0 -0
{graphdatascience-1.15a1 → graphdatascience-1.15a2}/graphdatascience/error/cypher_warning_handler.py
RENAMED
|
@@ -24,6 +24,12 @@ def filter_id_func_deprecation_warning() -> Callable[[F], F]:
|
|
|
24
24
|
message=r"^The query used a deprecated function. \('id' is no longer supported\)",
|
|
25
25
|
)
|
|
26
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'\)",
|
|
31
|
+
)
|
|
32
|
+
|
|
27
33
|
return func(self, *args, **kwargs)
|
|
28
34
|
|
|
29
35
|
return cast(F, wrapper)
|
|
@@ -7,6 +7,8 @@ from typing import Any, Optional, Type, Union
|
|
|
7
7
|
from neo4j import Driver
|
|
8
8
|
from pandas import DataFrame
|
|
9
9
|
|
|
10
|
+
from graphdatascience.query_runner.arrow_authentication import UsernamePasswordAuthentication
|
|
11
|
+
|
|
10
12
|
from .call_builder import IndirectCallBuilder
|
|
11
13
|
from .endpoints import AlphaEndpoints, BetaEndpoints, DirectEndpoints
|
|
12
14
|
from .error.uncallable_namespace import UncallableNamespace
|
|
@@ -93,10 +95,15 @@ class GraphDataScience(DirectEndpoints, UncallableNamespace):
|
|
|
93
95
|
|
|
94
96
|
arrow_info = ArrowInfo.create(self._query_runner)
|
|
95
97
|
if arrow and arrow_info.enabled and self._server_version >= ServerVersion(2, 1, 0):
|
|
98
|
+
arrow_auth = None
|
|
99
|
+
if auth is not None:
|
|
100
|
+
username, password = auth
|
|
101
|
+
arrow_auth = UsernamePasswordAuthentication(username, password)
|
|
102
|
+
|
|
96
103
|
self._query_runner = ArrowQueryRunner.create(
|
|
97
104
|
self._query_runner,
|
|
98
105
|
arrow_info,
|
|
99
|
-
|
|
106
|
+
arrow_auth,
|
|
100
107
|
self._query_runner.encrypted(),
|
|
101
108
|
arrow_disable_server_verification,
|
|
102
109
|
arrow_tls_root_certs,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class ArrowAuthentication(ABC):
|
|
6
|
+
@abstractmethod
|
|
7
|
+
def auth_pair(self) -> tuple[str, str]:
|
|
8
|
+
"""Returns the auth pair used for authentication."""
|
|
9
|
+
pass
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class UsernamePasswordAuthentication(ArrowAuthentication):
|
|
14
|
+
username: str
|
|
15
|
+
password: str
|
|
16
|
+
|
|
17
|
+
def auth_pair(self) -> tuple[str, str]:
|
|
18
|
+
return self.username, self.password
|
|
@@ -5,6 +5,7 @@ from typing import Any, Optional
|
|
|
5
5
|
|
|
6
6
|
from pandas import DataFrame
|
|
7
7
|
|
|
8
|
+
from graphdatascience.query_runner.arrow_authentication import ArrowAuthentication
|
|
8
9
|
from graphdatascience.retry_utils.retry_config import RetryConfig
|
|
9
10
|
|
|
10
11
|
from ..call_parameters import CallParameters
|
|
@@ -21,7 +22,7 @@ class ArrowQueryRunner(QueryRunner):
|
|
|
21
22
|
def create(
|
|
22
23
|
fallback_query_runner: QueryRunner,
|
|
23
24
|
arrow_info: ArrowInfo,
|
|
24
|
-
|
|
25
|
+
arrow_authentication: Optional[ArrowAuthentication] = None,
|
|
25
26
|
encrypted: bool = False,
|
|
26
27
|
disable_server_verification: bool = False,
|
|
27
28
|
tls_root_certs: Optional[bytes] = None,
|
|
@@ -33,7 +34,7 @@ class ArrowQueryRunner(QueryRunner):
|
|
|
33
34
|
|
|
34
35
|
gds_arrow_client = GdsArrowClient.create(
|
|
35
36
|
arrow_info,
|
|
36
|
-
|
|
37
|
+
arrow_authentication,
|
|
37
38
|
encrypted,
|
|
38
39
|
disable_server_verification,
|
|
39
40
|
tls_root_certs,
|
|
@@ -35,6 +35,7 @@ from tenacity import (
|
|
|
35
35
|
wait_exponential,
|
|
36
36
|
)
|
|
37
37
|
|
|
38
|
+
from graphdatascience.query_runner.arrow_authentication import ArrowAuthentication, UsernamePasswordAuthentication
|
|
38
39
|
from graphdatascience.retry_utils.retry_config import RetryConfig
|
|
39
40
|
from graphdatascience.retry_utils.retry_utils import before_log
|
|
40
41
|
|
|
@@ -48,7 +49,7 @@ class GdsArrowClient:
|
|
|
48
49
|
@staticmethod
|
|
49
50
|
def create(
|
|
50
51
|
arrow_info: ArrowInfo,
|
|
51
|
-
auth: Optional[tuple[str, str]] = None,
|
|
52
|
+
auth: Optional[Union[ArrowAuthentication, tuple[str, str]]] = None,
|
|
52
53
|
encrypted: bool = False,
|
|
53
54
|
disable_server_verification: bool = False,
|
|
54
55
|
tls_root_certs: Optional[bytes] = None,
|
|
@@ -92,7 +93,7 @@ class GdsArrowClient:
|
|
|
92
93
|
host: str,
|
|
93
94
|
retry_config: RetryConfig,
|
|
94
95
|
port: int = 8491,
|
|
95
|
-
auth: Optional[tuple[str, str]] = None,
|
|
96
|
+
auth: Optional[Union[ArrowAuthentication, tuple[str, str]]] = None,
|
|
96
97
|
encrypted: bool = False,
|
|
97
98
|
disable_server_verification: bool = False,
|
|
98
99
|
tls_root_certs: Optional[bytes] = None,
|
|
@@ -107,8 +108,8 @@ class GdsArrowClient:
|
|
|
107
108
|
The host address of the GDS Arrow server
|
|
108
109
|
port: int
|
|
109
110
|
The host port of the GDS Arrow server (default is 8491)
|
|
110
|
-
auth: Optional[tuple[str, str]]
|
|
111
|
-
|
|
111
|
+
auth: Optional[Union[ArrowAuthentication, tuple[str, str]]]
|
|
112
|
+
Either an implementation of ArrowAuthentication providing a pair to be used for basic authentication, or a username, password tuple
|
|
112
113
|
encrypted: bool
|
|
113
114
|
A flag that indicates whether the connection should be encrypted (default is False)
|
|
114
115
|
disable_server_verification: bool
|
|
@@ -125,7 +126,7 @@ class GdsArrowClient:
|
|
|
125
126
|
self._arrow_endpoint_version = arrow_endpoint_version
|
|
126
127
|
self._host = host
|
|
127
128
|
self._port = port
|
|
128
|
-
self._auth =
|
|
129
|
+
self._auth = None
|
|
129
130
|
self._encrypted = encrypted
|
|
130
131
|
self._disable_server_verification = disable_server_verification
|
|
131
132
|
self._tls_root_certs = tls_root_certs
|
|
@@ -134,6 +135,10 @@ class GdsArrowClient:
|
|
|
134
135
|
self._logger = logging.getLogger("gds_arrow_client")
|
|
135
136
|
|
|
136
137
|
if auth:
|
|
138
|
+
if not isinstance(auth, ArrowAuthentication):
|
|
139
|
+
username, password = auth
|
|
140
|
+
auth = UsernamePasswordAuthentication(username, password)
|
|
141
|
+
self._auth = auth
|
|
137
142
|
self._auth_middleware = AuthMiddleware(auth)
|
|
138
143
|
|
|
139
144
|
self._flight_client = self._instantiate_flight_client()
|
|
@@ -189,7 +194,8 @@ class GdsArrowClient:
|
|
|
189
194
|
def auth_with_retry() -> None:
|
|
190
195
|
client = self._client()
|
|
191
196
|
if self._auth:
|
|
192
|
-
|
|
197
|
+
auth_pair = self._auth.auth_pair()
|
|
198
|
+
client.authenticate_basic_token(auth_pair[0], auth_pair[1])
|
|
193
199
|
|
|
194
200
|
if self._auth:
|
|
195
201
|
auth_with_retry()
|
|
@@ -884,7 +890,7 @@ class AuthFactory(ClientMiddlewareFactory): # type: ignore
|
|
|
884
890
|
|
|
885
891
|
|
|
886
892
|
class AuthMiddleware(ClientMiddleware): # type: ignore
|
|
887
|
-
def __init__(self, auth:
|
|
893
|
+
def __init__(self, auth: ArrowAuthentication, *args: Any, **kwargs: Any) -> None:
|
|
888
894
|
super().__init__(*args, **kwargs)
|
|
889
895
|
self._auth = auth
|
|
890
896
|
self._token: Optional[str] = None
|
|
@@ -918,15 +924,15 @@ class AuthMiddleware(ClientMiddleware): # type: ignore
|
|
|
918
924
|
|
|
919
925
|
def sending_headers(self) -> dict[str, str]:
|
|
920
926
|
token = self.token()
|
|
921
|
-
if not
|
|
922
|
-
username, password = self._auth
|
|
923
|
-
auth_token = f"{username}:{password}"
|
|
924
|
-
auth_token = "Basic " + base64.b64encode(auth_token.encode("utf-8")).decode("ASCII")
|
|
925
|
-
# There seems to be a bug, `authorization` must be lower key
|
|
926
|
-
return {"authorization": auth_token}
|
|
927
|
-
else:
|
|
927
|
+
if token is not None:
|
|
928
928
|
return {"authorization": "Bearer " + token}
|
|
929
929
|
|
|
930
|
+
auth_pair = self._auth.auth_pair()
|
|
931
|
+
auth_token = f"{auth_pair[0]}:{auth_pair[1]}"
|
|
932
|
+
auth_token = "Basic " + base64.b64encode(auth_token.encode("utf-8")).decode("ASCII")
|
|
933
|
+
# There seems to be a bug, `authorization` must be lower key
|
|
934
|
+
return {"authorization": auth_token}
|
|
935
|
+
|
|
930
936
|
|
|
931
937
|
@dataclass(repr=True, frozen=True)
|
|
932
938
|
class NodeLoadDoneResult:
|
|
@@ -57,19 +57,9 @@ class Neo4jQueryRunner(QueryRunner):
|
|
|
57
57
|
query_runner = Neo4jQueryRunner(
|
|
58
58
|
endpoint, auto_close=False, bookmarks=bookmarks, database=database, show_progress=show_progress
|
|
59
59
|
)
|
|
60
|
-
|
|
61
60
|
else:
|
|
62
61
|
raise ValueError(f"Invalid endpoint type: {type(endpoint)}")
|
|
63
62
|
|
|
64
|
-
if Neo4jQueryRunner._NEO4J_DRIVER_VERSION >= SemanticVersion(5, 21, 0):
|
|
65
|
-
notifications_logger = logging.getLogger("neo4j.notifications")
|
|
66
|
-
# the client does not expose YIELD fields so we just skip these warnings for now
|
|
67
|
-
notifications_logger.addFilter(
|
|
68
|
-
lambda record: (
|
|
69
|
-
"The query used a deprecated field from a procedure" in record.msg and "by 'gds." in record.msg
|
|
70
|
-
)
|
|
71
|
-
)
|
|
72
|
-
|
|
73
63
|
return query_runner
|
|
74
64
|
|
|
75
65
|
@staticmethod
|
|
@@ -90,19 +80,12 @@ class Neo4jQueryRunner(QueryRunner):
|
|
|
90
80
|
show_progress=show_progress,
|
|
91
81
|
bookmarks=None,
|
|
92
82
|
config=driver_config,
|
|
83
|
+
# we need to explicitly set this as the default value is None
|
|
84
|
+
# database in the session is always neo4j
|
|
93
85
|
database="neo4j",
|
|
94
86
|
instance_description="GDS Session",
|
|
95
87
|
)
|
|
96
88
|
|
|
97
|
-
if Neo4jQueryRunner._NEO4J_DRIVER_VERSION >= SemanticVersion(5, 21, 0):
|
|
98
|
-
notifications_logger = logging.getLogger("neo4j.notifications")
|
|
99
|
-
# the client does not expose YIELD fields so we just skip these warnings for now
|
|
100
|
-
notifications_logger.addFilter(
|
|
101
|
-
lambda record: (
|
|
102
|
-
"The query used a deprecated field from a procedure" in record.msg and "by 'gds." in record.msg
|
|
103
|
-
)
|
|
104
|
-
)
|
|
105
|
-
|
|
106
89
|
return query_runner
|
|
107
90
|
|
|
108
91
|
@staticmethod
|
|
@@ -167,12 +150,7 @@ class Neo4jQueryRunner(QueryRunner):
|
|
|
167
150
|
else:
|
|
168
151
|
raise e
|
|
169
152
|
|
|
170
|
-
|
|
171
|
-
# be supported in the `graphdatascience` package.
|
|
172
|
-
warnings.filterwarnings(
|
|
173
|
-
"ignore",
|
|
174
|
-
message=r"^pandas support is experimental and might be changed or removed in future versions$",
|
|
175
|
-
)
|
|
153
|
+
self.__configure_warnings_filter()
|
|
176
154
|
|
|
177
155
|
df = result.to_df()
|
|
178
156
|
|
|
@@ -181,19 +159,10 @@ class Neo4jQueryRunner(QueryRunner):
|
|
|
181
159
|
else:
|
|
182
160
|
self._last_bookmarks = session.last_bookmarks()
|
|
183
161
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
# the client does not expose YIELD fields so we just skip these warnings for now
|
|
189
|
-
warnings.filterwarnings(
|
|
190
|
-
"ignore", message=r".*The query used a deprecated field from a procedure\. .* by 'gds.* "
|
|
191
|
-
)
|
|
192
|
-
else:
|
|
193
|
-
notifications = result.consume().notifications
|
|
194
|
-
if notifications:
|
|
195
|
-
for notification in notifications:
|
|
196
|
-
self._forward_cypher_warnings(notification)
|
|
162
|
+
notifications = result.consume().notifications
|
|
163
|
+
if notifications:
|
|
164
|
+
for notification in notifications:
|
|
165
|
+
self._forward_cypher_warnings(notification)
|
|
197
166
|
|
|
198
167
|
return df
|
|
199
168
|
|
|
@@ -266,7 +235,7 @@ class Neo4jQueryRunner(QueryRunner):
|
|
|
266
235
|
# (see https://neo4j.com/docs/status-codes/current/notifications/ for more details)
|
|
267
236
|
severity = notification["severity"]
|
|
268
237
|
if severity == "WARNING":
|
|
269
|
-
if "
|
|
238
|
+
if "deprecated field" in notification["description"] and "procedure" in notification["description"]:
|
|
270
239
|
# the client does not expose YIELD fields so we just skip these warnings for now
|
|
271
240
|
return
|
|
272
241
|
|
|
@@ -373,6 +342,27 @@ class Neo4jQueryRunner(QueryRunner):
|
|
|
373
342
|
if retrys == retry_config.max_retries:
|
|
374
343
|
raise UnableToConnectError(f"Unable to connect to the {self._instance_description}") from exception
|
|
375
344
|
|
|
345
|
+
def __configure_warnings_filter(self) -> None:
|
|
346
|
+
if Neo4jQueryRunner._NEO4J_DRIVER_VERSION >= SemanticVersion(5, 21, 0):
|
|
347
|
+
notifications_logger = logging.getLogger("neo4j.notifications")
|
|
348
|
+
# the client does not expose YIELD fields so we just skip these warnings for now
|
|
349
|
+
notifications_logger.addFilter(
|
|
350
|
+
lambda record: (
|
|
351
|
+
"The query used a deprecated field from a procedure" in record.msg and "by 'gds." in record.msg
|
|
352
|
+
)
|
|
353
|
+
)
|
|
354
|
+
notifications_logger.addFilter(
|
|
355
|
+
lambda record: "The procedure has a deprecated field" in record.msg and "gds." in record.msg
|
|
356
|
+
)
|
|
357
|
+
warnings.filterwarnings(
|
|
358
|
+
"ignore",
|
|
359
|
+
message=r"^pandas support is experimental and might be changed or removed in future versions$",
|
|
360
|
+
)
|
|
361
|
+
# neo4j 2025.04
|
|
362
|
+
warnings.filterwarnings("ignore", message=r".*The procedure has a deprecated field.*by 'gds.*")
|
|
363
|
+
# neo4j driver 4.4
|
|
364
|
+
warnings.filterwarnings("ignore", message=r".*The query used a deprecated field from a procedure.*by 'gds.*")
|
|
365
|
+
|
|
376
366
|
class ConnectivityRetriesConfig(NamedTuple):
|
|
377
367
|
max_retries: int = 600
|
|
378
368
|
wait_time: int = 1
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
from typing import Any, Optional
|
|
2
|
+
|
|
3
|
+
from pandas import DataFrame
|
|
4
|
+
|
|
5
|
+
from graphdatascience import QueryRunner, ServerVersion
|
|
6
|
+
from graphdatascience.call_parameters import CallParameters
|
|
7
|
+
from graphdatascience.query_runner.graph_constructor import GraphConstructor
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class StandaloneSessionQueryRunner(QueryRunner):
|
|
11
|
+
def __init__(self, session_query_runner: QueryRunner):
|
|
12
|
+
self._query_runner = session_query_runner
|
|
13
|
+
|
|
14
|
+
def call_procedure(
|
|
15
|
+
self,
|
|
16
|
+
endpoint: str,
|
|
17
|
+
params: Optional[CallParameters] = None,
|
|
18
|
+
yields: Optional[list[str]] = None,
|
|
19
|
+
database: Optional[str] = None,
|
|
20
|
+
logging: bool = False,
|
|
21
|
+
custom_error: bool = True,
|
|
22
|
+
) -> DataFrame:
|
|
23
|
+
if endpoint.endswith(".write"):
|
|
24
|
+
raise NotImplementedError("write procedures are not supported on standalone sessions")
|
|
25
|
+
|
|
26
|
+
return self._query_runner.call_procedure(endpoint, params, yields, database, logging, custom_error)
|
|
27
|
+
|
|
28
|
+
def call_function(self, endpoint: str, params: Optional[CallParameters] = None) -> Any:
|
|
29
|
+
return self._query_runner.call_function(endpoint, params)
|
|
30
|
+
|
|
31
|
+
def server_version(self) -> ServerVersion:
|
|
32
|
+
return self._query_runner.server_version()
|
|
33
|
+
|
|
34
|
+
def create_graph_constructor(
|
|
35
|
+
self, graph_name: str, concurrency: int, undirected_relationship_types: Optional[list[str]]
|
|
36
|
+
) -> GraphConstructor:
|
|
37
|
+
return self._query_runner.create_graph_constructor(graph_name, concurrency, undirected_relationship_types)
|
|
38
|
+
|
|
39
|
+
def set_show_progress(self, show_progress: bool) -> None:
|
|
40
|
+
self._query_runner.set_show_progress(show_progress)
|
|
41
|
+
|
|
42
|
+
def encrypted(self) -> bool:
|
|
43
|
+
return self._query_runner.encrypted()
|
|
44
|
+
|
|
45
|
+
def close(self) -> None:
|
|
46
|
+
self._query_runner.close()
|
|
47
|
+
|
|
48
|
+
def database(self) -> Optional[str]:
|
|
49
|
+
return "neo4j"
|
|
50
|
+
|
|
51
|
+
def run_cypher(
|
|
52
|
+
self,
|
|
53
|
+
query: str,
|
|
54
|
+
params: Optional[dict[str, Any]] = None,
|
|
55
|
+
database: Optional[str] = None,
|
|
56
|
+
custom_error: bool = True,
|
|
57
|
+
) -> DataFrame:
|
|
58
|
+
raise NotImplementedError
|
|
59
|
+
|
|
60
|
+
def driver_config(self) -> dict[str, Any]:
|
|
61
|
+
raise NotImplementedError
|
|
62
|
+
|
|
63
|
+
def set_database(self, database: str) -> None:
|
|
64
|
+
raise NotImplementedError
|
|
65
|
+
|
|
66
|
+
def set_bookmarks(self, bookmarks: Optional[Any]) -> None:
|
|
67
|
+
raise NotImplementedError
|
|
68
|
+
|
|
69
|
+
def bookmarks(self) -> Optional[Any]:
|
|
70
|
+
raise NotImplementedError
|
|
71
|
+
|
|
72
|
+
def last_bookmarks(self) -> Optional[Any]:
|
|
73
|
+
raise NotImplementedError
|
|
74
|
+
|
|
75
|
+
def set_server_version(self, _: ServerVersion) -> None:
|
|
76
|
+
super().set_server_version(_)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from .algorithm_category import AlgorithmCategory
|
|
2
|
+
from .aura_api import AuraApiError, SessionStatusError
|
|
2
3
|
from .cloud_location import CloudLocation
|
|
3
4
|
from .dbms_connection_info import DbmsConnectionInfo
|
|
4
5
|
from .gds_sessions import AuraAPICredentials, GdsSessions
|
|
@@ -14,4 +15,6 @@ __all__ = [
|
|
|
14
15
|
"SessionMemory",
|
|
15
16
|
"SessionMemoryValue",
|
|
16
17
|
"AlgorithmCategory",
|
|
18
|
+
"SessionStatusError",
|
|
19
|
+
"AuraApiError",
|
|
17
20
|
]
|
|
@@ -3,7 +3,6 @@ from __future__ import annotations
|
|
|
3
3
|
import logging
|
|
4
4
|
import math
|
|
5
5
|
import time
|
|
6
|
-
import uuid
|
|
7
6
|
import warnings
|
|
8
7
|
from collections import defaultdict
|
|
9
8
|
from datetime import timedelta
|
|
@@ -22,8 +21,10 @@ from graphdatascience.session.aura_api_responses import (
|
|
|
22
21
|
InstanceCreateDetails,
|
|
23
22
|
InstanceDetails,
|
|
24
23
|
InstanceSpecificDetails,
|
|
24
|
+
ProjectDetails,
|
|
25
25
|
SessionDetails,
|
|
26
|
-
|
|
26
|
+
SessionDetailsWithErrors,
|
|
27
|
+
SessionErrorData,
|
|
27
28
|
WaitResult,
|
|
28
29
|
)
|
|
29
30
|
from graphdatascience.session.cloud_location import CloudLocation
|
|
@@ -32,33 +33,51 @@ from graphdatascience.version import __version__
|
|
|
32
33
|
|
|
33
34
|
|
|
34
35
|
class AuraApiError(Exception):
|
|
36
|
+
"""
|
|
37
|
+
Raised when an API call to the AuraAPI fails (after retries).
|
|
38
|
+
"""
|
|
39
|
+
|
|
35
40
|
def __init__(self, message: str, status_code: int):
|
|
36
41
|
super().__init__(self, message)
|
|
37
42
|
self.status_code = status_code
|
|
38
43
|
self.message = message
|
|
39
44
|
|
|
40
45
|
|
|
46
|
+
class SessionStatusError(Exception):
|
|
47
|
+
"""
|
|
48
|
+
Raised when a session is in a non-healthy state. Such as after a session failed or got expired.
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
def __init__(self, errors: list[SessionErrorData]):
|
|
52
|
+
message = f"Session is in an unhealthy state. Details: {[str(e) for e in errors]}"
|
|
53
|
+
|
|
54
|
+
super().__init__(self, message)
|
|
55
|
+
|
|
56
|
+
|
|
41
57
|
class AuraApi:
|
|
42
|
-
API_VERSION = "
|
|
58
|
+
API_VERSION = "v1"
|
|
43
59
|
|
|
44
60
|
def __init__(
|
|
45
|
-
self, client_id: str, client_secret: str,
|
|
61
|
+
self, client_id: str, client_secret: str, project_id: Optional[str] = None, aura_env: Optional[str] = None
|
|
46
62
|
) -> None:
|
|
47
63
|
self._base_uri = AuraApi.base_uri(aura_env)
|
|
48
64
|
self._credentials = (client_id, client_secret)
|
|
49
65
|
|
|
50
|
-
self.
|
|
66
|
+
self._auth = AuraApi.Auth(
|
|
67
|
+
oauth_url=f"{self._base_uri}/oauth/token",
|
|
68
|
+
credentials=self._credentials,
|
|
69
|
+
headers={"User-agent": f"neo4j-graphdatascience-v{__version__}"},
|
|
70
|
+
)
|
|
71
|
+
self._request_session = self._init_request_session()
|
|
51
72
|
self._logger = logging.getLogger()
|
|
52
73
|
|
|
53
|
-
self.
|
|
54
|
-
self.
|
|
74
|
+
self._project_id = project_id if project_id else self._get_project_id()
|
|
75
|
+
self._project_details: Optional[ProjectDetails] = None
|
|
55
76
|
|
|
56
|
-
def _init_request_session(self
|
|
77
|
+
def _init_request_session(self) -> requests.Session:
|
|
57
78
|
request_session = requests.Session()
|
|
58
79
|
request_session.headers = {"User-agent": f"neo4j-graphdatascience-v{__version__}"}
|
|
59
|
-
request_session.auth =
|
|
60
|
-
oauth_url=f"{self._base_uri}/oauth/token", credentials=credentials, headers=request_session.headers
|
|
61
|
-
)
|
|
80
|
+
request_session.auth = self._auth
|
|
62
81
|
# dont retry on POST as its not idempotent
|
|
63
82
|
request_session.mount(
|
|
64
83
|
"https://",
|
|
@@ -106,8 +125,7 @@ class AuraApi:
|
|
|
106
125
|
ttl: Optional[timedelta] = None,
|
|
107
126
|
cloud_location: Optional[CloudLocation] = None,
|
|
108
127
|
) -> SessionDetails:
|
|
109
|
-
|
|
110
|
-
json = {"name": name, "password": pwd, "memory": memory.value, "tenant_id": self._tenant_id}
|
|
128
|
+
json = {"name": name, "memory": memory.value, "project_id": self._project_id}
|
|
111
129
|
|
|
112
130
|
if dbid:
|
|
113
131
|
json["instance_id"] = dbid
|
|
@@ -120,17 +138,19 @@ class AuraApi:
|
|
|
120
138
|
json["region"] = cloud_location.region
|
|
121
139
|
|
|
122
140
|
response = self._request_session.post(
|
|
123
|
-
f"{self._base_uri}/{AuraApi.API_VERSION}/
|
|
141
|
+
f"{self._base_uri}/{AuraApi.API_VERSION}/graph-analytics/sessions", json=json
|
|
124
142
|
)
|
|
125
143
|
|
|
126
144
|
self._check_resp(response)
|
|
127
145
|
|
|
128
146
|
raw_json: dict[str, Any] = response.json()
|
|
129
|
-
|
|
147
|
+
self._check_errors(raw_json)
|
|
148
|
+
|
|
149
|
+
return SessionDetails.from_json(raw_json["data"])
|
|
130
150
|
|
|
131
151
|
def get_session(self, session_id: str) -> Optional[SessionDetails]:
|
|
132
152
|
response = self._request_session.get(
|
|
133
|
-
f"{self._base_uri}/{AuraApi.API_VERSION}/
|
|
153
|
+
f"{self._base_uri}/{AuraApi.API_VERSION}/graph-analytics/sessions/{session_id}"
|
|
134
154
|
)
|
|
135
155
|
|
|
136
156
|
if response.status_code == HTTPStatus.NOT_FOUND.value:
|
|
@@ -139,17 +159,19 @@ class AuraApi:
|
|
|
139
159
|
self._check_resp(response)
|
|
140
160
|
|
|
141
161
|
raw_json: dict[str, Any] = response.json()
|
|
142
|
-
|
|
162
|
+
self._check_errors(raw_json)
|
|
143
163
|
|
|
144
|
-
|
|
164
|
+
return SessionDetails.from_json(raw_json["data"])
|
|
165
|
+
|
|
166
|
+
def list_sessions(self, dbid: Optional[str] = None) -> list[SessionDetailsWithErrors]:
|
|
145
167
|
# these are query parameters (not passed in the body)
|
|
146
168
|
params = {
|
|
147
|
-
"
|
|
169
|
+
"projectId": self._project_id,
|
|
148
170
|
"instanceId": dbid,
|
|
149
171
|
}
|
|
150
172
|
|
|
151
173
|
response = self._request_session.get(
|
|
152
|
-
f"{self._base_uri}/{AuraApi.API_VERSION}/
|
|
174
|
+
f"{self._base_uri}/{AuraApi.API_VERSION}/graph-analytics/sessions", params=params
|
|
153
175
|
)
|
|
154
176
|
|
|
155
177
|
self._check_resp(response)
|
|
@@ -161,7 +183,7 @@ class AuraApi:
|
|
|
161
183
|
for error in raw_json.get("errors", []):
|
|
162
184
|
errors_per_session[error["id"]].append(error)
|
|
163
185
|
|
|
164
|
-
return [
|
|
186
|
+
return [SessionDetailsWithErrors.from_json_with_error(s, errors_per_session[s["id"]]) for s in data] # noqa: F821
|
|
165
187
|
|
|
166
188
|
def wait_for_session_running(
|
|
167
189
|
self,
|
|
@@ -177,14 +199,6 @@ class AuraApi:
|
|
|
177
199
|
return WaitResult.from_error(f"Session `{session_id}` not found -- please retry")
|
|
178
200
|
elif session.status == "Ready":
|
|
179
201
|
return WaitResult.from_connection_url(session.bolt_connection_url())
|
|
180
|
-
elif session.status == "Failed":
|
|
181
|
-
return WaitResult.from_error(
|
|
182
|
-
f"Session `{session_id}` with name `{session.name}` failed due to: {session.errors}"
|
|
183
|
-
)
|
|
184
|
-
elif session.is_expired():
|
|
185
|
-
return WaitResult.from_error(
|
|
186
|
-
f"Session `{session_id}` with name `{session.name}` is expired. Expired due to: {session.errors}"
|
|
187
|
-
)
|
|
188
202
|
else:
|
|
189
203
|
self._logger.debug(
|
|
190
204
|
f"Session `{session_id}` is not yet running. "
|
|
@@ -204,7 +218,7 @@ class AuraApi:
|
|
|
204
218
|
|
|
205
219
|
def delete_session(self, session_id: str) -> bool:
|
|
206
220
|
response = self._request_session.delete(
|
|
207
|
-
f"{self._base_uri}/{AuraApi.API_VERSION}/
|
|
221
|
+
f"{self._base_uri}/{AuraApi.API_VERSION}/graph-analytics/sessions/{session_id}",
|
|
208
222
|
)
|
|
209
223
|
self._check_endpoint_deprecation(response)
|
|
210
224
|
|
|
@@ -223,7 +237,7 @@ class AuraApi:
|
|
|
223
237
|
"version": "5",
|
|
224
238
|
"region": region,
|
|
225
239
|
"type": type,
|
|
226
|
-
"tenant_id": self.
|
|
240
|
+
"tenant_id": self._project_id,
|
|
227
241
|
"cloud_provider": cloud_provider,
|
|
228
242
|
}
|
|
229
243
|
|
|
@@ -244,7 +258,7 @@ class AuraApi:
|
|
|
244
258
|
return InstanceSpecificDetails.fromJson(response.json()["data"])
|
|
245
259
|
|
|
246
260
|
def list_instances(self) -> list[InstanceDetails]:
|
|
247
|
-
response = self._request_session.get(f"{self._base_uri}/v1/instances", params={"tenantId": self.
|
|
261
|
+
response = self._request_session.get(f"{self._base_uri}/v1/instances", params={"tenantId": self._project_id})
|
|
248
262
|
|
|
249
263
|
self._check_resp(response)
|
|
250
264
|
|
|
@@ -303,26 +317,33 @@ class AuraApi:
|
|
|
303
317
|
|
|
304
318
|
return EstimationDetails.from_json(response.json()["data"])
|
|
305
319
|
|
|
306
|
-
def
|
|
320
|
+
def _get_project_id(self) -> str:
|
|
307
321
|
response = self._request_session.get(f"{self._base_uri}/v1/tenants")
|
|
308
322
|
self._check_resp(response)
|
|
309
323
|
|
|
310
324
|
raw_data = response.json()["data"]
|
|
311
325
|
|
|
312
326
|
if len(raw_data) != 1:
|
|
313
|
-
|
|
327
|
+
projects_dict = {d["id"]: d["name"] for d in raw_data}
|
|
314
328
|
raise RuntimeError(
|
|
315
|
-
f"This account has access to multiple
|
|
329
|
+
f"This account has access to multiple projects: `{projects_dict}`. Please specify which one to use."
|
|
316
330
|
)
|
|
317
331
|
|
|
318
332
|
return raw_data[0]["id"] # type: ignore
|
|
319
333
|
|
|
320
|
-
def
|
|
321
|
-
if not self.
|
|
322
|
-
response = self._request_session.get(f"{self._base_uri}/v1/tenants/{self.
|
|
334
|
+
def project_details(self) -> ProjectDetails:
|
|
335
|
+
if not self._project_details:
|
|
336
|
+
response = self._request_session.get(f"{self._base_uri}/v1/tenants/{self._project_id}")
|
|
323
337
|
self._check_resp(response)
|
|
324
|
-
self.
|
|
325
|
-
return self.
|
|
338
|
+
self._project_details = ProjectDetails.from_json(response.json()["data"])
|
|
339
|
+
return self._project_details
|
|
340
|
+
|
|
341
|
+
def _check_errors(self, raw_json: dict[str, Any]) -> None:
|
|
342
|
+
errors = raw_json.get("errors", [])
|
|
343
|
+
typed_errors = [SessionErrorData.from_json(error) for error in errors] if errors else None
|
|
344
|
+
|
|
345
|
+
if typed_errors:
|
|
346
|
+
raise SessionStatusError(typed_errors)
|
|
326
347
|
|
|
327
348
|
def _check_resp(self, resp: requests.Response) -> None:
|
|
328
349
|
self._check_status_code(resp)
|