atomicshop 2.8.1__py3-none-any.whl → 2.9.0__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.8.1'
4
+ __version__ = '2.9.0'
atomicshop/print_api.py CHANGED
@@ -39,6 +39,8 @@ def print_api(
39
39
 
40
40
  Then, in the function, you can use it like this:
41
41
  print_api(message, **print_kwargs)
42
+ # If 'print_kwargs' is 'None'.
43
+ print_api(message, **(print_kwargs or {}))
42
44
  print_api(message, print_kwargs=print_kwargs)
43
45
  print_api(message, print_kwargs={'logger': self.logger})
44
46
 
@@ -0,0 +1,220 @@
1
+ from typing import Union
2
+ import multiprocessing
3
+
4
+ from .print_api import print_api
5
+ from . import system_resources
6
+
7
+
8
+ def run_check_system_resources(
9
+ interval, get_cpu, get_memory, get_disk_io, get_disk_used_percent, shared_results, queue=None):
10
+ """
11
+ Continuously update the system resources in the shared results dictionary.
12
+ This function runs in a separate process.
13
+ """
14
+
15
+ while True:
16
+ # Get the results of the system resources check function and store them in temporary results dictionary.
17
+ results = system_resources.check_system_resources(
18
+ interval=interval, get_cpu=get_cpu, get_memory=get_memory,
19
+ get_disk_io=get_disk_io,
20
+ get_disk_used_percent=get_disk_used_percent)
21
+ # Update the shared results dictionary with the temporary results dictionary.
22
+ # This is done in separate steps to avoid overwriting the special 'multiprocessing.Manager.dict' object.
23
+ # So we update the shared results dictionary with the temporary results dictionary.
24
+ shared_results.update(results)
25
+
26
+ if queue is not None:
27
+ queue.put(results)
28
+
29
+
30
+ class SystemResourceMonitor:
31
+ """
32
+ A class to monitor system resources in a separate process.
33
+ """
34
+ def __init__(
35
+ self,
36
+ interval: float = 1,
37
+ get_cpu: bool = True,
38
+ get_memory: bool = True,
39
+ get_disk_io: bool = True,
40
+ get_disk_used_percent: bool = True,
41
+ use_queue: bool = False
42
+ ):
43
+ """
44
+ Initialize the system resource monitor.
45
+ :param interval: float, the interval in seconds to check the system resources.
46
+ Default is 1 second.
47
+ :param get_cpu: bool, get the CPU usage.
48
+ :param get_memory: bool, get the memory usage.
49
+ :param get_disk_io: bool, get the disk I/O utilization.
50
+ :param get_disk_used_percent: bool, get the disk used percentage.
51
+ :param use_queue: bool, use queue to store results.
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
+ """
86
+ # Store parameters as instance attributes
87
+ self.interval = interval
88
+ self.get_cpu = get_cpu
89
+ self.get_memory = get_memory
90
+ self.get_disk_io = get_disk_io
91
+ self.get_disk_used_percent = get_disk_used_percent
92
+
93
+ self.manager = multiprocessing.Manager()
94
+ self.shared_results = self.manager.dict()
95
+ self.process = None
96
+
97
+ if use_queue:
98
+ self.queue = multiprocessing.Queue()
99
+ else:
100
+ self.queue = None
101
+
102
+ def start(self, print_kwargs: dict = None):
103
+ """
104
+ Start the monitoring process.
105
+ :param print_kwargs:
106
+ :return:
107
+ """
108
+ if print_kwargs is None:
109
+ print_kwargs = {}
110
+
111
+ if self.process is None or not self.process.is_alive():
112
+ self.process = multiprocessing.Process(target=run_check_system_resources, args=(
113
+ self.interval, self.get_cpu, self.get_memory, self.get_disk_io,
114
+ self.get_disk_used_percent, self.shared_results))
115
+ self.process.start()
116
+ else:
117
+ print_api("Monitoring process is already running.", color='yellow', **print_kwargs)
118
+
119
+ def get_latest_results(self) -> dict:
120
+ """
121
+ Retrieve the latest results from the shared results dictionary.
122
+ """
123
+ return dict(self.shared_results)
124
+
125
+ def stop(self):
126
+ """
127
+ Stop the monitoring process.
128
+ """
129
+ if self.process is not None:
130
+ self.process.terminate()
131
+ self.process.join()
132
+
133
+
134
+ # === END OF SYSTEM RESOURCE MONITOR. ==================================================================================
135
+
136
+
137
+ SYSTEM_RESOURCES_MONITOR: Union[SystemResourceMonitor, None] = None
138
+
139
+
140
+ def start_system_resources_monitoring(
141
+ interval: float = 1,
142
+ get_cpu: bool = True,
143
+ get_memory: bool = True,
144
+ get_disk_io: bool = True,
145
+ get_disk_used_percent: bool = True,
146
+ print_kwargs: dict = None
147
+ ):
148
+ """
149
+ Start monitoring system resources.
150
+ :param interval: float, interval in seconds.
151
+ :param get_cpu: bool, get CPU usage.
152
+ :param get_memory: bool, get memory usage.
153
+ :param get_disk_io: bool, get TOTAL disk I/O utilization in bytes/s.
154
+ :param get_disk_used_percent: bool, get TOTAL disk used percentage.
155
+ :param print_kwargs: dict, print kwargs.
156
+ :return: SystemResourceMonitor
157
+ """
158
+
159
+ # if print_kwargs is None:
160
+ # print_kwargs = {}
161
+
162
+ global SYSTEM_RESOURCES_MONITOR
163
+
164
+ if not SYSTEM_RESOURCES_MONITOR:
165
+ SYSTEM_RESOURCES_MONITOR = SystemResourceMonitor(
166
+ interval=interval,
167
+ get_cpu=get_cpu,
168
+ get_memory=get_memory,
169
+ get_disk_io=get_disk_io,
170
+ get_disk_used_percent=get_disk_used_percent
171
+ )
172
+ SYSTEM_RESOURCES_MONITOR.start()
173
+ else:
174
+ print_api("System resources monitoring is already running.", color='yellow', **(print_kwargs or {}))
175
+
176
+
177
+ def stop_system_resources_monitoring():
178
+ """
179
+ Stop monitoring system resources.
180
+ :return: None
181
+ """
182
+ global SYSTEM_RESOURCES_MONITOR
183
+ if SYSTEM_RESOURCES_MONITOR is not None:
184
+ SYSTEM_RESOURCES_MONITOR.stop()
185
+
186
+
187
+ def get_system_resources_monitoring_instance() -> SystemResourceMonitor:
188
+ """
189
+ Get the system resources monitoring instance.
190
+ :return: SystemResourceMonitor
191
+ """
192
+ global SYSTEM_RESOURCES_MONITOR
193
+ return SYSTEM_RESOURCES_MONITOR
194
+
195
+
196
+ def get_system_resources_monitoring_result():
197
+ """
198
+ Get system resources monitoring result.
199
+
200
+ Usage Example:
201
+ system_resources.start_system_resources_monitoring()
202
+
203
+ while True:
204
+ time.sleep(1)
205
+ result = system_resources.get_system_resources_monitoring_result()
206
+
207
+ if result:
208
+ print(
209
+ f"{str(result['cpu_usage'])} | {str(result['memory_usage'])} | "
210
+ f"{str(result['disk_io_read'])} | {str(result['disk_io_write'])} | "
211
+ f"{str(result['disk_used_percent'])}"
212
+ )
213
+
214
+ :return: dict
215
+ """
216
+ global SYSTEM_RESOURCES_MONITOR
217
+ if SYSTEM_RESOURCES_MONITOR is not None:
218
+ return SYSTEM_RESOURCES_MONITOR.get_latest_results()
219
+ else:
220
+ return {}
@@ -1,15 +1,72 @@
1
- import psutil
1
+ import os
2
+ import shutil
3
+ import tempfile
2
4
  import time
5
+ import threading
3
6
 
4
7
  from .print_api import print_api
5
8
  from .wrappers.psutilw import cpus, memories, disks
6
9
 
7
10
 
8
- def check_system_resources(interval: float = 1):
9
- cpu_usage = cpus.get_cpu_usage(interval=interval)
10
- memory_usage = memories.get_memory_usage()
11
- disk_io_utilization = disks.get_disk_io_utilization(interval=interval)
12
- return cpu_usage, memory_usage, disk_io_utilization
11
+ def check_system_resources(
12
+ interval: float = 1,
13
+ get_cpu: bool = True,
14
+ get_memory: bool = True,
15
+ get_disk_io: bool = True,
16
+ get_disk_used_percent: bool = True
17
+ ):
18
+ """
19
+ Check system resources.
20
+ :param interval: float, interval in seconds.
21
+ :param get_cpu: bool, get CPU usage.
22
+ :param get_memory: bool, get memory usage.
23
+ :param get_disk_io: bool, get TOTAL disk I/O utilization in bytes/s.
24
+ :param get_disk_used_percent: bool, get TOTAL disk used percentage.
25
+ :return:
26
+ """
27
+
28
+ threads: list = []
29
+ result: dict = {
30
+ 'cpu_usage': None,
31
+ 'memory_usage': None,
32
+ 'disk_io_write': None,
33
+ 'disk_io_read': None,
34
+ 'disk_used_percent': None
35
+ }
36
+
37
+ def set_cpu_usage():
38
+ result['cpu_usage'] = cpus.get_cpu_usage(interval=interval)
39
+
40
+ def set_memory_usage():
41
+ result['memory_usage'] = memories.get_memory_usage()
42
+
43
+ def set_disk_io_utilization():
44
+ aggregated_disk_io_utilization = disks.get_disk_io_utilization(interval=interval)['aggregated']
45
+ result['disk_io_read'] = aggregated_disk_io_utilization['read_change_per_sec']
46
+ result['disk_io_write'] = aggregated_disk_io_utilization['write_change_per_sec']
47
+
48
+ def set_disk_used_percent():
49
+ result['disk_used_percent'] = disks.get_disk_usage()['total'].percent
50
+
51
+ # Create threads for each system resource check.
52
+ if get_cpu:
53
+ threads.append(threading.Thread(target=set_cpu_usage))
54
+ if get_memory:
55
+ threads.append(threading.Thread(target=set_memory_usage))
56
+ if get_disk_io:
57
+ threads.append(threading.Thread(target=set_disk_io_utilization))
58
+ if get_disk_used_percent:
59
+ threads.append(threading.Thread(target=set_disk_used_percent))
60
+
61
+ # Start threads.
62
+ for thread in threads:
63
+ thread.start()
64
+
65
+ # Wait for all threads to complete.
66
+ for thread in threads:
67
+ thread.join()
68
+
69
+ return result
13
70
 
14
71
 
15
72
  def wait_for_resource_availability(cpu_percent_max: int = 80, memory_percent_max: int = 80, wait_time: float = 5):
@@ -26,3 +83,71 @@ def wait_for_resource_availability(cpu_percent_max: int = 80, memory_percent_max
26
83
  break
27
84
  print_api(f"Waiting for resources to be available... CPU: {cpu}%, Memory: {memory}%", color='yellow')
28
85
  time.sleep(wait_time) # Wait for 'wait_time' seconds before checking again
86
+
87
+
88
+ def test_disk_speed(file_size_bytes, file_count, remove_file_after_each_copy: bool = True, target_directory=None):
89
+ """
90
+ Tests disk write and read speeds by generating files in a 'source' directory, copying them to a 'dest' directory
91
+ within the target directory, and optionally removing them after each copy. Now also returns the total execution time.
92
+
93
+ :param file_size_bytes: Size of each file in bytes.
94
+ :param file_count: Number of files to generate and copy.
95
+ :param remove_file_after_each_copy: Whether to remove the file after copying to target directory.
96
+ :param target_directory: Directory where files will be copied. Uses a temporary directory if None.
97
+ :return: Tuple of peak write speed, peak read speed, and total execution time in seconds.
98
+ """
99
+ if target_directory is None:
100
+ target_directory = tempfile.mkdtemp()
101
+ else:
102
+ os.makedirs(target_directory, exist_ok=True)
103
+
104
+ source_directory = os.path.join(target_directory, 'source')
105
+ dest_directory = os.path.join(target_directory, 'dest')
106
+ os.makedirs(source_directory, exist_ok=True)
107
+ os.makedirs(dest_directory, exist_ok=True)
108
+
109
+ write_speeds = []
110
+ read_speeds = []
111
+ created_files = [] # Keep track of all created files for cleanup
112
+
113
+ overall_start_time = time.time() # Start timing the entire operation
114
+
115
+ for i in range(file_count):
116
+ # Generate file in source directory
117
+ src_file_path = os.path.join(source_directory, f"tempfile_{i}")
118
+ with open(src_file_path, "wb") as file:
119
+ file.write(os.urandom(file_size_bytes))
120
+ created_files.append(src_file_path) # Add the file for cleanup
121
+
122
+ # Measure write speed
123
+ start_time = time.time()
124
+ shutil.copy(src_file_path, dest_directory)
125
+ end_time = time.time()
126
+ write_speeds.append(file_size_bytes / (end_time - start_time))
127
+
128
+ target_file_path = os.path.join(dest_directory, os.path.basename(src_file_path))
129
+
130
+ # Measure read speed
131
+ with open(target_file_path, "rb") as file:
132
+ start_time = time.time()
133
+ while file.read(1024 * 1024): # Read in chunks of 1 MB
134
+ pass
135
+ end_time = time.time()
136
+ read_speeds.append(file_size_bytes / (end_time - start_time))
137
+
138
+ if remove_file_after_each_copy:
139
+ os.remove(target_file_path)
140
+ os.remove(src_file_path)
141
+
142
+ overall_end_time = time.time()
143
+
144
+ # Calculate peak speeds in Bytes/s and total execution time
145
+ peak_write_speed = max(write_speeds)
146
+ peak_read_speed = max(read_speeds)
147
+ total_execution_time = overall_end_time - overall_start_time
148
+
149
+ # Cleanup. Remove all created files and directories.
150
+ shutil.rmtree(source_directory)
151
+ shutil.rmtree(dest_directory)
152
+
153
+ return peak_write_speed, peak_read_speed, total_execution_time
@@ -1,5 +1,12 @@
1
- import psutil
1
+ import os
2
2
  import time
3
+ import tempfile
4
+ import shutil
5
+ import threading
6
+
7
+ import psutil
8
+
9
+ from ... import system_resources
3
10
 
4
11
 
5
12
  def get_disk_io_utilization(
@@ -10,6 +17,9 @@ def get_disk_io_utilization(
10
17
  ) -> dict:
11
18
  """
12
19
  Get disk utilization based on disk I/O changes, allowing for both aggregated and separated values.
20
+ Windows: because 'psutil.disk_io_counters' before using this function, you may need to execute the following
21
+ command in the command prompt:
22
+ diskperf -y
13
23
 
14
24
  :param interval: Sampling interval in seconds to measure I/O changes.
15
25
  :param disk_list: List of disks to measure. If None, measure all disks. Affects only when separated is True.
@@ -41,7 +51,7 @@ def get_disk_io_utilization(
41
51
  'read_change_bytes': read_change,
42
52
  'write_change_bytes': write_change,
43
53
  'read_change_per_sec': read_change_per_sec,
44
- 'write_change_per_sec': write_change_per_sec
54
+ 'write_change_per_sec': write_change_per_sec,
45
55
  }
46
56
 
47
57
  if aggregated:
@@ -55,7 +65,184 @@ def get_disk_io_utilization(
55
65
  'read_change_bytes': total_read_change,
56
66
  'write_change_bytes': total_write_change,
57
67
  'read_change_per_sec': total_read_change_per_sec,
58
- 'write_change_per_sec': total_write_change_per_sec
68
+ 'write_change_per_sec': total_write_change_per_sec,
59
69
  }
60
70
 
61
71
  return io_change
72
+
73
+
74
+ def _get_disk_busy_time(
75
+ interval: float = 1,
76
+ disk_list: list = None,
77
+ aggregated: bool = True,
78
+ separated: bool = False
79
+ ) -> dict:
80
+ """
81
+ !!! For some reason on Windows it gets the count of files read or written and not the time in ms.
82
+
83
+ Get disk busy time, allowing for both aggregated and separated values.
84
+ Windows: because 'psutil.disk_io_counters' before using this function, you may need to execute the following
85
+ command in the command prompt:
86
+ diskperf -y
87
+
88
+ :param interval: Sampling interval in seconds to measure I/O changes.
89
+ :param disk_list: List of disks to measure. If None, measure all disks. Affects only when separated is True.
90
+ :param aggregated: Boolean indicating whether to return aggregated utilization.
91
+ :param separated: Boolean indicating whether to return separate utilizations for each disk.
92
+ :return: Disk utilization data.
93
+ """
94
+
95
+ io_start_aggregated = None
96
+ io_end_aggregated = None
97
+
98
+ io_start_separated = psutil.disk_io_counters(perdisk=True)
99
+ if aggregated:
100
+ io_start_aggregated = psutil.disk_io_counters(perdisk=False)
101
+ time.sleep(interval)
102
+ io_end_separated = psutil.disk_io_counters(perdisk=True)
103
+ if aggregated:
104
+ io_end_aggregated = psutil.disk_io_counters(perdisk=False)
105
+
106
+ busy_time = {}
107
+ if separated:
108
+ for disk in io_start_separated.keys():
109
+ if disk_list is None or disk in disk_list:
110
+ read_time = io_end_separated[disk].read_time - io_start_separated[disk].read_time
111
+ write_time = io_end_separated[disk].write_time - io_start_separated[disk].write_time
112
+ read_time_per_sec = read_time / interval
113
+ write_time_per_sec = write_time / interval
114
+ busy_time[disk] = {
115
+ 'read_time_ms': read_time,
116
+ 'write_time_ms': write_time,
117
+ 'read_time_per_sec': read_time_per_sec,
118
+ 'write_time_per_sec': write_time_per_sec,
119
+ 'busy_time': read_time + write_time,
120
+ 'busy_time_per_sec': read_time_per_sec + write_time_per_sec,
121
+ 'busy_time_percent': (read_time + write_time) / interval
122
+ }
123
+
124
+ if aggregated:
125
+ if not io_start_aggregated or not io_end_aggregated:
126
+ raise ValueError('Aggregated disk I/O counters are not available.')
127
+ # total_read_time = io_end_aggregated.read_time - io_start_aggregated.read_time
128
+ # total_write_time = io_end_aggregated.write_time - io_start_aggregated.write_time
129
+ total_read_time = io_end_aggregated.read_time
130
+ total_write_time = io_end_aggregated.write_time
131
+ total_read_time_per_sec = total_read_time / interval
132
+ total_write_time_per_sec = total_write_time / interval
133
+ busy_time['aggregated'] = {
134
+ 'read_time_ms': total_read_time,
135
+ 'write_time_ms': total_write_time,
136
+ 'read_time_per_sec': total_read_time_per_sec,
137
+ 'write_time_per_sec': total_write_time_per_sec,
138
+ 'busy_time': total_read_time + total_write_time,
139
+ 'busy_time_per_sec': total_read_time_per_sec + total_write_time_per_sec,
140
+ 'busy_time_percent': (total_read_time + total_write_time) / interval
141
+ }
142
+
143
+ return busy_time
144
+
145
+
146
+ def get_disk_usage(disk_list: list = None) -> dict:
147
+ """
148
+ Get the usage statistics of disks.
149
+
150
+ :param disk_list: List of disks to measure. If None, measure all disks.
151
+ :return:
152
+ """
153
+
154
+ disk_usage: dict = {}
155
+ for disk in psutil.disk_partitions():
156
+ if disk_list is None or disk.device in disk_list:
157
+ try:
158
+ disk_usage[disk.device] = psutil.disk_usage(disk.mountpoint)
159
+ except PermissionError as e:
160
+ disk_usage[disk.device] = str(e)
161
+
162
+ # Get total disk usage.
163
+ disk_usage['total'] = psutil.disk_usage('/')
164
+
165
+ return disk_usage
166
+
167
+
168
+ def test_disk_speed_with_monitoring(
169
+ file_size_bytes: int, file_count: int, remove_file_after_each_copy: bool = False, target_directory=None):
170
+ """
171
+ Generates files and performs write and read operations in the specified target directory,
172
+ while monitoring disk I/O speeds in a separate thread. Returns the maximum read and write rates,
173
+ and the total operation time.
174
+
175
+ :param file_size_bytes: Size of each file in bytes.
176
+ :param file_count: Number of files to generate and copy.
177
+ :param remove_file_after_each_copy: Whether to remove the file after copying to target directory.
178
+ :param target_directory: Directory where files will be copied. Uses a temporary directory if None.
179
+ :return: A tuple containing the maximum write speed, maximum read speed, and total operation time in seconds.
180
+ """
181
+ io_speeds = {'write_speed': [], 'read_speed': []}
182
+ stop_thread = False
183
+
184
+ def io_monitor():
185
+ """
186
+ Monitors disk I/O speed by checking psutil disk_io_counters every second and calculates the speed.
187
+ This function is intended to run in a separate thread.
188
+ """
189
+
190
+ while not stop_thread:
191
+ result = system_resources.check_system_resources(
192
+ interval=1, get_disk_io=True, get_cpu=False, get_memory=False, get_disk_used_percent=False)
193
+
194
+ io_speeds['write_speed'].append(result['disk_io_write'])
195
+ io_speeds['read_speed'].append(result['disk_io_read'])
196
+
197
+ # Start the I/O monitoring thread
198
+ monitor_thread = threading.Thread(target=io_monitor)
199
+ monitor_thread.start()
200
+
201
+ if target_directory is None:
202
+ target_directory = tempfile.mkdtemp()
203
+ else:
204
+ os.makedirs(target_directory, exist_ok=True)
205
+
206
+ source_directory = os.path.join(target_directory, 'source')
207
+ dest_directory = os.path.join(target_directory, 'dest')
208
+ os.makedirs(source_directory, exist_ok=True)
209
+ os.makedirs(dest_directory, exist_ok=True)
210
+
211
+ write_speeds = []
212
+ read_speeds = []
213
+ created_files = [] # Keep track of all created files for cleanup
214
+
215
+ overall_start_time = time.time() # Start timing the entire operation
216
+
217
+ for i in range(file_count):
218
+ # Generate file in source directory
219
+ src_file_path = os.path.join(source_directory, f"tempfile_{i}")
220
+ with open(src_file_path, "wb") as file:
221
+ file.write(os.urandom(file_size_bytes))
222
+ created_files.append(src_file_path) # Add the file for cleanup
223
+
224
+ shutil.copy(src_file_path, dest_directory)
225
+ target_file_path = os.path.join(dest_directory, os.path.basename(src_file_path))
226
+
227
+ # Measure read speed
228
+ with open(target_file_path, "rb") as file:
229
+ start_time = time.time()
230
+ while file.read(1024 * 1024): # Read in chunks of 1 MB
231
+ pass
232
+ end_time = time.time()
233
+ read_speeds.append(file_size_bytes / (end_time - start_time))
234
+
235
+ if remove_file_after_each_copy:
236
+ os.remove(target_file_path)
237
+ os.remove(src_file_path)
238
+
239
+ overall_end_time = time.time()
240
+
241
+ stop_thread = True
242
+ monitor_thread.join()
243
+
244
+ # Determine maximum speeds
245
+ max_write_speed = max(io_speeds['write_speed']) if io_speeds['write_speed'] else 0
246
+ max_read_speed = max(io_speeds['read_speed']) if io_speeds['read_speed'] else 0
247
+
248
+ return max_write_speed, max_read_speed, total_operation_time
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: atomicshop
3
- Version: 2.8.1
3
+ Version: 2.9.0
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=e17yj2a8aF04r4QwWIjR6oIlVKG41Ua6ur7Uz7hUyic,122
1
+ atomicshop/__init__.py,sha256=IbBAx01GvuncS_hxpSRIAExpJW75V-EhMbbVnwzyzVo,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
@@ -22,7 +22,7 @@ atomicshop/ip_addresses.py,sha256=Hvi4TumEFoTEpKWaq5WNF-YzcRzt24IxmNgv-Mgax1s,11
22
22
  atomicshop/keyboard_press.py,sha256=1W5kRtOB75fulVx-uF2yarBhW0_IzdI1k73AnvXstk0,452
23
23
  atomicshop/pbtkmultifile_argparse.py,sha256=aEk8nhvoQVu-xyfZosK3ma17CwIgOjzO1erXXdjwtS4,4574
24
24
  atomicshop/permissions.py,sha256=GYWxm9niuJWY0pWCnASF34_HiTuvhTamn8BCgcFyVAk,2540
25
- atomicshop/print_api.py,sha256=3n1CoiXvDcDGg00n5gEmQYInHryIhWbcpNjVobO1Gao,11468
25
+ atomicshop/print_api.py,sha256=DhbCQd0MWZZ5GYEk4oTu1opRFC-b31g1VWZgTGewG2Y,11568
26
26
  atomicshop/process.py,sha256=5lqepm1psRbz66J4MB43ou6HHyac9F34QJedGukwAnk,14188
27
27
  atomicshop/process_name_cmd.py,sha256=TNAK6kQZm5JKWzEW6QLqVHEG98ZLNDQiSS4YwDk8V8c,3830
28
28
  atomicshop/process_poller.py,sha256=WfmwCLALfTYOq8ri0vkPeqq8ruEyA_43DaN--CU2_XY,10854
@@ -36,7 +36,8 @@ 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_resources.py,sha256=08hWyHNvwEsW0sGn12bKCDgafMk2Cn7MSDqUCKmcVwg,1207
39
+ atomicshop/system_resource_monitor.py,sha256=SF376RE952sYbZJxVqHt32Bek0zMFxBVDocbUfon6-E,7538
40
+ atomicshop/system_resources.py,sha256=y5SjM87k3h4mffvBHn6P4DqNiMmLjtdgUb6gkZU_p0U,5882
40
41
  atomicshop/tempfiles.py,sha256=uq1ve2WlWehZ3NOTXJnpBBMt6HyCdBufqedF0HyzA6k,2517
41
42
  atomicshop/timer.py,sha256=KxBBgVM8po6pUJDW8TgY1UXj0iiDmRmL5XDCq0VHAfU,1670
42
43
  atomicshop/urls.py,sha256=CQl1j1kjEVDlAuYJqYD9XxPF1SUSgrmG8PjlcXNEKsQ,597
@@ -204,7 +205,7 @@ atomicshop/wrappers/playwrightw/mouse.py,sha256=-2FZbQtjgH7tdXWld6ZPGqlKFUdf5in0
204
205
  atomicshop/wrappers/playwrightw/scenarios.py,sha256=Wz7aVYfG7K4fuSe_TUAc1jhFXVq5jYvZKbDtvqUiONc,5236
205
206
  atomicshop/wrappers/playwrightw/waits.py,sha256=308fdOu6YDqQ7K7xywj7R27sSmFanPBQqpZyBC-NFmo,7015
206
207
  atomicshop/wrappers/psutilw/cpus.py,sha256=w6LPBMINqS-T_X8vzdYkLS2Wzuve28Ydp_GafTCngrc,236
207
- atomicshop/wrappers/psutilw/disks.py,sha256=YAF6KvcFHOi48sSqlHg2Wt75rYOjbH3a082RqXT9Fic,2702
208
+ atomicshop/wrappers/psutilw/disks.py,sha256=AfeQIi-ugZIzAd7dmkMwFku1rb6Yl0Uzt8dFYvJMRnI,10490
208
209
  atomicshop/wrappers/psutilw/memories.py,sha256=wpdKEkQ9Wty_r7ZJKkfli7wIHMXdQOMlmDlzmc_0FWo,161
209
210
  atomicshop/wrappers/psutilw/psutilw.py,sha256=W9PSEZmrm_Ct_-6oKqAcbgbyF21CwcIbbHOkVqgMiow,20866
210
211
  atomicshop/wrappers/psycopgw/psycopgw.py,sha256=XJvVf0oAUjCHkrYfKeFuGCpfn0Oxj3u4SbKMKA1508E,7118
@@ -225,8 +226,8 @@ atomicshop/wrappers/socketw/socket_server_tester.py,sha256=AhpurHJmP2kgzHaUbq5ey
225
226
  atomicshop/wrappers/socketw/socket_wrapper.py,sha256=aXBwlEIJhFT0-c4i8iNlFx2It9VpCEpsv--5Oqcpxao,11624
226
227
  atomicshop/wrappers/socketw/ssl_base.py,sha256=k4V3gwkbq10MvOH4btU4onLX2GNOsSfUAdcHmL1rpVE,2274
227
228
  atomicshop/wrappers/socketw/statistics_csv.py,sha256=t3dtDEfN47CfYVi0CW6Kc2QHTEeZVyYhc57IYYh5nmA,826
228
- atomicshop-2.8.1.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
229
- atomicshop-2.8.1.dist-info/METADATA,sha256=fqt0fOE-tw0JyjUMhV9U20oK-xJ_0reGgyBeh8Jl_88,10369
230
- atomicshop-2.8.1.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
231
- atomicshop-2.8.1.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
232
- atomicshop-2.8.1.dist-info/RECORD,,
229
+ atomicshop-2.9.0.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
230
+ atomicshop-2.9.0.dist-info/METADATA,sha256=6vLhMQYgyIHS0NE4S8s-m8cpEaK4gm-8chZ9LnUpZgk,10369
231
+ atomicshop-2.9.0.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
232
+ atomicshop-2.9.0.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
233
+ atomicshop-2.9.0.dist-info/RECORD,,