Compare commits

...

16 Commits

Author SHA1 Message Date
Florian Bruhin
a90a894177 Release v1.0.4 2017-11-28 10:51:29 +01:00
Florian Bruhin
ce305b0fed Make pylint shut up
This is fixed in master, but it makes no sense to backport that.
2017-11-28 08:21:36 +01:00
Florian Bruhin
b19b8163e1 Handle sqlite errors during :history-clear
(cherry picked from commit ef1825efb0)
2017-11-28 07:05:23 +01:00
Florian Bruhin
203664a12c Add SQLITE_CORRUPT to environmental SQL errors
(cherry picked from commit 73587b1e16)
2017-11-28 07:05:21 +01:00
Florian Bruhin
cfe7e7883a Handle "out of memory" error in sql.init()
(cherry picked from commit 4fed8518e1)
2017-11-28 07:05:15 +01:00
Florian Bruhin
dfe74ff0ee Handle empty messages in qt_message_handler
I can't reproduce this, but someone on KDE reported always getting a crash (as
msg.splitlines()[0] gives an IndexError) when trying to select a file with
Qt 5.9.3.

(cherry picked from commit 67253726fa)
2017-11-26 17:32:05 +01:00
Florian Bruhin
18a45bbd5b Break long lines 2017-11-24 16:03:21 +01:00
Florian Bruhin
30462b3839 Fix overflow handling for QtWebKit scrolling
If we do "m * val / 100", the value gets bigger, so we need to check for an
overflow afterwards.
2017-11-24 16:02:50 +01:00
Florian Bruhin
1a7669c8a2 Ignore new Qt 5.9.3 error message
(cherry picked from commit 187554a1673553e907185f4ba146e717fc68b2ae)
2017-11-24 14:23:24 +01:00
Florian Bruhin
da5f8269c7 Update to PyQt 5.9.2
(cherry picked from commit 9174676deb777def6998f84f447f59ea7b968786)
2017-11-24 14:23:02 +01:00
Florian Bruhin
39353cdc00 Fix content.cache.size overflow with QtWebEngine
While 64-bit values are allowed with QtWebKit/QNetworkDiskCache, QtWebEngine
only allows 32-bit values here. With the updated sip's strict overflow checking,
that means we get an exception when setting a too big value.

(cherry picked from commit 203b6c354f)
2017-11-21 14:12:20 +01:00
Florian Bruhin
6edfd1801d Handle OSError in :config-write-py
(cherry picked from commit 4d0511597b01c3f445b877cbb47e655c7dd5434c)
2017-11-17 09:09:16 +01:00
Florian Bruhin
21364f135e Improve documentation for :hint --rapid
(cherry picked from commit 456c854f06)
2017-11-10 13:19:39 +01:00
cryzed
6f6eeae902 Ignore additional Qt error messages
(cherry picked from commit 222c51aa6e)
2017-11-10 09:42:53 +01:00
cryzed
c551922e2d Fix issue #3251
(cherry picked from commit 6e719d1796)
2017-11-10 09:42:51 +01:00
Florian Bruhin
f7585eb60e Fix qute://gpl
(cherry picked from commit 378b280f9a)
2017-11-06 12:14:44 +01:00
25 changed files with 138 additions and 31 deletions

View File

@@ -109,7 +109,7 @@ The following software and libraries are required to run qutebrowser:
link:https://github.com/annulen/webkit/wiki[updated fork] (5.212) is
supported
* http://www.riverbankcomputing.com/software/pyqt/intro[PyQt] 5.7.0 or newer
(5.9 recommended) for Python 3
(5.9.2 recommended) for Python 3
* https://pypi.python.org/pypi/setuptools/[pkg_resources/setuptools]
* http://fdik.org/pyPEG/[pyPEG2]
* http://jinja.pocoo.org/[jinja2]

View File

@@ -15,6 +15,19 @@ breaking changes (such as renamed commands) can happen in minor releases.
// `Fixed` for any bug fixes.
// `Security` to invite users to upgrade in case of vulnerabilities.
v1.0.4
------
Fixed
~~~~~
- The `qute://gpl` page now works correctly again.
- Trying to bind an empty command now doesn't crash anymore.
- Fixed crash when `:config-write-py` fails to write to the given path.
- Fixed crash for some users when selecting a file with Qt 5.9.3
- Improved handling for various SQL errors
- Fix crash when setting content.cache.size to a big value (> 2 GB)
v1.0.3
------

View File

@@ -486,7 +486,9 @@ Start hinting.
==== optional arguments
* +*-r*+, +*--rapid*+: Whether to do rapid hinting. This is only possible with targets `tab` (with `tabs.background_tabs=true`), `tab-bg`,
* +*-r*+, +*--rapid*+: Whether to do rapid hinting. With rapid hinting, the hint mode isn't left after a hint is followed, so you can easily
open multiple links. This is only possible with targets
`tab` (with `tabs.background_tabs=true`), `tab-bg`,
`window`, `run`, `hover`, `userscript` and `spawn`.
* +*-m*+, +*--mode*+: The hinting mode to use.

View File

@@ -1407,6 +1407,7 @@ This setting is only available with the QtWebKit backend.
[[content.cache.size]]
=== content.cache.size
Size of the HTTP network cache. Null to use the default value.
With QtWebEngine, the maximum supported value is 2147483647 (~2 GB).
Type: <<types,Int>>

View File

@@ -1,4 +1,4 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
PyQt5==5.9.1
sip==4.19.4
PyQt5==5.9.2
sip==4.19.6

View File

@@ -1 +1 @@
PyQt5
PyQt5

View File

@@ -55,4 +55,6 @@ qt_log_ignore =
^QQuickWidget::invalidateRenderControl could not make context current
^libpng warning: iCCP: known incorrect sRGB profile
^inotify_add_watch(".*") failed: "No space left on device"
^QSettings::value: Empty key passed
^Icon theme ".*" not found
xfail_strict = true

View File

@@ -26,7 +26,7 @@ __copyright__ = "Copyright 2014-2017 Florian Bruhin (The Compiler)"
__license__ = "GPL"
__maintainer__ = __author__
__email__ = "mail@qutebrowser.org"
__version_info__ = (1, 0, 3)
__version_info__ = (1, 0, 4)
__version__ = '.'.join(str(e) for e in __version_info__)
__description__ = "A keyboard-driven, vim-like browser based on PyQt5."

View File

@@ -616,8 +616,10 @@ class HintManager(QObject):
"""Start hinting.
Args:
rapid: Whether to do rapid hinting. This is only possible with
targets `tab` (with `tabs.background_tabs=true`), `tab-bg`,
rapid: Whether to do rapid hinting. With rapid hinting, the hint
mode isn't left after a hint is followed, so you can easily
open multiple links. This is only possible with targets
`tab` (with `tabs.background_tabs=true`), `tab-bg`,
`window`, `run`, `hover`, `userscript` and `spawn`.
add_history: Whether to add the spawned or yanked link to the
browsing history.

View File

@@ -21,6 +21,7 @@
import os
import time
import contextlib
from PyQt5.QtCore import pyqtSlot, QUrl, QTimer
@@ -87,6 +88,16 @@ class WebHistory(sql.SqlTable):
def __contains__(self, url):
return self._contains_query.run(val=url).value()
@contextlib.contextmanager
def _handle_sql_errors(self):
try:
yield
except sql.SqlError as e:
if e.environmental:
message.error("Failed to write history: {}".format(e.text()))
else:
raise
def _rebuild_completion(self):
data = {'url': [], 'title': [], 'last_atime': []}
# select the latest entry for each url
@@ -142,8 +153,9 @@ class WebHistory(sql.SqlTable):
"history?")
def _do_clear(self):
self.delete_all()
self.completion.delete_all()
with self._handle_sql_errors():
self.delete_all()
self.completion.delete_all()
def delete_url(self, url):
"""Remove all history entries with the given url.
@@ -191,7 +203,7 @@ class WebHistory(sql.SqlTable):
atime = int(atime) if (atime is not None) else int(time.time())
try:
with self._handle_sql_errors():
self.insert({'url': self._format_url(url),
'title': title,
'atime': atime,
@@ -202,11 +214,6 @@ class WebHistory(sql.SqlTable):
'title': title,
'last_atime': atime
}, replace=True)
except sql.SqlError as e:
if e.environmental:
message.error("Failed to write history: {}".format(e.text()))
else:
raise
def _parse_entry(self, line):
"""Parse a history line like '12345 http://example.com title'."""

View File

@@ -307,7 +307,7 @@ def qute_log(url):
@add_handler('gpl')
def qute_gpl(_url):
"""Handler for qute://gpl. Return HTML content as string."""
return 'text/html', utils.read_file('html/LICENSE.html')
return 'text/html', utils.read_file('html/license.html')
@add_handler('help')

View File

@@ -92,9 +92,10 @@ class DefaultProfileSetter(websettings.Base):
"""A setting set on the QWebEngineProfile."""
def __init__(self, setter, default=websettings.UNSET):
def __init__(self, setter, converter=None, default=websettings.UNSET):
super().__init__(default)
self._setter = setter
self._converter = converter
def __repr__(self):
return utils.get_repr(self, setter=self._setter, constructor=True)
@@ -103,7 +104,11 @@ class DefaultProfileSetter(websettings.Base):
if settings is not None:
raise ValueError("'settings' may not be set with "
"DefaultProfileSetters!")
setter = getattr(default_profile, self._setter)
if self._converter is not None:
value = self._converter(value)
setter(value)
@@ -281,7 +286,9 @@ MAPPINGS = {
Attribute(QWebEngineSettings.LocalStorageEnabled),
'content.cache.size':
# 0: automatically managed by QtWebEngine
DefaultProfileSetter('setHttpCacheMaximumSize', default=0),
DefaultProfileSetter('setHttpCacheMaximumSize', default=0,
converter=lambda val:
qtutils.check_overflow(val, 'int', fatal=False)),
'content.xss_auditing':
Attribute(QWebEngineSettings.XSSAuditingEnabled),
'content.default_encoding':

View File

@@ -422,12 +422,13 @@ class WebKitScroller(browsertab.AbstractScroller):
else:
for val, orientation in [(x, Qt.Horizontal), (y, Qt.Vertical)]:
if val is not None:
val = qtutils.check_overflow(val, 'int', fatal=False)
frame = self._widget.page().mainFrame()
m = frame.scrollBarMaximum(orientation)
if m == 0:
maximum = frame.scrollBarMaximum(orientation)
if maximum == 0:
continue
frame.setScrollBarValue(orientation, int(m * val / 100))
pos = int(maximum * val / 100)
pos = qtutils.check_overflow(pos, 'int', fatal=False)
frame.setScrollBarValue(orientation, pos)
def _key_press(self, key, count=1, getter_name=None, direction=None):
frame = self._widget.page().mainFrame()

View File

@@ -170,6 +170,11 @@ class KeyConfig:
def bind(self, key, command, *, mode, save_yaml=False):
"""Add a new binding from key to command."""
if command is not None and not command.strip():
raise configexc.KeybindingError(
"Can't add binding '{}' with empty command in {} "
'mode'.format(key, mode))
key = self._prepare(key, mode)
log.keyboard.vdebug("Adding binding {} -> {} in mode {}.".format(
key, command, mode))

View File

@@ -287,4 +287,7 @@ class ConfigCommands:
writer = configfiles.ConfigPyWriter(options, bindings,
commented=commented)
writer.write(filename)
try:
writer.write(filename)
except OSError as e:
raise cmdexc.CommandError(str(e))

View File

@@ -181,7 +181,10 @@ content.cache.size:
none_ok: true
minval: 0
maxval: maxint64
desc: Size of the HTTP network cache. Null to use the default value.
desc: >-
Size of the HTTP network cache. Null to use the default value.
With QtWebEngine, the maximum supported value is 2147483647 (~2 GB).
# Defaults from QWebSettings::QWebSettings() in
# qtwebkit/Source/WebKit/qt/Api/qwebsettings.cpp

View File

@@ -70,9 +70,21 @@ class SqliteError(SqlError):
environmental_errors = [
'5', # SQLITE_BUSY ("database is locked")
'8', # SQLITE_READONLY
'11', # SQLITE_CORRUPT
'13', # SQLITE_FULL
]
self.environmental = error.nativeErrorCode() in environmental_errors
# At least in init(), we can get errors like this:
# type: ConnectionError
# database text: out of memory
# driver text: Error opening database
# error code: -1
environmental_strings = [
"out of memory",
]
errcode = error.nativeErrorCode()
self.environmental = (
errcode in environmental_errors or
(errcode == -1 and error.databaseText() in environmental_strings))
def text(self):
return self.error.databaseText()

View File

@@ -327,7 +327,8 @@ def change_console_formatter(level):
console_handler.setFormatter(console_formatter)
def qt_message_handler(msg_type, context, msg):
def qt_message_handler(msg_type, context, # pylint: disable=too-many-branches
msg):
"""Qt message handler to redirect qWarning etc. to the logging system.
Args:
@@ -421,6 +422,9 @@ def qt_message_handler(msg_type, context, msg):
'with: -9805', # flake8: disable=E131
]
if not msg:
msg = "Logged empty message!"
if any(msg.strip().startswith(pattern) for pattern in suppressed_msgs):
level = logging.DEBUG
else:

View File

@@ -209,3 +209,9 @@ Feature: Special qute:// pages
Scenario: Open qute://version
When I open qute://version
Then the page should contain the plaintext "Version info"
# qute://gpl
Scenario: Open qute://gpl
When I open qute://gpl
Then the page should contain the plaintext "GNU GENERAL PUBLIC LICENSE"

View File

@@ -141,6 +141,12 @@ def is_ignored_chromium_message(line):
# channel message
'Invalid node channel message',
# Qt 5.9.3
# [30217:30229:1124/141512.682110:ERROR:
# cert_verify_proc_openssl.cc(212)]
# X509 Verification error self signed certificate : 18 : 0 : 4
'X509 Verification error self signed certificate : 18 : 0 : 4',
# Not reproducible anymore?
'Running without the SUID sandbox! *',

View File

@@ -285,6 +285,12 @@ class TestKeyConfig:
key_config_stub.unbind('a')
assert key_config_stub.get_command('a', mode='normal') is None
def test_empty_command(self, key_config_stub):
"""Try binding a key to an empty command."""
message = "Can't add binding 'x' with empty command in normal mode"
with pytest.raises(configexc.KeybindingError, match=message):
key_config_stub.bind('x', ' ', mode='normal')
class TestConfig:

View File

@@ -406,6 +406,11 @@ class TestWritePy:
lines = confpy.read_text('utf-8').splitlines()
assert '# Autogenerated config.py' in lines
def test_oserror(self, commands, tmpdir):
"""Test writing to a directory which does not exist."""
with pytest.raises(cmdexc.CommandError):
commands.config_write_py(str(tmpdir / 'foo' / 'config.py'))
class TestBind:

View File

@@ -25,12 +25,15 @@ import itertools
import sys
import warnings
import attr
import pytest
import pytest_catchlog
from qutebrowser.utils import log
from qutebrowser.misc import utilcmds
from PyQt5 import QtCore
@pytest.fixture(autouse=True)
def restore_loggers():
@@ -252,3 +255,22 @@ def test_ignore_py_warnings(caplog):
assert len(caplog.records) == 1
msg = caplog.records[0].message.splitlines()[0]
assert msg.endswith("UserWarning: not hidden")
class TestQtMessageHandler:
@attr.s
class Context:
"""Fake QMessageLogContext."""
function = attr.ib(default=None)
category = attr.ib(default=None)
file = attr.ib(default=None)
line = attr.ib(default=None)
def test_empty_message(self, caplog):
"""Make sure there's no crash with an empty message."""
log.qt_message_handler(QtCore.QtDebugMsg, self.Context(), "")
assert len(caplog.records) == 1
assert caplog.records[0].msg == "Logged empty message!"

View File

@@ -86,7 +86,7 @@ setenv =
passenv = {[testenv]passenv}
deps =
{[testenv]deps}
PyQt5==5.9
PyQt5==5.9.2
commands = {envpython} -bb -m pytest {posargs:tests}
[testenv:py36-pyqt59]
@@ -97,7 +97,7 @@ setenv =
passenv = {[testenv]passenv}
deps =
{[testenv]deps}
PyQt5==5.9
PyQt5==5.9.2
commands = {envpython} -bb -m pytest {posargs:tests}
# test envs with coverage
@@ -110,7 +110,7 @@ setenv =
passenv = {[testenv]passenv}
deps =
{[testenv]deps}
PyQt5==5.9
PyQt5==5.9.2
commands =
{envpython} -bb -m pytest --cov --cov-report xml --cov-report=html --cov-report= {posargs:tests}
{envpython} scripts/dev/check_coverage.py {posargs}
@@ -123,7 +123,7 @@ setenv =
passenv = {[testenv]passenv}
deps =
{[testenv]deps}
PyQt5==5.9
PyQt5==5.9.2
commands =
{envpython} -bb -m pytest --cov --cov-report xml --cov-report=html --cov-report= {posargs:tests}
{envpython} scripts/dev/check_coverage.py {posargs}