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

View File

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

View File

@ -19,78 +19,61 @@
"""Functions that return config-related completion models.""" """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.completion.models import completionmodel, listcategory
from qutebrowser.utils import objreg from qutebrowser.utils import objreg
from qutebrowser.commands import cmdutils
def section(): def option():
"""A CompletionModel filled with settings sections.""" """A CompletionModel filled with settings and their descriptions."""
model = completionmodel.CompletionModel(column_widths=(20, 70, 10)) model = completionmodel.CompletionModel(column_widths=(30, 70, 0))
sections = ((name, configdata.SECTION_DESC[name].splitlines()[0].strip()) options = [(x.name, x.description) for x in configdata.DATA.values()]
for name in configdata.DATA) model.add_category(listcategory.ListCategory("Options", options))
model.add_category(listcategory.ListCategory("Sections", sections))
return model return model
def option(sectname): def value(optname, *values):
"""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):
"""A CompletionModel filled with setting values. """A CompletionModel filled with setting values.
Args: Args:
sectname: The name of the config section this model shows.
optname: The name of the config option 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)) model = completionmodel.CompletionModel(column_widths=(30, 70, 0))
config = objreg.get('config')
try: try:
current = config.get(sectname, optname, raw=True) or '""' current = str(config.instance.get(optname) or '""')
except (configexc.NoSectionError, configexc.NoOptionError): except configexc.NoOptionError:
return None return None
default = configdata.DATA[sectname][optname].default() or '""' opt = configdata.DATA[optname]
default = str(opt.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()
cur_cat = listcategory.ListCategory("Current/Default", cur_cat = listcategory.ListCategory("Current/Default",
[(current, "Current value"), (default, "Default value")]) [(current, "Current value"), (default, "Default value")])
model.add_category(cur_cat) model.add_category(cur_cat)
vals = opt.typ.complete()
if vals is not None: if vals is not None:
model.add_category(listcategory.ListCategory("Completions", vals)) model.add_category(listcategory.ListCategory("Completions", vals))
return model 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 # replace ' in timestamp-format to avoid breaking the query
timefmt = ("strftime('{}', last_atime, 'unixepoch', 'localtime')" timefmt = ("strftime('{}', last_atime, 'unixepoch', 'localtime')"
.format(config.get('completion', 'timestamp-format') .format(config.val.completion.timestamp_format
.replace("'", "`"))) .replace("'", "`")))
self._query = sql.Query(' '.join([ self._query = sql.Query(' '.join([
@ -58,7 +58,7 @@ class HistoryCategory(QSqlQueryModel):
def _atime_expr(self): def _atime_expr(self):
"""If max_items is set, return an expression to limit the query.""" """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. # HistoryCategory should not be added to the completion in that case.
assert max_items != 0 assert max_items != 0

View File

@ -21,8 +21,8 @@
from qutebrowser.config import config, configdata from qutebrowser.config import config, configdata
from qutebrowser.utils import objreg, log from qutebrowser.utils import objreg, log
from qutebrowser.commands import cmdutils
from qutebrowser.completion.models import completionmodel, listcategory from qutebrowser.completion.models import completionmodel, listcategory
from qutebrowser.commands import cmdutils
def command(): def command():
@ -135,26 +135,6 @@ def buffer():
return model 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=''): def _get_cmd_completions(include_hidden, include_aliases, prefix=''):
"""Get a list of completions info for commands, sorted by name. """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.register(instance='config-commands', star_args_optional=True)
@cmdutils.argument('option', completion=configmodel.option) @cmdutils.argument('option', completion=configmodel.option)
@cmdutils.argument('values', completion=configmodel.value)
@cmdutils.argument('win_id', win_id=True) @cmdutils.argument('win_id', win_id=True)
def set(self, win_id, option=None, *values, temp=False, print_=False): def set(self, win_id, option=None, *values, temp=False, print_=False):
"""Set an option. """Set an option.
@ -310,7 +311,7 @@ class ConfigCommands:
@cmdutils.register(instance='config-commands', maxsplit=1, @cmdutils.register(instance='config-commands', maxsplit=1,
no_cmd_split=True, no_replace_variables=True) 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): def bind(self, key, command=None, *, mode='normal', force=False):
"""Bind a key to a command. """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.commands import runners, cmdutils
from qutebrowser.config import config from qutebrowser.config import config
from qutebrowser.utils import (message, log, usertypes, qtutils, objreg, utils, from qutebrowser.utils import (message, log, usertypes, qtutils, objreg, utils,
jinja) jinja, debug)
from qutebrowser.mainwindow import tabbedbrowser, messageview, prompt from qutebrowser.mainwindow import tabbedbrowser, messageview, prompt
from qutebrowser.mainwindow.statusbar import bar from qutebrowser.mainwindow.statusbar import bar
from qutebrowser.completion import completionwidget, completer from qutebrowser.completion import completionwidget, completer

View File

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

View File

@ -21,7 +21,6 @@
"""Fake objects/stubs.""" """Fake objects/stubs."""
import collections
from unittest import mock from unittest import mock
from PyQt5.QtCore import pyqtSignal, QPoint, QProcess, QObject 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 PyQt5.QtWidgets import QCommonStyle, QLineEdit, QWidget, QTabBar
from qutebrowser.browser import browsertab from qutebrowser.browser import browsertab
from qutebrowser.config import configexc from qutebrowser.utils import usertypes
from qutebrowser.utils import usertypes, utils
from qutebrowser.mainwindow import mainwindow from qutebrowser.mainwindow import mainwindow

View File

@ -29,7 +29,7 @@ import pytest
from PyQt5.QtCore import QUrl from PyQt5.QtCore import QUrl
from qutebrowser.completion.models import miscmodels, urlmodel, configmodel 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 from qutebrowser.utils import objreg
@ -76,7 +76,8 @@ def _patch_cmdutils(monkeypatch, stubs, symbol):
def _patch_configdata(monkeypatch, stubs, symbol): def _patch_configdata(monkeypatch, stubs, symbol):
"""Patch the configdata module to provide fake data.""" """Patch the configdata module to provide fake data."""
data = collections.OrderedDict([ data = collections.OrderedDict([
('general', sections.KeyValue( ('general.time', configdata.Option(
name='general.time'
('time', ('time',
value.SettingValue(stubs.FakeConfigType('fast', 'slow'), value.SettingValue(stubs.FakeConfigType('fast', 'slow'),
default='slow'), default='slow'),
@ -141,8 +142,8 @@ def bookmarks(bookmark_manager_stub):
@pytest.fixture @pytest.fixture
def web_history(init_sql, stubs, config_stub): def web_history(init_sql, stubs, config_stub):
"""Fixture which provides a web-history object.""" """Fixture which provides a web-history object."""
config_stub.data['completion'] = {'timestamp-format': '%Y-%m-%d', config_stub.completion.timestamp_format = '%Y-%m-%d'
'web-history-max-items': -1} config_stub.completion.web_history_max_items = -1
stub = history.WebHistory() stub = history.WebHistory()
objreg.register('web-history', stub) objreg.register('web-history', stub)
yield stub yield stub
@ -182,7 +183,7 @@ def test_command_completion(qtmodeltester, monkeypatch, stubs, config_stub,
""" """
_patch_cmdutils(monkeypatch, stubs, _patch_cmdutils(monkeypatch, stubs,
'qutebrowser.completion.models.miscmodels.cmdutils') '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', key_config_stub.set_bindings_for('normal', {'s': 'stop',
'rr': 'roll', 'rr': 'roll',
'ro': 'rock'}) 'ro': 'rock'})
@ -443,7 +444,7 @@ def test_url_completion_delete_history(qtmodeltester,
def test_url_completion_zero_limit(config_stub, web_history, quickmarks, def test_url_completion_zero_limit(config_stub, web_history, quickmarks,
bookmarks): bookmarks):
"""Make sure there's no history if the limit was set to zero.""" """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 = urlmodel.url()
model.set_pattern('') model.set_pattern('')
category = model.index(2, 0) # "History" normally 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')] 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' module = 'qutebrowser.completion.models.configmodel'
_patch_configdata(monkeypatch, stubs, module + '.configdata.DATA') _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 = configmodel.option('ui')
model.set_pattern('') model.set_pattern('')
qtmodeltester.data_display_may_return_none = True 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, def test_bind_completion(qtmodeltester, monkeypatch, stubs, config_stub,
key_config_stub): key_config_stub):
"""Test the results of keybinding command completion. """Test the results of keybinding command completion.