commit
0611dc0cb4
@ -28,6 +28,8 @@ Breaking changes
|
||||
- New dependency on ruamel.yaml; dropped PyYAML dependency.
|
||||
- The QtWebEngine backend is now used by default if available.
|
||||
- New config system which ignores the old config file.
|
||||
- The depedency on PyOpenGL (when using QtWebEngine) got removed. Note
|
||||
that PyQt5.QtOpenGL is still a dependency.
|
||||
|
||||
Major changes
|
||||
~~~~~~~~~~~~~
|
||||
|
@ -45,8 +45,8 @@ pointers:
|
||||
|
||||
* https://github.com/qutebrowser/qutebrowser/labels/easy[Issues which should
|
||||
be easy to solve]
|
||||
* https://github.com/qutebrowser/qutebrowser/labels/not%20code[Issues which
|
||||
require little/no coding]
|
||||
* https://github.com/qutebrowser/qutebrowser/labels/component%3A%20docs[Documentation
|
||||
* issues which require little/no coding]
|
||||
|
||||
If you prefer C++ or Javascript to Python, see the relevant issues which involve
|
||||
work in those languages:
|
||||
|
@ -118,7 +118,6 @@ The following software and libraries are required to run qutebrowser:
|
||||
* http://jinja.pocoo.org/[jinja2]
|
||||
* http://pygments.org/[pygments]
|
||||
* http://pyyaml.org/wiki/PyYAML[PyYAML]
|
||||
* http://pyopengl.sourceforge.net/[PyOpenGL] when using QtWebEngine
|
||||
|
||||
The following libraries are optional:
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
certifi==2017.4.17
|
||||
certifi==2017.7.27.1
|
||||
chardet==3.0.4
|
||||
codecov==2.0.9
|
||||
coverage==4.4.1
|
||||
idna==2.5
|
||||
requests==2.18.1
|
||||
urllib3==1.21.1
|
||||
requests==2.18.2
|
||||
urllib3==1.22
|
||||
|
@ -3,7 +3,7 @@
|
||||
flake8==2.6.2 # rq.filter: < 3.0.0
|
||||
flake8-copyright==0.2.0
|
||||
flake8-debugger==1.4.0 # rq.filter: != 2.0.0
|
||||
flake8-deprecated==1.2
|
||||
flake8-deprecated==1.2.1
|
||||
flake8-docstrings==1.0.3 # rq.filter: < 1.1.0
|
||||
flake8-future-import==0.4.3
|
||||
flake8-mock==0.3
|
||||
|
@ -3,6 +3,6 @@
|
||||
appdirs==1.4.3
|
||||
packaging==16.8
|
||||
pyparsing==2.2.0
|
||||
setuptools==36.2.0
|
||||
setuptools==36.2.5
|
||||
six==1.10.0
|
||||
wheel==0.29.0
|
||||
|
@ -1,7 +1,7 @@
|
||||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
-e git+https://github.com/PyCQA/astroid.git#egg=astroid
|
||||
certifi==2017.4.17
|
||||
certifi==2017.7.27.1
|
||||
chardet==3.0.4
|
||||
github3.py==0.9.6
|
||||
idna==2.5
|
||||
@ -10,9 +10,9 @@ lazy-object-proxy==1.3.1
|
||||
mccabe==0.6.1
|
||||
-e git+https://github.com/PyCQA/pylint.git#egg=pylint
|
||||
./scripts/dev/pylint_checkers
|
||||
requests==2.18.1
|
||||
requests==2.18.2
|
||||
six==1.10.0
|
||||
uritemplate==3.0.0
|
||||
uritemplate.py==3.0.2
|
||||
urllib3==1.21.1
|
||||
urllib3==1.22
|
||||
wrapt==1.10.10
|
||||
|
@ -1,7 +1,7 @@
|
||||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
astroid==1.5.3
|
||||
certifi==2017.4.17
|
||||
certifi==2017.7.27.1
|
||||
chardet==3.0.4
|
||||
github3.py==0.9.6
|
||||
idna==2.5
|
||||
@ -10,9 +10,9 @@ lazy-object-proxy==1.3.1
|
||||
mccabe==0.6.1
|
||||
pylint==1.7.2
|
||||
./scripts/dev/pylint_checkers
|
||||
requests==2.18.1
|
||||
requests==2.18.2
|
||||
six==1.10.0
|
||||
uritemplate==3.0.0
|
||||
uritemplate.py==3.0.2
|
||||
urllib3==1.21.1
|
||||
urllib3==1.22
|
||||
wrapt==1.10.10
|
||||
|
@ -5,14 +5,14 @@ cheroot==5.7.0
|
||||
click==6.7
|
||||
# colorama==0.3.9
|
||||
coverage==4.4.1
|
||||
decorator==4.1.1
|
||||
decorator==4.1.2
|
||||
EasyProcess==0.2.3
|
||||
fields==5.0.0
|
||||
Flask==0.12.2
|
||||
glob2==0.5
|
||||
httpbin==0.5.0
|
||||
hunter==1.4.1
|
||||
hypothesis==3.13.0
|
||||
hypothesis==3.14.0
|
||||
itsdangerous==0.24
|
||||
# Jinja2==2.9.6
|
||||
Mako==1.0.7
|
||||
@ -22,12 +22,12 @@ parse-type==0.3.4
|
||||
py==1.4.34
|
||||
pytest==3.1.3
|
||||
pytest-bdd==2.18.2
|
||||
pytest-benchmark==3.0.0
|
||||
pytest-benchmark==3.1.1
|
||||
pytest-catchlog==1.2.2
|
||||
pytest-cov==2.5.1
|
||||
pytest-faulthandler==1.3.1
|
||||
pytest-instafail==0.3.0
|
||||
pytest-mock==1.6.0
|
||||
pytest-mock==1.6.2
|
||||
pytest-qt==2.1.2
|
||||
pytest-repeat==0.4.1
|
||||
pytest-rerunfailures==2.2
|
||||
@ -35,5 +35,5 @@ pytest-travis-fold==1.2.0
|
||||
pytest-xvfb==1.0.0
|
||||
PyVirtualDisplay==0.2.1
|
||||
six==1.10.0
|
||||
vulture==0.16
|
||||
vulture==0.21
|
||||
Werkzeug==0.12.2
|
||||
|
@ -1,3 +1,3 @@
|
||||
# This file is automatically generated by scripts/dev/recompile_requirements.py
|
||||
|
||||
vulture==0.16
|
||||
vulture==0.21
|
||||
|
@ -1,5 +1,5 @@
|
||||
[pytest]
|
||||
addopts = --strict -rfEw --faulthandler-timeout=70 --instafail --pythonwarnings error
|
||||
addopts = --strict -rfEw --faulthandler-timeout=70 --instafail --pythonwarnings error --benchmark-columns=Min,Max,Median
|
||||
testpaths = tests
|
||||
markers =
|
||||
gui: Tests using the GUI (e.g. spawning widgets)
|
||||
|
@ -77,13 +77,9 @@ class UrlMarkManager(QObject):
|
||||
|
||||
Signals:
|
||||
changed: Emitted when anything changed.
|
||||
added: Emitted when a new quickmark/bookmark was added.
|
||||
removed: Emitted when an existing quickmark/bookmark was removed.
|
||||
"""
|
||||
|
||||
changed = pyqtSignal()
|
||||
added = pyqtSignal(str, str)
|
||||
removed = pyqtSignal(str)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
"""Initialize and read quickmarks."""
|
||||
@ -121,7 +117,6 @@ class UrlMarkManager(QObject):
|
||||
"""
|
||||
del self.marks[key]
|
||||
self.changed.emit()
|
||||
self.removed.emit(key)
|
||||
|
||||
|
||||
class QuickmarkManager(UrlMarkManager):
|
||||
@ -133,7 +128,6 @@ class QuickmarkManager(UrlMarkManager):
|
||||
- self.marks maps names to URLs.
|
||||
- changed gets emitted with the name as first argument and the URL as
|
||||
second argument.
|
||||
- removed gets emitted with the name as argument.
|
||||
"""
|
||||
|
||||
def _init_lineparser(self):
|
||||
@ -193,7 +187,6 @@ class QuickmarkManager(UrlMarkManager):
|
||||
"""Really set the quickmark."""
|
||||
self.marks[name] = url
|
||||
self.changed.emit()
|
||||
self.added.emit(name, url)
|
||||
log.misc.debug("Added quickmark {} for {}".format(name, url))
|
||||
|
||||
if name in self.marks:
|
||||
@ -243,7 +236,6 @@ class BookmarkManager(UrlMarkManager):
|
||||
- self.marks maps URLs to titles.
|
||||
- changed gets emitted with the URL as first argument and the title as
|
||||
second argument.
|
||||
- removed gets emitted with the URL as argument.
|
||||
"""
|
||||
|
||||
def _init_lineparser(self):
|
||||
@ -295,5 +287,4 @@ class BookmarkManager(UrlMarkManager):
|
||||
else:
|
||||
self.marks[urlstr] = title
|
||||
self.changed.emit()
|
||||
self.added.emit(title, urlstr)
|
||||
return True
|
||||
|
@ -28,6 +28,9 @@ Module attributes:
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import ctypes
|
||||
import ctypes.util
|
||||
|
||||
from PyQt5.QtGui import QFont
|
||||
from PyQt5.QtWebEngineWidgets import (QWebEngineSettings, QWebEngineProfile,
|
||||
@ -199,6 +202,11 @@ def init(args):
|
||||
if args.enable_webengine_inspector:
|
||||
os.environ['QTWEBENGINE_REMOTE_DEBUGGING'] = str(utils.random_port())
|
||||
|
||||
# WORKAROUND for
|
||||
# https://bugs.launchpad.net/ubuntu/+source/python-qt4/+bug/941826
|
||||
if sys.platform == 'linux':
|
||||
ctypes.CDLL(ctypes.util.find_library("GL"), mode=ctypes.RTLD_GLOBAL)
|
||||
|
||||
_init_profiles()
|
||||
|
||||
# We need to do this here as a WORKAROUND for
|
||||
|
@ -148,6 +148,8 @@ class CompletionView(QTreeView):
|
||||
|
||||
def _resize_columns(self):
|
||||
"""Resize the completion columns based on column_widths."""
|
||||
if self.model() is None:
|
||||
return
|
||||
width = self.size().width()
|
||||
column_widths = self.model().column_widths
|
||||
pixel_widths = [(width * perc // 100) for perc in column_widths]
|
||||
@ -253,6 +255,10 @@ class CompletionView(QTreeView):
|
||||
selmodel.setCurrentIndex(
|
||||
idx, QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Rows)
|
||||
|
||||
# if the last item is focused, try to fetch more
|
||||
if idx.row() == self.model().rowCount(idx.parent()) - 1:
|
||||
self.expandAll()
|
||||
|
||||
count = self.model().count()
|
||||
if count == 0:
|
||||
self.hide()
|
||||
|
@ -93,10 +93,12 @@ class HistoryCategory(QSqlQueryModel):
|
||||
self._query.run(pat=pattern)
|
||||
self.setQuery(self._query)
|
||||
|
||||
def removeRows(self, _row, _count, _parent=None):
|
||||
def removeRows(self, row, _count, _parent=None):
|
||||
"""Override QAbstractItemModel::removeRows to re-run sql query."""
|
||||
# re-run query to reload updated table
|
||||
with debug.log_time('sql', 'Re-running completion query post-delete'):
|
||||
self._query.run()
|
||||
self.setQuery(self._query)
|
||||
while self.rowCount() < row:
|
||||
self.fetchMore()
|
||||
return True
|
||||
|
@ -60,17 +60,33 @@ def helptopic():
|
||||
|
||||
def quickmark():
|
||||
"""A CompletionModel filled with all quickmarks."""
|
||||
def delete(data):
|
||||
"""Delete a quickmark from the completion menu."""
|
||||
name = data[0]
|
||||
quickmark_manager = objreg.get('quickmark-manager')
|
||||
log.completion.debug('Deleting quickmark {}'.format(name))
|
||||
quickmark_manager.delete(name)
|
||||
|
||||
model = completionmodel.CompletionModel(column_widths=(30, 70, 0))
|
||||
marks = objreg.get('quickmark-manager').marks.items()
|
||||
model.add_category(listcategory.ListCategory('Quickmarks', marks))
|
||||
model.add_category(listcategory.ListCategory('Quickmarks', marks,
|
||||
delete_func=delete))
|
||||
return model
|
||||
|
||||
|
||||
def bookmark():
|
||||
"""A CompletionModel filled with all bookmarks."""
|
||||
def delete(data):
|
||||
"""Delete a bookmark from the completion menu."""
|
||||
urlstr = data[0]
|
||||
log.completion.debug('Deleting bookmark {}'.format(urlstr))
|
||||
bookmark_manager = objreg.get('bookmark-manager')
|
||||
bookmark_manager.delete(urlstr)
|
||||
|
||||
model = completionmodel.CompletionModel(column_widths=(30, 70, 0))
|
||||
marks = objreg.get('bookmark-manager').marks.items()
|
||||
model.add_category(listcategory.ListCategory('Bookmarks', marks))
|
||||
model.add_category(listcategory.ListCategory('Bookmarks', marks,
|
||||
delete_func=delete))
|
||||
return model
|
||||
|
||||
|
||||
@ -126,11 +142,12 @@ def bind(key):
|
||||
key: the key being bound.
|
||||
"""
|
||||
model = completionmodel.CompletionModel(column_widths=(20, 60, 20))
|
||||
cmd_name = objreg.get('key-config').get_bindings_for('normal').get(key)
|
||||
cmd_text = objreg.get('key-config').get_bindings_for('normal').get(key)
|
||||
|
||||
if cmd_name:
|
||||
if cmd_text:
|
||||
cmd_name = cmd_text.split(' ')[0]
|
||||
cmd = cmdutils.cmd_dict.get(cmd_name)
|
||||
data = [(cmd_name, cmd.desc, key)]
|
||||
data = [(cmd_text, cmd.desc, key)]
|
||||
model.add_category(listcategory.ListCategory("Current", data))
|
||||
|
||||
cmdlist = _get_cmd_completions(include_hidden=True, include_aliases=True)
|
||||
|
@ -708,13 +708,16 @@ class TabbedBrowser(tabwidget.TabWidget):
|
||||
}
|
||||
msg = messages[status]
|
||||
|
||||
def show_error_page(html):
|
||||
tab.set_html(html)
|
||||
log.webview.error(msg)
|
||||
|
||||
if qtutils.version_check('5.9'):
|
||||
url_string = tab.url(requested=True).toDisplayString()
|
||||
error_page = jinja.render(
|
||||
'error.html', title="Error loading {}".format(url_string),
|
||||
url=url_string, error=msg, icon='')
|
||||
QTimer.singleShot(0, lambda: tab.set_html(error_page))
|
||||
log.webview.error(msg)
|
||||
QTimer.singleShot(100, lambda: show_error_page(error_page))
|
||||
else:
|
||||
# WORKAROUND for https://bugreports.qt.io/browse/QTBUG-58698
|
||||
message.error(msg)
|
||||
|
@ -36,7 +36,6 @@ import traceback
|
||||
import signal
|
||||
import importlib
|
||||
import datetime
|
||||
import logging
|
||||
try:
|
||||
import tkinter
|
||||
except ImportError:
|
||||
@ -344,12 +343,6 @@ def check_libraries(backend):
|
||||
modules['PyQt5.QtWebEngineWidgets'] = _missing_str("QtWebEngine",
|
||||
webengine=True)
|
||||
modules['PyQt5.QtOpenGL'] = _missing_str("PyQt5.QtOpenGL")
|
||||
# Workaround for a black screen with some setups
|
||||
# https://github.com/spyder-ide/spyder/issues/3226
|
||||
if not os.environ.get('QUTE_NO_OPENGL_WORKAROUND'):
|
||||
# Hide "No OpenGL_accelerate module loaded: ..." message
|
||||
logging.getLogger('OpenGL.acceleratesupport').propagate = False
|
||||
modules['OpenGL.GL'] = _missing_str("PyOpenGL")
|
||||
else:
|
||||
assert backend == 'webkit'
|
||||
modules['PyQt5.QtWebKit'] = _missing_str("PyQt5.QtWebKit")
|
||||
|
@ -23,7 +23,7 @@ import os
|
||||
import os.path
|
||||
|
||||
import sip
|
||||
from PyQt5.QtCore import pyqtSignal, QUrl, QObject, QPoint, QTimer
|
||||
from PyQt5.QtCore import QUrl, QObject, QPoint, QTimer
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
import yaml
|
||||
try:
|
||||
@ -106,14 +106,8 @@ class SessionManager(QObject):
|
||||
closed.
|
||||
_current: The name of the currently loaded session, or None.
|
||||
did_load: Set when a session was loaded.
|
||||
|
||||
Signals:
|
||||
update_completion: Emitted when the session completion should get
|
||||
updated.
|
||||
"""
|
||||
|
||||
update_completion = pyqtSignal()
|
||||
|
||||
def __init__(self, base_path, parent=None):
|
||||
super().__init__(parent)
|
||||
self._current = None
|
||||
@ -303,8 +297,7 @@ class SessionManager(QObject):
|
||||
encoding='utf-8', allow_unicode=True)
|
||||
except (OSError, UnicodeEncodeError, yaml.YAMLError) as e:
|
||||
raise SessionError(e)
|
||||
else:
|
||||
self.update_completion.emit()
|
||||
|
||||
if load_next_time:
|
||||
state_config = objreg.get('state-config')
|
||||
state_config['general']['session'] = name
|
||||
@ -425,7 +418,6 @@ class SessionManager(QObject):
|
||||
os.remove(path)
|
||||
except OSError as e:
|
||||
raise SessionError(e)
|
||||
self.update_completion.emit()
|
||||
|
||||
def list_sessions(self):
|
||||
"""Get a list of all session names."""
|
||||
|
@ -186,7 +186,6 @@ def _module_versions():
|
||||
('yaml', ['__version__']),
|
||||
('cssutils', ['__version__']),
|
||||
('typing', []),
|
||||
('OpenGL', ['__version__']),
|
||||
('PyQt5.QtWebEngineWidgets', []),
|
||||
('PyQt5.QtWebKitWidgets', []),
|
||||
])
|
||||
|
@ -7,4 +7,3 @@ MarkupSafe==1.0
|
||||
Pygments==2.2.0
|
||||
pyPEG2==2.15.2
|
||||
PyYAML==3.12
|
||||
PyOpenGL==3.1.0
|
||||
|
@ -89,6 +89,12 @@ def whitelist_generator():
|
||||
# vulture doesn't notice the hasattr() and thus thinks netrc_used is unused
|
||||
# in NetworkManager.on_authentication_required
|
||||
yield 'PyQt5.QtNetwork.QNetworkReply.netrc_used'
|
||||
yield 'qutebrowser.browser.downloads.last_used_directory'
|
||||
yield 'PaintContext.clip' # from completiondelegate.py
|
||||
yield 'logging.LogRecord.log_color' # from logging.py
|
||||
yield 'scripts.utils.use_color' # from asciidoc2html.py
|
||||
for attr in ['pyeval_output', 'log_clipboard', 'fake_clipboard']:
|
||||
yield 'qutebrowser.misc.utilcmds.' + attr
|
||||
|
||||
for attr in ['fileno', 'truncate', 'closed', 'readable']:
|
||||
yield 'qutebrowser.utils.qtutils.PyQIODevice.' + attr
|
||||
@ -111,7 +117,7 @@ def filter_func(item):
|
||||
True if the missing function should be filtered/ignored, False
|
||||
otherwise.
|
||||
"""
|
||||
return bool(re.match(r'[a-z]+[A-Z][a-zA-Z]+', str(item)))
|
||||
return bool(re.match(r'[a-z]+[A-Z][a-zA-Z]+', item.name))
|
||||
|
||||
|
||||
def report(items):
|
||||
@ -125,7 +131,7 @@ def report(items):
|
||||
relpath = os.path.relpath(item.filename)
|
||||
path = relpath if not relpath.startswith('..') else item.filename
|
||||
output.append("{}:{}: Unused {} '{}'".format(path, item.lineno,
|
||||
item.typ, item))
|
||||
item.typ, item.name))
|
||||
return output
|
||||
|
||||
|
||||
|
@ -65,6 +65,9 @@ def completionview(qtbot, status_command_stub, config_stub, win_registry,
|
||||
}
|
||||
# mock the Completer that the widget creates in its constructor
|
||||
mocker.patch('qutebrowser.completion.completer.Completer', autospec=True)
|
||||
mocker.patch(
|
||||
'qutebrowser.completion.completiondelegate.CompletionItemDelegate',
|
||||
new=lambda *_: None)
|
||||
view = completionwidget.CompletionView(win_id=0)
|
||||
qtbot.addWidget(view)
|
||||
return view
|
||||
@ -186,6 +189,37 @@ def test_completion_item_focus_no_model(which, completionview, qtbot):
|
||||
completionview.completion_item_focus(which)
|
||||
|
||||
|
||||
def test_completion_item_focus_fetch(completionview, qtbot):
|
||||
"""Test that on_next_prev_item moves the selection properly.
|
||||
|
||||
Args:
|
||||
which: the direction in which to move the selection.
|
||||
tree: Each list represents a completion category, with each string
|
||||
being an item under that category.
|
||||
expected: expected argument from on_selection_changed for each
|
||||
successive movement. None implies no signal should be
|
||||
emitted.
|
||||
"""
|
||||
model = completionmodel.CompletionModel()
|
||||
cat = mock.Mock(spec=['layoutChanged', 'layoutAboutToBeChanged',
|
||||
'canFetchMore', 'fetchMore', 'rowCount', 'index', 'data'])
|
||||
cat.canFetchMore = lambda *_: True
|
||||
cat.rowCount = lambda *_: 2
|
||||
cat.fetchMore = mock.Mock()
|
||||
model.add_category(cat)
|
||||
completionview.set_model(model)
|
||||
# clear the fetchMore call that happens on set_model
|
||||
cat.reset_mock()
|
||||
|
||||
# not at end, fetchMore shouldn't be called
|
||||
completionview.completion_item_focus('next')
|
||||
assert not cat.fetchMore.called
|
||||
|
||||
# at end, fetchMore should be called
|
||||
completionview.completion_item_focus('next')
|
||||
assert cat.fetchMore.called
|
||||
|
||||
|
||||
@pytest.mark.parametrize('show', ['always', 'auto', 'never'])
|
||||
@pytest.mark.parametrize('rows', [[], ['Aa'], ['Aa', 'Bb']])
|
||||
@pytest.mark.parametrize('quick_complete', [True, False])
|
||||
@ -240,3 +274,8 @@ def test_completion_item_del_no_selection(completionview):
|
||||
with pytest.raises(cmdexc.CommandError, match='No item selected!'):
|
||||
completionview.completion_item_del()
|
||||
assert not func.called
|
||||
|
||||
|
||||
def test_resize_no_model(completionview, qtbot):
|
||||
"""Ensure no crash if resizeEvent is triggered with no model (#2854)."""
|
||||
completionview.resizeEvent(None)
|
||||
|
@ -22,7 +22,6 @@
|
||||
import datetime
|
||||
|
||||
import pytest
|
||||
from PyQt5.QtCore import QModelIndex
|
||||
|
||||
from qutebrowser.misc import sql
|
||||
from qutebrowser.completion.models import histcategory
|
||||
@ -147,6 +146,22 @@ def test_remove_rows(hist, model_validator):
|
||||
model_validator.set_model(cat)
|
||||
cat.set_pattern('')
|
||||
hist.delete('url', 'foo')
|
||||
# histcategory does not care which index was removed, it just regenerates
|
||||
cat.removeRows(QModelIndex(), 1)
|
||||
cat.removeRows(0, 1)
|
||||
model_validator.validate([('bar', 'Bar', '')])
|
||||
|
||||
|
||||
def test_remove_rows_fetch(hist):
|
||||
"""removeRows should fetch enough data to make the current index valid."""
|
||||
# we cannot use model_validator as it will fetch everything up front
|
||||
hist.insert_batch({'url': [str(i) for i in range(300)]})
|
||||
cat = histcategory.HistoryCategory()
|
||||
cat.set_pattern('')
|
||||
|
||||
# sanity check that we didn't fetch everything up front
|
||||
assert cat.rowCount() < 300
|
||||
cat.fetchMore()
|
||||
assert cat.rowCount() == 300
|
||||
|
||||
hist.delete('url', '298')
|
||||
cat.removeRows(297, 1)
|
||||
assert cat.rowCount() == 299
|
||||
|
@ -252,6 +252,27 @@ def test_quickmark_completion(qtmodeltester, quickmarks):
|
||||
})
|
||||
|
||||
|
||||
@pytest.mark.parametrize('row, removed', [
|
||||
(0, 'aw'),
|
||||
(1, 'ddg'),
|
||||
(2, 'wiki'),
|
||||
])
|
||||
def test_quickmark_completion_delete(qtmodeltester, quickmarks, row, removed):
|
||||
"""Test deleting a quickmark from the quickmark completion model."""
|
||||
model = miscmodels.quickmark()
|
||||
model.set_pattern('')
|
||||
qtmodeltester.data_display_may_return_none = True
|
||||
qtmodeltester.check(model)
|
||||
|
||||
parent = model.index(0, 0)
|
||||
idx = model.index(row, 0, parent)
|
||||
|
||||
before = set(quickmarks.marks.keys())
|
||||
model.delete_cur_item(idx)
|
||||
after = set(quickmarks.marks.keys())
|
||||
assert before.difference(after) == {removed}
|
||||
|
||||
|
||||
def test_bookmark_completion(qtmodeltester, bookmarks):
|
||||
"""Test the results of bookmark completion."""
|
||||
model = miscmodels.bookmark()
|
||||
@ -268,6 +289,27 @@ def test_bookmark_completion(qtmodeltester, bookmarks):
|
||||
})
|
||||
|
||||
|
||||
@pytest.mark.parametrize('row, removed', [
|
||||
(0, 'http://qutebrowser.org'),
|
||||
(1, 'https://github.com'),
|
||||
(2, 'https://python.org'),
|
||||
])
|
||||
def test_bookmark_completion_delete(qtmodeltester, bookmarks, row, removed):
|
||||
"""Test deleting a quickmark from the quickmark completion model."""
|
||||
model = miscmodels.bookmark()
|
||||
model.set_pattern('')
|
||||
qtmodeltester.data_display_may_return_none = True
|
||||
qtmodeltester.check(model)
|
||||
|
||||
parent = model.index(0, 0)
|
||||
idx = model.index(row, 0, parent)
|
||||
|
||||
before = set(bookmarks.marks.keys())
|
||||
model.delete_cur_item(idx)
|
||||
after = set(bookmarks.marks.keys())
|
||||
assert before.difference(after) == {removed}
|
||||
|
||||
|
||||
def test_url_completion(qtmodeltester, web_history_populated,
|
||||
quickmarks, bookmarks):
|
||||
"""Test the results of url completion.
|
||||
@ -583,7 +625,7 @@ def test_bind_completion(qtmodeltester, monkeypatch, stubs, config_stub,
|
||||
_patch_cmdutils(monkeypatch, stubs,
|
||||
'qutebrowser.completion.models.miscmodels.cmdutils')
|
||||
config_stub.data['aliases'] = {'rock': 'roll'}
|
||||
key_config_stub.set_bindings_for('normal', {'s': 'stop',
|
||||
key_config_stub.set_bindings_for('normal', {'s': 'stop now',
|
||||
'rr': 'roll',
|
||||
'ro': 'rock'})
|
||||
model = miscmodels.bind('s')
|
||||
@ -593,14 +635,14 @@ def test_bind_completion(qtmodeltester, monkeypatch, stubs, config_stub,
|
||||
|
||||
_check_completions(model, {
|
||||
"Current": [
|
||||
('stop', 'stop qutebrowser', 's'),
|
||||
('stop now', 'stop qutebrowser', 's'),
|
||||
],
|
||||
"Commands": [
|
||||
('drop', 'drop all user data', ''),
|
||||
('hide', '', ''),
|
||||
('rock', "Alias for 'roll'", 'ro'),
|
||||
('roll', 'never gonna give you up', 'rr'),
|
||||
('stop', 'stop qutebrowser', 's'),
|
||||
('stop', 'stop qutebrowser', ''),
|
||||
]
|
||||
})
|
||||
|
||||
|
@ -215,11 +215,6 @@ class TestSave:
|
||||
objreg.delete('main-window', scope='window', window=0)
|
||||
objreg.delete('tabbed-browser', scope='window', window=0)
|
||||
|
||||
def test_update_completion_signal(self, sess_man, tmpdir, qtbot):
|
||||
session_path = tmpdir / 'foo.yml'
|
||||
with qtbot.waitSignal(sess_man.update_completion):
|
||||
sess_man.save(str(session_path))
|
||||
|
||||
def test_no_state_config(self, sess_man, tmpdir, state_config):
|
||||
session_path = tmpdir / 'foo.yml'
|
||||
sess_man.save(str(session_path))
|
||||
@ -367,14 +362,6 @@ class TestLoadTab:
|
||||
assert loaded_item.original_url == expected
|
||||
|
||||
|
||||
def test_delete_update_completion_signal(sess_man, qtbot, tmpdir):
|
||||
sess = tmpdir / 'foo.yml'
|
||||
sess.ensure()
|
||||
|
||||
with qtbot.waitSignal(sess_man.update_completion):
|
||||
sess_man.delete(str(sess))
|
||||
|
||||
|
||||
class TestListSessions:
|
||||
|
||||
def test_no_sessions(self, tmpdir):
|
||||
|
@ -495,7 +495,6 @@ class ImportFake:
|
||||
('yaml', True),
|
||||
('cssutils', True),
|
||||
('typing', True),
|
||||
('OpenGL', True),
|
||||
('PyQt5.QtWebEngineWidgets', True),
|
||||
('PyQt5.QtWebKitWidgets', True),
|
||||
])
|
||||
|
Loading…
Reference in New Issue
Block a user