未經測試,但我之前已經封裝了QProcess,因此在出現錯誤時我可以獲得更多信息。
參見ERRORTEXT()方法:
class Process(QtCore.QProcess):
"""
Makes QProcess a bit more usable (to my mind) in the following ways:
- Automatically frees memory when it's spent (see __singleshot).
- Makes stderr and stdout more-like 'properties' of the object, rather than weird streams/buffers that evaporate after you read them!
- Abstracts success & failure such that succeeded() means 'everything succeeded' and failed() to mean '*something* failed'.
- All error text is available from a single call, regardless of error-origin (QProcess; the program invoked; or the underlying device).
- Defines __finished to mean 'we either succeeded or failed but, either way, it's all over'.
- Added various helper methods such as isValid(), isRunning(), etc.
"""
def __init__(self, singleshot=True, *args, **kwargs):
super().__init__(*args, **kwargs)
# Important that these slots are connected first, so our responses are readied first.
self.finished.connect(self.on_finished)
self.error.connect(self.on_error)
self.__singleshot = singleshot
self.__finished = False
self.__stdoutText = ""
self.__stderrText = ""
self.__QProcessErrorText = ""
self.__QIODeviceErrorText = ""
self.__QIODeviceDefaultErrorString = self.errorString() # So we can later avoid QIODevice's pessimistic, spurious default message of 'Unknown Error'.
self.__succeeded = False
def on_error(self, error):
self.__finished = True
self.__succeeded = False # .. probably overkill.. (probably already False..)
errorMap = {self.FailedToStart: "The process failed to start.",
self.Crashed: "The process crashed some time after starting successfully.",
self.Timedout: "The last waitFor...() function timed out.",
self.WriteError: "An error occurred when attempting to write to the process.",
self.ReadError: "An error occurred when attempting to read from the process.",
self.UnknownError: "An unknown error occurred."}
self.__QProcessErrorText = errorMap[error]
if self.__singleshot: self.deleteLater() ## Kinda handy for memory-management...
def on_finished(self, exitCode, exitStatus):
self.__finished = True
self.__succeeded = (exitCode == 0) & (exitStatus == self.NormalExit)
if self.__singleshot: self.deleteLater() ## Kinda handy for memory-management...
def outputText(self):
# Drain the stdout buffer into local instance variable..
self.__stdoutText += str(self.readAllStandardOutput(), encoding='utf-8')
return self.__stdoutText
def stdErrText(self):
# Drain the stderr buffer into local instance variable..
self.__stderrText += str(self.readAllStandardError(), encoding='utf-8')
return self.__stderrText
def errorText(self, delimiter=". "):
# Returns string detailing error from any potential error source (the program; the QProcess; the underlying QIODevice).
errorSources = {"stderr": self.stdErrText(),
"QProcessErrorText": self.__QProcessErrorText,
"QIODeviceErrorText": self.errorString() if not self.__QIODeviceDefaultErrorString else "" } # Drop QIODevice's spurious default message of ~'Unknown error'.
# Note that error texts are stripped, so they have to be substantive...
response = delimiter.join(": ".join([key, value.strip()]) for (key, value) in sorted(errorSources.items()) if value)
return response
def succeeded(self):
return self.__finished and self.__succeeded and (not self.stdErrText()) # stdErr checked because of edge case where QProcess claims to finish and succeed (but writes its own failure to stderr!) -- e.g. "QProcessPrivate::execChild() failed to chdir"...
def failed(self):
return self.__finished and not self.succeeded()
def isValid(self):
try: # An arbitrary interrogation to see if underlying c++ wrapper object has been deleted
self.objectName()
return True
except RuntimeError:
return False
def isRunning(self):
return self.state() == self.Running
def isStarting(self):
return self.state() == self.Starting
'打印(STR(self.JTAG_ServerProcess.errorString()))'。 state()的返回值與錯誤無關。如果狀態爲'1',則相當於'QProcess.Starting'。 – ekhumoro