python3-commons 0.22.5__tar.gz → 0.22.6__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 (84) hide show
  1. {python3_commons-0.22.5 → python3_commons-0.22.6}/.pre-commit-config.yaml +2 -2
  2. python3_commons-0.22.6/PKG-INFO +310 -0
  3. python3_commons-0.22.6/README.md +244 -0
  4. python3_commons-0.22.6/README.rst +260 -0
  5. {python3_commons-0.22.5 → python3_commons-0.22.6}/pyproject.toml +2 -2
  6. python3_commons-0.22.6/src/python3_commons.egg-info/PKG-INFO +310 -0
  7. {python3_commons-0.22.5 → python3_commons-0.22.6}/src/python3_commons.egg-info/SOURCES.txt +2 -0
  8. {python3_commons-0.22.5 → python3_commons-0.22.6}/src/python3_commons.egg-info/requires.txt +2 -2
  9. python3_commons-0.22.6/src/python3_commons.egg-info/scm_file_list.json +75 -0
  10. python3_commons-0.22.6/src/python3_commons.egg-info/scm_version.json +8 -0
  11. {python3_commons-0.22.5 → python3_commons-0.22.6}/uv.lock +153 -153
  12. python3_commons-0.22.5/PKG-INFO +0 -54
  13. python3_commons-0.22.5/README.md +0 -2
  14. python3_commons-0.22.5/README.rst +0 -4
  15. python3_commons-0.22.5/src/python3_commons.egg-info/PKG-INFO +0 -54
  16. {python3_commons-0.22.5 → python3_commons-0.22.6}/.coveragerc +0 -0
  17. {python3_commons-0.22.5 → python3_commons-0.22.6}/.devcontainer/Dockerfile +0 -0
  18. {python3_commons-0.22.5 → python3_commons-0.22.6}/.devcontainer/devcontainer.json +0 -0
  19. {python3_commons-0.22.5 → python3_commons-0.22.6}/.devcontainer/docker-compose.yml +0 -0
  20. {python3_commons-0.22.5 → python3_commons-0.22.6}/.env_template +0 -0
  21. {python3_commons-0.22.5 → python3_commons-0.22.6}/.github/workflows/checks.yml +0 -0
  22. {python3_commons-0.22.5 → python3_commons-0.22.6}/.github/workflows/python-publish.yaml +0 -0
  23. {python3_commons-0.22.5 → python3_commons-0.22.6}/.github/workflows/release-on-tag-push.yml +0 -0
  24. {python3_commons-0.22.5 → python3_commons-0.22.6}/.gitignore +0 -0
  25. {python3_commons-0.22.5 → python3_commons-0.22.6}/.python-version +0 -0
  26. {python3_commons-0.22.5 → python3_commons-0.22.6}/AUTHORS.rst +0 -0
  27. {python3_commons-0.22.5 → python3_commons-0.22.6}/CHANGELOG.rst +0 -0
  28. {python3_commons-0.22.5 → python3_commons-0.22.6}/LICENSE +0 -0
  29. {python3_commons-0.22.5 → python3_commons-0.22.6}/docs/Makefile +0 -0
  30. {python3_commons-0.22.5 → python3_commons-0.22.6}/docs/_static/.gitignore +0 -0
  31. {python3_commons-0.22.5 → python3_commons-0.22.6}/docs/authors.rst +0 -0
  32. {python3_commons-0.22.5 → python3_commons-0.22.6}/docs/changelog.rst +0 -0
  33. {python3_commons-0.22.5 → python3_commons-0.22.6}/docs/conf.py +0 -0
  34. {python3_commons-0.22.5 → python3_commons-0.22.6}/docs/index.rst +0 -0
  35. {python3_commons-0.22.5 → python3_commons-0.22.6}/docs/license.rst +0 -0
  36. {python3_commons-0.22.5 → python3_commons-0.22.6}/setup.cfg +0 -0
  37. {python3_commons-0.22.5 → python3_commons-0.22.6}/src/python3_commons/__init__.py +0 -0
  38. {python3_commons-0.22.5 → python3_commons-0.22.6}/src/python3_commons/api_client.py +0 -0
  39. {python3_commons-0.22.5 → python3_commons-0.22.6}/src/python3_commons/async_functools.py +0 -0
  40. {python3_commons-0.22.5 → python3_commons-0.22.6}/src/python3_commons/audit.py +0 -0
  41. {python3_commons-0.22.5 → python3_commons-0.22.6}/src/python3_commons/auth.py +0 -0
  42. {python3_commons-0.22.5 → python3_commons-0.22.6}/src/python3_commons/cache.py +0 -0
  43. {python3_commons-0.22.5 → python3_commons-0.22.6}/src/python3_commons/conf.py +0 -0
  44. {python3_commons-0.22.5 → python3_commons-0.22.6}/src/python3_commons/db/__init__.py +0 -0
  45. {python3_commons-0.22.5 → python3_commons-0.22.6}/src/python3_commons/db/helpers.py +0 -0
  46. {python3_commons-0.22.5 → python3_commons-0.22.6}/src/python3_commons/db/models/__init__.py +0 -0
  47. {python3_commons-0.22.5 → python3_commons-0.22.6}/src/python3_commons/db/models/auth.py +0 -0
  48. {python3_commons-0.22.5 → python3_commons-0.22.6}/src/python3_commons/db/models/common.py +0 -0
  49. {python3_commons-0.22.5 → python3_commons-0.22.6}/src/python3_commons/db/models/rbac.py +0 -0
  50. {python3_commons-0.22.5 → python3_commons-0.22.6}/src/python3_commons/db/models/users.py +0 -0
  51. {python3_commons-0.22.5 → python3_commons-0.22.6}/src/python3_commons/exceptions.py +0 -0
  52. {python3_commons-0.22.5 → python3_commons-0.22.6}/src/python3_commons/fs.py +0 -0
  53. {python3_commons-0.22.5 → python3_commons-0.22.6}/src/python3_commons/generators.py +0 -0
  54. {python3_commons-0.22.5 → python3_commons-0.22.6}/src/python3_commons/helpers.py +0 -0
  55. {python3_commons-0.22.5 → python3_commons-0.22.6}/src/python3_commons/log/__init__.py +0 -0
  56. {python3_commons-0.22.5 → python3_commons-0.22.6}/src/python3_commons/log/filters.py +0 -0
  57. {python3_commons-0.22.5 → python3_commons-0.22.6}/src/python3_commons/log/formatters.py +0 -0
  58. {python3_commons-0.22.5 → python3_commons-0.22.6}/src/python3_commons/object_storage.py +0 -0
  59. {python3_commons-0.22.5 → python3_commons-0.22.6}/src/python3_commons/permissions.py +0 -0
  60. {python3_commons-0.22.5 → python3_commons-0.22.6}/src/python3_commons/serializers/__init__.py +0 -0
  61. {python3_commons-0.22.5 → python3_commons-0.22.6}/src/python3_commons/serializers/common.py +0 -0
  62. {python3_commons-0.22.5 → python3_commons-0.22.6}/src/python3_commons/serializers/json.py +0 -0
  63. {python3_commons-0.22.5 → python3_commons-0.22.6}/src/python3_commons/serializers/msgpack.py +0 -0
  64. {python3_commons-0.22.5 → python3_commons-0.22.6}/src/python3_commons/serializers/msgspec.py +0 -0
  65. {python3_commons-0.22.5 → python3_commons-0.22.6}/src/python3_commons/soap_client.py +0 -0
  66. {python3_commons-0.22.5 → python3_commons-0.22.6}/src/python3_commons.egg-info/dependency_links.txt +0 -0
  67. {python3_commons-0.22.5 → python3_commons-0.22.6}/src/python3_commons.egg-info/top_level.txt +0 -0
  68. {python3_commons-0.22.5 → python3_commons-0.22.6}/tests/__init__.py +0 -0
  69. {python3_commons-0.22.5 → python3_commons-0.22.6}/tests/integration/__init__.py +0 -0
  70. {python3_commons-0.22.5 → python3_commons-0.22.6}/tests/integration/conftest.py +0 -0
  71. {python3_commons-0.22.5 → python3_commons-0.22.6}/tests/integration/test_auth.py +0 -0
  72. {python3_commons-0.22.5 → python3_commons-0.22.6}/tests/integration/test_cache.py +0 -0
  73. {python3_commons-0.22.5 → python3_commons-0.22.6}/tests/integration/test_osc.py +0 -0
  74. {python3_commons-0.22.5 → python3_commons-0.22.6}/tests/unit/__init__.py +0 -0
  75. {python3_commons-0.22.5 → python3_commons-0.22.6}/tests/unit/conftest.py +0 -0
  76. {python3_commons-0.22.5 → python3_commons-0.22.6}/tests/unit/db/__init__.py +0 -0
  77. {python3_commons-0.22.5 → python3_commons-0.22.6}/tests/unit/db/test_async_session_manager.py +0 -0
  78. {python3_commons-0.22.5 → python3_commons-0.22.6}/tests/unit/log/__init__.py +0 -0
  79. {python3_commons-0.22.5 → python3_commons-0.22.6}/tests/unit/log/test_formatters.py +0 -0
  80. {python3_commons-0.22.5 → python3_commons-0.22.6}/tests/unit/test_async_functools.py +0 -0
  81. {python3_commons-0.22.5 → python3_commons-0.22.6}/tests/unit/test_audit.py +0 -0
  82. {python3_commons-0.22.5 → python3_commons-0.22.6}/tests/unit/test_helpers.py +0 -0
  83. {python3_commons-0.22.5 → python3_commons-0.22.6}/tests/unit/test_msgpack.py +0 -0
  84. {python3_commons-0.22.5 → python3_commons-0.22.6}/tests/unit/test_msgspec.py +0 -0
@@ -1,12 +1,12 @@
1
1
  repos:
2
2
  - repo: https://github.com/astral-sh/uv-pre-commit
3
- rev: 0.11.21
3
+ rev: 0.11.24
4
4
  hooks:
5
5
  - id: uv-lock
6
6
  # - id: uv-export
7
7
 
8
8
  - repo: https://github.com/astral-sh/ruff-pre-commit
9
- rev: v0.15.17
9
+ rev: v0.15.20
10
10
  hooks:
11
11
  # Run the linter.
12
12
  - id: ruff-check
@@ -0,0 +1,310 @@
1
+ Metadata-Version: 2.4
2
+ Name: python3-commons
3
+ Version: 0.22.6
4
+ Summary: Re-usable Python3 code
5
+ Author-email: Oleg Korsak <kamikaze.is.waiting.you@gmail.com>
6
+ License-Expression: GPL-3.0
7
+ Project-URL: Homepage, https://github.com/kamikaze/python3-commons
8
+ Project-URL: Documentation, https://github.com/kamikaze/python3-commons/wiki
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Programming Language :: Python
11
+ Requires-Python: <3.15.0,>=3.14.0
12
+ Description-Content-Type: text/x-rst
13
+ License-File: LICENSE
14
+ License-File: AUTHORS.rst
15
+ Requires-Dist: msgpack~=1.2.1
16
+ Requires-Dist: msgspec~=0.21.1
17
+ Requires-Dist: pydantic-settings~=2.14.2
18
+ Provides-Extra: all
19
+ Requires-Dist: python3_commons[api-client,audit,authn,authz,cache,database,object-storage,soap-client]; extra == "all"
20
+ Provides-Extra: api-client
21
+ Requires-Dist: aiohttp[speedups]<3.15.0,>=3.14.1; extra == "api-client"
22
+ Requires-Dist: certifi~=2026.6.17; extra == "api-client"
23
+ Requires-Dist: python3_commons[audit,object-storage]; extra == "api-client"
24
+ Provides-Extra: audit
25
+ Requires-Dist: lxml~=6.1.1; extra == "audit"
26
+ Requires-Dist: zeep[async]~=4.3.3; extra == "audit"
27
+ Requires-Dist: python3_commons[object-storage]; extra == "audit"
28
+ Provides-Extra: authn
29
+ Requires-Dist: aiohttp[speedups]<3.15.0,>=3.14.1; extra == "authn"
30
+ Requires-Dist: certifi~=2026.6.17; extra == "authn"
31
+ Requires-Dist: python3_commons[api-client]; extra == "authn"
32
+ Provides-Extra: authz
33
+ Requires-Dist: python3_commons[database]; extra == "authz"
34
+ Requires-Dist: python3_commons[api-client]; extra == "authz"
35
+ Provides-Extra: cache
36
+ Requires-Dist: valkey[libvalkey]~=6.1.1; extra == "cache"
37
+ Provides-Extra: database
38
+ Requires-Dist: asyncpg~=0.31.0; extra == "database"
39
+ Requires-Dist: SQLAlchemy[asyncio]~=2.0.51; extra == "database"
40
+ Provides-Extra: object-storage
41
+ Requires-Dist: aiobotocore~=3.7.0; extra == "object-storage"
42
+ Requires-Dist: object-storage-client~=0.0.38; extra == "object-storage"
43
+ Provides-Extra: soap-client
44
+ Requires-Dist: aiohttp[speedups]<3.15.0,>=3.14.1; extra == "soap-client"
45
+ Requires-Dist: certifi~=2026.6.17; extra == "soap-client"
46
+ Requires-Dist: lxml~=6.1.1; extra == "soap-client"
47
+ Requires-Dist: requests~=2.34.2; extra == "soap-client"
48
+ Requires-Dist: zeep[async]~=4.3.3; extra == "soap-client"
49
+ Dynamic: license-file
50
+
51
+ Re-usable Python3 code
52
+ ======================
53
+
54
+ Re-usable code for Python 3 projects.
55
+
56
+ Installation
57
+ ------------
58
+
59
+ .. code-block:: bash
60
+
61
+ uv add python3-commons
62
+
63
+ Optional Dependencies
64
+ ~~~~~~~~~~~~~~~~~~~~~
65
+
66
+ Some features require extra dependencies. You can install them individually or all at once:
67
+
68
+ - ``api-client``: For ``python3_commons.api_client``
69
+ - ``audit``: For ``python3_commons.audit``
70
+ - ``authn``: For ``python3_commons.auth``
71
+ - ``authz``: For ``python3_commons.permissions``
72
+ - ``cache``: For ``python3_commons.cache``
73
+ - ``database``: For ``python3_commons.db``
74
+ - ``object-storage``: For ``python3_commons.object_storage``
75
+ - ``soap-client``: For ``python3_commons.soap_client``
76
+ - ``all``: Install all optional dependencies
77
+
78
+ .. code-block:: bash
79
+
80
+ uv add "python3-commons[all]"
81
+
82
+ Features
83
+ --------
84
+
85
+ Async LRU Cache
86
+ ~~~~~~~~~~~~~~~
87
+
88
+ An LRU cache decorator for asynchronous functions that handles ``await`` and prevents the dogpile effect (mitigating multiple concurrent calls for the same key by waiting for the first one to finish).
89
+
90
+ .. code-block:: python
91
+
92
+ from python3_commons.async_functools import async_lru_cache
93
+
94
+ @async_lru_cache(maxsize=128)
95
+ async def fetch_expensive_data(item_id: int):
96
+ # This function will only be called once for a given item_id
97
+ # even if multiple tasks await it simultaneously.
98
+ return await db.get(item_id)
99
+
100
+ # Usage
101
+ result = await fetch_expensive_data(42)
102
+
103
+ API Client
104
+ ~~~~~~~~~~
105
+
106
+ A context manager for ``aiohttp`` requests with built-in audit logging to S3 and standardized error mapping to Python exceptions.
107
+
108
+ .. code-block:: python
109
+
110
+ from python3_commons.api_client import request
111
+ from aiohttp import ClientSession
112
+
113
+ async with ClientSession() as session:
114
+ async with request(
115
+ session,
116
+ base_url="https://api.example.com",
117
+ uri="/data",
118
+ method="get",
119
+ audit_name="my_service_audit"
120
+ ) as response:
121
+ data = await response.json()
122
+
123
+ SOAP Client
124
+ ~~~~~~~~~~~
125
+
126
+ Async SOAP client support for ``zeep`` with S3 auditing capabilities.
127
+
128
+ .. code-block:: python
129
+
130
+ from python3_commons.soap_client import soap_client
131
+
132
+ async with soap_client("https://example.com/service?wsdl") as client:
133
+ result = await client.service.GetData(id=42)
134
+
135
+ Database Management
136
+ ~~~~~~~~~~~~~~~~~~~
137
+
138
+ SQLAlchemy async engine and session management with pool tuning, health checks, and dynamic query builders.
139
+
140
+ .. code-block:: python
141
+
142
+ from python3_commons.db import AsyncSessionManager
143
+ from python3_commons.conf import DBSettings
144
+
145
+ # Configuration
146
+ configs = {"default": DBSettings(dsn="postgresql+asyncpg://user:pass@localhost/db")}
147
+ manager = AsyncSessionManager(configs)
148
+
149
+ # Usage
150
+ async with manager.get_session_context("default") as session:
151
+ result = await session.execute(...)
152
+
153
+ # Health check
154
+ from python3_commons.db import is_healthy
155
+ await is_healthy(manager.get_engine("default"))
156
+
157
+ Object Storage
158
+ ~~~~~~~~~~~~~~
159
+
160
+ Utilities for async S3 operations using ``aiobotocore``.
161
+
162
+ .. code-block:: python
163
+
164
+ from python3_commons import object_storage
165
+ import io
166
+
167
+ # Upload an object
168
+ await object_storage.put_object(
169
+ bucket_name="my-bucket",
170
+ path="uploads/file.txt",
171
+ data=io.BytesIO(b"Hello World"),
172
+ length=11
173
+ )
174
+
175
+ # Download an object
176
+ content = await object_storage.get_object("my-bucket", "uploads/file.txt")
177
+
178
+ # List objects
179
+ async for obj in object_storage.list_objects("my-bucket", "uploads/"):
180
+ print(obj['Key'])
181
+
182
+ OIDC Authentication
183
+ ~~~~~~~~~~~~~~~~~~~
184
+
185
+ Client for OpenID Connect authentication, supporting configuration fetching, JWKS, and token acquisition.
186
+
187
+ .. code-block:: python
188
+
189
+ from python3_commons.auth import OIDCClient
190
+ from pydantic import HttpUrl
191
+
192
+ client = OIDCClient(
193
+ authority_url=HttpUrl("https://auth.example.com/realms/myrealm"),
194
+ client_id="my-app-client",
195
+ client_secret="secret"
196
+ )
197
+
198
+ async with client:
199
+ token_response = await client.fetch_token(username="user", password="password")
200
+ print(token_response.access_token)
201
+
202
+ Valkey Cache
203
+ ~~~~~~~~~~~~
204
+
205
+ Async caching using Valkey (Redis-compatible) with automatic Msgpack serialization for complex types.
206
+
207
+ .. code-block:: python
208
+
209
+ from python3_commons import cache
210
+
211
+ # Store a dictionary
212
+ await cache.store("user:123", {"name": "Alice", "role": "admin"}, ttl=3600)
213
+
214
+ # Retrieve it
215
+ user_data = await cache.get("user:123")
216
+
217
+ # Set operations
218
+ await cache.add_set_item("active_users", "user:123")
219
+ is_active = await cache.has_set_item("active_users", "user:123")
220
+
221
+ Structured Logging
222
+ ~~~~~~~~~~~~~~~~~~
223
+
224
+ A ``JSONFormatter`` for structured logging, compatible with standard Python ``logging``.
225
+
226
+ .. code-block:: python
227
+
228
+ import logging
229
+ from python3_commons.log.formatters import JSONFormatter
230
+
231
+ handler = logging.StreamHandler()
232
+ handler.setFormatter(JSONFormatter())
233
+ logging.getLogger().addHandler(handler)
234
+
235
+ logger = logging.getLogger("app")
236
+ logger.info("User logged in", extra={"user_id": "abc-123", "ip": "1.2.3.4"})
237
+
238
+ Serialization
239
+ ~~~~~~~~~~~~~
240
+
241
+ Enhanced JSON and Msgpack serialization for types not handled by default (Decimal, datetime, date, dataclasses, Pydantic models).
242
+
243
+ .. code-block:: python
244
+
245
+ from python3_commons.serializers.msgspec import serialize_msgpack, deserialize_msgpack
246
+ from decimal import Decimal
247
+ from datetime import datetime
248
+
249
+ data = {
250
+ "amount": Decimal("150.75"),
251
+ "timestamp": datetime.now(),
252
+ "tags": {"finance", "internal"}
253
+ }
254
+
255
+ # Serialize to Msgpack
256
+ binary = serialize_msgpack(data)
257
+
258
+ # Deserialize back
259
+ restored = deserialize_msgpack(binary)
260
+
261
+ RBAC Permissions
262
+ ~~~~~~~~~~~~~~~~
263
+
264
+ Database-backed Role-Based Access Control (RBAC) permission checking.
265
+
266
+ .. code-block:: python
267
+
268
+ from python3_commons.permissions import has_user_permission
269
+ from uuid import UUID
270
+
271
+ user_uuid = UUID("...")
272
+ allowed = await has_user_permission(session, user_uuid, "reports.view")
273
+
274
+ General Helpers
275
+ ~~~~~~~~~~~~~~~
276
+
277
+ A collection of useful utility functions:
278
+
279
+ - ``to_snake_case(text)``: Converts strings to snake_case.
280
+ - ``round_decimal(value, places)``: Rounds ``Decimal`` values.
281
+ - ``tries(n)``: An async retry decorator.
282
+ - ``log_execution_time``: An async decorator to log how long a function takes.
283
+ - ``date_from_string`` / ``datetime_from_string``: Flexible date/time parsing.
284
+ - ``request_to_curl``: Converts request parameters to a ``curl`` command string.
285
+
286
+ .. code-block:: python
287
+
288
+ from python3_commons.helpers import tries, log_execution_time
289
+
290
+ @tries(3)
291
+ @log_execution_time
292
+ async def flaky_network_call():
293
+ ...
294
+
295
+ Async CSV Stream
296
+ ~~~~~~~~~~~~~~~~
297
+
298
+ Efficiently generate CSV data as a byte stream from an async generator of tuples.
299
+
300
+ .. code-block:: python
301
+
302
+ from python3_commons.generators import tuple_csv_stream
303
+
304
+ async def generate_rows():
305
+ for i in range(1000):
306
+ yield (i, f"Name {i}", 10.5 * i)
307
+
308
+ async for chunk in tuple_csv_stream(generate_rows(), header=("ID", "Name", "Value")):
309
+ # Send chunk to HTTP response or write to file
310
+ pass
@@ -0,0 +1,244 @@
1
+ # python3-commons
2
+
3
+ Re-usable code for Python 3 projects.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ uv add python3-commons
9
+ ```
10
+
11
+ ### Optional Dependencies
12
+
13
+ Some features require extra dependencies. You can install them individually or all at once:
14
+
15
+ - `api-client`: For `python3_commons.api_client`
16
+ - `audit`: For `python3_commons.audit`
17
+ - `authn`: For `python3_commons.auth`
18
+ - `authz`: For `python3_commons.permissions`
19
+ - `cache`: For `python3_commons.cache`
20
+ - `database`: For `python3_commons.db`
21
+ - `object-storage`: For `python3_commons.object_storage`
22
+ - `soap-client`: For `python3_commons.soap_client`
23
+ - `all`: Install all optional dependencies
24
+
25
+ ```bash
26
+ uv add "python3-commons[all]"
27
+ ```
28
+
29
+ ## Features
30
+
31
+ ### Async LRU Cache
32
+
33
+ An LRU cache decorator for asynchronous functions that handles `await` and prevents the dogpile effect (mitigating multiple concurrent calls for the same key by waiting for the first one to finish).
34
+
35
+ ```python
36
+ from python3_commons.async_functools import async_lru_cache
37
+
38
+ @async_lru_cache(maxsize=128)
39
+ async def fetch_expensive_data(item_id: int):
40
+ # This function will only be called once for a given item_id
41
+ # even if multiple tasks await it simultaneously.
42
+ return await db.get(item_id)
43
+
44
+ # Usage
45
+ result = await fetch_expensive_data(42)
46
+ ```
47
+
48
+ ### API Client
49
+
50
+ A context manager for `aiohttp` requests with built-in audit logging to S3 and standardized error mapping to Python exceptions.
51
+
52
+ ```python
53
+ from python3_commons.api_client import request
54
+ from aiohttp import ClientSession
55
+
56
+ async with ClientSession() as session:
57
+ async with request(
58
+ session,
59
+ base_url="https://api.example.com",
60
+ uri="/data",
61
+ method="get",
62
+ audit_name="my_service_audit"
63
+ ) as response:
64
+ data = await response.json()
65
+ ```
66
+
67
+ ### SOAP Client
68
+
69
+ Async SOAP client support for `zeep` with S3 auditing capabilities.
70
+
71
+ ```python
72
+ from python3_commons.soap_client import soap_client
73
+
74
+ async with soap_client("https://example.com/service?wsdl") as client:
75
+ result = await client.service.GetData(id=42)
76
+ ```
77
+
78
+ ### Database Management
79
+
80
+ SQLAlchemy async engine and session management with pool tuning, health checks, and dynamic query builders.
81
+
82
+ ```python
83
+ from python3_commons.db import AsyncSessionManager
84
+ from python3_commons.conf import DBSettings
85
+
86
+ # Configuration
87
+ configs = {"default": DBSettings(dsn="postgresql+asyncpg://user:pass@localhost/db")}
88
+ manager = AsyncSessionManager(configs)
89
+
90
+ # Usage
91
+ async with manager.get_session_context("default") as session:
92
+ result = await session.execute(...)
93
+
94
+ # Health check
95
+ from python3_commons.db import is_healthy
96
+ await is_healthy(manager.get_engine("default"))
97
+ ```
98
+
99
+ ### Object Storage
100
+
101
+ Utilities for async S3 operations using `aiobotocore`.
102
+
103
+ ```python
104
+ from python3_commons import object_storage
105
+ import io
106
+
107
+ # Upload an object
108
+ await object_storage.put_object(
109
+ bucket_name="my-bucket",
110
+ path="uploads/file.txt",
111
+ data=io.BytesIO(b"Hello World"),
112
+ length=11
113
+ )
114
+
115
+ # Download an object
116
+ content = await object_storage.get_object("my-bucket", "uploads/file.txt")
117
+
118
+ # List objects
119
+ async for obj in object_storage.list_objects("my-bucket", "uploads/"):
120
+ print(obj['Key'])
121
+ ```
122
+
123
+ ### OIDC Authentication
124
+
125
+ Client for OpenID Connect authentication, supporting configuration fetching, JWKS, and token acquisition.
126
+
127
+ ```python
128
+ from python3_commons.auth import OIDCClient
129
+ from pydantic import HttpUrl
130
+
131
+ client = OIDCClient(
132
+ authority_url=HttpUrl("https://auth.example.com/realms/myrealm"),
133
+ client_id="my-app-client",
134
+ client_secret="secret"
135
+ )
136
+
137
+ async with client:
138
+ token_response = await client.fetch_token(username="user", password="password")
139
+ print(token_response.access_token)
140
+ ```
141
+
142
+ ### Valkey Cache
143
+
144
+ Async caching using Valkey (Redis-compatible) with automatic Msgpack serialization for complex types.
145
+
146
+ ```python
147
+ from python3_commons import cache
148
+
149
+ # Store a dictionary
150
+ await cache.store("user:123", {"name": "Alice", "role": "admin"}, ttl=3600)
151
+
152
+ # Retrieve it
153
+ user_data = await cache.get("user:123")
154
+
155
+ # Set operations
156
+ await cache.add_set_item("active_users", "user:123")
157
+ is_active = await cache.has_set_item("active_users", "user:123")
158
+ ```
159
+
160
+ ### Structured Logging
161
+
162
+ A `JSONFormatter` for structured logging, compatible with standard Python `logging`.
163
+
164
+ ```python
165
+ import logging
166
+ from python3_commons.log.formatters import JSONFormatter
167
+
168
+ handler = logging.StreamHandler()
169
+ handler.setFormatter(JSONFormatter())
170
+ logging.getLogger().addHandler(handler)
171
+
172
+ logger = logging.getLogger("app")
173
+ logger.info("User logged in", extra={"user_id": "abc-123", "ip": "1.2.3.4"})
174
+ ```
175
+
176
+ ### Serialization
177
+
178
+ Enhanced JSON and Msgpack serialization for types not handled by default (Decimal, datetime, date, dataclasses, Pydantic models).
179
+
180
+ ```python
181
+ from python3_commons.serializers.msgspec import serialize_msgpack, deserialize_msgpack
182
+ from decimal import Decimal
183
+ from datetime import datetime
184
+
185
+ data = {
186
+ "amount": Decimal("150.75"),
187
+ "timestamp": datetime.now(),
188
+ "tags": {"finance", "internal"}
189
+ }
190
+
191
+ # Serialize to Msgpack
192
+ binary = serialize_msgpack(data)
193
+
194
+ # Deserialize back
195
+ restored = deserialize_msgpack(binary)
196
+ ```
197
+
198
+ ### RBAC Permissions
199
+
200
+ Database-backed Role-Based Access Control (RBAC) permission checking.
201
+
202
+ ```python
203
+ from python3_commons.permissions import has_user_permission
204
+ from uuid import UUID
205
+
206
+ user_uuid = UUID("...")
207
+ allowed = await has_user_permission(session, user_uuid, "reports.view")
208
+ ```
209
+
210
+ ### General Helpers
211
+
212
+ A collection of useful utility functions:
213
+
214
+ - `to_snake_case(text)`: Converts strings to snake_case.
215
+ - `round_decimal(value, places)`: Rounds `Decimal` values.
216
+ - `tries(n)`: An async retry decorator.
217
+ - `log_execution_time`: An async decorator to log how long a function takes.
218
+ - `date_from_string` / `datetime_from_string`: Flexible date/time parsing.
219
+ - `request_to_curl`: Converts request parameters to a `curl` command string.
220
+
221
+ ```python
222
+ from python3_commons.helpers import tries, log_execution_time
223
+
224
+ @tries(3)
225
+ @log_execution_time
226
+ async def flaky_network_call():
227
+ ...
228
+ ```
229
+
230
+ ### Async CSV Stream
231
+
232
+ Efficiently generate CSV data as a byte stream from an async generator of tuples.
233
+
234
+ ```python
235
+ from python3_commons.generators import tuple_csv_stream
236
+
237
+ async def generate_rows():
238
+ for i in range(1000):
239
+ yield (i, f"Name {i}", 10.5 * i)
240
+
241
+ async for chunk in tuple_csv_stream(generate_rows(), header=("ID", "Name", "Value")):
242
+ # Send chunk to HTTP response or write to file
243
+ pass
244
+ ```