Move init stuff from config.py to configinit.py

Closes #2997
This commit is contained in:
Florian Bruhin 2017-09-22 14:08:06 +02:00
parent d1a4a028cd
commit d5a1fff637
5 changed files with 391 additions and 336 deletions

View File

@ -43,7 +43,8 @@ import qutebrowser
import qutebrowser.resources
from qutebrowser.completion.models import miscmodels
from qutebrowser.commands import cmdutils, runners, cmdexc
from qutebrowser.config import config, websettings, configexc, configfiles
from qutebrowser.config import (config, websettings, configexc, configfiles,
configinit)
from qutebrowser.browser import (urlmarks, adblock, history, browsertab,
downloads)
from qutebrowser.browser.network import proxy
@ -77,7 +78,7 @@ def run(args):
standarddir.init(args)
log.init.debug("Initializing config...")
config.early_init(args)
configinit.early_init(args)
global qApp
qApp = Application(args)
@ -393,7 +394,7 @@ def _init_modules(args, crash_handler):
log.init.debug("Initializing save manager...")
save_manager = savemanager.SaveManager(qApp)
objreg.register('save-manager', save_manager)
config.late_init(save_manager)
configinit.late_init(save_manager)
log.init.debug("Initializing network...")
networkmanager.init()
@ -762,7 +763,7 @@ class Application(QApplication):
"""
self._last_focus_object = None
qt_args = config.qt_args(args)
qt_args = configinit.qt_args(args)
log.init.debug("Qt arguments: {}, based on {}".format(qt_args, args))
super().__init__(qt_args)

View File

@ -19,18 +19,15 @@
"""Configuration storage and config-related utilities."""
import sys
import copy
import contextlib
import functools
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject, QUrl
from PyQt5.QtWidgets import QMessageBox
from qutebrowser.config import configdata, configexc, configtypes, configfiles
from qutebrowser.utils import (utils, objreg, message, log, usertypes, jinja,
qtutils)
from qutebrowser.misc import objects, msgbox, earlyinit
from qutebrowser.utils import utils, objreg, message, log, jinja, qtutils
from qutebrowser.misc import objects
from qutebrowser.commands import cmdexc, cmdutils
from qutebrowser.completion.models import configmodel
@ -40,9 +37,7 @@ instance = None
key_instance = None
# Keeping track of all change filters to validate them later.
_change_filters = []
# Errors which happened during init, so we can show a message box.
_init_errors = []
change_filters = []
class change_filter: # pylint: disable=invalid-name
@ -68,7 +63,7 @@ class change_filter: # pylint: disable=invalid-name
"""
self._option = option
self._function = function
_change_filters.append(self)
change_filters.append(self)
def validate(self):
"""Make sure the configured option or prefix exists.
@ -634,114 +629,3 @@ class StyleSheetObserver(QObject):
self._obj.setStyleSheet(qss)
if update:
instance.changed.connect(self._update_stylesheet)
def early_init(args):
"""Initialize the part of the config which works without a QApplication."""
configdata.init()
yaml_config = configfiles.YamlConfig()
global val, instance, key_instance
instance = Config(yaml_config=yaml_config)
val = ConfigContainer(instance)
key_instance = KeyConfig(instance)
for cf in _change_filters:
cf.validate()
configtypes.Font.monospace_fonts = val.fonts.monospace
config_commands = ConfigCommands(instance, key_instance)
objreg.register('config-commands', config_commands)
config_api = None
try:
config_api = configfiles.read_config_py()
# Raised here so we get the config_api back.
if config_api.errors:
raise configexc.ConfigFileErrors('config.py', config_api.errors)
except configexc.ConfigFileErrors as e:
log.config.exception("Error while loading config.py")
_init_errors.append(e)
try:
if getattr(config_api, 'load_autoconfig', True):
try:
instance.read_yaml()
except configexc.ConfigFileErrors as e:
raise # caught in outer block
except configexc.Error as e:
desc = configexc.ConfigErrorDesc("Error", e)
raise configexc.ConfigFileErrors('autoconfig.yml', [desc])
except configexc.ConfigFileErrors as e:
log.config.exception("Error while loading config.py")
_init_errors.append(e)
configfiles.init()
objects.backend = get_backend(args)
earlyinit.init_with_backend(objects.backend)
def get_backend(args):
"""Find out what backend to use based on available libraries."""
try:
import PyQt5.QtWebKit # pylint: disable=unused-variable
except ImportError:
webkit_available = False
else:
webkit_available = qtutils.is_new_qtwebkit()
str_to_backend = {
'webkit': usertypes.Backend.QtWebKit,
'webengine': usertypes.Backend.QtWebEngine,
}
if args.backend is not None:
return str_to_backend[args.backend]
elif val.backend != 'auto':
return str_to_backend[val.backend]
elif webkit_available:
return usertypes.Backend.QtWebKit
else:
return usertypes.Backend.QtWebEngine
def late_init(save_manager):
"""Initialize the rest of the config after the QApplication is created."""
global _init_errors
for err in _init_errors:
errbox = msgbox.msgbox(parent=None,
title="Error while reading config",
text=err.to_html(),
icon=QMessageBox.Warning,
plain_text=False)
errbox.exec_()
_init_errors = []
instance.init_save_manager(save_manager)
configfiles.state.init_save_manager(save_manager)
def qt_args(namespace):
"""Get the Qt QApplication arguments based on an argparse namespace.
Args:
namespace: The argparse namespace.
Return:
The argv list to be passed to Qt.
"""
argv = [sys.argv[0]]
if namespace.qt_flag is not None:
argv += ['--' + flag[0] for flag in namespace.qt_flag]
if namespace.qt_arg is not None:
for name, value in namespace.qt_arg:
argv += ['--' + name, value]
argv += ['--' + arg for arg in val.qt_args]
return argv

View File

@ -0,0 +1,144 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
# qutebrowser is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# qutebrowser is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
"""Initialization of the configuration."""
import sys
from PyQt5.QtWidgets import QMessageBox
from qutebrowser.config import (config, configdata, configfiles, configtypes,
configexc)
from qutebrowser.utils import objreg, qtutils, usertypes, log
from qutebrowser.misc import earlyinit, msgbox, objects
# Errors which happened during init, so we can show a message box.
_init_errors = []
def early_init(args):
"""Initialize the part of the config which works without a QApplication."""
configdata.init()
yaml_config = configfiles.YamlConfig()
config.instance = config.Config(yaml_config=yaml_config)
config.val = config.ConfigContainer(config.instance)
config.key_instance = config.KeyConfig(config.instance)
for cf in config.change_filters:
cf.validate()
configtypes.Font.monospace_fonts = config.val.fonts.monospace
config_commands = config.ConfigCommands(config.instance,
config.key_instance)
objreg.register('config-commands', config_commands)
config_api = None
try:
config_api = configfiles.read_config_py()
# Raised here so we get the config_api back.
if config_api.errors:
raise configexc.ConfigFileErrors('config.py', config_api.errors)
except configexc.ConfigFileErrors as e:
log.config.exception("Error while loading config.py")
_init_errors.append(e)
try:
if getattr(config_api, 'load_autoconfig', True):
try:
config.instance.read_yaml()
except configexc.ConfigFileErrors as e:
raise # caught in outer block
except configexc.Error as e:
desc = configexc.ConfigErrorDesc("Error", e)
raise configexc.ConfigFileErrors('autoconfig.yml', [desc])
except configexc.ConfigFileErrors as e:
log.config.exception("Error while loading config.py")
_init_errors.append(e)
configfiles.init()
objects.backend = get_backend(args)
earlyinit.init_with_backend(objects.backend)
def get_backend(args):
"""Find out what backend to use based on available libraries."""
try:
import PyQt5.QtWebKit # pylint: disable=unused-variable
except ImportError:
webkit_available = False
else:
webkit_available = qtutils.is_new_qtwebkit()
str_to_backend = {
'webkit': usertypes.Backend.QtWebKit,
'webengine': usertypes.Backend.QtWebEngine,
}
if args.backend is not None:
return str_to_backend[args.backend]
elif config.val.backend != 'auto':
return str_to_backend[config.val.backend]
elif webkit_available:
return usertypes.Backend.QtWebKit
else:
return usertypes.Backend.QtWebEngine
def late_init(save_manager):
"""Initialize the rest of the config after the QApplication is created."""
global _init_errors
for err in _init_errors:
errbox = msgbox.msgbox(parent=None,
title="Error while reading config",
text=err.to_html(),
icon=QMessageBox.Warning,
plain_text=False)
errbox.exec_()
_init_errors = []
config.instance.init_save_manager(save_manager)
configfiles.state.init_save_manager(save_manager)
def qt_args(namespace):
"""Get the Qt QApplication arguments based on an argparse namespace.
Args:
namespace: The argparse namespace.
Return:
The argv list to be passed to Qt.
"""
argv = [sys.argv[0]]
if namespace.qt_flag is not None:
argv += ['--' + flag[0] for flag in namespace.qt_flag]
if namespace.qt_arg is not None:
for name, value in namespace.qt_arg:
argv += ['--' + name, value]
argv += ['--' + arg for arg in config.val.qt_args]
return argv

View File

@ -18,19 +18,15 @@
"""Tests for qutebrowser.config.config."""
import sys
import copy
import types
import logging
import unittest.mock
import pytest
from PyQt5.QtCore import QObject, QUrl
from PyQt5.QtGui import QColor
from qutebrowser import qutebrowser
from qutebrowser.commands import cmdexc
from qutebrowser.config import config, configdata, configexc, configfiles
from qutebrowser.config import config, configdata, configexc
from qutebrowser.utils import objreg, usertypes
from qutebrowser.misc import objects
@ -52,8 +48,8 @@ class TestChangeFilter:
@pytest.fixture(autouse=True)
def cleanup_globals(self, monkeypatch):
"""Make sure config._change_filters is cleaned up."""
monkeypatch.setattr(config, '_change_filters', [])
"""Make sure config.change_filters is cleaned up."""
monkeypatch.setattr(config, 'change_filters', [])
@pytest.mark.parametrize('option', ['foobar', 'tab', 'tabss', 'tabs.'])
def test_unknown_option(self, option):
@ -65,7 +61,7 @@ class TestChangeFilter:
def test_validate(self, option):
cf = config.change_filter(option)
cf.validate()
assert cf in config._change_filters
assert cf in config.change_filters
@pytest.mark.parametrize('method', [True, False])
@pytest.mark.parametrize('option, changed, matches', [
@ -864,207 +860,3 @@ def test_set_register_stylesheet(delete, stylesheet_param, update, qtbot,
expected = 'yellow'
assert obj.rendered_stylesheet == expected
@pytest.fixture
def init_patch(qapp, fake_save_manager, monkeypatch, config_tmpdir,
data_tmpdir):
monkeypatch.setattr(configdata, 'DATA', None)
monkeypatch.setattr(configfiles, 'state', None)
monkeypatch.setattr(config, 'instance', None)
monkeypatch.setattr(config, 'key_instance', None)
monkeypatch.setattr(config, '_change_filters', [])
monkeypatch.setattr(config, '_init_errors', [])
# Make sure we get no SSL warning
monkeypatch.setattr(config.earlyinit, 'check_backend_ssl_support',
lambda _backend: None)
yield
try:
objreg.delete('config-commands')
except KeyError:
pass
@pytest.mark.parametrize('load_autoconfig', [True, False]) # noqa
@pytest.mark.parametrize('config_py', [True, 'error', False])
@pytest.mark.parametrize('invalid_yaml',
['42', 'unknown', 'wrong-type', False])
# pylint: disable=too-many-branches
def test_early_init(init_patch, config_tmpdir, caplog, fake_args,
load_autoconfig, config_py, invalid_yaml):
# Prepare files
autoconfig_file = config_tmpdir / 'autoconfig.yml'
config_py_file = config_tmpdir / 'config.py'
if invalid_yaml == '42':
text = '42'
elif invalid_yaml == 'unknown':
text = 'global:\n colors.foobar: magenta\n'
elif invalid_yaml == 'wrong-type':
text = 'global:\n tabs.position: true\n'
else:
assert not invalid_yaml
text = 'global:\n colors.hints.fg: magenta\n'
autoconfig_file.write_text(text, 'utf-8', ensure=True)
if config_py:
config_py_lines = ['c.colors.hints.bg = "red"']
if not load_autoconfig:
config_py_lines.append('config.load_autoconfig = False')
if config_py == 'error':
config_py_lines.append('c.foo = 42')
config_py_file.write_text('\n'.join(config_py_lines),
'utf-8', ensure=True)
with caplog.at_level(logging.ERROR):
config.early_init(fake_args)
# Check error messages
expected_errors = []
if config_py == 'error':
expected_errors.append(
"Errors occurred while reading config.py:\n"
" While setting 'foo': No option 'foo'")
if load_autoconfig or not config_py:
error = "Errors occurred while reading autoconfig.yml:\n"
if invalid_yaml == '42':
error += " While loading data: Toplevel object is not a dict"
expected_errors.append(error)
elif invalid_yaml == 'wrong-type':
error += (" Error: Invalid value 'True' - expected a value of "
"type str but got bool.")
expected_errors.append(error)
actual_errors = [str(err) for err in config._init_errors]
assert actual_errors == expected_errors
# Make sure things have been init'ed
objreg.get('config-commands')
assert isinstance(config.instance, config.Config)
assert isinstance(config.key_instance, config.KeyConfig)
# Check config values
if config_py and load_autoconfig and not invalid_yaml:
assert config.instance._values == {
'colors.hints.bg': 'red',
'colors.hints.fg': 'magenta',
}
elif config_py:
assert config.instance._values == {'colors.hints.bg': 'red'}
elif invalid_yaml:
assert config.instance._values == {}
else:
assert config.instance._values == {'colors.hints.fg': 'magenta'}
def test_early_init_invalid_change_filter(init_patch, fake_args):
config.change_filter('foobar')
with pytest.raises(configexc.NoOptionError):
config.early_init(fake_args)
@pytest.mark.parametrize('errors', [True, False])
def test_late_init(init_patch, monkeypatch, fake_save_manager, fake_args,
mocker, errors):
config.early_init(fake_args)
if errors:
err = configexc.ConfigErrorDesc("Error text", Exception("Exception"))
errs = configexc.ConfigFileErrors("config.py", [err])
monkeypatch.setattr(config, '_init_errors', [errs])
msgbox_mock = mocker.patch('qutebrowser.config.config.msgbox.msgbox',
autospec=True)
config.late_init(fake_save_manager)
fake_save_manager.add_saveable.assert_any_call(
'state-config', unittest.mock.ANY)
fake_save_manager.add_saveable.assert_any_call(
'yaml-config', unittest.mock.ANY)
if errors:
assert len(msgbox_mock.call_args_list) == 1
_call_posargs, call_kwargs = msgbox_mock.call_args_list[0]
text = call_kwargs['text'].strip()
assert text.startswith('Errors occurred while reading config.py:')
assert '<b>Error text</b>: Exception' in text
else:
assert not msgbox_mock.called
class TestQtArgs:
@pytest.fixture
def parser(self, mocker):
"""Fixture to provide an argparser.
Monkey-patches .exit() of the argparser so it doesn't exit on errors.
"""
parser = qutebrowser.get_argparser()
mocker.patch.object(parser, 'exit', side_effect=Exception)
return parser
@pytest.mark.parametrize('args, expected', [
# No Qt arguments
(['--debug'], [sys.argv[0]]),
# Qt flag
(['--debug', '--qt-flag', 'reverse'], [sys.argv[0], '--reverse']),
# Qt argument with value
(['--qt-arg', 'stylesheet', 'foo'],
[sys.argv[0], '--stylesheet', 'foo']),
# --qt-arg given twice
(['--qt-arg', 'stylesheet', 'foo', '--qt-arg', 'geometry', 'bar'],
[sys.argv[0], '--stylesheet', 'foo', '--geometry', 'bar']),
# --qt-flag given twice
(['--qt-flag', 'foo', '--qt-flag', 'bar'],
[sys.argv[0], '--foo', '--bar']),
])
def test_qt_args(self, config_stub, args, expected, parser):
"""Test commandline with no Qt arguments given."""
parsed = parser.parse_args(args)
assert config.qt_args(parsed) == expected
def test_qt_both(self, config_stub, parser):
"""Test commandline with a Qt argument and flag."""
args = parser.parse_args(['--qt-arg', 'stylesheet', 'foobar',
'--qt-flag', 'reverse'])
qt_args = config.qt_args(args)
assert qt_args[0] == sys.argv[0]
assert '--reverse' in qt_args
assert '--stylesheet' in qt_args
assert 'foobar' in qt_args
def test_with_settings(self, config_stub, parser):
parsed = parser.parse_args(['--qt-flag', 'foo'])
config_stub.val.qt_args = ['bar']
assert config.qt_args(parsed) == [sys.argv[0], '--foo', '--bar']
@pytest.mark.parametrize('arg, confval, can_import, is_new_webkit, used', [
# overridden by commandline arg
('webkit', 'auto', False, False, usertypes.Backend.QtWebKit),
# overridden by config
(None, 'webkit', False, False, usertypes.Backend.QtWebKit),
# WebKit available but too old
(None, 'auto', True, False, usertypes.Backend.QtWebEngine),
# WebKit available and new
(None, 'auto', True, True, usertypes.Backend.QtWebKit),
# WebKit unavailable
(None, 'auto', False, False, usertypes.Backend.QtWebEngine),
])
def test_get_backend(monkeypatch, fake_args, config_stub,
arg, confval, can_import, is_new_webkit, used):
real_import = __import__
def fake_import(name, *args, **kwargs):
if name != 'PyQt5.QtWebKit':
return real_import(name, *args, **kwargs)
if can_import:
return None
raise ImportError
fake_args.backend = arg
config_stub.val.backend = confval
monkeypatch.setattr(config.qtutils, 'is_new_qtwebkit',
lambda: is_new_webkit)
monkeypatch.setattr('builtins.__import__', fake_import)
assert config.get_backend(fake_args) == used

View File

@ -0,0 +1,234 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# This file is part of qutebrowser.
#
# qutebrowser is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# qutebrowser is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
"""Tests for qutebrowser.config.configinit."""
import sys
import logging
import unittest.mock
import pytest
from qutebrowser import qutebrowser
from qutebrowser.config import (config, configdata, configexc, configfiles,
configinit)
from qutebrowser.utils import objreg, usertypes
@pytest.fixture
def init_patch(qapp, fake_save_manager, monkeypatch, config_tmpdir,
data_tmpdir):
monkeypatch.setattr(configdata, 'DATA', None)
monkeypatch.setattr(configfiles, 'state', None)
monkeypatch.setattr(config, 'instance', None)
monkeypatch.setattr(config, 'key_instance', None)
monkeypatch.setattr(config, 'change_filters', [])
monkeypatch.setattr(configinit, '_init_errors', [])
# Make sure we get no SSL warning
monkeypatch.setattr(configinit.earlyinit, 'check_backend_ssl_support',
lambda _backend: None)
yield
try:
objreg.delete('config-commands')
except KeyError:
pass
@pytest.mark.parametrize('load_autoconfig', [True, False]) # noqa
@pytest.mark.parametrize('config_py', [True, 'error', False])
@pytest.mark.parametrize('invalid_yaml',
['42', 'unknown', 'wrong-type', False])
# pylint: disable=too-many-branches
def test_early_init(init_patch, config_tmpdir, caplog, fake_args,
load_autoconfig, config_py, invalid_yaml):
# Prepare files
autoconfig_file = config_tmpdir / 'autoconfig.yml'
config_py_file = config_tmpdir / 'config.py'
if invalid_yaml == '42':
text = '42'
elif invalid_yaml == 'unknown':
text = 'global:\n colors.foobar: magenta\n'
elif invalid_yaml == 'wrong-type':
text = 'global:\n tabs.position: true\n'
else:
assert not invalid_yaml
text = 'global:\n colors.hints.fg: magenta\n'
autoconfig_file.write_text(text, 'utf-8', ensure=True)
if config_py:
config_py_lines = ['c.colors.hints.bg = "red"']
if not load_autoconfig:
config_py_lines.append('config.load_autoconfig = False')
if config_py == 'error':
config_py_lines.append('c.foo = 42')
config_py_file.write_text('\n'.join(config_py_lines),
'utf-8', ensure=True)
with caplog.at_level(logging.ERROR):
configinit.early_init(fake_args)
# Check error messages
expected_errors = []
if config_py == 'error':
expected_errors.append(
"Errors occurred while reading config.py:\n"
" While setting 'foo': No option 'foo'")
if load_autoconfig or not config_py:
error = "Errors occurred while reading autoconfig.yml:\n"
if invalid_yaml == '42':
error += " While loading data: Toplevel object is not a dict"
expected_errors.append(error)
elif invalid_yaml == 'wrong-type':
error += (" Error: Invalid value 'True' - expected a value of "
"type str but got bool.")
expected_errors.append(error)
actual_errors = [str(err) for err in configinit._init_errors]
assert actual_errors == expected_errors
# Make sure things have been init'ed
objreg.get('config-commands')
assert isinstance(config.instance, config.Config)
assert isinstance(config.key_instance, config.KeyConfig)
# Check config values
if config_py and load_autoconfig and not invalid_yaml:
assert config.instance._values == {
'colors.hints.bg': 'red',
'colors.hints.fg': 'magenta',
}
elif config_py:
assert config.instance._values == {'colors.hints.bg': 'red'}
elif invalid_yaml:
assert config.instance._values == {}
else:
assert config.instance._values == {'colors.hints.fg': 'magenta'}
def test_early_init_invalid_change_filter(init_patch, fake_args):
config.change_filter('foobar')
with pytest.raises(configexc.NoOptionError):
configinit.early_init(fake_args)
@pytest.mark.parametrize('errors', [True, False])
def test_late_init(init_patch, monkeypatch, fake_save_manager, fake_args,
mocker, errors):
configinit.early_init(fake_args)
if errors:
err = configexc.ConfigErrorDesc("Error text", Exception("Exception"))
errs = configexc.ConfigFileErrors("config.py", [err])
monkeypatch.setattr(configinit, '_init_errors', [errs])
msgbox_mock = mocker.patch('qutebrowser.config.configinit.msgbox.msgbox',
autospec=True)
configinit.late_init(fake_save_manager)
fake_save_manager.add_saveable.assert_any_call(
'state-config', unittest.mock.ANY)
fake_save_manager.add_saveable.assert_any_call(
'yaml-config', unittest.mock.ANY)
if errors:
assert len(msgbox_mock.call_args_list) == 1
_call_posargs, call_kwargs = msgbox_mock.call_args_list[0]
text = call_kwargs['text'].strip()
assert text.startswith('Errors occurred while reading config.py:')
assert '<b>Error text</b>: Exception' in text
else:
assert not msgbox_mock.called
class TestQtArgs:
@pytest.fixture
def parser(self, mocker):
"""Fixture to provide an argparser.
Monkey-patches .exit() of the argparser so it doesn't exit on errors.
"""
parser = qutebrowser.get_argparser()
mocker.patch.object(parser, 'exit', side_effect=Exception)
return parser
@pytest.mark.parametrize('args, expected', [
# No Qt arguments
(['--debug'], [sys.argv[0]]),
# Qt flag
(['--debug', '--qt-flag', 'reverse'], [sys.argv[0], '--reverse']),
# Qt argument with value
(['--qt-arg', 'stylesheet', 'foo'],
[sys.argv[0], '--stylesheet', 'foo']),
# --qt-arg given twice
(['--qt-arg', 'stylesheet', 'foo', '--qt-arg', 'geometry', 'bar'],
[sys.argv[0], '--stylesheet', 'foo', '--geometry', 'bar']),
# --qt-flag given twice
(['--qt-flag', 'foo', '--qt-flag', 'bar'],
[sys.argv[0], '--foo', '--bar']),
])
def test_qt_args(self, config_stub, args, expected, parser):
"""Test commandline with no Qt arguments given."""
parsed = parser.parse_args(args)
assert configinit.qt_args(parsed) == expected
def test_qt_both(self, config_stub, parser):
"""Test commandline with a Qt argument and flag."""
args = parser.parse_args(['--qt-arg', 'stylesheet', 'foobar',
'--qt-flag', 'reverse'])
qt_args = configinit.qt_args(args)
assert qt_args[0] == sys.argv[0]
assert '--reverse' in qt_args
assert '--stylesheet' in qt_args
assert 'foobar' in qt_args
def test_with_settings(self, config_stub, parser):
parsed = parser.parse_args(['--qt-flag', 'foo'])
config_stub.val.qt_args = ['bar']
assert configinit.qt_args(parsed) == [sys.argv[0], '--foo', '--bar']
@pytest.mark.parametrize('arg, confval, can_import, is_new_webkit, used', [
# overridden by commandline arg
('webkit', 'auto', False, False, usertypes.Backend.QtWebKit),
# overridden by config
(None, 'webkit', False, False, usertypes.Backend.QtWebKit),
# WebKit available but too old
(None, 'auto', True, False, usertypes.Backend.QtWebEngine),
# WebKit available and new
(None, 'auto', True, True, usertypes.Backend.QtWebKit),
# WebKit unavailable
(None, 'auto', False, False, usertypes.Backend.QtWebEngine),
])
def test_get_backend(monkeypatch, fake_args, config_stub,
arg, confval, can_import, is_new_webkit, used):
real_import = __import__
def fake_import(name, *args, **kwargs):
if name != 'PyQt5.QtWebKit':
return real_import(name, *args, **kwargs)
if can_import:
return None
raise ImportError
fake_args.backend = arg
config_stub.val.backend = confval
monkeypatch.setattr(config.qtutils, 'is_new_qtwebkit',
lambda: is_new_webkit)
monkeypatch.setattr('builtins.__import__', fake_import)
assert configinit.get_backend(fake_args) == used