python3-commons 0.5.7__py2.py3-none-any.whl → 0.5.9__py2.py3-none-any.whl

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/audit.py CHANGED
@@ -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
- 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,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
- path = get_absolute_path(path)
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)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python3-commons
3
- Version: 0.5.7
3
+ Version: 0.5.9
4
4
  Summary: Re-usable Python3 code
5
5
  Home-page: https://github.com/kamikaze/python3-commons
6
6
  Author: Oleg Korsak
@@ -1,10 +1,10 @@
1
1
  python3_commons/__init__.py,sha256=h-KTJUaQ50E3RmkTn_GO88IRunmDTEpNc3ylpFvCTOc,339
2
- python3_commons/audit.py,sha256=O9-Qf8TC1CJEDbWlTMdx-ap3UIoxbncpkEhSszrf_N4,3771
2
+ python3_commons/audit.py,sha256=M8vAZOUsif4EhHMca9ahM-LvfbUrE0GvOLARJVrtjms,5177
3
3
  python3_commons/conf.py,sha256=vSXyFwXx2wb1uy8IffeeI-RoTqhUZs0RLSSG2OLc2ss,598
4
4
  python3_commons/db.py,sha256=qhaDIdzBWgFyeP_XPKfHZlYVlwS2bpBPYMv84yV6820,738
5
5
  python3_commons/fs.py,sha256=wfLjybXndwLqNlOxTpm_HRJnuTcC4wbrHEOaEeCo9Wc,337
6
6
  python3_commons/helpers.py,sha256=wI7afc-8o-SBpLBHQnWXiudw456EAVKguJaeZiSNXwE,1377
7
- python3_commons/object_storage.py,sha256=6iXf5GyYKE40X4E0LbabpcseLzNYMJzGTVkyTdse64c,3946
7
+ python3_commons/object_storage.py,sha256=oTA56qS-m_1OSWLCTAKdDgcxjcBhXgbttIhNyKY0WrY,3830
8
8
  python3_commons/logging/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  python3_commons/logging/filters.py,sha256=fuyjXZAUm-i2MNrxvFYag8F8Rr27x8W8MdV3ke6miSs,175
10
10
  python3_commons/logging/formatter.py,sha256=UXmmh1yd5Kc2dpvSHn6uCWLDWE2LMjlYAaH8cg3siV4,720
@@ -12,9 +12,9 @@ python3_commons/serializers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMp
12
12
  python3_commons/serializers/json.py,sha256=P288wWz9ic38QWEMrpp_uwKPYkQiOgvE1cI4WZn6ZCg,808
13
13
  python3_commons/serializers/msgpack.py,sha256=P7CZoRTBeDtgALT5GTOZVCNM_3snOfCnfh5S3zcCIEY,1679
14
14
  python3_commons/serializers/msgspec.py,sha256=ZrfQWBz_67t3yjU_S6avnRJZzYN-HFzef2qGB5W21KI,2023
15
- python3_commons-0.5.7.dist-info/AUTHORS.rst,sha256=3R9JnfjfjH5RoPWOeqKFJgxVShSSfzQPIrEr1nxIo9Q,90
16
- python3_commons-0.5.7.dist-info/LICENSE,sha256=xxILuojHm4fKQOrMHPSslbyy6WuKAN2RiG74HbrYfzM,34575
17
- python3_commons-0.5.7.dist-info/METADATA,sha256=II9MLcbrYmnS8RmEUZ8JDcyZa44K2Zrx5kYP1lS8onE,974
18
- python3_commons-0.5.7.dist-info/WHEEL,sha256=DZajD4pwLWue70CAfc7YaxT1wLUciNBvN_TTcvXpltE,110
19
- python3_commons-0.5.7.dist-info/top_level.txt,sha256=lJI6sCBf68eUHzupCnn2dzG10lH3jJKTWM_hrN1cQ7M,16
20
- python3_commons-0.5.7.dist-info/RECORD,,
15
+ python3_commons-0.5.9.dist-info/AUTHORS.rst,sha256=3R9JnfjfjH5RoPWOeqKFJgxVShSSfzQPIrEr1nxIo9Q,90
16
+ python3_commons-0.5.9.dist-info/LICENSE,sha256=xxILuojHm4fKQOrMHPSslbyy6WuKAN2RiG74HbrYfzM,34575
17
+ python3_commons-0.5.9.dist-info/METADATA,sha256=f4jClE1oP4nICSJvizStlkBotry6tCx7LTl818aiABU,974
18
+ python3_commons-0.5.9.dist-info/WHEEL,sha256=DZajD4pwLWue70CAfc7YaxT1wLUciNBvN_TTcvXpltE,110
19
+ python3_commons-0.5.9.dist-info/top_level.txt,sha256=lJI6sCBf68eUHzupCnn2dzG10lH3jJKTWM_hrN1cQ7M,16
20
+ python3_commons-0.5.9.dist-info/RECORD,,