atomicshop 2.12.19__py3-none-any.whl → 2.12.21__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.19'
4
+ __version__ = '2.12.21'
@@ -16,26 +16,13 @@ from ..wrappers.loggingw import loggingw
16
16
  from ..print_api import print_api
17
17
 
18
18
 
19
+ STATISTICS_HEADER: str = \
20
+ 'request_time_sent,host,path,command,status_code,request_size_bytes,response_size_bytes,file_path,process_cmd,error'
21
+
22
+
19
23
  def initialize_mitm_server(config_static):
20
24
  # Main function should return integer with error code, 0 is successful.
21
25
  # Since listening server is infinite, this will not be reached.
22
- def output_statistics_csv_header():
23
- # Since there is no implementation of header in logging file handler modules, we'll do it manually each time.
24
- statistics_header: list = ['request_time_sent',
25
- 'host',
26
- 'path',
27
- 'command',
28
- 'status_code',
29
- 'request_size_bytes',
30
- 'response_size_bytes',
31
- # 'request_hex',
32
- # 'response_hex',
33
- 'file_path',
34
- 'process_cmd',
35
- 'error'
36
- ]
37
- statistics_logger.info(','.join(statistics_header))
38
-
39
26
  # After modules import - we check for python version.
40
27
  check_python_version_compliance(minimum_version='3.11')
41
28
 
@@ -190,9 +177,8 @@ def initialize_mitm_server(config_static):
190
177
  # Creating Statistics logger.
191
178
  statistics_logger = loggingw.get_logger_with_stream_handler_and_timedfilehandler(
192
179
  logger_name="statistics", directory_path=config['log']['logs_path'],
193
- file_extension=config_static.CSV_EXTENSION, formatter_message_only=True
180
+ file_extension=config_static.CSV_EXTENSION, formatter_message_only=True, header=STATISTICS_HEADER
194
181
  )
195
- output_statistics_csv_header()
196
182
 
197
183
  network_logger_name = "network"
198
184
  network_logger = loggingw.get_logger_with_stream_handler_and_timedfilehandler(
File without changes
File without changes
@@ -0,0 +1,53 @@
1
+ import os
2
+ from pathlib import Path
3
+
4
+ from ...wrappers.pywin32w import winshell
5
+
6
+
7
+ STARTUP_FOLDER = os.path.join(os.environ['APPDATA'], 'Microsoft', 'Windows', 'Start Menu', 'Programs', 'Startup')
8
+
9
+
10
+ def add_to_startup_folder_with_shortcut(exe_file_path: str, shortcut_name: str) -> str:
11
+ """
12
+ This function will create a shortcut in the startup folder to your executable.
13
+
14
+ :param exe_file_path: The path to your executable file.
15
+ :param shortcut_name: The name of the shortcut file to create in the startup folder.
16
+ No need to add the ".lnk" extension.
17
+ :return: The path to the shortcut file created.
18
+ """
19
+
20
+ # Get the startup folder path and create if non-existent.
21
+ Path(STARTUP_FOLDER).mkdir(parents=True, exist_ok=True)
22
+
23
+ shortcut_file_path = str(Path(STARTUP_FOLDER, f'{shortcut_name}.lnk'))
24
+
25
+ # Create a shortcut to the executable file.
26
+ winshell.create_shortcut(exe_file_path, shortcut_file_path)
27
+
28
+ return shortcut_file_path
29
+
30
+
31
+ def is_in_startup_folder(shortcut_name: str):
32
+ """
33
+ This function will check if the shortcut is in the startup folder.
34
+
35
+ :param shortcut_name: The name of the shortcut file to check in the startup folder.
36
+ No need to add the ".LNK" extension.
37
+ :return: True if the shortcut is in the startup folder, False otherwise.
38
+ """
39
+ return Path(STARTUP_FOLDER, f'{shortcut_name}.lnk').exists()
40
+
41
+
42
+ def remove_from_startup_folder(shortcut_name: str):
43
+ """
44
+ This function will remove the shortcut from the startup folder.
45
+
46
+ :param shortcut_name: The name of the shortcut file to remove from the startup folder.
47
+ No need to add the ".LNK" extension.
48
+ """
49
+ shortcut_file_path = Path(STARTUP_FOLDER, f'{shortcut_name}.lnk')
50
+ if shortcut_file_path.exists():
51
+ shortcut_file_path.unlink()
52
+ return True
53
+ return False
@@ -0,0 +1,119 @@
1
+ import os
2
+ import datetime
3
+
4
+ import win32com.client
5
+ import pythoncom
6
+
7
+
8
+ TRIGGER_ONE_TIME: int = 1
9
+ TRIGGER_DAILY: int = 2
10
+ TRIGGER_AT_SYSTEM_STARTUP: int = 8
11
+ TRIGGER_ON_LOGON: int = 9
12
+
13
+
14
+ def create_on_logon_task_with_system_privileges(exe_file_path: str, task_name: str, user_id: str = None):
15
+ """
16
+ This function will add a task to the Windows Task Scheduler with system privileges.
17
+
18
+ :param exe_file_path: The path to your executable file.
19
+ :param task_name: The name of the task to create in the Task Scheduler.
20
+ :param user_id: The user ID to run the task as.
21
+ None: the task will run for every user that logs on.
22
+ "SYSTEM": is a common user ID to run tasks with system privileges.
23
+ :return: True if the task was added successfully, False otherwise.
24
+ """
25
+
26
+ scheduler = win32com.client.Dispatch('Schedule.Service')
27
+ scheduler.Connect()
28
+
29
+ root_folder = scheduler.GetFolder('\\')
30
+ task_def = scheduler.NewTask(0)
31
+
32
+ # Set up registration information for the task
33
+ reg_info = task_def.RegistrationInfo
34
+ reg_info.Description = f'Task to run {os.path.basename(exe_file_path)} at logon'
35
+ reg_info.Author = 'Your Name'
36
+
37
+ # Set up the principal for the task
38
+ principal = task_def.Principal
39
+ if user_id is not None:
40
+ principal.UserId = user_id
41
+ # principal.LogonType = 3 # TaskLogonTypeInteractiveToken, Only run when the user is logged on.
42
+ principal.LogonType = 1 # 1 is for password not required
43
+ principal.RunLevel = 1 # TaskRunLevelHighest
44
+
45
+ # Create the logon trigger
46
+ trigger = task_def.Triggers.Create(TRIGGER_ON_LOGON)
47
+ if user_id:
48
+ trigger.UserId = user_id
49
+ trigger.Id = "LogonTriggerId"
50
+ trigger.Enabled = True
51
+ trigger.StartBoundary = datetime.datetime.now().isoformat() # Set start boundary to current time in ISO format
52
+
53
+ # Create the action to run the executable
54
+ action = task_def.Actions.Create(0) # 0 stands for TASK_ACTION_EXEC
55
+ action.Path = exe_file_path
56
+ action.WorkingDirectory = os.path.dirname(exe_file_path)
57
+ action.Arguments = ''
58
+
59
+ # Set task settings
60
+ settings = task_def.Settings
61
+ settings.Enabled = True
62
+ settings.StartWhenAvailable = True
63
+ settings.Hidden = False
64
+ settings.StopIfGoingOnBatteries = False
65
+ settings.DisallowStartIfOnBatteries = False
66
+ # Sets the limit to zero, which means the task will run indefinitely. The default is 3 days.
67
+ settings.ExecutionTimeLimit = 'PT0S'
68
+
69
+ # Register the task
70
+ root_folder.RegisterTaskDefinition(
71
+ task_name, task_def, 6, # 6 is for CREATE_OR_UPDATE
72
+ None, # No user (runs in system context)
73
+ None, # No password
74
+ 3
75
+ )
76
+
77
+
78
+ def is_task_in_scheduler(task_name: str, scheduler_instance=None) -> bool:
79
+ """
80
+ This function will check if the task is in the Windows Task Scheduler.
81
+
82
+ :param task_name: The name of the task to check in the Task Scheduler.
83
+ :param scheduler_instance: The instance of the Task Scheduler to use.
84
+ If None, a new instance will be created.
85
+ :return: True if the task is in the Task Scheduler, False otherwise.
86
+ """
87
+
88
+ if scheduler_instance is None:
89
+ scheduler_instance = win32com.client.Dispatch('Schedule.Service')
90
+ scheduler_instance.Connect()
91
+
92
+ try:
93
+ root_folder = scheduler_instance.GetFolder('\\')
94
+ root_folder.GetTask(task_name)
95
+ return True
96
+ except pythoncom.com_error as e:
97
+ if e.hresult == -2147352567 and e.excepinfo[5] == -2147024894: # HRESULT code for "Task does not exist"
98
+ return False
99
+ else:
100
+ raise
101
+
102
+
103
+ def remove_task_from_scheduler(task_name: str) -> bool:
104
+ """
105
+ This function will remove the task from the Windows Task Scheduler.
106
+
107
+ :param task_name: The name of the task to remove from the Task Scheduler.
108
+ :return: True if the task was removed successfully, False otherwise.
109
+ """
110
+
111
+ scheduler_instance = win32com.client.Dispatch('Schedule.Service')
112
+ scheduler_instance.Connect()
113
+
114
+ if not is_task_in_scheduler(task_name, scheduler_instance=scheduler_instance):
115
+ return False
116
+ else:
117
+ root_folder = scheduler_instance.GetFolder('\\')
118
+ root_folder.GetTask(task_name)
119
+ return True
@@ -1,6 +1,34 @@
1
1
  import logging
2
2
  from logging.handlers import TimedRotatingFileHandler, QueueListener, QueueHandler
3
3
  import re
4
+ import os
5
+
6
+
7
+ class TimedRotatingFileHandlerWithHeader(TimedRotatingFileHandler):
8
+ """
9
+ Custom TimedRotatingFileHandler that writes a header to the log file each time there is a file rotation.
10
+ Useful for writing CSV files.
11
+
12
+ :param header: string, Header to write to the log file.
13
+ Example: "time,host,error"
14
+ """
15
+ def __init__(self, *args, **kwargs):
16
+ self.header = kwargs.pop('header', None)
17
+ super().__init__(*args, **kwargs)
18
+
19
+ def doRollover(self):
20
+ super().doRollover()
21
+ self._write_header()
22
+
23
+ def _write_header(self):
24
+ if self.header:
25
+ with open(self.baseFilename, 'a') as f:
26
+ f.write(self.header + '\n')
27
+
28
+ def emit(self, record):
29
+ if not os.path.exists(self.baseFilename) or os.path.getsize(self.baseFilename) == 0:
30
+ self._write_header()
31
+ super().emit(record)
4
32
 
5
33
 
6
34
  def get_stream_handler() -> logging.StreamHandler:
@@ -38,6 +66,28 @@ def get_timed_rotating_file_handler(
38
66
  filename=log_file_path, when=when, interval=interval, delay=delay, encoding=encoding)
39
67
 
40
68
 
69
+ def get_timed_rotating_file_handler_with_header(
70
+ log_file_path: str, when: str = "midnight", interval: int = 1, delay: bool = False, encoding=None,
71
+ header: str = None) -> TimedRotatingFileHandlerWithHeader:
72
+ """
73
+ Function to get a TimedRotatingFileHandler with header.
74
+ This handler will output messages to a file, rotating the log file at certain timed intervals.
75
+ It will write a header to the log file each time there is a file rotation.
76
+
77
+ :param log_file_path: Path to the log file.
78
+ :param when: When to rotate the log file. Possible
79
+ :param interval: Interval to rotate the log file.
80
+ :param delay: bool, If set to True, the log file will be created only if there's something to write.
81
+ :param encoding: Encoding to use for the log file. Same as for the TimeRotatingFileHandler, which uses Default None.
82
+ :param header: Header to write to the log file.
83
+ Example: "time,host,error"
84
+ :return: TimedRotatingFileHandlerWithHeader.
85
+ """
86
+
87
+ return TimedRotatingFileHandlerWithHeader(
88
+ filename=log_file_path, when=when, interval=interval, delay=delay, encoding=encoding, header=header)
89
+
90
+
41
91
  def start_queue_listener_for_file_handler(
42
92
  file_handler: logging.FileHandler, queue_object) -> logging.handlers.QueueListener:
43
93
  """
@@ -133,3 +183,22 @@ def change_rotated_filename(file_handler: logging.Handler, file_extension: str):
133
183
  file_handler.suffix = logfile_suffix
134
184
  file_handler.namer = lambda name: name.replace(file_extension + ".", "") + file_extension
135
185
  file_handler.extMatch = logfile_regex_suffix
186
+
187
+
188
+ def has_handlers(logger: logging.Logger) -> bool:
189
+ """
190
+ Function to check if the logger has handlers.
191
+ :param logger: Logger to check
192
+ :return: True if logger has handlers, False otherwise
193
+ """
194
+
195
+ # Omitted the usage of "hasHandlers()" method, since sometimes returned "True" even when there were no handlers
196
+ # Didn't research the issue much, just used the "len(logger.handlers)" to check how many handlers there are
197
+ # in the logger.
198
+ # if not logging.getLogger(function_module_name).hasHandlers():
199
+ # if len(logging.getLogger(function_module_name).handlers) == 0:
200
+
201
+ if len(logger.handlers) == 0:
202
+ return False
203
+ else:
204
+ return True
@@ -67,17 +67,87 @@ def get_logger_with_timedfilehandler(
67
67
 
68
68
  def get_logger_with_stream_handler_and_timedfilehandler(
69
69
  logger_name: str,
70
- directory_path, file_name: str = None, file_extension: str = '.txt',
71
- logging_level="DEBUG", formatter_filehandler='default',
70
+ directory_path,
71
+ file_name: str = None,
72
+ file_extension: str = '.txt',
73
+ logging_level="DEBUG",
74
+ formatter_filehandler='default',
72
75
  formatter_streamhandler: str = "%(levelname)s | %(threadName)s | %(name)s | %(message)s",
73
- formatter_message_only: bool = False, disable_duplicate_ms: bool = False,
74
- when: str = "midnight", interval: int = 1, delay: bool = True, encoding=None
76
+ formatter_message_only: bool = False,
77
+ disable_duplicate_ms: bool = False,
78
+ when: str = "midnight",
79
+ interval: int = 1,
80
+ delay: bool = True,
81
+ encoding=None,
82
+ header: str = None
75
83
  ) -> logging.Logger:
84
+ """
85
+ Function to get a logger and add StreamHandler and TimedRotatingFileHandler to it.
86
+
87
+ :param logger_name: Name of the logger.
88
+ :param directory_path: string, Path to the directory where the log file will be created.
89
+ :param file_name: string, Name of the log file without file extension, since we add it through separate argument.
90
+ If not provided, logger name will be used.
91
+ :param file_extension: string, Extension of the log file. Default is '.txt'.
92
+ '.txt': Text file.
93
+ '.csv': CSV file.
94
+ '.json': JSON file.
95
+ :param logging_level: str or int, Logging level for the handler, that will use the logger while initiated.
96
+ :param formatter_filehandler: string, Formatter to use for handler. It is template of how a message will look like.
97
+ None: No formatter will be used.
98
+ 'default': Default formatter will be used for each file extension:
99
+ .txt: "%(asctime)s | %(levelname)s | %(threadName)s | %(name)s | %(message)s"
100
+ .csv: "%(asctime)s,%(levelname)s,%(threadName)s,%(name)s,%(message)s"
101
+ .json: '{"time": "%(asctime)s", "level": "%(levelname)s", "thread": "%(threadName)s",
102
+ "logger": "%(name)s", "message": "%(message)s"}'
103
+ :param formatter_streamhandler: string, Formatter to use for StreamHandler. It is template of how a message will
104
+ look like.
105
+ :param formatter_message_only: bool, If set to True, formatter will be used only for the 'message' part.
106
+ :param disable_duplicate_ms: bool, If set to True, duplicate milliseconds will be removed from formatter
107
+ 'asctime' element.
108
+ :param when: string, When to rotate the log file. Default is 'midnight'.
109
+ [when="midnight"] is set to rotate the filename at midnight. This means that the current file name will be
110
+ added Yesterday's date to the end of the file and today's file will continue to write at the same
111
+ filename. Also, if the script finished working on 25.11.2021, the name of the log file will be "test.log"
112
+ If you run the script again on 28.11.2021, the logging module will take the last modification date of
113
+ the file "test.log" and assign a date to it: test.log.2021_11_25
114
+ The log filename of 28.11.2021 will be called "test.log" again.
115
+ :param interval: int, Interval to rotate the log file. Default is 1.
116
+ If 'when="midnight"' and 'interval=1', then the log file will be rotated every midnight.
117
+ If 'when="midnight"' and 'interval=2', then the log file will be rotated every 2nd midnights.
118
+ :param delay: bool, If set to True, the log file will be created only if there's something to write.
119
+ :param encoding: string, Encoding to use for the log file. Default is None.
120
+ :param header: string, Header to write to the log file.
121
+ Example: "time,host,error"
122
+
123
+ :return: Logger.
124
+
125
+ ================================================================================================================
126
+
127
+ Working example to write CSV logs to the file and output messages to the console:
128
+ from atomicshop.wrappers.loggingw import loggingw
129
+
130
+
131
+ def main():
132
+ header: str = "time,host,error"
133
+ output_directory: str = "D:\\logs"
134
+
135
+ error_logger = loggingw.get_logger_with_stream_handler_and_timedfilehandler(
136
+ logger_name="errors", directory_path=output_directory,
137
+ file_extension=".csv", formatter_message_only=True, header=header
138
+ )
139
+
140
+ error_logger.info(f"{datetime.now()},host1,/path/to/file,error message")
141
+
142
+
143
+ if __name__ == "__main__":
144
+ main()
145
+ """
76
146
  logger = get_logger_with_level(logger_name, logging_level)
77
147
  add_stream_handler(logger, logging_level, formatter_streamhandler, formatter_message_only)
78
148
  add_timedfilehandler_with_queuehandler(
79
149
  logger, directory_path, file_name, file_extension, logging_level, formatter_filehandler,
80
- formatter_message_only, disable_duplicate_ms, when, interval, delay, encoding
150
+ formatter_message_only, disable_duplicate_ms, when, interval, delay, encoding, header
81
151
  )
82
152
 
83
153
  return logger
@@ -123,10 +193,20 @@ def add_stream_handler(
123
193
 
124
194
 
125
195
  def add_timedfilehandler_with_queuehandler(
126
- logger: logging.Logger, directory_path, file_name_no_extension: str = None, file_extension: str = '.txt',
196
+ logger: logging.Logger,
197
+ directory_path: str,
198
+ file_name_no_extension: str = None,
199
+ file_extension: str = '.txt',
127
200
  logging_level="DEBUG",
128
- formatter='default', formatter_message_only: bool = False, disable_duplicate_ms: bool = False,
129
- when: str = 'midnight', interval: int = 1, delay: bool = True, encoding=None):
201
+ formatter='default',
202
+ formatter_message_only: bool = False,
203
+ disable_duplicate_ms: bool = False,
204
+ when: str = 'midnight',
205
+ interval: int = 1,
206
+ delay: bool = True,
207
+ encoding=None,
208
+ header: str = None
209
+ ):
130
210
  """
131
211
  Function to add TimedRotatingFileHandler and QueueHandler to logger.
132
212
  TimedRotatingFileHandler will output messages to the file through QueueHandler.
@@ -160,6 +240,8 @@ def add_timedfilehandler_with_queuehandler(
160
240
  If 'when="midnight"' and 'interval=2', then the log file will be rotated every 2nd midnights.
161
241
  :param delay: bool, If set to True, the log file will be created only if there's something to write.
162
242
  :param encoding: string, Encoding to use for the log file. Default is None.
243
+ :param header: string, Header to write to the log file.
244
+ Example: "time,host,error"
163
245
  """
164
246
 
165
247
  # If file name wasn't provided we will use the logger name instead.
@@ -176,8 +258,17 @@ def add_timedfilehandler_with_queuehandler(
176
258
 
177
259
  # Creating file handler with log filename. At this stage the log file is created and locked by the handler,
178
260
  # Unless we use "delay=True" to tell the class to write the file only if there's something to write.
179
- file_handler = handlers.get_timed_rotating_file_handler(
180
- log_file_path, when=when, interval=interval, delay=delay, encoding=encoding)
261
+
262
+ if file_extension == ".csv":
263
+ # If file extension is CSV, we'll set the header to the file.
264
+ # This is needed since the CSV file will be rotated, and we'll need to set the header each time.
265
+ # We'll use the custom TimedRotatingFileHandlerWithHeader class.
266
+ file_handler = handlers.get_timed_rotating_file_handler_with_header(
267
+ log_file_path, when=when, interval=interval, delay=delay, encoding=encoding, header=header)
268
+ else:
269
+ file_handler = handlers.get_timed_rotating_file_handler(
270
+ log_file_path, when=when, interval=interval, delay=delay, encoding=encoding)
271
+
181
272
  loggers.set_logging_level(file_handler, logging_level)
182
273
 
183
274
  if formatter == "default":
@@ -236,16 +236,25 @@ def get_latest_lines(
236
236
  return: List of new lines.
237
237
 
238
238
  Usage:
239
+ from typing import Union
240
+
241
+
242
+ # The header of the log file will be read from the first iteration of the log file.
243
+ # When the file is rotated, this header will be used to not read the header again.
244
+ header: Union[list, None] = None
239
245
  while True:
240
- latest_lines, current_lines, existing_lines, last_24_hours_lines = get_latest_log_lines(
246
+ latest_lines, previous_day_24h_lines, header = reading.get_latest_lines(
241
247
  log_file_path='/path/to/log.csv',
242
- log_type='csv'
248
+ log_type='csv',
249
+ date_pattern='%Y_%m_%d',
250
+ get_previous_file=True,
251
+ header=header
243
252
  )
244
253
 
245
254
  if latest_lines:
246
255
  # Do something with the new lines.
247
256
 
248
- if last_24_hours_lines:
257
+ if previous_day_24h_lines:
249
258
  # Do something with the last 24 hours lines. Reminder, this will happen once a day on log rotation.
250
259
 
251
260
  time.sleep(1)
@@ -0,0 +1,19 @@
1
+ from pathlib import Path
2
+
3
+ from win32com.client import Dispatch
4
+
5
+
6
+ def create_shortcut(file_path_to_link: str, shortcut_file_path: str):
7
+ """
8
+ Create a shortcut in the startup folder to the specified file.
9
+
10
+ :param file_path_to_link: The path to the file you want to create a shortcut to.
11
+ :param shortcut_file_path: The name of the shortcut file. Should be with the ".lnk" extension.
12
+ """
13
+
14
+ shell = Dispatch('WScript.Shell')
15
+ shortcut = shell.CreateShortCut(shortcut_file_path)
16
+ shortcut.Targetpath = file_path_to_link
17
+ shortcut.WorkingDirectory = str(Path(file_path_to_link).parent)
18
+ shortcut.Description = f"Shortcut for {Path(file_path_to_link).name}"
19
+ shortcut.save()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: atomicshop
3
- Version: 2.12.19
3
+ Version: 2.12.21
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=CBepG0XgfpgafeV__swI0Jz0kUF1uJvK3WLlJWWcQwk,124
1
+ atomicshop/__init__.py,sha256=LSUgsf6XY377_4Z2xaHNOnKX7HYoq7IlSOu4OJMwzf0,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
@@ -116,7 +116,7 @@ atomicshop/mitm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
116
116
  atomicshop/mitm/connection_thread_worker.py,sha256=PQ8bwOgrPudYP5oPnSi_DWaKXOi038M8TMImlLkxuPI,20486
117
117
  atomicshop/mitm/import_config.py,sha256=_V-IVJ7a1L6E-VOR4CDfZj-S1odbsIlBe13ij0NlpqY,7974
118
118
  atomicshop/mitm/initialize_engines.py,sha256=UGdT5DKYNri3MNOxESP7oeSxYiUDrVilJ4jic_nwdew,8055
119
- atomicshop/mitm/initialize_mitm_server.py,sha256=aXNZlRu1_RGjC7lagvs2Q8rjQiygxYucy-U4C_SBnsk,13871
119
+ atomicshop/mitm/initialize_mitm_server.py,sha256=5JGkyvAvz1sJVeRGMJWSQiQ-VOdrU-NJn633oxQe0cw,13143
120
120
  atomicshop/mitm/message.py,sha256=u2U2f2SOHdBNU-6r1Ik2W14ai2EOwxUV4wVfGZA098k,1732
121
121
  atomicshop/mitm/shared_functions.py,sha256=PaK_sbnEA5zo9k2ktEOKLmvo-6wRUunxzSNRr41uXIQ,1924
122
122
  atomicshop/mitm/statistic_analyzer.py,sha256=WvTal-Aox-enM-5jYtFqiTplNquS4VMnmQYNEIXvZZA,23552
@@ -142,6 +142,10 @@ atomicshop/monitor/checks/process_running.py,sha256=x66wd6-l466r8sbRQaIli0yswyGt
142
142
  atomicshop/monitor/checks/url.py,sha256=1PvKt_d7wFg7rDMFpUejAQhj0mqWsmlmrNfjNAV2G4g,4123
143
143
  atomicshop/ssh_scripts/process_from_ipv4.py,sha256=uDBKZ2Ds20614JW1xMLr4IPB-z1LzIwy6QH5-SJ4j0s,1681
144
144
  atomicshop/ssh_scripts/process_from_port.py,sha256=uDTkVh4zc3HOTTGv1Et3IxM3PonDJCPuFRL6rnZDQZ4,1389
145
+ atomicshop/startup/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
146
+ atomicshop/startup/win/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
147
+ atomicshop/startup/win/startup_folder.py,sha256=2RZEyF-Mf8eWPlt_-OaoGKKnMs6YhELEzJZ376EI0E0,1891
148
+ atomicshop/startup/win/task_scheduler.py,sha256=qALe-8sfthYxsdCViH2r8OsH3x-WauDqteg5RzElPdk,4348
145
149
  atomicshop/wrappers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
146
150
  atomicshop/wrappers/_process_wrapper_curl.py,sha256=XkZZXYl7D0Q6UfdWqy-18AvpU0yVp9i2BVD2qRcXlkk,841
147
151
  atomicshop/wrappers/_process_wrapper_tar.py,sha256=WUMZFKNrlG4nJP9tWZ51W7BR1j_pIjsjgyAStmWjRGs,655
@@ -210,12 +214,11 @@ atomicshop/wrappers/factw/rest/statistics.py,sha256=vznwzKP1gEF7uXz3HsuV66BU9wrp
210
214
  atomicshop/wrappers/factw/rest/status.py,sha256=4O3xS1poafwyUiLDkhyx4oMMe4PBwABuRPpOMnMKgIU,641
211
215
  atomicshop/wrappers/fibratusw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
212
216
  atomicshop/wrappers/fibratusw/install.py,sha256=PLVymDe0HuOvU0r2lje8BkQAgtiOWEeRO7n-1zKuL7A,3287
213
- atomicshop/wrappers/loggingw/checks.py,sha256=AGFsTsLxHQd1yAraa5popqLaGO9VM0KpcPGuSLn5ptU,719
214
217
  atomicshop/wrappers/loggingw/formatters.py,sha256=mUtcJJfmhLNrwUVYShXTmdu40dBaJu4TS8FiuTXI7ys,7189
215
- atomicshop/wrappers/loggingw/handlers.py,sha256=qm5Fbu8eDmlstMduUe5nKUlJU5IazFkSnQizz8Qt2os,5479
218
+ atomicshop/wrappers/loggingw/handlers.py,sha256=2A_3Qy1B0RvVWZmQocAB6CmpqlXoKJ-yi6iBWG2jNLo,8274
216
219
  atomicshop/wrappers/loggingw/loggers.py,sha256=DHOOTAtqkwn1xgvLHSkOiBm6yFGNuQy1kvbhG-TDog8,2374
217
- atomicshop/wrappers/loggingw/loggingw.py,sha256=v9WAseZXB50LluT9rIUcRvvevg2nLVKPgz3dbGejfV0,12151
218
- atomicshop/wrappers/loggingw/reading.py,sha256=CtYOwOLFHj_hqYyZx-dKUo5ZDrn3cO-f7vU4EX515xI,14980
220
+ atomicshop/wrappers/loggingw/loggingw.py,sha256=m6YySEedP3_4Ik1S_uGMxETSbmRkmMYmAZxhHBlXSlo,16616
221
+ atomicshop/wrappers/loggingw/reading.py,sha256=OgKDuYV8KD3brXD82_UIQLPGL6qUeFINcFOYxVIi8Q8,15347
219
222
  atomicshop/wrappers/nodejsw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
220
223
  atomicshop/wrappers/nodejsw/install_nodejs.py,sha256=QZg-R2iTQt7kFb8wNtnTmwraSGwvUs34JIasdbNa7ZU,5154
221
224
  atomicshop/wrappers/playwrightw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -233,6 +236,7 @@ atomicshop/wrappers/psutilw/disks.py,sha256=3ZSVoommKH1TWo37j_83frB-NqXF4Nf5q5mB
233
236
  atomicshop/wrappers/psutilw/memories.py,sha256=_S0aL8iaoIHebd1vOFrY_T9aROM5Jx2D5CvDh_4j0Vc,528
234
237
  atomicshop/wrappers/psutilw/psutilw.py,sha256=G22ZQfGnqX15-feD8KUXfEZO4pFkIEnB8zgPzJ2jc7M,20868
235
238
  atomicshop/wrappers/psycopgw/psycopgw.py,sha256=XJvVf0oAUjCHkrYfKeFuGCpfn0Oxj3u4SbKMKA1508E,7118
239
+ atomicshop/wrappers/pywin32w/winshell.py,sha256=i2bKiMldPU7_azsD5xGQDdMwjaM7suKJd3k0Szmcs6c,723
236
240
  atomicshop/wrappers/pywin32w/wmi_win32process.py,sha256=qMzXtJ5hBZ5ydAyqpDbSx0nO2RJQL95HdmV5SzNKMhk,6826
237
241
  atomicshop/wrappers/socketw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
238
242
  atomicshop/wrappers/socketw/accepter.py,sha256=HQC1EyZmyUtVEfFbaBkHCE-VZp6RWyd9mEqAkgsE1fk,1749
@@ -250,8 +254,8 @@ atomicshop/wrappers/socketw/socket_server_tester.py,sha256=AhpurHJmP2kgzHaUbq5ey
250
254
  atomicshop/wrappers/socketw/socket_wrapper.py,sha256=aXBwlEIJhFT0-c4i8iNlFx2It9VpCEpsv--5Oqcpxao,11624
251
255
  atomicshop/wrappers/socketw/ssl_base.py,sha256=k4V3gwkbq10MvOH4btU4onLX2GNOsSfUAdcHmL1rpVE,2274
252
256
  atomicshop/wrappers/socketw/statistics_csv.py,sha256=t3dtDEfN47CfYVi0CW6Kc2QHTEeZVyYhc57IYYh5nmA,826
253
- atomicshop-2.12.19.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
254
- atomicshop-2.12.19.dist-info/METADATA,sha256=XjMOMxBIk9wbHMRy4KgeBeYKoy8sD8FJjt-CGllbCsw,10479
255
- atomicshop-2.12.19.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
256
- atomicshop-2.12.19.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
257
- atomicshop-2.12.19.dist-info/RECORD,,
257
+ atomicshop-2.12.21.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
258
+ atomicshop-2.12.21.dist-info/METADATA,sha256=iWSjLaN-XwW8NsBxqu8wdQPgrJZZv1EaZ7-x4e_Tglo,10479
259
+ atomicshop-2.12.21.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
260
+ atomicshop-2.12.21.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
261
+ atomicshop-2.12.21.dist-info/RECORD,,
@@ -1,20 +0,0 @@
1
- import logging
2
-
3
-
4
- def has_handlers(logger: logging.Logger) -> bool:
5
- """
6
- Function to check if the logger has handlers.
7
- :param logger: Logger to check
8
- :return: True if logger has handlers, False otherwise
9
- """
10
-
11
- # Omitted the usage of "hasHandlers()" method, since sometimes returned "True" even when there were no handlers
12
- # Didn't research the issue much, just used the "len(logger.handlers)" to check how many handlers there are
13
- # in the logger.
14
- # if not logging.getLogger(function_module_name).hasHandlers():
15
- # if len(logging.getLogger(function_module_name).handlers) == 0:
16
-
17
- if len(logger.handlers) == 0:
18
- return False
19
- else:
20
- return True