avtomatika 1.0b6__tar.gz → 1.0b8__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 (92) hide show
  1. {avtomatika-1.0b6/src/avtomatika.egg-info → avtomatika-1.0b8}/PKG-INFO +91 -3
  2. {avtomatika-1.0b6 → avtomatika-1.0b8}/README.md +84 -1
  3. {avtomatika-1.0b6 → avtomatika-1.0b8}/pyproject.toml +5 -2
  4. avtomatika-1.0b8/src/avtomatika/api/handlers.py +549 -0
  5. avtomatika-1.0b8/src/avtomatika/api/routes.py +118 -0
  6. avtomatika-1.0b8/src/avtomatika/app_keys.py +33 -0
  7. {avtomatika-1.0b6 → avtomatika-1.0b8}/src/avtomatika/blueprint.py +125 -54
  8. {avtomatika-1.0b6 → avtomatika-1.0b8}/src/avtomatika/config.py +10 -0
  9. {avtomatika-1.0b6 → avtomatika-1.0b8}/src/avtomatika/context.py +2 -2
  10. {avtomatika-1.0b6 → avtomatika-1.0b8}/src/avtomatika/data_types.py +4 -2
  11. {avtomatika-1.0b6 → avtomatika-1.0b8}/src/avtomatika/dispatcher.py +9 -27
  12. avtomatika-1.0b8/src/avtomatika/engine.py +398 -0
  13. {avtomatika-1.0b6 → avtomatika-1.0b8}/src/avtomatika/executor.py +55 -22
  14. avtomatika-1.0b8/src/avtomatika/health_checker.py +57 -0
  15. avtomatika-1.0b8/src/avtomatika/history/base.py +105 -0
  16. {avtomatika-1.0b6 → avtomatika-1.0b8}/src/avtomatika/history/noop.py +18 -7
  17. {avtomatika-1.0b6 → avtomatika-1.0b8}/src/avtomatika/history/postgres.py +8 -6
  18. {avtomatika-1.0b6 → avtomatika-1.0b8}/src/avtomatika/history/sqlite.py +7 -5
  19. {avtomatika-1.0b6 → avtomatika-1.0b8}/src/avtomatika/metrics.py +1 -1
  20. {avtomatika-1.0b6 → avtomatika-1.0b8}/src/avtomatika/reputation.py +46 -40
  21. avtomatika-1.0b8/src/avtomatika/s3.py +323 -0
  22. {avtomatika-1.0b6 → avtomatika-1.0b8}/src/avtomatika/scheduler.py +8 -8
  23. {avtomatika-1.0b6 → avtomatika-1.0b8}/src/avtomatika/storage/base.py +45 -4
  24. {avtomatika-1.0b6 → avtomatika-1.0b8}/src/avtomatika/storage/memory.py +56 -13
  25. avtomatika-1.0b8/src/avtomatika/storage/redis.py +443 -0
  26. avtomatika-1.0b8/src/avtomatika/utils/__init__.py +0 -0
  27. avtomatika-1.0b8/src/avtomatika/utils/webhook_sender.py +96 -0
  28. avtomatika-1.0b8/src/avtomatika/watcher.py +78 -0
  29. {avtomatika-1.0b6 → avtomatika-1.0b8}/src/avtomatika/ws_manager.py +7 -6
  30. {avtomatika-1.0b6 → avtomatika-1.0b8/src/avtomatika.egg-info}/PKG-INFO +91 -3
  31. {avtomatika-1.0b6 → avtomatika-1.0b8}/src/avtomatika.egg-info/SOURCES.txt +11 -0
  32. {avtomatika-1.0b6 → avtomatika-1.0b8}/src/avtomatika.egg-info/requires.txt +7 -1
  33. avtomatika-1.0b8/tests/test_blueprint_integrity.py +100 -0
  34. {avtomatika-1.0b6 → avtomatika-1.0b8}/tests/test_dispatcher.py +31 -44
  35. {avtomatika-1.0b6 → avtomatika-1.0b8}/tests/test_dispatcher_extended.py +7 -3
  36. avtomatika-1.0b8/tests/test_engine.py +293 -0
  37. {avtomatika-1.0b6 → avtomatika-1.0b8}/tests/test_error_handling.py +21 -13
  38. {avtomatika-1.0b6 → avtomatika-1.0b8}/tests/test_executor.py +71 -0
  39. avtomatika-1.0b8/tests/test_handlers.py +459 -0
  40. {avtomatika-1.0b6 → avtomatika-1.0b8}/tests/test_history.py +15 -7
  41. avtomatika-1.0b8/tests/test_optimization.py +83 -0
  42. avtomatika-1.0b8/tests/test_postgres_history.py +84 -0
  43. {avtomatika-1.0b6 → avtomatika-1.0b8}/tests/test_reputation.py +2 -2
  44. avtomatika-1.0b8/tests/test_s3.py +265 -0
  45. avtomatika-1.0b8/tests/test_webhook_sender.py +74 -0
  46. avtomatika-1.0b6/src/avtomatika/engine.py +0 -929
  47. avtomatika-1.0b6/src/avtomatika/health_checker.py +0 -39
  48. avtomatika-1.0b6/src/avtomatika/history/base.py +0 -51
  49. avtomatika-1.0b6/src/avtomatika/storage/redis.py +0 -510
  50. avtomatika-1.0b6/src/avtomatika/watcher.py +0 -82
  51. avtomatika-1.0b6/tests/test_engine.py +0 -678
  52. avtomatika-1.0b6/tests/test_postgres_history.py +0 -107
  53. {avtomatika-1.0b6 → avtomatika-1.0b8}/LICENSE +0 -0
  54. {avtomatika-1.0b6 → avtomatika-1.0b8}/setup.cfg +0 -0
  55. {avtomatika-1.0b6 → avtomatika-1.0b8}/src/avtomatika/__init__.py +0 -0
  56. {avtomatika-1.0b6 → avtomatika-1.0b8}/src/avtomatika/api.html +0 -0
  57. {avtomatika-1.0b6 → avtomatika-1.0b8}/src/avtomatika/client_config_loader.py +0 -0
  58. {avtomatika-1.0b6 → avtomatika-1.0b8}/src/avtomatika/compression.py +0 -0
  59. {avtomatika-1.0b6 → avtomatika-1.0b8}/src/avtomatika/constants.py +0 -0
  60. {avtomatika-1.0b6 → avtomatika-1.0b8}/src/avtomatika/datastore.py +0 -0
  61. {avtomatika-1.0b6 → avtomatika-1.0b8}/src/avtomatika/logging_config.py +0 -0
  62. {avtomatika-1.0b6 → avtomatika-1.0b8}/src/avtomatika/py.typed +0 -0
  63. {avtomatika-1.0b6 → avtomatika-1.0b8}/src/avtomatika/quota.py +0 -0
  64. {avtomatika-1.0b6 → avtomatika-1.0b8}/src/avtomatika/ratelimit.py +0 -0
  65. {avtomatika-1.0b6 → avtomatika-1.0b8}/src/avtomatika/scheduler_config_loader.py +0 -0
  66. {avtomatika-1.0b6 → avtomatika-1.0b8}/src/avtomatika/security.py +0 -0
  67. {avtomatika-1.0b6 → avtomatika-1.0b8}/src/avtomatika/storage/__init__.py +0 -0
  68. {avtomatika-1.0b6 → avtomatika-1.0b8}/src/avtomatika/telemetry.py +0 -0
  69. {avtomatika-1.0b6 → avtomatika-1.0b8}/src/avtomatika/worker_config_loader.py +0 -0
  70. {avtomatika-1.0b6 → avtomatika-1.0b8}/src/avtomatika.egg-info/dependency_links.txt +0 -0
  71. {avtomatika-1.0b6 → avtomatika-1.0b8}/src/avtomatika.egg-info/top_level.txt +0 -0
  72. {avtomatika-1.0b6 → avtomatika-1.0b8}/tests/test_blueprint_conditions.py +0 -0
  73. {avtomatika-1.0b6 → avtomatika-1.0b8}/tests/test_blueprints.py +0 -0
  74. {avtomatika-1.0b6 → avtomatika-1.0b8}/tests/test_client_config_loader.py +0 -0
  75. {avtomatika-1.0b6 → avtomatika-1.0b8}/tests/test_compression.py +0 -0
  76. {avtomatika-1.0b6 → avtomatika-1.0b8}/tests/test_config_validation.py +0 -0
  77. {avtomatika-1.0b6 → avtomatika-1.0b8}/tests/test_context.py +0 -0
  78. {avtomatika-1.0b6 → avtomatika-1.0b8}/tests/test_health_checker.py +0 -0
  79. {avtomatika-1.0b6 → avtomatika-1.0b8}/tests/test_integration.py +0 -0
  80. {avtomatika-1.0b6 → avtomatika-1.0b8}/tests/test_logging_config.py +0 -0
  81. {avtomatika-1.0b6 → avtomatika-1.0b8}/tests/test_memory_locking.py +0 -0
  82. {avtomatika-1.0b6 → avtomatika-1.0b8}/tests/test_memory_storage.py +0 -0
  83. {avtomatika-1.0b6 → avtomatika-1.0b8}/tests/test_metrics.py +0 -0
  84. {avtomatika-1.0b6 → avtomatika-1.0b8}/tests/test_noop_history.py +0 -0
  85. {avtomatika-1.0b6 → avtomatika-1.0b8}/tests/test_ratelimit.py +0 -0
  86. {avtomatika-1.0b6 → avtomatika-1.0b8}/tests/test_redis_locking.py +0 -0
  87. {avtomatika-1.0b6 → avtomatika-1.0b8}/tests/test_redis_storage.py +0 -0
  88. {avtomatika-1.0b6 → avtomatika-1.0b8}/tests/test_scheduler.py +0 -0
  89. {avtomatika-1.0b6 → avtomatika-1.0b8}/tests/test_telemetry.py +0 -0
  90. {avtomatika-1.0b6 → avtomatika-1.0b8}/tests/test_watcher.py +0 -0
  91. {avtomatika-1.0b6 → avtomatika-1.0b8}/tests/test_worker_config_loader.py +0 -0
  92. {avtomatika-1.0b6 → avtomatika-1.0b8}/tests/test_ws_manager.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: avtomatika
3
- Version: 1.0b6
3
+ Version: 1.0b8
4
4
  Summary: A state-machine based orchestrator for long-running AI and other jobs.
5
5
  Project-URL: Homepage, https://github.com/avtomatika-ai/avtomatika
6
6
  Project-URL: Bug Tracker, https://github.com/avtomatika-ai/avtomatika/issues
@@ -12,7 +12,6 @@ Requires-Python: >=3.11
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
14
  Requires-Dist: aiohttp~=3.12
15
- Requires-Dist: aiocache~=0.12
16
15
  Requires-Dist: python-json-logger~=4.0
17
16
  Requires-Dist: graphviz~=0.21
18
17
  Requires-Dist: zstandard~=0.24
@@ -21,6 +20,9 @@ Requires-Dist: msgpack~=1.1
21
20
  Requires-Dist: orjson~=3.11
22
21
  Provides-Extra: redis
23
22
  Requires-Dist: redis~=7.1; extra == "redis"
23
+ Provides-Extra: s3
24
+ Requires-Dist: obstore>=0.2; extra == "s3"
25
+ Requires-Dist: aiofiles~=23.2; extra == "s3"
24
26
  Provides-Extra: history
25
27
  Requires-Dist: aiosqlite~=0.22; extra == "history"
26
28
  Requires-Dist: asyncpg~=0.30; extra == "history"
@@ -38,10 +40,13 @@ Requires-Dist: pytest-mock~=3.14; extra == "test"
38
40
  Requires-Dist: aioresponses~=0.7; extra == "test"
39
41
  Requires-Dist: backports.zstd~=1.2; extra == "test"
40
42
  Requires-Dist: opentelemetry-instrumentation-aiohttp-client; extra == "test"
43
+ Requires-Dist: obstore>=0.2; extra == "test"
44
+ Requires-Dist: aiofiles~=23.2; extra == "test"
41
45
  Provides-Extra: all
42
46
  Requires-Dist: avtomatika[redis]; extra == "all"
43
47
  Requires-Dist: avtomatika[history]; extra == "all"
44
48
  Requires-Dist: avtomatika[telemetry]; extra == "all"
49
+ Requires-Dist: avtomatika[s3]; extra == "all"
45
50
  Dynamic: license-file
46
51
 
47
52
  # Avtomatika Orchestrator
@@ -61,6 +66,8 @@ This document serves as a comprehensive guide for developers looking to build pi
61
66
  - [Parallel Execution and Aggregation (Fan-out/Fan-in)](#parallel-execution-and-aggregation-fan-outfan-in)
62
67
  - [Dependency Injection (DataStore)](#dependency-injection-datastore)
63
68
  - [Native Scheduler](#native-scheduler)
69
+ - [S3 Payload Offloading](#s3-payload-offloading)
70
+ - [Webhook Notifications](#webhook-notifications)
64
71
  - [Production Configuration](#production-configuration)
65
72
  - [Fault Tolerance](#fault-tolerance)
66
73
  - [Storage Backend](#storage-backend)
@@ -107,6 +114,11 @@ Avtomatika is part of a larger ecosystem:
107
114
  pip install "avtomatika[telemetry]"
108
115
  ```
109
116
 
117
+ * **Install with S3 support (Payload Offloading):**
118
+ ```bash
119
+ pip install "avtomatika[s3]"
120
+ ```
121
+
110
122
  * **Install all dependencies, including for testing:**
111
123
  ```bash
112
124
  pip install "avtomatika[all,test]"
@@ -157,7 +169,13 @@ async def end_handler(context):
157
169
  engine = OrchestratorEngine(storage, config)
158
170
  engine.register_blueprint(my_blueprint)
159
171
 
160
- # 4. Define the main entrypoint to run the server
172
+ # 4. Accessing Components (Optional)
173
+ # You can access the internal aiohttp app and core components using AppKeys
174
+ # from avtomatika.app_keys import ENGINE_KEY, DISPATCHER_KEY
175
+ # app = engine.app
176
+ # dispatcher = app[DISPATCHER_KEY]
177
+
178
+ # 5. Define the main entrypoint to run the server
161
179
  async def main():
162
180
  await engine.start()
163
181
 
@@ -244,6 +262,19 @@ async def publish_handler_old_style(context):
244
262
  print(f"Job {context.job_id}: Publishing video at {output_path} ({duration}s).")
245
263
  context.actions.transition_to("complete")
246
264
  ```
265
+ ## Key Concepts: JobContext and Actions
266
+
267
+ ### High Performance Architecture
268
+
269
+ Avtomatika is engineered for high-load environments with thousands of concurrent workers.
270
+
271
+ * **O(1) Dispatcher**: Uses advanced Redis Set intersections to find suitable workers instantly, regardless of the cluster size. No O(N) scanning.
272
+ * **Non-Blocking I/O**:
273
+ * **Webhooks**: Sent via a bounded background queue to prevent backpressure.
274
+ * **History Logging**: Writes to SQL databases are buffered and asynchronous, ensuring the main execution loop never blocks.
275
+ * **Redis Streams**: Uses blocking reads to eliminate busy-waiting and reduce CPU usage.
276
+ * **Memory Safety**: S3 file transfers use streaming to handle multi-gigabyte files with constant, low RAM usage.
277
+
247
278
  ## Blueprint Cookbook: Key Features
248
279
 
249
280
  ### 1. Conditional Transitions (`.when()`)
@@ -355,6 +386,63 @@ blueprint = "backup_flow"
355
386
  daily_at = "02:00"
356
387
  ```
357
388
 
389
+ ### 6. Webhook Notifications
390
+
391
+ The orchestrator can send asynchronous notifications to an external system when a job completes, fails, or is quarantined. This eliminates the need for clients to constantly poll the API for status updates.
392
+
393
+ ### 7. S3 Payload Offloading
394
+
395
+ Orchestrator provides first-class support for handling large files via S3-compatible storage, powered by the high-performance `obstore` library (Rust bindings).
396
+
397
+ * **Memory Safe (Streaming)**: Uses streaming for uploads and downloads, allowing processing of files larger than available RAM without OOM errors.
398
+ * **Managed Mode**: The Orchestrator manages file lifecycle (automatic cleanup of S3 objects and local temporary files on job completion).
399
+ * **Dependency Injection**: Use the `task_files` argument in your handlers to easily read/write data.
400
+ * **Directory Support**: Supports recursive download and upload of entire directories.
401
+
402
+ ```python
403
+ @bp.handler_for("process_data")
404
+ async def process_data(task_files, actions):
405
+ # Streaming download of a large file
406
+ local_path = await task_files.download("large_dataset.csv")
407
+
408
+ # ... process data ...
409
+
410
+ # Upload results
411
+ await task_files.write_json("results.json", {"status": "done"})
412
+
413
+ actions.transition_to("finished")
414
+ ```
415
+
416
+ ## Production Configuration
417
+ * **Events:**
418
+ * `job_finished`: The job reached a final success state.
419
+ * `job_failed`: The job failed (e.g., due to an error or invalid input).
420
+ * `job_quarantined`: The job was moved to quarantine after repeated failures.
421
+
422
+ **Example Request:**
423
+ ```json
424
+ POST /api/v1/jobs/my_flow
425
+ {
426
+ "initial_data": {
427
+ "video_url": "..."
428
+ },
429
+ "webhook_url": "https://my-app.com/webhooks/avtomatika"
430
+ }
431
+ ```
432
+
433
+ **Example Webhook Payload:**
434
+ ```json
435
+ {
436
+ "event": "job_finished",
437
+ "job_id": "123e4567-e89b-12d3-a456-426614174000",
438
+ "status": "finished",
439
+ "result": {
440
+ "output_path": "/videos/result.mp4"
441
+ },
442
+ "error": null
443
+ }
444
+ ```
445
+
358
446
  ## Production Configuration
359
447
 
360
448
  The orchestrator's behavior can be configured through environment variables. Additionally, any configuration parameter loaded from environment variables can be programmatically overridden in your application code after the `Config` object has been initialized. This provides flexibility for different deployment and testing scenarios.
@@ -15,6 +15,8 @@ This document serves as a comprehensive guide for developers looking to build pi
15
15
  - [Parallel Execution and Aggregation (Fan-out/Fan-in)](#parallel-execution-and-aggregation-fan-outfan-in)
16
16
  - [Dependency Injection (DataStore)](#dependency-injection-datastore)
17
17
  - [Native Scheduler](#native-scheduler)
18
+ - [S3 Payload Offloading](#s3-payload-offloading)
19
+ - [Webhook Notifications](#webhook-notifications)
18
20
  - [Production Configuration](#production-configuration)
19
21
  - [Fault Tolerance](#fault-tolerance)
20
22
  - [Storage Backend](#storage-backend)
@@ -61,6 +63,11 @@ Avtomatika is part of a larger ecosystem:
61
63
  pip install "avtomatika[telemetry]"
62
64
  ```
63
65
 
66
+ * **Install with S3 support (Payload Offloading):**
67
+ ```bash
68
+ pip install "avtomatika[s3]"
69
+ ```
70
+
64
71
  * **Install all dependencies, including for testing:**
65
72
  ```bash
66
73
  pip install "avtomatika[all,test]"
@@ -111,7 +118,13 @@ async def end_handler(context):
111
118
  engine = OrchestratorEngine(storage, config)
112
119
  engine.register_blueprint(my_blueprint)
113
120
 
114
- # 4. Define the main entrypoint to run the server
121
+ # 4. Accessing Components (Optional)
122
+ # You can access the internal aiohttp app and core components using AppKeys
123
+ # from avtomatika.app_keys import ENGINE_KEY, DISPATCHER_KEY
124
+ # app = engine.app
125
+ # dispatcher = app[DISPATCHER_KEY]
126
+
127
+ # 5. Define the main entrypoint to run the server
115
128
  async def main():
116
129
  await engine.start()
117
130
 
@@ -198,6 +211,19 @@ async def publish_handler_old_style(context):
198
211
  print(f"Job {context.job_id}: Publishing video at {output_path} ({duration}s).")
199
212
  context.actions.transition_to("complete")
200
213
  ```
214
+ ## Key Concepts: JobContext and Actions
215
+
216
+ ### High Performance Architecture
217
+
218
+ Avtomatika is engineered for high-load environments with thousands of concurrent workers.
219
+
220
+ * **O(1) Dispatcher**: Uses advanced Redis Set intersections to find suitable workers instantly, regardless of the cluster size. No O(N) scanning.
221
+ * **Non-Blocking I/O**:
222
+ * **Webhooks**: Sent via a bounded background queue to prevent backpressure.
223
+ * **History Logging**: Writes to SQL databases are buffered and asynchronous, ensuring the main execution loop never blocks.
224
+ * **Redis Streams**: Uses blocking reads to eliminate busy-waiting and reduce CPU usage.
225
+ * **Memory Safety**: S3 file transfers use streaming to handle multi-gigabyte files with constant, low RAM usage.
226
+
201
227
  ## Blueprint Cookbook: Key Features
202
228
 
203
229
  ### 1. Conditional Transitions (`.when()`)
@@ -309,6 +335,63 @@ blueprint = "backup_flow"
309
335
  daily_at = "02:00"
310
336
  ```
311
337
 
338
+ ### 6. Webhook Notifications
339
+
340
+ The orchestrator can send asynchronous notifications to an external system when a job completes, fails, or is quarantined. This eliminates the need for clients to constantly poll the API for status updates.
341
+
342
+ ### 7. S3 Payload Offloading
343
+
344
+ Orchestrator provides first-class support for handling large files via S3-compatible storage, powered by the high-performance `obstore` library (Rust bindings).
345
+
346
+ * **Memory Safe (Streaming)**: Uses streaming for uploads and downloads, allowing processing of files larger than available RAM without OOM errors.
347
+ * **Managed Mode**: The Orchestrator manages file lifecycle (automatic cleanup of S3 objects and local temporary files on job completion).
348
+ * **Dependency Injection**: Use the `task_files` argument in your handlers to easily read/write data.
349
+ * **Directory Support**: Supports recursive download and upload of entire directories.
350
+
351
+ ```python
352
+ @bp.handler_for("process_data")
353
+ async def process_data(task_files, actions):
354
+ # Streaming download of a large file
355
+ local_path = await task_files.download("large_dataset.csv")
356
+
357
+ # ... process data ...
358
+
359
+ # Upload results
360
+ await task_files.write_json("results.json", {"status": "done"})
361
+
362
+ actions.transition_to("finished")
363
+ ```
364
+
365
+ ## Production Configuration
366
+ * **Events:**
367
+ * `job_finished`: The job reached a final success state.
368
+ * `job_failed`: The job failed (e.g., due to an error or invalid input).
369
+ * `job_quarantined`: The job was moved to quarantine after repeated failures.
370
+
371
+ **Example Request:**
372
+ ```json
373
+ POST /api/v1/jobs/my_flow
374
+ {
375
+ "initial_data": {
376
+ "video_url": "..."
377
+ },
378
+ "webhook_url": "https://my-app.com/webhooks/avtomatika"
379
+ }
380
+ ```
381
+
382
+ **Example Webhook Payload:**
383
+ ```json
384
+ {
385
+ "event": "job_finished",
386
+ "job_id": "123e4567-e89b-12d3-a456-426614174000",
387
+ "status": "finished",
388
+ "result": {
389
+ "output_path": "/videos/result.mp4"
390
+ },
391
+ "error": null
392
+ }
393
+ ```
394
+
312
395
  ## Production Configuration
313
396
 
314
397
  The orchestrator's behavior can be configured through environment variables. Additionally, any configuration parameter loaded from environment variables can be programmatically overridden in your application code after the `Config` object has been initialized. This provides flexibility for different deployment and testing scenarios.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "avtomatika"
7
- version = "1.0b6"
7
+ version = "1.0b8"
8
8
  description = "A state-machine based orchestrator for long-running AI and other jobs."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -16,7 +16,6 @@ classifiers = [
16
16
  ]
17
17
  dependencies = [
18
18
  "aiohttp~=3.12",
19
- "aiocache~=0.12",
20
19
  "python-json-logger~=4.0",
21
20
  "graphviz~=0.21",
22
21
  "zstandard~=0.24",
@@ -27,6 +26,7 @@ dependencies = [
27
26
 
28
27
  [project.optional-dependencies]
29
28
  redis = ["redis~=7.1"]
29
+ s3 = ["obstore>=0.2", "aiofiles~=23.2"]
30
30
  history = ["aiosqlite~=0.22", "asyncpg~=0.30"]
31
31
  telemetry = [
32
32
  "opentelemetry-api~=1.39",
@@ -43,11 +43,14 @@ test = [
43
43
  "aioresponses~=0.7",
44
44
  "backports.zstd~=1.2",
45
45
  "opentelemetry-instrumentation-aiohttp-client",
46
+ "obstore>=0.2",
47
+ "aiofiles~=23.2",
46
48
  ]
47
49
  all = [
48
50
  "avtomatika[redis]",
49
51
  "avtomatika[history]",
50
52
  "avtomatika[telemetry]",
53
+ "avtomatika[s3]",
51
54
  ]
52
55
 
53
56
  [project.urls]