Fix startup crashes after config merge.

Get qutebrowser to the point where it can at least start

- Declare _messages earlier in MessageView.__init__ so it is set before
  the config trigger tries to access it.
- Remove unused configmodel completion functions
- Move bind completion to configmodel to avoid a circular import with
  the config module
- Fix some config accesses (forgot to use .val)
- Fix old Completion.CompletionKind references
This commit is contained in:
Ryan Roden-Corrent 2017-08-08 10:55:03 -04:00
parent 71b71dbc58
commit 5ea420b49b
10 changed files with 54 additions and 146 deletions

View File

@ -44,7 +44,6 @@ import qutebrowser.resources
from qutebrowser.completion.models import miscmodels
from qutebrowser.commands import cmdutils, runners, cmdexc
from qutebrowser.config import config, websettings, configexc
from qutebrowser.config.parsers import keyconf
from qutebrowser.browser import (urlmarks, adblock, history, browsertab,
downloads)
from qutebrowser.browser.network import proxy
@ -412,9 +411,6 @@ def _init_modules(args, crash_handler):
config.init(qApp)
save_manager.init_autosave()
log.init.debug("Initializing keys...")
keyconf.init(qApp)
log.init.debug("Initializing sql...")
try:
sql.init(os.path.join(standarddir.data(), 'history.sqlite'))
@ -631,7 +627,7 @@ class Quitter:
return True
@cmdutils.register(instance='quitter', name='quit')
@cmdutils.argument('session', completion=usertypes.Completion.sessions)
@cmdutils.argument('session', completion=miscmodels.session)
def quit(self, save=False, session=None):
"""Quit qutebrowser.

View File

@ -33,6 +33,7 @@ from PyQt5.QtPrintSupport import QPrinter
from qutebrowser.browser import browsertab
from qutebrowser.browser.webkit import webview, tabhistory, webkitelem
from qutebrowser.browser.network import proxy
from qutebrowser.utils import qtutils, objreg, usertypes, utils, log, debug

View File

@ -19,78 +19,61 @@
"""Functions that return config-related completion models."""
from qutebrowser.config import configdata, configexc
from qutebrowser.config import configdata, configexc, config
from qutebrowser.completion.models import completionmodel, listcategory
from qutebrowser.utils import objreg
from qutebrowser.commands import cmdutils
def section():
"""A CompletionModel filled with settings sections."""
model = completionmodel.CompletionModel(column_widths=(20, 70, 10))
sections = ((name, configdata.SECTION_DESC[name].splitlines()[0].strip())
for name in configdata.DATA)
model.add_category(listcategory.ListCategory("Sections", sections))
def option():
"""A CompletionModel filled with settings and their descriptions."""
model = completionmodel.CompletionModel(column_widths=(30, 70, 0))
options = [(x.name, x.description) for x in configdata.DATA.values()]
model.add_category(listcategory.ListCategory("Options", options))
return model
def option(sectname):
"""A CompletionModel filled with settings and their descriptions.
Args:
sectname: The name of the config section this model shows.
"""
model = completionmodel.CompletionModel(column_widths=(20, 70, 10))
try:
sectdata = configdata.DATA[sectname]
except KeyError:
return None
options = []
for name in sectdata:
try:
desc = sectdata.descriptions[name]
except (KeyError, AttributeError):
# Some stuff (especially ValueList items) don't have a
# description.
desc = ""
else:
desc = desc.splitlines()[0]
config = objreg.get('config')
val = config.get(sectname, name, raw=True)
options.append((name, desc, val))
model.add_category(listcategory.ListCategory(sectname, options))
return model
def value(sectname, optname):
def value(optname, *values):
"""A CompletionModel filled with setting values.
Args:
sectname: The name of the config section this model shows.
optname: The name of the config option this model shows.
values: The values already provided on the command line.
"""
model = completionmodel.CompletionModel(column_widths=(20, 70, 10))
config = objreg.get('config')
model = completionmodel.CompletionModel(column_widths=(30, 70, 0))
try:
current = config.get(sectname, optname, raw=True) or '""'
except (configexc.NoSectionError, configexc.NoOptionError):
current = str(config.instance.get(optname) or '""')
except configexc.NoOptionError:
return None
default = configdata.DATA[sectname][optname].default() or '""'
if hasattr(configdata.DATA[sectname], 'valtype'):
# Same type for all values (ValueList)
vals = configdata.DATA[sectname].valtype.complete()
else:
if optname is None:
raise ValueError("optname may only be None for ValueList "
"sections, but {} is not!".format(sectname))
# Different type for each value (KeyValue)
vals = configdata.DATA[sectname][optname].typ.complete()
opt = configdata.DATA[optname]
default = str(opt.default or '""')
cur_cat = listcategory.ListCategory("Current/Default",
[(current, "Current value"), (default, "Default value")])
model.add_category(cur_cat)
vals = opt.typ.complete()
if vals is not None:
model.add_category(listcategory.ListCategory("Completions", vals))
return model
def bind(key):
"""A CompletionModel filled with all bindable commands and descriptions.
Args:
key: the key being bound.
"""
model = completionmodel.CompletionModel(column_widths=(20, 60, 20))
cmd_text = objreg.get('key-config').get_bindings_for('normal').get(key)
if cmd_text:
cmd_name = cmd_text.split(' ')[0]
cmd = cmdutils.cmd_dict.get(cmd_name)
data = [(cmd_text, cmd.desc, key)]
model.add_category(listcategory.ListCategory("Current", data))
#cmdlist = _get_cmd_completions(include_hidden=True, include_aliases=True)
#model.add_category(listcategory.ListCategory("Commands", cmdlist))
return model

View File

@ -39,7 +39,7 @@ class HistoryCategory(QSqlQueryModel):
# replace ' in timestamp-format to avoid breaking the query
timefmt = ("strftime('{}', last_atime, 'unixepoch', 'localtime')"
.format(config.get('completion', 'timestamp-format')
.format(config.val.completion.timestamp_format
.replace("'", "`")))
self._query = sql.Query(' '.join([
@ -58,7 +58,7 @@ class HistoryCategory(QSqlQueryModel):
def _atime_expr(self):
"""If max_items is set, return an expression to limit the query."""
max_items = config.get('completion', 'web-history-max-items')
max_items = config.val.completion.web_history_max_items
# HistoryCategory should not be added to the completion in that case.
assert max_items != 0

View File

@ -21,8 +21,8 @@
from qutebrowser.config import config, configdata
from qutebrowser.utils import objreg, log
from qutebrowser.commands import cmdutils
from qutebrowser.completion.models import completionmodel, listcategory
from qutebrowser.commands import cmdutils
def command():
@ -135,26 +135,6 @@ def buffer():
return model
def bind(key):
"""A CompletionModel filled with all bindable commands and descriptions.
Args:
key: the key being bound.
"""
model = completionmodel.CompletionModel(column_widths=(20, 60, 20))
cmd_text = objreg.get('key-config').get_bindings_for('normal').get(key)
if cmd_text:
cmd_name = cmd_text.split(' ')[0]
cmd = cmdutils.cmd_dict.get(cmd_name)
data = [(cmd_text, cmd.desc, key)]
model.add_category(listcategory.ListCategory("Current", data))
cmdlist = _get_cmd_completions(include_hidden=True, include_aliases=True)
model.add_category(listcategory.ListCategory("Commands", cmdlist))
return model
def _get_cmd_completions(include_hidden, include_aliases, prefix=''):
"""Get a list of completions info for commands, sorted by name.

View File

@ -230,6 +230,7 @@ class ConfigCommands:
@cmdutils.register(instance='config-commands', star_args_optional=True)
@cmdutils.argument('option', completion=configmodel.option)
@cmdutils.argument('values', completion=configmodel.value)
@cmdutils.argument('win_id', win_id=True)
def set(self, win_id, option=None, *values, temp=False, print_=False):
"""Set an option.
@ -310,7 +311,7 @@ class ConfigCommands:
@cmdutils.register(instance='config-commands', maxsplit=1,
no_cmd_split=True, no_replace_variables=True)
@cmdutils.argument('command', completion=usertypes.Completion.bind)
@cmdutils.argument('command', completion=configmodel.bind)
def bind(self, key, command=None, *, mode='normal', force=False):
"""Bind a key to a command.

View File

@ -30,7 +30,7 @@ from PyQt5.QtWidgets import QWidget, QVBoxLayout, QApplication, QSizePolicy
from qutebrowser.commands import runners, cmdutils
from qutebrowser.config import config
from qutebrowser.utils import (message, log, usertypes, qtutils, objreg, utils,
jinja)
jinja, debug)
from qutebrowser.mainwindow import tabbedbrowser, messageview, prompt
from qutebrowser.mainwindow.statusbar import bar
from qutebrowser.completion import completionwidget, completer

View File

@ -77,6 +77,7 @@ class MessageView(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self._messages = []
self._vbox = QVBoxLayout(self)
self._vbox.setContentsMargins(0, 0, 0, 0)
self._vbox.setSpacing(0)
@ -88,7 +89,6 @@ class MessageView(QWidget):
config.instance.changed.connect(self._set_clear_timer_interval)
self._last_text = None
self._messages = []
def sizeHint(self):
"""Get the proposed height for the view."""

View File

@ -21,7 +21,6 @@
"""Fake objects/stubs."""
import collections
from unittest import mock
from PyQt5.QtCore import pyqtSignal, QPoint, QProcess, QObject
@ -30,8 +29,7 @@ from PyQt5.QtNetwork import (QNetworkRequest, QAbstractNetworkCache,
from PyQt5.QtWidgets import QCommonStyle, QLineEdit, QWidget, QTabBar
from qutebrowser.browser import browsertab
from qutebrowser.config import configexc
from qutebrowser.utils import usertypes, utils
from qutebrowser.utils import usertypes
from qutebrowser.mainwindow import mainwindow

View File

@ -29,7 +29,7 @@ import pytest
from PyQt5.QtCore import QUrl
from qutebrowser.completion.models import miscmodels, urlmodel, configmodel
from qutebrowser.config import sections, value
from qutebrowser.config import sections, value, configdata, configtype
from qutebrowser.utils import objreg
@ -76,7 +76,8 @@ def _patch_cmdutils(monkeypatch, stubs, symbol):
def _patch_configdata(monkeypatch, stubs, symbol):
"""Patch the configdata module to provide fake data."""
data = collections.OrderedDict([
('general', sections.KeyValue(
('general.time', configdata.Option(
name='general.time'
('time',
value.SettingValue(stubs.FakeConfigType('fast', 'slow'),
default='slow'),
@ -141,8 +142,8 @@ def bookmarks(bookmark_manager_stub):
@pytest.fixture
def web_history(init_sql, stubs, config_stub):
"""Fixture which provides a web-history object."""
config_stub.data['completion'] = {'timestamp-format': '%Y-%m-%d',
'web-history-max-items': -1}
config_stub.completion.timestamp_format = '%Y-%m-%d'
config_stub.completion.web_history_max_items = -1
stub = history.WebHistory()
objreg.register('web-history', stub)
yield stub
@ -182,7 +183,7 @@ def test_command_completion(qtmodeltester, monkeypatch, stubs, config_stub,
"""
_patch_cmdutils(monkeypatch, stubs,
'qutebrowser.completion.models.miscmodels.cmdutils')
config_stub.data['aliases'] = {'rock': 'roll'}
config_stub.aliases = {'rock': 'roll'}
key_config_stub.set_bindings_for('normal', {'s': 'stop',
'rr': 'roll',
'ro': 'rock'})
@ -443,7 +444,7 @@ def test_url_completion_delete_history(qtmodeltester,
def test_url_completion_zero_limit(config_stub, web_history, quickmarks,
bookmarks):
"""Make sure there's no history if the limit was set to zero."""
config_stub.data['completion']['web-history-max-items'] = 0
config_stub.completion.web_history_max_items = 0
model = urlmodel.url()
model.set_pattern('')
category = model.index(2, 0) # "History" normally
@ -520,32 +521,9 @@ def test_tab_completion_delete(qtmodeltester, fake_web_tab, app_stub,
QUrl('https://duckduckgo.com')]
def test_setting_section_completion(qtmodeltester, monkeypatch, stubs):
def test_setting_option_completion(qtmodeltester, monkeypatch, stubs):
module = 'qutebrowser.completion.models.configmodel'
_patch_configdata(monkeypatch, stubs, module + '.configdata.DATA')
_patch_config_section_desc(monkeypatch, stubs,
module + '.configdata.SECTION_DESC')
model = configmodel.section()
model.set_pattern('')
qtmodeltester.data_display_may_return_none = True
qtmodeltester.check(model)
_check_completions(model, {
"Sections": [
('general', 'General/miscellaneous options.', None),
('searchengines', 'Definitions of search engines ...', None),
('ui', 'General options related to the user interface.', None),
]
})
def test_setting_option_completion(qtmodeltester, monkeypatch, stubs,
config_stub):
module = 'qutebrowser.completion.models.configmodel'
_patch_configdata(monkeypatch, stubs, module + '.configdata.DATA')
config_stub.data = {'ui': {'gesture': 'off',
'mind': 'on',
'voice': 'sometimes'}}
model = configmodel.option('ui')
model.set_pattern('')
qtmodeltester.data_display_may_return_none = True
@ -585,35 +563,6 @@ def test_setting_option_completion_valuelist(qtmodeltester, monkeypatch, stubs,
})
def test_setting_value_completion(qtmodeltester, monkeypatch, stubs,
config_stub):
module = 'qutebrowser.completion.models.configmodel'
_patch_configdata(monkeypatch, stubs, module + '.configdata.DATA')
config_stub.data = {'general': {'volume': '0'}}
model = configmodel.value('general', 'volume')
model.set_pattern('')
qtmodeltester.data_display_may_return_none = True
qtmodeltester.check(model)
_check_completions(model, {
"Current/Default": [
('0', 'Current value', None),
('11', 'Default value', None),
],
"Completions": [
('0', '', None),
('11', '', None),
]
})
def test_setting_value_completion_empty(monkeypatch, stubs, config_stub):
module = 'qutebrowser.completion.models.configmodel'
_patch_configdata(monkeypatch, stubs, module + '.configdata.DATA')
config_stub.data = {'general': {}}
assert configmodel.value('general', 'typo') is None
def test_bind_completion(qtmodeltester, monkeypatch, stubs, config_stub,
key_config_stub):
"""Test the results of keybinding command completion.