codex-platform 0.1.0__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.
Files changed (45) hide show
  1. codex_platform/__init__.py +1 -0
  2. codex_platform/notifications/__init__.py +48 -0
  3. codex_platform/notifications/channels.py +24 -0
  4. codex_platform/notifications/clients/__init__.py +3 -0
  5. codex_platform/notifications/clients/smtp.py +134 -0
  6. codex_platform/notifications/delivery/__init__.py +18 -0
  7. codex_platform/notifications/delivery/arq.py +69 -0
  8. codex_platform/notifications/delivery/base.py +39 -0
  9. codex_platform/notifications/delivery/direct.py +89 -0
  10. codex_platform/notifications/dto.py +63 -0
  11. codex_platform/notifications/interfaces.py +30 -0
  12. codex_platform/notifications/orchestrator.py +116 -0
  13. codex_platform/notifications/registry.py +71 -0
  14. codex_platform/notifications/renderer.py +111 -0
  15. codex_platform/redis_service/__init__.py +59 -0
  16. codex_platform/redis_service/base.py +69 -0
  17. codex_platform/redis_service/exceptions.py +20 -0
  18. codex_platform/redis_service/keys.py +110 -0
  19. codex_platform/redis_service/managers/__init__.py +18 -0
  20. codex_platform/redis_service/managers/base_manager.py +31 -0
  21. codex_platform/redis_service/operations/__init__.py +19 -0
  22. codex_platform/redis_service/operations/hash.py +302 -0
  23. codex_platform/redis_service/operations/json_module.py +129 -0
  24. codex_platform/redis_service/operations/json_string.py +113 -0
  25. codex_platform/redis_service/operations/list_.py +219 -0
  26. codex_platform/redis_service/operations/pipeline.py +197 -0
  27. codex_platform/redis_service/operations/set_.py +212 -0
  28. codex_platform/redis_service/operations/string.py +318 -0
  29. codex_platform/redis_service/operations/zset.py +277 -0
  30. codex_platform/redis_service/service.py +80 -0
  31. codex_platform/streams/__init__.py +59 -0
  32. codex_platform/streams/consumer.py +106 -0
  33. codex_platform/streams/dispatcher.py +175 -0
  34. codex_platform/streams/processor.py +217 -0
  35. codex_platform/streams/producer.py +60 -0
  36. codex_platform/streams/router.py +78 -0
  37. codex_platform/workers/__init__.py +1 -0
  38. codex_platform/workers/arq/__init__.py +27 -0
  39. codex_platform/workers/arq/base.py +170 -0
  40. codex_platform/workers/arq/config.py +67 -0
  41. codex_platform/workers/arq/task_utils.py +72 -0
  42. codex_platform/workers/arq/types.py +11 -0
  43. codex_platform-0.1.0.dist-info/METADATA +120 -0
  44. codex_platform-0.1.0.dist-info/RECORD +45 -0
  45. codex_platform-0.1.0.dist-info/WHEEL +4 -0
@@ -0,0 +1 @@
1
+ """Worker infrastructure for async background job processing."""
@@ -0,0 +1,27 @@
1
+ """ARQ workers infrastructure — base classes, config, task utilities."""
2
+
3
+ from .base import (
4
+ CORE_FUNCTIONS,
5
+ HEALTH_FILE,
6
+ BaseArqService,
7
+ BaseArqWorkerSettings,
8
+ base_shutdown,
9
+ base_startup,
10
+ requeue_to_stream,
11
+ )
12
+ from .config import BaseWorkerConfig
13
+ from .task_utils import arq_task
14
+ from .types import DependencyFunction
15
+
16
+ __all__ = [
17
+ "BaseArqService",
18
+ "BaseArqWorkerSettings",
19
+ "BaseWorkerConfig",
20
+ "CORE_FUNCTIONS",
21
+ "DependencyFunction",
22
+ "HEALTH_FILE",
23
+ "arq_task",
24
+ "base_startup",
25
+ "base_shutdown",
26
+ "requeue_to_stream",
27
+ ]
@@ -0,0 +1,170 @@
1
+ """
2
+ codex_platform.workers.arq.base
3
+ ============================
4
+ Base infrastructure for ARQ background workers.
5
+
6
+ Usage:
7
+ from codex_platform.workers.arq import BaseArqWorkerSettings, base_startup, base_shutdown
8
+
9
+ class MyWorkerSettings(BaseArqWorkerSettings):
10
+ redis_settings = RedisSettings(...)
11
+ functions = MY_FUNCTIONS
12
+ on_startup = my_startup
13
+ on_shutdown = my_shutdown
14
+ """
15
+
16
+ import logging
17
+ import pathlib
18
+ from datetime import datetime, timezone
19
+ from typing import Any
20
+
21
+ from arq.connections import ArqRedis, RedisSettings, create_pool
22
+
23
+ log = logging.getLogger(__name__)
24
+
25
+
26
+ class BaseArqService:
27
+ """Async ARQ client for use inside worker tasks.
28
+
29
+ For the Django producer-side client see
30
+ ``codex_platform.adapters.arq.client.BaseArqClient``.
31
+
32
+ Example::
33
+
34
+ service = BaseArqService(redis_settings)
35
+ await service.init()
36
+ await service.enqueue_job("my_task", arg1, arg2)
37
+ await service.close()
38
+ """
39
+
40
+ def __init__(self, redis_settings: RedisSettings) -> None:
41
+ """Initialize the service with Redis connection settings.
42
+
43
+ Args:
44
+ redis_settings: ARQ ``RedisSettings`` instance.
45
+ """
46
+ self.pool: ArqRedis | None = None
47
+ self.redis_settings = redis_settings
48
+
49
+ async def init(self) -> None:
50
+ """Open the ARQ connection pool. No-op if already initialized.
51
+
52
+ Raises:
53
+ Exception: If the Redis connection cannot be established.
54
+ """
55
+ if not self.pool:
56
+ try:
57
+ self.pool = await create_pool(self.redis_settings)
58
+ log.debug("BaseArqService | init | status=success")
59
+ except Exception:
60
+ log.exception("BaseArqService | init | status=failed")
61
+ raise
62
+
63
+ async def close(self) -> None:
64
+ """Close the ARQ connection pool gracefully."""
65
+ if self.pool:
66
+ try:
67
+ await self.pool.close()
68
+ log.debug("BaseArqService | close | status=success")
69
+ except Exception:
70
+ log.exception("BaseArqService | close | status=failed")
71
+
72
+ async def enqueue_job(self, function: str, *args: Any, **kwargs: Any) -> Any | None:
73
+ """Enqueue a background job. Initializes the pool on first call.
74
+
75
+ Args:
76
+ function: ARQ worker function name.
77
+ *args: Positional arguments forwarded to the function.
78
+ **kwargs: Keyword arguments forwarded to the function.
79
+
80
+ Returns:
81
+ ARQ ``Job`` handle, or ``None`` if enqueueing failed.
82
+ """
83
+ if not self.pool:
84
+ await self.init()
85
+ if self.pool:
86
+ try:
87
+ job = await self.pool.enqueue_job(function, *args, **kwargs)
88
+ log.debug(
89
+ "BaseArqService | enqueue_job | function=%s | job_id=%s",
90
+ function,
91
+ job.job_id if job else "None",
92
+ )
93
+ return job
94
+ except Exception:
95
+ log.exception("BaseArqService | enqueue_job | function=%s | status=failed", function)
96
+ return None
97
+ return None
98
+
99
+
100
+ # --- Health Check ---
101
+ # Marker file for container health probes (Docker HEALTHCHECK, K8s liveness)
102
+ HEALTH_FILE = pathlib.Path("/tmp/arq_worker_healthy") # nosec B108
103
+
104
+
105
+ async def base_startup(ctx: dict[str, Any]) -> None:
106
+ """Base startup hook. Creates health check file. Extend in your workers."""
107
+ HEALTH_FILE.touch()
108
+ log.info("ArqWorker | startup | health_file=%s", HEALTH_FILE)
109
+
110
+
111
+ async def base_shutdown(ctx: dict[str, Any]) -> None:
112
+ """Base shutdown hook. Removes health check file. Extend in your workers."""
113
+ HEALTH_FILE.unlink(missing_ok=True)
114
+ log.info("ArqWorker | shutdown")
115
+
116
+
117
+ class BaseArqWorkerSettings:
118
+ """Base ARQ ``WorkerSettings``. Subclass and override fields in your workers module.
119
+
120
+ Example::
121
+
122
+ class MyWorkerSettings(BaseArqWorkerSettings):
123
+ redis_settings = RedisSettings(host="localhost", port=6379)
124
+ functions = [my_task1, my_task2] + CORE_FUNCTIONS
125
+ on_startup = my_startup
126
+ on_shutdown = my_shutdown
127
+ """
128
+
129
+ max_jobs: int = 20
130
+ job_timeout: int = 60
131
+ keep_result: int = 60
132
+ max_retries: int = 5
133
+ retry_delay: int = 10
134
+
135
+ on_startup = base_startup
136
+ on_shutdown = base_shutdown
137
+
138
+
139
+ # --- CORE_FUNCTIONS ---
140
+
141
+
142
+ async def requeue_to_stream(ctx: dict[str, Any], stream_name: str, payload: dict[str, Any]) -> None:
143
+ """Re-enqueue a failed message back into a Redis Stream for retry processing.
144
+
145
+ After 5 retries the message is moved to a Dead Letter Queue (DLQ) instead of
146
+ being dropped. DLQ key: ``{stream_name}:dlq``.
147
+
148
+ Args:
149
+ ctx: ARQ worker context dict. Must contain a ``"stream_manager"`` key.
150
+ stream_name: Target Redis Stream name.
151
+ payload: Original message payload. ``_retries`` counter is incremented in-place.
152
+ """
153
+ sm = ctx.get("stream_manager")
154
+ if not sm:
155
+ log.error("requeue_to_stream | stream_manager not in context")
156
+ return
157
+ retries = int(payload.get("_retries", 0)) + 1
158
+ if retries > 5:
159
+ dlq_name = f"{stream_name}:dlq"
160
+ payload["_failed_at"] = datetime.now(timezone.utc).isoformat()
161
+ payload["_original_stream"] = stream_name
162
+ await sm.add_event(dlq_name, payload)
163
+ log.error("requeue_to_stream | max retries reached | moved to DLQ '%s'", dlq_name)
164
+ return
165
+ payload["_retries"] = str(retries)
166
+ await sm.add_event(stream_name, payload)
167
+ log.info("requeue_to_stream | requeued to '%s' retry=%d", stream_name, retries)
168
+
169
+
170
+ CORE_FUNCTIONS = [requeue_to_stream]
@@ -0,0 +1,67 @@
1
+ """
2
+ codex_platform.workers.arq.config
3
+ ================================
4
+ Base workers configuration with SMTP and ARQ fields.
5
+
6
+ Extends BaseCommonSettings from codex_platform.settings.
7
+ Maps standard Django .env names to workers-friendly fields.
8
+
9
+ Usage:
10
+ class MyWorkerConfig(BaseWorkerConfig):
11
+ SEVEN_IO_API_KEY: str | None = None # project-specific
12
+ TEMPLATES_DIR: str = "src/workers/templates"
13
+
14
+ class Config:
15
+ env_file = ".env"
16
+ """
17
+
18
+ from typing import Any
19
+
20
+ from pydantic import Field
21
+
22
+ from codex_platform.settings import BaseCommonSettings
23
+
24
+
25
+ class BaseWorkerConfig(BaseCommonSettings):
26
+ """Base configuration for ARQ workers — provides SMTP and ARQ settings.
27
+
28
+ Maps standard Django ``.env`` variable names (``EMAIL_HOST``, etc.) to
29
+ internal ``SMTP_``-prefixed fields for clarity.
30
+
31
+ Extend this class in your project to add vendor-specific fields
32
+ (Twilio, Seven.io, SendGrid, etc.).
33
+
34
+ Example::
35
+
36
+ class MyWorkerConfig(BaseWorkerConfig):
37
+ SEVEN_IO_API_KEY: str | None = None
38
+ TEMPLATES_DIR: str = "src/workers/templates"
39
+
40
+ class Config:
41
+ env_file = ".env"
42
+ """
43
+
44
+ # --- Email (SMTP) — маппинг Django env names ---
45
+ SMTP_HOST: str = Field(default="localhost", alias="EMAIL_HOST")
46
+ SMTP_PORT: int = Field(default=465, alias="EMAIL_PORT")
47
+ SMTP_USER: str | None = Field(default=None, alias="EMAIL_HOST_USER")
48
+ SMTP_PASSWORD: str | None = Field(default=None, alias="EMAIL_HOST_PASSWORD")
49
+ SMTP_FROM_EMAIL: str | None = Field(default=None, alias="DEFAULT_FROM_EMAIL")
50
+ SMTP_USE_TLS: bool = Field(default=False, alias="EMAIL_USE_TLS")
51
+ SMTP_USE_SSL: bool = Field(default=True, alias="EMAIL_USE_SSL")
52
+
53
+ # --- ARQ Configuration ---
54
+ arq_max_jobs: int = 10
55
+ arq_job_timeout: int = 60
56
+ arq_keep_result: int = 60
57
+
58
+ @property
59
+ def arq_redis_settings(self) -> Any:
60
+ """Build and return an ARQ ``RedisSettings`` object from the base Redis config."""
61
+ from arq.connections import RedisSettings
62
+
63
+ return RedisSettings(
64
+ host=self.effective_redis_host,
65
+ port=self.redis_port,
66
+ password=self.redis_password,
67
+ )
@@ -0,0 +1,72 @@
1
+ """
2
+ codex_platform.workers.arq.task_utils
3
+ ====================================
4
+ Utilities for writing ARQ tasks with less boilerplate.
5
+
6
+ Usage:
7
+ from codex_platform.workers.arq import arq_task
8
+
9
+ @arq_task(retry_backoff=60, max_retries=3)
10
+ async def send_booking_notification(ctx, appointment_id: int):
11
+ service = ctx["notification_service"]
12
+ await service.send(...)
13
+ """
14
+
15
+ import logging
16
+ from functools import wraps
17
+ from typing import Any
18
+
19
+ from arq import Retry
20
+
21
+ log = logging.getLogger(__name__)
22
+
23
+
24
+ def arq_task(
25
+ *,
26
+ retry_backoff: int = 30,
27
+ max_retries: int = 5,
28
+ log_args: bool = False,
29
+ ) -> Any:
30
+ """
31
+ Decorator that adds standard error handling, logging, and retry to ARQ tasks.
32
+
33
+ Args:
34
+ retry_backoff: Base delay in seconds. Actual delay = job_try * retry_backoff.
35
+ max_retries: Maximum number of retries before giving up.
36
+ log_args: If True, log task arguments (be careful with PII).
37
+
38
+ Wrapped function receives ctx as first arg (standard ARQ convention).
39
+ On exception:
40
+ - If job_try < max_retries → raises Retry(defer=job_try * retry_backoff)
41
+ - If job_try >= max_retries → logs error and returns None (task dropped)
42
+ """
43
+
44
+ def decorator(fn: Any) -> Any:
45
+ @wraps(fn)
46
+ async def wrapper(ctx: dict[str, Any], *args: Any, **kwargs: Any) -> Any:
47
+ task_name = fn.__name__
48
+ job_try = ctx.get("job_try", 1)
49
+
50
+ if log_args:
51
+ log.info("%s | start | try=%d | args=%s kwargs=%s", task_name, job_try, args, kwargs)
52
+ else:
53
+ log.info("%s | start | try=%d", task_name, job_try)
54
+
55
+ try:
56
+ result = await fn(ctx, *args, **kwargs)
57
+ log.info("%s | success | try=%d", task_name, job_try)
58
+ return result
59
+ except Retry:
60
+ raise
61
+ except Exception as e:
62
+ if job_try < max_retries:
63
+ defer = job_try * retry_backoff
64
+ log.warning("%s | retry in %ds | try=%d | error=%s", task_name, defer, job_try, e)
65
+ raise Retry(defer=defer) from e
66
+ log.exception("%s | max retries (%d) reached | giving up", task_name, max_retries)
67
+ return None
68
+
69
+ wrapper.__qualname__ = fn.__qualname__
70
+ return wrapper
71
+
72
+ return decorator
@@ -0,0 +1,11 @@
1
+ """
2
+ codex_platform.workers.arq.types
3
+ ================================
4
+ Common type definitions for workers dependency injection.
5
+ """
6
+
7
+ from collections.abc import Awaitable, Callable
8
+ from typing import Any
9
+
10
+ # Type for dependency init/close functions used in workers startup/shutdown lists
11
+ DependencyFunction = Callable[[dict[str, Any], Any], Awaitable[None]]
@@ -0,0 +1,120 @@
1
+ Metadata-Version: 2.4
2
+ Name: codex-platform
3
+ Version: 0.1.0
4
+ Summary: Infrastructure, background tasks (ARQ), Redis service and framework adapters for Codex
5
+ Project-URL: Homepage, https://github.com/codexdlc/codex-platform
6
+ Project-URL: Documentation, https://codexdlc.github.io/codex-platform/
7
+ Project-URL: Repository, https://github.com/codexdlc/codex-platform
8
+ Project-URL: Issues, https://github.com/codexdlc/codex-platform/issues
9
+ Author: CodexDLC
10
+ License: Apache-2.0
11
+ Keywords: arq,django,notifications,redis,waas,worker
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: Apache Software License
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Requires-Python: >=3.10
20
+ Requires-Dist: codex-core
21
+ Requires-Dist: pydantic<3.0,>=2.0
22
+ Provides-Extra: all
23
+ Requires-Dist: aiosmtplib>=3.0; extra == 'all'
24
+ Requires-Dist: arq>=0.25; extra == 'all'
25
+ Requires-Dist: redis>=5.0; extra == 'all'
26
+ Provides-Extra: arq
27
+ Requires-Dist: arq>=0.25; extra == 'arq'
28
+ Provides-Extra: dev
29
+ Requires-Dist: aiosmtplib>=3.0; extra == 'dev'
30
+ Requires-Dist: arq>=0.25; extra == 'dev'
31
+ Requires-Dist: bandit>=1.7; extra == 'dev'
32
+ Requires-Dist: detect-secrets>=1.5; extra == 'dev'
33
+ Requires-Dist: fakeredis[lua]>=2.20; extra == 'dev'
34
+ Requires-Dist: mypy>=1.10; extra == 'dev'
35
+ Requires-Dist: pip-audit>=2.7; extra == 'dev'
36
+ Requires-Dist: pre-commit>=3.0; extra == 'dev'
37
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
38
+ Requires-Dist: pytest-cov; extra == 'dev'
39
+ Requires-Dist: pytest>=8.0; extra == 'dev'
40
+ Requires-Dist: redis>=5.0; extra == 'dev'
41
+ Requires-Dist: ruff>=0.4; extra == 'dev'
42
+ Provides-Extra: docs
43
+ Requires-Dist: mike>=2.0; extra == 'docs'
44
+ Requires-Dist: mkdocs-include-markdown-plugin; extra == 'docs'
45
+ Requires-Dist: mkdocs-material>=9.0; extra == 'docs'
46
+ Requires-Dist: mkdocs-static-i18n; extra == 'docs'
47
+ Requires-Dist: mkdocs<2.0,>=1.5; extra == 'docs'
48
+ Requires-Dist: mkdocstrings[python]>=0.24; extra == 'docs'
49
+ Provides-Extra: notifications
50
+ Requires-Dist: aiosmtplib>=3.0; extra == 'notifications'
51
+ Provides-Extra: redis
52
+ Requires-Dist: redis>=5.0; extra == 'redis'
53
+ Provides-Extra: streams
54
+ Requires-Dist: redis>=5.0; extra == 'streams'
55
+ Description-Content-Type: text/markdown
56
+
57
+ # codex-platform
58
+
59
+ [![PyPI version](https://img.shields.io/pypi/v/codex-platform.svg)](https://pypi.org/project/codex-platform/)
60
+ [![Python](https://img.shields.io/pypi/pyversions/codex-platform.svg)](https://pypi.org/project/codex-platform/)
61
+ [![CI](https://github.com/codexdlc/codex-platform/actions/workflows/ci.yml/badge.svg)](https://github.com/codexdlc/codex-platform/actions/workflows/ci.yml)
62
+ [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
63
+
64
+ Infrastructure library for the **Codex WaaS toolkit**. Provides async Redis abstraction, Redis Streams event bus, ARQ background workers, and a multi-channel notification engine — each as an independently installable extra.
65
+
66
+ ---
67
+
68
+ ## Install
69
+
70
+ ```bash
71
+ # Core only
72
+ pip install codex-platform
73
+
74
+ # With Redis support
75
+ pip install "codex-platform[redis]"
76
+
77
+ # With ARQ background workers
78
+ pip install "codex-platform[arq]"
79
+
80
+ # With async SMTP notifications
81
+ pip install "codex-platform[notifications]"
82
+
83
+ # Redis Streams
84
+ pip install "codex-platform[streams]"
85
+
86
+ # Everything
87
+ pip install "codex-platform[all]"
88
+ ```
89
+
90
+ ## Quick Start
91
+
92
+ ```python
93
+ from redis.asyncio import Redis
94
+ from codex_platform.redis_service import RedisService
95
+
96
+ redis = Redis(host="localhost", port=6379)
97
+ service = RedisService(redis)
98
+
99
+ await service.hash.set_json("user:42", "profile", {"name": "Alex"})
100
+ data = await service.hash.get_json("user:42", "profile")
101
+ ```
102
+
103
+ ## Modules
104
+
105
+ | Module | Extra | Description |
106
+ | :--- | :--- | :--- |
107
+ | `redis_service` | `[redis]` | Typed async Redis abstraction — Hash, String, List, Set, ZSet, JSON, Pipeline |
108
+ | `streams` | `[streams]` | Redis Streams producer/consumer with consumer groups, retry, and DLQ |
109
+ | `workers.arq` | `[arq]` | ARQ worker base infrastructure — health probes, DLQ retry, CORE_FUNCTIONS |
110
+ | `notifications` | `[notifications]` | Multi-channel notification engine — SMTP, ARQ/Direct delivery, Jinja2 renderer |
111
+
112
+ ## Documentation
113
+
114
+ Full docs with architecture, API reference, and data flow diagrams:
115
+
116
+ **[codexdlc.github.io/codex-platform](https://codexdlc.github.io/codex-platform/)**
117
+
118
+ ## Part of the Codex ecosystem
119
+
120
+ [codex-core](https://github.com/codexdlc/codex-core) · **codex-platform** · [codexdlc](https://github.com/codexdlc)
@@ -0,0 +1,45 @@
1
+ codex_platform/__init__.py,sha256=efyDuGd0noDsmCFnZ2fQnHDJ8L1XBEujKpLSSSvkcwk,86
2
+ codex_platform/notifications/__init__.py,sha256=4UdFzQ5-C8NTu0qvMNdSYJkdCLjokFSj7VMLxIEKhwQ,1745
3
+ codex_platform/notifications/channels.py,sha256=8mvSzRUSkwE5iSMZSwCqVDAgXFIBMF-pRCtBDXKt1zU,502
4
+ codex_platform/notifications/dto.py,sha256=-fg_Z-YLra6MwzkPPpCkfDsRb2_IR-HKHIaSgrpxhzY,1801
5
+ codex_platform/notifications/interfaces.py,sha256=rTLVz4odNBMAupBa-hzHXpuqbLouNo06a5W7KyqeimY,874
6
+ codex_platform/notifications/orchestrator.py,sha256=cJw4L9nJ1Lq3iZ55I6UXv4d6ZEALkUUTH5hyL5Tg4v4,3724
7
+ codex_platform/notifications/registry.py,sha256=ZmPxDywCDgwkIGAHSHr_WsHqgfqOcx3rXy_AU77q-AY,2617
8
+ codex_platform/notifications/renderer.py,sha256=2m1RzyNxaax5kcsoxdYKD_xq5eekGOETaieVtNzh40U,3466
9
+ codex_platform/notifications/clients/__init__.py,sha256=DZt0cwla0KlMHpapIUgI1A1_40GU06MrIshT6Hi-bMc,67
10
+ codex_platform/notifications/clients/smtp.py,sha256=GklQktt2-_ZHRDy3sc2w6ySMomjwyOACyettFukwvdw,4090
11
+ codex_platform/notifications/delivery/__init__.py,sha256=2o22-uBJ6Pazp3Z4Z9xXHSLRNU_MQIW-wBXjbIvtA6A,539
12
+ codex_platform/notifications/delivery/arq.py,sha256=j41_m4YSkkMg1nZzAS4SpMEo2pjG88CTRcTTino2lYk,2289
13
+ codex_platform/notifications/delivery/base.py,sha256=PRU80-5DV3zUO8FZ4RBqJXzknJdMlbkHd_WNVchmDlU,1279
14
+ codex_platform/notifications/delivery/direct.py,sha256=Lxp-P6G9J-jo-kwS7itHhZhyPrmxMgMQg9uSLdcKlh8,3241
15
+ codex_platform/redis_service/__init__.py,sha256=SN0e5CdQlqL9QVS984NO15RDH0_mL6eYSY6YjrrEkrY,1359
16
+ codex_platform/redis_service/base.py,sha256=xpIibHar0afaz2uwV8dPZQ7fWCPcP6SkRhxT3_6hSJw,2385
17
+ codex_platform/redis_service/exceptions.py,sha256=7WVBoMae0IczP_000p43MWhKYxYb9W-UgKCedLYyeo4,759
18
+ codex_platform/redis_service/keys.py,sha256=JXlT7NM9E9RqJ4Oyo2tBwaQ0PAz3wvErJ2jkZQnB-4w,3085
19
+ codex_platform/redis_service/service.py,sha256=usgiua76smJA8q6RdByH0Ro7JPrWWDgYCXmxXumUA3I,2783
20
+ codex_platform/redis_service/managers/__init__.py,sha256=aJUv1oL3LAy2Md6EHuBuu1cU6Fys2Qx8Z9n17u8cUIE,560
21
+ codex_platform/redis_service/managers/base_manager.py,sha256=GlYqA-94PcJI-oG_SxAG_n04pb1VDD7y6USAazsg94k,987
22
+ codex_platform/redis_service/operations/__init__.py,sha256=3X_5PEP_-g_QMGLrHnjdgOBwND1nLl49sM9LRcf_RDo,510
23
+ codex_platform/redis_service/operations/hash.py,sha256=9UWWnmVbJgnqkNkC66DZkqN6r8APdkKeGNqAr7glkK8,11120
24
+ codex_platform/redis_service/operations/json_module.py,sha256=LXgndy1XTO1Pokho9hxQXSDS-hd9FjeGzCeSpsWxAnM,4552
25
+ codex_platform/redis_service/operations/json_string.py,sha256=Dh75R_QnL8YHAIIw62qvlh4toBi5MMrLnY5w0rFj0mk,3780
26
+ codex_platform/redis_service/operations/list_.py,sha256=6MHlgDmkw4E7jiDtmLD5AxLoGNI6IrRjhFuX9O8Uy7c,7874
27
+ codex_platform/redis_service/operations/pipeline.py,sha256=lbwoDd97NwoOtKMZP6uJk2qr_UuHT70mBevyK3CYRXY,6796
28
+ codex_platform/redis_service/operations/set_.py,sha256=lFRykixCbW-0iz3BVEPAeyZtQeSIVKOT0IfX_sveEJQ,7356
29
+ codex_platform/redis_service/operations/string.py,sha256=xiXxFoeVg3WwfpOdkPv6VnTz_eiJz14bG3j6lpSyRGg,11041
30
+ codex_platform/redis_service/operations/zset.py,sha256=EGUYWLADUJthtSzWkQUcrIFLzjS-tX06NTkeI8DQUq8,10368
31
+ codex_platform/streams/__init__.py,sha256=qG-VJcpCRJlX62aTYavOttjumjWMf0Jlg5PhTciAjd0,1805
32
+ codex_platform/streams/consumer.py,sha256=4xO_c0NvtQeu6DRbwhXeJdsU43RU-kChvOIZ5UKV9bU,3997
33
+ codex_platform/streams/dispatcher.py,sha256=weePz1_oKTGoyCja1WUU6hBetnqrytdT3HfERE8isq8,5979
34
+ codex_platform/streams/processor.py,sha256=ORFyg8Ado6lgHWBZJroixxo9hnbb_N2actzCxEhUIUI,8042
35
+ codex_platform/streams/producer.py,sha256=AkdRvthL_DtfNMqS0XZgzxNDvU0HKkYxXSciyJAjPgg,2227
36
+ codex_platform/streams/router.py,sha256=T2Oe14G-HP40CDcZ-YwqOy6rSfZavp1TkWSOXmP_ijs,2281
37
+ codex_platform/workers/__init__.py,sha256=lLCwutgqNCeq6CI9y78EcyikRqhyNN_sMgxl0-O2Zt8,65
38
+ codex_platform/workers/arq/__init__.py,sha256=AJMkIuEF722Y9AVRNizlG2u-6PJfBNaPxGINDuMoA6o,589
39
+ codex_platform/workers/arq/base.py,sha256=_rnqQQryr28HrvAaeKEeJ1yFOnSTA4kGEmEkurFqLeg,5692
40
+ codex_platform/workers/arq/config.py,sha256=cYyP6aelo88DgKWeny90i94jMNd_tMTrtcZVkbPrnD8,2218
41
+ codex_platform/workers/arq/task_utils.py,sha256=2hKh-6Lxr9CJePXRdCYIV16OSXlFBP3hJe-9EV5Lvyw,2377
42
+ codex_platform/workers/arq/types.py,sha256=yiiQ-5hnGTEzVs_Ebv3bapvRc9gGBNUHzz7Hi0PV3_o,357
43
+ codex_platform-0.1.0.dist-info/METADATA,sha256=I6zKU__3ypIRettYDiixoQ4PgXh63Cpqa-FO761a8dI,4610
44
+ codex_platform-0.1.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
45
+ codex_platform-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.29.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any