kiarina-lib-redis 1.0.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.
@@ -0,0 +1,27 @@
1
+ import logging
2
+ from importlib import import_module
3
+ from importlib.metadata import version
4
+ from typing import TYPE_CHECKING
5
+
6
+ if TYPE_CHECKING:
7
+ from ._sync.registry import get_redis
8
+ from .settings import settings_manager
9
+
10
+ __version__ = version("kiarina-lib-redis")
11
+
12
+ __all__ = ["get_redis", "settings_manager"]
13
+
14
+ logging.getLogger(__name__).addHandler(logging.NullHandler())
15
+
16
+
17
+ def __getattr__(name: str) -> object:
18
+ if name not in __all__:
19
+ raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
20
+
21
+ module_map = {
22
+ "get_redis": "._sync.registry",
23
+ "settings_manager": ".settings",
24
+ }
25
+
26
+ globals()[name] = getattr(import_module(module_map[name], __name__), name)
27
+ return globals()[name]
File without changes
@@ -0,0 +1,36 @@
1
+ from typing import Any
2
+
3
+ import redis.asyncio as redis
4
+
5
+ from .._core.registry import get_redis as _get_redis
6
+
7
+
8
+ def get_redis(
9
+ config_key: str | None = None,
10
+ *,
11
+ cache_key: str | None = None,
12
+ use_retry: bool | None = None,
13
+ url: str | None = None,
14
+ **kwargs: Any,
15
+ ) -> redis.Redis:
16
+ """
17
+ Get a Redis client.
18
+
19
+ Args:
20
+ config_key (str | None): The configuration key for the Redis client.
21
+ cache_key (str | None): The cache key for the Redis client.
22
+ use_retry (bool | None): Whether to use retry for the Redis client.
23
+ url (str | None): The Redis URL.
24
+ **kwargs: Additional keyword arguments for the Redis client.
25
+
26
+ Returns:
27
+ redis.Redis: The Redis client.
28
+ """
29
+ return _get_redis(
30
+ "async",
31
+ config_key,
32
+ cache_key=cache_key,
33
+ use_retry=use_retry,
34
+ url=url,
35
+ **kwargs,
36
+ )
File without changes
@@ -0,0 +1,101 @@
1
+ from typing import Any, Literal, overload
2
+
3
+ import redis
4
+ import redis.asyncio
5
+ from redis.backoff import ExponentialBackoff
6
+ from redis.retry import Retry
7
+
8
+ from ..settings import settings_manager
9
+
10
+ _sync_cache: dict[str, redis.Redis] = {}
11
+ """
12
+ Sync Redis clients cache
13
+ """
14
+
15
+ _async_cache: dict[str, redis.asyncio.Redis] = {}
16
+ """
17
+ Async Redis clients cache
18
+ """
19
+
20
+
21
+ @overload
22
+ def get_redis(
23
+ mode: Literal["sync"],
24
+ config_key: str | None = None,
25
+ *,
26
+ cache_key: str | None = None,
27
+ use_retry: bool | None = None,
28
+ url: str | None = None,
29
+ **kwargs: Any,
30
+ ) -> redis.Redis: ...
31
+
32
+
33
+ @overload
34
+ def get_redis(
35
+ mode: Literal["async"],
36
+ config_key: str | None = None,
37
+ *,
38
+ cache_key: str | None = None,
39
+ use_retry: bool | None = None,
40
+ url: str | None = None,
41
+ **kwargs: Any,
42
+ ) -> redis.asyncio.Redis: ...
43
+
44
+
45
+ def get_redis(
46
+ mode: Literal["sync", "async"],
47
+ config_key: str | None = None,
48
+ *,
49
+ cache_key: str | None = None,
50
+ use_retry: bool | None = None,
51
+ url: str | None = None,
52
+ **kwargs: Any,
53
+ ) -> redis.Redis | redis.asyncio.Redis:
54
+ """
55
+ Get a Redis client with shared logic.
56
+ """
57
+ settings = settings_manager.get_settings_by_key(config_key)
58
+
59
+ if url is None:
60
+ url = settings.url
61
+
62
+ if use_retry is None:
63
+ use_retry = settings.use_retry
64
+
65
+ params = {**settings.initialize_params, **kwargs}
66
+
67
+ if use_retry:
68
+ params.update(
69
+ {
70
+ "socket_timeout": settings.socket_timeout,
71
+ "socket_connect_timeout": settings.socket_connect_timeout,
72
+ "health_check_interval": settings.health_check_interval,
73
+ "retry": Retry(
74
+ ExponentialBackoff(cap=settings.retry_delay),
75
+ settings.retry_attempts,
76
+ ),
77
+ }
78
+ )
79
+
80
+ if mode == "sync":
81
+ params["retry_on_error"] = [redis.ConnectionError, redis.TimeoutError]
82
+ else:
83
+ params["retry_on_error"] = [
84
+ redis.asyncio.ConnectionError,
85
+ redis.asyncio.TimeoutError,
86
+ ]
87
+
88
+ if cache_key is None:
89
+ cache_key = url
90
+
91
+ if mode == "sync":
92
+ if cache_key not in _sync_cache:
93
+ _sync_cache[cache_key] = redis.Redis.from_url(url, **params)
94
+
95
+ return _sync_cache[cache_key]
96
+
97
+ else:
98
+ if cache_key not in _async_cache:
99
+ _async_cache[cache_key] = redis.asyncio.Redis.from_url(url, **params)
100
+
101
+ return _async_cache[cache_key]
File without changes
@@ -0,0 +1,36 @@
1
+ from typing import Any
2
+
3
+ import redis
4
+
5
+ from .._core.registry import get_redis as _get_redis
6
+
7
+
8
+ def get_redis(
9
+ config_key: str | None = None,
10
+ *,
11
+ cache_key: str | None = None,
12
+ use_retry: bool | None = None,
13
+ url: str | None = None,
14
+ **kwargs: Any,
15
+ ) -> redis.Redis:
16
+ """
17
+ Get a Redis client.
18
+
19
+ Args:
20
+ config_key (str | None): The configuration key for the Redis client.
21
+ cache_key (str | None): The cache key for the Redis client.
22
+ use_retry (bool | None): Whether to use retry for the Redis client.
23
+ url (str | None): The Redis URL.
24
+ **kwargs: Additional keyword arguments for the Redis client.
25
+
26
+ Returns:
27
+ redis.Redis: The Redis client.
28
+ """
29
+ return _get_redis(
30
+ "sync",
31
+ config_key,
32
+ cache_key=cache_key,
33
+ use_retry=use_retry,
34
+ url=url,
35
+ **kwargs,
36
+ )
@@ -0,0 +1,25 @@
1
+ import logging
2
+ from importlib import import_module
3
+ from typing import TYPE_CHECKING
4
+
5
+ if TYPE_CHECKING:
6
+ from ._async.registry import get_redis
7
+ from .settings import settings_manager
8
+
9
+ __all__ = ["get_redis", "settings_manager"]
10
+
11
+ logging.getLogger(__name__).addHandler(logging.NullHandler())
12
+
13
+
14
+ def __getattr__(name: str) -> object:
15
+ if name not in __all__:
16
+ raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
17
+
18
+ module_map = {
19
+ "get_redis": "._async.registry",
20
+ "settings_manager": ".settings",
21
+ }
22
+
23
+ parent = __name__.rsplit(".", 1)[0]
24
+ globals()[name] = getattr(import_module(module_map[name], parent), name)
25
+ return globals()[name]
File without changes
@@ -0,0 +1,70 @@
1
+ from typing import Any
2
+
3
+ from pydantic import Field
4
+ from pydantic_settings import BaseSettings, SettingsConfigDict
5
+ from pydantic_settings_manager import SettingsManager
6
+
7
+
8
+ class RedisSettings(BaseSettings):
9
+ """
10
+ Redis Settings
11
+ """
12
+
13
+ model_config = SettingsConfigDict(env_prefix="KIARINA_LIB_REDIS_")
14
+
15
+ url: str = "redis://localhost:6379"
16
+ """
17
+ Redis URL
18
+
19
+ Example:
20
+ - redis://[[username]:[password]]@localhost:6379
21
+ - rediss://[[username]:[password]]@localhost:6379
22
+ """
23
+
24
+ initialize_params: dict[str, Any] = Field(default_factory=dict)
25
+ """
26
+ Additional parameters to initialize the Redis client.
27
+ """
28
+
29
+ use_retry: bool = False
30
+ """
31
+ Whether to enable automatic retries
32
+
33
+ When enabled, it is configured to retry upon occurrence of
34
+ redis.ConnectionError or redis.TimeoutError.
35
+ """
36
+
37
+ socket_timeout: float = 6.0
38
+ """
39
+ Socket timeout in seconds
40
+
41
+ After sending a command, if this time is exceeded, a redis.TimeoutError will be raised.
42
+ """
43
+
44
+ socket_connect_timeout: float = 3.0
45
+ """
46
+ Socket connection timeout in seconds
47
+
48
+ If this time is exceeded when establishing a new connection, a redis.ConnectionError will occur.
49
+ """
50
+
51
+ health_check_interval: int = 60
52
+ """
53
+ Health check interval in seconds
54
+
55
+ When acquiring a connection from the pool,
56
+ if the time since last use has elapsed, execute a PING to verify the connection status.
57
+ """
58
+
59
+ retry_attempts: int = 3
60
+ """
61
+ Number of retry attempts
62
+ """
63
+
64
+ retry_delay: float = 1.0
65
+ """
66
+ Delay between retry attempts in seconds
67
+ """
68
+
69
+
70
+ settings_manager = SettingsManager(RedisSettings, multi=True)
@@ -0,0 +1,280 @@
1
+ Metadata-Version: 2.4
2
+ Name: kiarina-lib-redis
3
+ Version: 1.0.0
4
+ Summary: Redis client library for kiarina namespace
5
+ Project-URL: Homepage, https://github.com/kiarina/kiarina-python
6
+ Project-URL: Repository, https://github.com/kiarina/kiarina-python
7
+ Project-URL: Issues, https://github.com/kiarina/kiarina-python/issues
8
+ Project-URL: Changelog, https://github.com/kiarina/kiarina-python/blob/main/packages/kiarina-lib-redis/CHANGELOG.md
9
+ Project-URL: Documentation, https://github.com/kiarina/kiarina-python/tree/main/packages/kiarina-lib-redis#readme
10
+ Author-email: kiarina <kiarinadawa@gmail.com>
11
+ Maintainer-email: kiarina <kiarinadawa@gmail.com>
12
+ License: MIT
13
+ Keywords: async,cache,client,database,pydantic,redis,settings
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Database
22
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
+ Classifier: Typing :: Typed
24
+ Requires-Python: >=3.12
25
+ Requires-Dist: pydantic-settings-manager>=2.1.0
26
+ Requires-Dist: pydantic-settings>=2.10.1
27
+ Requires-Dist: redis>=6.4.0
28
+ Description-Content-Type: text/markdown
29
+
30
+ # kiarina-lib-redis
31
+
32
+ A Python client library for [Redis](https://redis.io/) with configuration management and connection pooling.
33
+
34
+ ## Features
35
+
36
+ - **Configuration Management**: Use `pydantic-settings-manager` for flexible configuration
37
+ - **Connection Pooling**: Automatic connection caching and reuse
38
+ - **Retry Support**: Built-in retry mechanism for connection failures
39
+ - **Sync & Async**: Support for both synchronous and asynchronous operations
40
+ - **Type Safety**: Full type hints and Pydantic validation
41
+
42
+ ## Installation
43
+
44
+ ```bash
45
+ pip install kiarina-lib-redis
46
+ ```
47
+
48
+ ## Quick Start
49
+
50
+ ### Basic Usage (Sync)
51
+
52
+ ```python
53
+ from kiarina.lib.redis import get_redis
54
+
55
+ # Get a Redis client with default settings
56
+ redis = get_redis()
57
+
58
+ # Basic operations
59
+ redis.set("key", "value")
60
+ value = redis.get("key")
61
+ print(value) # b'value'
62
+
63
+ # With decode_responses=True for string values
64
+ redis = get_redis(decode_responses=True)
65
+ redis.set("key", "value")
66
+ value = redis.get("key")
67
+ print(value) # 'value'
68
+ ```
69
+
70
+ ### Async Usage
71
+
72
+ ```python
73
+ from kiarina.lib.redis.asyncio import get_redis
74
+
75
+ async def main():
76
+ # Get an async Redis client
77
+ redis = get_redis(decode_responses=True)
78
+
79
+ # Basic operations
80
+ await redis.set("key", "value")
81
+ value = await redis.get("key")
82
+ print(value) # 'value'
83
+ ```
84
+
85
+ ## Configuration
86
+
87
+ This library uses [pydantic-settings-manager](https://github.com/kiarina/pydantic-settings-manager) for flexible configuration management.
88
+
89
+ ### Environment Variables
90
+
91
+ Configure the Redis connection using environment variables:
92
+
93
+ ```bash
94
+ # Redis connection URL
95
+ export KIARINA_LIB_REDIS_URL="redis://localhost:6379"
96
+
97
+ # Enable retry mechanism
98
+ export KIARINA_LIB_REDIS_USE_RETRY="true"
99
+
100
+ # Timeout settings
101
+ export KIARINA_LIB_REDIS_SOCKET_TIMEOUT="6.0"
102
+ export KIARINA_LIB_REDIS_SOCKET_CONNECT_TIMEOUT="3.0"
103
+
104
+ # Retry settings
105
+ export KIARINA_LIB_REDIS_RETRY_ATTEMPTS="3"
106
+ export KIARINA_LIB_REDIS_RETRY_DELAY="1.0"
107
+ ```
108
+
109
+ ### Programmatic Configuration
110
+
111
+ ```python
112
+ from kiarina.lib.redis import settings_manager
113
+
114
+ # Configure for multiple environments
115
+ settings_manager.user_config = {
116
+ "development": {
117
+ "url": "redis://localhost:6379",
118
+ "use_retry": True,
119
+ "retry_attempts": 3
120
+ },
121
+ "production": {
122
+ "url": "redis://prod-server:6379",
123
+ "use_retry": True,
124
+ "retry_attempts": 5,
125
+ "socket_timeout": 10.0
126
+ }
127
+ }
128
+
129
+ # Switch to production configuration
130
+ settings_manager.active_key = "production"
131
+ redis = get_redis()
132
+ ```
133
+
134
+ ### Runtime Overrides
135
+
136
+ ```python
137
+ from kiarina.lib.redis import get_redis
138
+
139
+ # Override settings at runtime
140
+ redis = get_redis(
141
+ url="redis://custom-server:6379",
142
+ use_retry=True,
143
+ decode_responses=True
144
+ )
145
+ ```
146
+
147
+ ## Advanced Usage
148
+
149
+ ### Connection Caching
150
+
151
+ ```python
152
+ from kiarina.lib.redis import get_redis
153
+
154
+ # These will return the same cached connection
155
+ redis1 = get_redis()
156
+ redis2 = get_redis()
157
+ assert redis1 is redis2
158
+
159
+ # Use different cache keys for separate connections
160
+ redis3 = get_redis(cache_key="secondary")
161
+ assert redis1 is not redis3
162
+ ```
163
+
164
+ ### Custom Configuration Keys
165
+
166
+ ```python
167
+ from kiarina.lib.redis import settings_manager, get_redis
168
+
169
+ # Configure multiple named configurations
170
+ settings_manager.user_config = {
171
+ "cache": {
172
+ "url": "redis://cache-db:6379",
173
+ "socket_timeout": 5.0
174
+ },
175
+ "session": {
176
+ "url": "redis://session-db:6379",
177
+ "socket_timeout": 10.0
178
+ }
179
+ }
180
+
181
+ # Use specific configurations
182
+ cache_redis = get_redis("cache")
183
+ session_redis = get_redis("session")
184
+ ```
185
+
186
+ ### Error Handling and Retries
187
+
188
+ ```python
189
+ from kiarina.lib.redis import get_redis
190
+ import redis
191
+
192
+ # Enable automatic retries for connection issues
193
+ redis_client = get_redis(use_retry=True)
194
+
195
+ try:
196
+ redis_client.set("key", "value")
197
+ value = redis_client.get("key")
198
+ except redis.ConnectionError as e:
199
+ print(f"Connection failed: {e}")
200
+ except redis.TimeoutError as e:
201
+ print(f"Operation timed out: {e}")
202
+ ```
203
+
204
+ ## Configuration Reference
205
+
206
+ | Setting | Environment Variable | Default | Description |
207
+ |---------|---------------------|---------|-------------|
208
+ | `url` | `KIARINA_LIB_REDIS_URL` | `"redis://localhost:6379"` | Redis connection URL |
209
+ | `use_retry` | `KIARINA_LIB_REDIS_USE_RETRY` | `false` | Enable automatic retries |
210
+ | `socket_timeout` | `KIARINA_LIB_REDIS_SOCKET_TIMEOUT` | `6.0` | Socket timeout in seconds |
211
+ | `socket_connect_timeout` | `KIARINA_LIB_REDIS_SOCKET_CONNECT_TIMEOUT` | `3.0` | Connection timeout in seconds |
212
+ | `health_check_interval` | `KIARINA_LIB_REDIS_HEALTH_CHECK_INTERVAL` | `60` | Health check interval in seconds |
213
+ | `retry_attempts` | `KIARINA_LIB_REDIS_RETRY_ATTEMPTS` | `3` | Number of retry attempts |
214
+ | `retry_delay` | `KIARINA_LIB_REDIS_RETRY_DELAY` | `1.0` | Delay between retries in seconds |
215
+
216
+ ## URL Formats
217
+
218
+ Redis URLs support the following formats:
219
+
220
+ - `redis://localhost:6379` - Basic connection
221
+ - `redis://username:password@localhost:6379` - With authentication
222
+ - `rediss://localhost:6379` - SSL/TLS connection
223
+ - `rediss://username:password@localhost:6379` - SSL/TLS with authentication
224
+ - `redis://localhost:6379/0` - Specify database number
225
+ - `unix:///path/to/socket.sock` - Unix socket connection
226
+
227
+ ## Development
228
+
229
+ ### Prerequisites
230
+
231
+ - Python 3.12+
232
+ - Docker (for running Redis in tests)
233
+
234
+ ### Setup
235
+
236
+ ```bash
237
+ # Clone the repository
238
+ git clone https://github.com/kiarina/kiarina-python.git
239
+ cd kiarina-python
240
+
241
+ # Setup development environment (installs tools, syncs dependencies, downloads test data)
242
+ mise run setup
243
+
244
+ # Start Redis for testing
245
+ docker compose up -d redis
246
+ ```
247
+
248
+ ### Running Tests
249
+
250
+ ```bash
251
+ # Run format, lint, type checks and tests
252
+ mise run package kiarina-lib-redis
253
+
254
+ # Coverage report
255
+ mise run package:test kiarina-lib-redis --coverage
256
+
257
+ # Run specific tests
258
+ uv run --group test pytest packages/kiarina-lib-redis/tests/test_sync.py
259
+ uv run --group test pytest packages/kiarina-lib-redis/tests/test_async.py
260
+ ```
261
+
262
+ ## Dependencies
263
+
264
+ - [redis](https://github.com/redis/redis-py) - Redis client for Python
265
+ - [pydantic-settings](https://docs.pydantic.dev/latest/concepts/pydantic_settings/) - Settings management
266
+ - [pydantic-settings-manager](https://github.com/kiarina/pydantic-settings-manager) - Advanced settings management
267
+
268
+ ## License
269
+
270
+ This project is licensed under the MIT License - see the [LICENSE](../../LICENSE) file for details.
271
+
272
+ ## Contributing
273
+
274
+ This is a personal project, but contributions are welcome! Please feel free to submit issues or pull requests.
275
+
276
+ ## Related Projects
277
+
278
+ - [kiarina-python](https://github.com/kiarina/kiarina-python) - The main monorepo containing this package
279
+ - [Redis](https://redis.io/) - The in-memory data structure store this library connects to
280
+ - [pydantic-settings-manager](https://github.com/kiarina/pydantic-settings-manager) - Configuration management library used by this package
@@ -0,0 +1,13 @@
1
+ kiarina/lib/redis/__init__.py,sha256=ryMfPJYw8-TKcyG-NhZZHZ47UeTC2A94mzENlwjxR50,740
2
+ kiarina/lib/redis/asyncio.py,sha256=1khCmaPAPemFIxozT9ymY9w3a3etMfQAy7pImLztBzM,697
3
+ kiarina/lib/redis/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ kiarina/lib/redis/settings.py,sha256=NQtWauZjurSAASVrOu4qvZzlRvxW_9Gmo-mIpyBYHHo,1675
5
+ kiarina/lib/redis/_async/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ kiarina/lib/redis/_async/registry.py,sha256=uO3MYcadjBqHbwOMlcIdo4TN-mofm6u3kWRv96v3K_g,895
7
+ kiarina/lib/redis/_core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ kiarina/lib/redis/_core/registry.py,sha256=uFRYkTTT4GmDZ_LzHysUT_q6sXb_HO6o_3zk127LWtE,2495
9
+ kiarina/lib/redis/_sync/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ kiarina/lib/redis/_sync/registry.py,sha256=yIgZFQu580oD_t2z3-Rs6jfAmBRmpHjxpTX8VICvyGo,877
11
+ kiarina_lib_redis-1.0.0.dist-info/METADATA,sha256=vODAiV6MSSapXnZXlJZzHLwyva3gnV4vnBOdoAJ7rXQ,8126
12
+ kiarina_lib_redis-1.0.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
13
+ kiarina_lib_redis-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.27.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any