splight-lib 5.9.6.dev2__tar.gz → 5.10.1.dev0__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.dev2 → splight_lib-5.10.1.dev0}/PKG-INFO +1 -1
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/pyproject.toml +49 -1
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/client/database/classmap.py +1 -0
- splight_lib-5.10.1.dev0/splight_lib/client/datalake/abstract.py +36 -0
- splight_lib-5.10.1.dev0/splight_lib/client/datalake/constants.py +31 -0
- splight_lib-5.10.1.dev0/splight_lib/client/datalake/exceptions.py +12 -0
- splight_lib-5.10.1.dev0/splight_lib/client/datalake/remote_client.py +252 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/client/exceptions.py +2 -1
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/client/tests/test_datalake.py +2 -1
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/component/spec.py +1 -1
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/execution/task.py +2 -1
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/models/__init__.py +4 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/models/actions.py +4 -1
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/models/alert.py +1 -1
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/models/asset.py +4 -1
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/models/attribute.py +1 -1
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/models/component.py +2 -4
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/models/dashboard.py +2 -4
- splight_lib-5.10.1.dev0/splight_lib/models/database_base.py +79 -0
- splight_lib-5.10.1.dev0/splight_lib/models/datalake.py +155 -0
- splight_lib-5.10.1.dev0/splight_lib/models/datalake_base.py +130 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/models/exceptions.py +8 -1
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/models/file.py +1 -1
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/models/function.py +1 -1
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/models/hub_server.py +2 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/models/hub_solution.py +2 -2
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/models/metadata.py +1 -1
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/models/native.py +19 -13
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/models/secret.py +1 -1
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/models/server.py +34 -19
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/models/solution.py +1 -1
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/models/tag.py +1 -1
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/models/tests/test_database_model.py +3 -1
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/server/server.py +1 -3
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/tests/test_api_contracts.py +2 -1
- splight_lib-5.9.6.dev2/splight_lib/client/datalake/abstract.py +0 -71
- splight_lib-5.9.6.dev2/splight_lib/client/datalake/exceptions.py +0 -6
- splight_lib-5.9.6.dev2/splight_lib/client/datalake/remote_client.py +0 -405
- splight_lib-5.9.6.dev2/splight_lib/client/datalake/schemas.py +0 -56
- splight_lib-5.9.6.dev2/splight_lib/models/base.py +0 -203
- splight_lib-5.9.6.dev2/splight_lib/models/pipeline.py +0 -80
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/LICENSE.txt +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/README.md +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/__init__.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/abstract/__init__.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/abstract/client.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/auth/__init__.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/auth/exceptions.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/auth/mac_auth.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/auth/token.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/client/__init__.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/client/database/__init__.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/client/database/abstract.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/client/database/builder.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/client/database/remote_client.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/client/datalake/__init__.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/client/datalake/buffer.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/client/datalake/builder.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/client/file_handler.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/client/filter.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/client/hub/__init__.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/client/hub/abstract.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/client/hub/client.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/client/tests/test_database.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/component/__init__.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/component/abstract.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/component/exceptions.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/component/tests/test_abstract.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/component/tests/test_spec.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/conftest.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/constants.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/encryption.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/execution/__init__.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/execution/engine.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/execution/exceptions.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/execution/scheduling.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/execution/tests/test_execution.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/execution/tests/test_scheduling.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/execution/trigger.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/logging/__init__.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/logging/_internal.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/logging/component.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/logging/constants.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/logging/logging.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/logging/tests/test_logging.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/models/data_address.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/models/generic.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/models/hub.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/models/tests/models.json +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/models/tests/test_component_object_instance.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/models/tests/test_metadata.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/models/tests/test_models.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/restclient/__init__.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/restclient/client.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/restclient/exceptions.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/restclient/tests/test_restclient.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/restclient/types.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/server/__init__.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/server/exceptions.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/settings.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/solution/__init__.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/solution/exceptions.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/solution/solution.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/stringcase.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/testing/__init__.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/tests/FakeProc.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/tests/asset_geometries.json +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/tests/test_encryption.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/utils/__init__.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/utils/custom_model.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/utils/hub.py +0 -0
- {splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/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.1dev0"
|
|
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"
|
|
@@ -36,4 +36,5 @@ CUSTOM_PATHS_MAP = {
|
|
|
36
36
|
"get-asset-attribute": "{prefix}/assets/{asset}/get-attribute/",
|
|
37
37
|
"decrypt-secret": "{prefix}/secrets/decrypt/",
|
|
38
38
|
"routine-status": "{prefix}/component/routines/{routine}/update_status/",
|
|
39
|
+
"server-status": "{prefix}/server/servers/{server}/update-status/",
|
|
39
40
|
}
|
|
@@ -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
|
{splight_lib-5.9.6.dev2 → splight_lib-5.10.1.dev0}/splight_lib/client/tests/test_datalake.py
RENAMED
|
@@ -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,6 +18,7 @@ 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
|
|
@@ -46,6 +47,7 @@ __all__ = [
|
|
|
46
47
|
ComponentObject,
|
|
47
48
|
ComponentObjectInstance,
|
|
48
49
|
Dashboard,
|
|
50
|
+
DataRequest,
|
|
49
51
|
File,
|
|
50
52
|
Filter,
|
|
51
53
|
Function,
|
|
@@ -56,6 +58,7 @@ __all__ = [
|
|
|
56
58
|
QueryFilter,
|
|
57
59
|
Metadata,
|
|
58
60
|
Number,
|
|
61
|
+
PipelineStep,
|
|
59
62
|
RoutineEvaluation,
|
|
60
63
|
Secret,
|
|
61
64
|
Server,
|
|
@@ -65,4 +68,5 @@ __all__ = [
|
|
|
65
68
|
RoutineObject,
|
|
66
69
|
RoutineObjectInstance,
|
|
67
70
|
Tab,
|
|
71
|
+
Trace,
|
|
68
72
|
]
|
|
@@ -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
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
from enum import auto
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Dict, List, Optional, TypeVar
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, PrivateAttr
|
|
6
|
+
from strenum import LowercaseStrEnum
|
|
7
|
+
|
|
8
|
+
from splight_lib.client.database import DatabaseClientBuilder
|
|
9
|
+
from splight_lib.client.database.abstract import AbstractDatabaseClient
|
|
10
|
+
from splight_lib.settings import settings
|
|
11
|
+
|
|
12
|
+
FilePath = TypeVar("FilePath", str, Path)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class PrivacyPolicy(LowercaseStrEnum):
|
|
16
|
+
PUBLIC = auto()
|
|
17
|
+
PRIVATE = auto()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ResourceSummary(BaseModel):
|
|
21
|
+
id: str | None = None
|
|
22
|
+
name: str
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class SplightDatabaseBaseModel(BaseModel):
|
|
26
|
+
_db_client: AbstractDatabaseClient = PrivateAttr()
|
|
27
|
+
|
|
28
|
+
def __init__(self, **data):
|
|
29
|
+
super().__init__(**data)
|
|
30
|
+
self._db_client = self.__get_database_client()
|
|
31
|
+
|
|
32
|
+
@staticmethod
|
|
33
|
+
def get_event_name(type_: str, action: str) -> str:
|
|
34
|
+
return f"{type_.lower()}-{action.lower()}"
|
|
35
|
+
|
|
36
|
+
def save(self):
|
|
37
|
+
files_dict = self._get_model_files_dict()
|
|
38
|
+
saved = self._db_client.save(
|
|
39
|
+
self.__class__.__name__,
|
|
40
|
+
self.model_dump(exclude_none=True, mode="json"),
|
|
41
|
+
files=files_dict,
|
|
42
|
+
)
|
|
43
|
+
instance = self.model_validate(saved)
|
|
44
|
+
for key, field in self.model_fields.items():
|
|
45
|
+
setattr(self, key, getattr(instance, key))
|
|
46
|
+
|
|
47
|
+
def delete(self):
|
|
48
|
+
self._db_client.delete(
|
|
49
|
+
resource_name=self.__class__.__name__, id=self.id
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
@classmethod
|
|
53
|
+
def retrieve(cls, resource_id: str) -> "SplightDatabaseBaseModel":
|
|
54
|
+
db_client = cls.__get_database_client()
|
|
55
|
+
instance = db_client.get(
|
|
56
|
+
resource_name=cls.__name__, id=resource_id, first=True
|
|
57
|
+
)
|
|
58
|
+
return cls.model_validate(instance) if instance else None
|
|
59
|
+
|
|
60
|
+
@classmethod
|
|
61
|
+
def list(cls, **params: Dict) -> List["SplightDatabaseBaseModel"]:
|
|
62
|
+
db_client = cls.__get_database_client()
|
|
63
|
+
instances = db_client.get(resource_name=cls.__name__, **params)
|
|
64
|
+
instances = [cls.model_validate(item) for item in instances]
|
|
65
|
+
return instances
|
|
66
|
+
|
|
67
|
+
@staticmethod
|
|
68
|
+
def __get_database_client() -> AbstractDatabaseClient:
|
|
69
|
+
db_client = DatabaseClientBuilder.build(
|
|
70
|
+
parameters={
|
|
71
|
+
"base_url": settings.SPLIGHT_PLATFORM_API_HOST,
|
|
72
|
+
"access_id": settings.SPLIGHT_ACCESS_ID,
|
|
73
|
+
"secret_key": settings.SPLIGHT_SECRET_KEY,
|
|
74
|
+
},
|
|
75
|
+
)
|
|
76
|
+
return db_client
|
|
77
|
+
|
|
78
|
+
def _get_model_files_dict(self) -> Optional[Dict]:
|
|
79
|
+
return None
|