graphdatascience 1.10__tar.gz → 1.11a1__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.10/graphdatascience.egg-info → graphdatascience-1.11a1}/PKG-INFO +1 -1
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/graph/base_graph_proc_runner.py +1 -2
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/graph_data_science.py +9 -9
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/query_runner/arrow_query_runner.py +10 -3
- graphdatascience-1.11a1/graphdatascience/session/__init__.py +16 -0
- graphdatascience-1.11a1/graphdatascience/session/algorithm_category.py +14 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/session/aura_api.py +101 -106
- graphdatascience-1.11a1/graphdatascience/session/aura_api_responses.py +166 -0
- graphdatascience-1.11a1/graphdatascience/session/aurads_sessions.py +202 -0
- graphdatascience-1.11a1/graphdatascience/session/dedicated_sessions.py +137 -0
- graphdatascience-1.11a1/graphdatascience/session/gds_sessions.py +107 -0
- graphdatascience-1.11a1/graphdatascience/session/session_info.py +40 -0
- graphdatascience-1.11a1/graphdatascience/session/session_sizes.py +31 -0
- graphdatascience-1.11a1/graphdatascience/version.py +1 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1/graphdatascience.egg-info}/PKG-INFO +1 -1
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience.egg-info/SOURCES.txt +5 -0
- graphdatascience-1.10/graphdatascience/session/__init__.py +0 -13
- graphdatascience-1.10/graphdatascience/session/gds_sessions.py +0 -238
- graphdatascience-1.10/graphdatascience/session/session_sizes.py +0 -33
- graphdatascience-1.10/graphdatascience/version.py +0 -1
- {graphdatascience-1.10 → graphdatascience-1.11a1}/LICENSE +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/MANIFEST.in +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/README.md +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/__init__.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/algo/__init__.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/algo/algo_endpoints.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/algo/algo_proc_runner.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/algo/single_mode_algo_endpoints.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/call_builder.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/call_parameters.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/caller_base.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/endpoints.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/error/__init__.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/error/client_only_endpoint.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/error/cypher_warning_handler.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/error/endpoint_suggester.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/error/gds_not_installed.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/error/illegal_attr_checker.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/error/unable_to_connect.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/error/uncallable_namespace.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/graph/__init__.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/graph/graph_alpha_proc_runner.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/graph/graph_beta_proc_runner.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/graph/graph_create_result.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/graph/graph_cypher_runner.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/graph/graph_endpoints.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/graph/graph_entity_ops_runner.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/graph/graph_export_runner.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/graph/graph_object.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/graph/graph_proc_runner.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/graph/graph_project_runner.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/graph/graph_remote_proc_runner.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/graph/graph_remote_project_runner.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/graph/graph_sample_runner.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/graph/graph_type_check.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/graph/nx_loader.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/graph/ogb_loader.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/ignored_server_endpoints.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/model/__init__.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/model/graphsage_model.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/model/link_prediction_model.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/model/model.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/model/model_alpha_proc_runner.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/model/model_beta_proc_runner.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/model/model_endpoints.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/model/model_proc_runner.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/model/model_resolver.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/model/node_classification_model.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/model/node_regression_model.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/model/pipeline_model.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/model/simple_rel_embedding_model.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/pipeline/__init__.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/pipeline/classification_training_pipeline.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/pipeline/lp_pipeline_create_runner.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/pipeline/lp_training_pipeline.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/pipeline/nc_pipeline_create_runner.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/pipeline/nc_training_pipeline.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/pipeline/nr_pipeline_create_runner.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/pipeline/nr_training_pipeline.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/pipeline/pipeline_alpha_proc_runner.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/pipeline/pipeline_beta_proc_runner.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/pipeline/pipeline_endpoints.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/pipeline/pipeline_proc_runner.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/pipeline/training_pipeline.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/py.typed +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/query_runner/__init__.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/query_runner/arrow_endpoint_version.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/query_runner/arrow_graph_constructor.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/query_runner/aura_db_arrow_query_runner.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/query_runner/cypher_graph_constructor.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/query_runner/graph_constructor.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/query_runner/neo4j_query_runner.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/query_runner/query_runner.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/resources/__init__.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/resources/cora/__init__.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/resources/cora/cora_nodes.parquet.gzip +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/resources/cora/cora_rels.parquet.gzip +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/resources/cora/serialize_cora.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/resources/imdb/__init__.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/resources/imdb/imdb_acted_in.parquet.gzip +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/resources/imdb/imdb_actors.parquet.gzip +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/resources/imdb/imdb_directed_in.parquet.gzip +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/resources/imdb/imdb_directors.parquet.gzip +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/resources/imdb/imdb_movies_with_genre.parquet.gzip +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/resources/imdb/imdb_movies_without_genre.parquet.gzip +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/resources/imdb/serialize_imdb.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/resources/karate/__init__.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/resources/karate/karate_club.parquet.gzip +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/resources/lastfm/__init__.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/resources/lastfm/artist_nodes.parquet.gzip +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/resources/lastfm/serialize_lastfm.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/resources/lastfm/user_friend_df_directed.parquet.gzip +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/resources/lastfm/user_listen_artist_rels.parquet.gzip +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/resources/lastfm/user_nodes.parquet.gzip +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/resources/lastfm/user_tag_artist_rels.parquet.gzip +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/server_version/__init__.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/server_version/compatible_with.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/server_version/server_version.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/session/aura_graph_data_science.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/session/dbms_connection_info.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/session/region_suggester.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/session/schema.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/system/__init__.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/system/config_endpoints.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/system/system_endpoints.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/topological_lp/__init__.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/topological_lp/topological_lp_alpha_runner.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/topological_lp/topological_lp_endpoints.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/utils/__init__.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/utils/util_endpoints.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/utils/util_proc_runner.py +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience.egg-info/dependency_links.txt +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience.egg-info/not-zip-safe +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience.egg-info/requires.txt +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience.egg-info/top_level.txt +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/pyproject.toml +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/requirements/base/base.txt +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/requirements/base/networkx.txt +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/requirements/base/ogb.txt +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/setup.cfg +0 -0
- {graphdatascience-1.10 → graphdatascience-1.11a1}/setup.py +0 -0
{graphdatascience-1.10 → graphdatascience-1.11a1}/graphdatascience/graph/base_graph_proc_runner.py
RENAMED
|
@@ -517,8 +517,7 @@ class BaseGraphProcRunner(UncallableNamespace, IllegalAttrChecker):
|
|
|
517
517
|
).squeeze()
|
|
518
518
|
|
|
519
519
|
@multimethod
|
|
520
|
-
def removeNodeProperties(self) -> None:
|
|
521
|
-
...
|
|
520
|
+
def removeNodeProperties(self) -> None: ...
|
|
522
521
|
|
|
523
522
|
@removeNodeProperties.register
|
|
524
523
|
@graph_type_check
|
|
@@ -44,20 +44,20 @@ class GraphDataScience(DirectEndpoints, UncallableNamespace):
|
|
|
44
44
|
A username, password pair for database authentication.
|
|
45
45
|
aura_ds : bool, default False
|
|
46
46
|
A flag that indicates that that the client is used to connect
|
|
47
|
-
to a Neo4j
|
|
47
|
+
to a Neo4j AuraDS instance.
|
|
48
48
|
database: Optional[str], default None
|
|
49
49
|
The Neo4j database to query against.
|
|
50
50
|
arrow : Union[str, bool], default True
|
|
51
|
-
Arrow connection information.
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
Arrow connection information. This is either a bool or a string.
|
|
52
|
+
If it is a string, it will be interpreted as a connection URL to a GDS Arrow Server.
|
|
53
|
+
If it is a bool,
|
|
54
|
+
True will make the client discover the connection URI to the GDS Arrow server via the Neo4j endpoint,
|
|
55
|
+
while False will make the client use Bolt for all operations.
|
|
54
56
|
arrow_disable_server_verification : bool, default True
|
|
55
|
-
A flag that
|
|
56
|
-
TLS, that it skips server verification. If this is enabled, all
|
|
57
|
-
other TLS settings are overridden.
|
|
57
|
+
A flag that overrides other TLS settings and disables server verification for TLS connections.
|
|
58
58
|
arrow_tls_root_certs : Optional[bytes], default None
|
|
59
|
-
PEM-encoded certificates that are used for the
|
|
60
|
-
Arrow Flight server.
|
|
59
|
+
PEM-encoded certificates that are used for the connection to the
|
|
60
|
+
GDS Arrow Flight server.
|
|
61
61
|
bookmarks : Optional[Any], default None
|
|
62
62
|
The Neo4j bookmarks to require a certain state before the next query gets executed.
|
|
63
63
|
"""
|
|
@@ -282,7 +282,7 @@ class ArrowQueryRunner(QueryRunner):
|
|
|
282
282
|
|
|
283
283
|
if self._arrow_endpoint_version == ArrowEndpointVersion.V1:
|
|
284
284
|
payload = {
|
|
285
|
-
"name": "
|
|
285
|
+
"name": "GET_COMMAND",
|
|
286
286
|
"version": ArrowEndpointVersion.V1.version(),
|
|
287
287
|
"body": payload,
|
|
288
288
|
}
|
|
@@ -377,10 +377,17 @@ class AuthMiddleware(ClientMiddleware): # type: ignore
|
|
|
377
377
|
self._factory = factory
|
|
378
378
|
|
|
379
379
|
def received_headers(self, headers: Dict[str, Any]) -> None:
|
|
380
|
-
auth_header
|
|
380
|
+
auth_header = headers.get("authorization", None)
|
|
381
381
|
if not auth_header:
|
|
382
382
|
return
|
|
383
|
-
|
|
383
|
+
|
|
384
|
+
# the result is always a list
|
|
385
|
+
header_value = auth_header[0]
|
|
386
|
+
|
|
387
|
+
if not isinstance(header_value, str):
|
|
388
|
+
raise ValueError(f"Incompatible header value received from server: `{header_value}`")
|
|
389
|
+
|
|
390
|
+
auth_type, token = header_value.split(" ", 1)
|
|
384
391
|
if auth_type == "Bearer":
|
|
385
392
|
self._factory.set_token(token)
|
|
386
393
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from .algorithm_category import AlgorithmCategory
|
|
2
|
+
from .dbms_connection_info import DbmsConnectionInfo
|
|
3
|
+
from .gds_sessions import AuraAPICredentials, GdsSessions
|
|
4
|
+
from .schema import GdsPropertyTypes
|
|
5
|
+
from .session_info import SessionInfo
|
|
6
|
+
from .session_sizes import SessionMemory
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
"GdsSessions",
|
|
10
|
+
"SessionInfo",
|
|
11
|
+
"DbmsConnectionInfo",
|
|
12
|
+
"AuraAPICredentials",
|
|
13
|
+
"SessionMemory",
|
|
14
|
+
"GdsPropertyTypes",
|
|
15
|
+
"AlgorithmCategory",
|
|
16
|
+
]
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class AlgorithmCategory(Enum):
|
|
5
|
+
"""
|
|
6
|
+
Enumeration of supported algorithm categories used for size estimation.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
CENTRALITY = "centrality"
|
|
10
|
+
COMMUNITY_DETECTION = "community-detection"
|
|
11
|
+
MACHINE_LEARNING = "machine-learning"
|
|
12
|
+
NODE_EMBEDDING = "node-embedding"
|
|
13
|
+
PATH_FINDING = "path-finding"
|
|
14
|
+
SIMILARITY = "similarity"
|
|
@@ -1,121 +1,27 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import dataclasses
|
|
4
3
|
import logging
|
|
5
4
|
import os
|
|
6
5
|
import time
|
|
7
|
-
from
|
|
8
|
-
from dataclasses import dataclass
|
|
9
|
-
from typing import Any, List, NamedTuple, Optional, Set
|
|
6
|
+
from typing import Any, List, Optional
|
|
10
7
|
from urllib.parse import urlparse
|
|
11
8
|
|
|
12
9
|
import requests as req
|
|
13
10
|
from requests import HTTPError
|
|
14
11
|
|
|
12
|
+
from graphdatascience.session.algorithm_category import AlgorithmCategory
|
|
13
|
+
from graphdatascience.session.aura_api_responses import (
|
|
14
|
+
EstimationDetails,
|
|
15
|
+
InstanceCreateDetails,
|
|
16
|
+
InstanceDetails,
|
|
17
|
+
InstanceSpecificDetails,
|
|
18
|
+
SessionDetails,
|
|
19
|
+
TenantDetails,
|
|
20
|
+
WaitResult,
|
|
21
|
+
)
|
|
15
22
|
from graphdatascience.version import __version__
|
|
16
23
|
|
|
17
24
|
|
|
18
|
-
@dataclass(repr=True, frozen=True)
|
|
19
|
-
class InstanceDetails:
|
|
20
|
-
id: str
|
|
21
|
-
name: str
|
|
22
|
-
tenant_id: str
|
|
23
|
-
cloud_provider: str
|
|
24
|
-
|
|
25
|
-
@classmethod
|
|
26
|
-
def fromJson(cls, json: dict[str, Any]) -> InstanceDetails:
|
|
27
|
-
return cls(
|
|
28
|
-
id=json["id"],
|
|
29
|
-
name=json["name"],
|
|
30
|
-
tenant_id=json["tenant_id"],
|
|
31
|
-
cloud_provider=json["cloud_provider"],
|
|
32
|
-
)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
@dataclass(repr=True, frozen=True)
|
|
36
|
-
class InstanceSpecificDetails(InstanceDetails):
|
|
37
|
-
status: str
|
|
38
|
-
connection_url: str
|
|
39
|
-
memory: str
|
|
40
|
-
type: str
|
|
41
|
-
region: str
|
|
42
|
-
|
|
43
|
-
@classmethod
|
|
44
|
-
def fromJson(cls, json: dict[str, Any]) -> InstanceSpecificDetails:
|
|
45
|
-
return cls(
|
|
46
|
-
id=json["id"],
|
|
47
|
-
name=json["name"],
|
|
48
|
-
tenant_id=json["tenant_id"],
|
|
49
|
-
cloud_provider=json["cloud_provider"],
|
|
50
|
-
status=json["status"],
|
|
51
|
-
connection_url=json.get("connection_url", ""),
|
|
52
|
-
memory=json.get("memory", ""),
|
|
53
|
-
type=json["type"],
|
|
54
|
-
region=json["region"],
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
@dataclass(repr=True, frozen=True)
|
|
59
|
-
class InstanceCreateDetails:
|
|
60
|
-
id: str
|
|
61
|
-
username: str
|
|
62
|
-
password: str
|
|
63
|
-
connection_url: str
|
|
64
|
-
|
|
65
|
-
@classmethod
|
|
66
|
-
def from_json(cls, json: dict[str, Any]) -> InstanceCreateDetails:
|
|
67
|
-
fields = dataclasses.fields(cls)
|
|
68
|
-
if any(f.name not in json for f in fields):
|
|
69
|
-
raise RuntimeError(f"Missing required field. Expected `{[f.name for f in fields]}` but got `{json}`")
|
|
70
|
-
|
|
71
|
-
return cls(**{f.name: json[f.name] for f in fields})
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
class WaitResult(NamedTuple):
|
|
75
|
-
connection_url: str
|
|
76
|
-
error: str
|
|
77
|
-
|
|
78
|
-
@classmethod
|
|
79
|
-
def from_error(cls, error: str) -> WaitResult:
|
|
80
|
-
return cls(connection_url="", error=error)
|
|
81
|
-
|
|
82
|
-
@classmethod
|
|
83
|
-
def from_connection_url(cls, connection_url: str) -> WaitResult:
|
|
84
|
-
return cls(connection_url=connection_url, error="")
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
@dataclass(repr=True, frozen=True)
|
|
88
|
-
class TenantDetails:
|
|
89
|
-
id: str
|
|
90
|
-
ds_type: str
|
|
91
|
-
regions_per_provider: dict[str, Set[str]]
|
|
92
|
-
|
|
93
|
-
@classmethod
|
|
94
|
-
def from_json(cls, json: dict[str, Any]) -> TenantDetails:
|
|
95
|
-
regions_per_provider = defaultdict(set)
|
|
96
|
-
instance_types = set()
|
|
97
|
-
ds_type = None
|
|
98
|
-
|
|
99
|
-
for configs in json["instance_configurations"]:
|
|
100
|
-
type = configs["type"]
|
|
101
|
-
if type.split("-")[1] == "ds":
|
|
102
|
-
regions_per_provider[configs["cloud_provider"]].add(configs["region"])
|
|
103
|
-
ds_type = type
|
|
104
|
-
instance_types.add(configs["type"])
|
|
105
|
-
|
|
106
|
-
id = json["id"]
|
|
107
|
-
if not ds_type:
|
|
108
|
-
raise RuntimeError(
|
|
109
|
-
f"Tenant with id `{id}` cannot create DS instances. Available instances are `{instance_types}`."
|
|
110
|
-
)
|
|
111
|
-
|
|
112
|
-
return cls(
|
|
113
|
-
id=id,
|
|
114
|
-
ds_type=ds_type,
|
|
115
|
-
regions_per_provider=regions_per_provider,
|
|
116
|
-
)
|
|
117
|
-
|
|
118
|
-
|
|
119
25
|
class AuraApi:
|
|
120
26
|
class AuraAuthToken:
|
|
121
27
|
access_token: str
|
|
@@ -156,6 +62,79 @@ class AuraApi:
|
|
|
156
62
|
|
|
157
63
|
return host.split(".")[0].split("-")[0]
|
|
158
64
|
|
|
65
|
+
def create_session(self, name: str, dbid: str, pwd: str, memory: str) -> SessionDetails:
|
|
66
|
+
response = req.post(
|
|
67
|
+
f"{self._base_uri}/v1beta5/data-science/sessions",
|
|
68
|
+
headers=self._build_header(),
|
|
69
|
+
json={"name": name, "instance_id": dbid, "password": pwd, "memory": memory},
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
response.raise_for_status()
|
|
73
|
+
|
|
74
|
+
return SessionDetails.fromJson(response.json())
|
|
75
|
+
|
|
76
|
+
def list_session(self, session_id: str, dbid: str) -> Optional[SessionDetails]:
|
|
77
|
+
response = req.get(
|
|
78
|
+
f"{self._base_uri}/v1beta5/data-science/sessions/{session_id}?instanceId={dbid}",
|
|
79
|
+
headers=self._build_header(),
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
if response.status_code == 404:
|
|
83
|
+
return None
|
|
84
|
+
|
|
85
|
+
response.raise_for_status()
|
|
86
|
+
|
|
87
|
+
return SessionDetails.fromJson(response.json())
|
|
88
|
+
|
|
89
|
+
def list_sessions(self, dbid: str) -> List[SessionDetails]:
|
|
90
|
+
response = req.get(
|
|
91
|
+
f"{self._base_uri}/v1beta5/data-science/sessions?instanceId={dbid}",
|
|
92
|
+
headers=self._build_header(),
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
response.raise_for_status()
|
|
96
|
+
|
|
97
|
+
return [SessionDetails.fromJson(s) for s in response.json()]
|
|
98
|
+
|
|
99
|
+
def wait_for_session_running(
|
|
100
|
+
self, session_id: str, dbid: str, sleep_time: float = 0.2, max_sleep_time: float = 300
|
|
101
|
+
) -> WaitResult:
|
|
102
|
+
waited_time = 0.0
|
|
103
|
+
while waited_time <= max_sleep_time:
|
|
104
|
+
session = self.list_session(session_id, dbid)
|
|
105
|
+
if session is None:
|
|
106
|
+
return WaitResult.from_error(f"Session `{session_id}` for database `{dbid}` not found -- please retry")
|
|
107
|
+
elif session.status == "Ready" and session.host: # check host needed until dns based routing
|
|
108
|
+
return WaitResult.from_connection_url(session.bolt_connection_url())
|
|
109
|
+
else:
|
|
110
|
+
self._logger.debug(
|
|
111
|
+
f"Session `{session_id}` is not yet running. "
|
|
112
|
+
f"Current status: {session.status} Host: {session.host}. "
|
|
113
|
+
f"Retrying in {sleep_time} seconds..."
|
|
114
|
+
)
|
|
115
|
+
waited_time += sleep_time
|
|
116
|
+
time.sleep(sleep_time)
|
|
117
|
+
|
|
118
|
+
return WaitResult.from_error(
|
|
119
|
+
f"Session `{session_id}` for database `{dbid}` is not running after {waited_time} seconds"
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
def delete_session(self, session_id: str, dbid: str) -> bool:
|
|
123
|
+
response = req.delete(
|
|
124
|
+
f"{self._base_uri}/v1beta5/data-science/sessions/{session_id}",
|
|
125
|
+
headers=self._build_header(),
|
|
126
|
+
json={"instance_id": dbid},
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
if response.status_code == 404:
|
|
130
|
+
return False
|
|
131
|
+
elif response.status_code == 202:
|
|
132
|
+
return True
|
|
133
|
+
|
|
134
|
+
response.raise_for_status()
|
|
135
|
+
|
|
136
|
+
return False
|
|
137
|
+
|
|
159
138
|
def create_instance(self, name: str, memory: str, cloud_provider: str, region: str) -> InstanceCreateDetails:
|
|
160
139
|
tenant_details = self.tenant_details()
|
|
161
140
|
|
|
@@ -247,6 +226,21 @@ class AuraApi:
|
|
|
247
226
|
|
|
248
227
|
return WaitResult.from_error(f"Instance is not running after waiting for {waited_time} seconds")
|
|
249
228
|
|
|
229
|
+
def estimate_size(
|
|
230
|
+
self, node_count: int, relationship_count: int, algorithm_categories: List[AlgorithmCategory]
|
|
231
|
+
) -> EstimationDetails:
|
|
232
|
+
data = {
|
|
233
|
+
"node_count": node_count,
|
|
234
|
+
"relationship_count": relationship_count,
|
|
235
|
+
"algorithm_categories": [i.value for i in algorithm_categories],
|
|
236
|
+
"instance_type": "dsenterprise",
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
response = req.post(f"{self._base_uri}/v1/instances/sizing", headers=self._build_header(), json=data)
|
|
240
|
+
response.raise_for_status()
|
|
241
|
+
|
|
242
|
+
return EstimationDetails.from_json(response.json()["data"])
|
|
243
|
+
|
|
250
244
|
def _get_tenant_id(self) -> str:
|
|
251
245
|
response = req.get(
|
|
252
246
|
f"{self._base_uri}/v1/tenants",
|
|
@@ -257,8 +251,9 @@ class AuraApi:
|
|
|
257
251
|
raw_data = response.json()["data"]
|
|
258
252
|
|
|
259
253
|
if len(raw_data) != 1:
|
|
254
|
+
tenants_dict = {d["id"]: d["name"] for d in raw_data}
|
|
260
255
|
raise RuntimeError(
|
|
261
|
-
f"This account has access to multiple tenants `{
|
|
256
|
+
f"This account has access to multiple tenants: `{tenants_dict}`. Please specify which one to use."
|
|
262
257
|
)
|
|
263
258
|
|
|
264
259
|
return raw_data[0]["id"] # type: ignore
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import dataclasses
|
|
4
|
+
import sys
|
|
5
|
+
from collections import defaultdict
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from datetime import datetime, timezone
|
|
8
|
+
from typing import Any, NamedTuple, Optional, Set
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass(repr=True, frozen=True)
|
|
12
|
+
class SessionDetails:
|
|
13
|
+
id: str
|
|
14
|
+
name: str
|
|
15
|
+
instance_id: str
|
|
16
|
+
memory: str
|
|
17
|
+
status: str
|
|
18
|
+
host: Optional[str]
|
|
19
|
+
expiry_date: Optional[datetime]
|
|
20
|
+
created_at: datetime
|
|
21
|
+
|
|
22
|
+
@classmethod
|
|
23
|
+
def fromJson(cls, json: dict[str, Any]) -> SessionDetails:
|
|
24
|
+
expiry_date = json.get("expiry_date")
|
|
25
|
+
|
|
26
|
+
return cls(
|
|
27
|
+
id=json["id"],
|
|
28
|
+
name=json["name"],
|
|
29
|
+
instance_id=json["instance_id"],
|
|
30
|
+
memory=json["memory"],
|
|
31
|
+
status=json["status"],
|
|
32
|
+
host=json.get("host"),
|
|
33
|
+
expiry_date=TimeParser.fromisoformat(expiry_date) if expiry_date else None,
|
|
34
|
+
created_at=TimeParser.fromisoformat(json["created_at"]),
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
def bolt_connection_url(self) -> str:
|
|
38
|
+
return f"neo4j+ssc://{self.host}" # TODO use neo4j+s
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclass(repr=True, frozen=True)
|
|
42
|
+
class InstanceDetails:
|
|
43
|
+
id: str
|
|
44
|
+
name: str
|
|
45
|
+
tenant_id: str
|
|
46
|
+
cloud_provider: str
|
|
47
|
+
|
|
48
|
+
@classmethod
|
|
49
|
+
def fromJson(cls, json: dict[str, Any]) -> InstanceDetails:
|
|
50
|
+
return cls(
|
|
51
|
+
id=json["id"],
|
|
52
|
+
name=json["name"],
|
|
53
|
+
tenant_id=json["tenant_id"],
|
|
54
|
+
cloud_provider=json["cloud_provider"],
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@dataclass(repr=True, frozen=True)
|
|
59
|
+
class InstanceSpecificDetails(InstanceDetails):
|
|
60
|
+
status: str
|
|
61
|
+
connection_url: str
|
|
62
|
+
memory: str
|
|
63
|
+
type: str
|
|
64
|
+
region: str
|
|
65
|
+
|
|
66
|
+
@classmethod
|
|
67
|
+
def fromJson(cls, json: dict[str, Any]) -> InstanceSpecificDetails:
|
|
68
|
+
return cls(
|
|
69
|
+
id=json["id"],
|
|
70
|
+
name=json["name"],
|
|
71
|
+
tenant_id=json["tenant_id"],
|
|
72
|
+
cloud_provider=json["cloud_provider"],
|
|
73
|
+
status=json["status"],
|
|
74
|
+
connection_url=json.get("connection_url", ""),
|
|
75
|
+
memory=json.get("memory", ""),
|
|
76
|
+
type=json["type"],
|
|
77
|
+
region=json["region"],
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@dataclass(repr=True, frozen=True)
|
|
82
|
+
class InstanceCreateDetails:
|
|
83
|
+
id: str
|
|
84
|
+
username: str
|
|
85
|
+
password: str
|
|
86
|
+
connection_url: str
|
|
87
|
+
|
|
88
|
+
@classmethod
|
|
89
|
+
def from_json(cls, json: dict[str, Any]) -> InstanceCreateDetails:
|
|
90
|
+
fields = dataclasses.fields(cls)
|
|
91
|
+
if any(f.name not in json for f in fields):
|
|
92
|
+
raise RuntimeError(f"Missing required field. Expected `{[f.name for f in fields]}` but got `{json}`")
|
|
93
|
+
|
|
94
|
+
return cls(**{f.name: json[f.name] for f in fields})
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
@dataclass(repr=True, frozen=True)
|
|
98
|
+
class EstimationDetails:
|
|
99
|
+
min_required_memory: str
|
|
100
|
+
recommended_size: str
|
|
101
|
+
did_exceed_maximum: bool
|
|
102
|
+
|
|
103
|
+
@classmethod
|
|
104
|
+
def from_json(cls, json: dict[str, Any]) -> EstimationDetails:
|
|
105
|
+
fields = dataclasses.fields(cls)
|
|
106
|
+
if any(f.name not in json for f in fields):
|
|
107
|
+
raise RuntimeError(f"Missing required field. Expected `{[f.name for f in fields]}` but got `{json}`")
|
|
108
|
+
|
|
109
|
+
return cls(**{f.name: json[f.name] for f in fields})
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class WaitResult(NamedTuple):
|
|
113
|
+
connection_url: str
|
|
114
|
+
error: str
|
|
115
|
+
|
|
116
|
+
@classmethod
|
|
117
|
+
def from_error(cls, error: str) -> WaitResult:
|
|
118
|
+
return cls(connection_url="", error=error)
|
|
119
|
+
|
|
120
|
+
@classmethod
|
|
121
|
+
def from_connection_url(cls, connection_url: str) -> WaitResult:
|
|
122
|
+
return cls(connection_url=connection_url, error="")
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
@dataclass(repr=True, frozen=True)
|
|
126
|
+
class TenantDetails:
|
|
127
|
+
id: str
|
|
128
|
+
ds_type: str
|
|
129
|
+
regions_per_provider: dict[str, Set[str]]
|
|
130
|
+
|
|
131
|
+
@classmethod
|
|
132
|
+
def from_json(cls, json: dict[str, Any]) -> TenantDetails:
|
|
133
|
+
regions_per_provider = defaultdict(set)
|
|
134
|
+
instance_types = set()
|
|
135
|
+
ds_type = None
|
|
136
|
+
|
|
137
|
+
for configs in json["instance_configurations"]:
|
|
138
|
+
type = configs["type"]
|
|
139
|
+
if type.split("-")[1] == "ds":
|
|
140
|
+
regions_per_provider[configs["cloud_provider"]].add(configs["region"])
|
|
141
|
+
ds_type = type
|
|
142
|
+
instance_types.add(configs["type"])
|
|
143
|
+
|
|
144
|
+
id = json["id"]
|
|
145
|
+
if not ds_type:
|
|
146
|
+
raise RuntimeError(
|
|
147
|
+
f"Tenant with id `{id}` cannot create DS instances. Available instances are `{instance_types}`."
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
return cls(
|
|
151
|
+
id=id,
|
|
152
|
+
ds_type=ds_type,
|
|
153
|
+
regions_per_provider=regions_per_provider,
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
# datetime.fromisoformat only works with Python version > 3.9
|
|
158
|
+
class TimeParser:
|
|
159
|
+
|
|
160
|
+
@staticmethod
|
|
161
|
+
def fromisoformat(date: str) -> datetime:
|
|
162
|
+
if sys.version_info >= (3, 11):
|
|
163
|
+
return datetime.fromisoformat(date)
|
|
164
|
+
else:
|
|
165
|
+
# Aura API example: 1970-01-01T00:00:00Z
|
|
166
|
+
return datetime.strptime(date, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=timezone.utc)
|