python3-commons 0.5.17__tar.gz → 0.5.19__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.17/src/python3_commons.egg-info → python3_commons-0.5.19}/PKG-INFO +2 -2
- {python3_commons-0.5.17 → python3_commons-0.5.19}/requirements.txt +1 -1
- {python3_commons-0.5.17 → python3_commons-0.5.19}/setup.cfg +2 -2
- {python3_commons-0.5.17 → python3_commons-0.5.19}/src/python3_commons/audit.py +20 -10
- {python3_commons-0.5.17 → python3_commons-0.5.19}/src/python3_commons/object_storage.py +10 -14
- {python3_commons-0.5.17 → python3_commons-0.5.19}/src/python3_commons/stream_tar.py +21 -18
- {python3_commons-0.5.17 → python3_commons-0.5.19/src/python3_commons.egg-info}/PKG-INFO +2 -2
- {python3_commons-0.5.17 → python3_commons-0.5.19}/src/python3_commons.egg-info/requires.txt +1 -1
- python3_commons-0.5.19/tests/test_audit.py +29 -0
- python3_commons-0.5.17/tests/test_audit.py +0 -10
- {python3_commons-0.5.17 → python3_commons-0.5.19}/.coveragerc +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/.github/workflows/python-publish.yaml +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/.gitignore +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/AUTHORS.rst +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/CHANGELOG.rst +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/LICENSE +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/README.md +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/README.rst +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/docs/Makefile +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/docs/_static/.gitignore +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/docs/authors.rst +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/docs/changelog.rst +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/docs/conf.py +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/docs/index.rst +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/docs/license.rst +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/pyproject.toml +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/requirements_dev.txt +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/requirements_test.txt +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/setup.py +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/src/python3_commons/__init__.py +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/src/python3_commons/conf.py +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/src/python3_commons/db.py +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/src/python3_commons/fs.py +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/src/python3_commons/helpers.py +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/src/python3_commons/logging/__init__.py +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/src/python3_commons/logging/filters.py +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/src/python3_commons/logging/formatter.py +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/src/python3_commons/serializers/__init__.py +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/src/python3_commons/serializers/json.py +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/src/python3_commons/serializers/msgpack.py +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/src/python3_commons/serializers/msgspec.py +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/src/python3_commons.egg-info/SOURCES.txt +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/src/python3_commons.egg-info/dependency_links.txt +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/src/python3_commons.egg-info/not-zip-safe +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/src/python3_commons.egg-info/top_level.txt +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/tests/conftest.py +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/tests/test_msgpack.py +0 -0
- {python3_commons-0.5.17 → python3_commons-0.5.19}/tests/test_msgspec.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: python3-commons
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.19
|
|
4
4
|
Summary: Re-usable Python3 code
|
|
5
5
|
Home-page: https://github.com/kamikaze/python3-commons
|
|
6
6
|
Author: Oleg Korsak
|
|
@@ -20,7 +20,7 @@ Requires-Dist: minio==7.2.7
|
|
|
20
20
|
Requires-Dist: msgpack==1.0.8
|
|
21
21
|
Requires-Dist: msgspec==0.18.6
|
|
22
22
|
Requires-Dist: pydantic[email]==2.8.2
|
|
23
|
-
Requires-Dist: pydantic-settings==2.
|
|
23
|
+
Requires-Dist: pydantic-settings==2.4.0
|
|
24
24
|
Requires-Dist: zeep==4.2.1
|
|
25
25
|
Provides-Extra: testing
|
|
26
26
|
Requires-Dist: pytest; extra == "testing"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[metadata]
|
|
2
2
|
name = python3-commons
|
|
3
|
-
version = 0.5.
|
|
3
|
+
version = 0.5.19
|
|
4
4
|
description = Re-usable Python3 code
|
|
5
5
|
author = Oleg Korsak
|
|
6
6
|
author_email = kamikaze.is.waiting.you@gmail.com
|
|
@@ -29,7 +29,7 @@ install_requires =
|
|
|
29
29
|
msgpack==1.0.8
|
|
30
30
|
msgspec==0.18.6
|
|
31
31
|
pydantic[email]==2.8.2
|
|
32
|
-
pydantic-settings==2.
|
|
32
|
+
pydantic-settings==2.4.0
|
|
33
33
|
zeep==4.2.1
|
|
34
34
|
python_requires = >=3.12
|
|
35
35
|
|
|
@@ -24,16 +24,25 @@ class GeneratedStream(io.BytesIO):
|
|
|
24
24
|
self.generator = generator
|
|
25
25
|
|
|
26
26
|
def read(self, size: int = -1):
|
|
27
|
-
if size
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
27
|
+
if size < 0:
|
|
28
|
+
while True:
|
|
29
|
+
try:
|
|
30
|
+
chunk = next(self.generator)
|
|
31
|
+
except StopIteration:
|
|
32
|
+
break
|
|
33
|
+
else:
|
|
34
|
+
self.write(chunk)
|
|
35
|
+
else:
|
|
36
|
+
total_written_size = 0
|
|
35
37
|
|
|
36
|
-
|
|
38
|
+
while total_written_size < size:
|
|
39
|
+
try:
|
|
40
|
+
chunk = next(self.generator)
|
|
41
|
+
except StopIteration:
|
|
42
|
+
break
|
|
43
|
+
else:
|
|
44
|
+
self.write(chunk)
|
|
45
|
+
total_written_size += len(chunk)
|
|
37
46
|
|
|
38
47
|
self.seek(0)
|
|
39
48
|
|
|
@@ -46,6 +55,8 @@ class GeneratedStream(io.BytesIO):
|
|
|
46
55
|
if unread_data_size > 0:
|
|
47
56
|
buf[:unread_data_size] = buf[pos:pos+unread_data_size]
|
|
48
57
|
|
|
58
|
+
del buf
|
|
59
|
+
|
|
49
60
|
self.seek(0)
|
|
50
61
|
self.truncate(unread_data_size)
|
|
51
62
|
|
|
@@ -66,7 +77,6 @@ def generate_archive(objects: Iterable[tuple[str, datetime, bytes]],
|
|
|
66
77
|
info.size = len(content)
|
|
67
78
|
info.mtime = last_modified.timestamp()
|
|
68
79
|
archive.addfile(info, io.BytesIO(content))
|
|
69
|
-
archive.fileobj.flush()
|
|
70
80
|
|
|
71
81
|
buffer.seek(0)
|
|
72
82
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import io
|
|
2
2
|
import logging
|
|
3
|
+
from contextlib import contextmanager
|
|
3
4
|
from datetime import datetime
|
|
4
5
|
from typing import Generator, Iterable
|
|
5
6
|
|
|
@@ -42,9 +43,7 @@ def get_absolute_path(path: str) -> str:
|
|
|
42
43
|
|
|
43
44
|
|
|
44
45
|
def put_object(bucket_name: str, path: str, data: io.BytesIO, length: int, part_size: int = 0) -> str:
|
|
45
|
-
s3_client
|
|
46
|
-
|
|
47
|
-
if s3_client:
|
|
46
|
+
if s3_client := ObjectStorage(s3_settings).get_client():
|
|
48
47
|
result = s3_client.put_object(bucket_name, path, data, length, part_size=part_size)
|
|
49
48
|
|
|
50
49
|
logger.debug(f'Stored object into object storage: {bucket_name}:{path}')
|
|
@@ -54,10 +53,9 @@ def put_object(bucket_name: str, path: str, data: io.BytesIO, length: int, part_
|
|
|
54
53
|
logger.warning(f'No S3 client available, skipping object put')
|
|
55
54
|
|
|
56
55
|
|
|
56
|
+
@contextmanager
|
|
57
57
|
def get_object_stream(bucket_name: str, path: str):
|
|
58
|
-
s3_client
|
|
59
|
-
|
|
60
|
-
if s3_client:
|
|
58
|
+
if s3_client := ObjectStorage(s3_settings).get_client():
|
|
61
59
|
logger.debug(f'Getting object from object storage: {bucket_name}:{path}')
|
|
62
60
|
|
|
63
61
|
try:
|
|
@@ -67,19 +65,17 @@ def get_object_stream(bucket_name: str, path: str):
|
|
|
67
65
|
|
|
68
66
|
raise
|
|
69
67
|
|
|
70
|
-
|
|
68
|
+
yield response
|
|
69
|
+
|
|
70
|
+
response.close()
|
|
71
|
+
response.release_conn()
|
|
71
72
|
else:
|
|
72
73
|
logger.warning(f'No S3 client available, skipping object put')
|
|
73
74
|
|
|
74
75
|
|
|
75
76
|
def get_object(bucket_name: str, path: str) -> bytes:
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
try:
|
|
79
|
-
body = response.read()
|
|
80
|
-
finally:
|
|
81
|
-
response.close()
|
|
82
|
-
response.release_conn()
|
|
77
|
+
with get_object_stream(bucket_name, path) as stream:
|
|
78
|
+
body = stream.read()
|
|
83
79
|
|
|
84
80
|
logger.debug(f'Loaded object from object storage: {bucket_name}:{path}')
|
|
85
81
|
|
|
@@ -1,9 +1,14 @@
|
|
|
1
|
+
import logging
|
|
1
2
|
import os
|
|
2
3
|
import sys
|
|
3
4
|
import tarfile
|
|
4
5
|
from io import BytesIO
|
|
5
6
|
|
|
6
7
|
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
9
|
+
BLOCK_SIZE = 4096
|
|
10
|
+
|
|
11
|
+
|
|
7
12
|
class FileStream(object):
|
|
8
13
|
def __init__(self):
|
|
9
14
|
self.buffer = BytesIO()
|
|
@@ -28,7 +33,7 @@ class FileStream(object):
|
|
|
28
33
|
|
|
29
34
|
|
|
30
35
|
def stream_build_tar(in_filename, streaming_fp):
|
|
31
|
-
tar = tarfile.TarFile.open(
|
|
36
|
+
tar = tarfile.TarFile.open('test.tar.gz', 'w|gz', streaming_fp)
|
|
32
37
|
|
|
33
38
|
stat = os.stat(in_filename)
|
|
34
39
|
|
|
@@ -78,25 +83,23 @@ def stream_build_tar(in_filename, streaming_fp):
|
|
|
78
83
|
yield
|
|
79
84
|
|
|
80
85
|
|
|
81
|
-
|
|
86
|
+
def main():
|
|
87
|
+
if len(sys.argv) != 3:
|
|
88
|
+
print('Usage: %s in_filename out_filename' % sys.argv[0])
|
|
89
|
+
sys.exit(1)
|
|
82
90
|
|
|
91
|
+
in_filename = sys.argv[1]
|
|
92
|
+
out_filename = sys.argv[2]
|
|
83
93
|
|
|
84
|
-
|
|
85
|
-
print('Usage: %s in_filename out_filename' % sys.argv[0])
|
|
86
|
-
sys.exit(1)
|
|
94
|
+
streaming_fp = FileStream()
|
|
87
95
|
|
|
88
|
-
|
|
89
|
-
|
|
96
|
+
with open(out_filename, 'wb') as out_fp:
|
|
97
|
+
for i in stream_build_tar(in_filename, streaming_fp):
|
|
98
|
+
s = streaming_fp.pop()
|
|
90
99
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
s = streaming_fp.pop()
|
|
96
|
-
|
|
97
|
-
if len(s) > 0:
|
|
98
|
-
print('Writing %d bytes...' % len(s))
|
|
99
|
-
out_fp.write(s)
|
|
100
|
-
out_fp.flush()
|
|
100
|
+
if len(s) > 0:
|
|
101
|
+
print('Writing %d bytes...' % len(s))
|
|
102
|
+
out_fp.write(s)
|
|
103
|
+
out_fp.flush()
|
|
101
104
|
|
|
102
|
-
print('Wrote tar file to %s' % out_filename)
|
|
105
|
+
print('Wrote tar file to %s' % out_filename)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: python3-commons
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.19
|
|
4
4
|
Summary: Re-usable Python3 code
|
|
5
5
|
Home-page: https://github.com/kamikaze/python3-commons
|
|
6
6
|
Author: Oleg Korsak
|
|
@@ -20,7 +20,7 @@ Requires-Dist: minio==7.2.7
|
|
|
20
20
|
Requires-Dist: msgpack==1.0.8
|
|
21
21
|
Requires-Dist: msgspec==0.18.6
|
|
22
22
|
Requires-Dist: pydantic[email]==2.8.2
|
|
23
|
-
Requires-Dist: pydantic-settings==2.
|
|
23
|
+
Requires-Dist: pydantic-settings==2.4.0
|
|
24
24
|
Requires-Dist: zeep==4.2.1
|
|
25
25
|
Provides-Extra: testing
|
|
26
26
|
Requires-Dist: pytest; extra == "testing"
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from io import BytesIO
|
|
2
|
+
|
|
3
|
+
from python3_commons.audit import GeneratedStream, generate_archive
|
|
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
|
+
archive_stream = GeneratedStream(generator)
|
|
10
|
+
archived_data = archive_stream.read()
|
|
11
|
+
|
|
12
|
+
with open('/tmp/test.tar', 'wb') as f:
|
|
13
|
+
f.write(archived_data)
|
|
14
|
+
|
|
15
|
+
assert archived_data == expected_data
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def test_generated_stream_by_chunks(s3_file_objects):
|
|
19
|
+
expected_data = b''
|
|
20
|
+
generator = generate_archive(s3_file_objects, chunk_size=2)
|
|
21
|
+
archive_stream = GeneratedStream(generator)
|
|
22
|
+
archived_data = BytesIO()
|
|
23
|
+
|
|
24
|
+
with open('/tmp/test_chunked.tar', 'wb') as f:
|
|
25
|
+
while chunk := archive_stream.read(2):
|
|
26
|
+
f.write(chunk)
|
|
27
|
+
archived_data.write(chunk)
|
|
28
|
+
|
|
29
|
+
assert archived_data.getvalue() == expected_data
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
from python3_commons.audit import GeneratedStream, generate_archive
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
def test_generated_stream(s3_file_objects):
|
|
5
|
-
expected_data = b''
|
|
6
|
-
generator = generate_archive(s3_file_objects, chunk_size=5 * 1024 * 1024)
|
|
7
|
-
archive_stream = GeneratedStream(generator)
|
|
8
|
-
archived_data = archive_stream.read()
|
|
9
|
-
|
|
10
|
-
assert archived_data == 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
|
{python3_commons-0.5.17 → python3_commons-0.5.19}/src/python3_commons/serializers/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{python3_commons-0.5.17 → python3_commons-0.5.19}/src/python3_commons/serializers/msgpack.py
RENAMED
|
File without changes
|
{python3_commons-0.5.17 → python3_commons-0.5.19}/src/python3_commons/serializers/msgspec.py
RENAMED
|
File without changes
|
|
File without changes
|
{python3_commons-0.5.17 → python3_commons-0.5.19}/src/python3_commons.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
{python3_commons-0.5.17 → python3_commons-0.5.19}/src/python3_commons.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|