atomicshop 2.12.8__py3-none-any.whl → 2.12.10__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.8'
4
+ __version__ = '2.12.10'
@@ -100,7 +100,13 @@ def merge_to_dict(list_of_dicts: list) -> dict:
100
100
  return result_dict
101
101
 
102
102
 
103
- def is_value_exist_in_key(list_of_dicts: list, key: str, value_to_match: str, prefix_suffix: bool = False) -> bool:
103
+ def is_value_exist_in_key(
104
+ list_of_dicts: list,
105
+ key: str,
106
+ value_to_match: str,
107
+ value_case_insensitive: bool = False,
108
+ prefix_suffix: bool = False
109
+ ) -> bool:
104
110
  """
105
111
  The function will check if a value exists in a key in a list of dicts.
106
112
 
@@ -113,6 +119,7 @@ def is_value_exist_in_key(list_of_dicts: list, key: str, value_to_match: str, pr
113
119
  :param key: str, the key to check in each entry (dict) in the list.
114
120
  :param value_to_match: str, the value to find in the key.
115
121
  This values is a pattern, so it can be a part of the value and can contain wildcards as "*" character.
122
+ :param value_case_insensitive: bool, if True the value will be matched case insensitive.
116
123
  :param prefix_suffix: bool, related to how pattern of 'value_to_find' is matched against the value in the key.
117
124
  Check the 'strings.match_pattern_against_string' function for more information.
118
125
  :return: bool, True if the value exists in the key in any entry in the list of dicts, False if not.
@@ -121,7 +128,9 @@ def is_value_exist_in_key(list_of_dicts: list, key: str, value_to_match: str, pr
121
128
  for dictionary in list_of_dicts:
122
129
  try:
123
130
  # if value_to_find in dictionary.get(key, None):
124
- if strings.match_pattern_against_string(value_to_match, dictionary.get(key, None), prefix_suffix):
131
+ if strings.match_pattern_against_string(
132
+ value_to_match, dictionary.get(key, None), case_insensitive=value_case_insensitive,
133
+ prefix_suffix=prefix_suffix):
125
134
  return True
126
135
  # If the key is not present in the dict 'TypeError' will be raised, since 'None' doesn't have the 'in' operator.
127
136
  except TypeError:
@@ -108,7 +108,12 @@ def is_any_string_from_list_in_string(string_list: list, check_string: str) -> b
108
108
  return any(test_string in check_string for test_string in string_list)
109
109
 
110
110
 
111
- def match_pattern_against_string(pattern: str, check_string: str, prefix_suffix: bool = False) -> bool:
111
+ def match_pattern_against_string(
112
+ pattern: str,
113
+ check_string: str,
114
+ case_insensitive: bool = False,
115
+ prefix_suffix: bool = False
116
+ ) -> bool:
112
117
  """
113
118
  Function checks the 'pattern' against 'check_string' and returns 'True' if pattern matches and 'False' if not.
114
119
 
@@ -121,6 +126,7 @@ def match_pattern_against_string(pattern: str, check_string: str, prefix_suffix:
121
126
 
122
127
  :param pattern: string, can include wildcards as '*'.
123
128
  :param check_string: string, to check the pattern against.
129
+ :param case_insensitive: boolean, if 'True' will treat the 'pattern' and 'check_string' as case-insensitive.
124
130
  :param prefix_suffix: boolean, that sets if the function should return 'True' also for all the cases that wildcard
125
131
  in the beginning of the pattern and in the end of the pattern, since the default behavior of regex to return
126
132
  'False' on these cases.
@@ -152,12 +158,16 @@ def match_pattern_against_string(pattern: str, check_string: str, prefix_suffix:
152
158
  # on complex strings.
153
159
  # return fnmatch.fnmatch(check_string, pattern)
154
160
 
161
+ # Determine the regex flags based on case_insensitive.
162
+ flags = re.IGNORECASE if case_insensitive else 0
163
+
155
164
  def search_pattern(function_pattern):
156
165
  # Use regex to match the pattern.
157
- return re.search(fr'{function_pattern}', check_string)
166
+ return re.search(fr'{function_pattern}', check_string, flags)
158
167
 
159
168
  wildcard_str: str = '*'
160
169
  wildcard_re: str = '.+'
170
+ # wildcard_re: str = '.*' # Adjusted to '.*' to match zero or more characters
161
171
 
162
172
  # Replace the wildcard string '*' with regex wildcard string '.+'.
163
173
  # In regex '.' is a wildcard, but only for 1 character, if you need more than 1 character you should add '+'.
@@ -204,13 +214,19 @@ def match_pattern_against_string(pattern: str, check_string: str, prefix_suffix:
204
214
  return False
205
215
 
206
216
 
207
- def match_list_of_patterns_against_string(patterns: list, check_string: str, prefix_suffix: bool = False) -> bool:
217
+ def match_list_of_patterns_against_string(
218
+ patterns: list,
219
+ check_string: str,
220
+ case_insensitive: bool = False,
221
+ prefix_suffix: bool = False
222
+ ) -> bool:
208
223
  """
209
224
  Function checks each pattern in 'patterns' list against 'check_string' and returns 'True' if any pattern matches
210
225
  and 'False' if not.
211
226
 
212
227
  :param patterns: list, of string patterns to check against. May include wildcards.
213
228
  :param check_string: string, to check the pattern against.
229
+ :param case_insensitive: boolean, if 'True' will treat the 'pattern' and 'check_string' as case-insensitive.
214
230
  :param prefix_suffix: boolean, that sets if the function should return 'True' also for all the cases that wildcard
215
231
  in the beginning of the pattern and in the end of the pattern, since the default behavior of regex to return
216
232
  'False' on these cases.
@@ -221,7 +237,8 @@ def match_list_of_patterns_against_string(patterns: list, check_string: str, pre
221
237
  """
222
238
 
223
239
  for pattern in patterns:
224
- if match_pattern_against_string(pattern, check_string, prefix_suffix=prefix_suffix):
240
+ if match_pattern_against_string(
241
+ pattern, check_string, case_insensitive=case_insensitive, prefix_suffix=prefix_suffix):
225
242
  return True
226
243
 
227
244
  return False
atomicshop/diff_check.py CHANGED
@@ -31,7 +31,15 @@ class DiffChecker:
31
31
  input_file_path: str = None,
32
32
  input_file_write_only: bool = True,
33
33
  return_first_cycle: bool = True,
34
- operation_type: Literal['new_objects', 'hit_statistics', 'all_objects', 'single_object'] = None
34
+ operation_type: Literal[
35
+ 'new_objects',
36
+ 'hit_statistics',
37
+ 'all_objects',
38
+ 'single_object'] = None,
39
+ input_file_rotation_cycle_hours: Union[
40
+ float,
41
+ Literal['midnight'],
42
+ None] = None
35
43
  ):
36
44
  """
37
45
  :param check_object: any, object to check if it changed.
@@ -68,10 +76,16 @@ class DiffChecker:
68
76
  :param operation_type: string, type of operation to perform. The type must be one of the following:
69
77
  'new_objects': will only store the new objects in the input file.
70
78
  'hit_statistics': will only store the statistics of the entries in the input file.
79
+ The file will be rotated after the specified time in the 'input_file_rotation_cycle' variable, if
80
+ it is specified.
71
81
  'all_objects': disable the DiffChecker features, meaning any new entries will be emitted as is.
72
82
  'single_object': will store the object as is, without any comparison. Meaning, that the object will be
73
83
  compared only to itself, and if it changes, it will be updated.
74
84
  None: Nothing will be done, you will get an exception.
85
+ :param input_file_rotation_cycle_hours:
86
+ float, the amount of hours the input file will be rotated.
87
+ str, (only 'midnight' is valid), the input file will be rotated daily at midnight.
88
+ This is valid only for the 'hit_statistics' operation type.
75
89
 
76
90
  --------------------------------------------------
77
91
 
@@ -150,6 +164,9 @@ class DiffChecker:
150
164
  raise ValueError(f"[operation_type] must be one of the following: "
151
165
  f"'new_objects', 'hit_statistics', 'all_objects', 'single_object'.")
152
166
 
167
+ if input_file_rotation_cycle_hours and operation_type != 'hit_statistics':
168
+ raise ValueError("[input_file_rotation_cycle] can be specified only for 'hit_statistics' operation type.")
169
+
153
170
  self.check_object = check_object
154
171
  self.check_object_display_name = check_object_display_name
155
172
  self.aggregation: bool = aggregation
@@ -157,6 +174,7 @@ class DiffChecker:
157
174
  self.input_file_write_only: bool = input_file_write_only
158
175
  self.return_first_cycle: bool = return_first_cycle
159
176
  self.operation_type = operation_type
177
+ self.input_file_rotation_cycle = input_file_rotation_cycle_hours
160
178
 
161
179
  if not self.check_object_display_name:
162
180
  self.check_object_display_name = self.check_object
atomicshop/filesystem.py CHANGED
@@ -14,7 +14,7 @@ import psutil
14
14
  from .print_api import print_api, print_status_of_list
15
15
  from .basics import strings, list_of_dicts
16
16
  from .file_io import file_io
17
- from . import hashing
17
+ from . import hashing, datetimes
18
18
 
19
19
 
20
20
  WINDOWS_DIRECTORY_SPECIAL_CHARACTERS = ['<', '>', ':', '"', '/', '\\', '|', '?', '*']
@@ -446,6 +446,26 @@ def move_file(source_file_path: str, target_file_path: str, overwrite: bool = Tr
446
446
  shutil.move(source_file_path, target_file_path)
447
447
 
448
448
 
449
+ def move_folder(source_directory: str, target_directory: str, overwrite: bool = True) -> None:
450
+ """
451
+ The function moves folder from source to target.
452
+
453
+ :param source_directory: string, full path to source directory.
454
+ :param target_directory: string, full path to target directory.
455
+ :param overwrite: boolean, if 'False', then the function will not overwrite the directory if it exists.
456
+
457
+ :return: None
458
+ """
459
+
460
+ # Check if 'overwrite' is set to 'True' and if the directory exists.
461
+ if not overwrite:
462
+ if check_directory_existence(target_directory):
463
+ raise FileExistsError(f'Directory already exists: {target_directory}')
464
+
465
+ # Move directory.
466
+ shutil.move(source_directory, target_directory)
467
+
468
+
449
469
  def move_files_from_folder_to_folder(
450
470
  source_directory: str,
451
471
  target_directory: str,
@@ -1319,3 +1339,47 @@ def get_download_directory(place: Literal['temp', 'script', 'working'] = 'temp',
1319
1339
  raise ValueError("Invalid place specified.")
1320
1340
 
1321
1341
  return download_directory
1342
+
1343
+
1344
+ def backup_folder(directory_path: str, backup_directory: str) -> None:
1345
+ """
1346
+ Backup the specified directory.
1347
+
1348
+ :param directory_path: The directory path to backup.
1349
+ :param backup_directory: The directory to backup the directory to.
1350
+
1351
+ Example:
1352
+ backup_folder(directory_path='C:\\Users\\user1\\Downloads\\folder1', backup_directory='C:\\Users\\user1\\Downloads\\backup')
1353
+
1354
+ Backed up folder will be moved to 'C:\\Users\\user1\\Downloads\\backup' with timestamp in the name.
1355
+ Final path will look like: 'C:\\Users\\user1\\Downloads\\backup\\20231003-120000-000000_folder1'
1356
+ """
1357
+
1358
+ if check_directory_existence(directory_path):
1359
+ timestamp: str = datetimes.TimeFormats().get_current_formatted_time_filename_stamp(True)
1360
+ directory_name = Path(directory_path).name
1361
+ backup_directory_path: str = str(Path(backup_directory) / f"{timestamp}_{directory_name}")
1362
+ create_directory(backup_directory_path)
1363
+ move_folder(directory_path, backup_directory_path)
1364
+
1365
+
1366
+ def backup_file(file_path: str, backup_directory: str) -> None:
1367
+ """
1368
+ Backup the specified file.
1369
+
1370
+ :param file_path: The file path to backup.
1371
+ :param backup_directory: The directory to backup the file to.
1372
+
1373
+ Example:
1374
+ backup_file(file_path='C:\\Users\\user1\\Downloads\\file.txt', backup_directory='C:\\Users\\user1\\Downloads\\backup')
1375
+
1376
+ Backed up file will be moved to 'C:\\Users\\user1\\Downloads\\backup' with timestamp in the name.
1377
+ Final path will look like: 'C:\\Users\\user1\\Downloads\\backup\\20231003-120000-000000_file.txt'
1378
+ """
1379
+
1380
+ if check_file_existence(file_path):
1381
+ timestamp: str = datetimes.TimeFormats().get_current_formatted_time_filename_stamp(True)
1382
+ file_name_no_extension = Path(file_path).stem
1383
+ file_extension = Path(file_path).suffix
1384
+ backup_file_path: str = str(Path(backup_directory) / f"{file_name_no_extension}_{timestamp}{file_extension}")
1385
+ move_file(file_path, backup_file_path)
@@ -29,7 +29,13 @@ class ChangeMonitor:
29
29
  generate_input_file_name: bool = False,
30
30
  input_file_write_only: bool = True,
31
31
  store_original_object: bool = False,
32
- operation_type: Literal['hit_statistics', 'all_objects'] = None
32
+ operation_type: Literal[
33
+ 'hit_statistics',
34
+ 'all_objects'] = None,
35
+ input_file_rotation_cycle_hours: Union[
36
+ float,
37
+ Literal['midnight'],
38
+ None] = None
33
39
  ):
34
40
  """
35
41
  :param object_type: string, type of object to check. The type must be one of the following:
@@ -74,6 +80,10 @@ class ChangeMonitor:
74
80
  'hit_statistics': will only store the statistics of the entries in the input file.
75
81
  'all_objects': disable the DiffChecker features, meaning any new entries will be emitted as is.
76
82
  None: will use the default operation type, based on the object type.
83
+ :param input_file_rotation_cycle_hours:
84
+ float, the amount of hours the input file will be rotated.
85
+ str, (only 'midnight' is valid), the input file will be rotated daily at midnight.
86
+ This is valid only for the 'hit_statistics' operation type.
77
87
 
78
88
  If 'input_file_directory' is not specified, the 'input_file_name' is not specified, and
79
89
  'generate_input_file_name' is False, then the input file will not be used and the object will be stored
@@ -99,6 +109,9 @@ class ChangeMonitor:
99
109
  raise ValueError(
100
110
  'ERROR: [operation_type] must be one of the following: "hit_statistics", "all_objects".')
101
111
 
112
+ if input_file_rotation_cycle_hours and operation_type != 'hit_statistics':
113
+ raise ValueError("[input_file_rotation_cycle] can be specified only for 'hit_statistics' operation type.")
114
+
102
115
  # === EOF Exception section ========================================
103
116
  # === Initialize Main variables ====================================
104
117
 
@@ -113,6 +126,7 @@ class ChangeMonitor:
113
126
  self.input_file_write_only: bool = input_file_write_only
114
127
  self.store_original_object: bool = store_original_object
115
128
  self.operation_type = operation_type
129
+ self.input_file_rotation_cycle_hours = input_file_rotation_cycle_hours
116
130
 
117
131
  # === EOF Initialize Main variables ================================
118
132
  # === Initialize Secondary variables ===============================
@@ -126,7 +140,8 @@ class ChangeMonitor:
126
140
  self.diff_check_list.append(
127
141
  DiffChecker(
128
142
  input_file_write_only=self.input_file_write_only,
129
- operation_type=self.operation_type
143
+ operation_type=self.operation_type,
144
+ input_file_rotation_cycle_hours=self.input_file_rotation_cycle_hours
130
145
  )
131
146
  )
132
147
  # Else, if 'check_object_list' is None, create a DiffChecker object only once.
@@ -134,7 +149,8 @@ class ChangeMonitor:
134
149
  self.diff_check_list.append(
135
150
  DiffChecker(
136
151
  input_file_write_only=self.input_file_write_only,
137
- operation_type=self.operation_type
152
+ operation_type=self.operation_type,
153
+ input_file_rotation_cycle_hours=self.input_file_rotation_cycle_hours
138
154
  )
139
155
  )
140
156
 
@@ -20,7 +20,7 @@ def _execute_cycle(change_monitor_instance, print_kwargs: dict = None):
20
20
  processes = _get_list(change_monitor_instance)
21
21
 
22
22
  for process_name in change_monitor_instance.check_object_list:
23
- result = list_of_dicts.is_value_exist_in_key(processes, 'cmdline', process_name)
23
+ result = list_of_dicts.is_value_exist_in_key(processes, 'cmdline', process_name, value_case_insensitive=True)
24
24
 
25
25
  # If the process name was found in the list of currently running processes.
26
26
  if result:
atomicshop/process.py CHANGED
@@ -7,7 +7,7 @@ import shutil
7
7
 
8
8
  from .print_api import print_api
9
9
  from .inspect_wrapper import get_target_function_default_args_and_combine_with_current
10
- from .basics.strings import match_pattern_against_string
10
+ from .basics import strings
11
11
  from .wrappers import ubuntu_terminal
12
12
 
13
13
  if os.name == 'nt':
@@ -247,12 +247,18 @@ def safe_terminate(popen_process: subprocess.Popen):
247
247
  popen_process.wait()
248
248
 
249
249
 
250
- def match_pattern_against_running_processes_cmdlines(pattern: str, first: bool = False, prefix_suffix: bool = False):
250
+ def match_pattern_against_running_processes_cmdlines(
251
+ pattern: str,
252
+ process_name_case_insensitive: bool = False,
253
+ first: bool = False,
254
+ prefix_suffix: bool = False
255
+ ):
251
256
  """
252
257
  The function matches specified string pattern including wildcards against all the currently running processes'
253
258
  command lines.
254
259
 
255
260
  :param pattern: string, the pattern that we will search in the command line list of currently running processes.
261
+ :param process_name_case_insensitive: boolean, if True, the process name will be matched case insensitive.
256
262
  :param first: boolean, that will set if first pattern match found the iteration will stop, or we will return
257
263
  the list of all command lines that contain the pattern.
258
264
  :param prefix_suffix: boolean. Check the description in 'match_pattern_against_string' function.
@@ -268,7 +274,9 @@ def match_pattern_against_running_processes_cmdlines(pattern: str, first: bool =
268
274
  for process in processes:
269
275
  # Check if command line isn't empty and that string pattern is matched against command line.
270
276
  if process['cmdline'] and \
271
- match_pattern_against_string(pattern, process['cmdline'], prefix_suffix):
277
+ strings.match_pattern_against_string(
278
+ pattern, process['cmdline'], case_insensitive=process_name_case_insensitive,
279
+ prefix_suffix=prefix_suffix):
272
280
  matched_cmdlines.append(process['cmdline'])
273
281
  # If 'first' was set to 'True' we will stop, since we found the first match.
274
282
  if first:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: atomicshop
3
- Version: 2.12.8
3
+ Version: 2.12.10
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=I042GM8K4BPXWv_yalQoh8HGBDQ1Denw1R0XH2xM51k,123
1
+ atomicshop/__init__.py,sha256=7Vx_nxgUsmh8XnHp545Je0VoGYtduvu1AXK5YqXnoYc,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=U7eshTajImlsL6aB0O2yiRsGCQCwumiCvGoFcJ2iAfs,19226
12
+ atomicshop/diff_check.py,sha256=aa0cJAXc643qLbAnVCnVQUEzf3V0cTsy-y9fwarIdPE,20160
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=JVWoOSkm-lfh11nBMlrP0w_YnrTFnJ5noYLtoN5Nf5o,48809
17
+ atomicshop/filesystem.py,sha256=3LfLBXRwvdeK_qIBhIyGrDBO5l4OMpQ7Nev24yUfg0U,51606
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
@@ -24,7 +24,7 @@ atomicshop/keyboard_press.py,sha256=1W5kRtOB75fulVx-uF2yarBhW0_IzdI1k73AnvXstk0,
24
24
  atomicshop/pbtkmultifile_argparse.py,sha256=aEk8nhvoQVu-xyfZosK3ma17CwIgOjzO1erXXdjwtS4,4574
25
25
  atomicshop/permissions.py,sha256=P6tiUKV-Gw-c3ePEVsst9bqWaHJbB4ZlJB4xbDYVpEs,4436
26
26
  atomicshop/print_api.py,sha256=DhbCQd0MWZZ5GYEk4oTu1opRFC-b31g1VWZgTGewG2Y,11568
27
- atomicshop/process.py,sha256=kOLrpUb5T5QN9ZvpGOjXyo7Kivrc14A9gcw9lvNMidI,15670
27
+ atomicshop/process.py,sha256=Zgb4CUjy9gIBaawvtCOEcxGUCqvqPyARk0lpBjRzxWE,15950
28
28
  atomicshop/process_name_cmd.py,sha256=TNAK6kQZm5JKWzEW6QLqVHEG98ZLNDQiSS4YwDk8V8c,3830
29
29
  atomicshop/process_poller.py,sha256=WfmwCLALfTYOq8ri0vkPeqq8ruEyA_43DaN--CU2_XY,10854
30
30
  atomicshop/python_file_patcher.py,sha256=kd3rBWvTcosLEk-7TycNdfKW9fZbe161iVwmH4niUo0,5515
@@ -91,12 +91,12 @@ atomicshop/basics/guids.py,sha256=iRx5n18ATZWhpo748BwEjuLWLsu9y3OwF5-Adp-Dtik,40
91
91
  atomicshop/basics/hexs.py,sha256=i8CTG-J0TGGa25yFSbWEvpVyHFnof_qSWUrmXY-ylKM,1054
92
92
  atomicshop/basics/if_else.py,sha256=MakivJChofZCpr0mOVjwCthzpiaBxXVB-zv7GwMOqVo,202
93
93
  atomicshop/basics/isinstancing.py,sha256=fQ35xfqbguQz2BUn-3a4KVGskhTcIn8JjRtxV2rFcRQ,876
94
- atomicshop/basics/list_of_dicts.py,sha256=EeUh5FwUSmjQ7_Df7yTBgwHsou5jx3tP2a0dzgs8-fk,5773
94
+ atomicshop/basics/list_of_dicts.py,sha256=qI2uoYIcHjR8RSD5vtkqhpMgL6XTYRGJDcr9cb2HbZM,6051
95
95
  atomicshop/basics/lists.py,sha256=I0C62vrDrNwCTNl0EjUZNa1Jsd8l0rTkp28GEx9QoEI,4258
96
96
  atomicshop/basics/multiprocesses.py,sha256=nSskxJSlEdalPM_Uf8cc9kAYYlVwYM1GonBLAhCL2mM,18831
97
97
  atomicshop/basics/numbers.py,sha256=ESX0z_7o_ok3sOmCKAUBoZinATklgMy2v-4RndqXlVM,1837
98
98
  atomicshop/basics/randoms.py,sha256=DmYLtnIhDK29tAQrGP1Nt-A-v8WC7WIEB8Edi-nk3N4,282
99
- atomicshop/basics/strings.py,sha256=9DH1190jgSpSRPgcywSysJ0iovqPOWjSokumP6ng2BI,17686
99
+ atomicshop/basics/strings.py,sha256=T4MpEpwxqsiOSnXcwYkqMKB5okHiJfvUCO7t5kcRtBg,18316
100
100
  atomicshop/basics/threads.py,sha256=xvgdDJdmgN0wmmARoZ-H7Kvl1GOcEbvgaeGL4M3Hcx8,2819
101
101
  atomicshop/basics/timeit_template.py,sha256=fYLrk-X_dhdVtnPU22tarrhhvlggeW6FdKCXM8zkX68,405
102
102
  atomicshop/basics/tracebacks.py,sha256=cNfh_oAwF55kSIdqtv3boHZQIoQI8TajxkTnwJwpweI,535
@@ -132,12 +132,12 @@ 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=5LNBcVodxeZMXsDvhzdhb67ipUau__Kh6v6Znj9QjyY,10858
135
+ atomicshop/monitor/change_monitor.py,sha256=xLL5iLCAHSpxFqJ8EaYXo49py5k0r3qgZzbfbsgAebA,11801
136
136
  atomicshop/monitor/checks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
137
137
  atomicshop/monitor/checks/dns.py,sha256=orp-TgqL6EPzXVm0MtjEceFE8LRfTP3iPR6hGc8Y3TQ,4499
138
138
  atomicshop/monitor/checks/hash.py,sha256=A6bJ7F5Qv_brdEh3sGhOyfviab2dsnvbXUufyBk5C1U,1951
139
139
  atomicshop/monitor/checks/network.py,sha256=I9f3KyNnlx97E8igGZXpVJl4MlUp9iU6aSbILCKqbA0,3820
140
- atomicshop/monitor/checks/process_running.py,sha256=hJmqP0-KMsi6x46k4-4hGK0Mj_Ij9wj3qMb8SlRTHrg,1863
140
+ atomicshop/monitor/checks/process_running.py,sha256=948Sify4P2KFTE1ZrLHKLwd1B1HOgWmC11x3b6MCvz0,1892
141
141
  atomicshop/monitor/checks/hash_checks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
142
142
  atomicshop/monitor/checks/hash_checks/file.py,sha256=UDHrUphYSKeH4KJR5pC3ilPAGxX0oXTu3UD8ndnR5WU,2733
143
143
  atomicshop/monitor/checks/hash_checks/url.py,sha256=aNAL1bIeks6xsRDk-5arGy4rhzrJkJ4ZRCqCQTi4n3U,3237
@@ -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.8.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
255
- atomicshop-2.12.8.dist-info/METADATA,sha256=zHIPTb9wnVqipNdABp0gXEYDtJQvZ99EioWQdHJue8g,10478
256
- atomicshop-2.12.8.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
257
- atomicshop-2.12.8.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
258
- atomicshop-2.12.8.dist-info/RECORD,,
254
+ atomicshop-2.12.10.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
255
+ atomicshop-2.12.10.dist-info/METADATA,sha256=qeP1u3Xf--S_WBIEm2cilMZUhmBdQZMWS-COhqHhmKE,10479
256
+ atomicshop-2.12.10.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
257
+ atomicshop-2.12.10.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
258
+ atomicshop-2.12.10.dist-info/RECORD,,