Proxy QProcess signals.
This commit is contained in:
parent
1f67353a40
commit
ad401e035f
@ -101,8 +101,8 @@ class _BaseUserscriptRunner(QObject):
|
|||||||
self._proc = guiprocess.GUIProcess(self._win_id, 'userscript',
|
self._proc = guiprocess.GUIProcess(self._win_id, 'userscript',
|
||||||
additional_env=self._env,
|
additional_env=self._env,
|
||||||
parent=self)
|
parent=self)
|
||||||
self._proc.proc.error.connect(self.on_proc_error)
|
self._proc.error.connect(self.on_proc_error)
|
||||||
self._proc.proc.finished.connect(self.on_proc_finished)
|
self._proc.finished.connect(self.on_proc_finished)
|
||||||
self._proc.start(cmd, args)
|
self._proc.start(cmd, args)
|
||||||
|
|
||||||
def _cleanup(self):
|
def _cleanup(self):
|
||||||
|
@ -116,8 +116,8 @@ class ExternalEditor(QObject):
|
|||||||
return
|
return
|
||||||
self._proc = guiprocess.GUIProcess(self._win_id, what='editor',
|
self._proc = guiprocess.GUIProcess(self._win_id, what='editor',
|
||||||
parent=self)
|
parent=self)
|
||||||
self._proc.proc.finished.connect(self.on_proc_closed)
|
self._proc.finished.connect(self.on_proc_closed)
|
||||||
self._proc.proc.error.connect(self.on_proc_error)
|
self._proc.error.connect(self.on_proc_error)
|
||||||
editor = config.get('general', 'editor')
|
editor = config.get('general', 'editor')
|
||||||
executable = editor[0]
|
executable = editor[0]
|
||||||
args = [self._filename if arg == '{}' else arg for arg in editor[1:]]
|
args = [self._filename if arg == '{}' else arg for arg in editor[1:]]
|
||||||
|
@ -21,7 +21,8 @@
|
|||||||
|
|
||||||
import shlex
|
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
|
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.
|
"""An external process which shows notifications in the GUI.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
proc: The underlying QProcess.
|
|
||||||
cmd: The command which was started.
|
cmd: The command which was started.
|
||||||
args: A list of arguments which gets passed.
|
args: A list of arguments which gets passed.
|
||||||
started: Whether the underlying process is started.
|
started: Whether the underlying process is started.
|
||||||
|
_proc: The underlying QProcess.
|
||||||
_win_id: The window ID this process is used in.
|
_win_id: The window ID this process is used in.
|
||||||
_what: What kind of thing is spawned (process/editor/userscript/...).
|
_what: What kind of thing is spawned (process/editor/userscript/...).
|
||||||
Used in messages.
|
Used in messages.
|
||||||
_verbose: Whether to show more 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,
|
def __init__(self, win_id, what, *, verbose=False, additional_env=None,
|
||||||
parent=None):
|
parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
self._win_id = win_id
|
self._win_id = win_id
|
||||||
self._what = what
|
self._what = what
|
||||||
self._verbose = verbose
|
self._verbose = verbose
|
||||||
@ -63,16 +72,19 @@ class GUIProcess:
|
|||||||
self.cmd = None
|
self.cmd = None
|
||||||
self.args = None
|
self.args = None
|
||||||
|
|
||||||
self.proc = QProcess(parent)
|
self._proc = QProcess(self)
|
||||||
self.proc.error.connect(self.on_error)
|
self._proc.error.connect(self.on_error)
|
||||||
self.proc.finished.connect(self.on_finished)
|
self._proc.error.connect(self.error)
|
||||||
self.proc.started.connect(self.on_started)
|
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:
|
if additional_env is not None:
|
||||||
procenv = QProcessEnvironment.systemEnvironment()
|
procenv = QProcessEnvironment.systemEnvironment()
|
||||||
for k, v in additional_env.items():
|
for k, v in additional_env.items():
|
||||||
procenv.insert(k, v)
|
procenv.insert(k, v)
|
||||||
self.proc.setProcessEnvironment(procenv)
|
self._proc.setProcessEnvironment(procenv)
|
||||||
|
|
||||||
@pyqtSlot(QProcess.ProcessError)
|
@pyqtSlot(QProcess.ProcessError)
|
||||||
def on_error(self, error):
|
def on_error(self, error):
|
||||||
@ -117,21 +129,24 @@ class GUIProcess:
|
|||||||
fake_cmdline = ' '.join(shlex.quote(e) for e in [cmd] + list(args))
|
fake_cmdline = ' '.join(shlex.quote(e) for e in [cmd] + list(args))
|
||||||
message.info(self._win_id, 'Executing: ' + fake_cmdline)
|
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."""
|
"""Convenience wrapper around QProcess::start."""
|
||||||
log.procs.debug("Starting process.")
|
log.procs.debug("Starting process.")
|
||||||
self._pre_start(cmd, args)
|
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):
|
def start_detached(self, cmd, args, cwd=None):
|
||||||
"""Convenience wrapper around QProcess::startDetached."""
|
"""Convenience wrapper around QProcess::startDetached."""
|
||||||
log.procs.debug("Starting detached.")
|
log.procs.debug("Starting detached.")
|
||||||
self._pre_start(cmd, args)
|
self._pre_start(cmd, args)
|
||||||
ok = self.proc.startDetached(cmd, args, cwd)
|
ok = self._proc.startDetached(cmd, args, cwd)
|
||||||
|
|
||||||
if ok:
|
if ok:
|
||||||
log.procs.debug("Process started.")
|
log.procs.debug("Process started.")
|
||||||
self.started = True
|
self.started = True
|
||||||
else:
|
else:
|
||||||
message.error(self._win_id, "Error while spawning {}: {}.".format(
|
message.error(self._win_id, "Error while spawning {}: {}.".format(
|
||||||
self._what, self.proc.error()), immediately=True)
|
self._what, self._proc.error()), immediately=True)
|
||||||
|
@ -60,7 +60,7 @@ class TestArg:
|
|||||||
stubbed_config.data = {
|
stubbed_config.data = {
|
||||||
'general': {'editor': ['bin'], 'editor-encoding': 'utf-8'}}
|
'general': {'editor': ['bin'], 'editor-encoding': 'utf-8'}}
|
||||||
self.editor.edit("")
|
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):
|
def test_start_args(self, stubbed_config):
|
||||||
"""Test starting editor with static arguments."""
|
"""Test starting editor with static arguments."""
|
||||||
@ -68,7 +68,7 @@ class TestArg:
|
|||||||
'general': {'editor': ['bin', 'foo', 'bar'],
|
'general': {'editor': ['bin', 'foo', 'bar'],
|
||||||
'editor-encoding': 'utf-8'}}
|
'editor-encoding': 'utf-8'}}
|
||||||
self.editor.edit("")
|
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):
|
def test_placeholder(self, stubbed_config):
|
||||||
"""Test starting editor with placeholder argument."""
|
"""Test starting editor with placeholder argument."""
|
||||||
@ -77,7 +77,7 @@ class TestArg:
|
|||||||
'editor-encoding': 'utf-8'}}
|
'editor-encoding': 'utf-8'}}
|
||||||
self.editor.edit("")
|
self.editor.edit("")
|
||||||
filename = self.editor._filename
|
filename = self.editor._filename
|
||||||
self.editor._proc.proc.start.assert_called_with(
|
self.editor._proc._proc.start.assert_called_with(
|
||||||
"bin", ["foo", filename, "bar"])
|
"bin", ["foo", filename, "bar"])
|
||||||
|
|
||||||
def test_in_arg_placeholder(self, stubbed_config):
|
def test_in_arg_placeholder(self, stubbed_config):
|
||||||
@ -86,7 +86,7 @@ class TestArg:
|
|||||||
'general': {'editor': ['bin', 'foo{}bar'],
|
'general': {'editor': ['bin', 'foo{}bar'],
|
||||||
'editor-encoding': 'utf-8'}}
|
'editor-encoding': 'utf-8'}}
|
||||||
self.editor.edit("")
|
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:
|
class TestFileHandling:
|
||||||
@ -113,7 +113,7 @@ class TestFileHandling:
|
|||||||
self.editor.edit("")
|
self.editor.edit("")
|
||||||
filename = self.editor._filename
|
filename = self.editor._filename
|
||||||
assert os.path.exists(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)
|
assert not os.path.exists(filename)
|
||||||
|
|
||||||
def test_file_handling_closed_error(self, caplog):
|
def test_file_handling_closed_error(self, caplog):
|
||||||
@ -122,7 +122,7 @@ class TestFileHandling:
|
|||||||
filename = self.editor._filename
|
filename = self.editor._filename
|
||||||
assert os.path.exists(filename)
|
assert os.path.exists(filename)
|
||||||
with caplog.atLevel(logging.ERROR):
|
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 len(caplog.records()) == 2
|
||||||
assert not os.path.exists(filename)
|
assert not os.path.exists(filename)
|
||||||
|
|
||||||
@ -132,9 +132,9 @@ class TestFileHandling:
|
|||||||
filename = self.editor._filename
|
filename = self.editor._filename
|
||||||
assert os.path.exists(filename)
|
assert os.path.exists(filename)
|
||||||
with caplog.atLevel(logging.ERROR):
|
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
|
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)
|
assert not os.path.exists(filename)
|
||||||
|
|
||||||
|
|
||||||
@ -182,7 +182,7 @@ class TestModifyTests:
|
|||||||
self.editor.edit("")
|
self.editor.edit("")
|
||||||
assert self._read() == ""
|
assert self._read() == ""
|
||||||
self._write("Hello")
|
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")
|
self.editor.editing_finished.emit.assert_called_with("Hello")
|
||||||
|
|
||||||
def test_simple_input(self):
|
def test_simple_input(self):
|
||||||
@ -190,7 +190,7 @@ class TestModifyTests:
|
|||||||
self.editor.edit("Hello")
|
self.editor.edit("Hello")
|
||||||
assert self._read() == "Hello"
|
assert self._read() == "Hello"
|
||||||
self._write("World")
|
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")
|
self.editor.editing_finished.emit.assert_called_with("World")
|
||||||
|
|
||||||
def test_umlaut(self):
|
def test_umlaut(self):
|
||||||
@ -198,7 +198,7 @@ class TestModifyTests:
|
|||||||
self.editor.edit("Hällö Wörld")
|
self.editor.edit("Hällö Wörld")
|
||||||
assert self._read() == "Hällö Wörld"
|
assert self._read() == "Hällö Wörld"
|
||||||
self._write("Überprüfung")
|
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")
|
self.editor.editing_finished.emit.assert_called_with("Überprüfung")
|
||||||
|
|
||||||
def test_unicode(self):
|
def test_unicode(self):
|
||||||
|
Loading…
Reference in New Issue
Block a user