atomicshop 2.12.11__py3-none-any.whl → 2.12.12__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.12.11'
4
+ __version__ = '2.12.12'
atomicshop/diff_check.py CHANGED
@@ -2,7 +2,9 @@ import datetime
2
2
  from pathlib import Path
3
3
  from typing import Union, Literal
4
4
  import json
5
+ import queue
5
6
 
7
+ from . import filesystem, datetimes
6
8
  from .file_io import file_io, jsons
7
9
  from .print_api import print_api
8
10
  from .basics import list_of_dicts, dicts
@@ -39,7 +41,8 @@ class DiffChecker:
39
41
  input_file_rotation_cycle_hours: Union[
40
42
  float,
41
43
  Literal['midnight'],
42
- None] = None
44
+ None] = None,
45
+ enable_statistics_queue: bool = False
43
46
  ):
44
47
  """
45
48
  :param check_object: any, object to check if it changed.
@@ -83,9 +86,30 @@ class DiffChecker:
83
86
  compared only to itself, and if it changes, it will be updated.
84
87
  None: Nothing will be done, you will get an exception.
85
88
  :param input_file_rotation_cycle_hours:
86
- float, the amount of hours the input file will be rotated.
89
+ float, the amount of hours the input file will be rotated in the 'hit_statistics' operation type.
87
90
  str, (only 'midnight' is valid), the input file will be rotated daily at midnight.
88
91
  This is valid only for the 'hit_statistics' operation type.
92
+ :param enable_statistics_queue: boolean, if True, the statistics queue will be enabled for the 'hit_statistics'
93
+ operation type. You can use this queue to process the statistics in another thread.
94
+
95
+ Example:
96
+ diff_checker = DiffChecker(
97
+ check_object_display_name='List of Dicts',
98
+ input_file_path='D:\\input\\list_of_dicts.json',
99
+ input_file_write_only=True,
100
+ return_first_cycle=True,
101
+ operation_type='hit_statistics',
102
+ input_file_rotation_cycle_hours='midnight',
103
+ enable_statistics_queue=True)
104
+
105
+ def process_statistics_queue():
106
+ while True:
107
+ statistics = diff_checker.statistics_queue.get()
108
+ print(statistics)
109
+
110
+ threading.Thread(target=process_statistics_queue).start()
111
+
112
+ <... Your checking operation for the object ...>
89
113
 
90
114
  --------------------------------------------------
91
115
 
@@ -167,6 +191,14 @@ class DiffChecker:
167
191
  if input_file_rotation_cycle_hours and operation_type != 'hit_statistics':
168
192
  raise ValueError("[input_file_rotation_cycle] can be specified only for 'hit_statistics' operation type.")
169
193
 
194
+ if enable_statistics_queue and operation_type != 'hit_statistics':
195
+ raise ValueError("[enable_statistics_queue] can be specified only for 'hit_statistics' operation type.")
196
+
197
+ if input_file_rotation_cycle_hours and not isinstance(input_file_rotation_cycle_hours, float) and \
198
+ not isinstance(input_file_rotation_cycle_hours, int) and \
199
+ input_file_rotation_cycle_hours != 'midnight':
200
+ raise ValueError("[input_file_rotation_cycle] must be float, int or 'midnight' str.")
201
+
170
202
  self.check_object = check_object
171
203
  self.check_object_display_name = check_object_display_name
172
204
  self.aggregation: bool = aggregation
@@ -175,6 +207,7 @@ class DiffChecker:
175
207
  self.return_first_cycle: bool = return_first_cycle
176
208
  self.operation_type = operation_type
177
209
  self.input_file_rotation_cycle = input_file_rotation_cycle_hours
210
+ self.enable_statistics_queue = enable_statistics_queue
178
211
 
179
212
  if not self.check_object_display_name:
180
213
  self.check_object_display_name = self.check_object
@@ -184,6 +217,19 @@ class DiffChecker:
184
217
  # The format the file will be saved as (not used as extension): txt, json.
185
218
  self.save_as: str = str()
186
219
 
220
+ # If the input file rotation cycle is set and the statistics queue is enabled, we will create the queue.
221
+ if self.input_file_rotation_cycle and self.enable_statistics_queue:
222
+ # You can use this queue to process the statistics in another thread.
223
+ self.statistics_queue = queue.Queue()
224
+ else:
225
+ self.statistics_queue = None
226
+
227
+ # If the input file rotation cycle is set to midnight, we will store the previous day as today.
228
+ if self.input_file_rotation_cycle == 'midnight':
229
+ self.previous_day = datetime.datetime.now().strftime('%d')
230
+ else:
231
+ self.previous_day = None
232
+
187
233
  def check_string(self, print_kwargs: dict = None):
188
234
  """
189
235
  The function will check file content for change by hashing it and comparing the hash.
@@ -297,6 +343,35 @@ class DiffChecker:
297
343
  return result, message
298
344
 
299
345
  def _hit_statistics_only_handling(self, current_content, result, message, sort_by_keys, print_kwargs: dict = None):
346
+ if self.input_file_rotation_cycle == 'midnight':
347
+ # If the current time is midnight, we will rotate the file.
348
+ # Get current date.
349
+ current_date = datetime.datetime.now().strftime('%d')
350
+ # If current date is different from previous date it means it is a new day, rotate the file.
351
+ if current_date != self.previous_day:
352
+ input_file_statistics = None
353
+ try:
354
+ # Read the latest statistics from the input file.
355
+ input_file_statistics = jsons.read_json_file(self.input_file_path)
356
+ # Basically, this means that the input statistics file doesn't exist yet, and no events hit
357
+ # yet and new day has come, so it doesn't matter, since there are no statistics to rotate the file.
358
+ except FileNotFoundError:
359
+ pass
360
+
361
+ if input_file_statistics:
362
+ # Rename the file.
363
+ filesystem.backup_file(
364
+ self.input_file_path, str(Path(self.input_file_path).parent), timestamp_as_prefix=False)
365
+ # Update the previous date.
366
+ self.previous_day = current_date
367
+
368
+ previous_day_date_object = (datetime.datetime.now() - datetime.timedelta(days=1)).date()
369
+ # Put the statistics in the queue to be processed.
370
+ if self.statistics_queue:
371
+ self.statistics_queue.put((input_file_statistics, previous_day_date_object))
372
+ else:
373
+ raise NotImplementedError("This feature is not implemented yet.")
374
+
300
375
  # Convert the dictionary entry to string, since we will use it as a key in the dictionary.
301
376
  current_entry = json.dumps(current_content[0])
302
377
 
atomicshop/filesystem.py CHANGED
@@ -1391,23 +1391,44 @@ def backup_folder(directory_path: str, backup_directory: str) -> None:
1391
1391
  move_folder(directory_path, backup_directory_path)
1392
1392
 
1393
1393
 
1394
- def backup_file(file_path: str, backup_directory: str) -> None:
1394
+ def backup_file(file_path: str, backup_directory: str, timestamp_as_prefix: bool = False) -> None:
1395
1395
  """
1396
1396
  Backup the specified file.
1397
1397
 
1398
1398
  :param file_path: The file path to backup.
1399
1399
  :param backup_directory: The directory to backup the file to.
1400
-
1400
+ :param timestamp_as_prefix: boolean, if
1401
+ True, then the timestamp will be added as a prefix to the file name.
1402
+ False, then the timestamp will be added as a suffix to the file name.
1403
+ -----------------------------------------
1401
1404
  Example:
1402
- backup_file(file_path='C:\\Users\\user1\\Downloads\\file.txt', backup_directory='C:\\Users\\user1\\Downloads\\backup')
1405
+ backup_file(
1406
+ file_path='C:\\Users\\user1\\Downloads\\file.txt',
1407
+ backup_directory='C:\\Users\\user1\\Downloads\\backup',
1408
+ timestamp_as_prefix=True
1409
+ )
1403
1410
 
1404
1411
  Backed up file will be moved to 'C:\\Users\\user1\\Downloads\\backup' with timestamp in the name.
1405
1412
  Final path will look like: 'C:\\Users\\user1\\Downloads\\backup\\20231003-120000-000000_file.txt'
1413
+ ---------------------------------------------
1414
+ Example when timestamp_as_prefix is False:
1415
+ backup_file(
1416
+ file_path='C:\\Users\\user1\\Downloads\\file.txt',
1417
+ backup_directory='C:\\Users\\user1\\Downloads\\backup',
1418
+ timestamp_as_prefix=False
1419
+ )
1420
+
1421
+ Backed up file will be moved to 'C:\\Users\\user1\\Downloads\\backup' with timestamp in the name.
1422
+ Final path will look like: 'C:\\Users\\user1\\Downloads\\backup\\file_20231003-120000-000000.txt'
1406
1423
  """
1407
1424
 
1408
1425
  if check_file_existence(file_path):
1409
1426
  timestamp: str = datetimes.TimeFormats().get_current_formatted_time_filename_stamp(True)
1410
1427
  file_name_no_extension = Path(file_path).stem
1411
1428
  file_extension = Path(file_path).suffix
1412
- backup_file_path: str = str(Path(backup_directory) / f"{file_name_no_extension}_{timestamp}{file_extension}")
1429
+ if timestamp_as_prefix:
1430
+ file_name: str = f"{timestamp}_{file_name_no_extension}{file_extension}"
1431
+ else:
1432
+ file_name: str = f"{file_name_no_extension}_{timestamp}{file_extension}"
1433
+ backup_file_path: str = str(Path(backup_directory) / file_name)
1413
1434
  move_file(file_path, backup_file_path)
@@ -35,7 +35,8 @@ class ChangeMonitor:
35
35
  input_file_rotation_cycle_hours: Union[
36
36
  float,
37
37
  Literal['midnight'],
38
- None] = None
38
+ None] = None,
39
+ enable_statistics_queue: bool = False
39
40
  ):
40
41
  """
41
42
  :param object_type: string, type of object to check. The type must be one of the following:
@@ -81,9 +82,10 @@ class ChangeMonitor:
81
82
  'all_objects': disable the DiffChecker features, meaning any new entries will be emitted as is.
82
83
  None: will use the default operation type, based on the object type.
83
84
  :param input_file_rotation_cycle_hours:
84
- float, the amount of hours the input file will be rotated.
85
+ float, the amount of hours the input file will be rotated in the 'hit_statistics' operation type.
85
86
  str, (only 'midnight' is valid), the input file will be rotated daily at midnight.
86
87
  This is valid only for the 'hit_statistics' operation type.
88
+ :param enable_statistics_queue: boolean, if True, the statistics queue will be enabled.
87
89
 
88
90
  If 'input_file_directory' is not specified, the 'input_file_name' is not specified, and
89
91
  'generate_input_file_name' is False, then the input file will not be used and the object will be stored
@@ -172,6 +174,8 @@ class ChangeMonitor:
172
174
  self.fetch_engine = None
173
175
  self.thread_looper = scheduling.ThreadLooper()
174
176
 
177
+ self.statistics_queue = None
178
+
175
179
  def _set_input_file_path(self, check_object_index: int = 0):
176
180
  if self.first_cycle:
177
181
  # If 'input_file_directory' and 'input_file_name' are specified, we'll use a filename to store.
@@ -30,6 +30,11 @@ def _execute_cycle(change_monitor_instance, print_kwargs: dict = None):
30
30
  if not change_monitor_instance.operation_type:
31
31
  change_monitor_instance.diff_check_list[0].operation_type = 'new_objects'
32
32
 
33
+ # Since the 'operation_type' is 'hit_statistics', we'll set the 'statistics_queue' to the 'statistics_queue' of
34
+ # the 'diff_check_list[0]'.
35
+ if change_monitor_instance.diff_check_list[0].operation_type == 'hit_statistics':
36
+ change_monitor_instance.statistics_queue = change_monitor_instance.diff_check_list[0].statistics_queue
37
+
33
38
  if change_monitor_instance.generate_input_file_name:
34
39
  original_name = 'known_domains'
35
40
  # Make path for 'input_file_name'.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: atomicshop
3
- Version: 2.12.11
3
+ Version: 2.12.12
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=FlWupiC5nz7Tolwg5ENxv-hkazzMkviH2VV-21o4tHQ,124
1
+ atomicshop/__init__.py,sha256=FAQuL6PfPfI_HjBQdQfbEnMn0whUDPqtme8WtZbuJdo,124
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
@@ -9,12 +9,12 @@ atomicshop/config_init.py,sha256=z2RXD_mw9nQlAOpuGry1h9QT-2LhNscXgGAktN3dCVQ,249
9
9
  atomicshop/console_output.py,sha256=AOSJjrRryE97PAGtgDL03IBtWSi02aNol8noDnW3k6M,4667
10
10
  atomicshop/console_user_response.py,sha256=31HIy9QGXa7f-GVR8MzJauQ79E_ZqAeagF3Ks4GGdDU,3234
11
11
  atomicshop/datetimes.py,sha256=olsL01S5tkXk4WPzucxujqgLOh198BLgJntDnGYukRU,15533
12
- atomicshop/diff_check.py,sha256=aa0cJAXc643qLbAnVCnVQUEzf3V0cTsy-y9fwarIdPE,20160
12
+ atomicshop/diff_check.py,sha256=YRe4BKLFhJrOtG56-45VsviR4buxZ2nSykNZGHfH1K4,24248
13
13
  atomicshop/dns.py,sha256=bNZOo5jVPzq7OT2qCPukXoK3zb1oOsyaelUwQEyK1SA,2500
14
14
  atomicshop/domains.py,sha256=Rxu6JhhMqFZRcoFs69IoEd1PtYca0lMCG6F1AomP7z4,3197
15
15
  atomicshop/emails.py,sha256=I0KyODQpIMEsNRi9YWSOL8EUPBiWyon3HRdIuSj3AEU,1410
16
16
  atomicshop/file_types.py,sha256=-0jzQMRlmU1AP9DARjk-HJm1tVE22E6ngP2mRblyEjY,763
17
- atomicshop/filesystem.py,sha256=Gp-Pt13hJkuqMqcaxm-x2uJUcv22Drdaa8QuOCDWbms,52879
17
+ atomicshop/filesystem.py,sha256=202ue2LkjI1KdaxvB_RHV-2eIczy2-caZGLO4PSePik,53887
18
18
  atomicshop/functions.py,sha256=pK8hoCE9z61PtWCxQJsda7YAphrLH1wxU5x-1QJP-sY,499
19
19
  atomicshop/hashing.py,sha256=Le8qGFyt3_wX-zGTeQShz7L2HL_b6nVv9PnawjglyHo,3474
20
20
  atomicshop/http_parse.py,sha256=nrf2rZcprLqtW8HVrV7TCZ1iTBcWRRy-mXIlAOzcaJs,9703
@@ -132,9 +132,9 @@ atomicshop/mitm/engines/__reference_general/parser___reference_general.py,sha256
132
132
  atomicshop/mitm/engines/__reference_general/recorder___reference_general.py,sha256=KENDVf9OwXD9gwSh4B1XxACCe7iHYjrvnW1t6F64wdE,695
133
133
  atomicshop/mitm/engines/__reference_general/responder___reference_general.py,sha256=1AM49UaFTKA0AHw-k3SV3uH3QbG-o6ux0c-GoWkKNU0,6993
134
134
  atomicshop/monitor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
135
- atomicshop/monitor/change_monitor.py,sha256=xLL5iLCAHSpxFqJ8EaYXo49py5k0r3qgZzbfbsgAebA,11801
135
+ atomicshop/monitor/change_monitor.py,sha256=aIEZXU1J9Iw4yw68CTeNtsLjYH-Ls2uMx5R3G7XqYSY,12029
136
136
  atomicshop/monitor/checks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
137
- atomicshop/monitor/checks/dns.py,sha256=orp-TgqL6EPzXVm0MtjEceFE8LRfTP3iPR6hGc8Y3TQ,4499
137
+ atomicshop/monitor/checks/dns.py,sha256=QOjvIQZndETomgTuY1PcEbUJkZkRtr6GcRV3Tfbu89c,4866
138
138
  atomicshop/monitor/checks/hash.py,sha256=A6bJ7F5Qv_brdEh3sGhOyfviab2dsnvbXUufyBk5C1U,1951
139
139
  atomicshop/monitor/checks/network.py,sha256=I9f3KyNnlx97E8igGZXpVJl4MlUp9iU6aSbILCKqbA0,3820
140
140
  atomicshop/monitor/checks/process_running.py,sha256=948Sify4P2KFTE1ZrLHKLwd1B1HOgWmC11x3b6MCvz0,1892
@@ -251,8 +251,8 @@ atomicshop/wrappers/socketw/socket_server_tester.py,sha256=AhpurHJmP2kgzHaUbq5ey
251
251
  atomicshop/wrappers/socketw/socket_wrapper.py,sha256=aXBwlEIJhFT0-c4i8iNlFx2It9VpCEpsv--5Oqcpxao,11624
252
252
  atomicshop/wrappers/socketw/ssl_base.py,sha256=k4V3gwkbq10MvOH4btU4onLX2GNOsSfUAdcHmL1rpVE,2274
253
253
  atomicshop/wrappers/socketw/statistics_csv.py,sha256=t3dtDEfN47CfYVi0CW6Kc2QHTEeZVyYhc57IYYh5nmA,826
254
- atomicshop-2.12.11.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
255
- atomicshop-2.12.11.dist-info/METADATA,sha256=Pr00IaUDGCKqj4Nx-LPh-zTmnLNVryo2BMX-189flOg,10479
256
- atomicshop-2.12.11.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
257
- atomicshop-2.12.11.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
258
- atomicshop-2.12.11.dist-info/RECORD,,
254
+ atomicshop-2.12.12.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
255
+ atomicshop-2.12.12.dist-info/METADATA,sha256=AlUyT4NuHXp99ttoymg3AmbsvP9S9kIjbZCjFyI_l0Y,10479
256
+ atomicshop-2.12.12.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
257
+ atomicshop-2.12.12.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
258
+ atomicshop-2.12.12.dist-info/RECORD,,