esd-services-api-client 2.2.3__tar.gz → 2.2.5__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.
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/PKG-INFO +1 -1
- esd_services_api_client-2.2.5/esd_services_api_client/_version.py +1 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/nexus/core/app_core.py +9 -3
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/nexus/core/app_dependencies.py +71 -1
- esd_services_api_client-2.2.5/esd_services_api_client/nexus/core/serializers.py +78 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/nexus/telemetry/recorder.py +10 -7
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/pyproject.toml +1 -1
- esd_services_api_client-2.2.3/esd_services_api_client/_version.py +0 -1
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/LICENSE +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/README.md +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/__init__.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/beast/__init__.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/beast/v3/__init__.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/beast/v3/_connector.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/beast/v3/_models.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/boxer/README.md +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/boxer/__init__.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/boxer/_auth.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/boxer/_base.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/boxer/_connector.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/boxer/_models.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/common/__init__.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/crystal/__init__.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/crystal/_api_versions.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/crystal/_connector.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/crystal/_models.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/nexus/README.md +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/nexus/__init__.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/nexus/abstractions/__init__.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/nexus/abstractions/algrorithm_cache.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/nexus/abstractions/input_object.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/nexus/abstractions/logger_factory.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/nexus/abstractions/nexus_object.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/nexus/abstractions/socket_provider.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/nexus/algorithms/__init__.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/nexus/algorithms/_baseline_algorithm.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/nexus/algorithms/_remote_algorithm.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/nexus/algorithms/distributed.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/nexus/algorithms/forked_algorithm.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/nexus/algorithms/minimalistic.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/nexus/algorithms/recursive.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/nexus/configurations/__init__.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/nexus/configurations/algorithm_configuration.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/nexus/core/__init__.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/nexus/exceptions/__init__.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/nexus/exceptions/_nexus_error.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/nexus/exceptions/cache_errors.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/nexus/exceptions/input_reader_error.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/nexus/exceptions/startup_error.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/nexus/input/__init__.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/nexus/input/input_processor.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/nexus/input/input_reader.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/nexus/input/payload_reader.py +0 -0
- {esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/nexus/telemetry/__init__.py +0 -0
@@ -0,0 +1 @@
|
|
1
|
+
__version__ = '2.2.5'
|
@@ -30,7 +30,6 @@ import urllib3.exceptions
|
|
30
30
|
import azure.core.exceptions
|
31
31
|
from adapta.process_communication import DataSocket
|
32
32
|
from adapta.storage.blob.base import StorageClient
|
33
|
-
from adapta.storage.models.format import DataFrameJsonSerializationFormat
|
34
33
|
from adapta.storage.query_enabled_store import QueryEnabledStore
|
35
34
|
from injector import Injector
|
36
35
|
|
@@ -52,6 +51,9 @@ from esd_services_api_client.nexus.configurations.algorithm_configuration import
|
|
52
51
|
from esd_services_api_client.nexus.core.app_dependencies import (
|
53
52
|
ServiceConfigurator,
|
54
53
|
)
|
54
|
+
from esd_services_api_client.nexus.core.serializers import (
|
55
|
+
ResultSerializer,
|
56
|
+
)
|
55
57
|
from esd_services_api_client.nexus.input.input_processor import InputProcessor
|
56
58
|
from esd_services_api_client.nexus.input.input_reader import InputReader
|
57
59
|
from esd_services_api_client.nexus.input.payload_reader import (
|
@@ -204,15 +206,19 @@ class Nexus:
|
|
204
206
|
|
205
207
|
:return: blob uri
|
206
208
|
"""
|
209
|
+
dataframe_data = data.dataframe()
|
210
|
+
serializer = self._injector.get(ResultSerializer)
|
207
211
|
storage_client = self._injector.get(StorageClient)
|
208
212
|
output_path = f"{os.getenv('NEXUS__ALGORITHM_OUTPUT_PATH')}/{self._run_args.request_id}.json"
|
209
213
|
blob_path = DataSocket(
|
210
214
|
data_path=output_path, alias="output", data_format="null"
|
211
215
|
).parse_data_path()
|
212
216
|
storage_client.save_data_as_blob(
|
213
|
-
data=
|
217
|
+
data=dataframe_data,
|
214
218
|
blob_path=blob_path,
|
215
|
-
serialization_format=
|
219
|
+
serialization_format=serializer.get_serialization_format(
|
220
|
+
dataframe_data
|
221
|
+
),
|
216
222
|
overwrite=True,
|
217
223
|
)
|
218
224
|
return storage_client.get_blob_uri(blob_path=blob_path)
|
@@ -19,8 +19,9 @@
|
|
19
19
|
|
20
20
|
import json
|
21
21
|
import os
|
22
|
+
import re
|
22
23
|
from pydoc import locate
|
23
|
-
from typing import final, Type
|
24
|
+
from typing import final, Type, Any
|
24
25
|
|
25
26
|
from adapta.metrics import MetricsProvider
|
26
27
|
from adapta.storage.blob.base import StorageClient
|
@@ -45,6 +46,10 @@ from esd_services_api_client.nexus.input.payload_reader import (
|
|
45
46
|
AlgorithmPayload,
|
46
47
|
)
|
47
48
|
from esd_services_api_client.nexus.telemetry.recorder import TelemetryRecorder
|
49
|
+
from esd_services_api_client.nexus.core.serializers import (
|
50
|
+
TelemetrySerializer,
|
51
|
+
ResultSerializer,
|
52
|
+
)
|
48
53
|
|
49
54
|
|
50
55
|
@final
|
@@ -167,6 +172,48 @@ class ExternalSocketsModule(Module):
|
|
167
172
|
)
|
168
173
|
|
169
174
|
|
175
|
+
@final
|
176
|
+
class ResultSerializerModule(Module):
|
177
|
+
"""
|
178
|
+
Serialization format module for results.
|
179
|
+
"""
|
180
|
+
|
181
|
+
@singleton
|
182
|
+
@provider
|
183
|
+
def provide(self) -> ResultSerializer:
|
184
|
+
"""
|
185
|
+
DI factory method.
|
186
|
+
"""
|
187
|
+
serializer = ResultSerializer()
|
188
|
+
for serialization_format in locate_classes(
|
189
|
+
re.compile(r"NEXUS__RESULT_SERIALIZATION_FORMAT_(.+)_CLASS")
|
190
|
+
):
|
191
|
+
serializer = serializer.with_format(serialization_format)
|
192
|
+
|
193
|
+
return serializer
|
194
|
+
|
195
|
+
|
196
|
+
@final
|
197
|
+
class TelemetrySerializerModule(Module):
|
198
|
+
"""
|
199
|
+
Serialization format module for telemetry.
|
200
|
+
"""
|
201
|
+
|
202
|
+
@singleton
|
203
|
+
@provider
|
204
|
+
def provide(self) -> TelemetrySerializer:
|
205
|
+
"""
|
206
|
+
DI factory method.
|
207
|
+
"""
|
208
|
+
serializer = TelemetrySerializer()
|
209
|
+
for serialization_format in locate_classes(
|
210
|
+
re.compile(r"NEXUS__TELEMETRY_SERIALIZATION_FORMAT_(.+)_CLASS")
|
211
|
+
):
|
212
|
+
serializer = serializer.with_format(serialization_format)
|
213
|
+
|
214
|
+
return serializer
|
215
|
+
|
216
|
+
|
170
217
|
@final
|
171
218
|
class CacheModule(Module):
|
172
219
|
"""
|
@@ -195,6 +242,8 @@ class ServiceConfigurator:
|
|
195
242
|
QueryEnabledStoreModule(),
|
196
243
|
StorageClientModule(),
|
197
244
|
ExternalSocketsModule(),
|
245
|
+
TelemetrySerializerModule(),
|
246
|
+
ResultSerializerModule(),
|
198
247
|
CacheModule(),
|
199
248
|
type(f"{TelemetryRecorder.__name__}Module", (Module,), {})(),
|
200
249
|
]
|
@@ -241,3 +290,24 @@ class ServiceConfigurator:
|
|
241
290
|
lambda binder: binder.bind(config.__class__, to=config, scope=singleton)
|
242
291
|
)
|
243
292
|
return self
|
293
|
+
|
294
|
+
|
295
|
+
def locate_classes(pattern: re.Pattern) -> list[Type[Any]]:
|
296
|
+
"""
|
297
|
+
Locates all classes matching the pattern in the environment. Throws a start-up error if any class is not found.
|
298
|
+
"""
|
299
|
+
classes = {
|
300
|
+
(var_name, class_path): locate(class_path)
|
301
|
+
for var_name, class_path in os.environ.items()
|
302
|
+
if pattern.match(var_name)
|
303
|
+
}
|
304
|
+
|
305
|
+
non_located_classes = [
|
306
|
+
name_and_path for name_and_path, class_ in classes.items() if class_ is None
|
307
|
+
]
|
308
|
+
if non_located_classes:
|
309
|
+
raise FatalStartupConfigurationError(
|
310
|
+
f"Failed to locate classes: {non_located_classes}"
|
311
|
+
)
|
312
|
+
|
313
|
+
return list(classes.values())
|
@@ -0,0 +1,78 @@
|
|
1
|
+
"""Serialization format module."""
|
2
|
+
from typing import final, Any, TypeVar, Type
|
3
|
+
|
4
|
+
import pandas
|
5
|
+
from adapta.storage.models.format import (
|
6
|
+
DataFrameParquetSerializationFormat,
|
7
|
+
DictJsonSerializationFormat,
|
8
|
+
SerializationFormat,
|
9
|
+
)
|
10
|
+
|
11
|
+
T = TypeVar("T") # pylint: disable=C0103
|
12
|
+
|
13
|
+
|
14
|
+
class Serializer:
|
15
|
+
"""
|
16
|
+
Serializer that dynamically infers serialization format. The format to use is determined at runtime
|
17
|
+
by the type of the data.
|
18
|
+
"""
|
19
|
+
|
20
|
+
def __init__(
|
21
|
+
self,
|
22
|
+
default_serialization_formats: dict[
|
23
|
+
Type[T], Type[SerializationFormat[T]]
|
24
|
+
] = None,
|
25
|
+
):
|
26
|
+
self._serialization_formats = (
|
27
|
+
{}
|
28
|
+
if default_serialization_formats is None
|
29
|
+
else default_serialization_formats
|
30
|
+
)
|
31
|
+
|
32
|
+
def get_serialization_format(self, data: Any) -> Type[SerializationFormat]:
|
33
|
+
"""
|
34
|
+
Get the serializer for the data.
|
35
|
+
"""
|
36
|
+
return self._serialization_formats[type(data)]
|
37
|
+
|
38
|
+
def with_format(
|
39
|
+
self, serialization_format: Type[SerializationFormat]
|
40
|
+
) -> "Serializer":
|
41
|
+
"""Add a serialization format to the supported formats. Note that only 1 serialization format is allowed per
|
42
|
+
type."""
|
43
|
+
serialization_target_type = serialization_format.__orig_bases__[0].__args__[0]
|
44
|
+
self._serialization_formats[serialization_target_type] = serialization_format
|
45
|
+
|
46
|
+
return self
|
47
|
+
|
48
|
+
def serialize(self, data) -> bytes:
|
49
|
+
"""
|
50
|
+
Serialize data.
|
51
|
+
"""
|
52
|
+
return self.get_serialization_format(data)().serialize(data)
|
53
|
+
|
54
|
+
|
55
|
+
@final
|
56
|
+
class TelemetrySerializer(Serializer):
|
57
|
+
"""Telemetry serialization format"""
|
58
|
+
|
59
|
+
def __init__(self):
|
60
|
+
super().__init__(
|
61
|
+
default_serialization_formats={
|
62
|
+
pandas.DataFrame: DataFrameParquetSerializationFormat,
|
63
|
+
dict: DictJsonSerializationFormat,
|
64
|
+
}
|
65
|
+
)
|
66
|
+
|
67
|
+
|
68
|
+
@final
|
69
|
+
class ResultSerializer(Serializer):
|
70
|
+
"""Result serialization format"""
|
71
|
+
|
72
|
+
def __init__(self):
|
73
|
+
super().__init__(
|
74
|
+
default_serialization_formats={
|
75
|
+
pandas.DataFrame: DataFrameParquetSerializationFormat,
|
76
|
+
dict: DictJsonSerializationFormat,
|
77
|
+
}
|
78
|
+
)
|
@@ -10,14 +10,13 @@ import pandas as pd
|
|
10
10
|
from adapta.metrics import MetricsProvider
|
11
11
|
from adapta.process_communication import DataSocket
|
12
12
|
from adapta.storage.blob.base import StorageClient
|
13
|
-
from adapta.storage.models.format import (
|
14
|
-
DictJsonSerializationFormat,
|
15
|
-
DataFrameParquetSerializationFormat,
|
16
|
-
)
|
17
13
|
from injector import inject, singleton
|
18
14
|
|
19
15
|
from esd_services_api_client.nexus.abstractions.logger_factory import LoggerFactory
|
20
16
|
from esd_services_api_client.nexus.abstractions.nexus_object import NexusCoreObject
|
17
|
+
from esd_services_api_client.nexus.core.serializers import (
|
18
|
+
TelemetrySerializer,
|
19
|
+
)
|
21
20
|
|
22
21
|
|
23
22
|
@final
|
@@ -37,12 +36,14 @@ class TelemetryRecorder(NexusCoreObject):
|
|
37
36
|
def __init__(
|
38
37
|
self,
|
39
38
|
storage_client: StorageClient,
|
39
|
+
serializer: TelemetrySerializer,
|
40
40
|
metrics_provider: MetricsProvider,
|
41
41
|
logger_factory: LoggerFactory,
|
42
42
|
):
|
43
43
|
super().__init__(metrics_provider, logger_factory)
|
44
44
|
self._storage_client = storage_client
|
45
45
|
self._telemetry_base_path = os.getenv("NEXUS__TELEMETRY_PATH")
|
46
|
+
self._serializer = serializer
|
46
47
|
|
47
48
|
async def record(self, run_id: str, **telemetry_args):
|
48
49
|
"""
|
@@ -74,9 +75,9 @@ class TelemetryRecorder(NexusCoreObject):
|
|
74
75
|
data_path=f"{self._telemetry_base_path}/{entity_name}/{run_id}",
|
75
76
|
data_format="null",
|
76
77
|
).parse_data_path(),
|
77
|
-
serialization_format=
|
78
|
-
|
79
|
-
|
78
|
+
serialization_format=self._serializer.get_serialization_format(
|
79
|
+
entity_to_record
|
80
|
+
),
|
80
81
|
overwrite=True,
|
81
82
|
)
|
82
83
|
|
@@ -91,6 +92,8 @@ class TelemetryRecorder(NexusCoreObject):
|
|
91
92
|
)
|
92
93
|
for telemetry_key, telemetry_value in telemetry_args.items()
|
93
94
|
]
|
95
|
+
if not telemetry_tasks:
|
96
|
+
return
|
94
97
|
|
95
98
|
done, pending = await asyncio.wait(telemetry_tasks)
|
96
99
|
if len(pending) > 0:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[tool.poetry]
|
2
2
|
name = "esd-services-api-client"
|
3
|
-
version = "2.2.
|
3
|
+
version = "2.2.5"
|
4
4
|
description = "Python clients for ESD services"
|
5
5
|
authors = ["ECCO Sneaks & Data <esdsupport@ecco.com>"]
|
6
6
|
maintainers = ['GZU <gzu@ecco.com>', 'JRB <ext-jrb@ecco.com>', 'VISA <visa@ecco.com>']
|
@@ -1 +0,0 @@
|
|
1
|
-
__version__ = '2.2.3'
|
File without changes
|
File without changes
|
{esd_services_api_client-2.2.3 → esd_services_api_client-2.2.5}/esd_services_api_client/__init__.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
|
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
|