esd-services-api-client 2.5.13__tar.gz → 2.5.14a0.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.
Files changed (57) hide show
  1. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/PKG-INFO +3 -5
  2. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/__init__.py +1 -1
  3. esd_services_api_client-2.5.14a0.dev0/esd_services_api_client/_version.py +1 -0
  4. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/beast/v3/_connector.py +1 -0
  5. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/crystal/_connector.py +1 -0
  6. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/nexus/README.md +1 -1
  7. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/nexus/algorithms/_remote_algorithm.py +1 -0
  8. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/nexus/core/app_core.py +41 -23
  9. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/nexus/core/app_dependencies.py +8 -12
  10. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/nexus/input/payload_reader.py +10 -2
  11. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/nexus/telemetry/user_telemetry_recorder.py +1 -0
  12. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/pyproject.toml +3 -3
  13. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/LICENSE +0 -0
  14. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/README.md +0 -0
  15. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/beast/__init__.py +0 -0
  16. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/beast/v3/__init__.py +0 -0
  17. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/beast/v3/_models.py +0 -0
  18. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/boxer/README.md +0 -0
  19. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/boxer/__init__.py +0 -0
  20. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/boxer/_auth.py +0 -0
  21. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/boxer/_base.py +0 -0
  22. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/boxer/_connector.py +0 -0
  23. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/boxer/_models.py +0 -0
  24. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/common/__init__.py +0 -0
  25. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/crystal/__init__.py +0 -0
  26. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/crystal/_api_versions.py +0 -0
  27. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/crystal/_models.py +0 -0
  28. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/nexus/__init__.py +0 -0
  29. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/nexus/abstractions/__init__.py +0 -0
  30. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/nexus/abstractions/algrorithm_cache.py +0 -0
  31. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/nexus/abstractions/input_object.py +0 -0
  32. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/nexus/abstractions/logger_factory.py +0 -0
  33. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/nexus/abstractions/nexus_object.py +0 -0
  34. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/nexus/abstractions/socket_provider.py +0 -0
  35. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/nexus/algorithms/__init__.py +0 -0
  36. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/nexus/algorithms/_baseline_algorithm.py +0 -0
  37. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/nexus/algorithms/distributed.py +0 -0
  38. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/nexus/algorithms/forked_algorithm.py +0 -0
  39. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/nexus/algorithms/minimalistic.py +0 -0
  40. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/nexus/algorithms/recursive.py +0 -0
  41. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/nexus/configurations/__init__.py +0 -0
  42. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/nexus/configurations/algorithm_configuration.py +0 -0
  43. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/nexus/core/__init__.py +0 -0
  44. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/nexus/core/serializers.py +0 -0
  45. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/nexus/exceptions/__init__.py +0 -0
  46. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/nexus/exceptions/_nexus_error.py +0 -0
  47. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/nexus/exceptions/cache_errors.py +0 -0
  48. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/nexus/exceptions/input_reader_error.py +0 -0
  49. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/nexus/exceptions/startup_error.py +0 -0
  50. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/nexus/input/__init__.py +0 -0
  51. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/nexus/input/input_processor.py +0 -0
  52. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/nexus/input/input_reader.py +0 -0
  53. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/nexus/modules/__init__.py +0 -0
  54. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/nexus/modules/astra_client_module.py +0 -0
  55. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/nexus/modules/mlflow_module.py +0 -0
  56. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/nexus/telemetry/__init__.py +0 -0
  57. {esd_services_api_client-2.5.13 → esd_services_api_client-2.5.14a0.dev0}/esd_services_api_client/nexus/telemetry/recorder.py +0 -0
@@ -1,21 +1,19 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: esd-services-api-client
3
- Version: 2.5.13
3
+ Version: 2.5.14a0.dev0
4
4
  Summary: Python clients for ESD services
5
5
  License: Apache 2.0
6
6
  Author: ECCO Sneaks & Data
7
7
  Author-email: esdsupport@ecco.com
8
8
  Maintainer: GZU
9
9
  Maintainer-email: gzu@ecco.com
10
- Requires-Python: >=3.9,<3.12
10
+ Requires-Python: >=3.11,<3.12
11
11
  Classifier: License :: Other/Proprietary License
12
12
  Classifier: Programming Language :: Python :: 3
13
- Classifier: Programming Language :: Python :: 3.9
14
- Classifier: Programming Language :: Python :: 3.10
15
13
  Classifier: Programming Language :: Python :: 3.11
16
14
  Provides-Extra: azure
17
15
  Provides-Extra: nexus
18
- Requires-Dist: adapta[azure,datadog,storage] (>=3.2,<4.0)
16
+ Requires-Dist: adapta[azure,datadog,storage] (>=3.3,<4.0)
19
17
  Requires-Dist: azure-identity (>=1.7,<1.8) ; extra == "azure"
20
18
  Requires-Dist: dataclasses-json (>=0.6.0,<0.7.0)
21
19
  Requires-Dist: httpx (>=0.27.0,<0.28.0) ; extra == "nexus"
@@ -17,4 +17,4 @@
17
17
  Root index.
18
18
  """
19
19
 
20
- __version__ = "2.5.13"
20
+ __version__ = "0.0.0"
@@ -0,0 +1 @@
1
+ __version__ = 'v2.5.14a.dev'
@@ -220,6 +220,7 @@ class BeastConnector:
220
220
  f"Execution failed, please find request's log at: {self.base_url}/job/logs/{request_id}"
221
221
  )
222
222
 
223
+ # pylint: disable=too-many-positional-arguments
223
224
  @staticmethod
224
225
  def _report_backoff_failure(
225
226
  target: Any, args: Any, kwargs: Any, tries: int, elapsed: int, wait: int, **_
@@ -151,6 +151,7 @@ class CrystalConnector:
151
151
  def __exit__(self, exc_type, exc_val, exc_tb):
152
152
  self.dispose()
153
153
 
154
+ # pylint: disable=too-many-positional-arguments
154
155
  def create_run(
155
156
  self,
156
157
  algorithm: str,
@@ -297,7 +297,7 @@ async def main():
297
297
  server_thread.daemon = True
298
298
  server_thread.start()
299
299
  nexus = (
300
- await Nexus.create()
300
+ Nexus.create()
301
301
  .add_reader(XReader)
302
302
  .add_reader(YReader)
303
303
  .use_processor(XProcessor)
@@ -44,6 +44,7 @@ class RemoteAlgorithm(NexusObject[TPayload, AlgorithmResult]):
44
44
  Base class for all algorithm implementations.
45
45
  """
46
46
 
47
+ # pylint: disable=too-many-positional-arguments
47
48
  @inject
48
49
  def __init__(
49
50
  self,
@@ -27,12 +27,11 @@ from typing import final, Type, Optional
27
27
 
28
28
  import backoff
29
29
  import urllib3.exceptions
30
- import azure.core.exceptions
31
30
  from adapta.logs import LoggerInterface
32
31
  from adapta.process_communication import DataSocket
33
32
  from adapta.storage.blob.base import StorageClient
34
33
  from adapta.storage.query_enabled_store import QueryEnabledStore
35
- from injector import Injector, Module
34
+ from injector import Injector, Module, singleton
36
35
 
37
36
  import esd_services_api_client.nexus.exceptions
38
37
  from esd_services_api_client.crystal import (
@@ -119,6 +118,7 @@ class Nexus:
119
118
  self._run_args = args
120
119
  self._algorithm_run_task: Optional[asyncio.Task] = None
121
120
  self._on_complete_tasks: list[type[UserTelemetryRecorder]] = []
121
+ self._payload_types: list[type[AlgorithmPayload]] = []
122
122
 
123
123
  attach_signal_handlers()
124
124
 
@@ -157,22 +157,11 @@ class Nexus:
157
157
  self._algorithm_class = algorithm
158
158
  return self
159
159
 
160
- async def inject_payload(self, *payload_types: Type[AlgorithmPayload]) -> "Nexus":
160
+ def inject_payload(self, *payload_types: Type[AlgorithmPayload]) -> "Nexus":
161
161
  """
162
- Adds payloads processed into the specified types to the DI container
162
+ Adds payload types to inject to the DI container. Payloads will be deserialized at runtime.
163
163
  """
164
- for payload_type in payload_types:
165
-
166
- async def get_payload() -> payload_type: # pylint: disable=W0640
167
- async with AlgorithmPayloadReader(
168
- payload_uri=self._run_args.sas_uri,
169
- payload_type=payload_type, # pylint: disable=W0640
170
- ) as reader:
171
- return reader.payload
172
-
173
- # pylint warnings are silenced here because closure is called inside the same loop it is defined, thus each value of a loop variable is used
174
-
175
- self._configurator = self._configurator.with_payload((await get_payload()))
164
+ self._payload_types = payload_types
176
165
  return self
177
166
 
178
167
  def inject_configuration(
@@ -202,10 +191,7 @@ class Nexus:
202
191
  ) -> None:
203
192
  @backoff.on_exception(
204
193
  wait_gen=backoff.expo,
205
- exception=(
206
- azure.core.exceptions.HttpResponseError,
207
- urllib3.exceptions.HTTPError,
208
- ),
194
+ exception=(urllib3.exceptions.HTTPError,),
209
195
  max_time=10,
210
196
  raise_on_giveup=True,
211
197
  )
@@ -258,6 +244,15 @@ class Nexus:
258
244
  case _:
259
245
  sys.exit(1)
260
246
 
247
+ async def _get_payload(
248
+ self, payload_type: type[AlgorithmPayload]
249
+ ) -> AlgorithmPayload:
250
+ async with AlgorithmPayloadReader(
251
+ payload_uri=self._run_args.sas_uri,
252
+ payload_type=payload_type,
253
+ ) as reader:
254
+ return reader.payload
255
+
261
256
  async def activate(self):
262
257
  """
263
258
  Activates the run sequence.
@@ -265,14 +260,25 @@ class Nexus:
265
260
 
266
261
  self._injector = Injector(self._configurator.injection_binds)
267
262
 
268
- algorithm: BaselineAlgorithm = self._injector.get(self._algorithm_class)
269
- telemetry_recorder: TelemetryRecorder = self._injector.get(TelemetryRecorder)
270
263
  root_logger: LoggerInterface = self._injector.get(LoggerFactory).create_logger(
271
264
  logger_type=self.__class__,
272
265
  )
273
266
 
274
267
  root_logger.start()
275
268
 
269
+ for payload_type in self._payload_types:
270
+ try:
271
+ payload = await self._get_payload(payload_type=payload_type)
272
+ self._injector.binder.bind(
273
+ payload.__class__, to=payload, scope=singleton
274
+ )
275
+ except BaseException as ex: # pylint: disable=broad-except
276
+ root_logger.error("Error reading algorithm payload", ex)
277
+ sys.exit(1)
278
+
279
+ algorithm: BaselineAlgorithm = self._injector.get(self._algorithm_class)
280
+ telemetry_recorder: TelemetryRecorder = self._injector.get(TelemetryRecorder)
281
+
276
282
  root_logger.info(
277
283
  "Running algorithm {algorithm} on Nexus version {version}",
278
284
  algorithm=algorithm.__class__.__name__,
@@ -283,9 +289,21 @@ class Nexus:
283
289
  self._algorithm_run_task = asyncio.create_task(
284
290
  instance.run(**self._run_args.__dict__)
285
291
  )
286
- await self._algorithm_run_task
292
+
293
+ # avoid exception propagation to main thread, since we need to handle it later
294
+ await asyncio.wait(
295
+ [self._algorithm_run_task], return_when=asyncio.FIRST_EXCEPTION
296
+ )
287
297
  ex = self._algorithm_run_task.exception()
288
298
 
299
+ if ex is not None:
300
+ root_logger.error(
301
+ "Algorithm {algorithm} run failed on Nexus version {version}",
302
+ ex,
303
+ algorithm=self._algorithm_class,
304
+ version=__version__,
305
+ )
306
+
289
307
  await self._submit_result(
290
308
  self._algorithm_run_task.result() if not ex else None,
291
309
  self._algorithm_run_task.exception(),
@@ -42,9 +42,6 @@ from esd_services_api_client.nexus.exceptions.startup_error import (
42
42
  )
43
43
  from esd_services_api_client.nexus.input.input_processor import InputProcessor
44
44
  from esd_services_api_client.nexus.input.input_reader import InputReader
45
- from esd_services_api_client.nexus.input.payload_reader import (
46
- AlgorithmPayload,
47
- )
48
45
  from esd_services_api_client.nexus.telemetry.recorder import TelemetryRecorder
49
46
  from esd_services_api_client.nexus.core.serializers import (
50
47
  TelemetrySerializer,
@@ -247,6 +244,7 @@ class ServiceConfigurator:
247
244
  CacheModule(),
248
245
  type(f"{TelemetryRecorder.__name__}Module", (Module,), {})(),
249
246
  ]
247
+ self._runtime_injection_binds = []
250
248
 
251
249
  @property
252
250
  def injection_binds(self) -> list:
@@ -255,6 +253,13 @@ class ServiceConfigurator:
255
253
  """
256
254
  return self._injection_binds
257
255
 
256
+ @property
257
+ def runtime_injection_binds(self) -> list:
258
+ """
259
+ Currently configured injection bindings that are added at runtime
260
+ """
261
+ return self._runtime_injection_binds
262
+
258
263
  def with_module(self, module: Type[Module]) -> "ServiceConfigurator":
259
264
  """
260
265
  Adds a (custom) module into the DI container.
@@ -280,15 +285,6 @@ class ServiceConfigurator:
280
285
  )
281
286
  return self
282
287
 
283
- def with_payload(self, payload: AlgorithmPayload) -> "ServiceConfigurator":
284
- """
285
- Adds the specified payload instance to the DI container.
286
- """
287
- self._injection_binds.append(
288
- lambda binder: binder.bind(payload.__class__, to=payload, scope=singleton)
289
- )
290
- return self
291
-
292
288
  def with_configuration(self, config: NexusConfiguration) -> "ServiceConfigurator":
293
289
  """
294
290
  Adds the specified payload instance to the DI container.
@@ -1,6 +1,7 @@
1
1
  """
2
2
  Code infrastructure for manipulating payload received from Crystal SAS URI
3
3
  """
4
+ import os
4
5
 
5
6
  # Copyright (c) 2023-2024. ECCO Sneaks & Data
6
7
  #
@@ -62,8 +63,15 @@ class AlgorithmPayloadReader:
62
63
  self._http.close()
63
64
  self._http = None
64
65
 
65
- def __init__(self, payload_uri: str, payload_type: Type[AlgorithmPayload]):
66
- self._http = session_with_retries()
66
+ def __init__(
67
+ self,
68
+ payload_uri: str,
69
+ payload_type: Type[AlgorithmPayload],
70
+ ):
71
+ self._http = session_with_retries(
72
+ file_protocol_supported=os.getenv("NEXUS__SUPPORT_FILE_PROTOCOL_PAYLOADS")
73
+ is not None
74
+ )
67
75
  self._payload: Optional[AlgorithmPayload] = None
68
76
  self._payload_uri = payload_uri
69
77
  self._payload_type = payload_type
@@ -70,6 +70,7 @@ class UserTelemetryRecorder(Generic[TPayload, TResult], ABC):
70
70
  Base class for user-defined telemetry recorders.
71
71
  """
72
72
 
73
+ # pylint: disable=too-many-positional-arguments
73
74
  @inject
74
75
  def __init__(
75
76
  self,
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "esd-services-api-client"
3
- version = "2.5.13"
3
+ version = "v2.5.14a.dev"
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>']
@@ -9,8 +9,8 @@ license = 'Apache 2.0'
9
9
  repository = 'https://github.com/SneaksAndData/esd-services-api-client'
10
10
 
11
11
  [tool.poetry.dependencies]
12
- python = ">=3.9,<3.12"
13
- adapta = { version = "^3.2", extras = ["azure", "storage", "datadog"] }
12
+ python = ">=3.11,<3.12"
13
+ adapta = { version = "^3.3", extras = ["azure", "storage", "datadog"] }
14
14
  dataclasses-json = "^0.6.0"
15
15
  pycryptodome = "~3.15"
16
16
  azure-identity = { version = "~1.7", optional = true }