splight-lib 5.9.6.dev1__tar.gz → 5.10.0__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.
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/PKG-INFO +1 -1
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/pyproject.toml +49 -1
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/client/database/classmap.py +0 -3
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/client/database/remote_client.py +2 -6
- splight_lib-5.10.0/splight_lib/client/datalake/abstract.py +36 -0
- splight_lib-5.10.0/splight_lib/client/datalake/constants.py +31 -0
- splight_lib-5.10.0/splight_lib/client/datalake/exceptions.py +12 -0
- splight_lib-5.10.0/splight_lib/client/datalake/remote_client.py +252 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/client/exceptions.py +2 -1
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/client/tests/test_datalake.py +2 -1
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/component/spec.py +1 -1
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/execution/task.py +2 -1
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/logging/_internal.py +0 -1
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/models/__init__.py +4 -4
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/models/actions.py +4 -1
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/models/alert.py +1 -1
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/models/asset.py +4 -1
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/models/attribute.py +1 -1
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/models/component.py +2 -4
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/models/dashboard.py +2 -4
- splight_lib-5.10.0/splight_lib/models/database_base.py +79 -0
- splight_lib-5.10.0/splight_lib/models/datalake.py +155 -0
- splight_lib-5.10.0/splight_lib/models/datalake_base.py +130 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/models/exceptions.py +5 -7
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/models/file.py +1 -1
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/models/function.py +1 -1
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/models/hub_solution.py +2 -2
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/models/metadata.py +1 -1
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/models/native.py +19 -13
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/models/secret.py +1 -1
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/models/solution.py +1 -1
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/models/tag.py +1 -1
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/models/tests/test_database_model.py +3 -1
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/solution/solution.py +1 -1
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/tests/test_api_contracts.py +2 -1
- splight_lib-5.9.6.dev1/splight_lib/client/datalake/abstract.py +0 -71
- splight_lib-5.9.6.dev1/splight_lib/client/datalake/exceptions.py +0 -6
- splight_lib-5.9.6.dev1/splight_lib/client/datalake/remote_client.py +0 -405
- splight_lib-5.9.6.dev1/splight_lib/client/datalake/schemas.py +0 -56
- splight_lib-5.9.6.dev1/splight_lib/models/base.py +0 -203
- splight_lib-5.9.6.dev1/splight_lib/models/hub_server.py +0 -116
- splight_lib-5.9.6.dev1/splight_lib/models/pipeline.py +0 -80
- splight_lib-5.9.6.dev1/splight_lib/models/server.py +0 -196
- splight_lib-5.9.6.dev1/splight_lib/server/__init__.py +0 -5
- splight_lib-5.9.6.dev1/splight_lib/server/exceptions.py +0 -3
- splight_lib-5.9.6.dev1/splight_lib/server/server.py +0 -18
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/LICENSE.txt +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/README.md +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/__init__.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/abstract/__init__.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/abstract/client.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/auth/__init__.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/auth/exceptions.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/auth/mac_auth.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/auth/token.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/client/__init__.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/client/database/__init__.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/client/database/abstract.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/client/database/builder.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/client/datalake/__init__.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/client/datalake/buffer.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/client/datalake/builder.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/client/file_handler.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/client/filter.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/client/hub/__init__.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/client/hub/abstract.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/client/hub/client.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/client/tests/test_database.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/component/__init__.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/component/abstract.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/component/exceptions.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/component/tests/test_abstract.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/component/tests/test_spec.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/conftest.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/constants.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/encryption.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/execution/__init__.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/execution/engine.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/execution/exceptions.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/execution/scheduling.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/execution/tests/test_execution.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/execution/tests/test_scheduling.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/execution/trigger.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/logging/__init__.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/logging/component.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/logging/constants.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/logging/logging.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/logging/tests/test_logging.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/models/data_address.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/models/generic.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/models/hub.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/models/tests/models.json +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/models/tests/test_component_object_instance.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/models/tests/test_metadata.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/models/tests/test_models.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/restclient/__init__.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/restclient/client.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/restclient/exceptions.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/restclient/tests/test_restclient.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/restclient/types.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/settings.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/solution/__init__.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/solution/exceptions.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/stringcase.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/testing/__init__.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/tests/FakeProc.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/tests/asset_geometries.json +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/tests/test_encryption.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/utils/__init__.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/utils/custom_model.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/utils/hub.py +0 -0
- {splight_lib-5.9.6.dev1 → splight_lib-5.10.0}/splight_lib/version.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "splight-lib"
|
|
3
|
-
version = "5.
|
|
3
|
+
version = "5.10.0"
|
|
4
4
|
description = "Splight Library"
|
|
5
5
|
authors = ["Splight Dev <dev@splight-ae.com>"]
|
|
6
6
|
readme = "README.md"
|
|
@@ -71,4 +71,52 @@ filterwarnings = [
|
|
|
71
71
|
]
|
|
72
72
|
|
|
73
73
|
[tool.ruff]
|
|
74
|
+
# Exclude a variety of commonly ignored directories.
|
|
75
|
+
exclude = [
|
|
76
|
+
".bzr",
|
|
77
|
+
".direnv",
|
|
78
|
+
".eggs",
|
|
79
|
+
".git",
|
|
80
|
+
".git-rewrite",
|
|
81
|
+
".hg",
|
|
82
|
+
".ipynb_checkpoints",
|
|
83
|
+
".mypy_cache",
|
|
84
|
+
".nox",
|
|
85
|
+
".pants.d",
|
|
86
|
+
".pyenv",
|
|
87
|
+
".pytest_cache",
|
|
88
|
+
".pytype",
|
|
89
|
+
".ruff_cache",
|
|
90
|
+
".svn",
|
|
91
|
+
".tox",
|
|
92
|
+
".venv",
|
|
93
|
+
".vscode",
|
|
94
|
+
"__pypackages__",
|
|
95
|
+
"_build",
|
|
96
|
+
"buck-out",
|
|
97
|
+
"build",
|
|
98
|
+
"dist",
|
|
99
|
+
"node_modules",
|
|
100
|
+
"site-packages",
|
|
101
|
+
"venv",
|
|
102
|
+
]
|
|
103
|
+
|
|
104
|
+
# Same as Black.
|
|
74
105
|
line-length = 79
|
|
106
|
+
indent-width = 4
|
|
107
|
+
|
|
108
|
+
# Assume Python 3.8
|
|
109
|
+
target-version = "py38"
|
|
110
|
+
|
|
111
|
+
[tool.ruff.format]
|
|
112
|
+
# Like Black, use double quotes for strings.
|
|
113
|
+
quote-style = "double"
|
|
114
|
+
|
|
115
|
+
# Like Black, indent with spaces, rather than tabs.
|
|
116
|
+
indent-style = "space"
|
|
117
|
+
|
|
118
|
+
# Like Black, respect magic trailing commas.
|
|
119
|
+
skip-magic-trailing-comma = false
|
|
120
|
+
|
|
121
|
+
# Like Black, automatically detect the appropriate line ending.
|
|
122
|
+
line-ending = "auto"
|
|
@@ -23,12 +23,9 @@ MODEL_NAME_MAP = {
|
|
|
23
23
|
"secret": f"{ENGINE_PREFIX}/secrets/",
|
|
24
24
|
"setpoint": f"{ENGINE_PREFIX}/setpoints/",
|
|
25
25
|
"solution": f"{ENGINE_PREFIX}/solution/solutions/",
|
|
26
|
-
"server": f"{ENGINE_PREFIX}/server/servers/",
|
|
27
26
|
"tab": f"{ENGINE_PREFIX}/dashboard/tabs/",
|
|
28
27
|
"hubsolution": f"{HUB_PREFIX}/solution/solutions/",
|
|
29
28
|
"hubsolutionversion": f"{HUB_PREFIX}/solution/versions/",
|
|
30
|
-
"hubserver": f"{HUB_PREFIX}/server/servers/",
|
|
31
|
-
"hubserverversion": f"{HUB_PREFIX}/server/versions/",
|
|
32
29
|
}
|
|
33
30
|
|
|
34
31
|
CUSTOM_PATHS_MAP = {
|
|
@@ -211,13 +211,9 @@ class RemoteDatabaseClient(AbstractDatabaseClient, AbstractRemoteClient):
|
|
|
211
211
|
------
|
|
212
212
|
InvalidModelName thrown when the model name is not correct.
|
|
213
213
|
"""
|
|
214
|
-
if resource_name.lower() not in [
|
|
215
|
-
"file",
|
|
216
|
-
"hubsolutionversion",
|
|
217
|
-
"hubserverversion",
|
|
218
|
-
]:
|
|
214
|
+
if resource_name.lower() not in ["file", "hubsolutionversion"]:
|
|
219
215
|
raise InvalidModel(
|
|
220
|
-
"Only files
|
|
216
|
+
"Only files and hub solution can be downloaded."
|
|
221
217
|
)
|
|
222
218
|
api_path = self._get_api_path(resource_name)
|
|
223
219
|
resource_id = instance.get("id")
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
from typing import Any, TypedDict
|
|
3
|
+
|
|
4
|
+
from splight_lib.abstract.client import AbstractRemoteClient, QuerySet
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Records(TypedDict):
|
|
8
|
+
collection: str
|
|
9
|
+
records: list[dict[str, Any]]
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class AbstractDatalakeClient(AbstractRemoteClient):
|
|
13
|
+
def get(self, *args, **kwargs) -> QuerySet:
|
|
14
|
+
kwargs["get_func"] = "_get"
|
|
15
|
+
kwargs["count_func"] = "None"
|
|
16
|
+
return QuerySet(self, *args, **kwargs)
|
|
17
|
+
|
|
18
|
+
async def async_get(self, *args, **kwargs):
|
|
19
|
+
# TODO: consider using an async QuerySet
|
|
20
|
+
return await self._async_get(*args, **kwargs)
|
|
21
|
+
|
|
22
|
+
@abstractmethod
|
|
23
|
+
def save(self, records: Records) -> list[dict]:
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
@abstractmethod
|
|
27
|
+
async def async_save(self, records: Records) -> list[dict]:
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
@abstractmethod
|
|
31
|
+
def _get(self, request: dict) -> list[dict]:
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
@abstractmethod
|
|
35
|
+
async def _async_get(self, request: dict) -> list[dict]:
|
|
36
|
+
pass
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class StepName(str, Enum):
|
|
5
|
+
ADD_FIELDS = "addFields"
|
|
6
|
+
ADD_TO_SET = "addToSet"
|
|
7
|
+
BUCKET = "bucket"
|
|
8
|
+
BUCKET_AUTO = "bucketAuto"
|
|
9
|
+
BUCKET_GROUP = "bucketGroup"
|
|
10
|
+
COUNT = "count"
|
|
11
|
+
FACET = "facet"
|
|
12
|
+
GRAPH_LOOKUP = "graphLookup"
|
|
13
|
+
GROUP = "group"
|
|
14
|
+
INDEX_STATS = "indexStats"
|
|
15
|
+
LIMIT = "limit"
|
|
16
|
+
LIST_SESSIONS = "listSessions"
|
|
17
|
+
LOOKUP = "lookup"
|
|
18
|
+
MATCH = "match"
|
|
19
|
+
MERGE = "merge"
|
|
20
|
+
OUT = "out"
|
|
21
|
+
PLAN_CACHE_STATS = "planCacheStats"
|
|
22
|
+
PROJECT = "project"
|
|
23
|
+
REDACT = "redact"
|
|
24
|
+
REPLACE_ROOT = "replaceRoot"
|
|
25
|
+
REPLACE_WITH = "replaceWith"
|
|
26
|
+
SAMPLE = "sample"
|
|
27
|
+
SET = "set"
|
|
28
|
+
SKIP = "skip"
|
|
29
|
+
SORT = "sort"
|
|
30
|
+
UNSET = "unset"
|
|
31
|
+
UNWIND = "unwind"
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
class DatalakeRequestError(Exception):
|
|
2
|
+
def __init__(self, status_code: int, message: str):
|
|
3
|
+
self._msg = f"Request failed with status code {status_code}: {message}"
|
|
4
|
+
super().__init__(self._msg)
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class InvalidCollectionName(Exception):
|
|
8
|
+
def __init__(self, collection: str):
|
|
9
|
+
self._msg = f"Collection {collection} is not a valid collection"
|
|
10
|
+
|
|
11
|
+
def __str__(self) -> str:
|
|
12
|
+
return self._msg
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
from threading import Lock, Thread
|
|
2
|
+
from time import sleep
|
|
3
|
+
|
|
4
|
+
from furl import furl
|
|
5
|
+
from retry import retry
|
|
6
|
+
|
|
7
|
+
from splight_lib.auth import SplightAuthToken
|
|
8
|
+
from splight_lib.client.datalake.abstract import (
|
|
9
|
+
AbstractDatalakeClient,
|
|
10
|
+
Records,
|
|
11
|
+
)
|
|
12
|
+
from splight_lib.client.datalake.buffer import DatalakeDocumentBuffer
|
|
13
|
+
from splight_lib.client.datalake.exceptions import DatalakeRequestError
|
|
14
|
+
from splight_lib.client.exceptions import SPLIGHT_REQUEST_EXCEPTIONS
|
|
15
|
+
from splight_lib.constants import DL_BUFFER_SIZE, DL_BUFFER_TIMEOUT
|
|
16
|
+
from splight_lib.logging._internal import LogTags, get_splight_logger
|
|
17
|
+
from splight_lib.restclient import SplightRestClient
|
|
18
|
+
|
|
19
|
+
logger = get_splight_logger()
|
|
20
|
+
|
|
21
|
+
EXCEPTIONS = (*SPLIGHT_REQUEST_EXCEPTIONS, DatalakeRequestError)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class SyncRemoteDatalakeClient(AbstractDatalakeClient):
|
|
25
|
+
_PREFIX = "/data"
|
|
26
|
+
|
|
27
|
+
def __init__(
|
|
28
|
+
self, base_url: str, access_id: str, secret_key: str, *args, **kwargs
|
|
29
|
+
):
|
|
30
|
+
super().__init__()
|
|
31
|
+
self._base_url = furl(base_url)
|
|
32
|
+
token = SplightAuthToken(
|
|
33
|
+
access_key=access_id,
|
|
34
|
+
secret_key=secret_key,
|
|
35
|
+
)
|
|
36
|
+
self._restclient = SplightRestClient()
|
|
37
|
+
self._restclient.update_headers(token.header)
|
|
38
|
+
logger.debug(
|
|
39
|
+
"Remote datalake client initialized.", tags=LogTags.DATALAKE
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
@retry(EXCEPTIONS, tries=3, delay=2, jitter=1)
|
|
43
|
+
def save(self, records: Records) -> list[dict]:
|
|
44
|
+
url = self._base_url / f"{self._PREFIX}/write"
|
|
45
|
+
response = self._restclient.post(url, json=records)
|
|
46
|
+
if response.is_error:
|
|
47
|
+
raise DatalakeRequestError(response.status_code, response.text)
|
|
48
|
+
return records["records"]
|
|
49
|
+
|
|
50
|
+
@retry(EXCEPTIONS, tries=3, delay=2, jitter=1)
|
|
51
|
+
async def async_save(
|
|
52
|
+
self,
|
|
53
|
+
records: Records,
|
|
54
|
+
) -> list[dict]:
|
|
55
|
+
# POST /data/write
|
|
56
|
+
url = self._base_url / f"{self._PREFIX}/write"
|
|
57
|
+
response = await self._restclient.async_post(url, json=records)
|
|
58
|
+
if response.is_error:
|
|
59
|
+
raise DatalakeRequestError(response.status_code, response.text)
|
|
60
|
+
return records["records"]
|
|
61
|
+
|
|
62
|
+
@retry(EXCEPTIONS, tries=3, delay=2, jitter=1)
|
|
63
|
+
def _get(self, request: dict) -> list[dict]:
|
|
64
|
+
url = self._base_url / f"{self._PREFIX}/read"
|
|
65
|
+
response = self._restclient.post(url, json=request)
|
|
66
|
+
if response.is_error:
|
|
67
|
+
raise DatalakeRequestError(response.status_code, response.text)
|
|
68
|
+
return response.json()
|
|
69
|
+
|
|
70
|
+
@retry(EXCEPTIONS, tries=3, delay=2, jitter=1)
|
|
71
|
+
async def _async_get(self, request: dict) -> list[dict]:
|
|
72
|
+
url = self._base_url / f"{self._PREFIX}/read"
|
|
73
|
+
response = await self._restclient.async_post(url, json=request)
|
|
74
|
+
if response.is_error:
|
|
75
|
+
raise DatalakeRequestError(response.status_code, response.text)
|
|
76
|
+
return response.json()
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class BufferedAsyncRemoteDatalakeClient(SyncRemoteDatalakeClient):
|
|
80
|
+
_PREFIX = "data"
|
|
81
|
+
|
|
82
|
+
def __init__(
|
|
83
|
+
self,
|
|
84
|
+
base_url: str,
|
|
85
|
+
access_id: str,
|
|
86
|
+
secret_key: str,
|
|
87
|
+
buffer_size: int = DL_BUFFER_SIZE,
|
|
88
|
+
buffer_timeout: float = DL_BUFFER_TIMEOUT,
|
|
89
|
+
*args,
|
|
90
|
+
**kwargs,
|
|
91
|
+
):
|
|
92
|
+
super().__init__(
|
|
93
|
+
base_url,
|
|
94
|
+
access_id,
|
|
95
|
+
secret_key,
|
|
96
|
+
buffer_size,
|
|
97
|
+
buffer_timeout,
|
|
98
|
+
*args,
|
|
99
|
+
**kwargs,
|
|
100
|
+
)
|
|
101
|
+
self._base_url = furl(base_url)
|
|
102
|
+
token = SplightAuthToken(
|
|
103
|
+
access_key=access_id,
|
|
104
|
+
secret_key=secret_key,
|
|
105
|
+
)
|
|
106
|
+
self._restclient = SplightRestClient()
|
|
107
|
+
self._restclient.update_headers(token.header)
|
|
108
|
+
|
|
109
|
+
logger.debug(
|
|
110
|
+
"Initializing buffer with size %s and timeout %s",
|
|
111
|
+
buffer_size,
|
|
112
|
+
buffer_timeout,
|
|
113
|
+
)
|
|
114
|
+
self._data_buffers = {
|
|
115
|
+
"default": DatalakeDocumentBuffer(buffer_size, buffer_timeout),
|
|
116
|
+
"routine_evaluations": DatalakeDocumentBuffer(
|
|
117
|
+
buffer_size, buffer_timeout
|
|
118
|
+
),
|
|
119
|
+
}
|
|
120
|
+
self._lock = Lock()
|
|
121
|
+
self._flush_thread = Thread(target=self._flusher, daemon=True)
|
|
122
|
+
self._flush_thread.start()
|
|
123
|
+
logger.debug(
|
|
124
|
+
"Buffered Remote datalake client initialized.",
|
|
125
|
+
tags=LogTags.DATALAKE,
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
def save(self, records: Records) -> list[dict]:
|
|
129
|
+
logger.debug("Saving documents in datalake", tags=LogTags.DATALAKE)
|
|
130
|
+
collection = records["collection"]
|
|
131
|
+
instances = records["records"]
|
|
132
|
+
buffer = self._data_buffers[collection]
|
|
133
|
+
with self._lock:
|
|
134
|
+
if buffer.should_flush():
|
|
135
|
+
logger.debug(
|
|
136
|
+
"Flushing datalake buffer with %s elements",
|
|
137
|
+
len(buffer.data),
|
|
138
|
+
)
|
|
139
|
+
self._send_documents(collection, buffer.data)
|
|
140
|
+
buffer.reset()
|
|
141
|
+
buffer.add_documents(instances)
|
|
142
|
+
return instances
|
|
143
|
+
|
|
144
|
+
def _flusher(self):
|
|
145
|
+
while True:
|
|
146
|
+
for collection, buffer in self._data_buffers.items():
|
|
147
|
+
self._flush_buffer(collection, buffer)
|
|
148
|
+
sleep(0.5)
|
|
149
|
+
|
|
150
|
+
def _flush_buffer(
|
|
151
|
+
self, collection: str, buffer: DatalakeDocumentBuffer
|
|
152
|
+
) -> None:
|
|
153
|
+
with self._lock:
|
|
154
|
+
if buffer.should_flush():
|
|
155
|
+
try:
|
|
156
|
+
logger.debug(
|
|
157
|
+
"Flushing datalake buffer with %s elements",
|
|
158
|
+
len(buffer.data),
|
|
159
|
+
)
|
|
160
|
+
self._send_documents(collection, buffer.data)
|
|
161
|
+
buffer.reset()
|
|
162
|
+
except Exception:
|
|
163
|
+
logger.error("Unable to save documents", exc_info=True)
|
|
164
|
+
|
|
165
|
+
@retry(EXCEPTIONS, tries=3, delay=2, jitter=1)
|
|
166
|
+
def _send_documents(self, collection: str, docs: list[dict]) -> list[dict]:
|
|
167
|
+
url = self._base_url / f"{self._PREFIX}/write"
|
|
168
|
+
data = {
|
|
169
|
+
"collection": collection,
|
|
170
|
+
"records": docs,
|
|
171
|
+
}
|
|
172
|
+
response = self._restclient.post(url, json=data)
|
|
173
|
+
if response.is_error:
|
|
174
|
+
raise DatalakeRequestError(response.status_code, response.text)
|
|
175
|
+
return docs
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
class BufferedSyncRemoteDataClient(SyncRemoteDatalakeClient):
|
|
179
|
+
_PREFIX = "data"
|
|
180
|
+
|
|
181
|
+
def __init__(
|
|
182
|
+
self,
|
|
183
|
+
base_url: str,
|
|
184
|
+
access_id: str,
|
|
185
|
+
secret_key: str,
|
|
186
|
+
buffer_size: int = DL_BUFFER_SIZE,
|
|
187
|
+
buffer_timeout: float = DL_BUFFER_TIMEOUT,
|
|
188
|
+
*args,
|
|
189
|
+
**kwargs,
|
|
190
|
+
):
|
|
191
|
+
super().__init__(
|
|
192
|
+
base_url,
|
|
193
|
+
access_id,
|
|
194
|
+
secret_key,
|
|
195
|
+
buffer_size,
|
|
196
|
+
buffer_timeout,
|
|
197
|
+
*args,
|
|
198
|
+
**kwargs,
|
|
199
|
+
)
|
|
200
|
+
self._base_url = furl(base_url)
|
|
201
|
+
token = SplightAuthToken(
|
|
202
|
+
access_key=access_id,
|
|
203
|
+
secret_key=secret_key,
|
|
204
|
+
)
|
|
205
|
+
self._restclient = SplightRestClient()
|
|
206
|
+
self._restclient.update_headers(token.header)
|
|
207
|
+
|
|
208
|
+
logger.debug(
|
|
209
|
+
"Initializing buffer with size %s and timeout %s",
|
|
210
|
+
buffer_size,
|
|
211
|
+
buffer_timeout,
|
|
212
|
+
tags=LogTags.DATALAKE,
|
|
213
|
+
)
|
|
214
|
+
self._data_buffers = {
|
|
215
|
+
"default": DatalakeDocumentBuffer(buffer_size, buffer_timeout),
|
|
216
|
+
"routine_evaluations": DatalakeDocumentBuffer(
|
|
217
|
+
buffer_size, buffer_timeout
|
|
218
|
+
),
|
|
219
|
+
}
|
|
220
|
+
self._lock = Lock()
|
|
221
|
+
logger.debug(
|
|
222
|
+
"Synchronous Buffered Remote datalake client initialized.",
|
|
223
|
+
tags=LogTags.DATALAKE,
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
def save(self, records: Records) -> list[dict]:
|
|
227
|
+
logger.debug("Saving documents in datalake", tag=LogTags.DATALAKE)
|
|
228
|
+
collection = records["collection"]
|
|
229
|
+
buffer = self._data_buffers[collection]
|
|
230
|
+
with self._lock:
|
|
231
|
+
buffer.add_documents(records["records"])
|
|
232
|
+
if buffer.should_flush():
|
|
233
|
+
logger.debug(
|
|
234
|
+
"Flushing datalake buffer with %s elements",
|
|
235
|
+
len(buffer.data),
|
|
236
|
+
tags=LogTags.DATALAKE,
|
|
237
|
+
)
|
|
238
|
+
self._send_documents(collection, buffer.data)
|
|
239
|
+
buffer.reset()
|
|
240
|
+
return records["records"]
|
|
241
|
+
|
|
242
|
+
@retry(EXCEPTIONS, tries=3, delay=2, jitter=1)
|
|
243
|
+
def _send_documents(self, collection: str, docs: list[dict]) -> list[dict]:
|
|
244
|
+
url = self._base_url / f"{self._PREFIX}/write"
|
|
245
|
+
data = {
|
|
246
|
+
"collection": collection,
|
|
247
|
+
"records": docs,
|
|
248
|
+
}
|
|
249
|
+
response = self._restclient.post(url, json=data)
|
|
250
|
+
if response.is_error:
|
|
251
|
+
raise DatalakeRequestError(response.status_code, response.text)
|
|
252
|
+
return docs
|
|
@@ -65,6 +65,7 @@ def test_save(mocker: MockerFixture):
|
|
|
65
65
|
)
|
|
66
66
|
collection = "collection_name"
|
|
67
67
|
instances = [{"key": "value"}]
|
|
68
|
-
|
|
68
|
+
records = {"collection": collection, "records": instances}
|
|
69
|
+
result = client.save(records)
|
|
69
70
|
mock_post.assert_called_once()
|
|
70
71
|
assert result == instances
|
|
@@ -9,7 +9,6 @@ from splight_lib.component.exceptions import (
|
|
|
9
9
|
ParameterDependencyError,
|
|
10
10
|
)
|
|
11
11
|
from splight_lib.constants import DESCRIPTION_MAX_LENGTH
|
|
12
|
-
from splight_lib.models.base import SplightDatalakeBaseModel
|
|
13
12
|
from splight_lib.models.component import (
|
|
14
13
|
Component,
|
|
15
14
|
ComponentObjectInstance,
|
|
@@ -22,6 +21,7 @@ from splight_lib.models.component import (
|
|
|
22
21
|
Routine,
|
|
23
22
|
get_field_value,
|
|
24
23
|
)
|
|
24
|
+
from splight_lib.models.datalake_base import SplightDatalakeBaseModel
|
|
25
25
|
from splight_lib.utils.custom_model import create_custom_model
|
|
26
26
|
|
|
27
27
|
VALID_PARAMETER_VALUES = {
|
|
@@ -18,15 +18,14 @@ from splight_lib.models.dashboard import (
|
|
|
18
18
|
Filter,
|
|
19
19
|
Tab,
|
|
20
20
|
)
|
|
21
|
+
from splight_lib.models.datalake import DataRequest, PipelineStep, Trace
|
|
21
22
|
from splight_lib.models.file import File
|
|
22
23
|
from splight_lib.models.function import Function, FunctionItem, QueryFilter
|
|
23
24
|
from splight_lib.models.hub import HubComponent
|
|
24
|
-
from splight_lib.models.hub_server import HubServer
|
|
25
25
|
from splight_lib.models.hub_solution import HubSolution
|
|
26
26
|
from splight_lib.models.metadata import Metadata
|
|
27
27
|
from splight_lib.models.native import Boolean, Number, String
|
|
28
28
|
from splight_lib.models.secret import Secret
|
|
29
|
-
from splight_lib.models.server import Server
|
|
30
29
|
from splight_lib.models.solution import Solution
|
|
31
30
|
from splight_lib.models.tag import Tag
|
|
32
31
|
|
|
@@ -46,23 +45,24 @@ __all__ = [
|
|
|
46
45
|
ComponentObject,
|
|
47
46
|
ComponentObjectInstance,
|
|
48
47
|
Dashboard,
|
|
48
|
+
DataRequest,
|
|
49
49
|
File,
|
|
50
50
|
Filter,
|
|
51
51
|
Function,
|
|
52
52
|
FunctionItem,
|
|
53
53
|
HubSolution,
|
|
54
54
|
HubComponent,
|
|
55
|
-
HubServer,
|
|
56
55
|
QueryFilter,
|
|
57
56
|
Metadata,
|
|
58
57
|
Number,
|
|
58
|
+
PipelineStep,
|
|
59
59
|
RoutineEvaluation,
|
|
60
60
|
Secret,
|
|
61
|
-
Server,
|
|
62
61
|
SetPoint,
|
|
63
62
|
Solution,
|
|
64
63
|
String,
|
|
65
64
|
RoutineObject,
|
|
66
65
|
RoutineObjectInstance,
|
|
67
66
|
Tab,
|
|
67
|
+
Trace,
|
|
68
68
|
]
|
|
@@ -14,7 +14,7 @@ from strenum import LowercaseStrEnum, UppercaseStrEnum
|
|
|
14
14
|
from typing_extensions import TypedDict
|
|
15
15
|
|
|
16
16
|
from splight_lib.constants import DESCRIPTION_MAX_LENGTH
|
|
17
|
-
from splight_lib.models.
|
|
17
|
+
from splight_lib.models.database_base import SplightDatabaseBaseModel
|
|
18
18
|
from splight_lib.models.exceptions import (
|
|
19
19
|
InvalidAlertConfiguration,
|
|
20
20
|
MissingAlertItemExpression,
|
|
@@ -6,7 +6,10 @@ from pydantic import BaseModel, Field
|
|
|
6
6
|
|
|
7
7
|
from splight_lib.constants import DESCRIPTION_MAX_LENGTH
|
|
8
8
|
from splight_lib.models.attribute import Attribute
|
|
9
|
-
from splight_lib.models.
|
|
9
|
+
from splight_lib.models.database_base import (
|
|
10
|
+
ResourceSummary,
|
|
11
|
+
SplightDatabaseBaseModel,
|
|
12
|
+
)
|
|
10
13
|
from splight_lib.models.exceptions import MethodNotAllowed
|
|
11
14
|
from splight_lib.models.metadata import Metadata
|
|
12
15
|
from splight_lib.models.tag import Tag
|
|
@@ -20,11 +20,9 @@ from splight_lib.constants import DESCRIPTION_MAX_LENGTH
|
|
|
20
20
|
from splight_lib.execution.scheduling import Crontab
|
|
21
21
|
from splight_lib.models.asset import Asset
|
|
22
22
|
from splight_lib.models.attribute import Attribute
|
|
23
|
-
from splight_lib.models.base import (
|
|
24
|
-
SplightDatabaseBaseModel,
|
|
25
|
-
SplightDatalakeBaseModel,
|
|
26
|
-
)
|
|
27
23
|
from splight_lib.models.data_address import DataAddresses as DLDataAddress
|
|
24
|
+
from splight_lib.models.database_base import SplightDatabaseBaseModel
|
|
25
|
+
from splight_lib.models.datalake_base import SplightDatalakeBaseModel
|
|
28
26
|
from splight_lib.models.exceptions import InvalidObjectInstance
|
|
29
27
|
from splight_lib.models.file import File
|
|
30
28
|
from splight_lib.models.secret import Secret
|
|
@@ -3,7 +3,7 @@ from typing import Any, Dict, List, Optional
|
|
|
3
3
|
from pydantic import Field
|
|
4
4
|
|
|
5
5
|
from splight_lib.constants import DESCRIPTION_MAX_LENGTH
|
|
6
|
-
from splight_lib.models.
|
|
6
|
+
from splight_lib.models.database_base import SplightDatabaseBaseModel
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class Filter(SplightDatabaseBaseModel):
|
|
@@ -39,9 +39,7 @@ class ChartItem(SplightDatabaseBaseModel):
|
|
|
39
39
|
aggregate_period: Optional[str] = None
|
|
40
40
|
source: Optional[str] = None
|
|
41
41
|
source_label: Optional[str] = None
|
|
42
|
-
source_type: Optional[str] =
|
|
43
|
-
None # TODO: define options (component, native)
|
|
44
|
-
)
|
|
42
|
+
source_type: Optional[str] = None
|
|
45
43
|
source_component_label: Optional[str] = None
|
|
46
44
|
source_component_id: Optional[str] = None
|
|
47
45
|
output_format: Optional[str] = None
|