python3-commons 0.9.12__tar.gz → 0.9.14__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.
- {python3_commons-0.9.12 → python3_commons-0.9.14}/.pre-commit-config.yaml +2 -2
- {python3_commons-0.9.12 → python3_commons-0.9.14}/PKG-INFO +2 -2
- {python3_commons-0.9.12 → python3_commons-0.9.14}/pyproject.toml +1 -1
- {python3_commons-0.9.12 → python3_commons-0.9.14}/src/python3_commons/api_client.py +7 -2
- python3_commons-0.9.14/src/python3_commons/audit.py +185 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/src/python3_commons/helpers.py +6 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/src/python3_commons.egg-info/PKG-INFO +2 -2
- {python3_commons-0.9.12 → python3_commons-0.9.14}/src/python3_commons.egg-info/requires.txt +1 -1
- python3_commons-0.9.14/tests/test_audit.py +31 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/uv.lock +98 -98
- python3_commons-0.9.12/src/python3_commons/audit.py +0 -189
- python3_commons-0.9.12/tests/test_audit.py +0 -31
- {python3_commons-0.9.12 → python3_commons-0.9.14}/.coveragerc +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/.github/workflows/python-publish.yaml +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/.github/workflows/release-on-tag-push.yml +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/.gitignore +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/.python-version +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/AUTHORS.rst +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/CHANGELOG.rst +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/LICENSE +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/README.md +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/README.rst +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/docs/Makefile +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/docs/_static/.gitignore +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/docs/authors.rst +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/docs/changelog.rst +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/docs/conf.py +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/docs/index.rst +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/docs/license.rst +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/setup.cfg +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/src/python3_commons/__init__.py +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/src/python3_commons/auth.py +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/src/python3_commons/cache.py +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/src/python3_commons/conf.py +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/src/python3_commons/db/__init__.py +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/src/python3_commons/db/helpers.py +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/src/python3_commons/db/models/__init__.py +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/src/python3_commons/db/models/auth.py +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/src/python3_commons/db/models/common.py +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/src/python3_commons/db/models/rbac.py +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/src/python3_commons/fs.py +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/src/python3_commons/log/__init__.py +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/src/python3_commons/log/filters.py +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/src/python3_commons/log/formatters.py +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/src/python3_commons/object_storage.py +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/src/python3_commons/permissions.py +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/src/python3_commons/serializers/__init__.py +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/src/python3_commons/serializers/json.py +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/src/python3_commons/serializers/msgpack.py +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/src/python3_commons/serializers/msgspec.py +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/src/python3_commons.egg-info/SOURCES.txt +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/src/python3_commons.egg-info/dependency_links.txt +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/src/python3_commons.egg-info/top_level.txt +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/tests/conftest.py +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/tests/test_cache.py +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/tests/test_helpers.py +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/tests/test_msgpack.py +0 -0
- {python3_commons-0.9.12 → python3_commons-0.9.14}/tests/test_msgspec.py +0 -0
@@ -1,12 +1,12 @@
|
|
1
1
|
repos:
|
2
2
|
- repo: https://github.com/astral-sh/uv-pre-commit
|
3
|
-
rev: 0.8.
|
3
|
+
rev: 0.8.15
|
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.12.
|
9
|
+
rev: v0.12.12
|
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.
|
3
|
+
Version: 0.9.14
|
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
|
@@ -12,7 +12,7 @@ Requires-Python: ==3.13.*
|
|
12
12
|
Description-Content-Type: text/x-rst
|
13
13
|
License-File: LICENSE
|
14
14
|
License-File: AUTHORS.rst
|
15
|
-
Requires-Dist: aiobotocore~=2.24.
|
15
|
+
Requires-Dist: aiobotocore~=2.24.2
|
16
16
|
Requires-Dist: aiohttp[speedups]~=3.12.15
|
17
17
|
Requires-Dist: asyncpg~=0.30.0
|
18
18
|
Requires-Dist: fastapi-users-db-sqlalchemy~=7.0.0
|
@@ -8,6 +8,7 @@ from typing import AsyncGenerator, Literal, Mapping, Sequence
|
|
8
8
|
from uuid import uuid4
|
9
9
|
|
10
10
|
from aiohttp import ClientResponse, ClientSession, ClientTimeout, client_exceptions
|
11
|
+
from aiohttp.abc import URL
|
11
12
|
|
12
13
|
from python3_commons import audit
|
13
14
|
from python3_commons.conf import s3_settings
|
@@ -57,12 +58,15 @@ async def request(
|
|
57
58
|
|
58
59
|
if audit_name:
|
59
60
|
curl_request = None
|
61
|
+
cookies = client.cookie_jar.filter_cookies(URL(base_url))
|
60
62
|
|
61
63
|
if method == 'get':
|
62
64
|
if headers or query:
|
63
|
-
curl_request = request_to_curl(url, query, method, headers)
|
65
|
+
curl_request = request_to_curl(url=url, query=query, method=method, headers=headers, cookies=cookies)
|
64
66
|
else:
|
65
|
-
curl_request = request_to_curl(
|
67
|
+
curl_request = request_to_curl(
|
68
|
+
url=url, query=query, method=method, headers=headers, cookies=cookies, json=json, data=data
|
69
|
+
)
|
66
70
|
|
67
71
|
if curl_request:
|
68
72
|
await audit.write_audit_data(
|
@@ -70,6 +74,7 @@ async def request(
|
|
70
74
|
f'{date_path}/{audit_name}/{uri_path}/{method}_{timestamp}_{request_id}_request.txt',
|
71
75
|
curl_request.encode('utf-8'),
|
72
76
|
)
|
77
|
+
|
73
78
|
client_method = getattr(client, method)
|
74
79
|
|
75
80
|
logger.debug(f'Requesting {method} {url}')
|
@@ -0,0 +1,185 @@
|
|
1
|
+
import asyncio
|
2
|
+
import io
|
3
|
+
import logging
|
4
|
+
from datetime import UTC, datetime
|
5
|
+
from uuid import uuid4
|
6
|
+
|
7
|
+
from lxml import etree
|
8
|
+
from zeep.plugins import Plugin
|
9
|
+
from zeep.wsdl.definitions import AbstractOperation
|
10
|
+
|
11
|
+
from python3_commons import object_storage
|
12
|
+
from python3_commons.conf import S3Settings, s3_settings
|
13
|
+
|
14
|
+
logger = logging.getLogger(__name__)
|
15
|
+
|
16
|
+
|
17
|
+
# class GeneratedStream(io.BytesIO):
|
18
|
+
# def __init__(self, generator: AsyncGenerator[bytes], *args, **kwargs):
|
19
|
+
# super().__init__(*args, **kwargs)
|
20
|
+
# self.generator = generator
|
21
|
+
#
|
22
|
+
# def read(self, size: int = -1):
|
23
|
+
# if size < 0:
|
24
|
+
# while True:
|
25
|
+
# try:
|
26
|
+
# chunk = anext(self.generator)
|
27
|
+
# except StopIteration:
|
28
|
+
# break
|
29
|
+
# else:
|
30
|
+
# self.write(chunk)
|
31
|
+
# else:
|
32
|
+
# total_written_size = 0
|
33
|
+
#
|
34
|
+
# while total_written_size < size:
|
35
|
+
# try:
|
36
|
+
# chunk = anext(self.generator)
|
37
|
+
# except StopIteration:
|
38
|
+
# break
|
39
|
+
# else:
|
40
|
+
# total_written_size += self.write(chunk)
|
41
|
+
#
|
42
|
+
# self.seek(0)
|
43
|
+
#
|
44
|
+
# if chunk := super().read(size):
|
45
|
+
# pos = self.tell()
|
46
|
+
#
|
47
|
+
# buf = self.getbuffer()
|
48
|
+
# unread_data_size = len(buf) - pos
|
49
|
+
#
|
50
|
+
# if unread_data_size > 0:
|
51
|
+
# buf[:unread_data_size] = buf[pos : pos + unread_data_size]
|
52
|
+
#
|
53
|
+
# del buf
|
54
|
+
#
|
55
|
+
# self.seek(0)
|
56
|
+
# self.truncate(unread_data_size)
|
57
|
+
#
|
58
|
+
# return chunk
|
59
|
+
#
|
60
|
+
# def readable(self):
|
61
|
+
# return True
|
62
|
+
#
|
63
|
+
#
|
64
|
+
# async def generate_archive(
|
65
|
+
# objects: AsyncGenerator[tuple[str, datetime, bytes]], chunk_size: int = 4096
|
66
|
+
# ) -> AsyncGenerator[bytes]:
|
67
|
+
# buffer = deque()
|
68
|
+
#
|
69
|
+
# with tarfile.open(fileobj=buffer, mode='w') as archive:
|
70
|
+
# async for name, last_modified, content in objects:
|
71
|
+
# logger.info(f'Adding {name} to archive')
|
72
|
+
# info = tarfile.TarInfo(name)
|
73
|
+
# info.size = len(content)
|
74
|
+
# info.mtime = int(last_modified.timestamp())
|
75
|
+
# archive.addfile(info, io.BytesIO(content))
|
76
|
+
#
|
77
|
+
# buffer_length = buffer.tell()
|
78
|
+
#
|
79
|
+
# while buffer_length >= chunk_size:
|
80
|
+
# buffer.seek(0)
|
81
|
+
# chunk = buffer.read(chunk_size)
|
82
|
+
# chunk_len = len(chunk)
|
83
|
+
#
|
84
|
+
# if not chunk:
|
85
|
+
# break
|
86
|
+
#
|
87
|
+
# yield chunk
|
88
|
+
#
|
89
|
+
# buffer.seek(0)
|
90
|
+
# buffer.truncate(chunk_len)
|
91
|
+
# buffer.seek(0, io.SEEK_END)
|
92
|
+
# buffer_length = buffer.tell()
|
93
|
+
#
|
94
|
+
# while True:
|
95
|
+
# chunk = buffer.read(chunk_size)
|
96
|
+
#
|
97
|
+
# if not chunk:
|
98
|
+
# break
|
99
|
+
#
|
100
|
+
# yield chunk
|
101
|
+
#
|
102
|
+
# buffer.seek(0)
|
103
|
+
# buffer.truncate(0)
|
104
|
+
#
|
105
|
+
#
|
106
|
+
# async def generate_bzip2(chunks: AsyncGenerator[bytes]) -> AsyncGenerator[bytes]:
|
107
|
+
# compressor = BZ2Compressor()
|
108
|
+
#
|
109
|
+
# async for chunk in chunks:
|
110
|
+
# if compressed_chunk := compressor.compress(chunk):
|
111
|
+
# yield compressed_chunk
|
112
|
+
#
|
113
|
+
# if compressed_chunk := compressor.flush():
|
114
|
+
# yield compressed_chunk
|
115
|
+
#
|
116
|
+
|
117
|
+
# async def archive_audit_data(root_path: str = 'audit'):
|
118
|
+
# now = datetime.now(tz=UTC) - timedelta(days=1)
|
119
|
+
# year = now.year
|
120
|
+
# month = now.month
|
121
|
+
# day = now.day
|
122
|
+
# bucket_name = s3_settings.s3_bucket
|
123
|
+
# date_path = object_storage.get_absolute_path(f'{root_path}/{year}/{month:02}/{day:02}')
|
124
|
+
#
|
125
|
+
# if objects := object_storage.get_objects(bucket_name, date_path, recursive=True):
|
126
|
+
# logger.info(f'Compacting files in: {date_path}')
|
127
|
+
#
|
128
|
+
# generator = generate_archive(objects, chunk_size=900_000)
|
129
|
+
# bzip2_generator = generate_bzip2(generator)
|
130
|
+
# archive_stream = GeneratedStream(bzip2_generator)
|
131
|
+
#
|
132
|
+
# archive_path = object_storage.get_absolute_path(f'audit/.archive/{year}_{month:02}_{day:02}.tar.bz2')
|
133
|
+
# await object_storage.put_object(bucket_name, archive_path, archive_stream, -1, part_size=5 * 1024 * 1024)
|
134
|
+
#
|
135
|
+
# if errors := await object_storage.remove_objects(bucket_name, date_path):
|
136
|
+
# for error in errors:
|
137
|
+
# logger.error(f'Failed to delete object in {bucket_name=}: {error}')
|
138
|
+
|
139
|
+
|
140
|
+
async def write_audit_data(settings: S3Settings, key: str, data: bytes):
|
141
|
+
if settings.s3_secret_access_key:
|
142
|
+
try:
|
143
|
+
absolute_path = object_storage.get_absolute_path(f'audit/{key}')
|
144
|
+
|
145
|
+
await object_storage.put_object(settings.s3_bucket, absolute_path, io.BytesIO(data), len(data))
|
146
|
+
except Exception as e:
|
147
|
+
logger.error(f'Failed storing object in storage: {e}')
|
148
|
+
else:
|
149
|
+
logger.debug(f'Stored object in storage: {key}')
|
150
|
+
else:
|
151
|
+
logger.debug(f'S3 is not configured, not storing object in storage: {key}')
|
152
|
+
|
153
|
+
|
154
|
+
class ZeepAuditPlugin(Plugin):
|
155
|
+
def __init__(self, audit_name: str = 'zeep'):
|
156
|
+
super().__init__()
|
157
|
+
self.audit_name = audit_name
|
158
|
+
|
159
|
+
def store_audit_in_s3(self, envelope, operation: AbstractOperation, direction: str):
|
160
|
+
xml = etree.tostring(envelope, encoding='UTF-8', pretty_print=True)
|
161
|
+
now = datetime.now(tz=UTC)
|
162
|
+
date_path = now.strftime('%Y/%m/%d')
|
163
|
+
timestamp = now.strftime('%H%M%S')
|
164
|
+
path = f'{date_path}/{self.audit_name}/{operation.name}/{timestamp}_{str(uuid4())[-12:]}_{direction}.xml'
|
165
|
+
coro = write_audit_data(s3_settings, path, xml)
|
166
|
+
|
167
|
+
try:
|
168
|
+
loop = asyncio.get_running_loop()
|
169
|
+
except RuntimeError:
|
170
|
+
loop = None
|
171
|
+
|
172
|
+
if loop and loop.is_running():
|
173
|
+
loop.create_task(coro)
|
174
|
+
else:
|
175
|
+
asyncio.run(coro)
|
176
|
+
|
177
|
+
def ingress(self, envelope, http_headers, operation: AbstractOperation):
|
178
|
+
self.store_audit_in_s3(envelope, operation, 'ingress')
|
179
|
+
|
180
|
+
return envelope, http_headers
|
181
|
+
|
182
|
+
def egress(self, envelope, http_headers, operation: AbstractOperation, binding_options):
|
183
|
+
self.store_audit_in_s3(envelope, operation, 'egress')
|
184
|
+
|
185
|
+
return envelope, http_headers
|
@@ -8,6 +8,7 @@ from abc import ABCMeta
|
|
8
8
|
from collections import defaultdict
|
9
9
|
from datetime import date, datetime, timedelta
|
10
10
|
from decimal import ROUND_HALF_UP, Decimal
|
11
|
+
from http.cookies import BaseCookie
|
11
12
|
from json import dumps
|
12
13
|
from typing import Literal, Mapping, Sequence
|
13
14
|
from urllib.parse import urlencode
|
@@ -86,6 +87,7 @@ def request_to_curl(
|
|
86
87
|
query: Mapping | None = None,
|
87
88
|
method: Literal['get', 'post', 'put', 'patch', 'options', 'head', 'delete'] = 'get',
|
88
89
|
headers: Mapping | None = None,
|
90
|
+
cookies: BaseCookie[str] | None = None,
|
89
91
|
json: Mapping | Sequence | str | None = None,
|
90
92
|
data: bytes | None = None,
|
91
93
|
) -> str:
|
@@ -100,6 +102,10 @@ def request_to_curl(
|
|
100
102
|
curl_cmd.append('-H')
|
101
103
|
curl_cmd.append(shlex.quote(header_line))
|
102
104
|
|
105
|
+
if cookies:
|
106
|
+
cookie_str = '; '.join(f'{k}={v.value}' for k, v in cookies.items())
|
107
|
+
curl_cmd.extend(['-b', shlex.quote(cookie_str)])
|
108
|
+
|
103
109
|
if json:
|
104
110
|
curl_cmd.append('-H')
|
105
111
|
curl_cmd.append(shlex.quote('Content-Type: application/json'))
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: python3-commons
|
3
|
-
Version: 0.9.
|
3
|
+
Version: 0.9.14
|
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
|
@@ -12,7 +12,7 @@ Requires-Python: ==3.13.*
|
|
12
12
|
Description-Content-Type: text/x-rst
|
13
13
|
License-File: LICENSE
|
14
14
|
License-File: AUTHORS.rst
|
15
|
-
Requires-Dist: aiobotocore~=2.24.
|
15
|
+
Requires-Dist: aiobotocore~=2.24.2
|
16
16
|
Requires-Dist: aiohttp[speedups]~=3.12.15
|
17
17
|
Requires-Dist: asyncpg~=0.30.0
|
18
18
|
Requires-Dist: fastapi-users-db-sqlalchemy~=7.0.0
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# from io import BytesIO
|
2
|
+
#
|
3
|
+
# from python3_commons.audit import GeneratedStream, generate_archive, generate_bzip2
|
4
|
+
#
|
5
|
+
#
|
6
|
+
# def test_generated_stream(s3_file_objects):
|
7
|
+
# expected_data = b''
|
8
|
+
# generator = generate_archive(s3_file_objects, chunk_size=5 * 1024 * 1024)
|
9
|
+
# bzip2_generator = generate_bzip2(generator)
|
10
|
+
# archive_stream = GeneratedStream(bzip2_generator)
|
11
|
+
# archived_data = archive_stream.read()
|
12
|
+
#
|
13
|
+
# with open('/tmp/test.tar.bz2', 'wb') as f:
|
14
|
+
# f.write(archived_data)
|
15
|
+
#
|
16
|
+
# assert archived_data == expected_data
|
17
|
+
#
|
18
|
+
#
|
19
|
+
# def test_generated_stream_by_chunks(s3_file_objects):
|
20
|
+
# expected_data = b''
|
21
|
+
# generator = generate_archive(s3_file_objects, chunk_size=2)
|
22
|
+
# bzip2_generator = generate_bzip2(generator)
|
23
|
+
# archive_stream = GeneratedStream(bzip2_generator)
|
24
|
+
# archived_data = BytesIO()
|
25
|
+
#
|
26
|
+
# with open('/tmp/test_chunked.tar.bz2', 'wb') as f:
|
27
|
+
# while chunk := archive_stream.read(2):
|
28
|
+
# f.write(chunk)
|
29
|
+
# archived_data.write(chunk)
|
30
|
+
#
|
31
|
+
# assert archived_data.getvalue() == expected_data
|
@@ -4,7 +4,7 @@ requires-python = "==3.13.*"
|
|
4
4
|
|
5
5
|
[[package]]
|
6
6
|
name = "aiobotocore"
|
7
|
-
version = "2.24.
|
7
|
+
version = "2.24.2"
|
8
8
|
source = { registry = "https://pypi.org/simple" }
|
9
9
|
dependencies = [
|
10
10
|
{ name = "aiohttp" },
|
@@ -15,9 +15,9 @@ dependencies = [
|
|
15
15
|
{ name = "python-dateutil" },
|
16
16
|
{ name = "wrapt" },
|
17
17
|
]
|
18
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
18
|
+
sdist = { url = "https://files.pythonhosted.org/packages/05/93/9f5243c2fd2fc22cff92f8d8a7e98d3080171be60778d49aeabb555a463d/aiobotocore-2.24.2.tar.gz", hash = "sha256:dfb21bdb2610e8de4d22f401e91a24d50f1330a302d03c62c485757becd439a9", size = 119837, upload-time = "2025-09-05T12:13:46.963Z" }
|
19
19
|
wheels = [
|
20
|
-
{ url = "https://files.pythonhosted.org/packages/
|
20
|
+
{ url = "https://files.pythonhosted.org/packages/87/03/2330062ac4ea9fa6447e02b0625f24efd6f05b6c44d61d86610b3555ee66/aiobotocore-2.24.2-py3-none-any.whl", hash = "sha256:808c63b2bd344b91e2f2acb874831118a9f53342d248acd16a68455a226e283a", size = 85441, upload-time = "2025-09-05T12:13:45.378Z" },
|
21
21
|
]
|
22
22
|
|
23
23
|
[[package]]
|
@@ -235,16 +235,16 @@ wheels = [
|
|
235
235
|
|
236
236
|
[[package]]
|
237
237
|
name = "botocore"
|
238
|
-
version = "1.
|
238
|
+
version = "1.40.18"
|
239
239
|
source = { registry = "https://pypi.org/simple" }
|
240
240
|
dependencies = [
|
241
241
|
{ name = "jmespath" },
|
242
242
|
{ name = "python-dateutil" },
|
243
243
|
{ name = "urllib3" },
|
244
244
|
]
|
245
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
245
|
+
sdist = { url = "https://files.pythonhosted.org/packages/6a/91/2e745382793fa7d30810a7d5ca3e05f6817b6db07601ca5aaab12720caf9/botocore-1.40.18.tar.gz", hash = "sha256:afd69bdadd8c55cc89d69de0799829e555193a352d87867f746e19020271cc0f", size = 14375007, upload-time = "2025-08-26T19:21:24.996Z" }
|
246
246
|
wheels = [
|
247
|
-
{ url = "https://files.pythonhosted.org/packages/
|
247
|
+
{ url = "https://files.pythonhosted.org/packages/1a/f5/bd57bf21fdcc4e500cc406ed2c296e626ddd160f0fee2a4932256e5d62d8/botocore-1.40.18-py3-none-any.whl", hash = "sha256:57025c46ca00cf8cec25de07a759521bfbfb3036a0f69b272654a354615dc45f", size = 14039935, upload-time = "2025-08-26T19:21:19.085Z" },
|
248
248
|
]
|
249
249
|
|
250
250
|
[[package]]
|
@@ -369,68 +369,68 @@ wheels = [
|
|
369
369
|
|
370
370
|
[[package]]
|
371
371
|
name = "coverage"
|
372
|
-
version = "7.10.
|
373
|
-
source = { registry = "https://pypi.org/simple" }
|
374
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
375
|
-
wheels = [
|
376
|
-
{ url = "https://files.pythonhosted.org/packages/
|
377
|
-
{ url = "https://files.pythonhosted.org/packages/
|
378
|
-
{ url = "https://files.pythonhosted.org/packages/
|
379
|
-
{ url = "https://files.pythonhosted.org/packages/
|
380
|
-
{ url = "https://files.pythonhosted.org/packages/
|
381
|
-
{ url = "https://files.pythonhosted.org/packages/
|
382
|
-
{ url = "https://files.pythonhosted.org/packages/
|
383
|
-
{ url = "https://files.pythonhosted.org/packages/
|
384
|
-
{ url = "https://files.pythonhosted.org/packages/
|
385
|
-
{ url = "https://files.pythonhosted.org/packages/
|
386
|
-
{ url = "https://files.pythonhosted.org/packages/
|
387
|
-
{ url = "https://files.pythonhosted.org/packages/
|
388
|
-
{ url = "https://files.pythonhosted.org/packages/
|
389
|
-
{ url = "https://files.pythonhosted.org/packages/
|
390
|
-
{ url = "https://files.pythonhosted.org/packages/
|
391
|
-
{ url = "https://files.pythonhosted.org/packages/
|
392
|
-
{ url = "https://files.pythonhosted.org/packages/
|
393
|
-
{ url = "https://files.pythonhosted.org/packages/
|
394
|
-
{ url = "https://files.pythonhosted.org/packages/
|
395
|
-
{ url = "https://files.pythonhosted.org/packages/
|
396
|
-
{ url = "https://files.pythonhosted.org/packages/
|
397
|
-
{ url = "https://files.pythonhosted.org/packages/
|
398
|
-
{ url = "https://files.pythonhosted.org/packages/
|
372
|
+
version = "7.10.6"
|
373
|
+
source = { registry = "https://pypi.org/simple" }
|
374
|
+
sdist = { url = "https://files.pythonhosted.org/packages/14/70/025b179c993f019105b79575ac6edb5e084fb0f0e63f15cdebef4e454fb5/coverage-7.10.6.tar.gz", hash = "sha256:f644a3ae5933a552a29dbb9aa2f90c677a875f80ebea028e5a52a4f429044b90", size = 823736, upload-time = "2025-08-29T15:35:16.668Z" }
|
375
|
+
wheels = [
|
376
|
+
{ url = "https://files.pythonhosted.org/packages/bd/e7/917e5953ea29a28c1057729c1d5af9084ab6d9c66217523fd0e10f14d8f6/coverage-7.10.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ffea0575345e9ee0144dfe5701aa17f3ba546f8c3bb48db62ae101afb740e7d6", size = 217351, upload-time = "2025-08-29T15:33:45.438Z" },
|
377
|
+
{ url = "https://files.pythonhosted.org/packages/eb/86/2e161b93a4f11d0ea93f9bebb6a53f113d5d6e416d7561ca41bb0a29996b/coverage-7.10.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:95d91d7317cde40a1c249d6b7382750b7e6d86fad9d8eaf4fa3f8f44cf171e80", size = 217600, upload-time = "2025-08-29T15:33:47.269Z" },
|
378
|
+
{ url = "https://files.pythonhosted.org/packages/0e/66/d03348fdd8df262b3a7fb4ee5727e6e4936e39e2f3a842e803196946f200/coverage-7.10.6-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3e23dd5408fe71a356b41baa82892772a4cefcf758f2ca3383d2aa39e1b7a003", size = 248600, upload-time = "2025-08-29T15:33:48.953Z" },
|
379
|
+
{ url = "https://files.pythonhosted.org/packages/73/dd/508420fb47d09d904d962f123221bc249f64b5e56aa93d5f5f7603be475f/coverage-7.10.6-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0f3f56e4cb573755e96a16501a98bf211f100463d70275759e73f3cbc00d4f27", size = 251206, upload-time = "2025-08-29T15:33:50.697Z" },
|
380
|
+
{ url = "https://files.pythonhosted.org/packages/e9/1f/9020135734184f439da85c70ea78194c2730e56c2d18aee6e8ff1719d50d/coverage-7.10.6-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:db4a1d897bbbe7339946ffa2fe60c10cc81c43fab8b062d3fcb84188688174a4", size = 252478, upload-time = "2025-08-29T15:33:52.303Z" },
|
381
|
+
{ url = "https://files.pythonhosted.org/packages/a4/a4/3d228f3942bb5a2051fde28c136eea23a761177dc4ff4ef54533164ce255/coverage-7.10.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d8fd7879082953c156d5b13c74aa6cca37f6a6f4747b39538504c3f9c63d043d", size = 250637, upload-time = "2025-08-29T15:33:53.67Z" },
|
382
|
+
{ url = "https://files.pythonhosted.org/packages/36/e3/293dce8cdb9a83de971637afc59b7190faad60603b40e32635cbd15fbf61/coverage-7.10.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:28395ca3f71cd103b8c116333fa9db867f3a3e1ad6a084aa3725ae002b6583bc", size = 248529, upload-time = "2025-08-29T15:33:55.022Z" },
|
383
|
+
{ url = "https://files.pythonhosted.org/packages/90/26/64eecfa214e80dd1d101e420cab2901827de0e49631d666543d0e53cf597/coverage-7.10.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:61c950fc33d29c91b9e18540e1aed7d9f6787cc870a3e4032493bbbe641d12fc", size = 250143, upload-time = "2025-08-29T15:33:56.386Z" },
|
384
|
+
{ url = "https://files.pythonhosted.org/packages/3e/70/bd80588338f65ea5b0d97e424b820fb4068b9cfb9597fbd91963086e004b/coverage-7.10.6-cp313-cp313-win32.whl", hash = "sha256:160c00a5e6b6bdf4e5984b0ef21fc860bc94416c41b7df4d63f536d17c38902e", size = 219770, upload-time = "2025-08-29T15:33:58.063Z" },
|
385
|
+
{ url = "https://files.pythonhosted.org/packages/a7/14/0b831122305abcc1060c008f6c97bbdc0a913ab47d65070a01dc50293c2b/coverage-7.10.6-cp313-cp313-win_amd64.whl", hash = "sha256:628055297f3e2aa181464c3808402887643405573eb3d9de060d81531fa79d32", size = 220566, upload-time = "2025-08-29T15:33:59.766Z" },
|
386
|
+
{ url = "https://files.pythonhosted.org/packages/83/c6/81a83778c1f83f1a4a168ed6673eeedc205afb562d8500175292ca64b94e/coverage-7.10.6-cp313-cp313-win_arm64.whl", hash = "sha256:df4ec1f8540b0bcbe26ca7dd0f541847cc8a108b35596f9f91f59f0c060bfdd2", size = 219195, upload-time = "2025-08-29T15:34:01.191Z" },
|
387
|
+
{ url = "https://files.pythonhosted.org/packages/d7/1c/ccccf4bf116f9517275fa85047495515add43e41dfe8e0bef6e333c6b344/coverage-7.10.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:c9a8b7a34a4de3ed987f636f71881cd3b8339f61118b1aa311fbda12741bff0b", size = 218059, upload-time = "2025-08-29T15:34:02.91Z" },
|
388
|
+
{ url = "https://files.pythonhosted.org/packages/92/97/8a3ceff833d27c7492af4f39d5da6761e9ff624831db9e9f25b3886ddbca/coverage-7.10.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:8dd5af36092430c2b075cee966719898f2ae87b636cefb85a653f1d0ba5d5393", size = 218287, upload-time = "2025-08-29T15:34:05.106Z" },
|
389
|
+
{ url = "https://files.pythonhosted.org/packages/92/d8/50b4a32580cf41ff0423777a2791aaf3269ab60c840b62009aec12d3970d/coverage-7.10.6-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b0353b0f0850d49ada66fdd7d0c7cdb0f86b900bb9e367024fd14a60cecc1e27", size = 259625, upload-time = "2025-08-29T15:34:06.575Z" },
|
390
|
+
{ url = "https://files.pythonhosted.org/packages/7e/7e/6a7df5a6fb440a0179d94a348eb6616ed4745e7df26bf2a02bc4db72c421/coverage-7.10.6-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d6b9ae13d5d3e8aeca9ca94198aa7b3ebbc5acfada557d724f2a1f03d2c0b0df", size = 261801, upload-time = "2025-08-29T15:34:08.006Z" },
|
391
|
+
{ url = "https://files.pythonhosted.org/packages/3a/4c/a270a414f4ed5d196b9d3d67922968e768cd971d1b251e1b4f75e9362f75/coverage-7.10.6-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:675824a363cc05781b1527b39dc2587b8984965834a748177ee3c37b64ffeafb", size = 264027, upload-time = "2025-08-29T15:34:09.806Z" },
|
392
|
+
{ url = "https://files.pythonhosted.org/packages/9c/8b/3210d663d594926c12f373c5370bf1e7c5c3a427519a8afa65b561b9a55c/coverage-7.10.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:692d70ea725f471a547c305f0d0fc6a73480c62fb0da726370c088ab21aed282", size = 261576, upload-time = "2025-08-29T15:34:11.585Z" },
|
393
|
+
{ url = "https://files.pythonhosted.org/packages/72/d0/e1961eff67e9e1dba3fc5eb7a4caf726b35a5b03776892da8d79ec895775/coverage-7.10.6-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:851430a9a361c7a8484a36126d1d0ff8d529d97385eacc8dfdc9bfc8c2d2cbe4", size = 259341, upload-time = "2025-08-29T15:34:13.159Z" },
|
394
|
+
{ url = "https://files.pythonhosted.org/packages/3a/06/d6478d152cd189b33eac691cba27a40704990ba95de49771285f34a5861e/coverage-7.10.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d9369a23186d189b2fc95cc08b8160ba242057e887d766864f7adf3c46b2df21", size = 260468, upload-time = "2025-08-29T15:34:14.571Z" },
|
395
|
+
{ url = "https://files.pythonhosted.org/packages/ed/73/737440247c914a332f0b47f7598535b29965bf305e19bbc22d4c39615d2b/coverage-7.10.6-cp313-cp313t-win32.whl", hash = "sha256:92be86fcb125e9bda0da7806afd29a3fd33fdf58fba5d60318399adf40bf37d0", size = 220429, upload-time = "2025-08-29T15:34:16.394Z" },
|
396
|
+
{ url = "https://files.pythonhosted.org/packages/bd/76/b92d3214740f2357ef4a27c75a526eb6c28f79c402e9f20a922c295c05e2/coverage-7.10.6-cp313-cp313t-win_amd64.whl", hash = "sha256:6b3039e2ca459a70c79523d39347d83b73f2f06af5624905eba7ec34d64d80b5", size = 221493, upload-time = "2025-08-29T15:34:17.835Z" },
|
397
|
+
{ url = "https://files.pythonhosted.org/packages/fc/8e/6dcb29c599c8a1f654ec6cb68d76644fe635513af16e932d2d4ad1e5ac6e/coverage-7.10.6-cp313-cp313t-win_arm64.whl", hash = "sha256:3fb99d0786fe17b228eab663d16bee2288e8724d26a199c29325aac4b0319b9b", size = 219757, upload-time = "2025-08-29T15:34:19.248Z" },
|
398
|
+
{ url = "https://files.pythonhosted.org/packages/44/0c/50db5379b615854b5cf89146f8f5bd1d5a9693d7f3a987e269693521c404/coverage-7.10.6-py3-none-any.whl", hash = "sha256:92c4ecf6bf11b2e85fd4d8204814dc26e6a19f0c9d938c207c5cb0eadfcabbe3", size = 208986, upload-time = "2025-08-29T15:35:14.506Z" },
|
399
399
|
]
|
400
400
|
|
401
401
|
[[package]]
|
402
402
|
name = "cryptography"
|
403
|
-
version = "45.0.
|
403
|
+
version = "45.0.7"
|
404
404
|
source = { registry = "https://pypi.org/simple" }
|
405
405
|
dependencies = [
|
406
406
|
{ name = "cffi", marker = "platform_python_implementation != 'PyPy'" },
|
407
407
|
]
|
408
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
409
|
-
wheels = [
|
410
|
-
{ url = "https://files.pythonhosted.org/packages/
|
411
|
-
{ url = "https://files.pythonhosted.org/packages/
|
412
|
-
{ url = "https://files.pythonhosted.org/packages/
|
413
|
-
{ url = "https://files.pythonhosted.org/packages/
|
414
|
-
{ url = "https://files.pythonhosted.org/packages/
|
415
|
-
{ url = "https://files.pythonhosted.org/packages/
|
416
|
-
{ url = "https://files.pythonhosted.org/packages/
|
417
|
-
{ url = "https://files.pythonhosted.org/packages/
|
418
|
-
{ url = "https://files.pythonhosted.org/packages/
|
419
|
-
{ url = "https://files.pythonhosted.org/packages/
|
420
|
-
{ url = "https://files.pythonhosted.org/packages/
|
421
|
-
{ url = "https://files.pythonhosted.org/packages/
|
422
|
-
{ url = "https://files.pythonhosted.org/packages/
|
423
|
-
{ url = "https://files.pythonhosted.org/packages/
|
424
|
-
{ url = "https://files.pythonhosted.org/packages/
|
425
|
-
{ url = "https://files.pythonhosted.org/packages/
|
426
|
-
{ url = "https://files.pythonhosted.org/packages/
|
427
|
-
{ url = "https://files.pythonhosted.org/packages/
|
428
|
-
{ url = "https://files.pythonhosted.org/packages/
|
429
|
-
{ url = "https://files.pythonhosted.org/packages/
|
430
|
-
{ url = "https://files.pythonhosted.org/packages/
|
431
|
-
{ url = "https://files.pythonhosted.org/packages/
|
432
|
-
{ url = "https://files.pythonhosted.org/packages/
|
433
|
-
{ url = "https://files.pythonhosted.org/packages/
|
408
|
+
sdist = { url = "https://files.pythonhosted.org/packages/a7/35/c495bffc2056f2dadb32434f1feedd79abde2a7f8363e1974afa9c33c7e2/cryptography-45.0.7.tar.gz", hash = "sha256:4b1654dfc64ea479c242508eb8c724044f1e964a47d1d1cacc5132292d851971", size = 744980, upload-time = "2025-09-01T11:15:03.146Z" }
|
409
|
+
wheels = [
|
410
|
+
{ url = "https://files.pythonhosted.org/packages/0c/91/925c0ac74362172ae4516000fe877912e33b5983df735ff290c653de4913/cryptography-45.0.7-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:3be4f21c6245930688bd9e162829480de027f8bf962ede33d4f8ba7d67a00cee", size = 7041105, upload-time = "2025-09-01T11:13:59.684Z" },
|
411
|
+
{ url = "https://files.pythonhosted.org/packages/fc/63/43641c5acce3a6105cf8bd5baeceeb1846bb63067d26dae3e5db59f1513a/cryptography-45.0.7-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:67285f8a611b0ebc0857ced2081e30302909f571a46bfa7a3cc0ad303fe015c6", size = 4205799, upload-time = "2025-09-01T11:14:02.517Z" },
|
412
|
+
{ url = "https://files.pythonhosted.org/packages/bc/29/c238dd9107f10bfde09a4d1c52fd38828b1aa353ced11f358b5dd2507d24/cryptography-45.0.7-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:577470e39e60a6cd7780793202e63536026d9b8641de011ed9d8174da9ca5339", size = 4430504, upload-time = "2025-09-01T11:14:04.522Z" },
|
413
|
+
{ url = "https://files.pythonhosted.org/packages/62/62/24203e7cbcc9bd7c94739428cd30680b18ae6b18377ae66075c8e4771b1b/cryptography-45.0.7-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:4bd3e5c4b9682bc112d634f2c6ccc6736ed3635fc3319ac2bb11d768cc5a00d8", size = 4209542, upload-time = "2025-09-01T11:14:06.309Z" },
|
414
|
+
{ url = "https://files.pythonhosted.org/packages/cd/e3/e7de4771a08620eef2389b86cd87a2c50326827dea5528feb70595439ce4/cryptography-45.0.7-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:465ccac9d70115cd4de7186e60cfe989de73f7bb23e8a7aa45af18f7412e75bf", size = 3889244, upload-time = "2025-09-01T11:14:08.152Z" },
|
415
|
+
{ url = "https://files.pythonhosted.org/packages/96/b8/bca71059e79a0bb2f8e4ec61d9c205fbe97876318566cde3b5092529faa9/cryptography-45.0.7-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:16ede8a4f7929b4b7ff3642eba2bf79aa1d71f24ab6ee443935c0d269b6bc513", size = 4461975, upload-time = "2025-09-01T11:14:09.755Z" },
|
416
|
+
{ url = "https://files.pythonhosted.org/packages/58/67/3f5b26937fe1218c40e95ef4ff8d23c8dc05aa950d54200cc7ea5fb58d28/cryptography-45.0.7-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:8978132287a9d3ad6b54fcd1e08548033cc09dc6aacacb6c004c73c3eb5d3ac3", size = 4209082, upload-time = "2025-09-01T11:14:11.229Z" },
|
417
|
+
{ url = "https://files.pythonhosted.org/packages/0e/e4/b3e68a4ac363406a56cf7b741eeb80d05284d8c60ee1a55cdc7587e2a553/cryptography-45.0.7-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:b6a0e535baec27b528cb07a119f321ac024592388c5681a5ced167ae98e9fff3", size = 4460397, upload-time = "2025-09-01T11:14:12.924Z" },
|
418
|
+
{ url = "https://files.pythonhosted.org/packages/22/49/2c93f3cd4e3efc8cb22b02678c1fad691cff9dd71bb889e030d100acbfe0/cryptography-45.0.7-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:a24ee598d10befaec178efdff6054bc4d7e883f615bfbcd08126a0f4931c83a6", size = 4337244, upload-time = "2025-09-01T11:14:14.431Z" },
|
419
|
+
{ url = "https://files.pythonhosted.org/packages/04/19/030f400de0bccccc09aa262706d90f2ec23d56bc4eb4f4e8268d0ddf3fb8/cryptography-45.0.7-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:fa26fa54c0a9384c27fcdc905a2fb7d60ac6e47d14bc2692145f2b3b1e2cfdbd", size = 4568862, upload-time = "2025-09-01T11:14:16.185Z" },
|
420
|
+
{ url = "https://files.pythonhosted.org/packages/29/56/3034a3a353efa65116fa20eb3c990a8c9f0d3db4085429040a7eef9ada5f/cryptography-45.0.7-cp311-abi3-win32.whl", hash = "sha256:bef32a5e327bd8e5af915d3416ffefdbe65ed975b646b3805be81b23580b57b8", size = 2936578, upload-time = "2025-09-01T11:14:17.638Z" },
|
421
|
+
{ url = "https://files.pythonhosted.org/packages/b3/61/0ab90f421c6194705a99d0fa9f6ee2045d916e4455fdbb095a9c2c9a520f/cryptography-45.0.7-cp311-abi3-win_amd64.whl", hash = "sha256:3808e6b2e5f0b46d981c24d79648e5c25c35e59902ea4391a0dcb3e667bf7443", size = 3405400, upload-time = "2025-09-01T11:14:18.958Z" },
|
422
|
+
{ url = "https://files.pythonhosted.org/packages/63/e8/c436233ddf19c5f15b25ace33979a9dd2e7aa1a59209a0ee8554179f1cc0/cryptography-45.0.7-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bfb4c801f65dd61cedfc61a83732327fafbac55a47282e6f26f073ca7a41c3b2", size = 7021824, upload-time = "2025-09-01T11:14:20.954Z" },
|
423
|
+
{ url = "https://files.pythonhosted.org/packages/bc/4c/8f57f2500d0ccd2675c5d0cc462095adf3faa8c52294ba085c036befb901/cryptography-45.0.7-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:81823935e2f8d476707e85a78a405953a03ef7b7b4f55f93f7c2d9680e5e0691", size = 4202233, upload-time = "2025-09-01T11:14:22.454Z" },
|
424
|
+
{ url = "https://files.pythonhosted.org/packages/eb/ac/59b7790b4ccaed739fc44775ce4645c9b8ce54cbec53edf16c74fd80cb2b/cryptography-45.0.7-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3994c809c17fc570c2af12c9b840d7cea85a9fd3e5c0e0491f4fa3c029216d59", size = 4423075, upload-time = "2025-09-01T11:14:24.287Z" },
|
425
|
+
{ url = "https://files.pythonhosted.org/packages/b8/56/d4f07ea21434bf891faa088a6ac15d6d98093a66e75e30ad08e88aa2b9ba/cryptography-45.0.7-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:dad43797959a74103cb59c5dac71409f9c27d34c8a05921341fb64ea8ccb1dd4", size = 4204517, upload-time = "2025-09-01T11:14:25.679Z" },
|
426
|
+
{ url = "https://files.pythonhosted.org/packages/e8/ac/924a723299848b4c741c1059752c7cfe09473b6fd77d2920398fc26bfb53/cryptography-45.0.7-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ce7a453385e4c4693985b4a4a3533e041558851eae061a58a5405363b098fcd3", size = 3882893, upload-time = "2025-09-01T11:14:27.1Z" },
|
427
|
+
{ url = "https://files.pythonhosted.org/packages/83/dc/4dab2ff0a871cc2d81d3ae6d780991c0192b259c35e4d83fe1de18b20c70/cryptography-45.0.7-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:b04f85ac3a90c227b6e5890acb0edbaf3140938dbecf07bff618bf3638578cf1", size = 4450132, upload-time = "2025-09-01T11:14:28.58Z" },
|
428
|
+
{ url = "https://files.pythonhosted.org/packages/12/dd/b2882b65db8fc944585d7fb00d67cf84a9cef4e77d9ba8f69082e911d0de/cryptography-45.0.7-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:48c41a44ef8b8c2e80ca4527ee81daa4c527df3ecbc9423c41a420a9559d0e27", size = 4204086, upload-time = "2025-09-01T11:14:30.572Z" },
|
429
|
+
{ url = "https://files.pythonhosted.org/packages/5d/fa/1d5745d878048699b8eb87c984d4ccc5da4f5008dfd3ad7a94040caca23a/cryptography-45.0.7-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:f3df7b3d0f91b88b2106031fd995802a2e9ae13e02c36c1fc075b43f420f3a17", size = 4449383, upload-time = "2025-09-01T11:14:32.046Z" },
|
430
|
+
{ url = "https://files.pythonhosted.org/packages/36/8b/fc61f87931bc030598e1876c45b936867bb72777eac693e905ab89832670/cryptography-45.0.7-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:dd342f085542f6eb894ca00ef70236ea46070c8a13824c6bde0dfdcd36065b9b", size = 4332186, upload-time = "2025-09-01T11:14:33.95Z" },
|
431
|
+
{ url = "https://files.pythonhosted.org/packages/0b/11/09700ddad7443ccb11d674efdbe9a832b4455dc1f16566d9bd3834922ce5/cryptography-45.0.7-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1993a1bb7e4eccfb922b6cd414f072e08ff5816702a0bdb8941c247a6b1b287c", size = 4561639, upload-time = "2025-09-01T11:14:35.343Z" },
|
432
|
+
{ url = "https://files.pythonhosted.org/packages/71/ed/8f4c1337e9d3b94d8e50ae0b08ad0304a5709d483bfcadfcc77a23dbcb52/cryptography-45.0.7-cp37-abi3-win32.whl", hash = "sha256:18fcf70f243fe07252dcb1b268a687f2358025ce32f9f88028ca5c364b123ef5", size = 2926552, upload-time = "2025-09-01T11:14:36.929Z" },
|
433
|
+
{ url = "https://files.pythonhosted.org/packages/bc/ff/026513ecad58dacd45d1d24ebe52b852165a26e287177de1d545325c0c25/cryptography-45.0.7-cp37-abi3-win_amd64.whl", hash = "sha256:7285a89df4900ed3bfaad5679b1e668cb4b38a8de1ccbfc84b05f34512da0a90", size = 3392742, upload-time = "2025-09-01T11:14:38.368Z" },
|
434
434
|
]
|
435
435
|
|
436
436
|
[[package]]
|
@@ -804,11 +804,11 @@ wheels = [
|
|
804
804
|
|
805
805
|
[[package]]
|
806
806
|
name = "platformdirs"
|
807
|
-
version = "4.
|
807
|
+
version = "4.4.0"
|
808
808
|
source = { registry = "https://pypi.org/simple" }
|
809
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
809
|
+
sdist = { url = "https://files.pythonhosted.org/packages/23/e8/21db9c9987b0e728855bd57bff6984f67952bea55d6f75e055c46b5383e8/platformdirs-4.4.0.tar.gz", hash = "sha256:ca753cf4d81dc309bc67b0ea38fd15dc97bc30ce419a7f58d13eb3bf14c4febf", size = 21634, upload-time = "2025-08-26T14:32:04.268Z" }
|
810
810
|
wheels = [
|
811
|
-
{ url = "https://files.pythonhosted.org/packages/
|
811
|
+
{ url = "https://files.pythonhosted.org/packages/40/4b/2028861e724d3bd36227adfa20d3fd24c3fc6d52032f4a93c133be5d17ce/platformdirs-4.4.0-py3-none-any.whl", hash = "sha256:abd01743f24e5287cd7a5db3752faf1a2d65353f38ec26d98e25a6db65958c85", size = 18654, upload-time = "2025-08-26T14:32:02.735Z" },
|
812
812
|
]
|
813
813
|
|
814
814
|
[[package]]
|
@@ -1032,20 +1032,20 @@ wheels = [
|
|
1032
1032
|
|
1033
1033
|
[[package]]
|
1034
1034
|
name = "pyright"
|
1035
|
-
version = "1.1.
|
1035
|
+
version = "1.1.405"
|
1036
1036
|
source = { registry = "https://pypi.org/simple" }
|
1037
1037
|
dependencies = [
|
1038
1038
|
{ name = "nodeenv" },
|
1039
1039
|
{ name = "typing-extensions" },
|
1040
1040
|
]
|
1041
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
1041
|
+
sdist = { url = "https://files.pythonhosted.org/packages/fb/6c/ba4bbee22e76af700ea593a1d8701e3225080956753bee9750dcc25e2649/pyright-1.1.405.tar.gz", hash = "sha256:5c2a30e1037af27eb463a1cc0b9f6d65fec48478ccf092c1ac28385a15c55763", size = 4068319, upload-time = "2025-09-04T03:37:06.776Z" }
|
1042
1042
|
wheels = [
|
1043
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1043
|
+
{ url = "https://files.pythonhosted.org/packages/d5/1a/524f832e1ff1962a22a1accc775ca7b143ba2e9f5924bb6749dce566784a/pyright-1.1.405-py3-none-any.whl", hash = "sha256:a2cb13700b5508ce8e5d4546034cb7ea4aedb60215c6c33f56cec7f53996035a", size = 5905038, upload-time = "2025-09-04T03:37:04.913Z" },
|
1044
1044
|
]
|
1045
1045
|
|
1046
1046
|
[[package]]
|
1047
1047
|
name = "pytest"
|
1048
|
-
version = "8.4.
|
1048
|
+
version = "8.4.2"
|
1049
1049
|
source = { registry = "https://pypi.org/simple" }
|
1050
1050
|
dependencies = [
|
1051
1051
|
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
@@ -1054,9 +1054,9 @@ dependencies = [
|
|
1054
1054
|
{ name = "pluggy" },
|
1055
1055
|
{ name = "pygments" },
|
1056
1056
|
]
|
1057
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
1057
|
+
sdist = { url = "https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size = 1519618, upload-time = "2025-09-04T14:34:22.711Z" }
|
1058
1058
|
wheels = [
|
1059
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1059
|
+
{ url = "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size = 365750, upload-time = "2025-09-04T14:34:20.226Z" },
|
1060
1060
|
]
|
1061
1061
|
|
1062
1062
|
[[package]]
|
@@ -1087,14 +1087,14 @@ wheels = [
|
|
1087
1087
|
|
1088
1088
|
[[package]]
|
1089
1089
|
name = "pytest-mock"
|
1090
|
-
version = "3.
|
1090
|
+
version = "3.15.0"
|
1091
1091
|
source = { registry = "https://pypi.org/simple" }
|
1092
1092
|
dependencies = [
|
1093
1093
|
{ name = "pytest" },
|
1094
1094
|
]
|
1095
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
1095
|
+
sdist = { url = "https://files.pythonhosted.org/packages/61/99/3323ee5c16b3637b4d941c362182d3e749c11e400bea31018c42219f3a98/pytest_mock-3.15.0.tar.gz", hash = "sha256:ab896bd190316b9d5d87b277569dfcdf718b2d049a2ccff5f7aca279c002a1cf", size = 33838, upload-time = "2025-09-04T20:57:48.679Z" }
|
1096
1096
|
wheels = [
|
1097
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1097
|
+
{ url = "https://files.pythonhosted.org/packages/2b/b3/7fefc43fb706380144bcd293cc6e446e6f637ddfa8b83f48d1734156b529/pytest_mock-3.15.0-py3-none-any.whl", hash = "sha256:ef2219485fb1bd256b00e7ad7466ce26729b30eadfc7cbcdb4fa9a92ca68db6f", size = 10050, upload-time = "2025-09-04T20:57:47.274Z" },
|
1098
1098
|
]
|
1099
1099
|
|
1100
1100
|
[[package]]
|
@@ -1182,7 +1182,7 @@ testing = [
|
|
1182
1182
|
|
1183
1183
|
[package.metadata]
|
1184
1184
|
requires-dist = [
|
1185
|
-
{ name = "aiobotocore", specifier = "~=2.24.
|
1185
|
+
{ name = "aiobotocore", specifier = "~=2.24.2" },
|
1186
1186
|
{ name = "aiohttp", extras = ["speedups"], specifier = "~=3.12.15" },
|
1187
1187
|
{ name = "asyncpg", specifier = "~=0.30.0" },
|
1188
1188
|
{ name = "fastapi-users", extras = ["sqlalchemy"], specifier = "~=14.0.1" },
|
@@ -1296,28 +1296,28 @@ wheels = [
|
|
1296
1296
|
|
1297
1297
|
[[package]]
|
1298
1298
|
name = "ruff"
|
1299
|
-
version = "0.12.
|
1300
|
-
source = { registry = "https://pypi.org/simple" }
|
1301
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
1302
|
-
wheels = [
|
1303
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1304
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1305
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1306
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1307
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1308
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1309
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1310
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1311
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1312
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1313
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1314
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1315
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1316
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1317
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1318
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1319
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1320
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1299
|
+
version = "0.12.12"
|
1300
|
+
source = { registry = "https://pypi.org/simple" }
|
1301
|
+
sdist = { url = "https://files.pythonhosted.org/packages/a8/f0/e0965dd709b8cabe6356811c0ee8c096806bb57d20b5019eb4e48a117410/ruff-0.12.12.tar.gz", hash = "sha256:b86cd3415dbe31b3b46a71c598f4c4b2f550346d1ccf6326b347cc0c8fd063d6", size = 5359915, upload-time = "2025-09-04T16:50:18.273Z" }
|
1302
|
+
wheels = [
|
1303
|
+
{ url = "https://files.pythonhosted.org/packages/09/79/8d3d687224d88367b51c7974cec1040c4b015772bfbeffac95face14c04a/ruff-0.12.12-py3-none-linux_armv6l.whl", hash = "sha256:de1c4b916d98ab289818e55ce481e2cacfaad7710b01d1f990c497edf217dafc", size = 12116602, upload-time = "2025-09-04T16:49:18.892Z" },
|
1304
|
+
{ url = "https://files.pythonhosted.org/packages/c3/c3/6e599657fe192462f94861a09aae935b869aea8a1da07f47d6eae471397c/ruff-0.12.12-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:7acd6045e87fac75a0b0cdedacf9ab3e1ad9d929d149785903cff9bb69ad9727", size = 12868393, upload-time = "2025-09-04T16:49:23.043Z" },
|
1305
|
+
{ url = "https://files.pythonhosted.org/packages/e8/d2/9e3e40d399abc95336b1843f52fc0daaceb672d0e3c9290a28ff1a96f79d/ruff-0.12.12-py3-none-macosx_11_0_arm64.whl", hash = "sha256:abf4073688d7d6da16611f2f126be86523a8ec4343d15d276c614bda8ec44edb", size = 12036967, upload-time = "2025-09-04T16:49:26.04Z" },
|
1306
|
+
{ url = "https://files.pythonhosted.org/packages/e9/03/6816b2ed08836be272e87107d905f0908be5b4a40c14bfc91043e76631b8/ruff-0.12.12-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:968e77094b1d7a576992ac078557d1439df678a34c6fe02fd979f973af167577", size = 12276038, upload-time = "2025-09-04T16:49:29.056Z" },
|
1307
|
+
{ url = "https://files.pythonhosted.org/packages/9f/d5/707b92a61310edf358a389477eabd8af68f375c0ef858194be97ca5b6069/ruff-0.12.12-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42a67d16e5b1ffc6d21c5f67851e0e769517fb57a8ebad1d0781b30888aa704e", size = 11901110, upload-time = "2025-09-04T16:49:32.07Z" },
|
1308
|
+
{ url = "https://files.pythonhosted.org/packages/9d/3d/f8b1038f4b9822e26ec3d5b49cf2bc313e3c1564cceb4c1a42820bf74853/ruff-0.12.12-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b216ec0a0674e4b1214dcc998a5088e54eaf39417327b19ffefba1c4a1e4971e", size = 13668352, upload-time = "2025-09-04T16:49:35.148Z" },
|
1309
|
+
{ url = "https://files.pythonhosted.org/packages/98/0e/91421368ae6c4f3765dd41a150f760c5f725516028a6be30e58255e3c668/ruff-0.12.12-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:59f909c0fdd8f1dcdbfed0b9569b8bf428cf144bec87d9de298dcd4723f5bee8", size = 14638365, upload-time = "2025-09-04T16:49:38.892Z" },
|
1310
|
+
{ url = "https://files.pythonhosted.org/packages/74/5d/88f3f06a142f58ecc8ecb0c2fe0b82343e2a2b04dcd098809f717cf74b6c/ruff-0.12.12-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9ac93d87047e765336f0c18eacad51dad0c1c33c9df7484c40f98e1d773876f5", size = 14060812, upload-time = "2025-09-04T16:49:42.732Z" },
|
1311
|
+
{ url = "https://files.pythonhosted.org/packages/13/fc/8962e7ddd2e81863d5c92400820f650b86f97ff919c59836fbc4c1a6d84c/ruff-0.12.12-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:01543c137fd3650d322922e8b14cc133b8ea734617c4891c5a9fccf4bfc9aa92", size = 13050208, upload-time = "2025-09-04T16:49:46.434Z" },
|
1312
|
+
{ url = "https://files.pythonhosted.org/packages/53/06/8deb52d48a9a624fd37390555d9589e719eac568c020b27e96eed671f25f/ruff-0.12.12-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2afc2fa864197634e549d87fb1e7b6feb01df0a80fd510d6489e1ce8c0b1cc45", size = 13311444, upload-time = "2025-09-04T16:49:49.931Z" },
|
1313
|
+
{ url = "https://files.pythonhosted.org/packages/2a/81/de5a29af7eb8f341f8140867ffb93f82e4fde7256dadee79016ac87c2716/ruff-0.12.12-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:0c0945246f5ad776cb8925e36af2438e66188d2b57d9cf2eed2c382c58b371e5", size = 13279474, upload-time = "2025-09-04T16:49:53.465Z" },
|
1314
|
+
{ url = "https://files.pythonhosted.org/packages/7f/14/d9577fdeaf791737ada1b4f5c6b59c21c3326f3f683229096cccd7674e0c/ruff-0.12.12-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a0fbafe8c58e37aae28b84a80ba1817f2ea552e9450156018a478bf1fa80f4e4", size = 12070204, upload-time = "2025-09-04T16:49:56.882Z" },
|
1315
|
+
{ url = "https://files.pythonhosted.org/packages/77/04/a910078284b47fad54506dc0af13839c418ff704e341c176f64e1127e461/ruff-0.12.12-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:b9c456fb2fc8e1282affa932c9e40f5ec31ec9cbb66751a316bd131273b57c23", size = 11880347, upload-time = "2025-09-04T16:49:59.729Z" },
|
1316
|
+
{ url = "https://files.pythonhosted.org/packages/df/58/30185fcb0e89f05e7ea82e5817b47798f7fa7179863f9d9ba6fd4fe1b098/ruff-0.12.12-py3-none-musllinux_1_2_i686.whl", hash = "sha256:5f12856123b0ad0147d90b3961f5c90e7427f9acd4b40050705499c98983f489", size = 12891844, upload-time = "2025-09-04T16:50:02.591Z" },
|
1317
|
+
{ url = "https://files.pythonhosted.org/packages/21/9c/28a8dacce4855e6703dcb8cdf6c1705d0b23dd01d60150786cd55aa93b16/ruff-0.12.12-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:26a1b5a2bf7dd2c47e3b46d077cd9c0fc3b93e6c6cc9ed750bd312ae9dc302ee", size = 13360687, upload-time = "2025-09-04T16:50:05.8Z" },
|
1318
|
+
{ url = "https://files.pythonhosted.org/packages/c8/fa/05b6428a008e60f79546c943e54068316f32ec8ab5c4f73e4563934fbdc7/ruff-0.12.12-py3-none-win32.whl", hash = "sha256:173be2bfc142af07a01e3a759aba6f7791aa47acf3604f610b1c36db888df7b1", size = 12052870, upload-time = "2025-09-04T16:50:09.121Z" },
|
1319
|
+
{ url = "https://files.pythonhosted.org/packages/85/60/d1e335417804df452589271818749d061b22772b87efda88354cf35cdb7a/ruff-0.12.12-py3-none-win_amd64.whl", hash = "sha256:e99620bf01884e5f38611934c09dd194eb665b0109104acae3ba6102b600fd0d", size = 13178016, upload-time = "2025-09-04T16:50:12.559Z" },
|
1320
|
+
{ url = "https://files.pythonhosted.org/packages/28/7e/61c42657f6e4614a4258f1c3b0c5b93adc4d1f8575f5229d1906b483099b/ruff-0.12.12-py3-none-win_arm64.whl", hash = "sha256:2a8199cab4ce4d72d158319b63370abf60991495fb733db96cd923a34c52d093", size = 12256762, upload-time = "2025-09-04T16:50:15.737Z" },
|
1321
1321
|
]
|
1322
1322
|
|
1323
1323
|
[[package]]
|
@@ -1409,11 +1409,11 @@ wheels = [
|
|
1409
1409
|
|
1410
1410
|
[[package]]
|
1411
1411
|
name = "typing-extensions"
|
1412
|
-
version = "4.
|
1412
|
+
version = "4.15.0"
|
1413
1413
|
source = { registry = "https://pypi.org/simple" }
|
1414
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
1414
|
+
sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
|
1415
1415
|
wheels = [
|
1416
|
-
{ url = "https://files.pythonhosted.org/packages/
|
1416
|
+
{ url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
|
1417
1417
|
]
|
1418
1418
|
|
1419
1419
|
[[package]]
|
@@ -1,189 +0,0 @@
|
|
1
|
-
import asyncio
|
2
|
-
import io
|
3
|
-
import logging
|
4
|
-
import tarfile
|
5
|
-
from bz2 import BZ2Compressor
|
6
|
-
from collections import deque
|
7
|
-
from datetime import UTC, datetime, timedelta
|
8
|
-
from typing import AsyncGenerator
|
9
|
-
from uuid import uuid4
|
10
|
-
|
11
|
-
from lxml import etree
|
12
|
-
from zeep.plugins import Plugin
|
13
|
-
from zeep.wsdl.definitions import AbstractOperation
|
14
|
-
|
15
|
-
from python3_commons import object_storage
|
16
|
-
from python3_commons.conf import S3Settings, s3_settings
|
17
|
-
|
18
|
-
logger = logging.getLogger(__name__)
|
19
|
-
|
20
|
-
|
21
|
-
class GeneratedStream(io.BytesIO):
|
22
|
-
def __init__(self, generator: AsyncGenerator[bytes], *args, **kwargs):
|
23
|
-
super().__init__(*args, **kwargs)
|
24
|
-
self.generator = generator
|
25
|
-
|
26
|
-
def read(self, size: int = -1):
|
27
|
-
if size < 0:
|
28
|
-
while True:
|
29
|
-
try:
|
30
|
-
chunk = anext(self.generator)
|
31
|
-
except StopIteration:
|
32
|
-
break
|
33
|
-
else:
|
34
|
-
self.write(chunk)
|
35
|
-
else:
|
36
|
-
total_written_size = 0
|
37
|
-
|
38
|
-
while total_written_size < size:
|
39
|
-
try:
|
40
|
-
chunk = anext(self.generator)
|
41
|
-
except StopIteration:
|
42
|
-
break
|
43
|
-
else:
|
44
|
-
total_written_size += self.write(chunk)
|
45
|
-
|
46
|
-
self.seek(0)
|
47
|
-
|
48
|
-
if chunk := super().read(size):
|
49
|
-
pos = self.tell()
|
50
|
-
|
51
|
-
buf = self.getbuffer()
|
52
|
-
unread_data_size = len(buf) - pos
|
53
|
-
|
54
|
-
if unread_data_size > 0:
|
55
|
-
buf[:unread_data_size] = buf[pos : pos + unread_data_size]
|
56
|
-
|
57
|
-
del buf
|
58
|
-
|
59
|
-
self.seek(0)
|
60
|
-
self.truncate(unread_data_size)
|
61
|
-
|
62
|
-
return chunk
|
63
|
-
|
64
|
-
def readable(self):
|
65
|
-
return True
|
66
|
-
|
67
|
-
|
68
|
-
async def generate_archive(
|
69
|
-
objects: AsyncGenerator[tuple[str, datetime, bytes]], chunk_size: int = 4096
|
70
|
-
) -> AsyncGenerator[bytes]:
|
71
|
-
buffer = deque()
|
72
|
-
|
73
|
-
with tarfile.open(fileobj=buffer, mode='w') as archive:
|
74
|
-
async for name, last_modified, content in objects:
|
75
|
-
logger.info(f'Adding {name} to archive')
|
76
|
-
info = tarfile.TarInfo(name)
|
77
|
-
info.size = len(content)
|
78
|
-
info.mtime = int(last_modified.timestamp())
|
79
|
-
archive.addfile(info, io.BytesIO(content))
|
80
|
-
|
81
|
-
buffer_length = buffer.tell()
|
82
|
-
|
83
|
-
while buffer_length >= chunk_size:
|
84
|
-
buffer.seek(0)
|
85
|
-
chunk = buffer.read(chunk_size)
|
86
|
-
chunk_len = len(chunk)
|
87
|
-
|
88
|
-
if not chunk:
|
89
|
-
break
|
90
|
-
|
91
|
-
yield chunk
|
92
|
-
|
93
|
-
buffer.seek(0)
|
94
|
-
buffer.truncate(chunk_len)
|
95
|
-
buffer.seek(0, io.SEEK_END)
|
96
|
-
buffer_length = buffer.tell()
|
97
|
-
|
98
|
-
while True:
|
99
|
-
chunk = buffer.read(chunk_size)
|
100
|
-
|
101
|
-
if not chunk:
|
102
|
-
break
|
103
|
-
|
104
|
-
yield chunk
|
105
|
-
|
106
|
-
buffer.seek(0)
|
107
|
-
buffer.truncate(0)
|
108
|
-
|
109
|
-
|
110
|
-
async def generate_bzip2(chunks: AsyncGenerator[bytes]) -> AsyncGenerator[bytes]:
|
111
|
-
compressor = BZ2Compressor()
|
112
|
-
|
113
|
-
async for chunk in chunks:
|
114
|
-
if compressed_chunk := compressor.compress(chunk):
|
115
|
-
yield compressed_chunk
|
116
|
-
|
117
|
-
if compressed_chunk := compressor.flush():
|
118
|
-
yield compressed_chunk
|
119
|
-
|
120
|
-
|
121
|
-
async def write_audit_data(settings: S3Settings, key: str, data: bytes):
|
122
|
-
if settings.s3_secret_access_key:
|
123
|
-
try:
|
124
|
-
absolute_path = object_storage.get_absolute_path(f'audit/{key}')
|
125
|
-
|
126
|
-
await object_storage.put_object(settings.s3_bucket, absolute_path, io.BytesIO(data), len(data))
|
127
|
-
except Exception as e:
|
128
|
-
logger.error(f'Failed storing object in storage: {e}')
|
129
|
-
else:
|
130
|
-
logger.debug(f'Stored object in storage: {key}')
|
131
|
-
else:
|
132
|
-
logger.debug(f'S3 is not configured, not storing object in storage: {key}')
|
133
|
-
|
134
|
-
|
135
|
-
async def archive_audit_data(root_path: str = 'audit'):
|
136
|
-
now = datetime.now(tz=UTC) - timedelta(days=1)
|
137
|
-
year = now.year
|
138
|
-
month = now.month
|
139
|
-
day = now.day
|
140
|
-
bucket_name = s3_settings.s3_bucket
|
141
|
-
date_path = object_storage.get_absolute_path(f'{root_path}/{year}/{month:02}/{day:02}')
|
142
|
-
|
143
|
-
if objects := object_storage.get_objects(bucket_name, date_path, recursive=True):
|
144
|
-
logger.info(f'Compacting files in: {date_path}')
|
145
|
-
|
146
|
-
generator = generate_archive(objects, chunk_size=900_000)
|
147
|
-
bzip2_generator = generate_bzip2(generator)
|
148
|
-
archive_stream = GeneratedStream(bzip2_generator)
|
149
|
-
|
150
|
-
archive_path = object_storage.get_absolute_path(f'audit/.archive/{year}_{month:02}_{day:02}.tar.bz2')
|
151
|
-
await object_storage.put_object(bucket_name, archive_path, archive_stream, -1, part_size=5 * 1024 * 1024)
|
152
|
-
|
153
|
-
if errors := await object_storage.remove_objects(bucket_name, date_path):
|
154
|
-
for error in errors:
|
155
|
-
logger.error(f'Failed to delete object in {bucket_name=}: {error}')
|
156
|
-
|
157
|
-
|
158
|
-
class ZeepAuditPlugin(Plugin):
|
159
|
-
def __init__(self, audit_name: str = 'zeep'):
|
160
|
-
super().__init__()
|
161
|
-
self.audit_name = audit_name
|
162
|
-
|
163
|
-
def store_audit_in_s3(self, envelope, operation: AbstractOperation, direction: str):
|
164
|
-
xml = etree.tostring(envelope, encoding='UTF-8', pretty_print=True)
|
165
|
-
now = datetime.now(tz=UTC)
|
166
|
-
date_path = now.strftime('%Y/%m/%d')
|
167
|
-
timestamp = now.strftime('%H%M%S')
|
168
|
-
path = f'{date_path}/{self.audit_name}/{operation.name}/{timestamp}_{str(uuid4())[-12:]}_{direction}.xml'
|
169
|
-
coro = write_audit_data(s3_settings, path, xml)
|
170
|
-
|
171
|
-
try:
|
172
|
-
loop = asyncio.get_running_loop()
|
173
|
-
except RuntimeError:
|
174
|
-
loop = None
|
175
|
-
|
176
|
-
if loop and loop.is_running():
|
177
|
-
loop.create_task(coro)
|
178
|
-
else:
|
179
|
-
asyncio.run(coro)
|
180
|
-
|
181
|
-
def ingress(self, envelope, http_headers, operation: AbstractOperation):
|
182
|
-
self.store_audit_in_s3(envelope, operation, 'ingress')
|
183
|
-
|
184
|
-
return envelope, http_headers
|
185
|
-
|
186
|
-
def egress(self, envelope, http_headers, operation: AbstractOperation, binding_options):
|
187
|
-
self.store_audit_in_s3(envelope, operation, 'egress')
|
188
|
-
|
189
|
-
return envelope, http_headers
|
@@ -1,31 +0,0 @@
|
|
1
|
-
from io import BytesIO
|
2
|
-
|
3
|
-
from python3_commons.audit import GeneratedStream, generate_archive, generate_bzip2
|
4
|
-
|
5
|
-
|
6
|
-
def test_generated_stream(s3_file_objects):
|
7
|
-
expected_data = b''
|
8
|
-
generator = generate_archive(s3_file_objects, chunk_size=5 * 1024 * 1024)
|
9
|
-
bzip2_generator = generate_bzip2(generator)
|
10
|
-
archive_stream = GeneratedStream(bzip2_generator)
|
11
|
-
archived_data = archive_stream.read()
|
12
|
-
|
13
|
-
with open('/tmp/test.tar.bz2', 'wb') as f:
|
14
|
-
f.write(archived_data)
|
15
|
-
|
16
|
-
assert archived_data == expected_data
|
17
|
-
|
18
|
-
|
19
|
-
def test_generated_stream_by_chunks(s3_file_objects):
|
20
|
-
expected_data = b''
|
21
|
-
generator = generate_archive(s3_file_objects, chunk_size=2)
|
22
|
-
bzip2_generator = generate_bzip2(generator)
|
23
|
-
archive_stream = GeneratedStream(bzip2_generator)
|
24
|
-
archived_data = BytesIO()
|
25
|
-
|
26
|
-
with open('/tmp/test_chunked.tar.bz2', 'wb') as f:
|
27
|
-
while chunk := archive_stream.read(2):
|
28
|
-
f.write(chunk)
|
29
|
-
archived_data.write(chunk)
|
30
|
-
|
31
|
-
assert archived_data.getvalue() == expected_data
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{python3_commons-0.9.12 → python3_commons-0.9.14}/src/python3_commons/serializers/__init__.py
RENAMED
File without changes
|
File without changes
|
{python3_commons-0.9.12 → python3_commons-0.9.14}/src/python3_commons/serializers/msgpack.py
RENAMED
File without changes
|
{python3_commons-0.9.12 → python3_commons-0.9.14}/src/python3_commons/serializers/msgspec.py
RENAMED
File without changes
|
File without changes
|
{python3_commons-0.9.12 → python3_commons-0.9.14}/src/python3_commons.egg-info/dependency_links.txt
RENAMED
File without changes
|
{python3_commons-0.9.12 → python3_commons-0.9.14}/src/python3_commons.egg-info/top_level.txt
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|