python3-commons 0.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.

Potentially problematic release.


This version of python3-commons might be problematic. Click here for more details.

@@ -0,0 +1,48 @@
1
+ import logging
2
+ from uuid import UUID
3
+
4
+ import sqlalchemy as sa
5
+ from sqlalchemy import and_, exists, func
6
+ from sqlalchemy.ext.asyncio import AsyncSession
7
+
8
+ from python3_commons.db.models import RBACApiKeyRole, RBACPermission, RBACRolePermission, RBACUserRole
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ async def has_api_key_permission(session: AsyncSession, api_key_uid: UUID, permission: str) -> bool:
14
+ query = sa.select(
15
+ exists().where(
16
+ and_(
17
+ RBACApiKeyRole.api_key_uid == api_key_uid,
18
+ (RBACApiKeyRole.expires_at.is_(None) | (RBACApiKeyRole.expires_at > func.now())),
19
+ RBACApiKeyRole.role_uid == RBACRolePermission.role_uid,
20
+ RBACRolePermission.permission_uid == RBACPermission.uid,
21
+ RBACPermission.name == permission,
22
+ )
23
+ )
24
+ )
25
+
26
+ cursor = await session.execute(query)
27
+ result = cursor.scalar()
28
+
29
+ return result
30
+
31
+
32
+ async def has_user_permission(session: AsyncSession, user_id: UUID, permission: str) -> bool:
33
+ query = sa.select(
34
+ exists().where(
35
+ and_(
36
+ RBACUserRole.user_id == user_id,
37
+ (RBACUserRole.expires_at.is_(None) | (RBACUserRole.expires_at > func.now())),
38
+ RBACUserRole.role_uid == RBACRolePermission.role_uid,
39
+ RBACRolePermission.permission_uid == RBACPermission.uid,
40
+ RBACPermission.name == permission,
41
+ )
42
+ )
43
+ )
44
+
45
+ cursor = await session.execute(query)
46
+ result = cursor.scalar()
47
+
48
+ return result
File without changes
@@ -0,0 +1,26 @@
1
+ import base64
2
+ import dataclasses
3
+ import json
4
+ from datetime import date, datetime
5
+ from decimal import Decimal
6
+ from socket import socket
7
+ from typing import Any
8
+
9
+
10
+ class CustomJSONEncoder(json.JSONEncoder):
11
+ def default(self, o) -> Any:
12
+ try:
13
+ return super(CustomJSONEncoder, self).default(o)
14
+ except TypeError:
15
+ if isinstance(o, datetime):
16
+ return o.isoformat()
17
+ elif isinstance(o, date):
18
+ return o.isoformat()
19
+ elif isinstance(o, bytes):
20
+ return base64.b64encode(o).decode('ascii')
21
+ elif dataclasses.is_dataclass(o):
22
+ return dataclasses.asdict(o)
23
+ elif isinstance(o, (Decimal, socket, type, Exception)):
24
+ return str(o)
25
+
26
+ return type(o).__name__
@@ -0,0 +1,50 @@
1
+ import dataclasses
2
+ import json
3
+ import logging
4
+ from datetime import date, datetime
5
+ from decimal import Decimal
6
+
7
+ import msgpack
8
+ from msgpack import ExtType
9
+
10
+ from python3_commons.serializers.json import CustomJSONEncoder
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ def msgpack_encoder(obj):
16
+ if isinstance(obj, Decimal):
17
+ return ExtType(1, str(obj).encode())
18
+ elif isinstance(obj, datetime):
19
+ return ExtType(2, obj.isoformat().encode())
20
+ elif isinstance(obj, date):
21
+ return ExtType(3, obj.isoformat().encode())
22
+ elif dataclasses.is_dataclass(obj):
23
+ return ExtType(4, json.dumps(dataclasses.asdict(obj), cls=CustomJSONEncoder).encode())
24
+
25
+ return f'no encoder for {obj}'
26
+
27
+
28
+ def msgpack_decoder(code, data):
29
+ if code == 1:
30
+ return Decimal(data.decode())
31
+ elif code == 2:
32
+ return datetime.fromisoformat(data.decode())
33
+ elif code == 3:
34
+ return date.fromisoformat(data.decode())
35
+ elif code == 4:
36
+ return json.loads(data)
37
+
38
+ return f'no decoder for type {code}'
39
+
40
+
41
+ def serialize_msgpack(data) -> bytes:
42
+ result = msgpack.packb(data, default=msgpack_encoder)
43
+
44
+ return result
45
+
46
+
47
+ def deserialize_msgpack(data: bytes):
48
+ result = msgpack.unpackb(data, ext_hook=msgpack_decoder)
49
+
50
+ return result
@@ -0,0 +1,73 @@
1
+ import dataclasses
2
+ import json
3
+ import logging
4
+ import struct
5
+ from _decimal import Decimal
6
+ from datetime import date, datetime
7
+ from typing import Any
8
+
9
+ from msgspec import msgpack
10
+ from msgspec.msgpack import Ext, encode
11
+
12
+ from python3_commons.serializers.json import CustomJSONEncoder
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ def enc_hook(obj: Any) -> Any:
18
+ if isinstance(obj, Decimal):
19
+ return Ext(1, struct.pack('b', str(obj).encode()))
20
+ elif isinstance(obj, datetime):
21
+ return Ext(2, struct.pack('b', obj.isoformat().encode()))
22
+ elif isinstance(obj, date):
23
+ return Ext(3, struct.pack('b', obj.isoformat().encode()))
24
+ elif dataclasses.is_dataclass(obj):
25
+ return Ext(4, struct.pack('b', json.dumps(dataclasses.asdict(obj), cls=CustomJSONEncoder).encode()))
26
+
27
+ raise NotImplementedError(f'Objects of type {type(obj)} are not supported')
28
+
29
+
30
+ def ext_hook(code: int, data: memoryview) -> Any:
31
+ if code == 1:
32
+ return Decimal(data.tobytes().decode())
33
+ elif code == 2:
34
+ return datetime.fromisoformat(data.tobytes().decode())
35
+ elif code == 3:
36
+ return date.fromisoformat(data.tobytes().decode())
37
+ elif code == 4:
38
+ return json.loads(data.tobytes())
39
+
40
+ raise NotImplementedError(f'Extension type code {code} is not supported')
41
+
42
+
43
+ MSGPACK_ENCODER = msgpack.Encoder(enc_hook=enc_hook)
44
+ MSGPACK_DECODER = msgpack.Decoder(ext_hook=ext_hook)
45
+ MSGPACK_DECODER_NATIVE = msgpack.Decoder()
46
+
47
+
48
+ def serialize_msgpack_native(data) -> bytes:
49
+ return encode(data)
50
+
51
+
52
+ def deserialize_msgpack_native(data: bytes, data_type=None):
53
+ if data_type:
54
+ result = msgpack.decode(data, type=data_type)
55
+ else:
56
+ result = MSGPACK_DECODER_NATIVE.decode(data)
57
+
58
+ return result
59
+
60
+
61
+ def serialize_msgpack(data) -> bytes:
62
+ result = MSGPACK_ENCODER.encode(data)
63
+
64
+ return result
65
+
66
+
67
+ def deserialize_msgpack(data: bytes, data_type=None):
68
+ if data_type:
69
+ result = msgpack.decode(data, type=data_type)
70
+ else:
71
+ result = MSGPACK_DECODER.decode(data)
72
+
73
+ return result
@@ -0,0 +1,34 @@
1
+ Metadata-Version: 2.4
2
+ Name: python3-commons
3
+ Version: 0.0.0
4
+ Summary: Re-usable Python3 code
5
+ Author-email: Oleg Korsak <kamikaze.is.waiting.you@gmail.com>
6
+ License: gpl-3
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.13.*
12
+ Description-Content-Type: text/x-rst
13
+ License-File: LICENSE
14
+ License-File: AUTHORS.rst
15
+ Requires-Dist: aiohttp[speedups]~=3.11.16
16
+ Requires-Dist: asyncpg~=0.30.0
17
+ Requires-Dist: fastapi-users-db-sqlalchemy~=7.0.0
18
+ Requires-Dist: fastapi-users[sqlalchemy]~=14.0.1
19
+ Requires-Dist: lxml~=5.4.0
20
+ Requires-Dist: minio~=7.2.15
21
+ Requires-Dist: msgpack~=1.1.0
22
+ Requires-Dist: msgspec~=0.19.0
23
+ Requires-Dist: pydantic[email]~=2.11.3
24
+ Requires-Dist: pydantic-settings~=2.9.1
25
+ Requires-Dist: python-jose==3.4.0
26
+ Requires-Dist: SQLAlchemy[asyncio]~=2.0.40
27
+ Requires-Dist: valkey[libvalkey]~=6.1.0
28
+ Requires-Dist: zeep~=4.3.1
29
+ Dynamic: license-file
30
+
31
+ Re-usable Python3 code
32
+ ======================
33
+
34
+ Some description here
@@ -0,0 +1,29 @@
1
+ python3_commons/__init__.py,sha256=0KgaYU46H_IMKn-BuasoRN3C4Hi45KlkHHoPbU9cwiA,189
2
+ python3_commons/api_client.py,sha256=LT7_YmnYVHK2ucKxIhUJCZrmxgfy-lfOxx08-R0WvW0,4505
3
+ python3_commons/audit.py,sha256=osx2ywZXf-V0zOkrhlNgSyzCBvojXQwSYBQ4-ze1xiM,6249
4
+ python3_commons/auth.py,sha256=X8mo7L0dhy1EwzHjOkjBAPvHCCqeTS6yhkcVfVi89cU,2459
5
+ python3_commons/cache.py,sha256=lf27LTD4Z9Iqi5GaK8jH8UC0cL9sHH8wicZ88YDp6Mg,7725
6
+ python3_commons/conf.py,sha256=1VebgIPy195dX4mHDSsDRt-8rE1WrloxKGR-dP0PzBw,1466
7
+ python3_commons/fs.py,sha256=wfLjybXndwLqNlOxTpm_HRJnuTcC4wbrHEOaEeCo9Wc,337
8
+ python3_commons/helpers.py,sha256=ygnTv3KYoiibOFIi99-g8EXaETKHLt5i3jvykGrv6aE,3079
9
+ python3_commons/object_storage.py,sha256=nQsXca0zzzeSY35qhnjE6pLfkLuxn7jDul0-hw0jizE,3985
10
+ python3_commons/permissions.py,sha256=bhjTp-tq-oaTGFMHNnSBlcVX5XQCTL0nWcu6SdPEAB4,1555
11
+ python3_commons/db/__init__.py,sha256=ONlvuAYEagLeSdU9oX02JBpECvWdqNx0OoR9BMCvAIQ,2741
12
+ python3_commons/db/helpers.py,sha256=PY0h08aLiGx-J54wmP3GHPCgGCcLd60rayAUnR3aWdI,1742
13
+ python3_commons/db/models/__init__.py,sha256=Utr5AJf1FwcrxNtdesgjq92WMK4zpK4VL_8z1JEkJw0,185
14
+ python3_commons/db/models/auth.py,sha256=dmyD3BX7LVBgKiepPN-bxlY6J3PhcmUfVdQwhNR45fU,1187
15
+ python3_commons/db/models/common.py,sha256=8JUDUBJLf59xLNhF57zZBgcgrmvcWAYXGYO4P-LKzHY,1512
16
+ python3_commons/db/models/rbac.py,sha256=7NNTUbS8whuPUHpm4oba_UWDdNiJlHrm8HBO7oGtk64,3185
17
+ python3_commons/logging/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
+ python3_commons/logging/filters.py,sha256=fuyjXZAUm-i2MNrxvFYag8F8Rr27x8W8MdV3ke6miSs,175
19
+ python3_commons/logging/formatters.py,sha256=p2AtZD4Axp3Em0e9gWzW8U_yOR5entD7xn7Edvc-IuM,719
20
+ python3_commons/serializers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
+ python3_commons/serializers/json.py,sha256=91UaXLGKGj0yPyrnuMeNrkG2GuPUgcgAsmIokUgEwpU,808
22
+ python3_commons/serializers/msgpack.py,sha256=WrvaPE187shSK8zkH4UHHMimEZNMv9RaDSwsBE2HlCw,1269
23
+ python3_commons/serializers/msgspec.py,sha256=5SS_wQXcrThPmCWjI7k1a_cHWLz46Jzn3pit89SYJGY,2038
24
+ python3_commons-0.0.0.dist-info/licenses/AUTHORS.rst,sha256=3R9JnfjfjH5RoPWOeqKFJgxVShSSfzQPIrEr1nxIo9Q,90
25
+ python3_commons-0.0.0.dist-info/licenses/LICENSE,sha256=xxILuojHm4fKQOrMHPSslbyy6WuKAN2RiG74HbrYfzM,34575
26
+ python3_commons-0.0.0.dist-info/METADATA,sha256=RuVBD9YvT9Q0aRW7aEUDoYEpnXzUeqsgLu83xG0PKck,1113
27
+ python3_commons-0.0.0.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
28
+ python3_commons-0.0.0.dist-info/top_level.txt,sha256=lJI6sCBf68eUHzupCnn2dzG10lH3jJKTWM_hrN1cQ7M,16
29
+ python3_commons-0.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.8.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,5 @@
1
+ ============
2
+ Contributors
3
+ ============
4
+
5
+ * Oleg Korsak <kamikaze.is.waiting.you@gmail.com>