python3-commons 0.16.8__tar.gz → 0.17.1__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 (76) hide show
  1. python3_commons-0.17.1/PKG-INFO +42 -0
  2. {python3_commons-0.16.8 → python3_commons-0.17.1}/pyproject.toml +30 -9
  3. {python3_commons-0.16.8 → python3_commons-0.17.1}/src/python3_commons/api_client.py +17 -13
  4. {python3_commons-0.16.8 → python3_commons-0.17.1}/src/python3_commons/audit.py +6 -2
  5. {python3_commons-0.16.8 → python3_commons-0.17.1}/src/python3_commons/auth.py +10 -5
  6. {python3_commons-0.16.8 → python3_commons-0.17.1}/src/python3_commons/cache.py +13 -9
  7. {python3_commons-0.16.8 → python3_commons-0.17.1}/src/python3_commons/db/__init__.py +8 -4
  8. {python3_commons-0.16.8 → python3_commons-0.17.1}/src/python3_commons/db/helpers.py +7 -3
  9. {python3_commons-0.16.8 → python3_commons-0.17.1}/src/python3_commons/db/models/auth.py +6 -2
  10. {python3_commons-0.16.8 → python3_commons-0.17.1}/src/python3_commons/db/models/common.py +10 -6
  11. {python3_commons-0.16.8 → python3_commons-0.17.1}/src/python3_commons/db/models/rbac.py +7 -3
  12. {python3_commons-0.16.8 → python3_commons-0.17.1}/src/python3_commons/db/models/users.py +6 -2
  13. {python3_commons-0.16.8 → python3_commons-0.17.1}/src/python3_commons/log/formatters.py +6 -6
  14. {python3_commons-0.16.8 → python3_commons-0.17.1}/src/python3_commons/object_storage.py +7 -3
  15. {python3_commons-0.16.8 → python3_commons-0.17.1}/src/python3_commons/permissions.py +6 -2
  16. python3_commons-0.17.1/src/python3_commons.egg-info/PKG-INFO +42 -0
  17. python3_commons-0.17.1/src/python3_commons.egg-info/requires.txt +29 -0
  18. {python3_commons-0.16.8 → python3_commons-0.17.1}/uv.lock +50 -18
  19. python3_commons-0.16.8/PKG-INFO +0 -31
  20. python3_commons-0.16.8/src/python3_commons.egg-info/PKG-INFO +0 -31
  21. python3_commons-0.16.8/src/python3_commons.egg-info/requires.txt +0 -11
  22. {python3_commons-0.16.8 → python3_commons-0.17.1}/.coveragerc +0 -0
  23. {python3_commons-0.16.8 → python3_commons-0.17.1}/.devcontainer/Dockerfile +0 -0
  24. {python3_commons-0.16.8 → python3_commons-0.17.1}/.devcontainer/devcontainer.json +0 -0
  25. {python3_commons-0.16.8 → python3_commons-0.17.1}/.devcontainer/docker-compose.yml +0 -0
  26. {python3_commons-0.16.8 → python3_commons-0.17.1}/.env_template +0 -0
  27. {python3_commons-0.16.8 → python3_commons-0.17.1}/.github/workflows/checks.yml +0 -0
  28. {python3_commons-0.16.8 → python3_commons-0.17.1}/.github/workflows/python-publish.yaml +0 -0
  29. {python3_commons-0.16.8 → python3_commons-0.17.1}/.github/workflows/release-on-tag-push.yml +0 -0
  30. {python3_commons-0.16.8 → python3_commons-0.17.1}/.gitignore +0 -0
  31. {python3_commons-0.16.8 → python3_commons-0.17.1}/.pre-commit-config.yaml +0 -0
  32. {python3_commons-0.16.8 → python3_commons-0.17.1}/.python-version +0 -0
  33. {python3_commons-0.16.8 → python3_commons-0.17.1}/AUTHORS.rst +0 -0
  34. {python3_commons-0.16.8 → python3_commons-0.17.1}/CHANGELOG.rst +0 -0
  35. {python3_commons-0.16.8 → python3_commons-0.17.1}/LICENSE +0 -0
  36. {python3_commons-0.16.8 → python3_commons-0.17.1}/README.md +0 -0
  37. {python3_commons-0.16.8 → python3_commons-0.17.1}/README.rst +0 -0
  38. {python3_commons-0.16.8 → python3_commons-0.17.1}/docs/Makefile +0 -0
  39. {python3_commons-0.16.8 → python3_commons-0.17.1}/docs/_static/.gitignore +0 -0
  40. {python3_commons-0.16.8 → python3_commons-0.17.1}/docs/authors.rst +0 -0
  41. {python3_commons-0.16.8 → python3_commons-0.17.1}/docs/changelog.rst +0 -0
  42. {python3_commons-0.16.8 → python3_commons-0.17.1}/docs/conf.py +0 -0
  43. {python3_commons-0.16.8 → python3_commons-0.17.1}/docs/index.rst +0 -0
  44. {python3_commons-0.16.8 → python3_commons-0.17.1}/docs/license.rst +0 -0
  45. {python3_commons-0.16.8 → python3_commons-0.17.1}/setup.cfg +0 -0
  46. {python3_commons-0.16.8 → python3_commons-0.17.1}/src/python3_commons/__init__.py +0 -0
  47. {python3_commons-0.16.8 → python3_commons-0.17.1}/src/python3_commons/async_functools.py +0 -0
  48. {python3_commons-0.16.8 → python3_commons-0.17.1}/src/python3_commons/conf.py +0 -0
  49. {python3_commons-0.16.8 → python3_commons-0.17.1}/src/python3_commons/db/models/__init__.py +0 -0
  50. {python3_commons-0.16.8 → python3_commons-0.17.1}/src/python3_commons/exceptions.py +0 -0
  51. {python3_commons-0.16.8 → python3_commons-0.17.1}/src/python3_commons/fs.py +0 -0
  52. {python3_commons-0.16.8 → python3_commons-0.17.1}/src/python3_commons/generators.py +0 -0
  53. {python3_commons-0.16.8 → python3_commons-0.17.1}/src/python3_commons/helpers.py +0 -0
  54. {python3_commons-0.16.8 → python3_commons-0.17.1}/src/python3_commons/log/__init__.py +0 -0
  55. {python3_commons-0.16.8 → python3_commons-0.17.1}/src/python3_commons/log/filters.py +0 -0
  56. {python3_commons-0.16.8 → python3_commons-0.17.1}/src/python3_commons/serializers/__init__.py +0 -0
  57. {python3_commons-0.16.8 → python3_commons-0.17.1}/src/python3_commons/serializers/common.py +0 -0
  58. {python3_commons-0.16.8 → python3_commons-0.17.1}/src/python3_commons/serializers/json.py +0 -0
  59. {python3_commons-0.16.8 → python3_commons-0.17.1}/src/python3_commons/serializers/msgpack.py +0 -0
  60. {python3_commons-0.16.8 → python3_commons-0.17.1}/src/python3_commons/serializers/msgspec.py +0 -0
  61. {python3_commons-0.16.8 → python3_commons-0.17.1}/src/python3_commons.egg-info/SOURCES.txt +0 -0
  62. {python3_commons-0.16.8 → python3_commons-0.17.1}/src/python3_commons.egg-info/dependency_links.txt +0 -0
  63. {python3_commons-0.16.8 → python3_commons-0.17.1}/src/python3_commons.egg-info/top_level.txt +0 -0
  64. {python3_commons-0.16.8 → python3_commons-0.17.1}/tests/__init__.py +0 -0
  65. {python3_commons-0.16.8 → python3_commons-0.17.1}/tests/integration/__init__.py +0 -0
  66. {python3_commons-0.16.8 → python3_commons-0.17.1}/tests/integration/test_cache.py +0 -0
  67. {python3_commons-0.16.8 → python3_commons-0.17.1}/tests/integration/test_osc.py +0 -0
  68. {python3_commons-0.16.8 → python3_commons-0.17.1}/tests/unit/__init__.py +0 -0
  69. {python3_commons-0.16.8 → python3_commons-0.17.1}/tests/unit/conftest.py +0 -0
  70. {python3_commons-0.16.8 → python3_commons-0.17.1}/tests/unit/log/__init__.py +0 -0
  71. {python3_commons-0.16.8 → python3_commons-0.17.1}/tests/unit/log/test_formatters.py +0 -0
  72. {python3_commons-0.16.8 → python3_commons-0.17.1}/tests/unit/test_async_functools.py +0 -0
  73. {python3_commons-0.16.8 → python3_commons-0.17.1}/tests/unit/test_audit.py +0 -0
  74. {python3_commons-0.16.8 → python3_commons-0.17.1}/tests/unit/test_helpers.py +0 -0
  75. {python3_commons-0.16.8 → python3_commons-0.17.1}/tests/unit/test_msgpack.py +0 -0
  76. {python3_commons-0.16.8 → python3_commons-0.17.1}/tests/unit/test_msgspec.py +0 -0
@@ -0,0 +1,42 @@
1
+ Metadata-Version: 2.4
2
+ Name: python3-commons
3
+ Version: 0.17.1
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.1.2
16
+ Requires-Dist: msgspec==0.21.1
17
+ Requires-Dist: pydantic-settings~=2.14.0
18
+ Provides-Extra: all
19
+ Requires-Dist: python3_commons[audit,authn,authz,cache,database,object-storage]; extra == "all"
20
+ Provides-Extra: api-client
21
+ Requires-Dist: aiohttp[speedups]<3.15.0,>=3.13.5; extra == "api-client"
22
+ Requires-Dist: lxml~=6.1.0; extra == "api-client"
23
+ Requires-Dist: zeep~=4.3.2; extra == "api-client"
24
+ Requires-Dist: python3_commons[object-storage]; extra == "api-client"
25
+ Provides-Extra: authn
26
+ Requires-Dist: aiohttp[speedups]<3.15.0,>=3.13.5; extra == "authn"
27
+ Provides-Extra: authz
28
+ Requires-Dist: python3_commons[database]; extra == "authz"
29
+ Provides-Extra: cache
30
+ Requires-Dist: valkey[libvalkey]~=6.1.1; extra == "cache"
31
+ Provides-Extra: database
32
+ Requires-Dist: asyncpg~=0.31.0; extra == "database"
33
+ Requires-Dist: SQLAlchemy[asyncio]~=2.0.49; extra == "database"
34
+ Provides-Extra: object-storage
35
+ Requires-Dist: aiobotocore~=3.5.0; extra == "object-storage"
36
+ Requires-Dist: object-storage-client==0.0.22; extra == "object-storage"
37
+ Dynamic: license-file
38
+
39
+ Re-usable Python3 code
40
+ ======================
41
+
42
+ Some description here
@@ -18,18 +18,39 @@ classifiers = [
18
18
  keywords = []
19
19
  requires-python = ">=3.14.0,<3.15.0"
20
20
  dependencies = [
21
- "aiobotocore~=3.5.0",
22
- "aiohttp[speedups]>=3.13.5,<3.15.0",
23
- "asyncpg~=0.31.0",
24
- "lxml~=6.1.0",
25
21
  "msgpack~=1.1.2",
26
22
  "msgspec==0.21.1",
27
- "object-storage-client==0.0.22",
28
- "pydantic-settings~=2.14.0",
29
- "SQLAlchemy[asyncio]~=2.0.49",
30
- "valkey[libvalkey]~=6.1.1",
31
- "zeep~=4.3.2"
23
+ "pydantic-settings~=2.14.0"
24
+ ]
25
+
26
+ [project.optional-dependencies]
27
+ all = [
28
+ "python3_commons[audit,authn,authz,cache,database,object-storage]"
29
+ ]
30
+ api-client = [
31
+ "aiohttp[speedups]>=3.13.5,<3.15.0",
32
+ "lxml~=6.1.0",
33
+ "zeep~=4.3.2",
34
+ "python3_commons[object-storage]"
32
35
  ]
36
+ authn = [
37
+ "aiohttp[speedups]>=3.13.5,<3.15.0",
38
+ ]
39
+ authz = [
40
+ "python3_commons[database]"
41
+ ]
42
+ cache = [
43
+ "valkey[libvalkey]~=6.1.1"
44
+ ]
45
+ database = [
46
+ "asyncpg~=0.31.0",
47
+ "SQLAlchemy[asyncio]~=2.0.49"
48
+ ]
49
+ object-storage = [
50
+ "aiobotocore~=3.5.0",
51
+ "object-storage-client==0.0.22"
52
+ ]
53
+
33
54
 
34
55
  [dependency-groups]
35
56
  dev = [
@@ -9,8 +9,12 @@ from json import dumps
9
9
  from typing import Literal
10
10
  from uuid import uuid4
11
11
 
12
- from aiohttp import ClientResponse, ClientSession, ClientTimeout, client_exceptions
13
- from aiohttp.abc import URL
12
+ try:
13
+ from aiohttp import ClientResponse, ClientSession, ClientTimeout, client_exceptions
14
+ from aiohttp.abc import URL
15
+ except ImportError as e:
16
+ msg = 'Install python3-commons[api-client] to use this feature'
17
+ raise RuntimeError(msg) from e
14
18
 
15
19
  from python3_commons import audit
16
20
  from python3_commons.conf import s3_settings
@@ -21,7 +25,7 @@ logger = logging.getLogger(__name__)
21
25
 
22
26
 
23
27
  async def _store_response_for_audit(
24
- response: ClientResponse, audit_name: str, uri_path: str, method: str, request_id: str
28
+ response: ClientResponse, audit_name: str, uri_path: str, method: str, request_id: str
25
29
  ) -> None:
26
30
  response_text = await response.text()
27
31
 
@@ -39,16 +43,16 @@ async def _store_response_for_audit(
39
43
 
40
44
  @asynccontextmanager
41
45
  async def request(
42
- client: ClientSession,
43
- base_url: str,
44
- uri: str,
45
- query: Mapping | None = None,
46
- method: Literal['get', 'post', 'put', 'patch', 'options', 'head', 'delete'] = 'get',
47
- headers: Mapping | None = None,
48
- json: Mapping | Sequence | str | None = None,
49
- data: bytes | None = None,
50
- timeout: ClientTimeout | Enum | None = None,
51
- audit_name: str | None = None,
46
+ client: ClientSession,
47
+ base_url: str,
48
+ uri: str,
49
+ query: Mapping | None = None,
50
+ method: Literal['get', 'post', 'put', 'patch', 'options', 'head', 'delete'] = 'get',
51
+ headers: Mapping | None = None,
52
+ json: Mapping | Sequence | str | None = None,
53
+ data: bytes | None = None,
54
+ timeout: ClientTimeout | Enum | None = None,
55
+ audit_name: str | None = None,
52
56
  ) -> AsyncGenerator[ClientResponse]:
53
57
  now = datetime.now(tz=UTC)
54
58
  date_path = now.strftime('%Y/%m/%d')
@@ -5,8 +5,12 @@ from datetime import UTC, datetime
5
5
  from typing import TYPE_CHECKING
6
6
  from uuid import uuid4
7
7
 
8
- from lxml import etree
9
- from zeep.plugins import Plugin
8
+ try:
9
+ from lxml import etree
10
+ from zeep.plugins import Plugin
11
+ except ImportError as e:
12
+ msg = 'Install python3-commons[api-client] to use this feature'
13
+ raise RuntimeError(msg) from e
10
14
 
11
15
  from python3_commons import object_storage
12
16
  from python3_commons.conf import S3Settings, s3_settings
@@ -5,7 +5,12 @@ from collections.abc import Sequence
5
5
  from http import HTTPStatus
6
6
  from typing import TypeVar
7
7
 
8
- import aiohttp
8
+ try:
9
+ import aiohttp
10
+ except ImportError as e:
11
+ msg = 'Install python3-commons[authn] to use this feature'
12
+ raise RuntimeError(msg) from e
13
+
9
14
  import msgspec
10
15
 
11
16
  from python3_commons.conf import oidc_settings
@@ -51,9 +56,9 @@ async def fetch_openid_config() -> dict:
51
56
  """
52
57
  async with aiohttp.ClientSession() as session, session.get(OIDC_CONFIG_URL) as response:
53
58
  if response.status != HTTPStatus.OK:
54
- msg = 'Failed to fetch OpenID configuration'
59
+ _msg = 'Failed to fetch OpenID configuration'
55
60
 
56
- raise RuntimeError(msg)
61
+ raise RuntimeError(_msg)
57
62
 
58
63
  return await response.json()
59
64
 
@@ -67,8 +72,8 @@ async def fetch_jwks(jwks_uri: str) -> dict:
67
72
 
68
73
  async with aiohttp.ClientSession() as session, session.get(jwks_uri) as response:
69
74
  if response.status != HTTPStatus.OK:
70
- msg = 'Failed to fetch JWKS'
75
+ _msg = 'Failed to fetch JWKS'
71
76
 
72
- raise RuntimeError(msg)
77
+ raise RuntimeError(_msg)
73
78
 
74
79
  return await response.json()
@@ -4,10 +4,14 @@ from collections.abc import Mapping, Sequence
4
4
  from platform import platform
5
5
  from typing import TYPE_CHECKING, Any
6
6
 
7
- import valkey
8
- from valkey.asyncio import ConnectionPool, Sentinel, StrictValkey, Valkey
9
- from valkey.asyncio.retry import Retry
10
- from valkey.backoff import FullJitterBackoff
7
+ try:
8
+ import valkey
9
+ from valkey.asyncio import ConnectionPool, Sentinel, StrictValkey, Valkey
10
+ from valkey.asyncio.retry import Retry
11
+ from valkey.backoff import FullJitterBackoff
12
+ except ImportError as e:
13
+ msg = 'Install python3-commons[cache] to use this feature'
14
+ raise RuntimeError(msg) from e
11
15
 
12
16
  from python3_commons.conf import valkey_settings
13
17
  from python3_commons.helpers import SingletonMeta
@@ -77,11 +81,11 @@ def get_valkey_client() -> Valkey:
77
81
 
78
82
 
79
83
  async def scan(
80
- cursor: int = 0,
81
- match: bytes | str | memoryview | None = None,
82
- count: int | None = None,
83
- _type: str | None = None,
84
- **kwargs,
84
+ cursor: int = 0,
85
+ match: bytes | str | memoryview | None = None,
86
+ count: int | None = None,
87
+ _type: str | None = None,
88
+ **kwargs,
85
89
  ) -> ResponseT:
86
90
  return await get_valkey_client().scan(cursor, match, count, _type, **kwargs)
87
91
 
@@ -3,10 +3,14 @@ import logging
3
3
  from collections.abc import AsyncGenerator, Callable, Mapping
4
4
  from typing import TYPE_CHECKING
5
5
 
6
- from sqlalchemy import MetaData
7
- from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession, async_engine_from_config
8
- from sqlalchemy.ext.asyncio.session import async_sessionmaker
9
- from sqlalchemy.orm import declarative_base
6
+ try:
7
+ from sqlalchemy import MetaData
8
+ from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession, async_engine_from_config
9
+ from sqlalchemy.ext.asyncio.session import async_sessionmaker
10
+ from sqlalchemy.orm import declarative_base
11
+ except ImportError as e:
12
+ msg = 'Install python3-commons[database] to use this feature'
13
+ raise RuntimeError(msg) from e
10
14
 
11
15
  if TYPE_CHECKING:
12
16
  from python3_commons.conf import DBSettings
@@ -2,8 +2,12 @@ import logging
2
2
  from collections.abc import Mapping
3
3
  from typing import TYPE_CHECKING
4
4
 
5
- import sqlalchemy as sa
6
- from sqlalchemy import asc, desc, func
5
+ try:
6
+ import sqlalchemy as sa
7
+ from sqlalchemy import asc, desc, func
8
+ except ImportError as e:
9
+ msg = 'Install python3-commons[database] to use this feature'
10
+ raise RuntimeError(msg) from e
7
11
 
8
12
  if TYPE_CHECKING:
9
13
  from sqlalchemy.sql.elements import ColumnElement
@@ -12,7 +16,7 @@ logger = logging.getLogger(__name__)
12
16
 
13
17
 
14
18
  def get_query(
15
- search: Mapping[str, str] | None = None, order_by: str | None = None, columns: Mapping | None = None
19
+ search: Mapping[str, str] | None = None, order_by: str | None = None, columns: Mapping | None = None
16
20
  ) -> tuple[ColumnElement[bool] | None, tuple[ColumnElement[bool]] | None]:
17
21
  """
18
22
  :columns:
@@ -1,8 +1,12 @@
1
1
  import uuid
2
2
  from datetime import datetime
3
3
 
4
- from sqlalchemy import UUID, DateTime, ForeignKey, String
5
- from sqlalchemy.orm import Mapped, mapped_column
4
+ try:
5
+ from sqlalchemy import UUID, DateTime, ForeignKey, String
6
+ from sqlalchemy.orm import Mapped, mapped_column
7
+ except ImportError as e:
8
+ msg = 'Install python3-commons[database] to use this feature'
9
+ raise RuntimeError(msg) from e
6
10
 
7
11
  from python3_commons.db import Base
8
12
  from python3_commons.db.models.common import BaseDBUUIDModel
@@ -1,12 +1,16 @@
1
1
  import uuid
2
2
  from datetime import datetime
3
3
 
4
- from sqlalchemy import BIGINT, DateTime
5
- from sqlalchemy.dialects.postgresql import UUID
6
- from sqlalchemy.ext.compiler import compiles
7
- from sqlalchemy.orm import Mapped, mapped_column
8
- from sqlalchemy.sql import expression
9
- from sqlalchemy.sql.ddl import CreateColumn
4
+ try:
5
+ from sqlalchemy import BIGINT, DateTime
6
+ from sqlalchemy.dialects.postgresql import UUID
7
+ from sqlalchemy.ext.compiler import compiles
8
+ from sqlalchemy.orm import Mapped, mapped_column
9
+ from sqlalchemy.sql import expression
10
+ from sqlalchemy.sql.ddl import CreateColumn
11
+ except ImportError as e:
12
+ msg = 'Install python3-commons[database] to use this feature'
13
+ raise RuntimeError(msg) from e
10
14
 
11
15
 
12
16
  class UTCNow(expression.FunctionElement):
@@ -1,9 +1,13 @@
1
1
  import uuid
2
2
  from datetime import datetime
3
3
 
4
- from sqlalchemy import CheckConstraint, DateTime, ForeignKey, PrimaryKeyConstraint, String
5
- from sqlalchemy.dialects.postgresql import UUID
6
- from sqlalchemy.orm import Mapped, mapped_column
4
+ try:
5
+ from sqlalchemy import CheckConstraint, DateTime, ForeignKey, PrimaryKeyConstraint, String
6
+ from sqlalchemy.dialects.postgresql import UUID
7
+ from sqlalchemy.orm import Mapped, mapped_column
8
+ except ImportError as e:
9
+ msg = 'Install python3-commons[database] to use this feature'
10
+ raise RuntimeError(msg) from e
7
11
 
8
12
  from python3_commons.db import Base
9
13
 
@@ -1,7 +1,11 @@
1
1
  import uuid
2
2
 
3
- from sqlalchemy import UUID, ForeignKey, String
4
- from sqlalchemy.orm import Mapped, mapped_column
3
+ try:
4
+ from sqlalchemy import UUID, ForeignKey, String
5
+ from sqlalchemy.orm import Mapped, mapped_column
6
+ except ImportError as e:
7
+ msg = 'Install python3-commons[database] to use this feature'
8
+ raise RuntimeError(msg) from e
5
9
 
6
10
  from python3_commons.db import Base
7
11
  from python3_commons.db.models.common import BaseDBUUIDModel
@@ -1,6 +1,6 @@
1
1
  import logging
2
2
  import traceback
3
- from datetime import UTC, datetime, date
3
+ from datetime import UTC, date, datetime
4
4
  from decimal import Decimal
5
5
  from typing import Any, Final
6
6
 
@@ -51,13 +51,13 @@ def _normalize(v: Any) -> Any:
51
51
 
52
52
 
53
53
  class JSONFormatter(logging.Formatter):
54
- __slots__ = ('_max_tb_chars', '_encoder')
54
+ __slots__ = ('_encoder', '_max_tb_chars')
55
55
 
56
56
  def __init__(
57
- self,
58
- *,
59
- max_exc_tb_chars: int = _DEFAULT_MAX_TB_CHARS,
60
- **kwargs: Any,
57
+ self,
58
+ *,
59
+ max_exc_tb_chars: int = _DEFAULT_MAX_TB_CHARS,
60
+ **kwargs: Any,
61
61
  ) -> None:
62
62
  super().__init__(**kwargs)
63
63
 
@@ -5,9 +5,13 @@ import threading
5
5
  from contextlib import asynccontextmanager
6
6
  from typing import TYPE_CHECKING
7
7
 
8
- import aiobotocore.session
9
- from botocore.config import Config
10
- from object_storage_client import ObjectStorageClient
8
+ try:
9
+ import aiobotocore.session
10
+ from botocore.config import Config
11
+ from object_storage_client import ObjectStorageClient
12
+ except ImportError as e:
13
+ msg = 'Install python3-commons[object-storage] to use this feature'
14
+ raise RuntimeError(msg) from e
11
15
 
12
16
  if TYPE_CHECKING:
13
17
  import io
@@ -2,8 +2,12 @@ import logging
2
2
  from typing import TYPE_CHECKING
3
3
  from uuid import UUID
4
4
 
5
- import sqlalchemy as sa
6
- from sqlalchemy import and_, exists, func
5
+ try:
6
+ import sqlalchemy as sa
7
+ from sqlalchemy import and_, exists, func
8
+ except ImportError as e:
9
+ msg = 'Install python3-commons[authz] to use this feature'
10
+ raise RuntimeError(msg) from e
7
11
 
8
12
  from python3_commons.db.models.rbac import RBACApiKeyRole, RBACPermission, RBACRolePermission, RBACUserRole
9
13
 
@@ -0,0 +1,42 @@
1
+ Metadata-Version: 2.4
2
+ Name: python3-commons
3
+ Version: 0.17.1
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.1.2
16
+ Requires-Dist: msgspec==0.21.1
17
+ Requires-Dist: pydantic-settings~=2.14.0
18
+ Provides-Extra: all
19
+ Requires-Dist: python3_commons[audit,authn,authz,cache,database,object-storage]; extra == "all"
20
+ Provides-Extra: api-client
21
+ Requires-Dist: aiohttp[speedups]<3.15.0,>=3.13.5; extra == "api-client"
22
+ Requires-Dist: lxml~=6.1.0; extra == "api-client"
23
+ Requires-Dist: zeep~=4.3.2; extra == "api-client"
24
+ Requires-Dist: python3_commons[object-storage]; extra == "api-client"
25
+ Provides-Extra: authn
26
+ Requires-Dist: aiohttp[speedups]<3.15.0,>=3.13.5; extra == "authn"
27
+ Provides-Extra: authz
28
+ Requires-Dist: python3_commons[database]; extra == "authz"
29
+ Provides-Extra: cache
30
+ Requires-Dist: valkey[libvalkey]~=6.1.1; extra == "cache"
31
+ Provides-Extra: database
32
+ Requires-Dist: asyncpg~=0.31.0; extra == "database"
33
+ Requires-Dist: SQLAlchemy[asyncio]~=2.0.49; extra == "database"
34
+ Provides-Extra: object-storage
35
+ Requires-Dist: aiobotocore~=3.5.0; extra == "object-storage"
36
+ Requires-Dist: object-storage-client==0.0.22; extra == "object-storage"
37
+ Dynamic: license-file
38
+
39
+ Re-usable Python3 code
40
+ ======================
41
+
42
+ Some description here
@@ -0,0 +1,29 @@
1
+ msgpack~=1.1.2
2
+ msgspec==0.21.1
3
+ pydantic-settings~=2.14.0
4
+
5
+ [all]
6
+ python3_commons[audit,authn,authz,cache,database,object-storage]
7
+
8
+ [api-client]
9
+ aiohttp[speedups]<3.15.0,>=3.13.5
10
+ lxml~=6.1.0
11
+ zeep~=4.3.2
12
+ python3_commons[object-storage]
13
+
14
+ [authn]
15
+ aiohttp[speedups]<3.15.0,>=3.13.5
16
+
17
+ [authz]
18
+ python3_commons[database]
19
+
20
+ [cache]
21
+ valkey[libvalkey]~=6.1.1
22
+
23
+ [database]
24
+ asyncpg~=0.31.0
25
+ SQLAlchemy[asyncio]~=2.0.49
26
+
27
+ [object-storage]
28
+ aiobotocore~=3.5.0
29
+ object-storage-client==0.0.22
@@ -992,18 +992,45 @@ wheels = [
992
992
  name = "python3-commons"
993
993
  source = { editable = "." }
994
994
  dependencies = [
995
+ { name = "msgpack" },
996
+ { name = "msgspec" },
997
+ { name = "pydantic-settings" },
998
+ ]
999
+
1000
+ [package.optional-dependencies]
1001
+ all = [
995
1002
  { name = "aiobotocore" },
996
1003
  { name = "aiohttp", extra = ["speedups"] },
997
1004
  { name = "asyncpg" },
998
- { name = "lxml" },
999
- { name = "msgpack" },
1000
- { name = "msgspec" },
1001
1005
  { name = "object-storage-client" },
1002
- { name = "pydantic-settings" },
1003
1006
  { name = "sqlalchemy", extra = ["asyncio"] },
1004
1007
  { name = "valkey", extra = ["libvalkey"] },
1008
+ ]
1009
+ api-client = [
1010
+ { name = "aiobotocore" },
1011
+ { name = "aiohttp", extra = ["speedups"] },
1012
+ { name = "lxml" },
1013
+ { name = "object-storage-client" },
1005
1014
  { name = "zeep" },
1006
1015
  ]
1016
+ authn = [
1017
+ { name = "aiohttp", extra = ["speedups"] },
1018
+ ]
1019
+ authz = [
1020
+ { name = "asyncpg" },
1021
+ { name = "sqlalchemy", extra = ["asyncio"] },
1022
+ ]
1023
+ cache = [
1024
+ { name = "valkey", extra = ["libvalkey"] },
1025
+ ]
1026
+ database = [
1027
+ { name = "asyncpg" },
1028
+ { name = "sqlalchemy", extra = ["asyncio"] },
1029
+ ]
1030
+ object-storage = [
1031
+ { name = "aiobotocore" },
1032
+ { name = "object-storage-client" },
1033
+ ]
1007
1034
 
1008
1035
  [package.dev-dependencies]
1009
1036
  dev = [
@@ -1024,18 +1051,23 @@ testing = [
1024
1051
 
1025
1052
  [package.metadata]
1026
1053
  requires-dist = [
1027
- { name = "aiobotocore", specifier = "~=3.5.0" },
1028
- { name = "aiohttp", extras = ["speedups"], specifier = ">=3.13.5,<3.15.0" },
1029
- { name = "asyncpg", specifier = "~=0.31.0" },
1030
- { name = "lxml", specifier = "~=6.1.0" },
1054
+ { name = "aiobotocore", marker = "extra == 'object-storage'", specifier = "~=3.5.0" },
1055
+ { name = "aiohttp", extras = ["speedups"], marker = "extra == 'api-client'", specifier = ">=3.13.5,<3.15.0" },
1056
+ { name = "aiohttp", extras = ["speedups"], marker = "extra == 'authn'", specifier = ">=3.13.5,<3.15.0" },
1057
+ { name = "asyncpg", marker = "extra == 'database'", specifier = "~=0.31.0" },
1058
+ { name = "lxml", marker = "extra == 'api-client'", specifier = "~=6.1.0" },
1031
1059
  { name = "msgpack", specifier = "~=1.1.2" },
1032
1060
  { name = "msgspec", specifier = "==0.21.1" },
1033
- { name = "object-storage-client", specifier = "==0.0.22" },
1061
+ { name = "object-storage-client", marker = "extra == 'object-storage'", specifier = "==0.0.22" },
1034
1062
  { name = "pydantic-settings", specifier = "~=2.14.0" },
1035
- { name = "sqlalchemy", extras = ["asyncio"], specifier = "~=2.0.49" },
1036
- { name = "valkey", extras = ["libvalkey"], specifier = "~=6.1.1" },
1037
- { name = "zeep", specifier = "~=4.3.2" },
1063
+ { name = "python3-commons", extras = ["audit", "authn", "authz", "cache", "database", "object-storage"], marker = "extra == 'all'" },
1064
+ { name = "python3-commons", extras = ["database"], marker = "extra == 'authz'" },
1065
+ { name = "python3-commons", extras = ["object-storage"], marker = "extra == 'api-client'" },
1066
+ { name = "sqlalchemy", extras = ["asyncio"], marker = "extra == 'database'", specifier = "~=2.0.49" },
1067
+ { name = "valkey", extras = ["libvalkey"], marker = "extra == 'cache'", specifier = "~=6.1.1" },
1068
+ { name = "zeep", marker = "extra == 'api-client'", specifier = "~=4.3.2" },
1038
1069
  ]
1070
+ provides-extras = ["all", "api-client", "authn", "authz", "cache", "database", "object-storage"]
1039
1071
 
1040
1072
  [package.metadata.requires-dev]
1041
1073
  dev = [
@@ -1193,14 +1225,14 @@ asyncio = [
1193
1225
 
1194
1226
  [[package]]
1195
1227
  name = "types-aiobotocore"
1196
- version = "3.4.0"
1228
+ version = "3.5.0"
1197
1229
  source = { registry = "https://pypi.org/simple" }
1198
1230
  dependencies = [
1199
1231
  { name = "botocore-stubs" },
1200
1232
  ]
1201
- sdist = { url = "https://files.pythonhosted.org/packages/77/95/349d980d5e7da4e3f300bba5f09de71ffd70f3d96ad70b260420a4f4ff89/types_aiobotocore-3.4.0.tar.gz", hash = "sha256:010fa82ddc8aba6084e18edbf22981e541b7efc1f85e49e2320501c22913ef35", size = 87621, upload-time = "2026-04-08T02:46:37.316Z" }
1233
+ sdist = { url = "https://files.pythonhosted.org/packages/d5/99/3863acdc373aa621cf56634bb08145fb54f2213e647d893c1ac7b2636c11/types_aiobotocore-3.5.0.tar.gz", hash = "sha256:8636c9e5a9837d41e45264570349d98c0cdad51fe7961ee19664a11094bb2262", size = 87983, upload-time = "2026-04-23T02:57:02.576Z" }
1202
1234
  wheels = [
1203
- { url = "https://files.pythonhosted.org/packages/a7/e2/f2e1baa388a1ef70522132c287b1d9b23c89b4d6a7ec2981fa2f2d65c1a4/types_aiobotocore-3.4.0-py3-none-any.whl", hash = "sha256:17a52c57d879d5f9fbf7b69671dae8d8f593544a89a6f794b9bed4680e7fd334", size = 54653, upload-time = "2026-04-08T02:46:34.185Z" },
1235
+ { url = "https://files.pythonhosted.org/packages/ed/d7/2b2d4d5b64b81149b08cc3fde6e826788c703c012b687cd4cc4d83742afd/types_aiobotocore-3.5.0-py3-none-any.whl", hash = "sha256:7c75ff73c10098d1d885e5b061f05945afdc4e9d0d5b573274292c329abe8a62", size = 54805, upload-time = "2026-04-23T02:56:59.721Z" },
1204
1236
  ]
1205
1237
 
1206
1238
  [package.optional-dependencies]
@@ -1210,11 +1242,11 @@ s3 = [
1210
1242
 
1211
1243
  [[package]]
1212
1244
  name = "types-aiobotocore-s3"
1213
- version = "3.4.0"
1245
+ version = "3.5.0"
1214
1246
  source = { registry = "https://pypi.org/simple" }
1215
- sdist = { url = "https://files.pythonhosted.org/packages/31/12/070369e99af9c9f29b101386b8bda024e79b93ba926414907b2c1015f854/types_aiobotocore_s3-3.4.0.tar.gz", hash = "sha256:c85ef911ad4206a5af45656fc82f73bd49d364f40823f3cc9fb3887704c3f72b", size = 77156, upload-time = "2026-04-08T02:45:34.329Z" }
1247
+ sdist = { url = "https://files.pythonhosted.org/packages/2d/6b/0d9fd45a69afbd2007480a35e8612121f6e27b988741b3a6d0b05c964229/types_aiobotocore_s3-3.5.0.tar.gz", hash = "sha256:147e2128be67de8c8a33b8a9bcca5fa8e963c6c54e52c58c17fa5c6013195a5a", size = 77175, upload-time = "2026-04-23T02:54:40.652Z" }
1216
1248
  wheels = [
1217
- { url = "https://files.pythonhosted.org/packages/2b/fe/995476195978ddf5441ff5a1204dac0d385dc924d954c529557dd1e20631/types_aiobotocore_s3-3.4.0-py3-none-any.whl", hash = "sha256:4356c21155818fbb75ea60639069441a432c90ed1d4f38364f6ccf090838355b", size = 84917, upload-time = "2026-04-08T02:45:33.313Z" },
1249
+ { url = "https://files.pythonhosted.org/packages/3b/c4/ce16af65a9227fe0ff3e737c0b4317e138fffbd06f7d631fe3a1b5a7f0f3/types_aiobotocore_s3-3.5.0-py3-none-any.whl", hash = "sha256:6fc53a6da5ec5cfb5478197fca74e1d11c389e0e20df7c0e0006a84c56224ada", size = 84930, upload-time = "2026-04-23T02:54:36.283Z" },
1218
1250
  ]
1219
1251
 
1220
1252
  [[package]]
@@ -1,31 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: python3-commons
3
- Version: 0.16.8
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: aiobotocore~=3.5.0
16
- Requires-Dist: aiohttp[speedups]<3.15.0,>=3.13.5
17
- Requires-Dist: asyncpg~=0.31.0
18
- Requires-Dist: lxml~=6.1.0
19
- Requires-Dist: msgpack~=1.1.2
20
- Requires-Dist: msgspec==0.21.1
21
- Requires-Dist: object-storage-client==0.0.22
22
- Requires-Dist: pydantic-settings~=2.14.0
23
- Requires-Dist: SQLAlchemy[asyncio]~=2.0.49
24
- Requires-Dist: valkey[libvalkey]~=6.1.1
25
- Requires-Dist: zeep~=4.3.2
26
- Dynamic: license-file
27
-
28
- Re-usable Python3 code
29
- ======================
30
-
31
- Some description here
@@ -1,31 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: python3-commons
3
- Version: 0.16.8
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: aiobotocore~=3.5.0
16
- Requires-Dist: aiohttp[speedups]<3.15.0,>=3.13.5
17
- Requires-Dist: asyncpg~=0.31.0
18
- Requires-Dist: lxml~=6.1.0
19
- Requires-Dist: msgpack~=1.1.2
20
- Requires-Dist: msgspec==0.21.1
21
- Requires-Dist: object-storage-client==0.0.22
22
- Requires-Dist: pydantic-settings~=2.14.0
23
- Requires-Dist: SQLAlchemy[asyncio]~=2.0.49
24
- Requires-Dist: valkey[libvalkey]~=6.1.1
25
- Requires-Dist: zeep~=4.3.2
26
- Dynamic: license-file
27
-
28
- Re-usable Python3 code
29
- ======================
30
-
31
- Some description here
@@ -1,11 +0,0 @@
1
- aiobotocore~=3.5.0
2
- aiohttp[speedups]<3.15.0,>=3.13.5
3
- asyncpg~=0.31.0
4
- lxml~=6.1.0
5
- msgpack~=1.1.2
6
- msgspec==0.21.1
7
- object-storage-client==0.0.22
8
- pydantic-settings~=2.14.0
9
- SQLAlchemy[asyncio]~=2.0.49
10
- valkey[libvalkey]~=6.1.1
11
- zeep~=4.3.2