python3-commons 0.9.22__tar.gz → 0.10.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.

Potentially problematic release.


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

Files changed (59) hide show
  1. {python3_commons-0.9.22 → python3_commons-0.10.1}/.pre-commit-config.yaml +2 -2
  2. {python3_commons-0.9.22 → python3_commons-0.10.1}/PKG-INFO +1 -1
  3. {python3_commons-0.9.22 → python3_commons-0.10.1}/pyproject.toml +3 -3
  4. {python3_commons-0.9.22 → python3_commons-0.10.1}/src/python3_commons/audit.py +1 -1
  5. {python3_commons-0.9.22 → python3_commons-0.10.1}/src/python3_commons/auth.py +1 -1
  6. {python3_commons-0.9.22 → python3_commons-0.10.1}/src/python3_commons/cache.py +10 -13
  7. {python3_commons-0.9.22 → python3_commons-0.10.1}/src/python3_commons/conf.py +4 -3
  8. {python3_commons-0.9.22 → python3_commons-0.10.1}/src/python3_commons/db/__init__.py +1 -2
  9. {python3_commons-0.9.22 → python3_commons-0.10.1}/src/python3_commons/helpers.py +5 -4
  10. {python3_commons-0.9.22 → python3_commons-0.10.1}/src/python3_commons/object_storage.py +6 -6
  11. {python3_commons-0.9.22 → python3_commons-0.10.1}/src/python3_commons/permissions.py +2 -4
  12. {python3_commons-0.9.22 → python3_commons-0.10.1}/src/python3_commons/serializers/json.py +3 -3
  13. {python3_commons-0.9.22 → python3_commons-0.10.1}/src/python3_commons/serializers/msgpack.py +5 -9
  14. {python3_commons-0.9.22 → python3_commons-0.10.1}/src/python3_commons/serializers/msgspec.py +5 -9
  15. {python3_commons-0.9.22 → python3_commons-0.10.1}/src/python3_commons.egg-info/PKG-INFO +1 -1
  16. {python3_commons-0.9.22 → python3_commons-0.10.1}/.coveragerc +0 -0
  17. {python3_commons-0.9.22 → python3_commons-0.10.1}/.github/workflows/checks.yml +0 -0
  18. {python3_commons-0.9.22 → python3_commons-0.10.1}/.github/workflows/python-publish.yaml +0 -0
  19. {python3_commons-0.9.22 → python3_commons-0.10.1}/.github/workflows/release-on-tag-push.yml +0 -0
  20. {python3_commons-0.9.22 → python3_commons-0.10.1}/.gitignore +0 -0
  21. {python3_commons-0.9.22 → python3_commons-0.10.1}/.python-version +0 -0
  22. {python3_commons-0.9.22 → python3_commons-0.10.1}/AUTHORS.rst +0 -0
  23. {python3_commons-0.9.22 → python3_commons-0.10.1}/CHANGELOG.rst +0 -0
  24. {python3_commons-0.9.22 → python3_commons-0.10.1}/LICENSE +0 -0
  25. {python3_commons-0.9.22 → python3_commons-0.10.1}/README.md +0 -0
  26. {python3_commons-0.9.22 → python3_commons-0.10.1}/README.rst +0 -0
  27. {python3_commons-0.9.22 → python3_commons-0.10.1}/docs/Makefile +0 -0
  28. {python3_commons-0.9.22 → python3_commons-0.10.1}/docs/_static/.gitignore +0 -0
  29. {python3_commons-0.9.22 → python3_commons-0.10.1}/docs/authors.rst +0 -0
  30. {python3_commons-0.9.22 → python3_commons-0.10.1}/docs/changelog.rst +0 -0
  31. {python3_commons-0.9.22 → python3_commons-0.10.1}/docs/conf.py +0 -0
  32. {python3_commons-0.9.22 → python3_commons-0.10.1}/docs/index.rst +0 -0
  33. {python3_commons-0.9.22 → python3_commons-0.10.1}/docs/license.rst +0 -0
  34. {python3_commons-0.9.22 → python3_commons-0.10.1}/setup.cfg +0 -0
  35. {python3_commons-0.9.22 → python3_commons-0.10.1}/src/python3_commons/__init__.py +0 -0
  36. {python3_commons-0.9.22 → python3_commons-0.10.1}/src/python3_commons/api_client.py +0 -0
  37. {python3_commons-0.9.22 → python3_commons-0.10.1}/src/python3_commons/db/helpers.py +0 -0
  38. {python3_commons-0.9.22 → python3_commons-0.10.1}/src/python3_commons/db/models/__init__.py +0 -0
  39. {python3_commons-0.9.22 → python3_commons-0.10.1}/src/python3_commons/db/models/auth.py +0 -0
  40. {python3_commons-0.9.22 → python3_commons-0.10.1}/src/python3_commons/db/models/common.py +0 -0
  41. {python3_commons-0.9.22 → python3_commons-0.10.1}/src/python3_commons/db/models/rbac.py +0 -0
  42. {python3_commons-0.9.22 → python3_commons-0.10.1}/src/python3_commons/fs.py +0 -0
  43. {python3_commons-0.9.22 → python3_commons-0.10.1}/src/python3_commons/log/__init__.py +0 -0
  44. {python3_commons-0.9.22 → python3_commons-0.10.1}/src/python3_commons/log/filters.py +0 -0
  45. {python3_commons-0.9.22 → python3_commons-0.10.1}/src/python3_commons/log/formatters.py +0 -0
  46. {python3_commons-0.9.22 → python3_commons-0.10.1}/src/python3_commons/serializers/__init__.py +0 -0
  47. {python3_commons-0.9.22 → python3_commons-0.10.1}/src/python3_commons/serializers/common.py +0 -0
  48. {python3_commons-0.9.22 → python3_commons-0.10.1}/src/python3_commons.egg-info/SOURCES.txt +0 -0
  49. {python3_commons-0.9.22 → python3_commons-0.10.1}/src/python3_commons.egg-info/dependency_links.txt +0 -0
  50. {python3_commons-0.9.22 → python3_commons-0.10.1}/src/python3_commons.egg-info/requires.txt +0 -0
  51. {python3_commons-0.9.22 → python3_commons-0.10.1}/src/python3_commons.egg-info/top_level.txt +0 -0
  52. {python3_commons-0.9.22 → python3_commons-0.10.1}/tests/__init__.py +0 -0
  53. {python3_commons-0.9.22 → python3_commons-0.10.1}/tests/conftest.py +0 -0
  54. {python3_commons-0.9.22 → python3_commons-0.10.1}/tests/test_audit.py +0 -0
  55. {python3_commons-0.9.22 → python3_commons-0.10.1}/tests/test_cache.py +0 -0
  56. {python3_commons-0.9.22 → python3_commons-0.10.1}/tests/test_helpers.py +0 -0
  57. {python3_commons-0.9.22 → python3_commons-0.10.1}/tests/test_msgpack.py +0 -0
  58. {python3_commons-0.9.22 → python3_commons-0.10.1}/tests/test_msgspec.py +0 -0
  59. {python3_commons-0.9.22 → python3_commons-0.10.1}/uv.lock +0 -0
@@ -1,12 +1,12 @@
1
1
  repos:
2
2
  - repo: https://github.com/astral-sh/uv-pre-commit
3
- rev: 0.8.20
3
+ rev: 0.8.22
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.13.1
9
+ rev: v0.13.2
10
10
  hooks:
11
11
  # Run the linter.
12
12
  - id: ruff-check
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python3-commons
3
- Version: 0.9.22
3
+ Version: 0.10.1
4
4
  Summary: Re-usable Python3 code
5
5
  Author-email: Oleg Korsak <kamikaze.is.waiting.you@gmail.com>
6
6
  License-Expression: GPL-3.0
@@ -114,9 +114,9 @@ select = [
114
114
  "PT",
115
115
  "PTH",
116
116
  "Q",
117
- # "RET",
117
+ "RET",
118
118
  "RSE",
119
- # "RUF",
119
+ "RUF",
120
120
  "S",
121
121
  "SIM",
122
122
  "SLF",
@@ -132,7 +132,7 @@ ignore = [
132
132
  ]
133
133
 
134
134
  [tool.ruff.lint.per-file-ignores]
135
- "tests/*.py" = ["S101"]
135
+ "tests/*.py" = ["DTZ", "S101"]
136
136
 
137
137
  [tool.ruff.lint.flake8-quotes]
138
138
  docstring-quotes = "double"
@@ -138,7 +138,7 @@ logger = logging.getLogger(__name__)
138
138
 
139
139
 
140
140
  async def write_audit_data(settings: S3Settings, key: str, data: bytes):
141
- if settings.s3_secret_access_key:
141
+ if settings.aws_secret_access_key:
142
142
  try:
143
143
  absolute_path = object_storage.get_absolute_path(f'audit/{key}')
144
144
 
@@ -81,7 +81,7 @@ def get_token_verifier[T](
81
81
  except jwt.ExpiredSignatureError as e:
82
82
  raise HTTPException(status_code=HTTPStatus.UNAUTHORIZED, detail='Token has expired') from e
83
83
  except JWTError as e:
84
- raise HTTPException(status_code=HTTPStatus.UNAUTHORIZED, detail=f'Token is invalid: {str(e)}') from e
84
+ raise HTTPException(status_code=HTTPStatus.UNAUTHORIZED, detail=f'Token is invalid: {e!s}') from e
85
85
 
86
86
  return token_data
87
87
 
@@ -37,8 +37,7 @@ class AsyncValkeyClient(metaclass=SingletonMeta):
37
37
  def _get_keepalive_options():
38
38
  if platform in {'linux', 'darwin'}:
39
39
  return {socket.TCP_KEEPIDLE: 10, socket.TCP_KEEPINTVL: 5, socket.TCP_KEEPCNT: 5}
40
- else:
41
- return {}
40
+ return {}
42
41
 
43
42
  def _initialize_sentinel(self, dsn: RedisDsn):
44
43
  sentinel = Sentinel(
@@ -89,7 +88,7 @@ async def delete(*names: str | bytes | memoryview):
89
88
  await get_valkey_client().delete(*names)
90
89
 
91
90
 
92
- async def store_bytes(name: str, data: bytes, ttl: int = None, *, if_not_set: bool = False):
91
+ async def store_bytes(name: str, data: bytes, ttl: int | None = None, *, if_not_set: bool = False):
93
92
  r = get_valkey_client()
94
93
 
95
94
  return await r.set(name, data, ex=ttl, nx=if_not_set)
@@ -101,18 +100,18 @@ async def get_bytes(name: str) -> bytes | None:
101
100
  return await r.get(name)
102
101
 
103
102
 
104
- async def store(name: str, obj: Any, ttl: int = None, *, if_not_set: bool = False):
103
+ async def store(name: str, obj: Any, ttl: int | None = None, *, if_not_set: bool = False):
105
104
  return await store_bytes(name, serialize_msgpack_native(obj), ttl, if_not_set=if_not_set)
106
105
 
107
106
 
108
- async def get(name: str, default=None, data_type: Any = None) -> Any:
107
+ async def get(name: str, default: Any | None = None, data_type: Any = None) -> Any | None:
109
108
  if data := await get_bytes(name):
110
109
  return deserialize_msgpack_native(data, data_type)
111
110
 
112
111
  return default
113
112
 
114
113
 
115
- async def store_string(name: str, data: str, ttl: int = None):
114
+ async def store_string(name: str, data: str, ttl: int | None = None):
116
115
  await store_bytes(name, data.encode(), ttl)
117
116
 
118
117
 
@@ -123,7 +122,7 @@ async def get_string(name: str) -> str | None:
123
122
  return None
124
123
 
125
124
 
126
- async def store_sequence(name: str, data: Sequence, ttl: int = None):
125
+ async def store_sequence(name: str, data: Sequence, ttl: int | None = None):
127
126
  if data:
128
127
  try:
129
128
  r = get_valkey_client()
@@ -142,7 +141,7 @@ async def get_sequence(name: str, _type: type = list) -> Sequence:
142
141
  return _type(map(deserialize_msgpack_native, lrange))
143
142
 
144
143
 
145
- async def store_dict(name: str, data: Mapping, ttl: int = None):
144
+ async def store_dict(name: str, data: Mapping, ttl: int | None = None):
146
145
  if data:
147
146
  try:
148
147
  r = get_valkey_client()
@@ -159,14 +158,12 @@ async def get_dict(name: str, value_data_type=None) -> dict | None:
159
158
  r = get_valkey_client()
160
159
 
161
160
  if data := await r.hgetall(name):
162
- data = {k.decode(): deserialize_msgpack(v, value_data_type) for k, v in data.items()}
163
-
164
- return data
161
+ return {k.decode(): deserialize_msgpack(v, value_data_type) for k, v in data.items()}
165
162
 
166
163
  return None
167
164
 
168
165
 
169
- async def set_dict(name: str, mapping: dict, ttl: int = None):
166
+ async def set_dict(name: str, mapping: dict, ttl: int | None = None):
170
167
  if mapping:
171
168
  try:
172
169
  r = get_valkey_client()
@@ -209,7 +206,7 @@ async def delete_dict_item(name: str, *keys):
209
206
  logger.exception('Failed to delete dict item from cache.')
210
207
 
211
208
 
212
- async def store_set(name: str, value: set, ttl: int = None):
209
+ async def store_set(name: str, value: set, ttl: int | None = None):
213
210
  try:
214
211
  r = get_valkey_client()
215
212
  await r.sadd(name, *map(serialize_msgpack_native, value))
@@ -64,10 +64,11 @@ class DBSettings(BaseSettings):
64
64
 
65
65
 
66
66
  class S3Settings(BaseSettings):
67
+ aws_region: str | None = None
68
+ aws_access_key_id: SecretStr | None = None
69
+ aws_secret_access_key: SecretStr | None = None
70
+
67
71
  s3_endpoint_url: str | None = None
68
- s3_region_name: str | None = Field(default=None, alias='AWS_REGION')
69
- s3_access_key_id: SecretStr | None = None
70
- s3_secret_access_key: SecretStr | None = None
71
72
  s3_addressing_style: Literal['path', 'virtual'] = 'virtual'
72
73
  s3_secure: bool = True
73
74
  s3_bucket: str | None = None
@@ -38,9 +38,8 @@ class AsyncSessionManager:
38
38
  'pool_timeout': db_settings.pool_timeout,
39
39
  'pool_recycle': db_settings.pool_recycle,
40
40
  }
41
- engine = async_engine_from_config(configuration, prefix='')
42
41
 
43
- return engine
42
+ return async_engine_from_config(configuration, prefix='')
44
43
 
45
44
  def get_engine(self, name: str) -> AsyncEngine:
46
45
  try:
@@ -6,12 +6,12 @@ import threading
6
6
  import time
7
7
  from abc import ABCMeta
8
8
  from collections import defaultdict
9
- from collections.abc import Mapping, Sequence
9
+ from collections.abc import Mapping, MutableMapping, Sequence
10
10
  from datetime import date, datetime, timedelta
11
11
  from decimal import ROUND_HALF_UP, Decimal
12
12
  from http.cookies import BaseCookie
13
13
  from json import dumps
14
- from typing import Literal
14
+ from typing import ClassVar, Literal
15
15
  from urllib.parse import urlencode
16
16
 
17
17
  from python3_commons.serializers.json import CustomJSONEncoder
@@ -24,8 +24,8 @@ class SingletonMeta(ABCMeta):
24
24
  A metaclass that creates a Singleton base class when called.
25
25
  """
26
26
 
27
- __instances = {}
28
- __locks = defaultdict(threading.Lock)
27
+ __instances: ClassVar[MutableMapping] = {}
28
+ __locks: ClassVar[defaultdict] = defaultdict(threading.Lock)
29
29
 
30
30
  def __call__(cls, *args, **kwargs):
31
31
  try:
@@ -70,6 +70,7 @@ def tries(times):
70
70
  except Exception:
71
71
  if _time >= times:
72
72
  raise
73
+ return None
73
74
 
74
75
  return wrapper
75
76
 
@@ -25,7 +25,7 @@ class ObjectStorage(metaclass=SingletonMeta):
25
25
  def __init__(self, settings: S3Settings):
26
26
  self._session = aiobotocore.session.get_session()
27
27
  config = {
28
- 'region_name': settings.s3_region_name,
28
+ 'region_name': settings.aws_region,
29
29
  'use_ssl': settings.s3_secure,
30
30
  'verify': settings.s3_cert_verify,
31
31
  'config': Config(s3={'addressing_style': settings.s3_addressing_style}, signature_version='s3v4'),
@@ -34,11 +34,11 @@ class ObjectStorage(metaclass=SingletonMeta):
34
34
  if s3_endpoint_url := settings.s3_endpoint_url:
35
35
  config['endpoint_url'] = s3_endpoint_url
36
36
 
37
- if s3_access_key_id := settings.s3_access_key_id:
38
- config['aws_access_key_id'] = s3_access_key_id.get_secret_value()
37
+ if aws_access_key_id := settings.aws_access_key_id:
38
+ config['aws_access_key_id'] = aws_access_key_id.get_secret_value()
39
39
 
40
- if s3_secret_access_key := settings.s3_secret_access_key:
41
- config['aws_secret_access_key'] = s3_secret_access_key.get_secret_value()
40
+ if aws_secret_access_key := settings.aws_secret_access_key:
41
+ config['aws_secret_access_key'] = aws_secret_access_key.get_secret_value()
42
42
 
43
43
  self._config = config
44
44
 
@@ -150,7 +150,7 @@ async def remove_object(bucket_name: str, object_name: str):
150
150
 
151
151
 
152
152
  async def remove_objects(
153
- bucket_name: str, prefix: str = None, object_names: Iterable[str] = None
153
+ bucket_name: str, prefix: str | None = None, object_names: Iterable[str] | None = None
154
154
  ) -> Sequence[Mapping] | None:
155
155
  storage = ObjectStorage(s3_settings)
156
156
 
@@ -24,9 +24,8 @@ async def has_api_key_permission(session: AsyncSession, api_key_uid: UUID, permi
24
24
  )
25
25
 
26
26
  cursor = await session.execute(query)
27
- result = cursor.scalar()
28
27
 
29
- return result
28
+ return bool(cursor.scalar())
30
29
 
31
30
 
32
31
  async def has_user_permission(session: AsyncSession, user_id: UUID, permission: str) -> bool:
@@ -43,6 +42,5 @@ async def has_user_permission(session: AsyncSession, user_id: UUID, permission:
43
42
  )
44
43
 
45
44
  cursor = await session.execute(query)
46
- result = cursor.scalar()
47
45
 
48
- return result
46
+ return bool(cursor.scalar())
@@ -14,11 +14,11 @@ class CustomJSONEncoder(json.JSONEncoder):
14
14
  except TypeError:
15
15
  if isinstance(o, (datetime, date)):
16
16
  return o.isoformat()
17
- elif isinstance(o, bytes):
17
+ if isinstance(o, bytes):
18
18
  return base64.b64encode(o).decode('ascii')
19
- elif dataclasses.is_dataclass(o):
19
+ if dataclasses.is_dataclass(o):
20
20
  return dataclasses.asdict(o)
21
- elif isinstance(o, (Decimal, socket, type, Exception)):
21
+ if isinstance(o, (Decimal, socket, type, Exception)):
22
22
  return str(o)
23
23
 
24
24
  return type(o).__name__
@@ -16,11 +16,11 @@ logger = logging.getLogger(__name__)
16
16
  def msgpack_encoder(obj):
17
17
  if isinstance(obj, Decimal):
18
18
  return ExtType(ExtendedType.DECIMAL, str(obj).encode())
19
- elif isinstance(obj, datetime):
19
+ if isinstance(obj, datetime):
20
20
  return ExtType(ExtendedType.DATETIME, obj.isoformat().encode())
21
- elif isinstance(obj, date):
21
+ if isinstance(obj, date):
22
22
  return ExtType(ExtendedType.DATE, obj.isoformat().encode())
23
- elif dataclasses.is_dataclass(obj):
23
+ if dataclasses.is_dataclass(obj):
24
24
  return ExtType(ExtendedType.DATACLASS, json.dumps(dataclasses.asdict(obj), cls=CustomJSONEncoder).encode())
25
25
 
26
26
  return f'no encoder for {obj}'
@@ -41,12 +41,8 @@ def msgpack_decoder(code, data):
41
41
 
42
42
 
43
43
  def serialize_msgpack(data) -> bytes:
44
- result = msgpack.packb(data, default=msgpack_encoder)
45
-
46
- return result
44
+ return msgpack.packb(data, default=msgpack_encoder)
47
45
 
48
46
 
49
47
  def deserialize_msgpack(data: bytes):
50
- result = msgpack.unpackb(data, ext_hook=msgpack_decoder)
51
-
52
- return result
48
+ return msgpack.unpackb(data, ext_hook=msgpack_decoder)
@@ -20,11 +20,11 @@ T = TypeVar('T')
20
20
  def enc_hook(obj: Any) -> Any:
21
21
  if isinstance(obj, Decimal):
22
22
  return Ext(ExtendedType.DECIMAL, struct.pack('b', str(obj).encode()))
23
- elif isinstance(obj, datetime):
23
+ if isinstance(obj, datetime):
24
24
  return Ext(ExtendedType.DATETIME, struct.pack('b', obj.isoformat().encode()))
25
- elif isinstance(obj, date):
25
+ if isinstance(obj, date):
26
26
  return Ext(ExtendedType.DATE, struct.pack('b', obj.isoformat().encode()))
27
- elif dataclasses.is_dataclass(obj):
27
+ if dataclasses.is_dataclass(obj):
28
28
  return Ext(
29
29
  ExtendedType.DATACLASS,
30
30
  struct.pack('b', json.dumps(dataclasses.asdict(obj), cls=CustomJSONEncoder).encode()),
@@ -60,9 +60,7 @@ def serialize_msgpack_native(data: Any) -> bytes:
60
60
  if isinstance(data, BaseModel):
61
61
  data = data.model_dump()
62
62
 
63
- result = encode(data)
64
-
65
- return result
63
+ return encode(data)
66
64
 
67
65
 
68
66
  def deserialize_msgpack_native[T](data: bytes, data_type: type[T] | None = None) -> T | Any:
@@ -82,9 +80,7 @@ def serialize_msgpack(data: Any) -> bytes:
82
80
  if isinstance(data, BaseModel):
83
81
  data = data.model_dump()
84
82
 
85
- result = MSGPACK_ENCODER.encode(data)
86
-
87
- return result
83
+ return MSGPACK_ENCODER.encode(data)
88
84
 
89
85
 
90
86
  def deserialize_msgpack[T](data: bytes, data_type: type[T] | None = None) -> T | Any:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python3-commons
3
- Version: 0.9.22
3
+ Version: 0.10.1
4
4
  Summary: Re-usable Python3 code
5
5
  Author-email: Oleg Korsak <kamikaze.is.waiting.you@gmail.com>
6
6
  License-Expression: GPL-3.0