atomicshop 2.16.5__py3-none-any.whl → 2.16.6__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 atomicshop might be problematic. Click here for more details.

atomicshop/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
1
  """Atomic Basic functions and classes to make developer life easier"""
2
2
 
3
3
  __author__ = "Den Kras"
4
- __version__ = '2.16.5'
4
+ __version__ = '2.16.6'
@@ -2,7 +2,7 @@ import os
2
2
  import time
3
3
  import zipfile
4
4
  from io import BytesIO
5
- from typing import Union
5
+ from typing import Union, Literal
6
6
 
7
7
  from .. import filesystem
8
8
  from ..print_api import print_api
@@ -142,6 +142,67 @@ def get_file_list_from_zip(file_path: str) -> list:
142
142
  return zip_object.namelist()
143
143
 
144
144
 
145
+ def archive_directory(
146
+ directory_path: str,
147
+ compression: Literal[
148
+ 'store',
149
+ 'deflate',
150
+ 'bzip2',
151
+ 'lzma'] = 'deflate',
152
+ include_root_directory: bool = True,
153
+ remove_original: bool = False
154
+ ) -> str:
155
+ """
156
+ Function archives the directory.
157
+ :param directory_path: string, full path to the directory.
158
+ :param compression: string, default is 'deflate'.
159
+ 'store': No compression.
160
+ 'deflate': Standard ZIP compression.
161
+ 'bzip2': BZIP2 compression.
162
+ Provides better compression than Deflate but is typically slower. This method might not be supported by
163
+ all ZIP utilities.
164
+ 'lzma': LZMA compression.
165
+ high compression ratios but is also slower compared to Deflate. This method is less commonly used and
166
+ may not be supported by all ZIP utilities.
167
+ :param include_root_directory: boolean, default is 'True'.
168
+ 'True': The root directory will be included in the archive.
169
+ 'False': The root directory will not be included in the archive.
170
+ True is usually the case in most archiving utilities.
171
+ :param remove_original: boolean, default is 'False'. If 'True', the original directory will be removed.
172
+ :return: string, full path to the archived file.
173
+ """
174
+
175
+ if compression == 'store':
176
+ compression_method = zipfile.ZIP_STORED
177
+ elif compression == 'deflate':
178
+ compression_method = zipfile.ZIP_DEFLATED
179
+ elif compression == 'bzip2':
180
+ compression_method = zipfile.ZIP_BZIP2
181
+ elif compression == 'lzma':
182
+ compression_method = zipfile.ZIP_LZMA
183
+ else:
184
+ raise ValueError(f"Unsupported compression method: {compression}")
185
+
186
+ archive_path: str = directory_path + '.zip'
187
+ with zipfile.ZipFile(archive_path, 'w', compression_method) as zip_object:
188
+ for root, _, files in os.walk(directory_path):
189
+ for file in files:
190
+ file_path = os.path.join(root, file)
191
+
192
+ # If including the root directory, use the relative path from the parent directory of the root
193
+ if include_root_directory:
194
+ arcname = os.path.relpath(file_path, os.path.dirname(directory_path))
195
+ else:
196
+ arcname = os.path.relpath(file_path, directory_path)
197
+
198
+ zip_object.write(file_path, arcname)
199
+
200
+ if remove_original:
201
+ filesystem.remove_directory(directory_path)
202
+
203
+ return archive_path
204
+
205
+
145
206
  # def search_file_in_zip(
146
207
  # file_path: str = None,
147
208
  # file_bytes: bytes = None,
@@ -2,7 +2,7 @@ import os
2
2
  from datetime import datetime
3
3
 
4
4
  from ...shared_functions import build_module_names, create_custom_logger, get_json
5
- from ...message import ClientMessage
5
+ from ... import message, recs_files
6
6
  from ....urls import url_parser
7
7
  from .... import filesystem
8
8
 
@@ -13,8 +13,8 @@ class RecorderParent:
13
13
  # in the script these lines will not be called again, only the "init" function.
14
14
  logger = create_custom_logger()
15
15
 
16
- def __init__(self, class_client_message: ClientMessage, record_path: str):
17
- self.class_client_message: ClientMessage = class_client_message
16
+ def __init__(self, class_client_message: message.ClientMessage, record_path: str):
17
+ self.class_client_message: message.ClientMessage = class_client_message
18
18
  self.record_path: str = record_path
19
19
  self.file_extension: str = ".json"
20
20
  self.engine_name = None
@@ -41,7 +41,7 @@ class RecorderParent:
41
41
  # current date and time in object
42
42
  now = datetime.now()
43
43
  # Formatting the date and time and converting it to string object
44
- day_time_format: str = now.strftime("%Y_%m_%d-%H_%M_%S_%f")
44
+ day_time_format: str = now.strftime(recs_files.REC_FILE_DATE_TIME_FORMAT)
45
45
 
46
46
  # Build the record path with file name
47
47
  self.build_record_path_to_engine()
@@ -1,6 +1,7 @@
1
1
  import os
2
2
  import threading
3
3
  import time
4
+ import datetime
4
5
 
5
6
  import atomicshop # Importing atomicshop package to get the version of the package.
6
7
 
@@ -13,7 +14,7 @@ from ..print_api import print_api
13
14
 
14
15
  from .initialize_engines import ModuleCategory
15
16
  from .connection_thread_worker import thread_worker_main
16
- from . import config_static
17
+ from . import config_static, recs_files
17
18
 
18
19
 
19
20
  def exit_cleanup():
@@ -47,6 +48,9 @@ def initialize_mitm_server(config_file_path: str):
47
48
  filesystem.create_directory(
48
49
  config_static.Certificates.sni_server_certificate_from_server_socket_download_directory)
49
50
 
51
+ # Compress recordings of the previous days if there are any.
52
+ recs_files.recs_archiver_in_process(config_static.Recorder.recordings_path)
53
+
50
54
  # Create a logger that will log messages to file, Initiate System logger.
51
55
  logger_name = "system"
52
56
  system_logger = loggingw.create_logger(
@@ -317,6 +321,25 @@ def initialize_mitm_server(config_file_path: str):
317
321
  message = f"Unhandled Exception occurred in 'loop_for_incoming_sockets' function"
318
322
  print_api(message, error_type=True, color="red", logger=network_logger, traceback_string=True, oneline=True)
319
323
 
324
+ # Compress recordings each day in a separate process.
325
+ recs_archiver_thread = threading.Thread(target=_loop_at_midnight_recs_archive)
326
+ recs_archiver_thread.daemon = True
327
+ recs_archiver_thread.start()
328
+
320
329
  # This is needed for Keyboard Exception.
321
330
  while True:
322
331
  time.sleep(1)
332
+
333
+
334
+ def _loop_at_midnight_recs_archive():
335
+ previous_date = datetime.datetime.now().strftime('%d')
336
+ while True:
337
+ # Get current time.
338
+ current_date = datetime.datetime.now().strftime('%d')
339
+ # If it's midnight, start the archiving process.
340
+ if current_date != previous_date:
341
+ recs_files.recs_archiver_in_process(config_static.Recorder.recordings_path)
342
+ # Update the previous date.
343
+ previous_date = current_date
344
+ # Sleep for 1 minute.
345
+ time.sleep(60)
@@ -0,0 +1,61 @@
1
+ import datetime
2
+ import os
3
+ import multiprocessing
4
+
5
+ from ..wrappers.loggingw import reading
6
+ from ..archiver import zips
7
+ from .. import filesystem
8
+
9
+
10
+ REC_FILE_DATE_TIME_FORMAT: str = "%Y_%m_%d-%H_%M_%S_%f"
11
+ REC_FILE_DATE_FORMAT: str = REC_FILE_DATE_TIME_FORMAT.split('-')[0]
12
+
13
+
14
+ def recs_archiver(recs_directory: str) -> list:
15
+ """
16
+ Find recs files in a directory for each day.
17
+ Each day of recordings will have separate archive.
18
+
19
+ :param recs_directory: The directory where recordings are stored.
20
+ """
21
+
22
+ today_date_string = datetime.datetime.now().strftime(REC_FILE_DATE_FORMAT)
23
+
24
+ all_recs_files = reading.get_logs_paths(
25
+ log_files_directory_path=recs_directory,
26
+ file_name_pattern='*.json',
27
+ date_format=REC_FILE_DATE_FORMAT
28
+ )
29
+
30
+ archive_directories: list = list()
31
+ for recs_file_dict in all_recs_files:
32
+ # We don't need to archive today's files.
33
+ if today_date_string == recs_file_dict['date_string']:
34
+ continue
35
+
36
+ target_directory_path: str = f"{recs_directory}{os.sep}{recs_file_dict['date_string']}"
37
+ if target_directory_path not in archive_directories:
38
+ archive_directories.append(target_directory_path)
39
+
40
+ filesystem.create_directory(target_directory_path)
41
+ filesystem.move_file(
42
+ recs_file_dict['file_path'], f'{target_directory_path}{os.sep}{recs_file_dict["file_name"]}')
43
+
44
+ # Archive directories.
45
+ archived_files: list = list()
46
+ for archive_directory in archive_directories:
47
+ archived_file: str = zips.archive_directory(
48
+ archive_directory, remove_original=True, include_root_directory=True)
49
+ archived_files.append(archived_file)
50
+
51
+ return archived_files
52
+
53
+
54
+ def recs_archiver_in_process(recs_directory: str):
55
+ """
56
+ Archive recs files in a directory for each day in a separate process.
57
+ """
58
+
59
+ process = multiprocessing.Process(target=recs_archiver, args=(recs_directory,))
60
+ process.start()
61
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: atomicshop
3
- Version: 2.16.5
3
+ Version: 2.16.6
4
4
  Summary: Atomic functions and classes to make developer life easier
5
5
  Author: Denis Kras
6
6
  License: MIT License
@@ -1,4 +1,4 @@
1
- atomicshop/__init__.py,sha256=brLGdMD_yQxk-vW-768SsqOYGdgi3tFIZn06CAea2jU,123
1
+ atomicshop/__init__.py,sha256=NMVkLfOWWW1x6P0-ZbzZwEZakjOofspuaUcE3fKmzjk,123
2
2
  atomicshop/_basics_temp.py,sha256=6cu2dd6r2dLrd1BRNcVDKTHlsHs_26Gpw8QS6v32lQ0,3699
3
3
  atomicshop/_create_pdf_demo.py,sha256=Yi-PGZuMg0RKvQmLqVeLIZYadqEZwUm-4A9JxBl_vYA,3713
4
4
  atomicshop/_patch_import.py,sha256=ENp55sKVJ0e6-4lBvZnpz9PQCt3Otbur7F6aXDlyje4,6334
@@ -78,7 +78,7 @@ atomicshop/archiver/archiver.py,sha256=BomnK7zT-nQXA1z0i2R2aTv8eu88wPx7tf2HtOdbm
78
78
  atomicshop/archiver/search_in_archive.py,sha256=XAxa0QukkXZvPmKna8cpwBHLDEskRUtbgaW1eHvpn6w,10833
79
79
  atomicshop/archiver/sevenz_app_w.py,sha256=BWcJb4f7jZEiETDBKyNLE0f5YLFPQx6B91_ObEIXWf8,3007
80
80
  atomicshop/archiver/sevenzs.py,sha256=5i_C50-deC1Cz_GQdMGofV2jeMPbbGWAvih-QnA72cg,1370
81
- atomicshop/archiver/zips.py,sha256=k742K1bEDtc_4N44j_Waebi-uOkxxavqltvV6q-BLW4,14402
81
+ atomicshop/archiver/zips.py,sha256=JrAirzB94SelKq5M2ZUYASwqSSTJ2sxacKBOYeJ8VRQ,16979
82
82
  atomicshop/basics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
83
83
  atomicshop/basics/ansi_escape_codes.py,sha256=WtIkm-BjSZS5J5irDUdAMBNvdX-qXFZcTX98jcBMpJE,3140
84
84
  atomicshop/basics/argparse_template.py,sha256=horwgSf3MX1ZgRnYxtmmQuz9OU_vKrKggF65gmjlmfg,5836
@@ -126,8 +126,9 @@ atomicshop/mitm/config_toml_editor.py,sha256=2p1CMcktWRR_NW-SmyDwylu63ad5e0-w1QP
126
126
  atomicshop/mitm/connection_thread_worker.py,sha256=I5Oq6tSUIXAS6FYlflZzYDtC1rbIYdIKax_R1WsFjso,19093
127
127
  atomicshop/mitm/import_config.py,sha256=fvUESPMkpRvkL7HtMaUqQRPwPF0eHV5V6pwueg4DQkU,7881
128
128
  atomicshop/mitm/initialize_engines.py,sha256=YoSNksMdu4vHjr5xy77t9t5W74zyDZIdjIXrzd3eRXc,8204
129
- atomicshop/mitm/initialize_mitm_server.py,sha256=qP41_hgSa5Wd9WIwIugTqSmWxaL3S3Hh9OCQfcxUwqk,18367
129
+ atomicshop/mitm/initialize_mitm_server.py,sha256=hwqVk6PMc2iDpl0bLwbUlPrxEmu7Ql75-WWCJxiKh1g,19320
130
130
  atomicshop/mitm/message.py,sha256=fHvYEyEx-FAXbIMrKMJ_ybBinezF6IFbPlwCqpRrF44,1768
131
+ atomicshop/mitm/recs_files.py,sha256=O2nhK9awFAsglUjMlNfgHi-0PbJVGIKQxmEoUE00XUg,2030
131
132
  atomicshop/mitm/shared_functions.py,sha256=hplm98tz8pgJ4WHUVI9sf_oVqUM2KJ1Y2pD6EFSb8P0,1879
132
133
  atomicshop/mitm/statistic_analyzer.py,sha256=E0ba1PjsUEcmQUPPw2YH911lyWkbQb9OSAdgB3pihsY,24658
133
134
  atomicshop/mitm/engines/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -135,7 +136,7 @@ atomicshop/mitm/engines/create_module_template.py,sha256=tRjVSm1sD6FzML71Qbuwvit
135
136
  atomicshop/mitm/engines/create_module_template_example.py,sha256=X5xhvbV6-g9jU_bQVhf_crZmaH50LRWz3bS-faQ18ds,489
136
137
  atomicshop/mitm/engines/__parent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
137
138
  atomicshop/mitm/engines/__parent/parser___parent.py,sha256=sBvPlFMOCTdS-qgW9uTKvvJCFT5nNW9n3UyhaFcjAfg,1365
138
- atomicshop/mitm/engines/__parent/recorder___parent.py,sha256=OJb9McbueE4yfxxFsZ81JOU42rASj-1xC2A3nF70QkE,4637
139
+ atomicshop/mitm/engines/__parent/recorder___parent.py,sha256=kIBfETIgRX40-MfoqrCao6dbbAubp2QC_j29B3EY7Do,4666
139
140
  atomicshop/mitm/engines/__parent/responder___parent.py,sha256=e2cdw3tuvNSXp4C2xKdrz-ytveFih1-OV_rpxhJ3zEM,12214
140
141
  atomicshop/mitm/engines/__reference_general/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
141
142
  atomicshop/mitm/engines/__reference_general/parser___reference_general.py,sha256=QolWZKm8SiPxxSoyWY_UK7ODam7EUMAgVfOPFnXxODE,2987
@@ -304,8 +305,8 @@ atomicshop/wrappers/socketw/socket_server_tester.py,sha256=SdchUf9qrPk1Rrat0RzvM
304
305
  atomicshop/wrappers/socketw/socket_wrapper.py,sha256=g7f_8RkW80EZeQWNTqGYnfrQkgAI56T3SwWybq7ZsXg,28521
305
306
  atomicshop/wrappers/socketw/ssl_base.py,sha256=k4V3gwkbq10MvOH4btU4onLX2GNOsSfUAdcHmL1rpVE,2274
306
307
  atomicshop/wrappers/socketw/statistics_csv.py,sha256=Jc0D12crkKRaqoCRQ-2Mz1zm6n4UUx9dXakf-N2TYWA,3065
307
- atomicshop-2.16.5.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
308
- atomicshop-2.16.5.dist-info/METADATA,sha256=fo-TPcQE7W_em3KC6uHgkVSXRZMFaqK3PVuWXQTILDI,10502
309
- atomicshop-2.16.5.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
310
- atomicshop-2.16.5.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
311
- atomicshop-2.16.5.dist-info/RECORD,,
308
+ atomicshop-2.16.6.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
309
+ atomicshop-2.16.6.dist-info/METADATA,sha256=Wcm_aTmc3KMdMN4bkvvD3SRnCJbTopzIa8O7jCuAtUU,10502
310
+ atomicshop-2.16.6.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
311
+ atomicshop-2.16.6.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
312
+ atomicshop-2.16.6.dist-info/RECORD,,