Refactor qtutils.version_check API

Fixes #2423
This commit is contained in:
Florian Bruhin 2017-03-08 08:41:18 +01:00
parent ac0409c60d
commit f86f9cd92a
7 changed files with 54 additions and 43 deletions

View File

@ -38,8 +38,7 @@ disable=no-self-use,
suppressed-message,
too-many-return-statements,
duplicate-code,
wrong-import-position,
too-many-boolean-expressions
wrong-import-position
[BASIC]
function-rgx=[a-z_][a-z0-9_]{2,50}$

View File

@ -34,7 +34,6 @@ import sys
import faulthandler
import traceback
import signal
import operator
import importlib
import pkg_resources
import datetime
@ -264,14 +263,14 @@ def check_qt_version(backend):
"""Check if the Qt version is recent enough."""
from PyQt5.QtCore import PYQT_VERSION, PYQT_VERSION_STR
from qutebrowser.utils import qtutils, version
if (qtutils.version_check('5.2.0', operator.lt, strict=True) or
if (not qtutils.version_check('5.2.0', strict=True) or
PYQT_VERSION < 0x050200):
text = ("Fatal error: Qt and PyQt >= 5.2.0 are required, but Qt {} / "
"PyQt {} is installed.".format(version.qt_version(),
PYQT_VERSION_STR))
_die(text)
elif (backend == 'webengine' and (
qtutils.version_check('5.7.1', operator.lt, strict=True) or
not qtutils.version_check('5.7.1', strict=True) or
PYQT_VERSION < 0x050700)):
text = ("Fatal error: Qt >= 5.7.1 and PyQt >= 5.7 are required for "
"QtWebEngine support, but Qt {} / PyQt {} is installed."

View File

@ -262,7 +262,7 @@ class WrapperLayout(QLayout):
self._widget = widget
container.setFocusProxy(widget)
widget.setParent(container)
if (qtutils.version_check('5.8.0', op=operator.eq) and
if (qtutils.version_check('5.8.0', exact=True) and
objects.backend == usertypes.Backend.QtWebEngine and
container.window() and
container.window().windowHandle() and

View File

@ -80,20 +80,22 @@ class QtOSError(OSError):
self.qt_errno = None
def version_check(version, op=operator.ge, strict=False):
def version_check(version, exact=False, strict=False):
"""Check if the Qt runtime version is the version supplied or newer.
Args:
version: The version to check against.
op: The operator to use for the check.
exact: if given, check with == instead of >=
strict: If given, also check the compiled Qt version.
"""
if strict:
assert op in [operator.ge, operator.lt], op
# Catch code using the old API for this
assert exact not in [operator.gt, operator.lt, operator.ge, operator.le,
operator.eq], exact
parsed = pkg_resources.parse_version(version)
op = operator.eq if exact else operator.ge
result = op(pkg_resources.parse_version(qVersion()), parsed)
if ((strict and op == operator.ge and result) or
(strict and op == operator.lt and not result)):
if strict and result:
# v1 ==/>= parsed, now check if v2 ==/>= parsed too.
result = op(pkg_resources.parse_version(QT_VERSION_STR), parsed)
return result
@ -160,7 +162,10 @@ def get_args(namespace):
def check_print_compat():
"""Check if printing should work in the given Qt version."""
# WORKAROUND (remove this when we bump the requirements to 5.3.0)
return not (os.name == 'nt' and version_check('5.3.0', operator.lt))
if os.name == 'nt':
return version_check('5.3')
else:
return True
def ensure_valid(obj):

View File

@ -169,7 +169,7 @@ def actute_warning():
return
# Qt >= 5.3 doesn't seem to be affected
try:
if qtutils.version_check('5.3.0'):
if qtutils.version_check('5.3'):
return
except ValueError: # pragma: no cover
pass

View File

@ -68,7 +68,7 @@ def _get_version_tag(tag):
"""
version_re = re.compile(r"""
(?P<package>qt|pyqt)
(?P<operator>==|>|>=|<|<=|!=)
(?P<operator>==|>=|!=)
(?P<version>\d+\.\d+(\.\d+)?)
""", re.VERBOSE)
@ -76,23 +76,24 @@ def _get_version_tag(tag):
if not match:
return None
operators = {
'==': operator.eq,
'>': operator.gt,
'<': operator.lt,
'>=': operator.ge,
'<=': operator.le,
'!=': operator.ne,
}
package = match.group('package')
op = operators[match.group('operator')]
version = match.group('version')
if package == 'qt':
return pytest.mark.skipif(not qtutils.version_check(version, op),
reason='Needs ' + tag)
op = match.group('operator')
do_skip = {
'==': qtutils.version_check(version, exact=True),
'>=': qtutils.version_check(version),
'!=': not qtutils.version_check(version, exact=True),
}
return pytest.mark.skipif(do_skip[op], reason='Needs ' + tag)
elif package == 'pyqt':
operators = {
'==': operator.eq,
'>=': operator.ge,
'!=': operator.ne,
}
op = operators[match.group('operator')]
major, minor, patch = [int(e) for e in version.split('.')]
hex_version = (major << 16) | (minor << 8) | patch
return pytest.mark.skipif(not op(PYQT_VERSION, hex_version),

View File

@ -42,21 +42,28 @@ from qutebrowser.utils import qtutils
import overflow_test_cases
@pytest.mark.parametrize('qversion, compiled, version, op, expected', [
('5.4.0', None, '5.4.0', operator.ge, True),
('5.4.0', None, '5.4.0', operator.eq, True),
('5.4.0', None, '5.4', operator.eq, True),
('5.4.1', None, '5.4', operator.ge, True),
('5.3.2', None, '5.4', operator.ge, False),
('5.3.0', None, '5.3.2', operator.ge, False),
# strict=True
('5.4.0', '5.3.0', '5.4.0', operator.ge, False),
('5.4.0', '5.4.0', '5.4.0', operator.ge, True),
('5.4.0', '5.3.0', '5.4.0', operator.lt, True),
('5.4.0', '5.4.0', '5.4.0', operator.lt, False),
@pytest.mark.parametrize('qversion, compiled, version, exact, expected', [
# equal versions
('5.4.0', None, '5.4.0', False, True),
('5.4.0', None, '5.4.0', True, True), # exact=True
('5.4.0', None, '5.4', True, True), # without trailing 0
# newer version installed
('5.4.1', None, '5.4', False, True),
('5.4.1', None, '5.4', True, False), # exact=True
# older version installed
('5.3.2', None, '5.4', False, False),
('5.3.0', None, '5.3.2', False, False),
('5.3.0', None, '5.3.2', True, False), # exact=True
# strict
('5.4.0', '5.3.0', '5.4.0', False, False),
('5.4.0', '5.4.0', '5.4.0', False, True),
# strict and exact=True
('5.4.0', '5.5.0', '5.4.0', True, False),
('5.5.0', '5.4.0', '5.4.0', True, False),
('5.4.0', '5.4.0', '5.4.0', True, True),
])
def test_version_check(monkeypatch, qversion, compiled, version, op, expected):
def test_version_check(monkeypatch, qversion, compiled, version, exact,
expected):
"""Test for version_check().
Args:
@ -64,7 +71,7 @@ def test_version_check(monkeypatch, qversion, compiled, version, op, expected):
qversion: The version to set as fake qVersion().
compiled: The value for QT_VERSION_STR (set strict=True)
version: The version to compare with.
op: The operator to use when comparing.
exact: Use exact comparing (==)
expected: The expected result.
"""
monkeypatch.setattr(qtutils, 'qVersion', lambda: qversion)
@ -74,7 +81,7 @@ def test_version_check(monkeypatch, qversion, compiled, version, op, expected):
else:
strict = False
assert qtutils.version_check(version, op, strict=strict) == expected
assert qtutils.version_check(version, exact, strict=strict) == expected
@pytest.mark.parametrize('version, ng', [