summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.flake86
-rw-r--r--.github/workflows/ci.yml5
-rw-r--r--.mypy.ini2
-rw-r--r--.travis.yml4
-rw-r--r--README.asciidoc3
-rw-r--r--doc/changelog.asciidoc8
-rw-r--r--doc/contributing.asciidoc2
-rw-r--r--doc/install.asciidoc24
-rw-r--r--misc/requirements/requirements-tests.txt15
-rw-r--r--misc/requirements/requirements-tests.txt-raw13
-rw-r--r--qutebrowser/browser/browsertab.py7
-rw-r--r--qutebrowser/browser/qutescheme.py15
-rw-r--r--qutebrowser/browser/webengine/webenginetab.py12
-rw-r--r--qutebrowser/browser/webkit/mhtml.py5
-rw-r--r--qutebrowser/browser/webkit/webkittab.py7
-rw-r--r--qutebrowser/commands/command.py23
-rw-r--r--qutebrowser/config/configtypes.py37
-rw-r--r--qutebrowser/misc/checkpyver.py4
-rw-r--r--qutebrowser/misc/earlyinit.py2
-rw-r--r--qutebrowser/utils/debug.py5
-rw-r--r--qutebrowser/utils/utils.py11
-rwxr-xr-xsetup.py3
-rw-r--r--tests/end2end/test_invocations.py9
-rw-r--r--tests/unit/browser/webkit/test_mhtml.py5
-rw-r--r--tests/unit/config/test_configtypes.py32
-rw-r--r--tests/unit/misc/test_checkpyver.py11
-rw-r--r--tests/unit/utils/test_urlmatch.py7
-rw-r--r--tox.ini1
28 files changed, 91 insertions, 187 deletions
diff --git a/.flake8 b/.flake8
index e913647f9..573d0856f 100644
--- a/.flake8
+++ b/.flake8
@@ -38,6 +38,7 @@ exclude = .*,__pycache__,resources.py
# D413: Missing blank line after last section (not in pep257?)
# A003: Builtin name for class attribute (needed for overridden methods)
# W504: line break after binary operator
+# FI15: __future__ import "generator_stop" missing
ignore =
B001,B008,B305,
E128,E226,E265,E501,E402,E266,E722,E731,
@@ -46,8 +47,9 @@ ignore =
P101,P102,P103,
D102,D103,D106,D107,D104,D105,D209,D211,D401,D402,D403,D412,D413,
A003,
- W504
-min-version = 3.4.0
+ W504,
+ FI15
+min-version = 3.6.0
max-complexity = 12
per-file-ignores =
qutebrowser/api/hook.py : N801
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 828b9a739..d950494eb 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -100,11 +100,6 @@ jobs:
fail-fast: false
matrix:
include:
- ### PyQt 5.7.1 (Python 3.5)
- # - testenv: py35-pyqt57
- # os: ubuntu-16.04
- # python: 3.5
- # experimental: true
### PyQt 5.9 (Python 3.6)
- testenv: py36-pyqt59
os: ubuntu-18.04
diff --git a/.mypy.ini b/.mypy.ini
index 6295d4ebc..dfef7d3e5 100644
--- a/.mypy.ini
+++ b/.mypy.ini
@@ -1,6 +1,4 @@
[mypy]
-# We also need to support 3.5, but if we'd chose that here, we'd need to deal
-# with conditional imports (like secrets.py).
python_version = 3.6
# --strict
diff --git a/.travis.yml b/.travis.yml
index 9a56a756c..b75081477 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,8 +1,8 @@
dist: xenial
language: python
-python: 3.5
+python: 3.6
os: linux
-env: TESTENV=py35-pyqt57
+env: TESTENV=py36-pyqt57
install:
- python -m pip install -U pip
diff --git a/README.asciidoc b/README.asciidoc
index 48bf61ca3..42dd8f034 100644
--- a/README.asciidoc
+++ b/README.asciidoc
@@ -109,8 +109,7 @@ Requirements
The following software and libraries are required to run qutebrowser:
-* https://www.python.org/[Python] 3.5.2 or newer (3.6 - 3.8 recommended;
- support for 3.5 will be dropped with qutebrowser v2.0.0)
+* https://www.python.org/[Python] 3.6 or newer
* https://www.qt.io/[Qt] 5.7.1 or newer (5.14 recommended; support for < 5.11
will be dropped with qutebrowser v2.0.0) with the following modules:
- QtCore / qtbase
diff --git a/doc/changelog.asciidoc b/doc/changelog.asciidoc
index 1db13b0b2..42698c6a9 100644
--- a/doc/changelog.asciidoc
+++ b/doc/changelog.asciidoc
@@ -18,6 +18,14 @@ breaking changes (such as renamed commands) can happen in minor releases.
v2.0.0 (unreleased)
-------------------
+Major changes
+~~~~~~~~~~~~~
+
+- At least Python 3.6 is now required to run qutebrowser, support for Python
+ 3.5 is dropped. Note that Python 3.5 is
+ https://www.python.org/downloads/release/python-3510/[no longer supported
+ upstream] since September 2020.
+
Changed
~~~~~~~
diff --git a/doc/contributing.asciidoc b/doc/contributing.asciidoc
index 6fc54ae5d..b8c9b9010 100644
--- a/doc/contributing.asciidoc
+++ b/doc/contributing.asciidoc
@@ -111,7 +111,7 @@ unittests and several linters/checkers.
Currently, the following tox environments are available:
* Tests using https://www.pytest.org[pytest]:
- - `py35`, `py36`: Run pytest for python 3.5/3.6 with the system-wide PyQt.
+ - `py36`, `py37`, ...: Run pytest for python 3.6/3.7/... with the system-wide PyQt.
- `py36-pyqt57`, ..., `py36-pyqt59`: Run pytest with the given PyQt version (`py35-*` also works).
- `py36-pyqt59-cov`: Run with coverage support (other Python/PyQt versions work too).
* `flake8`: Run various linting checks via https://pypi.python.org/pypi/flake8[flake8].
diff --git a/doc/install.asciidoc b/doc/install.asciidoc
index ec0710c08..9c71bf2b5 100644
--- a/doc/install.asciidoc
+++ b/doc/install.asciidoc
@@ -32,10 +32,17 @@ Ubuntu 16.04 LTS / Linux Mint 18
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Ubuntu 16.04 doesn't come with an up-to-date engine (a new enough QtWebKit, or
-QtWebEngine). However, it comes with Python 3.5, so you can
-<<tox,install qutebrowser in a virtualenv>>.
+QtWebEngine). It also comes with Python 3.5 which is not supported anymore since
+qutebrowser v2.0.0.
-You'll need some basic libraries to use the virtualenv-installed PyQt:
+You should be able to install a newer Python (3.6+) using the
+https://launchpad.net/~deadsnakes/+archive/ubuntu/ppa[deadsnakes PPA] or
+https://github.com/pyenv/pyenv[pyenv], and then proceed to
+<<tox,install qutebrowser in a virtualenv>>. However, this is currently untested. If you
+got this setup to work successfully, please submit a pull request to adjust these
+instructions!
+
+Note you'll need some basic libraries to use the virtualenv-installed PyQt:
----
# apt install --no-install-recommends git ca-certificates python3 python3-venv asciidoc libglib2.0-0 libgl1 libfontconfig1 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-shape0 libxcb-xfixes0 libxcb-xinerama0 libxcb-xkb1 libxkbcommon-x11-0 libdbus-1-3 libyaml-dev gcc python3-dev
@@ -44,12 +51,6 @@ You'll need some basic libraries to use the virtualenv-installed PyQt:
// FIXME not needed anymore?
// libxi6 libxrender1 libegl1-mesa
-NOTE: Support for Python 3.5 will be dropped with the qutebrowser v2.0.0
-release, preliminarily planned for late 2020. At that point, you will need to
-either upgrade to a newer Ubuntu release, or use something like the
-https://launchpad.net/~deadsnakes/+archive/ubuntu/ppa[deadsnakes PPA] or
-https://github.com/pyenv/pyenv[pyenv] to install a newer Python.
-
Debian Stretch
~~~~~~~~~~~~~~
@@ -439,9 +440,8 @@ This installs all needed Python dependencies in a `.venv` subfolder
This comes with an up-to-date Qt/PyQt including a pre-compiled QtWebEngine
binary, but has a few caveats:
-- Make sure your `python3` is Python 3.5 or newer, otherwise you'll get a "No
- matching distribution found" error. Note that qutebrowser itself also requires
- this.
+- Make sure your `python3` is Python 3.6 or newer, otherwise you'll get a "No
+ matching distribution found" error and/or qutebrowser will not run.
- It only works on 64-bit x86 systems, with other architectures you'll get the
same error.
- It comes with a QtWebEngine compiled without proprietary codec support (such
diff --git a/misc/requirements/requirements-tests.txt b/misc/requirements/requirements-tests.txt
index 3136d5d90..066f4c4db 100644
--- a/misc/requirements/requirements-tests.txt
+++ b/misc/requirements/requirements-tests.txt
@@ -15,12 +15,12 @@ filelock==3.0.12
Flask==1.1.2
glob2==0.7
hunter==3.3.1
-hypothesis==5.38.0 ; python_version>="3.6"
-icdiff==1.9.1 ; python_version>="3.6"
+hypothesis==5.38.0
+icdiff==1.9.1
idna==2.10
iniconfig==1.1.1
itsdangerous==1.1.0
-jaraco.functools==3.0.1 ; python_version>="3.6"
+jaraco.functools==3.0.1
# Jinja2==2.11.2
Mako==1.1.3
manhole==1.6.0
@@ -30,7 +30,7 @@ packaging==20.4
parse==1.18.0
parse-type==0.5.2
pluggy==0.13.1
-pprintpp==0.4.0 ; python_version>="3.6"
+pprintpp==0.4.0
py==1.9.0
py-cpuinfo==7.0.0
Pygments==2.7.2
@@ -41,7 +41,7 @@ pytest-benchmark==3.2.3
pytest-clarity==0.3.0a0
pytest-cov==2.10.1
pytest-forked==1.3.0
-pytest-icdiff==0.5 ; python_version>="3.6"
+pytest-icdiff==0.5
pytest-instafail==0.4.2
pytest-mock==3.3.1
pytest-qt==3.3.0
@@ -59,8 +59,5 @@ termcolor==1.1.0
tldextract==3.0.2
toml==0.10.1
urllib3==1.25.11
-vulture==2.1 ; python_version>="3.6"
+vulture==2.1
Werkzeug==1.0.1
-jaraco.functools==2.0; python_version<"3.6"
-vulture==1.6; python_version<"3.6"
-hypothesis<5.34.0; python_version<"3.6"
diff --git a/misc/requirements/requirements-tests.txt-raw b/misc/requirements/requirements-tests.txt-raw
index 1ab0fd842..fd346d475 100644
--- a/misc/requirements/requirements-tests.txt-raw
+++ b/misc/requirements/requirements-tests.txt-raw
@@ -34,17 +34,4 @@ pytest-clarity
# Needed to test misc/userscripts/qute-lastpass
tldextract
-#@ markers: pytest-icdiff python_version>="3.6"
-#@ markers: icdiff python_version>="3.6"
-#@ markers: pprintpp python_version>="3.6"
-
-#@ markers: jaraco.functools python_version>="3.6"
-#@ add: jaraco.functools==2.0; python_version<"3.6"
-
-#@ markers: vulture python_version>="3.6"
-#@ add: vulture==1.6; python_version<"3.6"
-
-#@ markers: hypothesis python_version>="3.6"
-#@ add: hypothesis<5.34.0; python_version<"3.6"
-
#@ ignore: Jinja2, MarkupSafe, colorama
diff --git a/qutebrowser/browser/browsertab.py b/qutebrowser/browser/browsertab.py
index 4501ba4aa..1d248b61d 100644
--- a/qutebrowser/browser/browsertab.py
+++ b/qutebrowser/browser/browsertab.py
@@ -465,6 +465,7 @@ class AbstractCaret(QObject):
follow_selected_done = pyqtSignal()
def __init__(self,
+ tab: 'AbstractTab',
mode_manager: modeman.ModeManager,
parent: QWidget = None) -> None:
super().__init__(parent)
@@ -472,7 +473,7 @@ class AbstractCaret(QObject):
self._mode_manager = mode_manager
mode_manager.entered.connect(self._on_mode_entered)
mode_manager.left.connect(self._on_mode_left)
- # self._tab is set by subclasses so mypy knows its concrete type.
+ self._tab = tab
def _on_mode_entered(self, mode: usertypes.KeyMode) -> None:
raise NotImplementedError
@@ -715,9 +716,9 @@ class AbstractElements:
[typing.Optional['webelem.AbstractWebElement']], None]
_ErrorCallback = typing.Callable[[Exception], None]
- def __init__(self) -> None:
+ def __init__(self, tab: 'AbstractTab') -> None:
self._widget = typing.cast(QWidget, None)
- # self._tab is set by subclasses so mypy knows its concrete type.
+ self._tab = tab
def find_css(self, selector: str,
callback: _MultiCallback,
diff --git a/qutebrowser/browser/qutescheme.py b/qutebrowser/browser/qutescheme.py
index b661f533d..47a54d2a5 100644
--- a/qutebrowser/browser/qutescheme.py
+++ b/qutebrowser/browser/qutescheme.py
@@ -31,16 +31,10 @@ import time
import textwrap
import urllib
import collections
-import base64
import typing
+import secrets
from typing import TypeVar, Callable, Union, Tuple
-try:
- import secrets
-except ImportError:
- # New in Python 3.6
- secrets = None # type: ignore[assignment]
-
from PyQt5.QtCore import QUrlQuery, QUrl, qVersion
import qutebrowser
@@ -449,12 +443,7 @@ def qute_settings(url: QUrl) -> _HandlerRet:
# Requests to qute://settings/set should only be allowed from
# qute://settings. As an additional security precaution, we generate a CSRF
# token to use here.
- if secrets:
- csrf_token = secrets.token_urlsafe()
- else:
- # On Python < 3.6, from secrets.py
- token = base64.urlsafe_b64encode(os.urandom(32))
- csrf_token = token.rstrip(b'=').decode('ascii')
+ csrf_token = secrets.token_urlsafe()
src = jinja.render('settings.html', title='settings',
configdata=configdata,
diff --git a/qutebrowser/browser/webengine/webenginetab.py b/qutebrowser/browser/webengine/webenginetab.py
index fec87acaf..21d1615b6 100644
--- a/qutebrowser/browser/webengine/webenginetab.py
+++ b/qutebrowser/browser/webengine/webenginetab.py
@@ -41,7 +41,6 @@ from qutebrowser.browser.webengine import (webview, webengineelem, tabhistory,
from qutebrowser.misc import miscwidgets, objects, quitter
from qutebrowser.utils import (usertypes, qtutils, log, javascript, utils,
message, objreg, jinja, debug)
-from qutebrowser.keyinput import modeman
from qutebrowser.qt import sip
@@ -356,12 +355,7 @@ class WebEngineCaret(browsertab.AbstractCaret):
"""QtWebEngine implementations related to moving the cursor/selection."""
- def __init__(self,
- tab: 'WebEngineTab',
- mode_manager: modeman.ModeManager,
- parent: QWidget = None) -> None:
- super().__init__(mode_manager, parent)
- self._tab = tab
+ _tab: 'WebEngineTab'
def _flags(self):
"""Get flags to pass to JS."""
@@ -786,9 +780,7 @@ class WebEngineElements(browsertab.AbstractElements):
"""QtWebEngine implemementations related to elements on the page."""
- def __init__(self, tab: 'WebEngineTab') -> None:
- super().__init__()
- self._tab = tab
+ _tab: 'WebEngineTab'
def _js_cb_multiple(self, callback, error_cb, js_elems):
"""Handle found elements coming from JS and call the real callback.
diff --git a/qutebrowser/browser/webkit/mhtml.py b/qutebrowser/browser/webkit/mhtml.py
index a045e10f2..11906e600 100644
--- a/qutebrowser/browser/webkit/mhtml.py
+++ b/qutebrowser/browser/webkit/mhtml.py
@@ -90,10 +90,7 @@ def _get_css_imports_cssutils(data, inline=False):
"""
try:
import cssutils
- except (ImportError, re.error):
- # Catching re.error because cssutils in earlier releases (<= 1.0) is
- # broken on Python 3.5
- # See https://bitbucket.org/cthedot/cssutils/issues/52
+ except ImportError:
return None
# We don't care about invalid CSS data, this will only litter the log
diff --git a/qutebrowser/browser/webkit/webkittab.py b/qutebrowser/browser/webkit/webkittab.py
index d26975d46..2d0f01212 100644
--- a/qutebrowser/browser/webkit/webkittab.py
+++ b/qutebrowser/browser/webkit/webkittab.py
@@ -201,8 +201,7 @@ class WebKitCaret(browsertab.AbstractCaret):
tab: 'WebKitTab',
mode_manager: modeman.ModeManager,
parent: QWidget = None) -> None:
- super().__init__(mode_manager, parent)
- self._tab = tab
+ super().__init__(tab, mode_manager, parent)
self._selection_state = browsertab.SelectionState.none
@pyqtSlot(usertypes.KeyMode)
@@ -693,9 +692,7 @@ class WebKitElements(browsertab.AbstractElements):
"""QtWebKit implemementations related to elements on the page."""
- def __init__(self, tab: 'WebKitTab') -> None:
- super().__init__()
- self._tab = tab
+ _tab: 'WebKitTab'
def find_css(self, selector, callback, error_cb, *, only_visible=False):
utils.unused(error_cb)
diff --git a/qutebrowser/commands/command.py b/qutebrowser/commands/command.py
index 2672fcd68..715bf4972 100644
--- a/qutebrowser/commands/command.py
+++ b/qutebrowser/commands/command.py
@@ -406,22 +406,19 @@ class Command:
raise TypeError("{}: Legacy tuple type annotation!".format(
self.name))
- if hasattr(typing, 'UnionMeta'):
- # Python 3.5.2
- # pylint: disable=no-member,useless-suppression
- is_union = isinstance(
- typ, typing.UnionMeta) # type: ignore[attr-defined]
- else:
- is_union = getattr(typ, '__origin__', None) is typing.Union
+ try:
+ origin = typing.get_origin(typ) # type: ignore[attr-defined]
+ except AttributeError:
+ # typing.get_origin was added in Python 3.8
+ origin = getattr(typ, '__origin__', None)
- if is_union:
- # this is... slightly evil, I know
+ if origin is typing.Union:
try:
- types = list(typ.__args__)
+ types = list(typing.get_args(typ)) # type: ignore[attr-defined]
except AttributeError:
- # Python 3.5.2
- types = list(typ.__union_params__)
- # pylint: enable=no-member,useless-suppression
+ # typing.get_args was added in Python 3.8
+ types = list(typ.__args__)
+
if param.default is not inspect.Parameter.empty:
types.append(type(param.default))
choices = self.get_arg_info(param).choices
diff --git a/qutebrowser/config/configtypes.py b/qutebrowser/config/configtypes.py
index 75148947e..a20514a4b 100644
--- a/qutebrowser/config/configtypes.py
+++ b/qutebrowser/config/configtypes.py
@@ -47,7 +47,6 @@ import html
import codecs
import os.path
import itertools
-import warnings
import functools
import operator
import json
@@ -1317,32 +1316,16 @@ class Regex(BaseType):
(getattr(re, flag.strip()) for flag in flags.split(' | ')))
def _compile_regex(self, pattern: str) -> typing.Pattern[str]:
- """Check if the given regex is valid.
-
- This is more complicated than it could be since there's a warning on
- invalid escapes with newer Python versions, and we want to catch that
- case and treat it as invalid.
- """
- with warnings.catch_warnings(record=True) as recorded_warnings:
- warnings.simplefilter('always')
- try:
- compiled = re.compile(pattern, self.flags)
- except re.error as e:
- raise configexc.ValidationError(
- pattern, "must be a valid regex - " + str(e))
- except RuntimeError: # pragma: no cover
- raise configexc.ValidationError(
- pattern, "must be a valid regex - recursion depth "
- "exceeded")
-
- assert recorded_warnings is not None
-
- for w in recorded_warnings:
- if (issubclass(w.category, DeprecationWarning) and
- str(w.message).startswith('bad escape')):
- raise configexc.ValidationError(
- pattern, "must be a valid regex - " + str(w.message))
- warnings.warn(w.message)
+ """Check if the given regex is valid."""
+ try:
+ compiled = re.compile(pattern, self.flags)
+ except re.error as e:
+ raise configexc.ValidationError(
+ pattern, "must be a valid regex - " + str(e))
+ except RuntimeError: # pragma: no cover
+ raise configexc.ValidationError(
+ pattern, "must be a valid regex - recursion depth "
+ "exceeded")
return compiled
diff --git a/qutebrowser/misc/checkpyver.py b/qutebrowser/misc/checkpyver.py
index 8283dd13e..116514b8d 100644
--- a/qutebrowser/misc/checkpyver.py
+++ b/qutebrowser/misc/checkpyver.py
@@ -43,11 +43,11 @@ except ImportError: # pragma: no cover
# to stderr.
def check_python_version():
"""Check if correct python version is run."""
- if sys.hexversion < 0x03050200:
+ if sys.hexversion < 0x03060000:
# We don't use .format() and print_function here just in case someone
# still has < 2.6 installed.
version_str = '.'.join(map(str, sys.version_info[:3]))
- text = ("At least Python 3.5.2 is required to run qutebrowser, but " +
+ text = ("At least Python 3.6 is required to run qutebrowser, but " +
"it's running with " + version_str + ".\n")
if (Tk and # type: ignore[unreachable]
'--no-err-windows' not in sys.argv): # pragma: no cover
diff --git a/qutebrowser/misc/earlyinit.py b/qutebrowser/misc/earlyinit.py
index 1594bdec6..b5bfcb1db 100644
--- a/qutebrowser/misc/earlyinit.py
+++ b/qutebrowser/misc/earlyinit.py
@@ -19,7 +19,7 @@
"""Things which need to be done really early (e.g. before importing Qt).
-At this point we can be sure we have all python 3.5 features available.
+At this point we can be sure we have all python 3.6 features available.
"""
try:
diff --git a/qutebrowser/utils/debug.py b/qutebrowser/utils/debug.py
index 24968e4f0..e25252d1c 100644
--- a/qutebrowser/utils/debug.py
+++ b/qutebrowser/utils/debug.py
@@ -310,11 +310,8 @@ class log_time: # noqa: N801,N806 pylint: disable=invalid-name
def __enter__(self) -> None:
self._started = datetime.datetime.now()
- # The string annotation is a WORKAROUND for a Python 3.5.2 bug:
- # https://github.com/python/typing/issues/266
-
def __exit__(self,
- _exc_type: 'typing.Optional[typing.Type[BaseException]]',
+ _exc_type: typing.Optional[typing.Type[BaseException]],
_exc_val: typing.Optional[BaseException],
_exc_tb: typing.Optional[types.TracebackType]) -> None:
assert self._started is not None
diff --git a/qutebrowser/utils/utils.py b/qutebrowser/utils/utils.py
index d7d2a0ecb..fcfd26846 100644
--- a/qutebrowser/utils/utils.py
+++ b/qutebrowser/utils/utils.py
@@ -485,12 +485,13 @@ def qualname(obj: typing.Any) -> str:
return repr(obj)
-# The string annotation is a WORKAROUND for a Python 3.5.2 bug:
-# https://github.com/python/typing/issues/266
+_ExceptionType = typing.Union[
+ typing.Type[BaseException],
+ typing.Tuple[typing.Type[BaseException]]
+]
-def raises(exc: ('typing.Union[' # pylint: disable=bad-docstring-quotes
- ' typing.Type[BaseException], '
- ' typing.Tuple[typing.Type[BaseException]]]'),
+
+def raises(exc: _ExceptionType,
func: typing.Callable,
*args: typing.Any) -> bool:
"""Check if a function raises a given exception.
diff --git a/setup.py b/setup.py
index 0c0bf73b4..1169eae81 100755
--- a/setup.py
+++ b/setup.py
@@ -72,7 +72,7 @@ try:
['qutebrowser = qutebrowser.qutebrowser:main']},
zip_safe=True,
install_requires=['pypeg2', 'jinja2', 'pygments', 'PyYAML', 'attrs'],
- python_requires='>=3.5',
+ python_requires='>=3.6',
name='qutebrowser',
version=_get_constant('version'),
description=_get_constant('description'),
@@ -94,7 +94,6 @@ try:
'Operating System :: MacOS',
'Operating System :: POSIX :: BSD',
'Programming Language :: Python :: 3',
- 'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
diff --git a/tests/end2end/test_invocations.py b/tests/end2end/test_invocations.py
index cd9aefe16..3e8731fad 100644
--- a/tests/end2end/test_invocations.py
+++ b/tests/end2end/test_invocations.py
@@ -333,16 +333,17 @@ def test_command_on_start(request, quteproc_new):
quteproc_new.wait_for_quit()
-def test_launching_with_python2():
+@pytest.mark.parametrize('python', ['python2', 'python3.5'])
+def test_launching_with_old_python(python):
try:
proc = subprocess.run(
- ['python2', '-m', 'qutebrowser', '--no-err-windows'],
+ [python, '-m', 'qutebrowser', '--no-err-windows'],
stderr=subprocess.PIPE,
check=False)
except FileNotFoundError:
- pytest.skip("python2 not found")
+ pytest.skip(f"{python} not found")
assert proc.returncode == 1
- error = "At least Python 3.5.2 is required to run qutebrowser"
+ error = "At least Python 3.6 is required to run qutebrowser"
assert proc.stderr.decode('ascii').startswith(error)
diff --git a/tests/unit/browser/webkit/test_mhtml.py b/tests/unit/browser/webkit/test_mhtml.py
index 8d4289f4b..58e5602b3 100644
--- a/tests/unit/browser/webkit/test_mhtml.py
+++ b/tests/unit/browser/webkit/test_mhtml.py
@@ -29,10 +29,7 @@ mhtml = pytest.importorskip('qutebrowser.browser.webkit.mhtml')
try:
import cssutils
-except (ImportError, re.error):
- # Catching re.error because cssutils in earlier releases (<= 1.0) is
- # broken on Python 3.5
- # See https://bitbucket.org/cthedot/cssutils/issues/52
+except ImportError:
cssutils = None
diff --git a/tests/unit/config/test_configtypes.py b/tests/unit/config/test_configtypes.py
index b28b001d9..ec2e4072f 100644
--- a/tests/unit/config/test_configtypes.py
+++ b/tests/unit/config/test_configtypes.py
@@ -1482,27 +1482,13 @@ class TestRegex:
@pytest.mark.parametrize('val', [
pytest.param(r'(foo|bar))?baz[fis]h', id='unmatched parens'),
pytest.param('(' * 500, id='too many parens'),
+ r'foo\Xbar',
+ r'foo\Cbar',
])
def test_to_py_invalid(self, klass, val):
with pytest.raises(configexc.ValidationError):
klass().to_py(val)
- @pytest.mark.parametrize('val', [
- r'foo\Xbar',
- r'foo\Cbar',
- ])
- def test_to_py_maybe_valid(self, klass, val):
- """Those values are valid on some Python versions (and systems?).
-
- On others, they raise a DeprecationWarning because of an invalid
- escape. This tests makes sure this gets translated to a
- ValidationError.
- """
- try:
- klass().to_py(val)
- except configexc.ValidationError:
- pass
-
@pytest.mark.parametrize('warning', [
Warning('foo'), DeprecationWarning('foo'),
])
@@ -1518,20 +1504,6 @@ class TestRegex:
with pytest.raises(type(warning)):
regex.to_py('foo')
- def test_bad_pattern_warning(self, mocker, klass):
- """Test a simulated bad pattern warning.
-
- This only seems to happen with Python 3.5, so we simulate this for
- better coverage.
- """
- regex = klass()
- m = mocker.patch('qutebrowser.config.configtypes.re')
- m.compile.side_effect = lambda *args: warnings.warn(r'bad escape \C',
- DeprecationWarning)
- m.error = re.error
- with pytest.raises(configexc.ValidationError):
- regex.to_py('foo')
-
@pytest.mark.parametrize('flags, expected', [
(None, 0),
('IGNORECASE', re.IGNORECASE),
diff --git a/tests/unit/misc/test_checkpyver.py b/tests/unit/misc/test_checkpyver.py
index 5202efd07..2d4da12e8 100644
--- a/tests/unit/misc/test_checkpyver.py
+++ b/tests/unit/misc/test_checkpyver.py
@@ -28,21 +28,22 @@ import pytest
from qutebrowser.misc import checkpyver
-TEXT = (r"At least Python 3.5.2 is required to run qutebrowser, but it's "
+TEXT = (r"At least Python 3.6 is required to run qutebrowser, but it's "
r"running with \d+\.\d+\.\d+.")
@pytest.mark.not_frozen
-def test_python2():
- """Run checkpyver with python 2."""
+@pytest.mark.parametrize('python', ['python2', 'python3.5'])
+def test_old_python(python):
+ """Run checkpyver with old python versions."""
try:
proc = subprocess.run(
- ['python2', checkpyver.__file__, '--no-err-windows'],
+ [python, checkpyver.__file__, '--no-err-windows'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
check=False)
except FileNotFoundError:
- pytest.skip("python2 not found")
+ pytest.skip(f"{python} not found")
assert not proc.stdout
stderr = proc.stderr.decode('utf-8').rstrip()
assert re.fullmatch(TEXT, stderr), stderr
diff --git a/tests/unit/utils/test_urlmatch.py b/tests/unit/utils/test_urlmatch.py
index 8292a09ad..c38794c40 100644
--- a/tests/unit/utils/test_urlmatch.py
+++ b/tests/unit/utils/test_urlmatch.py
@@ -28,7 +28,6 @@ Currently not tested:
- Any other features we don't need, such as .GetAsString() or set operations.
"""
-import sys
import string
import pytest
@@ -89,11 +88,7 @@ from qutebrowser.utils import urlmatch
("http://foo:/", "Invalid port: Port is empty"),
("http://*.foo:/", "Invalid port: Port is empty"),
("http://foo:com/", "Invalid port: .* 'com'"),
- pytest.param("http://foo:123456/",
- "Invalid port: Port out of range 0-65535",
- marks=pytest.mark.skipif(
- sys.hexversion < 0x03060000,
- reason="Doesn't show an error on Python 3.5")),
+ ("http://foo:123456/", "Invalid port: Port out of range 0-65535"),
("http://foo:80:80/monkey", "Invalid port: .* '80:80'"),
("chrome://foo:1234/bar", "Ports are unsupported with chrome scheme"),
# No port specified, but port separator.
diff --git a/tox.ini b/tox.ini
index a25374672..bfc1f2b49 100644
--- a/tox.ini
+++ b/tox.ini
@@ -18,7 +18,6 @@ setenv =
passenv = PYTHON DISPLAY XAUTHORITY HOME USERNAME USER CI XDG_* QUTE_* DOCKER QT_QUICK_BACKEND PY_COLORS
basepython =
py3: {env:PYTHON:python3}
- py35: {env:PYTHON:python3.5}
py36: {env:PYTHON:python3.6}
py37: {env:PYTHON:python3.7}
py38: {env:PYTHON:python3.8}