python3-commons 0.5.7__tar.gz → 0.5.9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of python3-commons might be problematic. Click here for more details.
- {python3_commons-0.5.7/src/python3_commons.egg-info → python3_commons-0.5.9}/PKG-INFO +1 -1
- {python3_commons-0.5.7 → python3_commons-0.5.9}/setup.cfg +1 -1
- {python3_commons-0.5.7 → python3_commons-0.5.9}/src/python3_commons/audit.py +71 -20
- {python3_commons-0.5.7 → python3_commons-0.5.9}/src/python3_commons/object_storage.py +2 -7
- {python3_commons-0.5.7 → python3_commons-0.5.9/src/python3_commons.egg-info}/PKG-INFO +1 -1
- {python3_commons-0.5.7 → python3_commons-0.5.9}/.coveragerc +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/.github/workflows/python-publish.yaml +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/.gitignore +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/AUTHORS.rst +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/CHANGELOG.rst +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/LICENSE +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/README.md +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/README.rst +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/docs/Makefile +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/docs/_static/.gitignore +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/docs/authors.rst +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/docs/changelog.rst +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/docs/conf.py +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/docs/index.rst +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/docs/license.rst +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/pyproject.toml +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/requirements.txt +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/requirements_dev.txt +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/requirements_test.txt +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/setup.py +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/src/python3_commons/__init__.py +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/src/python3_commons/conf.py +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/src/python3_commons/db.py +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/src/python3_commons/fs.py +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/src/python3_commons/helpers.py +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/src/python3_commons/logging/__init__.py +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/src/python3_commons/logging/filters.py +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/src/python3_commons/logging/formatter.py +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/src/python3_commons/serializers/__init__.py +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/src/python3_commons/serializers/json.py +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/src/python3_commons/serializers/msgpack.py +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/src/python3_commons/serializers/msgspec.py +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/src/python3_commons.egg-info/SOURCES.txt +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/src/python3_commons.egg-info/dependency_links.txt +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/src/python3_commons.egg-info/not-zip-safe +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/src/python3_commons.egg-info/requires.txt +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/src/python3_commons.egg-info/top_level.txt +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/tests/conftest.py +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/tests/test_msgpack.py +0 -0
- {python3_commons-0.5.7 → python3_commons-0.5.9}/tests/test_msgspec.py +0 -0
|
@@ -4,6 +4,7 @@ import logging
|
|
|
4
4
|
import tarfile
|
|
5
5
|
from datetime import datetime, timedelta, UTC
|
|
6
6
|
from io import BytesIO
|
|
7
|
+
from typing import Generator
|
|
7
8
|
from uuid import uuid4
|
|
8
9
|
|
|
9
10
|
from lxml import etree
|
|
@@ -18,6 +19,69 @@ from python3_commons.object_storage import get_s3_client
|
|
|
18
19
|
logger = logging.getLogger(__name__)
|
|
19
20
|
|
|
20
21
|
|
|
22
|
+
class BytesIOStream(io.BytesIO):
|
|
23
|
+
def __init__(self, generator: Generator[bytes, None, None], *args, **kwargs):
|
|
24
|
+
super().__init__(*args, **kwargs)
|
|
25
|
+
self.generator = generator
|
|
26
|
+
|
|
27
|
+
def read(self, size: int = -1):
|
|
28
|
+
if size == -1:
|
|
29
|
+
size = 4096
|
|
30
|
+
|
|
31
|
+
while self.tell() < size:
|
|
32
|
+
try:
|
|
33
|
+
chunk = next(self.generator)
|
|
34
|
+
except StopIteration:
|
|
35
|
+
break
|
|
36
|
+
|
|
37
|
+
self.write(chunk)
|
|
38
|
+
|
|
39
|
+
if chunk := self.read(size):
|
|
40
|
+
pos = self.tell()
|
|
41
|
+
|
|
42
|
+
buf = self.getbuffer()
|
|
43
|
+
unread_data_size = len(buf) - pos
|
|
44
|
+
|
|
45
|
+
if unread_data_size > 0:
|
|
46
|
+
buf[:unread_data_size] = buf[pos:pos+unread_data_size]
|
|
47
|
+
|
|
48
|
+
self.truncate(unread_data_size)
|
|
49
|
+
self.seek(0)
|
|
50
|
+
|
|
51
|
+
return chunk
|
|
52
|
+
|
|
53
|
+
def readable(self):
|
|
54
|
+
return True
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def generate_archive(bucket_name: str, date_path: str, chunk_size: int = 4096) -> Generator[bytes, None, None]:
|
|
58
|
+
buffer = io.BytesIO()
|
|
59
|
+
|
|
60
|
+
with tarfile.open(fileobj=buffer, mode='w|bz2') as archive:
|
|
61
|
+
objects = object_storage.get_objects(bucket_name, date_path, recursive=True)
|
|
62
|
+
|
|
63
|
+
if objects:
|
|
64
|
+
logger.info(f'Compacting files in: {date_path}')
|
|
65
|
+
|
|
66
|
+
for name, last_modified, content in objects:
|
|
67
|
+
info = tarfile.TarInfo(name)
|
|
68
|
+
info.size = len(content)
|
|
69
|
+
info.mtime = last_modified.timestamp()
|
|
70
|
+
archive.addfile(info, io.BytesIO(content))
|
|
71
|
+
buffer.seek(0)
|
|
72
|
+
|
|
73
|
+
while True:
|
|
74
|
+
chunk = buffer.read(chunk_size)
|
|
75
|
+
|
|
76
|
+
if not chunk:
|
|
77
|
+
break
|
|
78
|
+
|
|
79
|
+
yield chunk
|
|
80
|
+
|
|
81
|
+
buffer.seek(0)
|
|
82
|
+
buffer.truncate(0)
|
|
83
|
+
|
|
84
|
+
|
|
21
85
|
def write_audit_data_sync(settings: S3Settings, key: str, data: bytes):
|
|
22
86
|
if settings.s3_secret_access_key:
|
|
23
87
|
try:
|
|
@@ -45,25 +109,14 @@ async def archive_audit_data(root_path: str = 'audit'):
|
|
|
45
109
|
bucket_name = s3_settings.s3_bucket
|
|
46
110
|
fo = BytesIO()
|
|
47
111
|
object_names = []
|
|
48
|
-
date_path = f'{root_path}/{year}/{month:02}/{day:02}'
|
|
49
|
-
|
|
50
|
-
with tarfile.open(fileobj=fo, mode='w|bz2') as archive:
|
|
51
|
-
if objects := object_storage.get_objects(bucket_name, date_path, recursive=True):
|
|
52
|
-
logger.info(f'Compacting files in: {date_path}')
|
|
53
|
-
|
|
54
|
-
for name, last_modified, content in objects:
|
|
55
|
-
info = tarfile.TarInfo(name)
|
|
56
|
-
info.size = len(content)
|
|
57
|
-
info.mtime = last_modified.timestamp()
|
|
58
|
-
archive.addfile(info, BytesIO(content))
|
|
59
|
-
object_names.append(name)
|
|
112
|
+
date_path = object_storage.get_absolute_path(f'{root_path}/{year}/{month:02}/{day:02}')
|
|
60
113
|
|
|
61
|
-
|
|
114
|
+
generator = generate_archive(bucket_name, date_path, chunk_size=4096)
|
|
115
|
+
archive_stream = BytesIOStream(generator)
|
|
62
116
|
|
|
63
117
|
if object_names:
|
|
64
|
-
archive_path = object_storage.get_absolute_path(
|
|
65
|
-
|
|
66
|
-
object_storage.put_object(bucket_name, archive_path, fo, fo.getbuffer().nbytes)
|
|
118
|
+
archive_path = object_storage.get_absolute_path(f'audit/.archive/{year}_{month:02}_{day:02}.tar.bz2')
|
|
119
|
+
object_storage.put_object(bucket_name, archive_path, archive_stream, -1, part_size=4096)
|
|
67
120
|
|
|
68
121
|
if errors := object_storage.remove_objects(bucket_name, object_names=object_names):
|
|
69
122
|
for error in errors:
|
|
@@ -82,10 +135,8 @@ class ZeepAuditPlugin(Plugin):
|
|
|
82
135
|
now = datetime.now(tz=UTC)
|
|
83
136
|
date_path = now.strftime('%Y/%m/%d')
|
|
84
137
|
timestamp = now.strftime('%H%M%S')
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
f'{date_path}/{self.audit_name}/{operation.name}/{timestamp}_{str(uuid4())[-12:]}_{direction}.xml', xml
|
|
88
|
-
)
|
|
138
|
+
path = f'{date_path}/{self.audit_name}/{operation.name}/{timestamp}_{str(uuid4())[-12:]}_{direction}.xml'
|
|
139
|
+
coro = write_audit_data(s3_settings, path, xml)
|
|
89
140
|
|
|
90
141
|
try:
|
|
91
142
|
loop = asyncio.get_running_loop()
|
|
@@ -39,12 +39,11 @@ def get_absolute_path(path: str) -> str:
|
|
|
39
39
|
return path
|
|
40
40
|
|
|
41
41
|
|
|
42
|
-
def put_object(bucket_name: str, path: str, data: io.BytesIO, length: int) -> str:
|
|
42
|
+
def put_object(bucket_name: str, path: str, data: io.BytesIO, length: int, part_size: int = 0) -> str:
|
|
43
43
|
s3_client = get_s3_client(s3_settings)
|
|
44
44
|
|
|
45
45
|
if s3_client:
|
|
46
|
-
|
|
47
|
-
result = s3_client.put_object(bucket_name, path, data, length)
|
|
46
|
+
result = s3_client.put_object(bucket_name, path, data, length, part_size=part_size)
|
|
48
47
|
|
|
49
48
|
logger.debug(f'Stored object into object storage: {bucket_name}:{path}')
|
|
50
49
|
|
|
@@ -57,7 +56,6 @@ def get_object_stream(bucket_name: str, path: str):
|
|
|
57
56
|
s3_client = get_s3_client(s3_settings)
|
|
58
57
|
|
|
59
58
|
if s3_client:
|
|
60
|
-
path = get_absolute_path(path)
|
|
61
59
|
logger.debug(f'Getting object from object storage: {bucket_name}:{path}')
|
|
62
60
|
|
|
63
61
|
try:
|
|
@@ -94,8 +92,6 @@ def list_objects(bucket_name: str, prefix: str, recursive: bool = True) -> Gener
|
|
|
94
92
|
|
|
95
93
|
def get_objects(bucket_name: str, path: str,
|
|
96
94
|
recursive: bool = True) -> Generator[tuple[str, datetime, bytes], None, None]:
|
|
97
|
-
path = get_absolute_path(path)
|
|
98
|
-
|
|
99
95
|
for obj in list_objects(bucket_name, path, recursive):
|
|
100
96
|
object_name = obj.object_name
|
|
101
97
|
|
|
@@ -117,7 +113,6 @@ def remove_objects(bucket_name: str, prefix: str = None,
|
|
|
117
113
|
s3_client = get_s3_client(s3_settings)
|
|
118
114
|
|
|
119
115
|
if prefix:
|
|
120
|
-
prefix = get_absolute_path(prefix)
|
|
121
116
|
delete_object_list = map(
|
|
122
117
|
lambda obj: DeleteObject(obj.object_name), s3_client.list_objects(bucket_name, prefix=prefix,
|
|
123
118
|
recursive=True)
|
|
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.5.7 → python3_commons-0.5.9}/src/python3_commons.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|