atomicshop 2.9.3__py3-none-any.whl → 2.9.5__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.9.3'
4
+ __version__ = '2.9.5'
@@ -185,6 +185,31 @@ def import_first_class_name_from_file_path(script_directory: str, file_path: str
185
185
  return imported_class
186
186
 
187
187
 
188
+ def import_file_as_module(script_directory: str, file_path: str):
189
+ """
190
+ Function imports file as module and returns the module object.
191
+
192
+ :param script_directory: string, of file full path to working directory of the main script that will be subtracted
193
+ from the file path.
194
+ :param file_path: string, of full file path to python file module.
195
+ :return: module object.
196
+ """
197
+
198
+ # Get the module name string.
199
+ module_name: str = get_module_name_from_file_path(script_directory, file_path)
200
+
201
+ # Import the module.
202
+ try:
203
+ imported_module = import_module_by_string(module_name)
204
+ except ModuleNotFoundError:
205
+ # If the module is not found, we will try to add this path to the system path and try again.
206
+ sys.path.append(str(Path(file_path).parent))
207
+
208
+ imported_module = import_module_by_string(module_name)
209
+
210
+ return imported_module
211
+
212
+
188
213
  def get_attributes(
189
214
  obj,
190
215
  include_private_1: bool = False,
@@ -1,3 +1,6 @@
1
+ from typing import Union
2
+
3
+
1
4
  def is_divisible(n, k):
2
5
  """Return True if n is divisible by k, False otherwise."""
3
6
 
@@ -18,3 +21,28 @@ def find_highest_number(numbers: list[float, int, str]):
18
21
  raise ValueError('The list of numbers is empty.')
19
22
 
20
23
  return max(numbers)
24
+
25
+
26
+ def convert_bytes_to_readable(byte_size: Union[int, float]):
27
+ """
28
+ Convert bytes to a more readable format (KB, MB, GB, etc.) with two numbers after the decimal point.
29
+
30
+ :param byte_size: Size in bytes
31
+ :type byte_size: int or float
32
+ :return: A string representing the size in a readable format
33
+ :rtype: str
34
+ """
35
+ # Define the suffixes for each unit of measurement
36
+ suffixes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
37
+ i = 0
38
+ # Convert byte_size to float for division
39
+ byte_size = float(byte_size)
40
+
41
+ # Calculate the unit of measurement to use
42
+ while byte_size >= 1024 and i < len(suffixes) - 1:
43
+ byte_size /= 1024.
44
+ i += 1
45
+
46
+ # Format the result to include two digits after the decimal point
47
+ readable_format = "{:.2f} {}".format(byte_size, suffixes[i])
48
+ return readable_format
@@ -1,45 +1,11 @@
1
1
  from typing import Union
2
+ import threading
2
3
  import multiprocessing
3
4
 
4
5
  from .print_api import print_api
5
6
  from . import system_resources
6
7
 
7
8
 
8
- def run_check_system_resources(
9
- interval, get_cpu, get_memory, get_disk_io_bytes, get_disk_files_count, get_disk_busy_time,
10
- get_disk_used_percent, calculate_maximum_changed_disk_io, maximum_disk_io, shared_results, queue=None):
11
- """
12
- Continuously update the system resources in the shared results dictionary.
13
- This function runs in a separate process.
14
- """
15
-
16
- while True:
17
- # Get the results of the system resources check function and store them in temporary results dictionary.
18
- results = system_resources.check_system_resources(
19
- interval=interval, get_cpu=get_cpu, get_memory=get_memory,
20
- get_disk_io_bytes=get_disk_io_bytes, get_disk_files_count=get_disk_files_count,
21
- get_disk_busy_time=get_disk_busy_time, get_disk_used_percent=get_disk_used_percent)
22
-
23
- if calculate_maximum_changed_disk_io:
24
- if results['disk_io_read'] > maximum_disk_io['read_bytes_per_sec']:
25
- maximum_disk_io['read_bytes_per_sec'] = results['disk_io_read']
26
- if results['disk_io_write'] > maximum_disk_io['write_bytes_per_sec']:
27
- maximum_disk_io['write_bytes_per_sec'] = results['disk_io_write']
28
- if results['disk_files_count_read'] > maximum_disk_io['read_files_count_per_sec']:
29
- maximum_disk_io['read_files_count_per_sec'] = results['disk_files_count_read']
30
- if results['disk_files_count_write'] > maximum_disk_io['write_files_count_per_sec']:
31
- maximum_disk_io['write_files_count_per_sec'] = results['disk_files_count_write']
32
- results['maximum_disk_io'] = maximum_disk_io
33
-
34
- # Update the shared results dictionary with the temporary results dictionary.
35
- # This is done in separate steps to avoid overwriting the special 'multiprocessing.Manager.dict' object.
36
- # So we update the shared results dictionary with the temporary results dictionary.
37
- shared_results.update(results)
38
-
39
- if queue is not None:
40
- queue.put(results)
41
-
42
-
43
9
  class SystemResourceMonitor:
44
10
  """
45
11
  A class to monitor system resources in a separate process.
@@ -54,7 +20,8 @@ class SystemResourceMonitor:
54
20
  get_disk_busy_time: bool = False,
55
21
  get_disk_used_percent: bool = True,
56
22
  calculate_maximum_changed_disk_io: bool = False,
57
- use_queue: bool = False
23
+ queue_list: list = None,
24
+ manager_dict = None # multiprocessing.Manager().dict()
58
25
  ):
59
26
  """
60
27
  Initialize the system resource monitor.
@@ -69,40 +36,55 @@ class SystemResourceMonitor:
69
36
  :param get_disk_used_percent: bool, get the disk used percentage.
70
37
  :param calculate_maximum_changed_disk_io: bool, calculate the maximum changed disk I/O. This includes the
71
38
  maximum changed disk I/O read and write in bytes/s and the maximum changed disk files count.
72
- :param use_queue: bool, use queue to store results.
73
- If you need ot get the queue, you can access it through the 'queue' attribute:
74
- SystemResourceMonitor.queue
75
-
76
- Example:
77
- system_resource_monitor = SystemResourceMonitor()
78
- your_queue = system_resource_monitor.queue
79
-
80
- while True:
81
- if not your_queue.empty():
82
- results = your_queue.get()
83
- print(results)
84
-
85
- ================
86
-
87
- Usage Example with queue:
88
- system_resource_monitor = SystemResourceMonitor(use_queue=True)
89
- system_resource_monitor.start()
90
- queue = system_resource_monitor.queue
91
- while True:
92
- if not queue.empty():
93
- results = queue.get()
94
- print(results)
95
-
96
- ================
97
-
98
- Usage Example without queue:
99
- interval = 1
100
- system_resource_monitor = SystemResourceMonitor(interval=interval, use_queue=False)
101
- system_resource_monitor.start()
102
- while True:
103
- time.sleep(interval)
104
- results = system_resource_monitor.get_latest_results()
105
- print(results)
39
+ :param queue_list: list, list of queues to store results. The queue type depends on your application.
40
+ If you need to use the results of the System Resource Monitor in another process or several processes
41
+ you can pass several queues in the queue_list to store the results.
42
+
43
+ Usage Example with multiprocessing.Manager().dict():
44
+ # Create multiprocessing manager dict that will be shared for monitoring results between the processes.
45
+ manager = multiprocessing.Manager()
46
+ shared_dict = manager.dict()
47
+
48
+ # Start the system resource monitor.
49
+ multiprocessing.Process(
50
+ target=system_resource_monitor.start_monitoring, kwargs={'manager_dict': shared_dict}).start()
51
+
52
+ # If you need ot get the queue, you can access it through the 'queue' attribute:
53
+ # SystemResourceMonitor.queue
54
+ #
55
+ # Example:
56
+ # system_resource_monitor = SystemResourceMonitor()
57
+ # your_queue = system_resource_monitor.queue
58
+ #
59
+ # while True:
60
+ # if not your_queue.empty():
61
+ # results = your_queue.get()
62
+ # print(results)
63
+ #
64
+ # ================
65
+ #
66
+ # Usage Example with queue:
67
+ # system_resource_monitor = SystemResourceMonitor(use_queue=True)
68
+ # system_resource_monitor.start()
69
+ # queue = system_resource_monitor.queue
70
+ # while True:
71
+ # if not queue.empty():
72
+ # results = queue.get()
73
+ # print(results)
74
+ #
75
+ # ================
76
+ #
77
+ # Usage Example without queue:
78
+ # interval = 1
79
+ # system_resource_monitor = SystemResourceMonitor(interval=interval, use_queue=False)
80
+ # system_resource_monitor.start()
81
+ # while True:
82
+ # time.sleep(interval)
83
+ # results = system_resource_monitor.get_latest_results()
84
+ # print(results)
85
+ :param manager_dict: multiprocessing.Manager().dict(), a dictionary to store the results.
86
+ If you need to use the results of the System Resource Monitor in another process or several processes
87
+ you can pass the manager_dict to store the results.
106
88
  """
107
89
  # Store parameters as instance attributes
108
90
  self.interval: float = interval
@@ -113,10 +95,9 @@ class SystemResourceMonitor:
113
95
  self.get_disk_busy_time: bool = get_disk_busy_time
114
96
  self.get_disk_used_percent: bool = get_disk_used_percent
115
97
  self.calculate_maximum_changed_disk_io: bool = calculate_maximum_changed_disk_io
98
+ self.queue_list: list = queue_list
99
+ self.manager_dict: multiprocessing.Manager().dict = manager_dict
116
100
 
117
- self.manager = multiprocessing.Manager()
118
- self.shared_results = self.manager.dict()
119
- self.process = None
120
101
  self.maximum_disk_io: dict = {
121
102
  'read_bytes_per_sec': 0,
122
103
  'write_bytes_per_sec': 0,
@@ -124,10 +105,12 @@ class SystemResourceMonitor:
124
105
  'write_files_count_per_sec': 0
125
106
  }
126
107
 
127
- if use_queue:
128
- self.queue = multiprocessing.Queue()
129
- else:
130
- self.queue = None
108
+ # Main thread that gets the monitoring results.
109
+ self.thread: Union[threading.Thread, None] = None
110
+ # Sets the running state of the monitoring process. Needed to stop the monitoring and queue threads.
111
+ self.running: bool = False
112
+ # The shared results dictionary.
113
+ self.results: dict = {}
131
114
 
132
115
  def start(self, print_kwargs: dict = None):
133
116
  """
@@ -135,31 +118,72 @@ class SystemResourceMonitor:
135
118
  :param print_kwargs:
136
119
  :return:
137
120
  """
121
+
122
+ def run_check_system_resources(
123
+ interval, get_cpu, get_memory, get_disk_io_bytes, get_disk_files_count, get_disk_busy_time,
124
+ get_disk_used_percent, calculate_maximum_changed_disk_io, maximum_disk_io, queue_list, manager_dict):
125
+ """
126
+ Continuously update the system resources in the shared results dictionary.
127
+ This function runs in a separate process.
128
+ """
129
+
130
+ while self.running:
131
+ # Get the results of the system resources check function and store them in temporary results dictionary.
132
+ results = system_resources.check_system_resources(
133
+ interval=interval, get_cpu=get_cpu, get_memory=get_memory,
134
+ get_disk_io_bytes=get_disk_io_bytes, get_disk_files_count=get_disk_files_count,
135
+ get_disk_busy_time=get_disk_busy_time, get_disk_used_percent=get_disk_used_percent)
136
+
137
+ if calculate_maximum_changed_disk_io:
138
+ if results['disk_io_read'] > maximum_disk_io['read_bytes_per_sec']:
139
+ maximum_disk_io['read_bytes_per_sec'] = results['disk_io_read']
140
+ if results['disk_io_write'] > maximum_disk_io['write_bytes_per_sec']:
141
+ maximum_disk_io['write_bytes_per_sec'] = results['disk_io_write']
142
+ if results['disk_files_count_read'] > maximum_disk_io['read_files_count_per_sec']:
143
+ maximum_disk_io['read_files_count_per_sec'] = results['disk_files_count_read']
144
+ if results['disk_files_count_write'] > maximum_disk_io['write_files_count_per_sec']:
145
+ maximum_disk_io['write_files_count_per_sec'] = results['disk_files_count_write']
146
+ results['maximum_disk_io'] = maximum_disk_io
147
+
148
+ if queue_list is not None:
149
+ for queue in queue_list:
150
+ queue.put(results)
151
+
152
+ # Update the shared results dictionary with the temporary results dictionary.
153
+ # This is done in separate steps to avoid overwriting the special 'multiprocessing.Manager.dict' object.
154
+ # So we update the shared results dictionary with the temporary results dictionary.
155
+ if manager_dict is not None:
156
+ manager_dict.update(results)
157
+
158
+ self.results = results
159
+
138
160
  if print_kwargs is None:
139
161
  print_kwargs = {}
140
162
 
141
- if self.process is None or not self.process.is_alive():
142
- self.process = multiprocessing.Process(target=run_check_system_resources, args=(
163
+ if self.thread is None:
164
+ self.running = True
165
+ self.thread = threading.Thread(target=run_check_system_resources, args=(
143
166
  self.interval, self.get_cpu, self.get_memory, self.get_disk_io_bytes, self.get_disk_files_count,
144
167
  self.get_disk_busy_time, self.get_disk_used_percent, self.calculate_maximum_changed_disk_io,
145
- self.maximum_disk_io, self.shared_results, self.queue))
146
- self.process.start()
168
+ self.maximum_disk_io, self.queue_list, self.manager_dict))
169
+ self.thread.start()
147
170
  else:
148
- print_api("Monitoring process is already running.", color='yellow', **print_kwargs)
171
+ print_api("Monitoring is already running.", color='yellow', **print_kwargs)
149
172
 
150
- def get_latest_results(self) -> dict:
173
+ def get_results(self) -> dict:
151
174
  """
152
- Retrieve the latest results from the shared results dictionary.
175
+ Retrieve the latest results.
153
176
  """
154
- return dict(self.shared_results)
177
+
178
+ return self.results
155
179
 
156
180
  def stop(self):
157
181
  """
158
182
  Stop the monitoring process.
159
183
  """
160
- if self.process is not None:
161
- self.process.terminate()
162
- self.process.join()
184
+ if self.thread is not None:
185
+ self.running = False
186
+ self.thread.join()
163
187
 
164
188
 
165
189
  # === END OF SYSTEM RESOURCE MONITOR. ==================================================================================
@@ -177,7 +201,8 @@ def start_monitoring(
177
201
  get_disk_busy_time: bool = False,
178
202
  get_disk_used_percent: bool = True,
179
203
  calculate_maximum_changed_disk_io: bool = False,
180
- use_queue: bool = False,
204
+ queue_list: list = None,
205
+ manager_dict=None, # multiprocessing.Manager().dict()
181
206
  print_kwargs: dict = None
182
207
  ):
183
208
  """
@@ -192,14 +217,21 @@ def start_monitoring(
192
217
  :param get_disk_used_percent: bool, get TOTAL disk used percentage.
193
218
  :param calculate_maximum_changed_disk_io: bool, calculate the maximum changed disk I/O. This includes the
194
219
  maximum changed disk I/O read and write in bytes/s and the maximum changed disk files count.
195
- :param use_queue: bool, use queue to store results.
196
- Usage Example:
197
- system_resources.start_monitoring(use_queue=True)
198
- queue = system_resources.get_monitoring_queue()
199
- while True:
200
- if not queue.empty():
201
- results = queue.get()
202
- print(results)
220
+ :param queue_list: list, list of queues to store results. The queue type depends on your application.
221
+ If you need to use the results of the System Resource Monitor in another process or several processes
222
+ you can pass several queues in the queue_list to store the results.
223
+ :param manager_dict: multiprocessing.Manager().dict(), a dictionary to store the results.
224
+ If you need to use the results of the System Resource Monitor in another process or several processes
225
+ you can pass the manager_dict to store the results.
226
+
227
+ Usage Example with multiprocessing.Manager().dict():
228
+ # Create multiprocessing manager dict that will be shared for monitoring results between the processes.
229
+ manager = multiprocessing.Manager()
230
+ shared_dict = manager.dict()
231
+
232
+ # Start the system resource monitor.
233
+ multiprocessing.Process(
234
+ target=system_resource_monitor.start_monitoring, kwargs={'manager_dict': shared_dict}).start()
203
235
 
204
236
  :param print_kwargs: dict, print kwargs.
205
237
  :return:
@@ -220,7 +252,8 @@ def start_monitoring(
220
252
  get_disk_busy_time=get_disk_busy_time,
221
253
  get_disk_used_percent=get_disk_used_percent,
222
254
  calculate_maximum_changed_disk_io=calculate_maximum_changed_disk_io,
223
- use_queue=use_queue
255
+ queue_list=queue_list,
256
+ manager_dict=manager_dict
224
257
  )
225
258
  SYSTEM_RESOURCES_MONITOR.start()
226
259
  else:
@@ -246,7 +279,7 @@ def get_monitoring_instance() -> SystemResourceMonitor:
246
279
  return SYSTEM_RESOURCES_MONITOR
247
280
 
248
281
 
249
- def get_result():
282
+ def get_results():
250
283
  """
251
284
  Get system resources monitoring result.
252
285
 
@@ -268,39 +301,6 @@ def get_result():
268
301
  """
269
302
  global SYSTEM_RESOURCES_MONITOR
270
303
  if SYSTEM_RESOURCES_MONITOR is not None:
271
- return SYSTEM_RESOURCES_MONITOR.get_latest_results()
272
- else:
273
- raise RuntimeError("System resources monitoring is not running.")
274
-
275
-
276
- def get_result_by_queue():
277
- """
278
- Get system resources monitoring result by queue.
279
-
280
- Usage Example:
281
- system_resources.start_system_resources_monitoring()
282
-
283
- while True:
284
- result = system_resources.get_result_by_queue()
285
- print(result)
286
-
287
- :return: dict
288
- """
289
- global SYSTEM_RESOURCES_MONITOR
290
- if SYSTEM_RESOURCES_MONITOR is not None:
291
- if not SYSTEM_RESOURCES_MONITOR.queue.empty():
292
- return SYSTEM_RESOURCES_MONITOR.queue.get()
293
- else:
294
- raise RuntimeError("System resources monitoring is not running.")
295
-
296
-
297
- def get_monitoring_queue() -> Union[multiprocessing.Queue, None]:
298
- """
299
- Get the monitoring queue.
300
- :return: multiprocessing.Queue
301
- """
302
- global SYSTEM_RESOURCES_MONITOR
303
- if SYSTEM_RESOURCES_MONITOR is not None:
304
- return SYSTEM_RESOURCES_MONITOR.queue
304
+ return SYSTEM_RESOURCES_MONITOR.get_results()
305
305
  else:
306
306
  raise RuntimeError("System resources monitoring is not running.")
@@ -38,14 +38,16 @@ def get_disk_io(
38
38
  }
39
39
  :param io_busy_time: Boolean indicating whether to return I/O busy time.
40
40
  !!! For some reason on Windows it gets the count of files read or written and not the time in ms.
41
+ !!! On Ubuntu it gets the time in ms, but for some reason it can return value higher than the interval.
42
+ Which is not possible, so it is not reliable.
41
43
  Returned dictionary:
42
44
  {
43
45
  'read_time_ms': int,
44
46
  'write_time_ms': int,
45
- 'read_time_per_sec': float,
46
- 'write_time_per_sec': float,
47
+ 'read_time_in_sec': float,
48
+ 'write_time_in_sec': float,
47
49
  'busy_time': int,
48
- 'busy_time_per_sec': float,
50
+ 'busy_time_in_sec': float,
49
51
  'busy_time_percent': float
50
52
  }
51
53
  :return: Disk utilization data.
@@ -121,40 +123,44 @@ def get_disk_io(
121
123
  io_change['aggregated'] = {}
122
124
 
123
125
  if io_change_bytes:
124
- total_read_change = io_end_aggregated.read_bytes - io_start_aggregated.read_bytes
125
- total_write_change = io_end_aggregated.write_bytes - io_start_aggregated.write_bytes
126
- total_read_change_per_sec = total_read_change / interval
127
- total_write_change_per_sec = total_write_change / interval
126
+ aggregated_read_change = io_end_aggregated.read_bytes - io_start_aggregated.read_bytes
127
+ aggregated_write_change = io_end_aggregated.write_bytes - io_start_aggregated.write_bytes
128
+ aggregated_read_change_per_sec = aggregated_read_change / interval
129
+ aggregated_write_change_per_sec = aggregated_write_change / interval
128
130
  io_change['aggregated'] = {
129
- 'read_change_bytes': total_read_change,
130
- 'write_change_bytes': total_write_change,
131
- 'read_change_per_sec': total_read_change_per_sec,
132
- 'write_change_per_sec': total_write_change_per_sec,
131
+ 'read_change_bytes': aggregated_read_change,
132
+ 'write_change_bytes': aggregated_write_change,
133
+ 'total_change_bytes': aggregated_read_change + aggregated_write_change,
134
+ 'read_change_per_sec': aggregated_read_change_per_sec,
135
+ 'write_change_per_sec': aggregated_write_change_per_sec,
136
+ 'total_change_per_sec': aggregated_read_change_per_sec + aggregated_write_change_per_sec
133
137
  }
134
138
  if io_file_count:
135
- total_read_count = io_end_aggregated.read_count - io_start_aggregated.read_count
136
- total_write_count = io_end_aggregated.write_count - io_start_aggregated.write_count
137
- total_read_count_per_sec = total_read_count / interval
138
- total_write_count_per_sec = total_write_count / interval
139
+ aggregated_read_count = io_end_aggregated.read_count - io_start_aggregated.read_count
140
+ aggregated_write_count = io_end_aggregated.write_count - io_start_aggregated.write_count
141
+ aggregated_read_count_per_sec = aggregated_read_count / interval
142
+ aggregated_write_count_per_sec = aggregated_write_count / interval
139
143
  io_change['aggregated'].update({
140
- 'read_file_count': total_read_count,
141
- 'write_file_count': total_write_count,
142
- 'read_file_count_per_sec': total_read_count_per_sec,
143
- 'write_file_count_per_sec': total_write_count_per_sec,
144
+ 'read_file_count': aggregated_read_count,
145
+ 'write_file_count': aggregated_write_count,
146
+ 'total_file_count': aggregated_read_count + aggregated_write_count,
147
+ 'read_file_count_per_sec': aggregated_read_count_per_sec,
148
+ 'write_file_count_per_sec': aggregated_write_count_per_sec,
149
+ 'total_file_count_per_sec': aggregated_read_count_per_sec + aggregated_write_count_per_sec
144
150
  })
145
151
  if io_busy_time:
146
- total_read_time = io_end_aggregated.read_time - io_start_aggregated.read_time
147
- total_write_time = io_end_aggregated.write_time - io_start_aggregated.write_time
148
- total_read_time_per_sec = total_read_time / 1000 / interval
149
- total_write_time_per_sec = total_write_time / 1000 / interval
152
+ aggregated_read_time = io_end_aggregated.read_time - io_start_aggregated.read_time
153
+ aggregated_write_time = io_end_aggregated.write_time - io_start_aggregated.write_time
154
+ aggregated_read_time_per_sec = aggregated_read_time / 1000 / interval
155
+ aggregated_write_time_per_sec = aggregated_write_time / 1000 / interval
150
156
  io_change['aggregated'].update({
151
- 'read_time_ms': total_read_time,
152
- 'write_time_ms': total_write_time,
153
- 'read_time_per_sec': total_read_time_per_sec,
154
- 'write_time_per_sec': total_write_time_per_sec,
155
- 'busy_time_ms': total_read_time + total_write_time,
156
- 'busy_time_per_sec': total_read_time_per_sec + total_write_time_per_sec,
157
- 'busy_time_percent': (total_read_time + total_write_time) / 1000 / interval
157
+ 'read_time_ms': aggregated_read_time,
158
+ 'write_time_ms': aggregated_write_time,
159
+ 'read_time_in_sec': aggregated_read_time_per_sec,
160
+ 'write_time_in_sec': aggregated_write_time_per_sec,
161
+ 'busy_time_ms': aggregated_read_time + aggregated_write_time,
162
+ 'busy_time_in_sec': aggregated_read_time_per_sec + aggregated_write_time_per_sec,
163
+ 'busy_time_percent': (aggregated_read_time + aggregated_write_time) / 1000 / interval
158
164
  })
159
165
 
160
166
  return io_change
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: atomicshop
3
- Version: 2.9.3
3
+ Version: 2.9.5
4
4
  Summary: Atomic functions and classes to make developer life easier
5
5
  Author: Denis Kras
6
6
  License: MIT License
@@ -52,6 +52,7 @@ Requires-Dist: pyopenssl
52
52
  Requires-Dist: python-bidi
53
53
  Requires-Dist: python-docx
54
54
  Requires-Dist: python-magic
55
+ Requires-Dist: reportlab
55
56
  Requires-Dist: SoundCard
56
57
  Requires-Dist: soundfile
57
58
  Requires-Dist: SpeechRecognition
@@ -1,4 +1,4 @@
1
- atomicshop/__init__.py,sha256=UjSVtKaCSXbeT09qt1iqtuZYnzeqYmKlvao2qVvXB28,122
1
+ atomicshop/__init__.py,sha256=QkIgch9FQImXtv5BITVxDWIEqyTcxufteFX_AG9NohM,122
2
2
  atomicshop/_basics_temp.py,sha256=6cu2dd6r2dLrd1BRNcVDKTHlsHs_26Gpw8QS6v32lQ0,3699
3
3
  atomicshop/_patch_import.py,sha256=ENp55sKVJ0e6-4lBvZnpz9PQCt3Otbur7F6aXDlyje4,6334
4
4
  atomicshop/appointment_management.py,sha256=N3wVGJgrqJfsj_lqiRfaL3FxMEe57by5Stzanh189mk,7263
@@ -36,7 +36,7 @@ atomicshop/sound.py,sha256=KSzWRF8dkpEVXmFidIv-Eftc3kET-hQzQOxZRE7rMto,24297
36
36
  atomicshop/speech_recognize.py,sha256=55-dIjgkpF93mvJnJuxSFuft5H5eRvGNlUj9BeIOZxk,5903
37
37
  atomicshop/ssh_remote.py,sha256=Sas3nrQv8ardxR51t59xZZsYm8nvUcA7tMSqEDViRLk,17155
38
38
  atomicshop/sys_functions.py,sha256=MTBxRve5bh58SPvhX3gMiGqHlSBuI_rdNN1NnnBBWqI,906
39
- atomicshop/system_resource_monitor.py,sha256=20pnGrr9bgCK03ptlKcoRifgFHzUP-UfkJY87Ige6FY,11923
39
+ atomicshop/system_resource_monitor.py,sha256=rQrY_iSNYisRXOXcCwykUxj937jCqeg-dDOF_ETO_0I,13626
40
40
  atomicshop/system_resources.py,sha256=BndRa6qgHAe4vzhQYWKfhQIuw3WwnwgJ8Etda4i1914,8059
41
41
  atomicshop/tempfiles.py,sha256=uq1ve2WlWehZ3NOTXJnpBBMt6HyCdBufqedF0HyzA6k,2517
42
42
  atomicshop/timer.py,sha256=KxBBgVM8po6pUJDW8TgY1UXj0iiDmRmL5XDCq0VHAfU,1670
@@ -73,7 +73,7 @@ atomicshop/basics/ansi_escape_codes.py,sha256=WtIkm-BjSZS5J5irDUdAMBNvdX-qXFZcTX
73
73
  atomicshop/basics/argparse_template.py,sha256=horwgSf3MX1ZgRnYxtmmQuz9OU_vKrKggF65gmjlmfg,5836
74
74
  atomicshop/basics/booleans.py,sha256=-4JnSQ1pSb6CNY_62wtHBW8NltjPJEKM-gYOxFujunA,1772
75
75
  atomicshop/basics/bytes_arrays.py,sha256=WvSRDhIGt1ywF95t-yNgpxLm1nlZUbM1Dz6QckcyE8Y,5915
76
- atomicshop/basics/classes.py,sha256=Ogb7i6sNYlUK219iJDA5PwhNvHlYmxPGXfm1AfX_ZQI,8854
76
+ atomicshop/basics/classes.py,sha256=EijW_g4EhdNBnKPMG3nT3HjFspTchtM7to6zm9Ad_Mk,9771
77
77
  atomicshop/basics/dicts.py,sha256=w9_ZolDNSf2ZyoZ53zIOrFq7VZWGWYAvAvwc4qHORAo,10973
78
78
  atomicshop/basics/dicts_nested.py,sha256=StYxYnYPa0SEJr1lmEwAv5zfERWWqoULeyG8e0zRAwE,4107
79
79
  atomicshop/basics/enumerations.py,sha256=41VVQYh_vnVapggxKg2IRU5e_EiMpZzX1n1mtxvoSzM,1364
@@ -86,7 +86,7 @@ atomicshop/basics/isinstancing.py,sha256=fQ35xfqbguQz2BUn-3a4KVGskhTcIn8JjRtxV2r
86
86
  atomicshop/basics/list_of_dicts.py,sha256=fu0H6dUD9uUo2kl7FYIrWzOQMwCmg7qRxGnFM5S319E,5716
87
87
  atomicshop/basics/lists.py,sha256=pLpYPSu0BjJIAe_Ar55XhLsH2YBhftn7b-tTAdkK1sw,3928
88
88
  atomicshop/basics/multiprocesses.py,sha256=AczaI4TmYduNjE6_VEQhxvDQn4VLDdXYRxhPDpjH4T0,17974
89
- atomicshop/basics/numbers.py,sha256=II-jP8MG0IYvmjT9_BLEai65xzDJ0LTHK2eFVSrgVqo,527
89
+ atomicshop/basics/numbers.py,sha256=j0f4glCtyIypEdCKv145F1gkzEEoZ2GdsGO-OM4BN7o,1439
90
90
  atomicshop/basics/randoms.py,sha256=DmYLtnIhDK29tAQrGP1Nt-A-v8WC7WIEB8Edi-nk3N4,282
91
91
  atomicshop/basics/strings.py,sha256=aQ92AJPvb3U0O6n2FMqRUqEsPCiklwGX--jPmB9M0_s,15418
92
92
  atomicshop/basics/threads.py,sha256=xvgdDJdmgN0wmmARoZ-H7Kvl1GOcEbvgaeGL4M3Hcx8,2819
@@ -205,7 +205,7 @@ atomicshop/wrappers/playwrightw/mouse.py,sha256=-2FZbQtjgH7tdXWld6ZPGqlKFUdf5in0
205
205
  atomicshop/wrappers/playwrightw/scenarios.py,sha256=Wz7aVYfG7K4fuSe_TUAc1jhFXVq5jYvZKbDtvqUiONc,5236
206
206
  atomicshop/wrappers/playwrightw/waits.py,sha256=308fdOu6YDqQ7K7xywj7R27sSmFanPBQqpZyBC-NFmo,7015
207
207
  atomicshop/wrappers/psutilw/cpus.py,sha256=w6LPBMINqS-T_X8vzdYkLS2Wzuve28Ydp_GafTCngrc,236
208
- atomicshop/wrappers/psutilw/disks.py,sha256=CMCDtM1kCvFvvaV2lX2rNiiNgrdPhrvBk4OBMeTYrLI,8487
208
+ atomicshop/wrappers/psutilw/disks.py,sha256=3ZSVoommKH1TWo37j_83frB-NqXF4Nf5q5mBCX8G4jE,9221
209
209
  atomicshop/wrappers/psutilw/memories.py,sha256=wpdKEkQ9Wty_r7ZJKkfli7wIHMXdQOMlmDlzmc_0FWo,161
210
210
  atomicshop/wrappers/psutilw/psutilw.py,sha256=W9PSEZmrm_Ct_-6oKqAcbgbyF21CwcIbbHOkVqgMiow,20866
211
211
  atomicshop/wrappers/psycopgw/psycopgw.py,sha256=XJvVf0oAUjCHkrYfKeFuGCpfn0Oxj3u4SbKMKA1508E,7118
@@ -226,8 +226,8 @@ atomicshop/wrappers/socketw/socket_server_tester.py,sha256=AhpurHJmP2kgzHaUbq5ey
226
226
  atomicshop/wrappers/socketw/socket_wrapper.py,sha256=aXBwlEIJhFT0-c4i8iNlFx2It9VpCEpsv--5Oqcpxao,11624
227
227
  atomicshop/wrappers/socketw/ssl_base.py,sha256=k4V3gwkbq10MvOH4btU4onLX2GNOsSfUAdcHmL1rpVE,2274
228
228
  atomicshop/wrappers/socketw/statistics_csv.py,sha256=t3dtDEfN47CfYVi0CW6Kc2QHTEeZVyYhc57IYYh5nmA,826
229
- atomicshop-2.9.3.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
230
- atomicshop-2.9.3.dist-info/METADATA,sha256=Md_39e1f8ZxkuyLAGiYU_PZDuIu9oBsWP_or49eBOWQ,10369
231
- atomicshop-2.9.3.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
232
- atomicshop-2.9.3.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
233
- atomicshop-2.9.3.dist-info/RECORD,,
229
+ atomicshop-2.9.5.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
230
+ atomicshop-2.9.5.dist-info/METADATA,sha256=e5PpNLxmJbvsfWIKUZsmDxPJUk3LFk6RZtaW3E3infM,10395
231
+ atomicshop-2.9.5.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
232
+ atomicshop-2.9.5.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
233
+ atomicshop-2.9.5.dist-info/RECORD,,