-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Expand file tree
/
Copy pathDemo_psutil_Kill_Python_Processes.py
More file actions
219 lines (188 loc) · 10.5 KB
/
Copy pathDemo_psutil_Kill_Python_Processes.py
File metadata and controls
219 lines (188 loc) · 10.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
#!/usr/bin/env python
import PySimpleGUI as sg
import os
import signal
import psutil
import operator
import sys
CONFIRM_KILLS = False
"""
Task killer program focused on Python only programs
While there is another demo program that handles all running processes, this specific
demo is for Python oriented processes only. It is based on the original, more general
purpose task killer demo.
In addition to filtering out all but Python programs, it also displays the command line used
to launch the program. This is particularly good for programs that have no titlebar or
are running in the background or system tray.
Copyright 2018-2026 PySimpleGUI. All rights reserved.
"""
def kill_proc_tree(pid, sig=signal.SIGTERM, include_parent=True,
timeout=None, on_terminate=None):
"""Kill a process tree (including grandchildren) with signal
"sig" and return a (gone, still_alive) tuple.
"on_terminate", if specified, is a callabck function which is
called as soon as a child terminates.
"""
if pid == os.getpid():
raise RuntimeError("I refuse to kill myself")
parent = psutil.Process(pid)
children = parent.children(recursive=True)
if include_parent:
children.append(parent)
for p in children:
p.send_signal(sig)
gone, alive = psutil.wait_procs(children, timeout=timeout,
callback=on_terminate)
return (gone, alive)
def kill_proc(pid, sig=signal.SIGTERM, include_parent=True,
timeout=None, on_terminate=None):
"""Kill a process tree (including grandchildren) with signal
"sig" and return a (gone, still_alive) tuple.
"on_terminate", if specified, is a callabck function which is
called as soon as a child terminates.
"""
if pid == os.getpid():
raise RuntimeError("I refuse to kill myself")
parent = psutil.Process(pid)
parent.send_signal(sig)
def get_all_procs():
psutil.cpu_percent(interval=.1)
procs = psutil.process_iter()
all_procs = []
for proc in procs:
try:
all_procs.append([proc.cpu_percent(), proc.name(), proc.pid, proc.cmdline()])
except: pass
disp_data = []
for process in all_procs:
try:
name = process[3][1]
except:
name = ''
disp_data.append([process[2], process[0]/10, process[1], name])
return disp_data
def show_list_by_name(python_only=False):
disp_data = get_all_procs()
disp_data = sorted(disp_data, key=operator.itemgetter(3), reverse=False)
display_list = []
for process in disp_data:
if not python_only or (python_only and 'python' in process[2].lower()):
display_list.append('{:5d} {:5.2f} {} {}\n'.format(process[0], process[1], process[2], process[3]))
return display_list
def show_list_by_cpu(python_only=False):
disp_data = get_all_procs()
disp_data = sorted(disp_data, key=operator.itemgetter(1), reverse=True)
display_list = []
for process in disp_data:
if not python_only or (python_only and 'python' in process[2].lower()):
display_list.append('{:5d} {:5.2f} {} {}\n'.format(process[0], process[1], process[2], process[3]))
return display_list
def make_window():
layout = [[sg.Text('Python Process Killer - Choose one or more processes',
size=(45, 1), font=('Helvetica', 15), text_color='yellow')],
[sg.Listbox(values=[' '], size=(130, 30), select_mode=sg.SELECT_MODE_EXTENDED, font=('Courier', 10), key='-PROCESSES-', expand_x=True, expand_y=True)],
[sg.Text('Click refresh once or twice.. once for list, second to get CPU usage')],
[sg.Text('Filter by typing name', font='ANY 14'), sg.Input(size=(15, 1), font='any 14', key='-FILTER-', enable_events=True),
sg.Checkbox('Show only Python processes', default=True, enable_events=True, key='-PYTHON ONLY-')],
[sg.Button('Sort by Name', ),
sg.Button('Sort by % CPU', button_color=('white', 'DarkOrange2')),
sg.Button('Show Open Files', button_color=('white', 'dark green')),
sg.Button('Kill Selected', button_color=('white', 'red'), bind_return_key=True),
sg.Button('Kill All', button_color='red on white'),
sg.Button('Kill All & Exit', button_color='red on white'),
sg.Exit(button_color=('white', 'sea green')), sg.Sizegrip()]]
window = sg.Window('Python Process Killer', layout,
keep_on_top=True,
auto_size_buttons=False,
default_button_element_size=(12, 1),
return_keyboard_events=True,
resizable=True,
right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_EXIT,
finalize=True)
window.bind('<Delete>', 'Kill Selected')
window.set_min_size(window.size)
return window
def kill_all(python_only=True):
processes_to_kill = show_list_by_name(python_only=python_only)
for proc in processes_to_kill:
pid = int(proc[0:5])
try:
kill_proc(pid=pid)
# kill_proc_tree(pid=pid)
except Exception as e:
pass
def main(silent=False):
if silent:
kill_all(python_only=True)
sg.popup_auto_close('Killed everything....', 'This window autocloses')
sys.exit()
# ---------------- Create Form ----------------
sg.theme('Dark Grey 9')
sg.set_options(icon=icon)
window = make_window()
current_display_list = display_list = show_list_by_name(window['-PYTHON ONLY-'].get())
window['-PROCESSES-'].update(display_list)
name_sorted = True
# ---------------- main loop ----------------
while True:
# --------- Read and update window --------
event, values = window.read()
if event in (sg.WIN_CLOSED, 'Exit'):
break
# skip mouse, control key and shift key events entirely
if 'Mouse' in event or 'Control' in event or 'Shift' in event:
continue
# --------- Do Button Operations --------
if event == 'Sort by Name':
window['-PROCESSES-'].update(show_list_by_name(values['-PYTHON ONLY-']))
name_sorted = True
elif event.startswith('Kill'):
if event.startswith('Kill All'):
processes_to_kill = show_list_by_name(values['-PYTHON ONLY-'])
else:
processes_to_kill = values['-PROCESSES-']
for proc in processes_to_kill:
pid = int(proc[0:5])
try:
kill_proc(pid=pid)
# kill_proc_tree(pid=pid)
except Exception as e:
if event.endswith('Selected'): # only show the error if trying to kill only 1 process
sg.popup_no_wait('Error killing process', e, auto_close_duration=2, auto_close=True, keep_on_top=True)
current_display_list = show_list_by_name(values['-PYTHON ONLY-']) if name_sorted else show_list_by_cpu(values['-PYTHON ONLY-'])
window['-PROCESSES-'].update(current_display_list)
if event.endswith('Exit'):
break
elif event == 'Sort by % CPU':
window['-PROCESSES-'].update(show_list_by_cpu(values['-PYTHON ONLY-']))
name_sorted = False
elif event == 'Show Open Files':
for proc in values['-PROCESSES-']:
pid = int(proc[0:5])
parent = psutil.Process(pid)
file_list = parent.open_files()
out = ''
for f in file_list:
out += f'{f}\n'
sg.popup_scrolled(out, non_blocking=True, keep_on_top=True,size=(100,30))
elif event == '-PYTHON ONLY-': # if checkbox changed
current_display_list = show_list_by_name(values['-PYTHON ONLY-']) if name_sorted else show_list_by_cpu(values['-PYTHON ONLY-'])
window['-PROCESSES-'].update(current_display_list)
elif event == '-FILTER-': # was a typed character
# display_list = window['-PROCESSES-'].get_list_values()
display_list = current_display_list
if display_list is not None:
new_output = []
for line in display_list:
if values['-FILTER-'] in line.lower():
new_output.append(line)
window['-PROCESSES-'].update(new_output)
elif event == 'Edit Me':
sg.execute_editor(__file__)
window.close()
if __name__ == "__main__":
icon = b'iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAFLklEQVR4nO2ZW2xURRjHfzNnz9meXnYplHKtIhKEAgoEabUgKARBQTQ8+mLi5dXERIJPhMREownhyQfii8+aKKCCRIPRQiGEi3IRuSXc5dbSbbvdc5vxYUvAsmfP6bKtmuwvOS87s9/3/We++WbOHKhQoUKFChVKR4Q1fP3T3k1Jy5rluu5IxhOKZVk4rnvitWVtGwu1J4r8d0WyqqpVyFCtI4plJXFcdxIwVCHacZwcrutiGgkMwwCthynMEIQgCAK8wEdrDWgnrGuxGcl3MAz2nDzM2WuXQBpljTMSFTBtQhNLm+dFdo0WIg32nztJ+5H9YJoxnOv8yhNlSEnPY9G8VpbPXoCKijOOPdNIgGlFC9EaWVuNdj2065VBjMj7joF8SE/30BohJaPfWEl1SzP4QdlMx6F8QrwAu2Um1S3NpFa1IOvrQEUlRPkoj5BAYTSkSa9dBFpjNjVSt3wBBP83IVqTerkVs6kR/1Y32vWoXTYf89HxI5ZiDy/ED0g2T6H2hfmo3iy3t+6g/+hZEmPSpNY8C4aEEdh+4pUEpfIjKwbp1hphJxm17jlkrU33tnaco2fQjkvVrClUL5xJtuME/Yf+BLOAq0AV32T9IPY6ixaiNUZDmsRjExCJQd0Dhf30DJLNU3AvXKfn+wNgmbhnr9C75wjptYtJvdJG7tRFtOP+sxwrTWJcPcJOhorRvo9RX5dvjyjlkUK06zNq3VIaGtqwVAFjIi8os2Mvwa07YJkQKHp+OIg9fzrJJ5qoXfIUPd/tB2vAnR+QmNhA44bXSTSkQlPPRVF7zkVnfEgW38OiZ0QIgkwfvt+L1AWEGAbOmUtk9528lz6GJLjZRebbDsa8vZq6lS1kD58muHEnv2akIL22DbNxFH5nBt3vFjyH+1qheo1YG2ukEGEluPPlz9w+dhASBUZFgA5UPpfvd2gmyHYcp6a1GXv+dFKrWun6Yhe4PvbCGdS0ziLI9HFry1e456+CUeAc53v0zFmAeGlqZL2IV7UChfZ8tF/g8fyB89WgURMCnfPo3taO6slSu/hJrOlNiJok6VcXI+wkPT8ewjl1Ea11cdsxiCfk7iEw9An5nylxTl2k95ffkHU2qdXPkFrThvX4JJzzV+nZfRASRnHbMYlXfktGAJqeXQew507LP3Omol2PzPZ2VGcmXxzKQPnOWmEYEv9aJ5mdBxBCICyT/sOnyR74o/DeUiLDLwTANOj79XdyZy6j+vrp/qY9vxmW451lgGFOrQGEQGdzZLbvw5rcgHfhr/zaKCMjIwTATJA7do7c8fNlFwExhfhBAJ5X5PIoJnePInFTyvPyvmMQKcT1fdYtXMLzM+bCSF8NKc3oVBrX90lEFIZIIUorpjVOQo5vKlt8Q0Epha+iZyVeaqkAYhj7NwkXIrBtuxpZ6AwUhdZ4IVetpmWVVHaTVhLHdeyw9mIzsrk/29fk+N6Qneb6c2Nvdna/jxgUsdZ67Oj0p1V21c2h2lS+D3AprH1YVu9b6z+eXD+u/mIhIV3Xux75/JMNl8vtc1j2kXGNdSKQ8sEU0ppxjXXDMnglG/1gy2ezlTJbpSFNNei9WgjRiNYbC80IQmzSWt+4/2cpJSpQnonu+PC9d06UEk9JQtZv3jpLCHYnq+yJd0+4g+MtttgH67trw8nlrkgpV3z07psnhxpTSaklpFhRU5ua6DoOhFwvJ0LuibXWA58IHrBKTV1qUl9v5kVgZIRIoS/5nrvT90I/V5SElAIpdGhlqlChQoUK/zn+BhjXF7IsC7cbAAAAAElFTkSuQmCC'
if len(sys.argv) == 2 and sys.argv[1] == 'silent':
main(silent=True)
else:
main(silent=False)