python3-commons 0.5.8__tar.gz → 0.5.10__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.

Files changed (45) hide show
  1. {python3_commons-0.5.8/src/python3_commons.egg-info → python3_commons-0.5.10}/PKG-INFO +1 -1
  2. {python3_commons-0.5.8 → python3_commons-0.5.10}/setup.cfg +1 -1
  3. {python3_commons-0.5.8 → python3_commons-0.5.10}/src/python3_commons/audit.py +71 -20
  4. {python3_commons-0.5.8 → python3_commons-0.5.10}/src/python3_commons/object_storage.py +2 -2
  5. {python3_commons-0.5.8 → python3_commons-0.5.10/src/python3_commons.egg-info}/PKG-INFO +1 -1
  6. {python3_commons-0.5.8 → python3_commons-0.5.10}/.coveragerc +0 -0
  7. {python3_commons-0.5.8 → python3_commons-0.5.10}/.github/workflows/python-publish.yaml +0 -0
  8. {python3_commons-0.5.8 → python3_commons-0.5.10}/.gitignore +0 -0
  9. {python3_commons-0.5.8 → python3_commons-0.5.10}/AUTHORS.rst +0 -0
  10. {python3_commons-0.5.8 → python3_commons-0.5.10}/CHANGELOG.rst +0 -0
  11. {python3_commons-0.5.8 → python3_commons-0.5.10}/LICENSE +0 -0
  12. {python3_commons-0.5.8 → python3_commons-0.5.10}/README.md +0 -0
  13. {python3_commons-0.5.8 → python3_commons-0.5.10}/README.rst +0 -0
  14. {python3_commons-0.5.8 → python3_commons-0.5.10}/docs/Makefile +0 -0
  15. {python3_commons-0.5.8 → python3_commons-0.5.10}/docs/_static/.gitignore +0 -0
  16. {python3_commons-0.5.8 → python3_commons-0.5.10}/docs/authors.rst +0 -0
  17. {python3_commons-0.5.8 → python3_commons-0.5.10}/docs/changelog.rst +0 -0
  18. {python3_commons-0.5.8 → python3_commons-0.5.10}/docs/conf.py +0 -0
  19. {python3_commons-0.5.8 → python3_commons-0.5.10}/docs/index.rst +0 -0
  20. {python3_commons-0.5.8 → python3_commons-0.5.10}/docs/license.rst +0 -0
  21. {python3_commons-0.5.8 → python3_commons-0.5.10}/pyproject.toml +0 -0
  22. {python3_commons-0.5.8 → python3_commons-0.5.10}/requirements.txt +0 -0
  23. {python3_commons-0.5.8 → python3_commons-0.5.10}/requirements_dev.txt +0 -0
  24. {python3_commons-0.5.8 → python3_commons-0.5.10}/requirements_test.txt +0 -0
  25. {python3_commons-0.5.8 → python3_commons-0.5.10}/setup.py +0 -0
  26. {python3_commons-0.5.8 → python3_commons-0.5.10}/src/python3_commons/__init__.py +0 -0
  27. {python3_commons-0.5.8 → python3_commons-0.5.10}/src/python3_commons/conf.py +0 -0
  28. {python3_commons-0.5.8 → python3_commons-0.5.10}/src/python3_commons/db.py +0 -0
  29. {python3_commons-0.5.8 → python3_commons-0.5.10}/src/python3_commons/fs.py +0 -0
  30. {python3_commons-0.5.8 → python3_commons-0.5.10}/src/python3_commons/helpers.py +0 -0
  31. {python3_commons-0.5.8 → python3_commons-0.5.10}/src/python3_commons/logging/__init__.py +0 -0
  32. {python3_commons-0.5.8 → python3_commons-0.5.10}/src/python3_commons/logging/filters.py +0 -0
  33. {python3_commons-0.5.8 → python3_commons-0.5.10}/src/python3_commons/logging/formatter.py +0 -0
  34. {python3_commons-0.5.8 → python3_commons-0.5.10}/src/python3_commons/serializers/__init__.py +0 -0
  35. {python3_commons-0.5.8 → python3_commons-0.5.10}/src/python3_commons/serializers/json.py +0 -0
  36. {python3_commons-0.5.8 → python3_commons-0.5.10}/src/python3_commons/serializers/msgpack.py +0 -0
  37. {python3_commons-0.5.8 → python3_commons-0.5.10}/src/python3_commons/serializers/msgspec.py +0 -0
  38. {python3_commons-0.5.8 → python3_commons-0.5.10}/src/python3_commons.egg-info/SOURCES.txt +0 -0
  39. {python3_commons-0.5.8 → python3_commons-0.5.10}/src/python3_commons.egg-info/dependency_links.txt +0 -0
  40. {python3_commons-0.5.8 → python3_commons-0.5.10}/src/python3_commons.egg-info/not-zip-safe +0 -0
  41. {python3_commons-0.5.8 → python3_commons-0.5.10}/src/python3_commons.egg-info/requires.txt +0 -0
  42. {python3_commons-0.5.8 → python3_commons-0.5.10}/src/python3_commons.egg-info/top_level.txt +0 -0
  43. {python3_commons-0.5.8 → python3_commons-0.5.10}/tests/conftest.py +0 -0
  44. {python3_commons-0.5.8 → python3_commons-0.5.10}/tests/test_msgpack.py +0 -0
  45. {python3_commons-0.5.8 → python3_commons-0.5.10}/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.8
3
+ Version: 0.5.10
4
4
  Summary: Re-usable Python3 code
5
5
  Home-page: https://github.com/kamikaze/python3-commons
6
6
  Author: Oleg Korsak
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = python3-commons
3
- version = 0.5.8
3
+ version = 0.5.10
4
4
  description = Re-usable Python3 code
5
5
  author = Oleg Korsak
6
6
  author_email = kamikaze.is.waiting.you@gmail.com
@@ -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,70 @@ 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.seek(0)
49
+ self.truncate(unread_data_size)
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
+ logger.info(f'Adding {name} to archive')
68
+ info = tarfile.TarInfo(name)
69
+ info.size = len(content)
70
+ info.mtime = last_modified.timestamp()
71
+ archive.addfile(info, io.BytesIO(content))
72
+ buffer.seek(0)
73
+
74
+ while True:
75
+ chunk = buffer.read(chunk_size)
76
+
77
+ if not chunk:
78
+ break
79
+
80
+ yield chunk
81
+
82
+ buffer.seek(0)
83
+ buffer.truncate(0)
84
+
85
+
21
86
  def write_audit_data_sync(settings: S3Settings, key: str, data: bytes):
22
87
  if settings.s3_secret_access_key:
23
88
  try:
@@ -43,27 +108,15 @@ async def archive_audit_data(root_path: str = 'audit'):
43
108
  month = now.month
44
109
  day = now.day
45
110
  bucket_name = s3_settings.s3_bucket
46
- fo = BytesIO()
47
111
  object_names = []
48
112
  date_path = object_storage.get_absolute_path(f'{root_path}/{year}/{month:02}/{day:02}')
49
113
 
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)
60
-
61
- fo.seek(0)
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
- f'audit/.archive/{year}_{month:02}_{day:02}.tar.bz2')
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
- coro = write_audit_data(
86
- s3_settings,
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,11 +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
- 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)
47
47
 
48
48
  logger.debug(f'Stored object into object storage: {bucket_name}:{path}')
49
49
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python3-commons
3
- Version: 0.5.8
3
+ Version: 0.5.10
4
4
  Summary: Re-usable Python3 code
5
5
  Home-page: https://github.com/kamikaze/python3-commons
6
6
  Author: Oleg Korsak