esd-services-api-client 2.0.4__py3-none-any.whl → 2.0.5__py3-none-any.whl

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.
@@ -1 +1 @@
1
- __version__ = '2.0.4'
1
+ __version__ = '2.0.5'
@@ -15,9 +15,9 @@ Example usage:
15
15
  ```python
16
16
  import asyncio
17
17
  import json
18
+ import os
18
19
  import socketserver
19
20
  import threading
20
- import os
21
21
  from dataclasses import dataclass
22
22
  from http.server import ThreadingHTTPServer, BaseHTTPRequestHandler
23
23
  from typing import Dict, Optional
@@ -32,10 +32,12 @@ from esd_services_api_client.nexus.abstractions.logger_factory import LoggerFact
32
32
  from esd_services_api_client.nexus.abstractions.socket_provider import (
33
33
  ExternalSocketProvider,
34
34
  )
35
+ from esd_services_api_client.nexus.configurations.algorithm_configuration import (
36
+ NexusConfiguration,
37
+ )
35
38
  from esd_services_api_client.nexus.core.app_core import Nexus
36
39
  from esd_services_api_client.nexus.algorithms import MinimalisticAlgorithm
37
40
  from esd_services_api_client.nexus.input import InputReader, InputProcessor
38
- from esd_services_api_client.nexus.configurations.algorithm_configuration import NexusConfiguration
39
41
  from pandas import DataFrame as PandasDataFrame
40
42
 
41
43
  from esd_services_api_client.nexus.input.payload_reader import AlgorithmPayload
@@ -142,11 +144,11 @@ class XReader(InputReader[MyAlgorithmPayload]):
142
144
  *readers: "InputReader"
143
145
  ):
144
146
  super().__init__(
145
- socket_provider.socket("x"),
146
- store,
147
- metrics_provider,
148
- logger_factory,
149
- payload,
147
+ socket=socket_provider.socket("x"),
148
+ store=store,
149
+ metrics_provider=metrics_provider,
150
+ logger_factory=logger_factory,
151
+ payload=payload,
150
152
  *readers
151
153
  )
152
154
 
@@ -177,11 +179,11 @@ class YReader(InputReader[MyAlgorithmPayload2]):
177
179
  *readers: "InputReader"
178
180
  ):
179
181
  super().__init__(
180
- socket_provider.socket("y"),
181
- store,
182
- metrics_provider,
183
- logger_factory,
184
- payload,
182
+ socket=socket_provider.socket("y"),
183
+ store=store,
184
+ metrics_provider=metrics_provider,
185
+ logger_factory=logger_factory,
186
+ payload=payload,
185
187
  *readers
186
188
  )
187
189
 
@@ -208,6 +210,7 @@ class MyInputProcessor(InputProcessor):
208
210
  y: YReader,
209
211
  metrics_provider: MetricsProvider,
210
212
  logger_factory: LoggerFactory,
213
+ my_conf: MyAlgorithmConfiguration,
211
214
  ):
212
215
  super().__init__(
213
216
  x,
@@ -217,7 +220,10 @@ class MyInputProcessor(InputProcessor):
217
220
  payload=None,
218
221
  )
219
222
 
223
+ self.conf = my_conf
224
+
220
225
  async def process_input(self, **_) -> Dict[str, PandasDataFrame]:
226
+ self._logger.info("Config: {config}", config=self.conf.to_json())
221
227
  inputs = await self._read_input()
222
228
  return {
223
229
  "x_ready": inputs["x"].assign(c=[-1, 1]),
@@ -20,3 +20,4 @@
20
20
 
21
21
  from esd_services_api_client.nexus.input.input_processor import *
22
22
  from esd_services_api_client.nexus.input.input_reader import *
23
+ from esd_services_api_client.nexus.input._functions import *
@@ -0,0 +1,69 @@
1
+ """
2
+ Utility functions to handle input processing.
3
+ """
4
+
5
+ # Copyright (c) 2023. ECCO Sneaks & Data
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ import asyncio
21
+ from typing import Dict, Union, Type
22
+ import azure.core.exceptions
23
+ import deltalake
24
+ from pandas import DataFrame as PandasDataFrame
25
+
26
+ from esd_services_api_client.nexus.exceptions.input_reader_error import (
27
+ FatalInputReaderError,
28
+ TransientInputReaderError,
29
+ )
30
+ from esd_services_api_client.nexus.input.input_reader import InputReader
31
+
32
+
33
+ def resolve_reader_exc_type(
34
+ ex: BaseException,
35
+ ) -> Union[Type[FatalInputReaderError], Type[TransientInputReaderError]]:
36
+ """
37
+ Resolve base exception into a specific Nexus exception.
38
+ """
39
+ match type(ex):
40
+ case azure.core.exceptions.HttpResponseError, deltalake.PyDeltaTableError:
41
+ return TransientInputReaderError
42
+ case azure.core.exceptions.AzureError, azure.core.exceptions.ClientAuthenticationError:
43
+ return FatalInputReaderError
44
+ case _:
45
+ return FatalInputReaderError
46
+
47
+
48
+ async def resolve_readers(*readers: InputReader) -> Dict[str, PandasDataFrame]:
49
+ """
50
+ Concurrently resolve `data` property of all readers by invoking their `read` method.
51
+ """
52
+
53
+ def get_result(alias: str, completed_task: asyncio.Task) -> PandasDataFrame:
54
+ reader_exc = completed_task.exception()
55
+ if reader_exc:
56
+ raise resolve_reader_exc_type(reader_exc)(alias, reader_exc)
57
+
58
+ return completed_task.result()
59
+
60
+ async def _read(input_reader: InputReader):
61
+ async with input_reader as instance:
62
+ return await instance.read()
63
+
64
+ read_tasks: dict[str, asyncio.Task] = {
65
+ reader.socket.alias: asyncio.create_task(_read(reader)) for reader in readers
66
+ }
67
+ await asyncio.wait(fs=read_tasks.values())
68
+
69
+ return {alias: get_result(alias, task) for alias, task in read_tasks.items()}
@@ -17,15 +17,11 @@
17
17
  # limitations under the License.
18
18
  #
19
19
 
20
- import asyncio
21
20
  from abc import abstractmethod
22
- from typing import Dict, Union, Type
21
+ from typing import Dict
23
22
 
24
- import deltalake
25
23
  from adapta.metrics import MetricsProvider
26
24
 
27
- import azure.core.exceptions
28
-
29
25
  from pandas import DataFrame as PandasDataFrame
30
26
 
31
27
  from esd_services_api_client.nexus.abstractions.nexus_object import (
@@ -33,10 +29,7 @@ from esd_services_api_client.nexus.abstractions.nexus_object import (
33
29
  TPayload,
34
30
  )
35
31
  from esd_services_api_client.nexus.abstractions.logger_factory import LoggerFactory
36
- from esd_services_api_client.nexus.exceptions.input_reader_error import (
37
- FatalInputReaderError,
38
- TransientInputReaderError,
39
- )
32
+ from esd_services_api_client.nexus.input._functions import resolve_readers
40
33
  from esd_services_api_client.nexus.input.input_reader import InputReader
41
34
 
42
35
 
@@ -56,36 +49,8 @@ class InputProcessor(NexusObject[TPayload]):
56
49
  self._readers = readers
57
50
  self._payload = payload
58
51
 
59
- def _get_exc_type(
60
- self, ex: BaseException
61
- ) -> Union[Type[FatalInputReaderError], Type[TransientInputReaderError]]:
62
- match type(ex):
63
- case azure.core.exceptions.HttpResponseError, deltalake.PyDeltaTableError:
64
- return TransientInputReaderError
65
- case azure.core.exceptions.AzureError, azure.core.exceptions.ClientAuthenticationError:
66
- return FatalInputReaderError
67
- case _:
68
- return FatalInputReaderError
69
-
70
52
  async def _read_input(self) -> Dict[str, PandasDataFrame]:
71
- def get_result(alias: str, completed_task: asyncio.Task) -> PandasDataFrame:
72
- reader_exc = completed_task.exception()
73
- if reader_exc:
74
- raise self._get_exc_type(reader_exc)(alias, reader_exc)
75
-
76
- return completed_task.result()
77
-
78
- async def _read(input_reader: InputReader):
79
- async with input_reader as instance:
80
- return await instance.read()
81
-
82
- read_tasks: dict[str, asyncio.Task] = {
83
- reader.socket.alias: asyncio.create_task(_read(reader))
84
- for reader in self._readers
85
- }
86
- await asyncio.wait(fs=read_tasks.values())
87
-
88
- return {alias: get_result(alias, task) for alias, task in read_tasks.items()}
53
+ return await resolve_readers(*self._readers)
89
54
 
90
55
  @abstractmethod
91
56
  async def process_input(self, **kwargs) -> Dict[str, PandasDataFrame]:
@@ -1,6 +1,7 @@
1
1
  """
2
2
  Input reader.
3
3
  """
4
+ import functools
4
5
 
5
6
  # Copyright (c) 2023. ECCO Sneaks & Data
6
7
  #
@@ -43,12 +44,12 @@ class InputReader(NexusObject[TPayload]):
43
44
 
44
45
  def __init__(
45
46
  self,
46
- socket: DataSocket,
47
47
  store: QueryEnabledStore,
48
48
  metrics_provider: MetricsProvider,
49
49
  logger_factory: LoggerFactory,
50
50
  payload: TPayload,
51
- *readers: "InputReader"
51
+ *readers: "InputReader",
52
+ socket: Optional[DataSocket] = None,
52
53
  ):
53
54
  super().__init__(metrics_provider, logger_factory)
54
55
  self.socket = socket
@@ -58,6 +59,16 @@ class InputReader(NexusObject[TPayload]):
58
59
  self._payload = payload
59
60
 
60
61
  @property
62
+ def alias(self) -> str:
63
+ """
64
+ Alias to identify this reader's output
65
+ """
66
+ if self.socket:
67
+ return self.socket.alias
68
+
69
+ return self._metric_name
70
+
71
+ @functools.cached_property
61
72
  def data(self) -> Optional[PandasDataFrame]:
62
73
  """
63
74
  Data read by this reader.
@@ -92,8 +103,10 @@ class InputReader(NexusObject[TPayload]):
92
103
  on_finish_message_template="Finished reading {entity} from path {data_path} in {elapsed:.2f}s seconds",
93
104
  template_args={
94
105
  "entity": self._metric_name.upper(),
95
- "data_path": self.socket.data_path,
96
- },
106
+ }
107
+ | {"data_path": self.socket.data_path}
108
+ if self.socket
109
+ else {},
97
110
  )
98
111
  async def _read(**_) -> PandasDataFrame:
99
112
  if not self._data:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: esd-services-api-client
3
- Version: 2.0.4
3
+ Version: 2.0.5
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
@@ -1,5 +1,5 @@
1
1
  esd_services_api_client/__init__.py,sha256=rP0njtEgVSMm-sOVayVfcRUrrubl4lme7HI2zS678Lo,598
2
- esd_services_api_client/_version.py,sha256=YuAuFLBrpl-SUl_UsvW1U1NTjqnldfuD1xUmSLmtaRw,22
2
+ esd_services_api_client/_version.py,sha256=dVcGCZ5wUWMpOJgTrQrOvt6L6HdIhykCRMVFZFr-q20,22
3
3
  esd_services_api_client/beast/__init__.py,sha256=NTaz_7YoLPK8MCLwbwqH7rW1zDWLxXu2T7fGmMmRxyg,718
4
4
  esd_services_api_client/beast/v3/__init__.py,sha256=TRjB4-T6eIORpMvdylb32_GinrIpYNFmAdshSC1HqHg,749
5
5
  esd_services_api_client/beast/v3/_connector.py,sha256=oPizDQ1KOKOfiyh-jAofKodlpRzrRiELv-rmP_o_oio,11473
@@ -15,7 +15,7 @@ esd_services_api_client/crystal/__init__.py,sha256=afSGQRkDic0ECsJfgu3b291kX8CyU
15
15
  esd_services_api_client/crystal/_api_versions.py,sha256=2BMiQRS0D8IEpWCCys3dge5alVBRCZrOuCR1QAn8UIM,832
16
16
  esd_services_api_client/crystal/_connector.py,sha256=WjfMezWXia41Z8aiNupaT577fk9Sx6uy6V23O6y9hfI,12870
17
17
  esd_services_api_client/crystal/_models.py,sha256=eRhGAl8LjglCyIFwf1bcFBhjbpSuRYucuF2LO388L2E,4025
18
- esd_services_api_client/nexus/README.md,sha256=73TcvRlAoMUrxE4rnARZmlwS7AwlW9fDV0Tj-MPwC00,8141
18
+ esd_services_api_client/nexus/README.md,sha256=jnCK4CWsQBNDhxQ-5xzJp4NNrpC93ifr7aYLPW5rp3Q,8402
19
19
  esd_services_api_client/nexus/__init__.py,sha256=e7RPs-qJNQqDHj121TeYx-_YadZSOIyJuAPyhSSXRsE,622
20
20
  esd_services_api_client/nexus/abstractions/__init__.py,sha256=e7RPs-qJNQqDHj121TeYx-_YadZSOIyJuAPyhSSXRsE,622
21
21
  esd_services_api_client/nexus/abstractions/logger_factory.py,sha256=JHl_t0d0ra_k-EixZlkw-s746wHUdBhSU6preqoARtk,2031
@@ -35,11 +35,12 @@ esd_services_api_client/nexus/exceptions/__init__.py,sha256=JgPXhrvBIi0U1QOF90TY
35
35
  esd_services_api_client/nexus/exceptions/_nexus_error.py,sha256=b3L8JnNvV2jdxNfuFWh9-j4kVb_VX7gNH5WHKcC-R78,890
36
36
  esd_services_api_client/nexus/exceptions/input_reader_error.py,sha256=D-xYTKRNREQ2-NGhc88GHOmXCvLNsIVQsH8wf0LLC_0,1760
37
37
  esd_services_api_client/nexus/exceptions/startup_error.py,sha256=f2PIOSdLgT-42eKD6ec8p7nROADshMawCsDGDUbxO_w,1546
38
- esd_services_api_client/nexus/input/__init__.py,sha256=0k_HMIP4NPC5O2ixKJPgKsLzYeHS14DhibF_MUtez1c,753
39
- esd_services_api_client/nexus/input/input_processor.py,sha256=MiXXd_APrG85Pi-Ke68_UHNEV7T_QHN1hU1WAPWoTsw,3187
40
- esd_services_api_client/nexus/input/input_reader.py,sha256=uxTAGX5xNhjTFpEsVQnr8BkVgpIH_U_om54hh3pvJ3s,3269
38
+ esd_services_api_client/nexus/input/__init__.py,sha256=DEdzkK43xjNl3XPQy3Q8xHGzXYsMwxCMs1QdEAsS4FI,814
39
+ esd_services_api_client/nexus/input/_functions.py,sha256=Na1T5KTExtQTOQohEG-CbnJJ95FVkdZy0wfoPcbvq50,2410
40
+ esd_services_api_client/nexus/input/input_processor.py,sha256=5uJSZIB0epLIVf_Z0IEVAfIo0yvEQ_ioILRlz_s9-X0,1870
41
+ esd_services_api_client/nexus/input/input_reader.py,sha256=-vh_5tcj-aT96ArLGFpKbeezD-zlmyr877INyMdxjPo,3576
41
42
  esd_services_api_client/nexus/input/payload_reader.py,sha256=__r_QjIFRAWwx56X5WUK1qensJUae0vZEb422dzOgSY,2511
42
- esd_services_api_client-2.0.4.dist-info/LICENSE,sha256=0gS6zXsPp8qZhzi1xaGCIYPzb_0e8on7HCeFJe8fOpw,10693
43
- esd_services_api_client-2.0.4.dist-info/METADATA,sha256=CGlXTMSDUh5Fvzm0E4-r8b9FA9SuQ5gm5xUX7ulxhIg,1236
44
- esd_services_api_client-2.0.4.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
45
- esd_services_api_client-2.0.4.dist-info/RECORD,,
43
+ esd_services_api_client-2.0.5.dist-info/LICENSE,sha256=0gS6zXsPp8qZhzi1xaGCIYPzb_0e8on7HCeFJe8fOpw,10693
44
+ esd_services_api_client-2.0.5.dist-info/METADATA,sha256=TKu9S0uioyrpqQdNNhNprEcY7ey97K_BZsNGFrRLFKY,1236
45
+ esd_services_api_client-2.0.5.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
46
+ esd_services_api_client-2.0.5.dist-info/RECORD,,