From 5a78bffb153b4f992d40afbb24cfde5107a1c117 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Thu, 24 Sep 2020 14:37:52 +0200 Subject: Update similar project list --- README.asciidoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'README.asciidoc') diff --git a/README.asciidoc b/README.asciidoc index 6f4bf2a4a..48bf61ca3 100644 --- a/README.asciidoc +++ b/README.asciidoc @@ -218,11 +218,11 @@ Active * https://fanglingsu.github.io/vimb/[vimb] (C, GTK+ with WebKit2) * https://luakit.github.io/luakit/[luakit] (C/Lua, GTK+ with WebKit2) -* https://surf.suckless.org/[surf] (C, GTK+ with WebKit1/WebKit2) * https://nyxt.atlas.engineer/[Nyxt browser] (formerly "Next browser", Lisp, Emacs-like but also offers Vim bindings, QtWebKit or GTK+/WebKit2 - note there was a http://jgkamat.gitlab.io/blog/next-rce.html[critical remote code execution] which was handled quite badly) * https://vieb.dev/[Vieb] (JavaScript, Electron) * Chrome/Chromium addons: https://vimium.github.io/[Vimium], + https://github.com/dcchambers/vb4c[vb4c] (fork of cVim) * Firefox addons (based on WebExtensions): https://github.com/tridactyl/tridactyl[Tridactyl], https://addons.mozilla.org/en-GB/firefox/addon/vimium-ff/[Vimium-FF] (experimental), @@ -230,7 +230,6 @@ Active https://github.com/amedama41/vvimpulation[VVimpulation] * Addons for Firefox and Chrome: https://github.com/brookhong/Surfingkeys[Surfingkeys], - https://github.com/lusakasa/saka-key[Saka Key], https://krabby.netlify.com/[Krabby], https://lydell.github.io/LinkHints/[Link Hints] (hinting only) * Addons for Safari: @@ -252,6 +251,7 @@ original site is gone but the Arch Linux wiki has some data) * https://www.uzbl.org/[uzbl] (C, GTK+ with WebKit1/WebKit2) * https://github.com/conformal/xombrero[xombrero] (C, GTK+ with WebKit1) * https://github.com/linkdd/cream-browser[Cream Browser] (C, GTK+ with WebKit1) +* https://surf.suckless.org/[surf] (C, GTK+ with WebKit1/WebKit2) * Firefox addons (not based on WebExtensions or no recent activity): http://www.vimperator.org/[Vimperator], http://bug.5digits.org/pentadactyl/index[Pentadactyl], @@ -261,7 +261,7 @@ original site is gone but the Arch Linux wiki has some data) * Chrome/Chromium addons: https://github.com/k2nr/ViChrome/[ViChrome], https://github.com/jinzhu/vrome[Vrome], - https://github.com/lusakasa/saka-key[Saka Key], + https://github.com/lusakasa/saka-key[Saka Key] (https://github.com/lusakasa/saka-key/issues/171[unmaintained]), https://github.com/1995eaton/chromium-vim[cVim], https://glee.github.io/[GleeBox] -- cgit v1.2.3-54-g00ecf From 685a66280aff600a83aa30da814aea63f0116c31 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Mon, 26 Oct 2020 13:51:12 +0100 Subject: Initial drop of Python 3.5 See #4800 --- .flake8 | 6 +++-- .github/workflows/ci.yml | 5 ---- .mypy.ini | 2 -- .travis.yml | 4 +-- README.asciidoc | 3 +-- doc/changelog.asciidoc | 8 ++++++ doc/contributing.asciidoc | 2 +- doc/install.asciidoc | 24 ++++++++--------- misc/requirements/requirements-tests.txt | 15 +++++------ misc/requirements/requirements-tests.txt-raw | 13 ---------- qutebrowser/browser/browsertab.py | 7 ++--- qutebrowser/browser/qutescheme.py | 15 ++--------- qutebrowser/browser/webengine/webenginetab.py | 12 ++------- qutebrowser/browser/webkit/mhtml.py | 5 +--- qutebrowser/browser/webkit/webkittab.py | 7 ++--- qutebrowser/commands/command.py | 23 ++++++++--------- qutebrowser/config/configtypes.py | 37 ++++++++------------------- qutebrowser/misc/checkpyver.py | 4 +-- qutebrowser/misc/earlyinit.py | 2 +- qutebrowser/utils/debug.py | 5 +--- qutebrowser/utils/utils.py | 11 ++++---- setup.py | 3 +-- tests/end2end/test_invocations.py | 9 ++++--- tests/unit/browser/webkit/test_mhtml.py | 5 +--- tests/unit/config/test_configtypes.py | 32 ++--------------------- tests/unit/misc/test_checkpyver.py | 11 ++++---- tests/unit/utils/test_urlmatch.py | 7 +---- tox.ini | 1 - 28 files changed, 91 insertions(+), 187 deletions(-) (limited to 'README.asciidoc') 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 -<>. +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 +<>. 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} -- cgit v1.2.3-54-g00ecf