esd-services-api-client 2.6.2a150.dev14__tar.gz → 2.6.2a155.dev2__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 (59) hide show
  1. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/PKG-INFO +1 -1
  2. esd_services_api_client-2.6.2a155.dev2/esd_services_api_client/_version.py +1 -0
  3. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/beast/v3/_connector.py +0 -1
  4. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/crystal/_connector.py +0 -1
  5. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/nexus/README.md +5 -0
  6. esd_services_api_client-2.6.2a155.dev2/esd_services_api_client/nexus/abstractions/metrics_provider_factory.py +70 -0
  7. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/nexus/algorithms/_remote_algorithm.py +0 -1
  8. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/nexus/core/app_core.py +77 -21
  9. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/nexus/core/app_dependencies.py +0 -25
  10. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/nexus/input/payload_reader.py +2 -10
  11. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/nexus/telemetry/user_telemetry_recorder.py +0 -1
  12. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/pyproject.toml +1 -1
  13. esd_services_api_client-2.6.2a150.dev14/esd_services_api_client/_version.py +0 -1
  14. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/LICENSE +0 -0
  15. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/README.md +0 -0
  16. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/__init__.py +0 -0
  17. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/beast/__init__.py +0 -0
  18. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/beast/v3/__init__.py +0 -0
  19. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/beast/v3/_models.py +0 -0
  20. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/boxer/README.md +0 -0
  21. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/boxer/__init__.py +0 -0
  22. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/boxer/_auth.py +0 -0
  23. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/boxer/_base.py +0 -0
  24. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/boxer/_connector.py +0 -0
  25. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/boxer/_models.py +0 -0
  26. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/common/__init__.py +0 -0
  27. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/crystal/__init__.py +0 -0
  28. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/crystal/_api_versions.py +0 -0
  29. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/crystal/_models.py +0 -0
  30. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/nexus/__init__.py +0 -0
  31. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/nexus/abstractions/__init__.py +0 -0
  32. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/nexus/abstractions/algrorithm_cache.py +0 -0
  33. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/nexus/abstractions/input_object.py +0 -0
  34. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/nexus/abstractions/logger_factory.py +0 -0
  35. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/nexus/abstractions/nexus_object.py +0 -0
  36. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/nexus/abstractions/socket_provider.py +0 -0
  37. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/nexus/algorithms/__init__.py +0 -0
  38. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/nexus/algorithms/_baseline_algorithm.py +0 -0
  39. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/nexus/algorithms/distributed.py +0 -0
  40. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/nexus/algorithms/forked_algorithm.py +0 -0
  41. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/nexus/algorithms/minimalistic.py +0 -0
  42. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/nexus/algorithms/recursive.py +0 -0
  43. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/nexus/configurations/__init__.py +0 -0
  44. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/nexus/configurations/algorithm_configuration.py +0 -0
  45. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/nexus/core/__init__.py +0 -0
  46. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/nexus/core/serializers.py +0 -0
  47. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/nexus/exceptions/__init__.py +0 -0
  48. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/nexus/exceptions/_nexus_error.py +0 -0
  49. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/nexus/exceptions/cache_errors.py +0 -0
  50. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/nexus/exceptions/input_reader_error.py +0 -0
  51. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/nexus/exceptions/startup_error.py +0 -0
  52. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/nexus/input/__init__.py +0 -0
  53. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/nexus/input/input_processor.py +0 -0
  54. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/nexus/input/input_reader.py +0 -0
  55. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/nexus/modules/__init__.py +0 -0
  56. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/nexus/modules/astra_client_module.py +0 -0
  57. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/nexus/modules/mlflow_module.py +0 -0
  58. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/nexus/telemetry/__init__.py +0 -0
  59. {esd_services_api_client-2.6.2a150.dev14 → esd_services_api_client-2.6.2a155.dev2}/esd_services_api_client/nexus/telemetry/recorder.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: esd-services-api-client
3
- Version: 2.6.2a150.dev14
3
+ Version: 2.6.2a155.dev2
4
4
  Summary: Python clients for ESD services
5
5
  License: Apache 2.0
6
6
  Author: ECCO Sneaks & Data
@@ -0,0 +1 @@
1
+ __version__ = 'v2.6.2a155.dev2'
@@ -220,7 +220,6 @@ 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
224
223
  @staticmethod
225
224
  def _report_backoff_failure(
226
225
  target: Any, args: Any, kwargs: Any, tries: int, elapsed: int, wait: int, **_
@@ -151,7 +151,6 @@ 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
155
154
  def create_run(
156
155
  self,
157
156
  algorithm: str,
@@ -302,6 +302,10 @@ async def main():
302
302
  "(value of y:{y})": {"y": payload.y},
303
303
  "(request_id:{request_id})": {"request_id": run_args.request_id}
304
304
  }
305
+ def tag_metrics(payload: MyAlgorithmPayload2, run_args: CrystalEntrypointArguments) -> dict[str, str]:
306
+ return {
307
+ "country": payload.y,
308
+ }
305
309
  with ThreadingHTTPServer(("localhost", 9876), MockRequestHandler) as server:
306
310
  server_thread = threading.Thread(target=server.serve_forever)
307
311
  server_thread.daemon = True
@@ -317,6 +321,7 @@ async def main():
317
321
  .inject_configuration(MyAlgorithmConfiguration)
318
322
  .inject_payload(MyAlgorithmPayload, MyAlgorithmPayload2)
319
323
  .with_log_enricher(tags_from_payload, enrich_from_payload)
324
+ .with_metric_tagger(tag_metrics)
320
325
  )
321
326
 
322
327
  await nexus.activate()
@@ -0,0 +1,70 @@
1
+ """
2
+ Metrics provider factory.
3
+ """
4
+
5
+ # Copyright (c) 2023-2024. 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 json
21
+ import os
22
+ from pydoc import locate
23
+ from typing import final
24
+
25
+ from adapta.metrics import MetricsProvider
26
+ from adapta.metrics.providers.datadog_provider import DatadogMetricsProvider
27
+
28
+
29
+ @final
30
+ class MetricsProviderFactory:
31
+ """
32
+ Async logger provisioner.
33
+ """
34
+
35
+ def __init__(
36
+ self,
37
+ global_tags: dict[str, str] | None = None,
38
+ ):
39
+ self._global_tags = global_tags
40
+ self._metrics_class: type[MetricsProvider] = locate(
41
+ os.getenv(
42
+ "NEXUS__METRICS_PROVIDER_CLASS",
43
+ "adapta.metrics.providers.datadog_provider.DatadogMetricsProvider",
44
+ )
45
+ )
46
+ self._metrics_settings: dict = json.loads(
47
+ os.getenv("NEXUS__METRICS_PROVIDER_CONFIGURATION")
48
+ )
49
+
50
+ def create_provider(
51
+ self,
52
+ ) -> MetricsProvider:
53
+ """
54
+ Creates a metrics provider enriched with additional tags for each metric emitted by this algorithm.
55
+ In case of DatadogMetricsProvider, takes care of UDP/UDS specific initialization.
56
+ """
57
+ self._metrics_settings["fixed_tags"] = (
58
+ self._metrics_settings.get("fixed_tags", {}) | self._global_tags
59
+ )
60
+
61
+ if type(self._metrics_class) is DatadogMetricsProvider:
62
+ assert isinstance(self._metrics_class, DatadogMetricsProvider)
63
+
64
+ if self._metrics_settings["protocol"] == "udp":
65
+ return self._metrics_class.udp(**self._metrics_settings)
66
+
67
+ if self._metrics_settings["protocol"] == "uds":
68
+ return self._metrics_class.uds(**self._metrics_settings)
69
+
70
+ return self._metrics_class(**self._metrics_settings)
@@ -44,7 +44,6 @@ class RemoteAlgorithm(NexusObject[TPayload, AlgorithmResult]):
44
44
  Base class for all algorithm implementations.
45
45
  """
46
46
 
47
- # pylint: disable=too-many-positional-arguments
48
47
  @inject
49
48
  def __init__(
50
49
  self,
@@ -45,6 +45,9 @@ from esd_services_api_client.nexus.abstractions.logger_factory import (
45
45
  LoggerFactory,
46
46
  BootstrapLoggerFactory,
47
47
  )
48
+ from esd_services_api_client.nexus.abstractions.metrics_provider_factory import (
49
+ MetricsProviderFactory,
50
+ )
48
51
  from esd_services_api_client.nexus.abstractions.nexus_object import AlgorithmResult
49
52
  from esd_services_api_client.nexus.algorithms import (
50
53
  BaselineAlgorithm,
@@ -138,6 +141,14 @@ class Nexus:
138
141
  ] | None = None
139
142
  self._log_enrichment_delimiter: str = ", "
140
143
 
144
+ self._metric_tagger: Callable[
145
+ [
146
+ AlgorithmPayload,
147
+ CrystalEntrypointArguments,
148
+ ],
149
+ dict[str, str],
150
+ ] | None = None
151
+
141
152
  attach_signal_handlers()
142
153
 
143
154
  @property
@@ -225,6 +236,23 @@ class Nexus:
225
236
  self._log_enrichment_delimiter = delimiter
226
237
  return self
227
238
 
239
+ def with_metric_tagger(
240
+ self,
241
+ tagger: Callable[
242
+ [
243
+ AlgorithmPayload,
244
+ CrystalEntrypointArguments,
245
+ ],
246
+ dict[str, str],
247
+ ]
248
+ | None = None,
249
+ ) -> "Nexus":
250
+ """
251
+ Adds a metric `enricher` to be used with injected metrics provider to assign additional tags to emitted metrics.
252
+ """
253
+ self._metric_tagger = tagger
254
+ return self
255
+
228
256
  def with_module(self, module: Type[Module]) -> "Nexus":
229
257
  """
230
258
  Adds a (custom) DI module into the DI container.
@@ -317,30 +345,59 @@ class Nexus:
317
345
 
318
346
  bootstrap_logger.start()
319
347
 
320
- for payload_type in self._payload_types:
321
- try:
348
+ try:
349
+ logger_fixed_template = {}
350
+ logger_tags = {}
351
+ metric_tags = {}
352
+
353
+ for payload_type in self._payload_types:
322
354
  payload = await self._get_payload(payload_type=payload_type)
323
355
  self._injector.binder.bind(
324
356
  payload.__class__, to=payload, scope=singleton
325
357
  )
326
- logger_factory = LoggerFactory(
327
- fixed_template=None
328
- if not self._log_enricher
329
- else self._log_enricher(payload, self._run_args),
330
- fixed_template_delimiter=self._log_enrichment_delimiter,
331
- global_tags=self._log_tagger(payload, self._run_args)
358
+ logger_fixed_template |= (
359
+ self._log_enricher(payload, self._run_args)
360
+ if self._log_enricher
361
+ else {}
362
+ )
363
+ logger_tags |= (
364
+ self._log_tagger(payload, self._run_args)
332
365
  if self._log_tagger
333
- else None,
366
+ else {}
334
367
  )
335
- # bind app-level LoggerFactory now
336
- self._injector.binder.bind(
337
- logger_factory.__class__,
338
- to=logger_factory,
339
- scope=singleton,
368
+ metric_tags |= (
369
+ self._metric_tagger(payload, self._run_args)
370
+ if self._metric_tagger
371
+ else {}
340
372
  )
341
- except BaseException as ex: # pylint: disable=broad-except
342
- bootstrap_logger.error("Error reading algorithm payload", ex)
343
- sys.exit(1)
373
+
374
+ logger_factory = LoggerFactory(
375
+ fixed_template=logger_fixed_template,
376
+ fixed_template_delimiter=self._log_enrichment_delimiter,
377
+ global_tags=logger_tags,
378
+ )
379
+ # bind app-level LoggerFactory now
380
+ self._injector.binder.bind(
381
+ logger_factory.__class__,
382
+ to=logger_factory,
383
+ scope=singleton,
384
+ )
385
+
386
+ # bind app-level MetricsProvider now
387
+ metrics_provider = MetricsProviderFactory(
388
+ global_tags=metric_tags,
389
+ ).create_provider()
390
+ self._injector.binder.bind(
391
+ metrics_provider.__class__,
392
+ to=metrics_provider,
393
+ scope=singleton,
394
+ )
395
+ except BaseException as ex: # pylint: disable=broad-except
396
+ bootstrap_logger.error("Error reading algorithm payload", ex)
397
+
398
+ # ensure we flush bootstrap logger before we exit
399
+ bootstrap_logger.stop()
400
+ sys.exit(1)
344
401
 
345
402
  bootstrap_logger.stop()
346
403
 
@@ -402,7 +459,9 @@ class Nexus:
402
459
  for on_complete_task_class in self._on_complete_tasks
403
460
  ]
404
461
  if len(on_complete_tasks) > 0:
405
- done, pending = await asyncio.wait(on_complete_tasks)
462
+ done, pending = await asyncio.wait(
463
+ on_complete_tasks, return_when=asyncio.FIRST_EXCEPTION
464
+ )
406
465
  if len(pending) > 0:
407
466
  root_logger.warning(
408
467
  "Some post-processing operations did not complete or failed. Please review application logs for more information"
@@ -425,9 +484,6 @@ class Nexus:
425
484
 
426
485
  root_logger.stop()
427
486
 
428
- if os.getenv("NEXUS__RAISE_ERROR_ON_COMPLETE") and ex is not None:
429
- raise ex
430
-
431
487
  @classmethod
432
488
  def create(cls) -> "Nexus":
433
489
  """
@@ -17,13 +17,11 @@
17
17
  # limitations under the License.
18
18
  #
19
19
 
20
- import json
21
20
  import os
22
21
  import re
23
22
  from pydoc import locate
24
23
  from typing import final, Type, Any
25
24
 
26
- from adapta.metrics import MetricsProvider
27
25
  from adapta.storage.blob.base import StorageClient
28
26
  from adapta.storage.query_enabled_store import QueryEnabledStore
29
27
  from injector import Module, singleton, provider
@@ -51,28 +49,6 @@ from esd_services_api_client.nexus.core.serializers import (
51
49
  )
52
50
 
53
51
 
54
- @final
55
- class MetricsModule(Module):
56
- """
57
- Metrics provider module.
58
- """
59
-
60
- @singleton
61
- @provider
62
- def provide(self) -> MetricsProvider:
63
- """
64
- DI factory method.
65
- """
66
- metrics_class: Type[MetricsProvider] = locate(
67
- os.getenv(
68
- "NEXUS__METRIC_PROVIDER_CLASS",
69
- "adapta.metrics.providers.datadog_provider.DatadogMetricsProvider",
70
- )
71
- )
72
- metrics_settings = json.loads(os.getenv("NEXUS__METRIC_PROVIDER_CONFIGURATION"))
73
- return metrics_class(**metrics_settings)
74
-
75
-
76
52
  @final
77
53
  class BootstrapLoggerFactoryModule(Module):
78
54
  """
@@ -237,7 +213,6 @@ class ServiceConfigurator:
237
213
  def __init__(self):
238
214
  self._injection_binds = [
239
215
  BootstrapLoggerFactoryModule(),
240
- MetricsModule(),
241
216
  CrystalReceiverClientModule(),
242
217
  QueryEnabledStoreModule(),
243
218
  StorageClientModule(),
@@ -1,7 +1,6 @@
1
1
  """
2
2
  Code infrastructure for manipulating payload received from Crystal SAS URI
3
3
  """
4
- import os
5
4
 
6
5
  # Copyright (c) 2023-2024. ECCO Sneaks & Data
7
6
  #
@@ -63,15 +62,8 @@ class AlgorithmPayloadReader:
63
62
  self._http.close()
64
63
  self._http = None
65
64
 
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
- )
65
+ def __init__(self, payload_uri: str, payload_type: Type[AlgorithmPayload]):
66
+ self._http = session_with_retries()
75
67
  self._payload: Optional[AlgorithmPayload] = None
76
68
  self._payload_uri = payload_uri
77
69
  self._payload_type = payload_type
@@ -70,7 +70,6 @@ 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
74
73
  @inject
75
74
  def __init__(
76
75
  self,
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "esd-services-api-client"
3
- version = "v2.6.2a150.dev14"
3
+ version = "v2.6.2a155.dev2"
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__ = 'v2.6.2a150.dev14'