atomicshop 2.15.11__py3-none-any.whl → 3.10.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.
- atomicshop/__init__.py +1 -1
- atomicshop/{addons/mains → a_mains}/FACT/update_extract.py +3 -2
- atomicshop/a_mains/dns_gateway_setting.py +11 -0
- atomicshop/a_mains/get_local_tcp_ports.py +85 -0
- atomicshop/a_mains/github_wrapper.py +11 -0
- atomicshop/a_mains/install_ca_certificate.py +172 -0
- atomicshop/a_mains/process_from_port.py +119 -0
- atomicshop/a_mains/set_default_dns_gateway.py +90 -0
- atomicshop/a_mains/update_config_toml.py +38 -0
- atomicshop/basics/ansi_escape_codes.py +3 -1
- atomicshop/basics/argparse_template.py +2 -0
- atomicshop/basics/booleans.py +27 -30
- atomicshop/basics/bytes_arrays.py +43 -0
- atomicshop/basics/classes.py +149 -1
- atomicshop/basics/enums.py +2 -2
- atomicshop/basics/exceptions.py +5 -1
- atomicshop/basics/list_of_classes.py +29 -0
- atomicshop/basics/multiprocesses.py +374 -50
- atomicshop/basics/strings.py +72 -3
- atomicshop/basics/threads.py +14 -0
- atomicshop/basics/tracebacks.py +13 -3
- atomicshop/certificates.py +153 -52
- atomicshop/config_init.py +11 -6
- atomicshop/console_user_response.py +7 -14
- atomicshop/consoles.py +9 -0
- atomicshop/datetimes.py +1 -1
- atomicshop/diff_check.py +3 -3
- atomicshop/dns.py +128 -3
- atomicshop/etws/_pywintrace_fix.py +17 -0
- atomicshop/etws/trace.py +40 -42
- atomicshop/etws/traces/trace_dns.py +56 -44
- atomicshop/etws/traces/trace_tcp.py +130 -0
- atomicshop/file_io/csvs.py +27 -5
- atomicshop/file_io/docxs.py +34 -17
- atomicshop/file_io/file_io.py +31 -17
- atomicshop/file_io/jsons.py +49 -0
- atomicshop/file_io/tomls.py +139 -0
- atomicshop/filesystem.py +616 -291
- atomicshop/get_process_list.py +3 -3
- atomicshop/http_parse.py +149 -93
- atomicshop/ip_addresses.py +6 -1
- atomicshop/mitm/centered_settings.py +132 -0
- atomicshop/mitm/config_static.py +207 -0
- atomicshop/mitm/config_toml_editor.py +55 -0
- atomicshop/mitm/connection_thread_worker.py +875 -357
- atomicshop/mitm/engines/__parent/parser___parent.py +4 -17
- atomicshop/mitm/engines/__parent/recorder___parent.py +108 -51
- atomicshop/mitm/engines/__parent/requester___parent.py +116 -0
- atomicshop/mitm/engines/__parent/responder___parent.py +75 -114
- atomicshop/mitm/engines/__reference_general/parser___reference_general.py +10 -7
- atomicshop/mitm/engines/__reference_general/recorder___reference_general.py +5 -5
- atomicshop/mitm/engines/__reference_general/requester___reference_general.py +47 -0
- atomicshop/mitm/engines/__reference_general/responder___reference_general.py +95 -13
- atomicshop/mitm/engines/create_module_template.py +58 -14
- atomicshop/mitm/import_config.py +359 -139
- atomicshop/mitm/initialize_engines.py +160 -80
- atomicshop/mitm/message.py +64 -23
- atomicshop/mitm/mitm_main.py +892 -0
- atomicshop/mitm/recs_files.py +183 -0
- atomicshop/mitm/shared_functions.py +4 -10
- atomicshop/mitm/ssh_tester.py +82 -0
- atomicshop/mitm/statistic_analyzer.py +136 -40
- atomicshop/mitm/statistic_analyzer_helper/moving_average_helper.py +265 -83
- atomicshop/monitor/checks/dns.py +1 -1
- atomicshop/networks.py +671 -0
- atomicshop/on_exit.py +39 -9
- atomicshop/package_mains_processor.py +84 -0
- atomicshop/permissions/permissions.py +22 -0
- atomicshop/permissions/ubuntu_permissions.py +239 -0
- atomicshop/permissions/win_permissions.py +33 -0
- atomicshop/print_api.py +24 -42
- atomicshop/process.py +24 -6
- atomicshop/process_poller/process_pool.py +0 -1
- atomicshop/process_poller/simple_process_pool.py +204 -5
- atomicshop/python_file_patcher.py +1 -1
- atomicshop/python_functions.py +27 -75
- atomicshop/speech_recognize.py +8 -0
- atomicshop/ssh_remote.py +158 -172
- atomicshop/system_resource_monitor.py +61 -47
- atomicshop/system_resources.py +8 -8
- atomicshop/tempfiles.py +1 -2
- atomicshop/urls.py +6 -0
- atomicshop/venvs.py +28 -0
- atomicshop/versioning.py +27 -0
- atomicshop/web.py +98 -27
- atomicshop/web_apis/google_custom_search.py +44 -0
- atomicshop/web_apis/google_llm.py +188 -0
- atomicshop/websocket_parse.py +450 -0
- atomicshop/wrappers/certauthw/certauth.py +1 -0
- atomicshop/wrappers/cryptographyw.py +29 -8
- atomicshop/wrappers/ctyping/etw_winapi/const.py +97 -47
- atomicshop/wrappers/ctyping/etw_winapi/etw_functions.py +178 -49
- atomicshop/wrappers/ctyping/file_details_winapi.py +67 -0
- atomicshop/wrappers/ctyping/msi_windows_installer/cabs.py +2 -1
- atomicshop/wrappers/ctyping/msi_windows_installer/extract_msi_main.py +2 -2
- atomicshop/wrappers/ctyping/setup_device.py +466 -0
- atomicshop/wrappers/ctyping/win_console.py +39 -0
- atomicshop/wrappers/dockerw/dockerw.py +113 -2
- atomicshop/wrappers/elasticsearchw/config_basic.py +0 -12
- atomicshop/wrappers/elasticsearchw/elastic_infra.py +75 -0
- atomicshop/wrappers/elasticsearchw/elasticsearchw.py +2 -20
- atomicshop/wrappers/factw/get_file_data.py +12 -5
- atomicshop/wrappers/factw/install/install_after_restart.py +89 -5
- atomicshop/wrappers/factw/install/pre_install_and_install_before_restart.py +20 -14
- atomicshop/wrappers/githubw.py +537 -54
- atomicshop/wrappers/loggingw/consts.py +1 -1
- atomicshop/wrappers/loggingw/filters.py +23 -0
- atomicshop/wrappers/loggingw/formatters.py +12 -0
- atomicshop/wrappers/loggingw/handlers.py +214 -107
- atomicshop/wrappers/loggingw/loggers.py +19 -0
- atomicshop/wrappers/loggingw/loggingw.py +860 -22
- atomicshop/wrappers/loggingw/reading.py +134 -112
- atomicshop/wrappers/mongodbw/mongo_infra.py +31 -0
- atomicshop/wrappers/mongodbw/mongodbw.py +1324 -36
- atomicshop/wrappers/netshw.py +271 -0
- atomicshop/wrappers/playwrightw/engine.py +34 -19
- atomicshop/wrappers/playwrightw/infra.py +5 -0
- atomicshop/wrappers/playwrightw/javascript.py +7 -3
- atomicshop/wrappers/playwrightw/keyboard.py +14 -0
- atomicshop/wrappers/playwrightw/scenarios.py +172 -5
- atomicshop/wrappers/playwrightw/waits.py +9 -7
- atomicshop/wrappers/powershell_networking.py +80 -0
- atomicshop/wrappers/psutilw/processes.py +37 -1
- atomicshop/wrappers/psutilw/psutil_networks.py +85 -0
- atomicshop/wrappers/pyopensslw.py +9 -2
- atomicshop/wrappers/pywin32w/cert_store.py +116 -0
- atomicshop/wrappers/pywin32w/win_event_log/fetch.py +174 -0
- atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_create.py +3 -105
- atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_terminate.py +3 -57
- atomicshop/wrappers/pywin32w/wmis/msft_netipaddress.py +113 -0
- atomicshop/wrappers/pywin32w/wmis/win32_networkadapterconfiguration.py +259 -0
- atomicshop/wrappers/pywin32w/wmis/win32networkadapter.py +112 -0
- atomicshop/wrappers/pywin32w/wmis/wmi_helpers.py +236 -0
- atomicshop/wrappers/socketw/accepter.py +21 -7
- atomicshop/wrappers/socketw/certificator.py +216 -150
- atomicshop/wrappers/socketw/creator.py +190 -50
- atomicshop/wrappers/socketw/dns_server.py +491 -182
- atomicshop/wrappers/socketw/exception_wrapper.py +45 -52
- atomicshop/wrappers/socketw/process_getter.py +86 -0
- atomicshop/wrappers/socketw/receiver.py +144 -102
- atomicshop/wrappers/socketw/sender.py +65 -35
- atomicshop/wrappers/socketw/sni.py +334 -165
- atomicshop/wrappers/socketw/socket_base.py +134 -0
- atomicshop/wrappers/socketw/socket_client.py +137 -95
- atomicshop/wrappers/socketw/socket_server_tester.py +11 -7
- atomicshop/wrappers/socketw/socket_wrapper.py +717 -116
- atomicshop/wrappers/socketw/ssl_base.py +15 -14
- atomicshop/wrappers/socketw/statistics_csv.py +148 -17
- atomicshop/wrappers/sysmonw.py +1 -1
- atomicshop/wrappers/ubuntu_terminal.py +65 -26
- atomicshop/wrappers/win_auditw.py +189 -0
- atomicshop/wrappers/winregw/__init__.py +0 -0
- atomicshop/wrappers/winregw/winreg_installed_software.py +58 -0
- atomicshop/wrappers/winregw/winreg_network.py +232 -0
- {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info}/METADATA +31 -51
- atomicshop-3.10.5.dist-info/RECORD +306 -0
- {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info}/WHEEL +1 -1
- atomicshop/_basics_temp.py +0 -101
- atomicshop/a_installs/win/fibratus.py +0 -9
- atomicshop/a_installs/win/mongodb.py +0 -9
- atomicshop/a_installs/win/pycharm.py +0 -9
- atomicshop/addons/a_setup_scripts/install_psycopg2_ubuntu.sh +0 -3
- atomicshop/addons/a_setup_scripts/install_pywintrace_0.3.cmd +0 -2
- atomicshop/addons/mains/__pycache__/install_fibratus_windows.cpython-312.pyc +0 -0
- atomicshop/addons/mains/__pycache__/msi_unpacker.cpython-312.pyc +0 -0
- atomicshop/addons/mains/install_docker_rootless_ubuntu.py +0 -11
- atomicshop/addons/mains/install_docker_ubuntu_main_sudo.py +0 -11
- atomicshop/addons/mains/install_elastic_search_and_kibana_ubuntu.py +0 -10
- atomicshop/addons/mains/install_wsl_ubuntu_lts_admin.py +0 -9
- atomicshop/addons/package_setup/CreateWheel.cmd +0 -7
- atomicshop/addons/package_setup/Setup in Edit mode.cmd +0 -6
- atomicshop/addons/package_setup/Setup.cmd +0 -7
- atomicshop/archiver/_search_in_zip.py +0 -189
- atomicshop/archiver/archiver.py +0 -34
- atomicshop/archiver/search_in_archive.py +0 -250
- atomicshop/archiver/sevenz_app_w.py +0 -86
- atomicshop/archiver/sevenzs.py +0 -44
- atomicshop/archiver/zips.py +0 -293
- atomicshop/file_types.py +0 -24
- atomicshop/mitm/config_editor.py +0 -37
- atomicshop/mitm/engines/create_module_template_example.py +0 -13
- atomicshop/mitm/initialize_mitm_server.py +0 -268
- atomicshop/pbtkmultifile_argparse.py +0 -88
- atomicshop/permissions.py +0 -151
- atomicshop/script_as_string_processor.py +0 -38
- atomicshop/ssh_scripts/process_from_ipv4.py +0 -37
- atomicshop/ssh_scripts/process_from_port.py +0 -27
- atomicshop/wrappers/_process_wrapper_curl.py +0 -27
- atomicshop/wrappers/_process_wrapper_tar.py +0 -21
- atomicshop/wrappers/dockerw/install_docker.py +0 -209
- atomicshop/wrappers/elasticsearchw/infrastructure.py +0 -265
- atomicshop/wrappers/elasticsearchw/install_elastic.py +0 -232
- atomicshop/wrappers/ffmpegw.py +0 -125
- atomicshop/wrappers/fibratusw/install.py +0 -81
- atomicshop/wrappers/mongodbw/infrastructure.py +0 -53
- atomicshop/wrappers/mongodbw/install_mongodb.py +0 -190
- atomicshop/wrappers/msiw.py +0 -149
- atomicshop/wrappers/nodejsw/install_nodejs.py +0 -139
- atomicshop/wrappers/process_wrapper_pbtk.py +0 -16
- atomicshop/wrappers/psutilw/networks.py +0 -45
- atomicshop/wrappers/pycharmw.py +0 -81
- atomicshop/wrappers/socketw/base.py +0 -59
- atomicshop/wrappers/socketw/get_process.py +0 -107
- atomicshop/wrappers/wslw.py +0 -191
- atomicshop-2.15.11.dist-info/RECORD +0 -302
- /atomicshop/{addons/mains → a_mains}/FACT/factw_fact_extractor_docker_image_main_sudo.py +0 -0
- /atomicshop/{addons → a_mains/addons}/PlayWrightCodegen.cmd +0 -0
- /atomicshop/{addons → a_mains/addons}/ScriptExecution.cmd +0 -0
- /atomicshop/{addons → a_mains/addons}/inits/init_to_import_all_modules.py +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/ReadMe.txt +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/compile.cmd +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.dll +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.exp +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.lib +0 -0
- /atomicshop/{addons → a_mains/addons}/process_list/process_list.cpp +0 -0
- /atomicshop/{archiver → permissions}/__init__.py +0 -0
- /atomicshop/{wrappers/fibratusw → web_apis}/__init__.py +0 -0
- /atomicshop/wrappers/{nodejsw → pywin32w/wmis}/__init__.py +0 -0
- /atomicshop/wrappers/pywin32w/{wmi_win32process.py → wmis/win32process.py} +0 -0
- {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info/licenses}/LICENSE.txt +0 -0
- {atomicshop-2.15.11.dist-info → atomicshop-3.10.5.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import threading
|
|
2
2
|
from pathlib import Path
|
|
3
3
|
import time
|
|
4
|
+
import multiprocessing.managers
|
|
5
|
+
import queue
|
|
6
|
+
|
|
4
7
|
|
|
5
8
|
from ..wrappers.pywin32w.win_event_log.subscribes import process_create, process_terminate
|
|
6
9
|
from .. import get_process_list
|
|
@@ -10,6 +13,13 @@ from ..print_api import print_api
|
|
|
10
13
|
WAIT_BEFORE_PROCESS_TERMINATION_CHECK_SECONDS: float = 3
|
|
11
14
|
WAIT_BEFORE_PROCESS_TERMINATION_CHECK_COUNTS: float = WAIT_BEFORE_PROCESS_TERMINATION_CHECK_SECONDS * 10
|
|
12
15
|
|
|
16
|
+
WAIT_FOR_PROCESS_POLLER_PID_SECONDS: int = 3
|
|
17
|
+
WAIT_FOR_PROCESS_POLLER_PID_COUNTS: int = WAIT_FOR_PROCESS_POLLER_PID_SECONDS * 10
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class PidProcessConverterPIDNotFoundError(Exception):
|
|
21
|
+
pass
|
|
22
|
+
|
|
13
23
|
|
|
14
24
|
class SimpleProcessPool:
|
|
15
25
|
"""
|
|
@@ -19,29 +29,99 @@ class SimpleProcessPool:
|
|
|
19
29
|
The idea is similar to the process_poller.process_pool.ProcessPool class, but this class is simpler and uses
|
|
20
30
|
only the pywin32 tracing of the Windows Event Log Process Creation and Process Termination events.
|
|
21
31
|
The simple process pool is used to get things simpler than the process_pool.ProcessPool class.
|
|
32
|
+
|
|
33
|
+
Example of starting the process pool in multiprocess:
|
|
34
|
+
import sys
|
|
35
|
+
|
|
36
|
+
from atomicshop.process_poller import simple_process_pool
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def start_process_pool(process_pool_shared_dict_proxy):
|
|
40
|
+
process_poller = simple_process_pool.SimpleProcessPool(
|
|
41
|
+
process_pool_shared_dict_proxy=process_pool_shared_dict_proxy)
|
|
42
|
+
process_poller.start()
|
|
43
|
+
|
|
44
|
+
try:
|
|
45
|
+
# Keep the process alive.
|
|
46
|
+
while True:
|
|
47
|
+
time.sleep(1)
|
|
48
|
+
except KeyboardInterrupt:
|
|
49
|
+
process_poller.stop()
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def main():
|
|
53
|
+
# Create the shared multiprocessing dictionary of the process pool.
|
|
54
|
+
manager = multiprocessing.Manager()
|
|
55
|
+
multiprocess_dict_proxy = manager.dict()
|
|
56
|
+
|
|
57
|
+
# Start the process pool in a separate process.
|
|
58
|
+
pool_process = multiprocessing.Process(target=start_process_pool, args=(multiprocess_dict_proxy,))
|
|
59
|
+
pool_process.start()
|
|
60
|
+
|
|
61
|
+
# Pass the shared dict proxy to other functions.
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
if __name__ == '__main__':
|
|
65
|
+
sys.exit(main())
|
|
22
66
|
"""
|
|
23
67
|
|
|
24
68
|
def __init__(
|
|
25
69
|
self,
|
|
26
|
-
wait_before_pid_remove_seconds: float = 5
|
|
70
|
+
wait_before_pid_remove_seconds: float = 5,
|
|
71
|
+
process_pool_shared_dict_proxy: multiprocessing.managers.DictProxy = None
|
|
27
72
|
):
|
|
28
73
|
"""
|
|
29
74
|
:param wait_before_pid_remove_seconds: float, how many seconds to wait before the process is removed from
|
|
30
75
|
the pool after process termination event is received for that pid.
|
|
76
|
+
:param process_pool_shared_dict_proxy: multiprocessing.managers.DictProxy, shared dict proxy to update
|
|
77
|
+
the process pool.
|
|
78
|
+
If you run a function from other multiprocessing.Process, you can pass the shared_dict_proxy to the function
|
|
79
|
+
and update the process pool from that function.
|
|
80
|
+
|
|
81
|
+
Example:
|
|
82
|
+
import multiprocessing.managers
|
|
83
|
+
|
|
84
|
+
manager: multiprocessing.managers.SyncManager = multiprocessing.Manager()
|
|
85
|
+
multiprocess_dict_proxy: multiprocessing.managers.DictProxy = manager.dict()
|
|
86
|
+
|
|
87
|
+
process_poller = SimpleProcessPool()
|
|
88
|
+
process_poller.start()
|
|
89
|
+
|
|
90
|
+
while True:
|
|
91
|
+
#============================
|
|
92
|
+
# your function where you get info with pid
|
|
93
|
+
# result = {
|
|
94
|
+
# 'pid': 1234,
|
|
95
|
+
# 'info': 'some info'
|
|
96
|
+
# }
|
|
97
|
+
#============================
|
|
98
|
+
info_with_process_details = {
|
|
99
|
+
'pid': result['pid'],
|
|
100
|
+
'info': result['info']
|
|
101
|
+
'process_details': shared_dict_proxy[result['pid']]
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
break
|
|
105
|
+
|
|
106
|
+
process_poller.stop()
|
|
107
|
+
manager.shutdown()
|
|
31
108
|
"""
|
|
32
109
|
|
|
33
110
|
self.wait_before_pid_remove_seconds: float = wait_before_pid_remove_seconds
|
|
111
|
+
self.process_pool_shared_dict_proxy: multiprocessing.managers.DictProxy = process_pool_shared_dict_proxy
|
|
34
112
|
|
|
35
113
|
self._processes: dict = dict()
|
|
36
114
|
self._running: bool = False
|
|
115
|
+
self.shared_dict_update_queue: queue.Queue = queue.Queue()
|
|
116
|
+
self.empty_cmdline_queue: queue.Queue = queue.Queue()
|
|
37
117
|
|
|
38
118
|
def start(self):
|
|
39
119
|
self._running = True
|
|
40
120
|
|
|
41
121
|
self._processes = get_process_list.GetProcessList(
|
|
42
|
-
get_method='
|
|
122
|
+
get_method='psutil', connect_on_init=True).get_processes(as_dict=True)
|
|
43
123
|
|
|
44
|
-
thread_get_queue = threading.Thread(target=self._start_main_thread)
|
|
124
|
+
thread_get_queue = threading.Thread(target=self._start_main_thread, args=(self.shared_dict_update_queue,))
|
|
45
125
|
thread_get_queue.daemon = True
|
|
46
126
|
thread_get_queue.start()
|
|
47
127
|
|
|
@@ -49,13 +129,21 @@ class SimpleProcessPool:
|
|
|
49
129
|
thread_process_termination.daemon = True
|
|
50
130
|
thread_process_termination.start()
|
|
51
131
|
|
|
132
|
+
thread_get_psutil_commandline = threading.Thread(target=self._thread_get_psutil_commandline)
|
|
133
|
+
thread_get_psutil_commandline.daemon = True
|
|
134
|
+
thread_get_psutil_commandline.start()
|
|
135
|
+
|
|
136
|
+
thread_update_shared_dict = threading.Thread(target=self._update_shared_dict, args=(self.shared_dict_update_queue,))
|
|
137
|
+
thread_update_shared_dict.daemon = True
|
|
138
|
+
thread_update_shared_dict.start()
|
|
139
|
+
|
|
52
140
|
def stop(self):
|
|
53
141
|
self._running = False
|
|
54
142
|
|
|
55
143
|
def get_processes(self):
|
|
56
144
|
return self._processes
|
|
57
145
|
|
|
58
|
-
def _start_main_thread(self):
|
|
146
|
+
def _start_main_thread(self, shared_dict_update_queue):
|
|
59
147
|
get_instance = process_create.ProcessCreateSubscriber()
|
|
60
148
|
get_instance.start()
|
|
61
149
|
|
|
@@ -65,12 +153,35 @@ class SimpleProcessPool:
|
|
|
65
153
|
process_name = Path(event['NewProcessName']).name
|
|
66
154
|
command_line = event['CommandLine']
|
|
67
155
|
|
|
156
|
+
# The event log tracing method doesn't always give the command line, unlike the psutil method.
|
|
157
|
+
# So, we'll get the command line from the current psutil snapshot separately.
|
|
158
|
+
if command_line == '':
|
|
159
|
+
self.empty_cmdline_queue.put(process_id)
|
|
160
|
+
|
|
68
161
|
self._processes[process_id] = {
|
|
69
162
|
'name': process_name,
|
|
70
163
|
'cmdline': command_line
|
|
71
164
|
}
|
|
72
165
|
|
|
73
|
-
#
|
|
166
|
+
# Update the multiprocessing shared dict proxy.
|
|
167
|
+
shared_dict_update_queue.put(dict(self._processes))
|
|
168
|
+
|
|
169
|
+
def _thread_get_psutil_commandline(self):
|
|
170
|
+
"""
|
|
171
|
+
This function will get an entry from the queue where command line is missing and get the command line
|
|
172
|
+
from the psutil snapshot.
|
|
173
|
+
"""
|
|
174
|
+
|
|
175
|
+
while self._running:
|
|
176
|
+
empty_cmd_pid = self.empty_cmdline_queue.get()
|
|
177
|
+
current_psutil_process_snapshot: dict = get_process_list.GetProcessList(
|
|
178
|
+
get_method='psutil', connect_on_init=True).get_processes(as_dict=True)
|
|
179
|
+
command_line = current_psutil_process_snapshot[empty_cmd_pid]['cmdline']
|
|
180
|
+
|
|
181
|
+
self._processes[empty_cmd_pid]['cmdline'] = command_line
|
|
182
|
+
|
|
183
|
+
# Update the multiprocessing shared dict proxy.
|
|
184
|
+
self.shared_dict_update_queue.put(dict(self._processes))
|
|
74
185
|
|
|
75
186
|
def _thread_process_termination(self):
|
|
76
187
|
process_terminate_instance = process_terminate.ProcessTerminateSubscriber()
|
|
@@ -110,3 +221,91 @@ class SimpleProcessPool:
|
|
|
110
221
|
time.sleep(self.wait_before_pid_remove_seconds)
|
|
111
222
|
_ = self._processes.pop(process_id, None)
|
|
112
223
|
# print_api(f'Process [{process_id}] removed from the pool.', color='yellow')
|
|
224
|
+
|
|
225
|
+
self.shared_dict_update_queue.put(dict(self._processes))
|
|
226
|
+
|
|
227
|
+
def _update_shared_dict(self, shared_dict_update_queue):
|
|
228
|
+
while self._running:
|
|
229
|
+
current_process_pool = shared_dict_update_queue.get()
|
|
230
|
+
if self.process_pool_shared_dict_proxy is not None:
|
|
231
|
+
self.process_pool_shared_dict_proxy.clear()
|
|
232
|
+
self.process_pool_shared_dict_proxy.update(current_process_pool)
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
class PidProcessConverter:
|
|
236
|
+
"""
|
|
237
|
+
This class is used to get the process details by PID from the process pool shared dict proxy.
|
|
238
|
+
"""
|
|
239
|
+
|
|
240
|
+
def __init__(
|
|
241
|
+
self,
|
|
242
|
+
process_pool_shared_dict_proxy: multiprocessing.managers.DictProxy
|
|
243
|
+
):
|
|
244
|
+
"""
|
|
245
|
+
:param process_pool_shared_dict_proxy: multiprocessing.managers.DictProxy, multiprocessing shared dict proxy.
|
|
246
|
+
"""
|
|
247
|
+
|
|
248
|
+
self.process_pool_shared_dict_proxy: multiprocessing.managers.DictProxy = process_pool_shared_dict_proxy
|
|
249
|
+
|
|
250
|
+
self.get_process_with_psutil = get_process_list.GetProcessList(get_method='psutil', connect_on_init=True)
|
|
251
|
+
|
|
252
|
+
def get_process_by_pid(self, pid: int):
|
|
253
|
+
"""
|
|
254
|
+
THIS FUNCTION WILL RUN OUTSIDE THE PROCESS POOL PROCESS. Inside the function that needs
|
|
255
|
+
the pid to process conversion.
|
|
256
|
+
Get the process details by PID from the process pool shared dict proxy.
|
|
257
|
+
|
|
258
|
+
:param pid: int, the process ID.
|
|
259
|
+
:return: dict, the process details.
|
|
260
|
+
"""
|
|
261
|
+
|
|
262
|
+
counter = 0
|
|
263
|
+
process_dict: dict = dict()
|
|
264
|
+
while counter < WAIT_FOR_PROCESS_POLLER_PID_COUNTS:
|
|
265
|
+
# We need it so that the pool will not change in the middle of the process.
|
|
266
|
+
current_pid_pool = convert_proxy_dict_to_dict(self.process_pool_shared_dict_proxy)
|
|
267
|
+
if pid not in current_pid_pool:
|
|
268
|
+
# print(dict(self.process_pool_shared_dict_proxy))
|
|
269
|
+
time.sleep(0.1)
|
|
270
|
+
counter += 1
|
|
271
|
+
else:
|
|
272
|
+
process_dict = current_pid_pool[pid]
|
|
273
|
+
break
|
|
274
|
+
|
|
275
|
+
if not process_dict:
|
|
276
|
+
print_api(f"Error: The PID [{pid}] is not in the pool, trying psutil snapshot.", color='yellow')
|
|
277
|
+
# Last resort, try to get the process name by current process snapshot.
|
|
278
|
+
processes = self.get_process_with_psutil.get_processes(as_dict=True)
|
|
279
|
+
if pid not in processes:
|
|
280
|
+
print_api(f"Error: Couldn't get the process name for PID: {pid}.", color='red')
|
|
281
|
+
process_dict = {
|
|
282
|
+
'name': pid,
|
|
283
|
+
'cmdline': ''
|
|
284
|
+
}
|
|
285
|
+
else:
|
|
286
|
+
process_dict = processes[pid]
|
|
287
|
+
|
|
288
|
+
return process_dict
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
def convert_proxy_dict_to_dict(proxy_dict: multiprocessing.managers.DictProxy) -> dict:
|
|
292
|
+
"""
|
|
293
|
+
Convert the multiprocessing shared dict proxy to a normal dict.
|
|
294
|
+
|
|
295
|
+
:param proxy_dict: multiprocessing.managers.DictProxy, the shared dict proxy.
|
|
296
|
+
:return: dict, the normal dict.
|
|
297
|
+
"""
|
|
298
|
+
|
|
299
|
+
# Create a snapshot of the keys
|
|
300
|
+
keys = list(proxy_dict.keys())
|
|
301
|
+
current_pid_pool = {}
|
|
302
|
+
|
|
303
|
+
for key in keys:
|
|
304
|
+
try:
|
|
305
|
+
# Attempt to retrieve the value for each key
|
|
306
|
+
current_pid_pool[key] = proxy_dict[key]
|
|
307
|
+
except KeyError:
|
|
308
|
+
# The key was removed concurrently; skip it
|
|
309
|
+
continue
|
|
310
|
+
|
|
311
|
+
return current_pid_pool
|
|
@@ -113,4 +113,4 @@ def find_and_replace_in_file(
|
|
|
113
113
|
for index in found_string_indexes:
|
|
114
114
|
file_data[index] = file_data[index].replace(single_find.find_what, single_find.replace_to)
|
|
115
115
|
|
|
116
|
-
file_io.write_file(content=file_data, file_path=file_path, encoding=encoding
|
|
116
|
+
file_io.write_file(content=file_data, file_path=file_path, encoding=encoding)
|
atomicshop/python_functions.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import sys
|
|
2
|
+
from typing import Union
|
|
2
3
|
|
|
3
4
|
from .print_api import print_api
|
|
4
5
|
|
|
5
6
|
|
|
6
|
-
def
|
|
7
|
+
def get_python_version_string() -> str:
|
|
7
8
|
"""
|
|
8
9
|
Function gets version MAJOR.MINOR.MICRO from 'sys.version_info' object and returns it as a string.
|
|
9
10
|
:return: python MAJOR.MINOR.MICRO version string.
|
|
@@ -12,84 +13,35 @@ def get_current_python_version_string() -> str:
|
|
|
12
13
|
return f'{sys.version_info[0]}.{sys.version_info[1]}.{sys.version_info[2]}'
|
|
13
14
|
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
Function checks if 'version_object' that was passed is tuple or string.
|
|
20
|
-
If it's tuple then returns it back. If it's string, converts to tuple then returns it.
|
|
21
|
-
If the object is none of the above, returns None.
|
|
22
|
-
|
|
23
|
-
:param version_object: Can be string ('3.10') or tuple of integers ((3, 10)).
|
|
24
|
-
:return:
|
|
25
|
-
"""
|
|
26
|
-
# Check if tuple was passed.
|
|
27
|
-
if isinstance(version_object, tuple):
|
|
28
|
-
return version_object
|
|
29
|
-
else:
|
|
30
|
-
# Then check if a string was passed.
|
|
31
|
-
if isinstance(version_object, str):
|
|
32
|
-
# The check will be against tuple of integers, so we'll convert a string to tuple of integers.
|
|
33
|
-
return tuple(map(int, version_object.split('.')))
|
|
34
|
-
else:
|
|
35
|
-
message = f'[*] Function: [check_if_version_object_is_tuple_or_string]\n' \
|
|
36
|
-
f'[*] [version_object] object passed is not tuple or string.\n' \
|
|
37
|
-
f'[*] Object type: {type(version_object)}\n' \
|
|
38
|
-
f'[*] Object content {version_object}\n' \
|
|
39
|
-
f'Exiting...'
|
|
40
|
-
print_api(message, error_type=True, logger_method='critical', **kwargs)
|
|
41
|
-
|
|
42
|
-
return None
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
# noinspection PyUnusedLocal
|
|
46
|
-
def check_python_version_compliance(minimum_version: any,
|
|
47
|
-
maximum_version: any = None,
|
|
48
|
-
**kwargs) -> bool:
|
|
16
|
+
def check_python_version_compliance(
|
|
17
|
+
min_ver: tuple = None,
|
|
18
|
+
max_ver: tuple = None,
|
|
19
|
+
) -> str | None:
|
|
49
20
|
"""
|
|
50
21
|
Python version check. Should be executed before importing external libraries, since they depend on Python version.
|
|
51
22
|
|
|
52
|
-
:param
|
|
53
|
-
:param
|
|
23
|
+
:param min_ver: tuple of integers (3, 10).
|
|
24
|
+
:param max_ver: tuple of integers (3, 10).
|
|
54
25
|
If maximum version is not specified, it will be considered as all versions above the minimum are compliant.
|
|
55
|
-
:return:
|
|
26
|
+
:return: If version is not compliant, returns string with error message. Otherwise, returns None.
|
|
56
27
|
"""
|
|
57
28
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
f"{'.'.join(str(i) for i in minimum_version_scheme)}, " \
|
|
76
|
-
f"AND EARLIER THAN {'.'.join(str(i) for i in maximum_version_scheme)}, " \
|
|
77
|
-
f"to work properly. Unhandled exceptions are inevitable!"
|
|
78
|
-
print_api(message, error_type=True, logger_method='critical', **kwargs)
|
|
79
|
-
|
|
80
|
-
return False
|
|
81
|
-
# If 'maximum_version' wasn't passed.
|
|
29
|
+
if not min_ver and not max_ver:
|
|
30
|
+
raise ValueError("At least one of the version parameters should be passed.")
|
|
31
|
+
|
|
32
|
+
current_version_info: tuple = sys.version_info[:3]
|
|
33
|
+
if min_ver and not max_ver:
|
|
34
|
+
if current_version_info < min_ver:
|
|
35
|
+
return f'Python version {".".join(map(str, min_ver))} or higher is required. '\
|
|
36
|
+
f'Current version is {".".join(map(str, current_version_info))}.'
|
|
37
|
+
elif max_ver and not min_ver:
|
|
38
|
+
if current_version_info > max_ver:
|
|
39
|
+
return f'Python version up to {".".join(map(str, max_ver))} is required. '\
|
|
40
|
+
f'Current version is {".".join(map(str, current_version_info))}.'
|
|
41
|
+
elif min_ver and max_ver:
|
|
42
|
+
if not (min_ver <= current_version_info <= max_ver):
|
|
43
|
+
return f'Python version between {".".join(map(str, min_ver))} and '\
|
|
44
|
+
f'{".".join(map(str, max_ver))} is required. '\
|
|
45
|
+
f'Current version is {".".join(map(str, current_version_info))}.'
|
|
82
46
|
else:
|
|
83
|
-
|
|
84
|
-
if not sys.version_info >= minimum_version_scheme:
|
|
85
|
-
message = f"[!!!] YOU NEED TO INSTALL AT LEAST PYTHON " \
|
|
86
|
-
f"{'.'.join(str(i) for i in minimum_version_scheme)}, " \
|
|
87
|
-
f"to work properly. Unhandled exceptions are inevitable!"
|
|
88
|
-
print_api(message, error_type=True, logger_method='critical', **kwargs)
|
|
89
|
-
|
|
90
|
-
return False
|
|
91
|
-
|
|
92
|
-
message = "[*] Version Check PASSED."
|
|
93
|
-
print_api(message, logger_method='info', **kwargs)
|
|
94
|
-
|
|
95
|
-
return True
|
|
47
|
+
return None
|
atomicshop/speech_recognize.py
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
# TODO: Change manual wrapper to:
|
|
2
|
+
# from ffmpy import FFmpeg
|
|
3
|
+
# ff = FFmpeg(
|
|
4
|
+
# inputs={'input.mp4': None},
|
|
5
|
+
# outputs={'output.avi': None}
|
|
6
|
+
# )
|
|
7
|
+
# ff.run()
|
|
8
|
+
|
|
1
9
|
from .wrappers.ffmpegw import FFmpegWrapper
|
|
2
10
|
from .tempfiles import TempFile
|
|
3
11
|
from .web import download
|