splight-lib 5.10.1.dev1__tar.gz → 5.10.2__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.10.1.dev1 → splight_lib-5.10.2}/PKG-INFO +1 -1
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/pyproject.toml +1 -1
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/abstract/client.py +4 -3
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/client/database/classmap.py +0 -4
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/client/database/remote_client.py +2 -6
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/client/datalake/abstract.py +5 -3
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/client/datalake/remote_client.py +1 -1
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/logging/_internal.py +0 -1
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/models/__init__.py +0 -4
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/models/datalake_base.py +3 -2
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/models/exceptions.py +0 -9
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/models/function.py +9 -2
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/solution/solution.py +1 -1
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/tests/test_api_contracts.py +6 -1
- splight_lib-5.10.1.dev1/splight_lib/models/hub_server.py +0 -118
- splight_lib-5.10.1.dev1/splight_lib/models/server.py +0 -211
- splight_lib-5.10.1.dev1/splight_lib/server/__init__.py +0 -5
- splight_lib-5.10.1.dev1/splight_lib/server/exceptions.py +0 -3
- splight_lib-5.10.1.dev1/splight_lib/server/server.py +0 -16
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/LICENSE.txt +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/README.md +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/__init__.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/abstract/__init__.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/auth/__init__.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/auth/exceptions.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/auth/mac_auth.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/auth/token.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/client/__init__.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/client/database/__init__.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/client/database/abstract.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/client/database/builder.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/client/datalake/__init__.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/client/datalake/buffer.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/client/datalake/builder.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/client/datalake/constants.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/client/datalake/exceptions.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/client/exceptions.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/client/file_handler.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/client/filter.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/client/hub/__init__.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/client/hub/abstract.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/client/hub/client.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/client/tests/test_database.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/client/tests/test_datalake.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/component/__init__.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/component/abstract.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/component/exceptions.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/component/spec.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/component/tests/test_abstract.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/component/tests/test_spec.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/conftest.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/constants.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/encryption.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/execution/__init__.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/execution/engine.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/execution/exceptions.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/execution/scheduling.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/execution/task.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/execution/tests/test_execution.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/execution/tests/test_scheduling.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/execution/trigger.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/logging/__init__.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/logging/component.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/logging/constants.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/logging/logging.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/logging/tests/test_logging.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/models/actions.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/models/alert.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/models/asset.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/models/attribute.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/models/component.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/models/dashboard.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/models/data_address.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/models/database_base.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/models/datalake.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/models/file.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/models/generic.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/models/hub.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/models/hub_solution.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/models/metadata.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/models/native.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/models/secret.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/models/solution.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/models/tag.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/models/tests/models.json +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/models/tests/test_component_object_instance.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/models/tests/test_database_model.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/models/tests/test_metadata.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/models/tests/test_models.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/restclient/__init__.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/restclient/client.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/restclient/exceptions.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/restclient/tests/test_restclient.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/restclient/types.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/settings.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/solution/__init__.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/solution/exceptions.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/stringcase.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/testing/__init__.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/tests/FakeProc.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/tests/asset_geometries.json +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/tests/test_encryption.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/utils/__init__.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/utils/custom_model.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/utils/hub.py +0 -0
- {splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/version.py +0 -0
|
@@ -32,6 +32,7 @@ class AbstractRemoteClient(AbstractClient):
|
|
|
32
32
|
return params
|
|
33
33
|
|
|
34
34
|
|
|
35
|
+
# TODO: Remove this class
|
|
35
36
|
class QuerySet(UserList):
|
|
36
37
|
def __init__(
|
|
37
38
|
self,
|
|
@@ -70,7 +71,7 @@ class QuerySet(UserList):
|
|
|
70
71
|
return self._cached_results[i]
|
|
71
72
|
|
|
72
73
|
if isinstance(i, slice):
|
|
73
|
-
skip_ = self._kwargs.get("skip_", 0) + i.start
|
|
74
|
+
# skip_ = self._kwargs.get("skip_", 0) + i.start
|
|
74
75
|
|
|
75
76
|
limit_ = i.stop - i.start
|
|
76
77
|
if "limit_" in self._kwargs:
|
|
@@ -78,8 +79,8 @@ class QuerySet(UserList):
|
|
|
78
79
|
limit_ = min(limit_, old_limit_)
|
|
79
80
|
|
|
80
81
|
kwargs = {**self._kwargs}
|
|
81
|
-
kwargs["skip_"] = skip_
|
|
82
|
-
kwargs["limit_"] = limit_
|
|
82
|
+
# kwargs["skip_"] = skip_
|
|
83
|
+
# kwargs["limit_"] = limit_
|
|
83
84
|
kwargs.pop("get_func", None)
|
|
84
85
|
kwargs.pop("count_func", None)
|
|
85
86
|
return QuerySet(
|
|
@@ -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 = {
|
|
@@ -36,5 +33,4 @@ CUSTOM_PATHS_MAP = {
|
|
|
36
33
|
"get-asset-attribute": "{prefix}/assets/{asset}/get-attribute/",
|
|
37
34
|
"decrypt-secret": "{prefix}/secrets/decrypt/",
|
|
38
35
|
"routine-status": "{prefix}/component/routines/{routine}/update_status/",
|
|
39
|
-
"server-status": "{prefix}/server/servers/{server}/update-status/",
|
|
40
36
|
}
|
|
@@ -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")
|
|
@@ -9,11 +9,13 @@ class Records(TypedDict):
|
|
|
9
9
|
records: list[dict[str, Any]]
|
|
10
10
|
|
|
11
11
|
|
|
12
|
+
# TODO: Fix this class after delete QuerySet
|
|
12
13
|
class AbstractDatalakeClient(AbstractRemoteClient):
|
|
13
14
|
def get(self, *args, **kwargs) -> QuerySet:
|
|
14
|
-
kwargs["get_func"] = "_get"
|
|
15
|
-
kwargs["count_func"] = "None"
|
|
16
|
-
return QuerySet(self, *args, **kwargs)
|
|
15
|
+
# kwargs["get_func"] = "_get"
|
|
16
|
+
# kwargs["count_func"] = "None"
|
|
17
|
+
# return QuerySet(self, *args, **kwargs)
|
|
18
|
+
return self._get(*args, **kwargs)
|
|
17
19
|
|
|
18
20
|
async def async_get(self, *args, **kwargs):
|
|
19
21
|
# TODO: consider using an async QuerySet
|
|
@@ -224,7 +224,7 @@ class BufferedSyncRemoteDataClient(SyncRemoteDatalakeClient):
|
|
|
224
224
|
)
|
|
225
225
|
|
|
226
226
|
def save(self, records: Records) -> list[dict]:
|
|
227
|
-
logger.debug("Saving documents in datalake",
|
|
227
|
+
logger.debug("Saving documents in datalake", tags=LogTags.DATALAKE)
|
|
228
228
|
collection = records["collection"]
|
|
229
229
|
buffer = self._data_buffers[collection]
|
|
230
230
|
with self._lock:
|
|
@@ -22,12 +22,10 @@ from splight_lib.models.datalake import DataRequest, PipelineStep, Trace
|
|
|
22
22
|
from splight_lib.models.file import File
|
|
23
23
|
from splight_lib.models.function import Function, FunctionItem, QueryFilter
|
|
24
24
|
from splight_lib.models.hub import HubComponent
|
|
25
|
-
from splight_lib.models.hub_server import HubServer
|
|
26
25
|
from splight_lib.models.hub_solution import HubSolution
|
|
27
26
|
from splight_lib.models.metadata import Metadata
|
|
28
27
|
from splight_lib.models.native import Boolean, Number, String
|
|
29
28
|
from splight_lib.models.secret import Secret
|
|
30
|
-
from splight_lib.models.server import Server
|
|
31
29
|
from splight_lib.models.solution import Solution
|
|
32
30
|
from splight_lib.models.tag import Tag
|
|
33
31
|
|
|
@@ -54,14 +52,12 @@ __all__ = [
|
|
|
54
52
|
FunctionItem,
|
|
55
53
|
HubSolution,
|
|
56
54
|
HubComponent,
|
|
57
|
-
HubServer,
|
|
58
55
|
QueryFilter,
|
|
59
56
|
Metadata,
|
|
60
57
|
Number,
|
|
61
58
|
PipelineStep,
|
|
62
59
|
RoutineEvaluation,
|
|
63
60
|
Secret,
|
|
64
|
-
Server,
|
|
65
61
|
SetPoint,
|
|
66
62
|
Solution,
|
|
67
63
|
String,
|
|
@@ -62,8 +62,9 @@ class SplightDatalakeBaseModel(BaseModel):
|
|
|
62
62
|
)
|
|
63
63
|
instances = request.apply()
|
|
64
64
|
df = pd.DataFrame([instance.dict() for instance in instances])
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
if not df.empty:
|
|
66
|
+
df.index = df["timestamp"]
|
|
67
|
+
df.drop(columns="timestamp", inplace=True)
|
|
67
68
|
return df
|
|
68
69
|
|
|
69
70
|
def save(self) -> None:
|
|
@@ -66,15 +66,6 @@ class InvalidArgument(Exception):
|
|
|
66
66
|
pass
|
|
67
67
|
|
|
68
68
|
|
|
69
|
-
class InvalidServerConfigType(Exception):
|
|
70
|
-
def __init__(self, name: str, type_: str):
|
|
71
|
-
msg = (
|
|
72
|
-
f"Config parameter {name} has an invalid type {type_}. The only "
|
|
73
|
-
"valid types are native and 'File'"
|
|
74
|
-
)
|
|
75
|
-
super().__init__(msg)
|
|
76
|
-
|
|
77
|
-
|
|
78
69
|
class TraceAlreadyExistsError(Exception):
|
|
79
70
|
def __init__(self, ref_id: str):
|
|
80
71
|
msg = f"Trace with ref_id {ref_id} already exists"
|
|
@@ -19,6 +19,7 @@ from splight_lib.models.exceptions import (
|
|
|
19
19
|
InvalidFunctionConfiguration,
|
|
20
20
|
MissingFunctionItemExpression,
|
|
21
21
|
)
|
|
22
|
+
from splight_lib.models.generic import ValueTypeEnum
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
class FunctionItemType(UppercaseStrEnum):
|
|
@@ -31,6 +32,12 @@ class QueryFilter(TypedDict):
|
|
|
31
32
|
name: str
|
|
32
33
|
|
|
33
34
|
|
|
35
|
+
class TypedQueryFilter(TypedDict):
|
|
36
|
+
id: str
|
|
37
|
+
name: str
|
|
38
|
+
type: ValueTypeEnum
|
|
39
|
+
|
|
40
|
+
|
|
34
41
|
class GroupUnit(LowercaseStrEnum):
|
|
35
42
|
EMPTY = ""
|
|
36
43
|
SECOND = auto()
|
|
@@ -62,7 +69,7 @@ class FunctionItem(BaseModel):
|
|
|
62
69
|
expression_plain: str = ""
|
|
63
70
|
|
|
64
71
|
query_filter_asset: Optional[QueryFilter] = None
|
|
65
|
-
query_filter_attribute: Optional[
|
|
72
|
+
query_filter_attribute: Optional[TypedQueryFilter] = None
|
|
66
73
|
|
|
67
74
|
query_group_function: GroupCriteria = GroupCriteria.EMPTY
|
|
68
75
|
query_group_unit: GroupUnit = GroupUnit.EMPTY
|
|
@@ -170,7 +177,7 @@ class Function(SplightDatabaseBaseModel):
|
|
|
170
177
|
type: Literal["cron", "rate"]
|
|
171
178
|
target_variable: str
|
|
172
179
|
target_asset: QueryFilter # NOTE: optional in API
|
|
173
|
-
target_attribute:
|
|
180
|
+
target_attribute: TypedQueryFilter # NOTE: optional in API
|
|
174
181
|
|
|
175
182
|
cron_minutes: Optional[str] = None
|
|
176
183
|
cron_hours: Optional[str] = None
|
|
@@ -15,7 +15,7 @@ class SolutionLoader:
|
|
|
15
15
|
def from_env(cls) -> Solution:
|
|
16
16
|
if not (str_instance := os.environ.get(ENV_VAR)):
|
|
17
17
|
raise MissingInstanceEnvVar(ENV_VAR)
|
|
18
|
-
str_instance = os.environ.get(
|
|
18
|
+
str_instance = os.environ.get("INSTANCE_AS_STR", "")
|
|
19
19
|
instance = json.loads(str_instance)
|
|
20
20
|
if not (instance_id := instance.get("id")):
|
|
21
21
|
raise MissingInstanceId()
|
|
@@ -73,6 +73,7 @@ class AttributeFactory(ModelFactory[Attribute]):
|
|
|
73
73
|
id: str = Use(lambda: str(uuid.uuid4()))
|
|
74
74
|
asset: str = Use(lambda: str(uuid.uuid4()))
|
|
75
75
|
unit: str = Use(lambda: random.choice(["m", "cm", "mm"]))
|
|
76
|
+
type: str = Use(lambda: random.choice(["Number", "String", "Boolean"]))
|
|
76
77
|
|
|
77
78
|
|
|
78
79
|
class AssetFactory(ModelFactory[Asset]):
|
|
@@ -89,7 +90,11 @@ class FunctionItemFactory(ModelFactory[FunctionItem]):
|
|
|
89
90
|
lambda: {"id": str(uuid.uuid4()), "name": "asset"}
|
|
90
91
|
)
|
|
91
92
|
query_filter_attribute = Use(
|
|
92
|
-
lambda: {
|
|
93
|
+
lambda: {
|
|
94
|
+
"id": str(uuid.uuid4()),
|
|
95
|
+
"name": "attribute",
|
|
96
|
+
"type": "Number",
|
|
97
|
+
}
|
|
93
98
|
)
|
|
94
99
|
|
|
95
100
|
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
from glob import glob
|
|
3
|
-
from tempfile import NamedTemporaryFile
|
|
4
|
-
from typing import Dict, List, Optional
|
|
5
|
-
|
|
6
|
-
import py7zr
|
|
7
|
-
from pydantic import BaseModel, Field
|
|
8
|
-
|
|
9
|
-
from splight_lib.constants import DESCRIPTION_MAX_LENGTH
|
|
10
|
-
from splight_lib.models.database_base import (
|
|
11
|
-
FilePath,
|
|
12
|
-
PrivacyPolicy,
|
|
13
|
-
SplightDatabaseBaseModel,
|
|
14
|
-
)
|
|
15
|
-
from splight_lib.models.component import InputParameter
|
|
16
|
-
from splight_lib.utils.hub import (
|
|
17
|
-
COMPRESSION_TYPE,
|
|
18
|
-
README_FILE_1,
|
|
19
|
-
get_ignore_pathspec,
|
|
20
|
-
get_spec,
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class Port(BaseModel):
|
|
25
|
-
name: Optional[str]
|
|
26
|
-
protocol: str = "tcp"
|
|
27
|
-
internal_port: int
|
|
28
|
-
exposed_port: int
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
class HubServer(SplightDatabaseBaseModel):
|
|
32
|
-
id: Optional[str] = None
|
|
33
|
-
name: str
|
|
34
|
-
version: str
|
|
35
|
-
description: Optional[str] = Field(
|
|
36
|
-
default=None, max_length=DESCRIPTION_MAX_LENGTH
|
|
37
|
-
)
|
|
38
|
-
tags: Optional[List[str]] = Field(default=[])
|
|
39
|
-
privacy_policy: PrivacyPolicy = PrivacyPolicy.PUBLIC
|
|
40
|
-
|
|
41
|
-
config: List[InputParameter] = []
|
|
42
|
-
ports: List[Port] = []
|
|
43
|
-
environment: List[Dict[str, str]] = []
|
|
44
|
-
|
|
45
|
-
@classmethod
|
|
46
|
-
def upload(cls, path: FilePath, image_file: str) -> "HubServer":
|
|
47
|
-
db_client = cls._SplightDatabaseBaseModel__get_database_client()
|
|
48
|
-
image_path = os.path.join(path, image_file)
|
|
49
|
-
spec = get_spec(path)
|
|
50
|
-
name = spec.get("name")
|
|
51
|
-
version = spec.get("version")
|
|
52
|
-
|
|
53
|
-
raw_hub_server = db_client.get(
|
|
54
|
-
resource_name=cls.__name__,
|
|
55
|
-
name=name,
|
|
56
|
-
version=version,
|
|
57
|
-
)
|
|
58
|
-
server = cls.model_validate(spec)
|
|
59
|
-
if raw_hub_server:
|
|
60
|
-
old_hub_server = cls.model_validate(raw_hub_server[0])
|
|
61
|
-
server.id = old_hub_server.id
|
|
62
|
-
|
|
63
|
-
server.save()
|
|
64
|
-
|
|
65
|
-
file_name = f"{name}-{version}.{COMPRESSION_TYPE}"
|
|
66
|
-
ignore_pathspec = get_ignore_pathspec(path)
|
|
67
|
-
versioned_path = f"{name}-{version}"
|
|
68
|
-
# TODO: Add required files validations
|
|
69
|
-
readme_path = os.path.join(path, README_FILE_1)
|
|
70
|
-
if not os.path.exists(readme_path):
|
|
71
|
-
raise FileNotFoundError(f"README.md file not found: {readme_path}")
|
|
72
|
-
with py7zr.SevenZipFile(file_name, "w") as archive:
|
|
73
|
-
all_files = glob(f"{path}/**", recursive=True)
|
|
74
|
-
for filepath in all_files:
|
|
75
|
-
if ignore_pathspec and ignore_pathspec.match_file(filepath):
|
|
76
|
-
continue
|
|
77
|
-
if os.path.isdir(filepath):
|
|
78
|
-
continue
|
|
79
|
-
if image_file in filepath:
|
|
80
|
-
continue
|
|
81
|
-
rel_filename = os.path.relpath(filepath, path)
|
|
82
|
-
new_filepath = os.path.join(versioned_path, rel_filename)
|
|
83
|
-
archive.write(filepath, new_filepath)
|
|
84
|
-
|
|
85
|
-
data = server.model_dump()
|
|
86
|
-
try:
|
|
87
|
-
db_client.upload(
|
|
88
|
-
"hubserverversion",
|
|
89
|
-
instance=data,
|
|
90
|
-
file_path=file_name,
|
|
91
|
-
type_="source",
|
|
92
|
-
)
|
|
93
|
-
db_client.upload(
|
|
94
|
-
"hubserverversion",
|
|
95
|
-
instance=data,
|
|
96
|
-
file_path=readme_path,
|
|
97
|
-
type_="readme",
|
|
98
|
-
)
|
|
99
|
-
db_client.upload(
|
|
100
|
-
"hubserverversion",
|
|
101
|
-
instance=data,
|
|
102
|
-
file_path=image_path,
|
|
103
|
-
type_="image",
|
|
104
|
-
)
|
|
105
|
-
except Exception as exc:
|
|
106
|
-
raise exc
|
|
107
|
-
finally:
|
|
108
|
-
if os.path.exists(file_name):
|
|
109
|
-
os.remove(file_name)
|
|
110
|
-
return server
|
|
111
|
-
|
|
112
|
-
def download(self) -> NamedTemporaryFile:
|
|
113
|
-
db_client = self._SplightDatabaseBaseModel__get_database_client()
|
|
114
|
-
return db_client.download(
|
|
115
|
-
resource_name="hubserverversion",
|
|
116
|
-
instance=self.model_dump(),
|
|
117
|
-
type_="source",
|
|
118
|
-
)
|
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
import re
|
|
2
|
-
import warnings
|
|
3
|
-
from collections import namedtuple
|
|
4
|
-
from datetime import datetime
|
|
5
|
-
from enum import auto
|
|
6
|
-
from typing import Any, NamedTuple, Optional
|
|
7
|
-
|
|
8
|
-
from pydantic import AnyUrl, BaseModel, Field, computed_field
|
|
9
|
-
from strenum import LowercaseStrEnum, PascalCaseStrEnum
|
|
10
|
-
|
|
11
|
-
from splight_lib.models.database_base import SplightDatabaseBaseModel
|
|
12
|
-
from splight_lib.models.exceptions import (
|
|
13
|
-
InvalidArgument,
|
|
14
|
-
InvalidServerConfigType,
|
|
15
|
-
)
|
|
16
|
-
from splight_lib.models.file import File
|
|
17
|
-
from splight_lib.models.hub_server import HubServer
|
|
18
|
-
from splight_lib.models.secret import Secret
|
|
19
|
-
|
|
20
|
-
warnings.filterwarnings("ignore", category=RuntimeWarning)
|
|
21
|
-
|
|
22
|
-
NATIVE_TYPES = {
|
|
23
|
-
"int": int,
|
|
24
|
-
"bool": bool,
|
|
25
|
-
"str": str,
|
|
26
|
-
"float": float,
|
|
27
|
-
"datetime": datetime,
|
|
28
|
-
"url": AnyUrl,
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
DATABASE_TYPES = {
|
|
32
|
-
"File": File,
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
DB_MODEL_TYPE_MAPPING = {
|
|
36
|
-
**NATIVE_TYPES,
|
|
37
|
-
**DATABASE_TYPES,
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
def get_field_value(field: dict):
|
|
42
|
-
field_multiple = field.get("multiple", False)
|
|
43
|
-
field_type = field.get("type")
|
|
44
|
-
field_value = field.get("value")
|
|
45
|
-
|
|
46
|
-
if not field_value:
|
|
47
|
-
return [] if field_multiple else None
|
|
48
|
-
|
|
49
|
-
if field_type in NATIVE_TYPES:
|
|
50
|
-
value = (
|
|
51
|
-
field_value
|
|
52
|
-
if not isinstance(field_value, str)
|
|
53
|
-
else parse_variable_string(field_value)
|
|
54
|
-
)
|
|
55
|
-
elif field_type in DATABASE_TYPES:
|
|
56
|
-
model_class = DATABASE_TYPES[field_type]
|
|
57
|
-
value = (
|
|
58
|
-
model_class.retrieve(field_value)
|
|
59
|
-
if not field_multiple
|
|
60
|
-
else [model_class.retrieve(item) for item in field_value]
|
|
61
|
-
)
|
|
62
|
-
return value
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
def get_model_class(config: BaseModel, name: str) -> NamedTuple:
|
|
66
|
-
config_class = namedtuple(name, [x.name for x in config])
|
|
67
|
-
return config_class
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
def load_server_config(
|
|
71
|
-
config: list[dict], config_class: NamedTuple
|
|
72
|
-
) -> NamedTuple:
|
|
73
|
-
config_dict = {}
|
|
74
|
-
for item in config:
|
|
75
|
-
if item["type"] not in DB_MODEL_TYPE_MAPPING:
|
|
76
|
-
raise InvalidServerConfigType(item["name"], item["type"])
|
|
77
|
-
config_dict.update({item["name"]: get_field_value(item)})
|
|
78
|
-
config = config_class(**config_dict)
|
|
79
|
-
return config
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def load_server_ports(
|
|
83
|
-
ports: list[dict], model_class: NamedTuple
|
|
84
|
-
) -> namedtuple:
|
|
85
|
-
ports_dict = {}
|
|
86
|
-
for port in ports:
|
|
87
|
-
if isinstance(port["internal_port"], int) and not (
|
|
88
|
-
0 <= port["internal_port"] <= 65535
|
|
89
|
-
):
|
|
90
|
-
raise ValueError(
|
|
91
|
-
f"Internal port {port['internal_port']} is out of valid range (0-65535)"
|
|
92
|
-
)
|
|
93
|
-
if isinstance(port["exposed_port"], int) and not (
|
|
94
|
-
0 <= port["exposed_port"] <= 65535
|
|
95
|
-
):
|
|
96
|
-
raise ValueError(
|
|
97
|
-
f"External port {port['exposed_port']} is out of valid range (0-65535)"
|
|
98
|
-
)
|
|
99
|
-
if port["protocol"] not in ["tcp", "udp"]:
|
|
100
|
-
raise ValueError(
|
|
101
|
-
f"Protocol {port['protocol']} is not valid. Must be 'tcp' or 'udp'"
|
|
102
|
-
)
|
|
103
|
-
ports_dict.update({port["name"]: port})
|
|
104
|
-
resources = model_class(**ports_dict)
|
|
105
|
-
return resources
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
class ServerStatus(PascalCaseStrEnum):
|
|
109
|
-
RUNNING = auto()
|
|
110
|
-
FAILED = auto()
|
|
111
|
-
SUCCEEDED = auto()
|
|
112
|
-
PENDING = auto()
|
|
113
|
-
START_REQUESTED = auto()
|
|
114
|
-
STOP_REQUESTED = auto()
|
|
115
|
-
STOPPED = auto()
|
|
116
|
-
UNKNOWN = auto()
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
class PrivacyPolicy(LowercaseStrEnum):
|
|
120
|
-
PUBLIC = auto()
|
|
121
|
-
PRIVATE = auto()
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
class Port(BaseModel):
|
|
125
|
-
name: Optional[str]
|
|
126
|
-
internal_port: int
|
|
127
|
-
exposed_port: int
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
class Server(SplightDatabaseBaseModel):
|
|
131
|
-
id: Optional[str] = None
|
|
132
|
-
name: Optional[str] = None
|
|
133
|
-
version: str
|
|
134
|
-
hub_server: HubServer
|
|
135
|
-
raw_config: list[dict] = Field(alias="config")
|
|
136
|
-
raw_ports: list[dict] = Field(alias="ports")
|
|
137
|
-
raw_env_vars: list[dict] = Field(alias="env_vars")
|
|
138
|
-
|
|
139
|
-
def model_dump(self, *args, **kwargs):
|
|
140
|
-
kwargs.update({"by_alias": True})
|
|
141
|
-
return super().model_dump(*args, **kwargs)
|
|
142
|
-
|
|
143
|
-
def model_dump_json(self, *args, **kwargs):
|
|
144
|
-
kwargs.update({"by_alias": True})
|
|
145
|
-
return super().model_dump_json(*args, **kwargs)
|
|
146
|
-
|
|
147
|
-
@computed_field(alias="parsed_config")
|
|
148
|
-
@property
|
|
149
|
-
def config(self) -> NamedTuple:
|
|
150
|
-
model_class = get_model_class(self.hub_server.config, "Config")
|
|
151
|
-
config = load_server_config(self.raw_config, model_class)
|
|
152
|
-
return config
|
|
153
|
-
|
|
154
|
-
@computed_field(alias="parsed_ports")
|
|
155
|
-
@property
|
|
156
|
-
def ports(self) -> NamedTuple:
|
|
157
|
-
model_class = get_model_class(self.hub_server.ports, "Ports")
|
|
158
|
-
ports = load_server_ports(self.raw_ports, model_class)
|
|
159
|
-
return ports
|
|
160
|
-
|
|
161
|
-
def update_config(self, **kwargs: dict):
|
|
162
|
-
valid_params = [x["name"] for x in self.raw_config]
|
|
163
|
-
for key, value in kwargs.items():
|
|
164
|
-
if key not in valid_params:
|
|
165
|
-
raise InvalidArgument(
|
|
166
|
-
(
|
|
167
|
-
f"Got invalid parameter {key}. Valid config parameter "
|
|
168
|
-
f"are {valid_params}"
|
|
169
|
-
)
|
|
170
|
-
)
|
|
171
|
-
for item in self.raw_config:
|
|
172
|
-
if item["name"] == key:
|
|
173
|
-
item["value"] = value
|
|
174
|
-
break
|
|
175
|
-
|
|
176
|
-
def update_ports(self, **kwargs: dict):
|
|
177
|
-
valid_params = [x["name"] for x in self.raw_ports]
|
|
178
|
-
for key, value in kwargs.items():
|
|
179
|
-
if key not in valid_params:
|
|
180
|
-
raise InvalidArgument(
|
|
181
|
-
(
|
|
182
|
-
f"Got invalid parameter {key}. Valid port "
|
|
183
|
-
f"parameter are {valid_params}"
|
|
184
|
-
)
|
|
185
|
-
)
|
|
186
|
-
for item in self.raw_ports:
|
|
187
|
-
if item["name"] == key:
|
|
188
|
-
item["value"] = value
|
|
189
|
-
break
|
|
190
|
-
|
|
191
|
-
def update_status(self, status: ServerStatus):
|
|
192
|
-
_ = self._db_client.operate(
|
|
193
|
-
resource_name="server-status",
|
|
194
|
-
instance={
|
|
195
|
-
"server": self.id,
|
|
196
|
-
"deployment_status": status,
|
|
197
|
-
},
|
|
198
|
-
)
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
def parse_variable_string(raw_value: Optional[str]) -> Any:
|
|
202
|
-
if raw_value is None:
|
|
203
|
-
return ""
|
|
204
|
-
pattern = re.compile(r"^\$\{\{(\w+)\.(\w+)\}\}$")
|
|
205
|
-
match = pattern.search(raw_value)
|
|
206
|
-
if not match:
|
|
207
|
-
return raw_value
|
|
208
|
-
_, secret_name = match.groups()
|
|
209
|
-
# TODO: handle errors (not found or not allowed)
|
|
210
|
-
secret = Secret.decrypt(name=secret_name)
|
|
211
|
-
return secret.value
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
import os
|
|
3
|
-
|
|
4
|
-
from splight_lib.models import Server
|
|
5
|
-
from splight_lib.server.exceptions import MissingInstanceEnvVar
|
|
6
|
-
|
|
7
|
-
ENV_VAR = "SPLIGHT_SERVER_ID"
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class ServerLoader:
|
|
11
|
-
@classmethod
|
|
12
|
-
def from_env(cls) -> Server:
|
|
13
|
-
if not (instance_id := os.environ.get(ENV_VAR)):
|
|
14
|
-
raise MissingInstanceEnvVar(ENV_VAR)
|
|
15
|
-
server = Server.retrieve(instance_id)
|
|
16
|
-
return server
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/execution/tests/test_execution.py
RENAMED
|
File without changes
|
{splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/execution/tests/test_scheduling.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/models/tests/test_database_model.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{splight_lib-5.10.1.dev1 → splight_lib-5.10.2}/splight_lib/restclient/tests/test_restclient.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|