python3-commons 0.14.15__tar.gz → 0.14.17__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 (67) hide show
  1. {python3_commons-0.14.15 → python3_commons-0.14.17}/.pre-commit-config.yaml +1 -1
  2. {python3_commons-0.14.15 → python3_commons-0.14.17}/PKG-INFO +1 -1
  3. {python3_commons-0.14.15 → python3_commons-0.14.17}/pyproject.toml +2 -1
  4. {python3_commons-0.14.15 → python3_commons-0.14.17}/src/python3_commons/api_client.py +1 -1
  5. {python3_commons-0.14.15 → python3_commons-0.14.17}/src/python3_commons/audit.py +2 -2
  6. {python3_commons-0.14.15 → python3_commons-0.14.17}/src/python3_commons/db/__init__.py +3 -3
  7. {python3_commons-0.14.15 → python3_commons-0.14.17}/src/python3_commons/helpers.py +1 -1
  8. {python3_commons-0.14.15 → python3_commons-0.14.17}/src/python3_commons/log/formatters.py +10 -3
  9. {python3_commons-0.14.15 → python3_commons-0.14.17}/src/python3_commons/object_storage.py +9 -9
  10. {python3_commons-0.14.15 → python3_commons-0.14.17}/src/python3_commons.egg-info/PKG-INFO +1 -1
  11. {python3_commons-0.14.15 → python3_commons-0.14.17}/src/python3_commons.egg-info/SOURCES.txt +3 -1
  12. python3_commons-0.14.17/tests/unit/log/__init__.py +0 -0
  13. python3_commons-0.14.17/tests/unit/log/test_formatters.py +34 -0
  14. {python3_commons-0.14.15 → python3_commons-0.14.17}/uv.lock +31 -31
  15. {python3_commons-0.14.15 → python3_commons-0.14.17}/.coveragerc +0 -0
  16. {python3_commons-0.14.15 → python3_commons-0.14.17}/.devcontainer/Dockerfile +0 -0
  17. {python3_commons-0.14.15 → python3_commons-0.14.17}/.devcontainer/devcontainer.json +0 -0
  18. {python3_commons-0.14.15 → python3_commons-0.14.17}/.devcontainer/docker-compose.yml +0 -0
  19. {python3_commons-0.14.15 → python3_commons-0.14.17}/.env_template +0 -0
  20. {python3_commons-0.14.15 → python3_commons-0.14.17}/.github/workflows/checks.yml +0 -0
  21. {python3_commons-0.14.15 → python3_commons-0.14.17}/.github/workflows/python-publish.yaml +0 -0
  22. {python3_commons-0.14.15 → python3_commons-0.14.17}/.github/workflows/release-on-tag-push.yml +0 -0
  23. {python3_commons-0.14.15 → python3_commons-0.14.17}/.gitignore +0 -0
  24. {python3_commons-0.14.15 → python3_commons-0.14.17}/.python-version +0 -0
  25. {python3_commons-0.14.15 → python3_commons-0.14.17}/AUTHORS.rst +0 -0
  26. {python3_commons-0.14.15 → python3_commons-0.14.17}/CHANGELOG.rst +0 -0
  27. {python3_commons-0.14.15 → python3_commons-0.14.17}/LICENSE +0 -0
  28. {python3_commons-0.14.15 → python3_commons-0.14.17}/README.md +0 -0
  29. {python3_commons-0.14.15 → python3_commons-0.14.17}/README.rst +0 -0
  30. {python3_commons-0.14.15 → python3_commons-0.14.17}/docs/Makefile +0 -0
  31. {python3_commons-0.14.15 → python3_commons-0.14.17}/docs/_static/.gitignore +0 -0
  32. {python3_commons-0.14.15 → python3_commons-0.14.17}/docs/authors.rst +0 -0
  33. {python3_commons-0.14.15 → python3_commons-0.14.17}/docs/changelog.rst +0 -0
  34. {python3_commons-0.14.15 → python3_commons-0.14.17}/docs/conf.py +0 -0
  35. {python3_commons-0.14.15 → python3_commons-0.14.17}/docs/index.rst +0 -0
  36. {python3_commons-0.14.15 → python3_commons-0.14.17}/docs/license.rst +0 -0
  37. {python3_commons-0.14.15 → python3_commons-0.14.17}/setup.cfg +0 -0
  38. {python3_commons-0.14.15 → python3_commons-0.14.17}/src/python3_commons/__init__.py +0 -0
  39. {python3_commons-0.14.15 → python3_commons-0.14.17}/src/python3_commons/auth.py +0 -0
  40. {python3_commons-0.14.15 → python3_commons-0.14.17}/src/python3_commons/cache.py +0 -0
  41. {python3_commons-0.14.15 → python3_commons-0.14.17}/src/python3_commons/conf.py +0 -0
  42. {python3_commons-0.14.15 → python3_commons-0.14.17}/src/python3_commons/db/helpers.py +0 -0
  43. {python3_commons-0.14.15 → python3_commons-0.14.17}/src/python3_commons/db/models/__init__.py +0 -0
  44. {python3_commons-0.14.15 → python3_commons-0.14.17}/src/python3_commons/db/models/auth.py +0 -0
  45. {python3_commons-0.14.15 → python3_commons-0.14.17}/src/python3_commons/db/models/common.py +0 -0
  46. {python3_commons-0.14.15 → python3_commons-0.14.17}/src/python3_commons/exceptions.py +0 -0
  47. {python3_commons-0.14.15 → python3_commons-0.14.17}/src/python3_commons/fs.py +0 -0
  48. {python3_commons-0.14.15 → python3_commons-0.14.17}/src/python3_commons/generators.py +0 -0
  49. {python3_commons-0.14.15 → python3_commons-0.14.17}/src/python3_commons/log/__init__.py +0 -0
  50. {python3_commons-0.14.15 → python3_commons-0.14.17}/src/python3_commons/log/filters.py +0 -0
  51. {python3_commons-0.14.15 → python3_commons-0.14.17}/src/python3_commons/serializers/__init__.py +0 -0
  52. {python3_commons-0.14.15 → python3_commons-0.14.17}/src/python3_commons/serializers/common.py +0 -0
  53. {python3_commons-0.14.15 → python3_commons-0.14.17}/src/python3_commons/serializers/json.py +0 -0
  54. {python3_commons-0.14.15 → python3_commons-0.14.17}/src/python3_commons/serializers/msgpack.py +0 -0
  55. {python3_commons-0.14.15 → python3_commons-0.14.17}/src/python3_commons/serializers/msgspec.py +0 -0
  56. {python3_commons-0.14.15 → python3_commons-0.14.17}/src/python3_commons.egg-info/dependency_links.txt +0 -0
  57. {python3_commons-0.14.15 → python3_commons-0.14.17}/src/python3_commons.egg-info/requires.txt +0 -0
  58. {python3_commons-0.14.15 → python3_commons-0.14.17}/src/python3_commons.egg-info/top_level.txt +0 -0
  59. {python3_commons-0.14.15 → python3_commons-0.14.17}/tests/__init__.py +0 -0
  60. {python3_commons-0.14.15 → python3_commons-0.14.17}/tests/integration/__init__.py +0 -0
  61. {python3_commons-0.14.15 → python3_commons-0.14.17}/tests/integration/test_cache.py +0 -0
  62. {python3_commons-0.14.15 → python3_commons-0.14.17}/tests/unit/__init__.py +0 -0
  63. {python3_commons-0.14.15 → python3_commons-0.14.17}/tests/unit/conftest.py +0 -0
  64. {python3_commons-0.14.15 → python3_commons-0.14.17}/tests/unit/test_audit.py +0 -0
  65. {python3_commons-0.14.15 → python3_commons-0.14.17}/tests/unit/test_helpers.py +0 -0
  66. {python3_commons-0.14.15 → python3_commons-0.14.17}/tests/unit/test_msgpack.py +0 -0
  67. {python3_commons-0.14.15 → python3_commons-0.14.17}/tests/unit/test_msgspec.py +0 -0
@@ -6,7 +6,7 @@ repos:
6
6
  # - id: uv-export
7
7
 
8
8
  - repo: https://github.com/astral-sh/ruff-pre-commit
9
- rev: v0.14.8
9
+ rev: v0.14.9
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.14.15
3
+ Version: 0.14.17
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
@@ -94,7 +94,7 @@ select = [
94
94
  "FBT",
95
95
  "FLY",
96
96
  "FURB",
97
- # "G",
97
+ "G",
98
98
  "ICN",
99
99
  "INP",
100
100
  "ISC",
@@ -142,6 +142,7 @@ indent-style = "space"
142
142
  quote-style = "single"
143
143
 
144
144
  [tool.pyright]
145
+ pythonVersion = "3.14"
145
146
  venvPath = "."
146
147
  venv = ".venv"
147
148
  reportMatchNotExhaustive = "error"
@@ -79,7 +79,7 @@ async def request(
79
79
 
80
80
  client_method = getattr(client, method)
81
81
 
82
- logger.debug(f'Requesting {method} {url}')
82
+ logger.debug('Requesting %s %s', method, url)
83
83
 
84
84
  try:
85
85
  if method == 'get':
@@ -26,9 +26,9 @@ async def write_audit_data(settings: S3Settings, key: str, data: bytes) -> None:
26
26
  except Exception:
27
27
  logger.exception('Failed storing object in storage.')
28
28
  else:
29
- logger.debug(f'Stored object in storage: {key}')
29
+ logger.debug('Stored object in storage: %s', key)
30
30
  else:
31
- logger.debug(f'S3 is not configured, not storing object in storage: {key}')
31
+ logger.debug('S3 is not configured, not storing object in storage: %s', key)
32
32
 
33
33
 
34
34
  class ZeepAuditPlugin(Plugin):
@@ -26,7 +26,7 @@ class AsyncSessionManager:
26
26
  try:
27
27
  return self.db_settings[name]
28
28
  except KeyError:
29
- logger.exception(f'Missing database settings: {name}')
29
+ logger.exception('Missing database settings: %s', name)
30
30
 
31
31
  raise
32
32
 
@@ -47,7 +47,7 @@ class AsyncSessionManager:
47
47
  try:
48
48
  engine = self.engines[name]
49
49
  except KeyError:
50
- logger.debug(f'Creating engine: {name}')
50
+ logger.debug('Creating engine: %s', name)
51
51
  engine = self.async_engine_from_db_settings(name)
52
52
  self.engines[name] = engine
53
53
 
@@ -57,7 +57,7 @@ class AsyncSessionManager:
57
57
  try:
58
58
  session_maker = self.session_makers[name]
59
59
  except KeyError:
60
- logger.debug(f'Creating session maker: {name}')
60
+ logger.debug('Creating session maker: %s', name)
61
61
  engine = self.get_engine(name)
62
62
  session_maker = async_sessionmaker(engine, expire_on_commit=False)
63
63
  self.session_makers[name] = session_maker
@@ -133,7 +133,7 @@ def log_execution_time(func):
133
133
  return await func(*args, **kwargs)
134
134
  finally:
135
135
  elapsed = time.monotonic() - start_time
136
- _logger.info(f'{func.__module__}.{func.__name__} executed in {elapsed:.4f} seconds')
136
+ _logger.info('%s.%s executed in %.4f seconds', func.__module__, func.__name__, elapsed)
137
137
 
138
138
  wrapper.__signature__ = inspect.signature(func)
139
139
 
@@ -10,16 +10,23 @@ correlation_id: ContextVar[str | None] = ContextVar('correlation_id', default=No
10
10
 
11
11
  class JSONFormatter(logging.Formatter):
12
12
  @staticmethod
13
- def format_exception(exc_info):
13
+ def format_exception(exc_info: logging._SysExcInfoType):
14
14
  return ''.join(traceback.format_exception(*exc_info))
15
15
 
16
- def format(self, record):
16
+ def format(self, record: logging.LogRecord):
17
17
  if corr_id := correlation_id.get():
18
18
  record.correlation_id = corr_id
19
19
 
20
+ record.message = record.getMessage()
21
+
20
22
  if record.exc_info:
21
23
  record.exc_text = self.format_exception(record.exc_info)
22
24
  else:
23
25
  record.exc_text = None
24
26
 
25
- return json.dumps(record.__dict__, cls=CustomJSONEncoder)
27
+ record_dict = record.__dict__
28
+
29
+ del record_dict['args']
30
+ del record_dict['msg']
31
+
32
+ return json.dumps(record_dict, cls=CustomJSONEncoder)
@@ -66,9 +66,9 @@ async def put_object(bucket_name: str, path: str, data: io.BytesIO, length: int,
66
66
 
67
67
  await s3_client.put_object(Bucket=bucket_name, Key=path, Body=data, ContentLength=length)
68
68
 
69
- logger.debug(f'Stored object into object storage: {bucket_name}:{path}')
69
+ logger.debug('Stored object into object storage: %s:%s', bucket_name, path)
70
70
  except Exception as e:
71
- logger.exception(f'Failed to put object to object storage: {bucket_name}:{path}', exc_info=e)
71
+ logger.exception('Failed to put object to object storage: %s:%s', bucket_name, path, exc_info=e)
72
72
 
73
73
  raise
74
74
 
@@ -80,7 +80,7 @@ async def get_object_stream(bucket_name: str, path: str) -> AsyncGenerator[Strea
80
80
  storage = ObjectStorage(s3_settings)
81
81
 
82
82
  async with storage.get_client() as s3_client:
83
- logger.debug(f'Getting object from object storage: {bucket_name}:{path}')
83
+ logger.debug('Getting object from object storage: %s:%s', bucket_name, path)
84
84
 
85
85
  try:
86
86
  response = await s3_client.get_object(Bucket=bucket_name, Key=path)
@@ -88,7 +88,7 @@ async def get_object_stream(bucket_name: str, path: str) -> AsyncGenerator[Strea
88
88
  async with response['Body'] as stream:
89
89
  yield stream
90
90
  except Exception as e:
91
- logger.exception(f'Failed getting object from object storage: {bucket_name}:{path}', exc_info=e)
91
+ logger.exception('Failed getting object from object storage: %s:%s', bucket_name, path, exc_info=e)
92
92
 
93
93
  raise
94
94
 
@@ -97,7 +97,7 @@ async def get_object(bucket_name: str, path: str) -> bytes:
97
97
  async with get_object_stream(bucket_name, path) as stream:
98
98
  body = await stream.read()
99
99
 
100
- logger.debug(f'Loaded object from object storage: {bucket_name}:{path}')
100
+ logger.debug('Loaded object from object storage: %s:%s', bucket_name, path)
101
101
 
102
102
  return body
103
103
 
@@ -142,9 +142,9 @@ async def remove_object(bucket_name: str, object_name: str) -> None:
142
142
  async with storage.get_client() as s3_client:
143
143
  try:
144
144
  await s3_client.delete_object(Bucket=bucket_name, Key=object_name)
145
- logger.debug(f'Removed object from object storage: {bucket_name}:{object_name}')
145
+ logger.debug('Removed object from object storage: %s:%s', bucket_name, object_name)
146
146
  except Exception as e:
147
- logger.exception(f'Failed to remove object from object storage: {bucket_name}:{object_name}', exc_info=e)
147
+ logger.exception('Failed to remove object from object storage: %s:%s', bucket_name, object_name, exc_info=e)
148
148
 
149
149
  raise
150
150
 
@@ -180,9 +180,9 @@ async def remove_objects(
180
180
  if 'Errors' in response:
181
181
  errors.extend(response['Errors'])
182
182
 
183
- logger.debug(f'Removed {len(objects_to_delete)} objects from object storage: {bucket_name}')
183
+ logger.debug('Removed %d objects from object storage: %s', len(objects_to_delete), bucket_name)
184
184
  except Exception as e:
185
- logger.exception(f'Failed to remove objects from object storage: {bucket_name}', exc_info=e)
185
+ logger.exception('Failed to remove objects from object storage: %s', bucket_name, exc_info=e)
186
186
 
187
187
  raise
188
188
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python3-commons
3
- Version: 0.14.15
3
+ Version: 0.14.17
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
@@ -60,4 +60,6 @@ tests/unit/conftest.py
60
60
  tests/unit/test_audit.py
61
61
  tests/unit/test_helpers.py
62
62
  tests/unit/test_msgpack.py
63
- tests/unit/test_msgspec.py
63
+ tests/unit/test_msgspec.py
64
+ tests/unit/log/__init__.py
65
+ tests/unit/log/test_formatters.py
File without changes
@@ -0,0 +1,34 @@
1
+ import json
2
+ from logging import INFO, LogRecord
3
+
4
+ import pytest
5
+
6
+ from python3_commons.log.formatters import JSONFormatter
7
+
8
+
9
+ def test_json_formatter_info_record() -> None:
10
+ formatter = JSONFormatter()
11
+ record = LogRecord(
12
+ name='test.log',
13
+ level=INFO,
14
+ pathname='/dev/null',
15
+ lineno=12345,
16
+ msg='This is a %s, %d, %s',
17
+ args=(
18
+ 'test',
19
+ 1234,
20
+ 'magic',
21
+ ),
22
+ exc_info=None,
23
+ )
24
+ expected_message = 'This is a test, 1234, magic'
25
+ formatted_record_str = formatter.format(record)
26
+ formatted_record = json.loads(formatted_record_str)
27
+
28
+ with pytest.raises(KeyError):
29
+ _ = formatted_record['msg']
30
+
31
+ with pytest.raises(KeyError):
32
+ _ = formatted_record['args']
33
+
34
+ assert formatted_record['message'] == expected_message
@@ -250,14 +250,14 @@ wheels = [
250
250
 
251
251
  [[package]]
252
252
  name = "botocore-stubs"
253
- version = "1.42.7"
253
+ version = "1.42.8"
254
254
  source = { registry = "https://pypi.org/simple" }
255
255
  dependencies = [
256
256
  { name = "types-awscrt" },
257
257
  ]
258
- sdist = { url = "https://files.pythonhosted.org/packages/cf/71/60ed60efadff75be02bdd9acb554c043d0f9388fc3907c3be953709e04c7/botocore_stubs-1.42.7.tar.gz", hash = "sha256:951fc41e78e1a53b49bfe8511bc24e430eda4c689ca6033c643693e56485e69c", size = 42392, upload-time = "2025-12-10T21:29:19.759Z" }
258
+ sdist = { url = "https://files.pythonhosted.org/packages/c7/df/d2be0d6d485edfcf44e3b92d55b643a3e0a38555e2202fa0ef95ef998008/botocore_stubs-1.42.8.tar.gz", hash = "sha256:9656c43dcfdadf92b7a87d7997cd941a0ed6cb111374ed879ecdd07c9ab301dd", size = 42408, upload-time = "2025-12-11T22:26:51.474Z" }
259
259
  wheels = [
260
- { url = "https://files.pythonhosted.org/packages/37/45/ab92dfc4d44b9fd652fca4ca02f523ea03c5f1f5babea225ce1230f30cd6/botocore_stubs-1.42.7-py3-none-any.whl", hash = "sha256:d5c9ac851e8d7ce30d25204add0e2448cb23cb5f8fbe6b5c768ea1e4471b4455", size = 66749, upload-time = "2025-12-10T21:29:18.25Z" },
260
+ { url = "https://files.pythonhosted.org/packages/13/6d/01635795111d6622280f52678f32f7399502c90af045a15a98fb81b2f55e/botocore_stubs-1.42.8-py3-none-any.whl", hash = "sha256:ebcd1c6a136f99cba54a30d1214a0e9ff2f2adcc43e627d8bcd371f6dd887e5e", size = 66749, upload-time = "2025-12-11T22:26:49.916Z" },
261
261
  ]
262
262
 
263
263
  [[package]]
@@ -1443,28 +1443,28 @@ wheels = [
1443
1443
 
1444
1444
  [[package]]
1445
1445
  name = "ruff"
1446
- version = "0.14.8"
1447
- source = { registry = "https://pypi.org/simple" }
1448
- sdist = { url = "https://files.pythonhosted.org/packages/ed/d9/f7a0c4b3a2bf2556cd5d99b05372c29980249ef71e8e32669ba77428c82c/ruff-0.14.8.tar.gz", hash = "sha256:774ed0dd87d6ce925e3b8496feb3a00ac564bea52b9feb551ecd17e0a23d1eed", size = 5765385, upload-time = "2025-12-04T15:06:17.669Z" }
1449
- wheels = [
1450
- { url = "https://files.pythonhosted.org/packages/48/b8/9537b52010134b1d2b72870cc3f92d5fb759394094741b09ceccae183fbe/ruff-0.14.8-py3-none-linux_armv6l.whl", hash = "sha256:ec071e9c82eca417f6111fd39f7043acb53cd3fde9b1f95bbed745962e345afb", size = 13441540, upload-time = "2025-12-04T15:06:14.896Z" },
1451
- { url = "https://files.pythonhosted.org/packages/24/00/99031684efb025829713682012b6dd37279b1f695ed1b01725f85fd94b38/ruff-0.14.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:8cdb162a7159f4ca36ce980a18c43d8f036966e7f73f866ac8f493b75e0c27e9", size = 13669384, upload-time = "2025-12-04T15:06:51.809Z" },
1452
- { url = "https://files.pythonhosted.org/packages/72/64/3eb5949169fc19c50c04f28ece2c189d3b6edd57e5b533649dae6ca484fe/ruff-0.14.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:2e2fcbefe91f9fad0916850edf0854530c15bd1926b6b779de47e9ab619ea38f", size = 12806917, upload-time = "2025-12-04T15:06:08.925Z" },
1453
- { url = "https://files.pythonhosted.org/packages/c4/08/5250babb0b1b11910f470370ec0cbc67470231f7cdc033cee57d4976f941/ruff-0.14.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9d70721066a296f45786ec31916dc287b44040f553da21564de0ab4d45a869b", size = 13256112, upload-time = "2025-12-04T15:06:23.498Z" },
1454
- { url = "https://files.pythonhosted.org/packages/78/4c/6c588e97a8e8c2d4b522c31a579e1df2b4d003eddfbe23d1f262b1a431ff/ruff-0.14.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2c87e09b3cd9d126fc67a9ecd3b5b1d3ded2b9c7fce3f16e315346b9d05cfb52", size = 13227559, upload-time = "2025-12-04T15:06:33.432Z" },
1455
- { url = "https://files.pythonhosted.org/packages/23/ce/5f78cea13eda8eceac71b5f6fa6e9223df9b87bb2c1891c166d1f0dce9f1/ruff-0.14.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d62cb310c4fbcb9ee4ac023fe17f984ae1e12b8a4a02e3d21489f9a2a5f730c", size = 13896379, upload-time = "2025-12-04T15:06:02.687Z" },
1456
- { url = "https://files.pythonhosted.org/packages/cf/79/13de4517c4dadce9218a20035b21212a4c180e009507731f0d3b3f5df85a/ruff-0.14.8-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:1af35c2d62633d4da0521178e8a2641c636d2a7153da0bac1b30cfd4ccd91344", size = 15372786, upload-time = "2025-12-04T15:06:29.828Z" },
1457
- { url = "https://files.pythonhosted.org/packages/00/06/33df72b3bb42be8a1c3815fd4fae83fa2945fc725a25d87ba3e42d1cc108/ruff-0.14.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:25add4575ffecc53d60eed3f24b1e934493631b48ebbc6ebaf9d8517924aca4b", size = 14990029, upload-time = "2025-12-04T15:06:36.812Z" },
1458
- { url = "https://files.pythonhosted.org/packages/64/61/0f34927bd90925880394de0e081ce1afab66d7b3525336f5771dcf0cb46c/ruff-0.14.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4c943d847b7f02f7db4201a0600ea7d244d8a404fbb639b439e987edcf2baf9a", size = 14407037, upload-time = "2025-12-04T15:06:39.979Z" },
1459
- { url = "https://files.pythonhosted.org/packages/96/bc/058fe0aefc0fbf0d19614cb6d1a3e2c048f7dc77ca64957f33b12cfdc5ef/ruff-0.14.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb6e8bf7b4f627548daa1b69283dac5a296bfe9ce856703b03130732e20ddfe2", size = 14102390, upload-time = "2025-12-04T15:06:46.372Z" },
1460
- { url = "https://files.pythonhosted.org/packages/af/a4/e4f77b02b804546f4c17e8b37a524c27012dd6ff05855d2243b49a7d3cb9/ruff-0.14.8-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:7aaf2974f378e6b01d1e257c6948207aec6a9b5ba53fab23d0182efb887a0e4a", size = 14230793, upload-time = "2025-12-04T15:06:20.497Z" },
1461
- { url = "https://files.pythonhosted.org/packages/3f/52/bb8c02373f79552e8d087cedaffad76b8892033d2876c2498a2582f09dcf/ruff-0.14.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e5758ca513c43ad8a4ef13f0f081f80f08008f410790f3611a21a92421ab045b", size = 13160039, upload-time = "2025-12-04T15:06:49.06Z" },
1462
- { url = "https://files.pythonhosted.org/packages/1f/ad/b69d6962e477842e25c0b11622548df746290cc6d76f9e0f4ed7456c2c31/ruff-0.14.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:f74f7ba163b6e85a8d81a590363bf71618847e5078d90827749bfda1d88c9cdf", size = 13205158, upload-time = "2025-12-04T15:06:54.574Z" },
1463
- { url = "https://files.pythonhosted.org/packages/06/63/54f23da1315c0b3dfc1bc03fbc34e10378918a20c0b0f086418734e57e74/ruff-0.14.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:eed28f6fafcc9591994c42254f5a5c5ca40e69a30721d2ab18bb0bb3baac3ab6", size = 13469550, upload-time = "2025-12-04T15:05:59.209Z" },
1464
- { url = "https://files.pythonhosted.org/packages/70/7d/a4d7b1961e4903bc37fffb7ddcfaa7beb250f67d97cfd1ee1d5cddb1ec90/ruff-0.14.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:21d48fa744c9d1cb8d71eb0a740c4dd02751a5de9db9a730a8ef75ca34cf138e", size = 14211332, upload-time = "2025-12-04T15:06:06.027Z" },
1465
- { url = "https://files.pythonhosted.org/packages/5d/93/2a5063341fa17054e5c86582136e9895db773e3c2ffb770dde50a09f35f0/ruff-0.14.8-py3-none-win32.whl", hash = "sha256:15f04cb45c051159baebb0f0037f404f1dc2f15a927418f29730f411a79bc4e7", size = 13151890, upload-time = "2025-12-04T15:06:11.668Z" },
1466
- { url = "https://files.pythonhosted.org/packages/02/1c/65c61a0859c0add13a3e1cbb6024b42de587456a43006ca2d4fd3d1618fe/ruff-0.14.8-py3-none-win_amd64.whl", hash = "sha256:9eeb0b24242b5bbff3011409a739929f497f3fb5fe3b5698aba5e77e8c833097", size = 14537826, upload-time = "2025-12-04T15:06:26.409Z" },
1467
- { url = "https://files.pythonhosted.org/packages/6d/63/8b41cea3afd7f58eb64ac9251668ee0073789a3bc9ac6f816c8c6fef986d/ruff-0.14.8-py3-none-win_arm64.whl", hash = "sha256:965a582c93c63fe715fd3e3f8aa37c4b776777203d8e1d8aa3cc0c14424a4b99", size = 13634522, upload-time = "2025-12-04T15:06:43.212Z" },
1446
+ version = "0.14.9"
1447
+ source = { registry = "https://pypi.org/simple" }
1448
+ sdist = { url = "https://files.pythonhosted.org/packages/f6/1b/ab712a9d5044435be8e9a2beb17cbfa4c241aa9b5e4413febac2a8b79ef2/ruff-0.14.9.tar.gz", hash = "sha256:35f85b25dd586381c0cc053f48826109384c81c00ad7ef1bd977bfcc28119d5b", size = 5809165, upload-time = "2025-12-11T21:39:47.381Z" }
1449
+ wheels = [
1450
+ { url = "https://files.pythonhosted.org/packages/b8/1c/d1b1bba22cffec02351c78ab9ed4f7d7391876e12720298448b29b7229c1/ruff-0.14.9-py3-none-linux_armv6l.whl", hash = "sha256:f1ec5de1ce150ca6e43691f4a9ef5c04574ad9ca35c8b3b0e18877314aba7e75", size = 13576541, upload-time = "2025-12-11T21:39:14.806Z" },
1451
+ { url = "https://files.pythonhosted.org/packages/94/ab/ffe580e6ea1fca67f6337b0af59fc7e683344a43642d2d55d251ff83ceae/ruff-0.14.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ed9d7417a299fc6030b4f26333bf1117ed82a61ea91238558c0268c14e00d0c2", size = 13779363, upload-time = "2025-12-11T21:39:20.29Z" },
1452
+ { url = "https://files.pythonhosted.org/packages/7d/f8/2be49047f929d6965401855461e697ab185e1a6a683d914c5c19c7962d9e/ruff-0.14.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d5dc3473c3f0e4a1008d0ef1d75cee24a48e254c8bed3a7afdd2b4392657ed2c", size = 12925292, upload-time = "2025-12-11T21:39:38.757Z" },
1453
+ { url = "https://files.pythonhosted.org/packages/9e/e9/08840ff5127916bb989c86f18924fd568938b06f58b60e206176f327c0fe/ruff-0.14.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84bf7c698fc8f3cb8278830fb6b5a47f9bcc1ed8cb4f689b9dd02698fa840697", size = 13362894, upload-time = "2025-12-11T21:39:02.524Z" },
1454
+ { url = "https://files.pythonhosted.org/packages/31/1c/5b4e8e7750613ef43390bb58658eaf1d862c0cc3352d139cd718a2cea164/ruff-0.14.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:aa733093d1f9d88a5d98988d8834ef5d6f9828d03743bf5e338bf980a19fce27", size = 13311482, upload-time = "2025-12-11T21:39:17.51Z" },
1455
+ { url = "https://files.pythonhosted.org/packages/5b/3a/459dce7a8cb35ba1ea3e9c88f19077667a7977234f3b5ab197fad240b404/ruff-0.14.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6a1cfb04eda979b20c8c19550c8b5f498df64ff8da151283311ce3199e8b3648", size = 14016100, upload-time = "2025-12-11T21:39:41.948Z" },
1456
+ { url = "https://files.pythonhosted.org/packages/a6/31/f064f4ec32524f9956a0890fc6a944e5cf06c63c554e39957d208c0ffc45/ruff-0.14.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:1e5cb521e5ccf0008bd74d5595a4580313844a42b9103b7388eca5a12c970743", size = 15477729, upload-time = "2025-12-11T21:39:23.279Z" },
1457
+ { url = "https://files.pythonhosted.org/packages/7a/6d/f364252aad36ccd443494bc5f02e41bf677f964b58902a17c0b16c53d890/ruff-0.14.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd429a8926be6bba4befa8cdcf3f4dd2591c413ea5066b1e99155ed245ae42bb", size = 15122386, upload-time = "2025-12-11T21:39:33.125Z" },
1458
+ { url = "https://files.pythonhosted.org/packages/20/02/e848787912d16209aba2799a4d5a1775660b6a3d0ab3944a4ccc13e64a02/ruff-0.14.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab208c1b7a492e37caeaf290b1378148f75e13c2225af5d44628b95fd7834273", size = 14497124, upload-time = "2025-12-11T21:38:59.33Z" },
1459
+ { url = "https://files.pythonhosted.org/packages/f3/51/0489a6a5595b7760b5dbac0dd82852b510326e7d88d51dbffcd2e07e3ff3/ruff-0.14.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72034534e5b11e8a593f517b2f2f2b273eb68a30978c6a2d40473ad0aaa4cb4a", size = 14195343, upload-time = "2025-12-11T21:39:44.866Z" },
1460
+ { url = "https://files.pythonhosted.org/packages/f6/53/3bb8d2fa73e4c2f80acc65213ee0830fa0c49c6479313f7a68a00f39e208/ruff-0.14.9-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:712ff04f44663f1b90a1195f51525836e3413c8a773574a7b7775554269c30ed", size = 14346425, upload-time = "2025-12-11T21:39:05.927Z" },
1461
+ { url = "https://files.pythonhosted.org/packages/ad/04/bdb1d0ab876372da3e983896481760867fc84f969c5c09d428e8f01b557f/ruff-0.14.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a111fee1db6f1d5d5810245295527cda1d367c5aa8f42e0fca9a78ede9b4498b", size = 13258768, upload-time = "2025-12-11T21:39:08.691Z" },
1462
+ { url = "https://files.pythonhosted.org/packages/40/d9/8bf8e1e41a311afd2abc8ad12be1b6c6c8b925506d9069b67bb5e9a04af3/ruff-0.14.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8769efc71558fecc25eb295ddec7d1030d41a51e9dcf127cbd63ec517f22d567", size = 13326939, upload-time = "2025-12-11T21:39:53.842Z" },
1463
+ { url = "https://files.pythonhosted.org/packages/f4/56/a213fa9edb6dd849f1cfbc236206ead10913693c72a67fb7ddc1833bf95d/ruff-0.14.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:347e3bf16197e8a2de17940cd75fd6491e25c0aa7edf7d61aa03f146a1aa885a", size = 13578888, upload-time = "2025-12-11T21:39:35.988Z" },
1464
+ { url = "https://files.pythonhosted.org/packages/33/09/6a4a67ffa4abae6bf44c972a4521337ffce9cbc7808faadede754ef7a79c/ruff-0.14.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:7715d14e5bccf5b660f54516558aa94781d3eb0838f8e706fb60e3ff6eff03a8", size = 14314473, upload-time = "2025-12-11T21:39:50.78Z" },
1465
+ { url = "https://files.pythonhosted.org/packages/12/0d/15cc82da5d83f27a3c6b04f3a232d61bc8c50d38a6cd8da79228e5f8b8d6/ruff-0.14.9-py3-none-win32.whl", hash = "sha256:df0937f30aaabe83da172adaf8937003ff28172f59ca9f17883b4213783df197", size = 13202651, upload-time = "2025-12-11T21:39:26.628Z" },
1466
+ { url = "https://files.pythonhosted.org/packages/32/f7/c78b060388eefe0304d9d42e68fab8cffd049128ec466456cef9b8d4f06f/ruff-0.14.9-py3-none-win_amd64.whl", hash = "sha256:c0b53a10e61df15a42ed711ec0bda0c582039cf6c754c49c020084c55b5b0bc2", size = 14702079, upload-time = "2025-12-11T21:39:11.954Z" },
1467
+ { url = "https://files.pythonhosted.org/packages/26/09/7a9520315decd2334afa65ed258fed438f070e31f05a2e43dd480a5e5911/ruff-0.14.9-py3-none-win_arm64.whl", hash = "sha256:8e821c366517a074046d92f0e9213ed1c13dbc5b37a7fc20b07f79b64d62cc84", size = 13744730, upload-time = "2025-12-11T21:39:29.659Z" },
1468
1468
  ]
1469
1469
 
1470
1470
  [[package]]
@@ -1585,11 +1585,11 @@ wheels = [
1585
1585
 
1586
1586
  [[package]]
1587
1587
  name = "types-awscrt"
1588
- version = "0.29.2"
1588
+ version = "0.30.0"
1589
1589
  source = { registry = "https://pypi.org/simple" }
1590
- sdist = { url = "https://files.pythonhosted.org/packages/4b/55/880afcfb08a8f683444074c1be70ad6141cf873b7f8115e9cc9e87a487b3/types_awscrt-0.29.2.tar.gz", hash = "sha256:41e01e14d646877bd310e7e3c49ff193f8361480b9568e97b1639775009bbefa", size = 17761, upload-time = "2025-12-04T01:53:21.148Z" }
1590
+ sdist = { url = "https://files.pythonhosted.org/packages/30/1f/febd2df22e24f77b759db0dd9ecdd7f07f055e6a4dbbb699c5eb34b617ef/types_awscrt-0.30.0.tar.gz", hash = "sha256:362fd8f5eaebcfcd922cb9fd8274fb375df550319f78031ee3779eac0b9ecc79", size = 17761, upload-time = "2025-12-12T01:55:59.626Z" }
1591
1591
  wheels = [
1592
- { url = "https://files.pythonhosted.org/packages/3f/26/dcbfda45af027355647c8860429066922f8405197af912817e79bc75efa4/types_awscrt-0.29.2-py3-none-any.whl", hash = "sha256:3f5d1e6c99b0b551af6365f9c04d8ce2effbcfe18bb719a34501efea279ae7bb", size = 42394, upload-time = "2025-12-04T01:53:19.074Z" },
1592
+ { url = "https://files.pythonhosted.org/packages/5b/5f/15999051fca2949a67562c3f80fae2dd5d3404a3f97b326b614533843281/types_awscrt-0.30.0-py3-none-any.whl", hash = "sha256:8204126e01a00eaa4a746e7a0076538ca0e4e3f52408adec0ab9b471bb0bb64b", size = 42392, upload-time = "2025-12-12T01:55:58.194Z" },
1593
1593
  ]
1594
1594
 
1595
1595
  [[package]]
@@ -1615,11 +1615,11 @@ wheels = [
1615
1615
 
1616
1616
  [[package]]
1617
1617
  name = "urllib3"
1618
- version = "2.6.1"
1618
+ version = "2.6.2"
1619
1619
  source = { registry = "https://pypi.org/simple" }
1620
- sdist = { url = "https://files.pythonhosted.org/packages/5e/1d/0f3a93cca1ac5e8287842ed4eebbd0f7a991315089b1a0b01c7788aa7b63/urllib3-2.6.1.tar.gz", hash = "sha256:5379eb6e1aba4088bae84f8242960017ec8d8e3decf30480b3a1abdaa9671a3f", size = 432678, upload-time = "2025-12-08T15:25:26.773Z" }
1620
+ sdist = { url = "https://files.pythonhosted.org/packages/1e/24/a2a2ed9addd907787d7aa0355ba36a6cadf1768b934c652ea78acbd59dcd/urllib3-2.6.2.tar.gz", hash = "sha256:016f9c98bb7e98085cb2b4b17b87d2c702975664e4f060c6532e64d1c1a5e797", size = 432930, upload-time = "2025-12-11T15:56:40.252Z" }
1621
1621
  wheels = [
1622
- { url = "https://files.pythonhosted.org/packages/bc/56/190ceb8cb10511b730b564fb1e0293fa468363dbad26145c34928a60cb0c/urllib3-2.6.1-py3-none-any.whl", hash = "sha256:e67d06fe947c36a7ca39f4994b08d73922d40e6cca949907be05efa6fd75110b", size = 131138, upload-time = "2025-12-08T15:25:25.51Z" },
1622
+ { url = "https://files.pythonhosted.org/packages/6d/b9/4095b668ea3678bf6a0af005527f39de12fb026516fb3df17495a733b7f8/urllib3-2.6.2-py3-none-any.whl", hash = "sha256:ec21cddfe7724fc7cb4ba4bea7aa8e2ef36f607a4bab81aa6ce42a13dc3f03dd", size = 131182, upload-time = "2025-12-11T15:56:38.584Z" },
1623
1623
  ]
1624
1624
 
1625
1625
  [[package]]