python3-commons 0.3.19__tar.gz → 0.4.0__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.3.19/src/python3_commons.egg-info → python3_commons-0.4.0}/PKG-INFO +2 -2
- {python3_commons-0.3.19 → python3_commons-0.4.0}/requirements.txt +1 -1
- {python3_commons-0.3.19 → python3_commons-0.4.0}/setup.cfg +2 -2
- python3_commons-0.4.0/src/python3_commons/audit.py +44 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/src/python3_commons/conf.py +1 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/src/python3_commons/object_storage.py +35 -21
- {python3_commons-0.3.19 → python3_commons-0.4.0/src/python3_commons.egg-info}/PKG-INFO +2 -2
- {python3_commons-0.3.19 → python3_commons-0.4.0}/src/python3_commons.egg-info/SOURCES.txt +1 -1
- {python3_commons-0.3.19 → python3_commons-0.4.0}/src/python3_commons.egg-info/requires.txt +1 -1
- python3_commons-0.3.19/src/python3_commons/minio.py +0 -28
- {python3_commons-0.3.19 → python3_commons-0.4.0}/.coveragerc +0 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/.github/workflows/python-publish.yaml +0 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/.gitignore +0 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/AUTHORS.rst +0 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/CHANGELOG.rst +0 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/LICENSE +0 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/README.md +0 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/README.rst +0 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/docs/Makefile +0 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/docs/_static/.gitignore +0 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/docs/authors.rst +0 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/docs/changelog.rst +0 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/docs/conf.py +0 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/docs/index.rst +0 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/docs/license.rst +0 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/pyproject.toml +0 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/requirements_dev.txt +0 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/requirements_test.txt +0 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/setup.py +0 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/src/python3_commons/__init__.py +0 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/src/python3_commons/db.py +0 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/src/python3_commons/fs.py +0 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/src/python3_commons/helpers.py +0 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/src/python3_commons/logging/__init__.py +0 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/src/python3_commons/logging/filters.py +0 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/src/python3_commons/logging/formatter.py +0 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/src/python3_commons/serializers/__init__.py +0 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/src/python3_commons/serializers/json.py +0 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/src/python3_commons/serializers/msgpack.py +0 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/src/python3_commons/serializers/msgspec.py +0 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/src/python3_commons.egg-info/dependency_links.txt +0 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/src/python3_commons.egg-info/not-zip-safe +0 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/src/python3_commons.egg-info/top_level.txt +0 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/tests/conftest.py +0 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/tests/test_msgpack.py +0 -0
- {python3_commons-0.3.19 → python3_commons-0.4.0}/tests/test_msgspec.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: python3-commons
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Re-usable Python3 code
|
|
5
5
|
Home-page: https://github.com/kamikaze/python3-commons
|
|
6
6
|
Author: Oleg Korsak
|
|
@@ -18,7 +18,7 @@ Requires-Dist: asyncpg==0.29.0
|
|
|
18
18
|
Requires-Dist: minio==7.2.7
|
|
19
19
|
Requires-Dist: msgpack==1.0.8
|
|
20
20
|
Requires-Dist: msgspec==0.18.6
|
|
21
|
-
Requires-Dist: pydantic[email]==2.7.
|
|
21
|
+
Requires-Dist: pydantic[email]==2.7.2
|
|
22
22
|
Requires-Dist: pydantic-settings==2.2.1
|
|
23
23
|
Provides-Extra: testing
|
|
24
24
|
Requires-Dist: pytest; extra == "testing"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[metadata]
|
|
2
2
|
name = python3-commons
|
|
3
|
-
version = 0.
|
|
3
|
+
version = 0.4.0
|
|
4
4
|
description = Re-usable Python3 code
|
|
5
5
|
author = Oleg Korsak
|
|
6
6
|
author_email = kamikaze.is.waiting.you@gmail.com
|
|
@@ -27,7 +27,7 @@ install_requires =
|
|
|
27
27
|
minio==7.2.7
|
|
28
28
|
msgpack==1.0.8
|
|
29
29
|
msgspec==0.18.6
|
|
30
|
-
pydantic[email]==2.7.
|
|
30
|
+
pydantic[email]==2.7.2
|
|
31
31
|
pydantic-settings==2.2.1
|
|
32
32
|
python_requires = >=3.12
|
|
33
33
|
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import tarfile
|
|
3
|
+
from datetime import date, timedelta
|
|
4
|
+
from io import BytesIO
|
|
5
|
+
|
|
6
|
+
from python3_commons import object_storage
|
|
7
|
+
from python3_commons.conf import s3_settings
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
async def archive_audit_data(root_path: str = 'audit'):
|
|
13
|
+
today = date.today() - timedelta(days=1)
|
|
14
|
+
year = today.year
|
|
15
|
+
month = today.month
|
|
16
|
+
day = today.day
|
|
17
|
+
bucket_name = s3_settings.s3_bucket
|
|
18
|
+
fo = BytesIO()
|
|
19
|
+
object_names = []
|
|
20
|
+
date_path = object_storage.get_absolute_path(f'{root_path}/{year}/{month:02}/{day:02}')
|
|
21
|
+
|
|
22
|
+
with tarfile.open(fileobj=fo, mode='w|bz2') as archive:
|
|
23
|
+
if objects := object_storage.get_objects(bucket_name, date_path, recursive=True):
|
|
24
|
+
logger.info(f'Compacting files in: {date_path}')
|
|
25
|
+
|
|
26
|
+
for name, last_modified, content in objects:
|
|
27
|
+
info = tarfile.TarInfo(name)
|
|
28
|
+
info.size = len(content)
|
|
29
|
+
info.mtime = last_modified.timestamp()
|
|
30
|
+
archive.addfile(info, BytesIO(content))
|
|
31
|
+
object_names.append(name)
|
|
32
|
+
|
|
33
|
+
fo.seek(0)
|
|
34
|
+
|
|
35
|
+
if object_names:
|
|
36
|
+
archive_path = object_storage.get_absolute_path(
|
|
37
|
+
f'.archive/{year}_{month:02}/{year}_{month:02}_{day:02}.tar.bz2')
|
|
38
|
+
object_storage.put_object(bucket_name, archive_path, fo, fo.getbuffer().nbytes)
|
|
39
|
+
|
|
40
|
+
if errors := object_storage.remove_objects(bucket_name, object_names=object_names):
|
|
41
|
+
for error in errors:
|
|
42
|
+
logger.error(f'Failed to delete object in {bucket_name=}: {error}')
|
|
43
|
+
else:
|
|
44
|
+
logger.info('No objects to archive found.')
|
|
@@ -1,29 +1,29 @@
|
|
|
1
|
+
import io
|
|
1
2
|
import logging
|
|
2
3
|
from datetime import datetime
|
|
3
|
-
from
|
|
4
|
-
from typing import Generator, Iterable, Any
|
|
4
|
+
from typing import Generator, Iterable
|
|
5
5
|
|
|
6
|
-
from minio import Minio
|
|
6
|
+
from minio import Minio, S3Error
|
|
7
7
|
from minio.datatypes import Object
|
|
8
|
-
from minio.deleteobjects import DeleteObject
|
|
8
|
+
from minio.deleteobjects import DeleteObject, DeleteError
|
|
9
9
|
|
|
10
|
-
from python3_commons import
|
|
11
|
-
from python3_commons.conf import s3_settings
|
|
10
|
+
from python3_commons.conf import s3_settings, S3Settings
|
|
12
11
|
|
|
13
12
|
logger = logging.getLogger(__name__)
|
|
14
13
|
__CLIENT = None
|
|
15
14
|
|
|
16
15
|
|
|
17
|
-
def get_s3_client() -> Minio:
|
|
16
|
+
def get_s3_client(settings: S3Settings) -> Minio:
|
|
18
17
|
global __CLIENT
|
|
19
18
|
|
|
20
19
|
if not __CLIENT and s3_settings.s3_endpoint_url:
|
|
21
|
-
__CLIENT =
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
20
|
+
__CLIENT = Minio(
|
|
21
|
+
settings.s3_endpoint_url,
|
|
22
|
+
region=settings.s3_region_name,
|
|
23
|
+
access_key=settings.s3_access_key_id.get_secret_value(),
|
|
24
|
+
secret_key=settings.s3_secret_access_key.get_secret_value(),
|
|
25
|
+
secure=settings.s3_secure,
|
|
26
|
+
cert_check=settings.s3_cert_verify
|
|
27
27
|
)
|
|
28
28
|
|
|
29
29
|
return __CLIENT
|
|
@@ -34,13 +34,13 @@ def get_absolute_path(path: str) -> str:
|
|
|
34
34
|
path = path[1:]
|
|
35
35
|
|
|
36
36
|
if bucket_root := s3_settings.s3_bucket_root:
|
|
37
|
-
path = f'{bucket_root[:1] if bucket_root.startswith(
|
|
37
|
+
path = f'{bucket_root[:1] if bucket_root.startswith('/') else bucket_root}/{path}'
|
|
38
38
|
|
|
39
39
|
return path
|
|
40
40
|
|
|
41
41
|
|
|
42
|
-
def put_object(bucket_name: str, path: str, data:
|
|
43
|
-
s3_client = get_s3_client()
|
|
42
|
+
def put_object(bucket_name: str, path: str, data: io.BytesIO, length: int) -> str:
|
|
43
|
+
s3_client = get_s3_client(s3_settings)
|
|
44
44
|
|
|
45
45
|
if s3_client:
|
|
46
46
|
result = s3_client.put_object(bucket_name, path, data, length)
|
|
@@ -53,7 +53,7 @@ def put_object(bucket_name: str, path: str, data: IOBase, length: int) -> str:
|
|
|
53
53
|
|
|
54
54
|
|
|
55
55
|
def get_object_stream(bucket_name: str, path: str):
|
|
56
|
-
s3_client = get_s3_client()
|
|
56
|
+
s3_client = get_s3_client(s3_settings)
|
|
57
57
|
|
|
58
58
|
if s3_client:
|
|
59
59
|
logger.debug(f'Getting object from object storage: {bucket_name}:{path}')
|
|
@@ -85,7 +85,7 @@ def get_object(bucket_name: str, path: str) -> bytes:
|
|
|
85
85
|
|
|
86
86
|
|
|
87
87
|
def list_objects(bucket_name: str, prefix: str, recursive: bool = True) -> Generator[Object, None, None]:
|
|
88
|
-
s3_client = get_s3_client()
|
|
88
|
+
s3_client = get_s3_client(s3_settings)
|
|
89
89
|
|
|
90
90
|
yield from s3_client.list_objects(bucket_name, prefix=prefix, recursive=recursive)
|
|
91
91
|
|
|
@@ -104,13 +104,13 @@ def get_objects(bucket_name: str, path: str,
|
|
|
104
104
|
|
|
105
105
|
|
|
106
106
|
def remove_object(bucket_name: str, object_name: str):
|
|
107
|
-
s3_client = get_s3_client()
|
|
107
|
+
s3_client = get_s3_client(s3_settings)
|
|
108
108
|
s3_client.remove_object(bucket_name, object_name)
|
|
109
109
|
|
|
110
110
|
|
|
111
111
|
def remove_objects(bucket_name: str, prefix: str = None,
|
|
112
|
-
object_names: Iterable[str] = None) ->
|
|
113
|
-
s3_client = get_s3_client()
|
|
112
|
+
object_names: Iterable[str] = None) -> Iterable[DeleteError] | None:
|
|
113
|
+
s3_client = get_s3_client(s3_settings)
|
|
114
114
|
|
|
115
115
|
if prefix:
|
|
116
116
|
delete_object_list = map(
|
|
@@ -125,3 +125,17 @@ def remove_objects(bucket_name: str, prefix: str = None,
|
|
|
125
125
|
errors = s3_client.remove_objects(bucket_name, delete_object_list)
|
|
126
126
|
|
|
127
127
|
return errors
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
async def store_bytes_in_s3(settings: S3Settings, data: bytes, key: str):
|
|
131
|
+
if settings.s3_secret_access_key:
|
|
132
|
+
try:
|
|
133
|
+
client = get_s3_client(settings)
|
|
134
|
+
|
|
135
|
+
client.put_object(settings.s3_bucket, key, io.BytesIO(data), len(data))
|
|
136
|
+
except S3Error as e:
|
|
137
|
+
logger.error(f'Failed storing object in storage: {e}')
|
|
138
|
+
else:
|
|
139
|
+
logger.debug(f'Stored object in storage: {key}')
|
|
140
|
+
else:
|
|
141
|
+
logger.debug(f'S3 is not configured, not storing object in storage: {key}')
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: python3-commons
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Re-usable Python3 code
|
|
5
5
|
Home-page: https://github.com/kamikaze/python3-commons
|
|
6
6
|
Author: Oleg Korsak
|
|
@@ -18,7 +18,7 @@ Requires-Dist: asyncpg==0.29.0
|
|
|
18
18
|
Requires-Dist: minio==7.2.7
|
|
19
19
|
Requires-Dist: msgpack==1.0.8
|
|
20
20
|
Requires-Dist: msgspec==0.18.6
|
|
21
|
-
Requires-Dist: pydantic[email]==2.7.
|
|
21
|
+
Requires-Dist: pydantic[email]==2.7.2
|
|
22
22
|
Requires-Dist: pydantic-settings==2.2.1
|
|
23
23
|
Provides-Extra: testing
|
|
24
24
|
Requires-Dist: pytest; extra == "testing"
|
|
@@ -20,11 +20,11 @@ docs/index.rst
|
|
|
20
20
|
docs/license.rst
|
|
21
21
|
docs/_static/.gitignore
|
|
22
22
|
src/python3_commons/__init__.py
|
|
23
|
+
src/python3_commons/audit.py
|
|
23
24
|
src/python3_commons/conf.py
|
|
24
25
|
src/python3_commons/db.py
|
|
25
26
|
src/python3_commons/fs.py
|
|
26
27
|
src/python3_commons/helpers.py
|
|
27
|
-
src/python3_commons/minio.py
|
|
28
28
|
src/python3_commons/object_storage.py
|
|
29
29
|
src/python3_commons.egg-info/PKG-INFO
|
|
30
30
|
src/python3_commons.egg-info/SOURCES.txt
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import urllib3
|
|
2
|
-
from minio import Minio
|
|
3
|
-
from pydantic import SecretStr
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def get_client(endpoint_url: str, region_name: str, access_key_id: SecretStr, secret_access_key: SecretStr,
|
|
7
|
-
secure: bool = True) -> Minio:
|
|
8
|
-
http_client = urllib3.PoolManager(
|
|
9
|
-
timeout=urllib3.util.Timeout(connect=300, read=300),
|
|
10
|
-
maxsize=50,
|
|
11
|
-
cert_reqs='CERT_REQUIRED' if secure else 'CERT_NONE',
|
|
12
|
-
retries=urllib3.Retry(
|
|
13
|
-
total=5,
|
|
14
|
-
backoff_factor=0.2,
|
|
15
|
-
status_forcelist=[500, 502, 503, 504]
|
|
16
|
-
)
|
|
17
|
-
)
|
|
18
|
-
|
|
19
|
-
client = Minio(
|
|
20
|
-
endpoint_url,
|
|
21
|
-
region=region_name,
|
|
22
|
-
access_key=access_key_id.get_secret_value(),
|
|
23
|
-
secret_key=secret_access_key.get_secret_value(),
|
|
24
|
-
http_client=http_client,
|
|
25
|
-
secure=secure
|
|
26
|
-
)
|
|
27
|
-
|
|
28
|
-
return client
|
|
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.3.19 → python3_commons-0.4.0}/src/python3_commons/serializers/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python3_commons-0.3.19 → python3_commons-0.4.0}/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
|