Skip to content

Commit f09a024

Browse files
committed
Enhance SubProcessTool
大幅改动及增加`SubProcessTool`类的功能; 注:此部分改动尚未完成;
1 parent 0e3a20c commit f09a024

2 files changed

Lines changed: 114 additions & 35 deletions

File tree

src/py2exe_gui/Core/packaging.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def __init__(self, parent: Optional[QObject] = None):
2323
]
2424
self.args_dict: dict = dict.fromkeys(pyinstaller_args, "")
2525
self._args: List[str] = []
26-
self._subprocess: SubProcessTool = SubProcessTool(self)
26+
self._subprocess: SubProcessTool = SubProcessTool(self, program="pyinstaller")
2727

2828
def set_pyinstaller_args(self, arg: tuple[str, str]) -> None:
2929
"""
@@ -68,15 +68,16 @@ def run_packaging_process(self) -> None:
6868
"""
6969

7070
# self._subprocess.output.connect(lambda val: print(val)) # 测试用
71-
self._subprocess.start_process("pyinstaller", self._args)
71+
self._subprocess.set_arguments(self._args)
72+
self._subprocess.start_process()
7273

7374
def abort_process(self) -> int:
7475
"""
7576
紧急终止打包进程 \n
7677
:return: 子进程返回值
7778
"""
7879

79-
if self._subprocess.process:
80+
if self._subprocess._process:
8081
result = 0
8182

8283
def handel(output: tuple):
@@ -86,8 +87,8 @@ def handel(output: tuple):
8687
result = int(output[1])
8788

8889
self._subprocess.output.connect(handel)
89-
self._subprocess.process.terminate()
90-
self._subprocess.process.waitForFinished(10000)
90+
self._subprocess.abort_process()
91+
9192
return result
9293
else:
9394
return 0
Lines changed: 108 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,140 @@
1+
import os.path
12
from sys import getdefaultencoding
23
from typing import Optional, Sequence
34

45
from PySide6 import QtCore
56

67

78
class SubProcessTool(QtCore.QObject):
8-
"""辅助使用QProcess创建并管理子进程的工具类"""
9+
"""辅助QProcess使用的工具类,将所有直接对子进程进行的操作都封装在此类中"""
910

1011
# 自定义信号,参数为 tuple[output_type: SubProcessTool.output_type, output_text: str]
1112
output = QtCore.Signal(tuple)
1213

1314
# output_types
14-
STATE = 0
15-
FINISHED = 1
15+
STATE = 1
1616
STDOUT = 2
1717
STDERR = 3
18+
FINISHED = 4
19+
20+
def __init__(
21+
self,
22+
parent: Optional[QtCore.QObject] = None,
23+
*,
24+
program: str = "",
25+
arguments: Sequence[str] = (),
26+
working_directory: str = "./",
27+
) -> None:
28+
"""
29+
:param parent: 父对象
30+
:param program: 待运行的子进程
31+
:param arguments: 运行参数
32+
:param working_directory: 子进程工作目录
33+
:return: None
34+
"""
1835

19-
def __init__(self, parent: Optional[QtCore.QObject] = None) -> None:
2036
super(SubProcessTool, self).__init__(parent)
21-
self.process: Optional[QtCore.QProcess] = None
2237

23-
def start_process(self, program: str, arguments: Sequence[str]) -> None:
38+
self.program: str = program
39+
self._arguments: Sequence[str] = arguments
40+
self._working_directory: str = working_directory
41+
self._process: Optional[QtCore.QProcess] = None
42+
self.exit_code: int = 0
43+
self.exit_status: QtCore.QProcess.ExitStatus = QtCore.QProcess.NormalExit
44+
45+
def start_process(
46+
self,
47+
*,
48+
mode: QtCore.QIODeviceBase.OpenMode = QtCore.QIODeviceBase.OpenModeFlag.ReadWrite, # type: ignore
49+
) -> None:
50+
"""
51+
创建并启动子进程 \n
52+
:param mode: 设备打开的模式
53+
:return: None
54+
"""
55+
56+
if self._process is None: # 防止在子进程运行结束前重复启动
57+
self._process = QtCore.QProcess(self)
58+
59+
self._process.stateChanged.connect(self._handle_state) # type: ignore
60+
self._process.readyReadStandardOutput.connect(self._handle_stdout) # type: ignore
61+
self._process.readyReadStandardError.connect(self._handle_stderr) # type: ignore
62+
self._process.started.connect(self._process_started) # type: ignore
63+
self._process.finished.connect(self._process_finished) # type: ignore
64+
self._process.errorOccurred.connect(self._handle_error) # type: ignore
65+
66+
self._process.setWorkingDirectory(self._working_directory)
67+
self._process.start(self.program, self._arguments, mode)
68+
self._process.waitForStarted(1000) # 阻塞,直到启动了子进程或超时(单位为毫秒)
69+
70+
def abort_process(self, timeout: int = 10000) -> bool:
71+
"""
72+
终止子进程 \n
73+
:param timeout: 超时时间,单位为毫秒
74+
:return: 子进程是否完成
75+
"""
76+
77+
if self._process:
78+
self._process.terminate()
79+
finished = self._process.waitForFinished(timeout) # 阻塞,直到进程终止或超时
80+
if not finished:
81+
self._process.kill() # 超时后杀死子进程
82+
return finished
83+
else:
84+
return True
85+
86+
def set_arguments(self, arguments: Sequence[str]) -> None:
2487
"""
25-
使用给定参数启动指定子进程 \n
26-
:param program: 子进程命令
27-
:param arguments: 子进程参数
88+
设置子进程参数 \n
89+
:param arguments: 参数列表
2890
:return: None
2991
"""
3092

31-
if self.process is None: # 防止在子进程运行结束前重复启动
32-
self.process = QtCore.QProcess()
93+
self._arguments = arguments
3394

34-
self.process.stateChanged.connect(self._handle_state) # type: ignore
35-
self.process.readyReadStandardOutput.connect(self._handle_stdout) # type: ignore
36-
self.process.readyReadStandardError.connect(self._handle_stderr) # type: ignore
37-
self.process.started.connect(self._process_started) # type: ignore
38-
self.process.finished.connect(self._process_finished) # type: ignore
95+
def set_working_dir(self, work_dir: str) -> bool:
96+
"""
97+
设置子进程工作目录 \n
98+
:param work_dir: 工作目录
99+
:return: 是否设置成功
100+
"""
39101

40-
self.process.start(program, arguments)
102+
if os.path.isdir(work_dir):
103+
self._working_directory = work_dir
104+
return True
105+
else:
106+
return False
41107

42108
def _process_started(self) -> None:
43109
"""
44-
处理子进程的槽 \n
110+
处理子进程开始的槽 \n
45111
:return: None
46112
"""
113+
47114
pass
48115

49-
def _process_finished(
50-
self, exit_code: int, exit_status: QtCore.QProcess.ExitStatus
51-
) -> None:
116+
def _process_finished(self, code: int, status: QtCore.QProcess.ExitStatus) -> None:
52117
"""
53-
处理子进程的槽 \n
118+
处理子进程结束的槽 \n
119+
:param code: 退出码
120+
:param status: 退出状态
54121
:return: None
55122
"""
56123

57-
self.output.emit((self.FINISHED, str(exit_code)))
58-
self.process = None
124+
self.exit_code = code
125+
self.exit_status = status
126+
self.output.emit((self.FINISHED, str(code)))
127+
self._process = None
59128

60129
def _handle_stdout(self) -> None:
61130
"""
62131
处理标准输出的槽 \n
63132
:return: None
64133
"""
65134

66-
if self.process:
67-
data = self.process.readAllStandardOutput()
68-
stdout = bytes(data).decode(getdefaultencoding())
135+
if self._process:
136+
data = self._process.readAllStandardOutput()
137+
stdout = bytes(data).decode(getdefaultencoding()) # 将QByteArray转为str
69138
self.output.emit((self.STDOUT, stdout))
70139

71140
def _handle_stderr(self) -> None:
@@ -74,9 +143,9 @@ def _handle_stderr(self) -> None:
74143
:return: None
75144
"""
76145

77-
if self.process:
78-
data = self.process.readAllStandardError()
79-
stderr = bytes(data).decode(getdefaultencoding())
146+
if self._process:
147+
data = self._process.readAllStandardError()
148+
stderr = bytes(data).decode(getdefaultencoding()) # 将QByteArray转为str
80149
self.output.emit((self.STDERR, stderr))
81150

82151
def _handle_state(self, state: QtCore.QProcess.ProcessState) -> None:
@@ -93,3 +162,12 @@ def _handle_state(self, state: QtCore.QProcess.ProcessState) -> None:
93162
}
94163
state_name = states[state]
95164
self.output.emit((self.STATE, state_name))
165+
166+
def _handle_error(self, error: QtCore.QProcess.ProcessError) -> None:
167+
"""
168+
处理子进程错误 \n
169+
:param error: 子进程错误
170+
:return: None
171+
"""
172+
173+
pass

0 commit comments

Comments
 (0)