atomicshop 2.16.26__py3-none-any.whl → 2.16.27__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.26'
4
+ __version__ = '2.16.27'
@@ -254,3 +254,23 @@ def escape_csv_line_to_list(csv_line: list) -> list:
254
254
  result_csv_entries.append(escape_csv_value(entry))
255
255
 
256
256
  return result_csv_entries
257
+
258
+
259
+ def get_number_of_cells_in_string_line(line: str) -> int:
260
+ """
261
+ Function to get number of cells in CSV line.
262
+
263
+ :param line: String, line of CSV file.
264
+ :return: int, number of cells in the line.
265
+ """
266
+
267
+ # Create CSV reader from 'input_file'. By default, the first row will be the header if 'fieldnames' is None.
268
+ csv_reader = csv.reader([line])
269
+
270
+ # Get the first row of the CSV file.
271
+ csv_list = list(csv_reader)
272
+
273
+ # Get the number of cells in the first row.
274
+ number_of_cells = len(csv_list[0])
275
+
276
+ return number_of_cells
@@ -1,13 +1,12 @@
1
1
  import logging
2
2
  import threading
3
+ import multiprocessing
3
4
  import time
4
5
  import datetime
5
6
 
6
7
  import atomicshop # Importing atomicshop package to get the version of the package.
7
8
 
8
9
  from .. import filesystem, queues, dns, on_exit
9
- from ..basics import tracebacks
10
- from ..file_io import csvs
11
10
  from ..permissions import permissions
12
11
  from ..python_functions import get_current_python_version_string, check_python_version_compliance
13
12
  from ..wrappers.socketw import socket_wrapper, dns_server, base
@@ -21,12 +20,14 @@ from . import config_static, recs_files
21
20
 
22
21
  NETWORK_INTERFACE_IS_DYNAMIC: bool = bool()
23
22
  NETWORK_INTERFACE_IPV4_ADDRESS_LIST: list[str] = list()
23
+ # noinspection PyTypeChecker
24
+ RECS_PROCESS_INSTANCE: multiprocessing.Process = None
24
25
 
25
26
 
26
27
  EXCEPTIONS_CSV_LOGGER_NAME: str = 'exceptions'
27
28
  EXCEPTIONS_CSV_LOGGER_HEADER: str = 'time,exception'
28
29
  # noinspection PyTypeChecker
29
- MITM_ERROR_LOGGER: logging.Logger = None
30
+ MITM_ERROR_LOGGER: loggingw.ExceptionCsvLogger = None
30
31
 
31
32
 
32
33
  def exit_cleanup():
@@ -39,9 +40,13 @@ def exit_cleanup():
39
40
  dns.set_connection_dns_gateway_dynamic(use_default_connection=True)
40
41
  print_api("Returned default DNS gateway...", color='blue')
41
42
 
43
+ print_api(RECS_PROCESS_INSTANCE.is_alive())
44
+ RECS_PROCESS_INSTANCE.terminate()
45
+ RECS_PROCESS_INSTANCE.join()
46
+
42
47
 
43
48
  def mitm_server(config_file_path: str):
44
- on_exit.register_exit_handler(exit_cleanup)
49
+ on_exit.register_exit_handler(exit_cleanup, at_exit=False)
45
50
 
46
51
  # Main function should return integer with error code, 0 is successful.
47
52
  # Since listening server is infinite, this will not be reached.
@@ -54,14 +59,7 @@ def mitm_server(config_file_path: str):
54
59
  return result
55
60
 
56
61
  global MITM_ERROR_LOGGER
57
- MITM_ERROR_LOGGER = loggingw.create_logger(
58
- logger_name=EXCEPTIONS_CSV_LOGGER_NAME,
59
- directory_path=config_static.LogRec.logs_path,
60
- file_type="csv",
61
- add_timedfile=True,
62
- formatter_filehandler='MESSAGE',
63
- header=EXCEPTIONS_CSV_LOGGER_HEADER
64
- )
62
+ MITM_ERROR_LOGGER = loggingw.ExceptionCsvLogger(EXCEPTIONS_CSV_LOGGER_NAME, config_static.LogRec.logs_path)
65
63
 
66
64
  # Create folders.
67
65
  filesystem.create_directory(config_static.LogRec.logs_path)
@@ -69,7 +67,8 @@ def mitm_server(config_file_path: str):
69
67
  if config_static.LogRec.enable_request_response_recordings_in_logs:
70
68
  filesystem.create_directory(config_static.LogRec.recordings_path)
71
69
  # Compress recordings of the previous days if there are any.
72
- recs_files.recs_archiver_in_process(config_static.LogRec.recordings_path)
70
+ global RECS_PROCESS_INSTANCE
71
+ RECS_PROCESS_INSTANCE = recs_files.recs_archiver_in_process(config_static.LogRec.recordings_path)
73
72
 
74
73
  if config_static.Certificates.sni_get_server_certificate_from_server_socket:
75
74
  filesystem.create_directory(
@@ -335,7 +334,7 @@ def mitm_server(config_file_path: str):
335
334
  global NETWORK_INTERFACE_IS_DYNAMIC, NETWORK_INTERFACE_IPV4_ADDRESS_LIST
336
335
  NETWORK_INTERFACE_IS_DYNAMIC, NETWORK_INTERFACE_IPV4_ADDRESS_LIST = dns.get_default_dns_gateway()
337
336
  if set_dns_gateway:
338
- # Set the DNS gateway to the specified one only if the DNS gateway is dynamic or it is static but different
337
+ # Set the DNS gateway to the specified one only if the DNS gateway is dynamic, or it is static but different
339
338
  # from the one specified in the configuration file.
340
339
  if (NETWORK_INTERFACE_IS_DYNAMIC or (not NETWORK_INTERFACE_IS_DYNAMIC and
341
340
  NETWORK_INTERFACE_IPV4_ADDRESS_LIST != dns_gateway_server_list)):
@@ -374,7 +373,8 @@ def _loop_at_midnight_recs_archive():
374
373
  # If it's midnight, start the archiving process.
375
374
  if current_date != previous_date:
376
375
  if config_static.LogRec.enable_request_response_recordings_in_logs:
377
- recs_files.recs_archiver_in_process(config_static.LogRec.recordings_path)
376
+ global RECS_PROCESS_INSTANCE
377
+ RECS_PROCESS_INSTANCE = recs_files.recs_archiver_in_process(config_static.LogRec.recordings_path)
378
378
  # Update the previous date.
379
379
  previous_date = current_date
380
380
  # Sleep for 1 minute.
@@ -387,9 +387,11 @@ def mitm_server_main(config_file_path: str):
387
387
  return mitm_server(config_file_path)
388
388
  except KeyboardInterrupt:
389
389
  print_api("Server Stopped by [KeyboardInterrupt].", color='blue')
390
+ exit_cleanup()
390
391
  return 0
391
392
  except Exception as e:
392
- msg = tracebacks.get_as_string()
393
- output_csv_line: str = csvs.escape_csv_line_to_string([datetime.datetime.now(), msg])
394
- MITM_ERROR_LOGGER.info(output_csv_line)
395
- print_api(str(e), error_type=True, color="red", traceback_string=True)
393
+ RECS_PROCESS_INSTANCE.terminate()
394
+
395
+ MITM_ERROR_LOGGER.write(e)
396
+ exit_cleanup()
397
+ return 1
@@ -64,10 +64,11 @@ def recs_archiver(recs_directory: str) -> list:
64
64
  return archived_files
65
65
 
66
66
 
67
- def recs_archiver_in_process(recs_directory: str):
67
+ def recs_archiver_in_process(recs_directory: str) -> multiprocessing.Process:
68
68
  """
69
69
  Archive recs files in a directory for each day in a separate process.
70
70
  """
71
71
 
72
72
  process = multiprocessing.Process(target=recs_archiver, args=(recs_directory,))
73
73
  process.start()
74
+ return process
atomicshop/on_exit.py CHANGED
@@ -91,25 +91,54 @@ class ExitHandler:
91
91
  # Exit the process gracefully
92
92
  raise SystemExit(0)
93
93
 
94
- def register_handlers(self):
95
- win32api.SetConsoleCtrlHandler(self.console_handler, True)
96
- atexit.register(self.atexit_handler)
97
- signal.signal(signal.SIGINT, self.signal_handler)
98
- signal.signal(signal.SIGTERM, self.signal_handler)
99
-
100
-
101
- def register_exit_handler(clean_up_function, *args, **kwargs):
94
+ def register_handlers(
95
+ self,
96
+ at_exit: bool = True,
97
+ console_close: bool = True,
98
+ kill_signal: bool = True
99
+ ):
100
+ """
101
+ Register the exit handlers.
102
+
103
+ :param at_exit: Register the atexit handler.
104
+ Just remember that the atexit handler will be called right away on [Ctrl+C], meaning if you want to do
105
+ something specifically on KeyboardInterrupt, you should handle it separately and set this parameter to False.
106
+ Same goes for all the exceptions.
107
+ :param console_close: Register the console close handler.
108
+ :param kill_signal: Register the kill signal handler.
109
+ """
110
+ if at_exit:
111
+ atexit.register(self.atexit_handler)
112
+ if console_close:
113
+ win32api.SetConsoleCtrlHandler(self.console_handler, True)
114
+ if kill_signal:
115
+ signal.signal(signal.SIGINT, self.signal_handler)
116
+ signal.signal(signal.SIGTERM, self.signal_handler)
117
+
118
+
119
+ def register_exit_handler(
120
+ clean_up_function,
121
+ at_exit: bool = True,
122
+ console_close: bool = True,
123
+ kill_signal: bool = True,
124
+ *args, **kwargs):
102
125
  """
103
126
  This function will register the exit handler to handle exit events: Closing the console, pressing 'CTRL+C',
104
127
  Killing the process.
105
128
 
106
129
  :param clean_up_function: The action to run when one of exit types is triggered.
130
+ :param at_exit: Register the atexit handler.
131
+ Just remember that the atexit handler will be called right away on [Ctrl+C], meaning if you want to do something
132
+ specifically on KeyboardInterrupt, you should handle it separately and set this parameter to False.
133
+ Same goes for all the exceptions.
134
+ :param console_close: Register the console close handler.
135
+ :param kill_signal: Register the kill signal handler.
107
136
  :param args: The arguments to pass to the cleanup action.
108
137
  :param kwargs: The keyword arguments to pass to the cleanup action.
109
138
  """
110
139
  global EXIT_HANDLER_INSTANCE
111
140
  EXIT_HANDLER_INSTANCE = ExitHandler(clean_up_function, args, kwargs)
112
- EXIT_HANDLER_INSTANCE.register_handlers()
141
+ EXIT_HANDLER_INSTANCE.register_handlers(at_exit=at_exit, console_close=console_close, kill_signal=kill_signal)
113
142
 
114
143
 
115
144
  def restart_function(callable_function, *args, **kwargs):
atomicshop/print_api.py CHANGED
@@ -1,4 +1,5 @@
1
1
  import sys
2
+ import logging
2
3
 
3
4
  from .basics.ansi_escape_codes import ColorsBasic, get_colors_basic_dict
4
5
  from .basics import tracebacks
@@ -94,6 +95,20 @@ def print_api(
94
95
  from bidi.algorithm import get_display
95
96
  message = get_display(message)
96
97
 
98
+ if logger_method == 'error' or logger_method == 'critical':
99
+ error_type = True
100
+
101
+ # If exception was raised and 'stderr=True'.
102
+ if sys.exc_info()[0] is not None and stderr and traceback_string:
103
+ # If 'traceback' is set to 'True', we'll output traceback of exception.
104
+ if traceback_string:
105
+ if message:
106
+ message = f'{message}\n{tracebacks.get_as_string()}{message}'
107
+ else:
108
+ message = tracebacks.get_as_string()
109
+
110
+ color = 'red'
111
+
97
112
  # If 'stdcolor' is 'True', the console output will be colored.
98
113
  if stdcolor:
99
114
  # If 'logger.error' should be outputted to console, and 'color' wasn't selected, then set color to 'yellow'.
@@ -103,19 +118,22 @@ def print_api(
103
118
  elif logger_method == 'critical' and not color:
104
119
  color = 'red'
105
120
 
106
- if color:
121
+ if color and not logger:
107
122
  message = get_colors_basic_dict(color) + message + ColorsBasic.END
123
+ elif color and logger:
124
+ # Save the original formatter
125
+ original_formatter = None
108
126
 
109
- if logger_method == 'error' or logger_method == 'critical':
110
- error_type = True
111
-
112
- # If exception was raised and 'stderr=True'.
113
- if sys.exc_info()[0] is not None and stderr:
114
- # If 'traceback' is set to 'True', we'll output traceback of exception.
115
- if traceback_string:
116
- message = f'{message} | Exception: {tracebacks.get_as_string()}'
127
+ # Find the stream handler and change its formatter
128
+ for handler in logger.handlers:
129
+ if isinstance(handler, logging.StreamHandler):
130
+ # Save the original formatter
131
+ original_formatter = handler.formatter
117
132
 
118
- color = 'red'
133
+ # Create a colored formatter for errors
134
+ color_formatter = logging.Formatter(
135
+ get_colors_basic_dict(color) + original_formatter + ColorsBasic.END)
136
+ handler.setFormatter(color_formatter)
119
137
 
120
138
  # If 'online' is set to 'True', we'll output message as oneline.
121
139
  if oneline:
@@ -130,6 +148,12 @@ def print_api(
130
148
  if print_end == '\n':
131
149
  # Use logger to output message.
132
150
  getattr(logger, logger_method)(message)
151
+
152
+ if stdcolor:
153
+ # Restore the original formatter after logging
154
+ for handler in logger.handlers:
155
+ if isinstance(handler, logging.StreamHandler):
156
+ handler.setFormatter(original_formatter)
133
157
  # If logger wasn't passed.
134
158
  else:
135
159
  # Use print to output the message.
@@ -1,8 +1,12 @@
1
1
  import logging
2
2
  import os
3
3
  from typing import Literal, Union
4
+ import datetime
4
5
 
5
6
  from . import loggers, handlers
7
+ from ...file_io import csvs
8
+ from ...basics import tracebacks
9
+ from ...print_api import print_api
6
10
 
7
11
 
8
12
  class LoggingwLoggerAlreadyExistsError(Exception):
@@ -258,3 +262,93 @@ def get_datetime_format_string_from_logger_file_handlers(logger: logging.Logger)
258
262
  datetime_format_strings.append(date_time_format_string)
259
263
 
260
264
  return datetime_format_strings
265
+
266
+
267
+ def is_logger_exists(logger_name: str) -> bool:
268
+ """
269
+ Function to check if the logger exists.
270
+ :param logger_name: Name of the logger.
271
+ :return: True if the logger exists, False if it doesn't.
272
+ """
273
+
274
+ return loggers.is_logger_exists(logger_name)
275
+
276
+
277
+ class ExceptionCsvLogger:
278
+ def __init__(
279
+ self,
280
+ logger_name: str,
281
+ custom_header: str = None,
282
+ directory_path: str = None
283
+ ):
284
+ """
285
+ Initialize the ExceptionCsvLogger object.
286
+
287
+ :param logger_name: Name of the logger.
288
+ :param custom_header: Custom header to write to the log file.
289
+ If None, the default header will be used: "timestamp,exception", since that what is written to the log file.
290
+ If you want to add more columns to the csv file, you can provide a custom header:
291
+ "custom1,custom2,custom3".
292
+ These will be added to the default header as:
293
+ "timestamp,custom1,custom2,custom3,exception".
294
+ :param directory_path: Directory path where the log file will be saved.
295
+ You can leave it as None, but if the logger doesn't exist, you will get an exception.
296
+ """
297
+
298
+ if custom_header:
299
+ self.header = f"timestamp,{custom_header},exception"
300
+ else:
301
+ self.header = "timestamp,exception"
302
+
303
+ if is_logger_exists(logger_name):
304
+ self.logger = get_logger_with_level(logger_name)
305
+ else:
306
+ if directory_path is None:
307
+ raise ValueError("You need to provide 'directory_path' if the logger doesn't exist.")
308
+
309
+ self.logger = create_logger(
310
+ logger_name=logger_name,
311
+ directory_path=directory_path,
312
+ file_type="csv",
313
+ add_timedfile=True,
314
+ formatter_filehandler='MESSAGE',
315
+ header=self.header)
316
+
317
+ def write(
318
+ self,
319
+ message: Union[str, Exception] = None,
320
+ custom_csv_string: str = None
321
+ ):
322
+ """
323
+ Write the message to the log file.
324
+
325
+ :param message: The message to write to the log file.
326
+ If None, the message will be retrieved from current traceback frame.
327
+ :param custom_csv_string: Custom CSV string to add between the timestamp and the exception.
328
+ Currently, without the 'custom_csv_string', the csv line written as "timestamp,exception" as the header.
329
+ If you add a 'custom_csv_string', the csv line will be written as "timestamp,custom_csv_string,exception".
330
+ Meaning, that you need to provide the 'custom_header' during the initialization of the object.
331
+ Off course, you can use as many commas as you need in the 'custom_csv_string': "custom1,custom2,custom3".
332
+ This need to be mirrored in the 'custom_header' as well: "custom1,custom2,custom3".
333
+ """
334
+
335
+ if message is None or isinstance(message, Exception):
336
+ message = tracebacks.get_as_string()
337
+
338
+ if custom_csv_string:
339
+ output_csv_line: str = csvs.escape_csv_line_to_string([datetime.datetime.now(), custom_csv_string, message])
340
+ else:
341
+ output_csv_line: str = csvs.escape_csv_line_to_string([datetime.datetime.now(), message])
342
+
343
+ # If the number of cells in the 'output_csv_line' doesn't match the number of cells in the 'header',
344
+ # raise an exception.
345
+ if (csvs.get_number_of_cells_in_string_line(output_csv_line) !=
346
+ csvs.get_number_of_cells_in_string_line(self.header)):
347
+ raise ValueError(
348
+ "Number of cells in the 'output_csv_line' doesn't match the number of cells in the 'header'.")
349
+
350
+ self.logger.info(output_csv_line)
351
+ print_api('', error_type=True, color="red", traceback_string=True)
352
+
353
+ def get_logger(self):
354
+ return self.logger
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: atomicshop
3
- Version: 2.16.26
3
+ Version: 2.16.27
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=joVK_ueWgYu4gbqtZdDb4rswSixoXOc-sNEsTq6qwqs,124
1
+ atomicshop/__init__.py,sha256=uvGTfzSHIYxELvSkSy25hxKozcYi2WpTk6bDs1_wXVs,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
@@ -23,9 +23,9 @@ atomicshop/http_parse.py,sha256=nrf2rZcprLqtW8HVrV7TCZ1iTBcWRRy-mXIlAOzcaJs,9703
23
23
  atomicshop/inspect_wrapper.py,sha256=sGRVQhrJovNygHTydqJj0hxES-aB2Eg9KbIk3G31apw,11429
24
24
  atomicshop/ip_addresses.py,sha256=Hvi4TumEFoTEpKWaq5WNF-YzcRzt24IxmNgv-Mgax1s,1190
25
25
  atomicshop/keyboard_press.py,sha256=1W5kRtOB75fulVx-uF2yarBhW0_IzdI1k73AnvXstk0,452
26
- atomicshop/on_exit.py,sha256=Wf1iy2e0b0Zu7oRxrct3VkLdQ_x9B32-z_JerKTt9Z0,5493
26
+ atomicshop/on_exit.py,sha256=Rpg2SaF0aginuO7JYwA49YJYnS8F6K2jUqhjH65WzuU,6889
27
27
  atomicshop/pbtkmultifile_argparse.py,sha256=aEk8nhvoQVu-xyfZosK3ma17CwIgOjzO1erXXdjwtS4,4574
28
- atomicshop/print_api.py,sha256=j0bZ9b2rFKCcr0TVx1ARraVKeEs6JaaSgIlBdndy1nI,11600
28
+ atomicshop/print_api.py,sha256=37zugPqm04XFLmMnXxNo0bJtv1ImNSDHosPTlOuYyhw,12760
29
29
  atomicshop/process.py,sha256=PeLvyixXaCfftdUF3oMbohI1L4MdLtvQVDx2V1Tz_Rk,16662
30
30
  atomicshop/python_file_patcher.py,sha256=-uhbUX-um5k-If_XXuOfCr8wMzZ3QE6h9N8xGWw6W_o,5486
31
31
  atomicshop/python_functions.py,sha256=zJg4ogUwECxrDD7xdDN5JikIUctITM5lsyabr_ZNsRw,4435
@@ -114,7 +114,7 @@ atomicshop/etws/traces/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
114
114
  atomicshop/etws/traces/trace_dns.py,sha256=WvOZm7KNdP4r6ofkZhUGi9WjtYlkV3mUp_yxita3Qg4,6399
115
115
  atomicshop/etws/traces/trace_sysmon_process_creation.py,sha256=OM-bkK38uYMwWLZKNOTDa0Xdk3sO6sqsxoMUIiPvm5g,4656
116
116
  atomicshop/file_io/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
117
- atomicshop/file_io/csvs.py,sha256=oZiaIEd1q50ypNdd9mlHWb-f7HAdGa_D6jLd3T_4sWU,8777
117
+ atomicshop/file_io/csvs.py,sha256=XFZ-kvg2nWLXUpFh_FyPwOXB_TYLFRrHpS5hWMblTi8,9353
118
118
  atomicshop/file_io/docxs.py,sha256=ffJhnmM_WyD8mCoq2dGdpfahdIrGTPy96QVlH5EWjeI,5754
119
119
  atomicshop/file_io/file_io.py,sha256=IVqs0Kd7PV8O-NH9321hK_IvPqWx2z_45zdDtqgw4II,7113
120
120
  atomicshop/file_io/jsons.py,sha256=q9ZU8slBKnHLrtn3TnbK1qxrRpj5ZvCm6AlsFzoANjo,5303
@@ -128,8 +128,8 @@ atomicshop/mitm/connection_thread_worker.py,sha256=rfullUfMRR5YUEI45KJdGXlbOGYF8
128
128
  atomicshop/mitm/import_config.py,sha256=_nu8mgA-M4s6dZ8_QWx3x0aVb75upvsCuX_PIUg4X2w,8345
129
129
  atomicshop/mitm/initialize_engines.py,sha256=VyJE8QnzlgD3QbX5inz5o6rC3zQ3is9CeTL7-B10g1w,8292
130
130
  atomicshop/mitm/message.py,sha256=d_sm3O_aoZf87dDQP44xOMNEG-uZBN1ZecQgMCacbZs,1814
131
- atomicshop/mitm/mitm_main.py,sha256=yqVyyZvxqfu-lqsFmHGinXFGJ9TZ3ljGgJ-jU-wXJFk,21852
132
- atomicshop/mitm/recs_files.py,sha256=B8fSuvYXlh50LWfwLRw_bYswreTjmdZLuHJzbDC5Gss,2930
131
+ atomicshop/mitm/mitm_main.py,sha256=L8fcFNU_azIJepymb3JZRnfvvRIsUf1gWNcFQKeQTcs,21876
132
+ atomicshop/mitm/recs_files.py,sha256=VjgtJF7vy365mBjctwB2bpDYoLMkEeogzF8kbb01dAk,2977
133
133
  atomicshop/mitm/shared_functions.py,sha256=jjCDZVQCwQ8hf9QNMe3T8W3ISkfZo4Mm2HtXOJLZYgI,1999
134
134
  atomicshop/mitm/statistic_analyzer.py,sha256=mBmwEe68WAjnIskGndQTRldnsAsDHuaOW0O7UXlM3Pc,26702
135
135
  atomicshop/mitm/engines/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -249,7 +249,7 @@ atomicshop/wrappers/loggingw/filters.py,sha256=CMs5PAMb68zxJgBcQobaOFDG5kLJBOVYn
249
249
  atomicshop/wrappers/loggingw/formatters.py,sha256=7XUJvlB0CK4DCkEp8NTL0S0dkyrZD0UTADgEwkStKOY,5483
250
250
  atomicshop/wrappers/loggingw/handlers.py,sha256=hAPFJQ-wFoNO8QzGrJRSvyuP09Q1F0Dl9_w7zzlgcW0,18155
251
251
  atomicshop/wrappers/loggingw/loggers.py,sha256=mmM__XR3W4QC82wbsDRG_M4_0JYGGEP0Qn0WCOSp-go,2910
252
- atomicshop/wrappers/loggingw/loggingw.py,sha256=nt4UxOBHL--M-Ls9b3eicffCrspYWDWG1q4ZVlHATIs,12068
252
+ atomicshop/wrappers/loggingw/loggingw.py,sha256=oqH_u1AFyu4YG468ZDnCalRNNu2438AEYZa2MFB9iqg,16143
253
253
  atomicshop/wrappers/loggingw/reading.py,sha256=ERBSiQbEksySKpXpu2E_6k9dZ6MPH95ZIsmdjWW9MUE,16436
254
254
  atomicshop/wrappers/mongodbw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
255
255
  atomicshop/wrappers/mongodbw/install_mongodb.py,sha256=3ZPqrXxj3lC-PnAKGXclylLuOqsbyXYeUpb5iGjdeUU,6626
@@ -309,8 +309,8 @@ atomicshop/wrappers/socketw/ssl_base.py,sha256=kmiif84kMhBr5yjQW17p935sfjR5JKG0L
309
309
  atomicshop/wrappers/socketw/statistics_csv.py,sha256=w1AH-zf4mBuT4euf28UKij9ihM-b1BRU9Qfby0QDdqI,2957
310
310
  atomicshop/wrappers/winregw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
311
311
  atomicshop/wrappers/winregw/winreg_network.py,sha256=bQ8Jql8bVGBJ0dt3VQ56lga_1LBOMLI3Km_otvvbU6c,7138
312
- atomicshop-2.16.26.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
313
- atomicshop-2.16.26.dist-info/METADATA,sha256=B4rCAdBWrX5ocldHxSS8ijnIvauLJQ_de10bMYy-pto,10473
314
- atomicshop-2.16.26.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
315
- atomicshop-2.16.26.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
316
- atomicshop-2.16.26.dist-info/RECORD,,
312
+ atomicshop-2.16.27.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
313
+ atomicshop-2.16.27.dist-info/METADATA,sha256=JD7sHdbqBZwiuJmXdvhYXs4qgSy5S5riQpv0m6lAMKU,10473
314
+ atomicshop-2.16.27.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
315
+ atomicshop-2.16.27.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
316
+ atomicshop-2.16.27.dist-info/RECORD,,