Proxy QProcess signals.

This commit is contained in:
Florian Bruhin 2015-06-11 19:10:01 +02:00
parent 1f67353a40
commit ad401e035f
4 changed files with 42 additions and 27 deletions

View File

@ -101,8 +101,8 @@ class _BaseUserscriptRunner(QObject):
self._proc = guiprocess.GUIProcess(self._win_id, 'userscript',
additional_env=self._env,
parent=self)
self._proc.proc.error.connect(self.on_proc_error)
self._proc.proc.finished.connect(self.on_proc_finished)
self._proc.error.connect(self.on_proc_error)
self._proc.finished.connect(self.on_proc_finished)
self._proc.start(cmd, args)
def _cleanup(self):

View File

@ -116,8 +116,8 @@ class ExternalEditor(QObject):
return
self._proc = guiprocess.GUIProcess(self._win_id, what='editor',
parent=self)
self._proc.proc.finished.connect(self.on_proc_closed)
self._proc.proc.error.connect(self.on_proc_error)
self._proc.finished.connect(self.on_proc_closed)
self._proc.error.connect(self.on_proc_error)
editor = config.get('general', 'editor')
executable = editor[0]
args = [self._filename if arg == '{}' else arg for arg in editor[1:]]

View File

@ -21,7 +21,8 @@
import shlex
from PyQt5.QtCore import pyqtSlot, QProcess, QIODevice, QProcessEnvironment
from PyQt5.QtCore import (pyqtSlot, pyqtSignal, QObject, QProcess,
QProcessEnvironment)
from qutebrowser.utils import message, log
@ -39,23 +40,31 @@ ERROR_STRINGS = {
}
class GUIProcess:
class GUIProcess(QObject):
"""An external process which shows notifications in the GUI.
Args:
proc: The underlying QProcess.
cmd: The command which was started.
args: A list of arguments which gets passed.
started: Whether the underlying process is started.
_proc: The underlying QProcess.
_win_id: The window ID this process is used in.
_what: What kind of thing is spawned (process/editor/userscript/...).
Used in messages.
_verbose: Whether to show more messages.
Signals:
error/finished/started signals proxied from QProcess.
"""
error = pyqtSignal(QProcess.ProcessError)
finished = pyqtSignal(int, QProcess.ExitStatus)
started = pyqtSignal()
def __init__(self, win_id, what, *, verbose=False, additional_env=None,
parent=None):
super().__init__(parent)
self._win_id = win_id
self._what = what
self._verbose = verbose
@ -63,16 +72,19 @@ class GUIProcess:
self.cmd = None
self.args = None
self.proc = QProcess(parent)
self.proc.error.connect(self.on_error)
self.proc.finished.connect(self.on_finished)
self.proc.started.connect(self.on_started)
self._proc = QProcess(self)
self._proc.error.connect(self.on_error)
self._proc.error.connect(self.error)
self._proc.finished.connect(self.on_finished)
self._proc.finished.connect(self.finished)
self._proc.started.connect(self.on_started)
self._proc.started.connect(self.started)
if additional_env is not None:
procenv = QProcessEnvironment.systemEnvironment()
for k, v in additional_env.items():
procenv.insert(k, v)
self.proc.setProcessEnvironment(procenv)
self._proc.setProcessEnvironment(procenv)
@pyqtSlot(QProcess.ProcessError)
def on_error(self, error):
@ -117,21 +129,24 @@ class GUIProcess:
fake_cmdline = ' '.join(shlex.quote(e) for e in [cmd] + list(args))
message.info(self._win_id, 'Executing: ' + fake_cmdline)
def start(self, cmd, args, mode=QIODevice.ReadWrite):
def start(self, cmd, args, mode=None):
"""Convenience wrapper around QProcess::start."""
log.procs.debug("Starting process.")
self._pre_start(cmd, args)
self.proc.start(cmd, args, mode)
if mode is None:
self._proc.start(cmd, args)
else:
self._proc.start(cmd, args, mode)
def start_detached(self, cmd, args, cwd=None):
"""Convenience wrapper around QProcess::startDetached."""
log.procs.debug("Starting detached.")
self._pre_start(cmd, args)
ok = self.proc.startDetached(cmd, args, cwd)
ok = self._proc.startDetached(cmd, args, cwd)
if ok:
log.procs.debug("Process started.")
self.started = True
else:
message.error(self._win_id, "Error while spawning {}: {}.".format(
self._what, self.proc.error()), immediately=True)
self._what, self._proc.error()), immediately=True)

View File

@ -60,7 +60,7 @@ class TestArg:
stubbed_config.data = {
'general': {'editor': ['bin'], 'editor-encoding': 'utf-8'}}
self.editor.edit("")
self.editor._proc.proc.start.assert_called_with("bin", [])
self.editor._proc._proc.start.assert_called_with("bin", [])
def test_start_args(self, stubbed_config):
"""Test starting editor with static arguments."""
@ -68,7 +68,7 @@ class TestArg:
'general': {'editor': ['bin', 'foo', 'bar'],
'editor-encoding': 'utf-8'}}
self.editor.edit("")
self.editor._proc.proc.start.assert_called_with("bin", ["foo", "bar"])
self.editor._proc._proc.start.assert_called_with("bin", ["foo", "bar"])
def test_placeholder(self, stubbed_config):
"""Test starting editor with placeholder argument."""
@ -77,7 +77,7 @@ class TestArg:
'editor-encoding': 'utf-8'}}
self.editor.edit("")
filename = self.editor._filename
self.editor._proc.proc.start.assert_called_with(
self.editor._proc._proc.start.assert_called_with(
"bin", ["foo", filename, "bar"])
def test_in_arg_placeholder(self, stubbed_config):
@ -86,7 +86,7 @@ class TestArg:
'general': {'editor': ['bin', 'foo{}bar'],
'editor-encoding': 'utf-8'}}
self.editor.edit("")
self.editor._proc.proc.start.assert_called_with("bin", ["foo{}bar"])
self.editor._proc._proc.start.assert_called_with("bin", ["foo{}bar"])
class TestFileHandling:
@ -113,7 +113,7 @@ class TestFileHandling:
self.editor.edit("")
filename = self.editor._filename
assert os.path.exists(filename)
self.editor._proc.proc.finished.emit(0, QProcess.NormalExit)
self.editor._proc.finished.emit(0, QProcess.NormalExit)
assert not os.path.exists(filename)
def test_file_handling_closed_error(self, caplog):
@ -122,7 +122,7 @@ class TestFileHandling:
filename = self.editor._filename
assert os.path.exists(filename)
with caplog.atLevel(logging.ERROR):
self.editor._proc.proc.finished.emit(1, QProcess.NormalExit)
self.editor._proc.finished.emit(1, QProcess.NormalExit)
assert len(caplog.records()) == 2
assert not os.path.exists(filename)
@ -132,9 +132,9 @@ class TestFileHandling:
filename = self.editor._filename
assert os.path.exists(filename)
with caplog.atLevel(logging.ERROR):
self.editor._proc.proc.error.emit(QProcess.Crashed)
self.editor._proc.error.emit(QProcess.Crashed)
assert len(caplog.records()) == 2
self.editor._proc.proc.finished.emit(0, QProcess.CrashExit)
self.editor._proc.finished.emit(0, QProcess.CrashExit)
assert not os.path.exists(filename)
@ -182,7 +182,7 @@ class TestModifyTests:
self.editor.edit("")
assert self._read() == ""
self._write("Hello")
self.editor._proc.proc.finished.emit(0, QProcess.NormalExit)
self.editor._proc.finished.emit(0, QProcess.NormalExit)
self.editor.editing_finished.emit.assert_called_with("Hello")
def test_simple_input(self):
@ -190,7 +190,7 @@ class TestModifyTests:
self.editor.edit("Hello")
assert self._read() == "Hello"
self._write("World")
self.editor._proc.proc.finished.emit(0, QProcess.NormalExit)
self.editor._proc.finished.emit(0, QProcess.NormalExit)
self.editor.editing_finished.emit.assert_called_with("World")
def test_umlaut(self):
@ -198,7 +198,7 @@ class TestModifyTests:
self.editor.edit("Hällö Wörld")
assert self._read() == "Hällö Wörld"
self._write("Überprüfung")
self.editor._proc.proc.finished.emit(0, QProcess.NormalExit)
self.editor._proc.finished.emit(0, QProcess.NormalExit)
self.editor.editing_finished.emit.assert_called_with("Überprüfung")
def test_unicode(self):