esd-services-api-client 2.2.2__tar.gz → 2.2.4__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.
Files changed (54) hide show
  1. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/PKG-INFO +1 -1
  2. esd_services_api_client-2.2.4/esd_services_api_client/_version.py +1 -0
  3. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/crystal/_connector.py +1 -0
  4. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/crystal/_models.py +1 -0
  5. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/nexus/core/app_core.py +9 -3
  6. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/nexus/core/app_dependencies.py +71 -1
  7. esd_services_api_client-2.2.4/esd_services_api_client/nexus/core/serializers.py +78 -0
  8. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/nexus/telemetry/recorder.py +8 -7
  9. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/pyproject.toml +1 -1
  10. esd_services_api_client-2.2.2/esd_services_api_client/_version.py +0 -1
  11. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/LICENSE +0 -0
  12. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/README.md +0 -0
  13. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/__init__.py +0 -0
  14. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/beast/__init__.py +0 -0
  15. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/beast/v3/__init__.py +0 -0
  16. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/beast/v3/_connector.py +0 -0
  17. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/beast/v3/_models.py +0 -0
  18. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/boxer/README.md +0 -0
  19. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/boxer/__init__.py +0 -0
  20. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/boxer/_auth.py +0 -0
  21. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/boxer/_base.py +0 -0
  22. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/boxer/_connector.py +0 -0
  23. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/boxer/_models.py +0 -0
  24. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/common/__init__.py +0 -0
  25. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/crystal/__init__.py +0 -0
  26. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/crystal/_api_versions.py +0 -0
  27. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/nexus/README.md +0 -0
  28. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/nexus/__init__.py +0 -0
  29. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/nexus/abstractions/__init__.py +0 -0
  30. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/nexus/abstractions/algrorithm_cache.py +0 -0
  31. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/nexus/abstractions/input_object.py +0 -0
  32. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/nexus/abstractions/logger_factory.py +0 -0
  33. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/nexus/abstractions/nexus_object.py +0 -0
  34. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/nexus/abstractions/socket_provider.py +0 -0
  35. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/nexus/algorithms/__init__.py +0 -0
  36. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/nexus/algorithms/_baseline_algorithm.py +0 -0
  37. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/nexus/algorithms/_remote_algorithm.py +0 -0
  38. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/nexus/algorithms/distributed.py +0 -0
  39. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/nexus/algorithms/forked_algorithm.py +0 -0
  40. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/nexus/algorithms/minimalistic.py +0 -0
  41. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/nexus/algorithms/recursive.py +0 -0
  42. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/nexus/configurations/__init__.py +0 -0
  43. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/nexus/configurations/algorithm_configuration.py +0 -0
  44. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/nexus/core/__init__.py +0 -0
  45. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/nexus/exceptions/__init__.py +0 -0
  46. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/nexus/exceptions/_nexus_error.py +0 -0
  47. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/nexus/exceptions/cache_errors.py +0 -0
  48. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/nexus/exceptions/input_reader_error.py +0 -0
  49. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/nexus/exceptions/startup_error.py +0 -0
  50. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/nexus/input/__init__.py +0 -0
  51. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/nexus/input/input_processor.py +0 -0
  52. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/nexus/input/input_reader.py +0 -0
  53. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/nexus/input/payload_reader.py +0 -0
  54. {esd_services_api_client-2.2.2 → esd_services_api_client-2.2.4}/esd_services_api_client/nexus/telemetry/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: esd-services-api-client
3
- Version: 2.2.2
3
+ Version: 2.2.4
4
4
  Summary: Python clients for ESD services
5
5
  Home-page: https://github.com/SneaksAndData/esd-services-api-client
6
6
  License: Apache 2.0
@@ -0,0 +1 @@
1
+ __version__ = '2.2.4'
@@ -125,6 +125,7 @@ class CrystalConnector:
125
125
  RequestLifeCycleStage.FAILED,
126
126
  RequestLifeCycleStage.SCHEDULING_TIMEOUT,
127
127
  RequestLifeCycleStage.DEADLINE_EXCEEDED,
128
+ RequestLifeCycleStage.CANCELLED,
128
129
  ]
129
130
 
130
131
  @classmethod
@@ -36,6 +36,7 @@ class RequestLifeCycleStage(Enum):
36
36
  SCHEDULING_TIMEOUT = "SCHEDULING_TIMEOUT"
37
37
  DEADLINE_EXCEEDED = "DEADLINE_EXCEEDED"
38
38
  THROTTLED = "THROTTLED"
39
+ CANCELLED = "CANCELLED"
39
40
 
40
41
 
41
42
  @dataclass_json(letter_case=LetterCase.CAMEL)
@@ -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=data.dataframe(),
217
+ data=dataframe_data,
214
218
  blob_path=blob_path,
215
- serialization_format=DataFrameJsonSerializationFormat,
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=DictJsonSerializationFormat
78
- if isinstance(entity_to_record, dict)
79
- else DataFrameParquetSerializationFormat,
78
+ serialization_format=self._serializer.get_serialization_format(
79
+ entity_to_record
80
+ ),
80
81
  overwrite=True,
81
82
  )
82
83
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "esd-services-api-client"
3
- version = "2.2.2"
3
+ version = "2.2.4"
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.2'