summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Bruhin <me@the-compiler.org>2021-04-08 09:51:16 +0200
committerFlorian Bruhin <me@the-compiler.org>2021-04-08 09:51:16 +0200
commite2c5fe6262564d9d85806bfa9d4486a411cf5045 (patch)
tree21602b102bd37a5d46edff1c98cd531d09c7390e
parente0657a550a80876c6236bc065593b01ef098f18c (diff)
downloadqutebrowser-e2c5fe6262564d9d85806bfa9d4486a411cf5045.tar.gz
qutebrowser-e2c5fe6262564d9d85806bfa9d4486a411cf5045.zip
Fix enum stringification for Python 3.10 a7+
https://bugs.python.org/issue40066 https://mail.python.org/archives/list/python-dev@python.org/message/CHQW6THTDYNPPFWQ2KDDTUYSAJDCZFNP/ https://github.com/python/cpython/commit/b775106d940e3d77c8af7967545bb9a5b7b162df
-rw-r--r--qutebrowser/browser/browsertab.py4
-rw-r--r--qutebrowser/browser/webengine/webenginetab.py2
-rw-r--r--qutebrowser/keyinput/modeman.py10
-rw-r--r--qutebrowser/utils/utils.py20
-rw-r--r--tests/end2end/features/downloads.feature24
-rw-r--r--tests/end2end/features/misc.feature2
-rw-r--r--tests/end2end/features/qutescheme.feature2
-rw-r--r--tests/end2end/features/test_downloads_bdd.py2
-rw-r--r--tests/unit/utils/test_debug.py2
-rw-r--r--tests/unit/utils/test_utils.py28
10 files changed, 73 insertions, 23 deletions
diff --git a/qutebrowser/browser/browsertab.py b/qutebrowser/browser/browsertab.py
index cc358a810..cbe698009 100644
--- a/qutebrowser/browser/browsertab.py
+++ b/qutebrowser/browser/browsertab.py
@@ -1003,7 +1003,7 @@ class AbstractTab(QWidget):
"""Setter for load_status."""
if not isinstance(val, usertypes.LoadStatus):
raise TypeError("Type {} is no LoadStatus member!".format(val))
- log.webview.debug("load status for {}: {}".format(repr(self), val))
+ log.webview.debug(f"load status for {self!r}: {utils.pyenum_str(val)}")
self._load_status = val
self.load_status_changed.emit(val)
@@ -1063,7 +1063,7 @@ class AbstractTab(QWidget):
url = utils.elide(navigation.url.toDisplayString(), 100)
log.webview.debug("navigation request: url {}, type {}, is_main_frame "
"{}".format(url,
- navigation.navigation_type,
+ utils.pyenum_str(navigation.navigation_type),
navigation.is_main_frame))
if navigation.is_main_frame:
diff --git a/qutebrowser/browser/webengine/webenginetab.py b/qutebrowser/browser/webengine/webenginetab.py
index 754b764cb..c03e94408 100644
--- a/qutebrowser/browser/webengine/webenginetab.py
+++ b/qutebrowser/browser/webengine/webenginetab.py
@@ -464,7 +464,7 @@ class WebEngineCaret(browsertab.AbstractCaret):
# `:selection-toggle` is executed and before this callback function
# is asynchronously called.
log.misc.debug("Ignoring caret selection callback in {}".format(
- self._mode_manager.mode))
+ utils.pyenum_str(self._mode_manager.mode)))
return
if state_str is None:
message.error("Error toggling caret selection")
diff --git a/qutebrowser/keyinput/modeman.py b/qutebrowser/keyinput/modeman.py
index 3c47fafe3..21a6be052 100644
--- a/qutebrowser/keyinput/modeman.py
+++ b/qutebrowser/keyinput/modeman.py
@@ -284,8 +284,8 @@ class ModeManager(QObject):
curmode = self.mode
parser = self.parsers[curmode]
if curmode != usertypes.KeyMode.insert:
- log.modes.debug("got keypress in mode {} - delegating to "
- "{}".format(curmode, utils.qualname(parser)))
+ log.modes.debug("got keypress in mode {} - delegating to {}".format(
+ utils.pyenum_str(curmode), utils.qualname(parser)))
match = parser.handle(event, dry_run=dry_run)
has_modifier = event.modifiers() not in [
@@ -361,7 +361,8 @@ class ModeManager(QObject):
return
log.modes.debug("Entering mode {}{}".format(
- mode, '' if reason is None else ' (reason: {})'.format(reason)))
+ utils.pyenum_str(mode),
+ '' if reason is None else ' (reason: {})'.format(reason)))
if mode not in self.parsers:
raise ValueError("No keyparser for mode {}".format(mode))
if self.mode == mode or (self.mode in PROMPT_MODES and
@@ -429,7 +430,8 @@ class ModeManager(QObject):
raise NotInModeError("Not in mode {}!".format(mode))
log.modes.debug("Leaving mode {}{}".format(
- mode, '' if reason is None else ' (reason: {})'.format(reason)))
+ utils.pyenum_str(mode),
+ '' if reason is None else ' (reason: {})'.format(reason)))
# leaving a mode implies clearing keychain, see
# https://github.com/qutebrowser/qutebrowser/issues/1805
self.clear_keychain()
diff --git a/qutebrowser/utils/utils.py b/qutebrowser/utils/utils.py
index 762d2d370..56ebe45c4 100644
--- a/qutebrowser/utils/utils.py
+++ b/qutebrowser/utils/utils.py
@@ -375,6 +375,18 @@ def is_enum(obj: Any) -> bool:
return False
+def pyenum_str(value: enum.Enum) -> str:
+ """Get a string representation of a Python enum value.
+
+ This will have the form of "EnumType.membername", which is the default string
+ representation for Python up to 3.10. Unfortunately, that changes with Python 3.10:
+ https://bugs.python.org/issue40066
+ """
+ if sys.version_info[:2] >= (3, 10):
+ return repr(value)
+ return str(value)
+
+
def get_repr(obj: Any, constructor: bool = False, **attrs: Any) -> str:
"""Get a suitable __repr__ string for an object.
@@ -387,8 +399,14 @@ def get_repr(obj: Any, constructor: bool = False, **attrs: Any) -> str:
cls = qualname(obj.__class__)
parts = []
items = sorted(attrs.items())
+
for name, val in items:
- parts.append('{}={!r}'.format(name, val))
+ if isinstance(val, enum.Enum):
+ s = pyenum_str(val)
+ else:
+ s = repr(val)
+ parts.append(f'{name}={s}')
+
if constructor:
return '{}({})'.format(cls, ', '.join(parts))
else:
diff --git a/tests/end2end/features/downloads.feature b/tests/end2end/features/downloads.feature
index dfdb24704..6448e7809 100644
--- a/tests/end2end/features/downloads.feature
+++ b/tests/end2end/features/downloads.feature
@@ -79,7 +79,7 @@ Feature: Downloading things from a website.
And I set downloads.location.prompt to true
And I open data/downloads/issue1243.html
And I hint with args "links download" and follow a
- And I wait for "Asking question <qutebrowser.utils.usertypes.Question default='qutebrowser-download' mode=<PromptMode.download: 5> option=None text=* title='Save file to:'>, *" in the log
+ And I wait for "Asking question <qutebrowser.utils.usertypes.Question default='qutebrowser-download' mode=PromptMode.download option=None text=* title='Save file to:'>, *" in the log
Then the error "Download error: No handler found for qute://" should be shown
And "NotFoundError while handling qute://* URL" should be logged
@@ -88,7 +88,7 @@ Feature: Downloading things from a website.
And I set downloads.location.prompt to true
And I open data/data_link.html
And I hint with args "links download" and follow s
- And I wait for "Asking question <qutebrowser.utils.usertypes.Question default='download.pdf' mode=<PromptMode.download: 5> option=None text=* title='Save file to:'>, *" in the log
+ And I wait for "Asking question <qutebrowser.utils.usertypes.Question default='download.pdf' mode=PromptMode.download option=None text=* title='Save file to:'>, *" in the log
And I run :mode-leave
Then no crash should happen
@@ -96,7 +96,7 @@ Feature: Downloading things from a website.
When I set downloads.location.suggestion to filename
And I set downloads.location.prompt to true
And I open data/downloads/download.bin in a new window without waiting
- And I wait for "Asking question <qutebrowser.utils.usertypes.Question default='*' mode=<PromptMode.download: 5> *" in the log
+ And I wait for "Asking question <qutebrowser.utils.usertypes.Question default='*' mode=PromptMode.download *" in the log
And I run :window-only
And I run :mode-leave
Then no crash should happen
@@ -164,7 +164,7 @@ Feature: Downloading things from a website.
Scenario: Downloading a file to a reserved path
When I set downloads.location.prompt to true
And I open data/downloads/download.bin without waiting
- And I wait for "Asking question <qutebrowser.utils.usertypes.Question default='*' mode=<PromptMode.download: 5> option=None text='Please enter a location for <b>http://localhost:*/data/downloads/download.bin</b>' title='Save file to:'>, *" in the log
+ And I wait for "Asking question <qutebrowser.utils.usertypes.Question default='*' mode=PromptMode.download option=None text='Please enter a location for <b>http://localhost:*/data/downloads/download.bin</b>' title='Save file to:'>, *" in the log
And I run :prompt-accept COM1
And I run :mode-leave
Then the error "Invalid filename" should be shown
@@ -173,7 +173,7 @@ Feature: Downloading things from a website.
Scenario: Downloading a file to a drive-relative working directory
When I set downloads.location.prompt to true
And I open data/downloads/download.bin without waiting
- And I wait for "Asking question <qutebrowser.utils.usertypes.Question default='*' mode=<PromptMode.download: 5> option=None text='Please enter a location for <b>http://localhost:*/data/downloads/download.bin</b>' title='Save file to:'>, *" in the log
+ And I wait for "Asking question <qutebrowser.utils.usertypes.Question default='*' mode=PromptMode.download option=None text='Please enter a location for <b>http://localhost:*/data/downloads/download.bin</b>' title='Save file to:'>, *" in the log
And I run :prompt-accept C:foobar
And I run :mode-leave
Then the error "Invalid filename" should be shown
@@ -247,14 +247,14 @@ Feature: Downloading things from a website.
Scenario: :download with a filename and directory which doesn't exist
When I run :download --dest (tmpdir)(dirsep)downloads(dirsep)somedir(dirsep)file http://localhost:(port)/data/downloads/download.bin
- And I wait for "Asking question <qutebrowser.utils.usertypes.Question default=None mode=<PromptMode.yesno: 1> option=None text='<b>*</b> does not exist. Create it?' title='Create directory?'>, *" in the log
+ And I wait for "Asking question <qutebrowser.utils.usertypes.Question default=None mode=PromptMode.yesno option=None text='<b>*</b> does not exist. Create it?' title='Create directory?'>, *" in the log
And I run :prompt-accept yes
And I wait until the download is finished
Then the downloaded file somedir/file should exist
Scenario: :download with a directory which doesn't exist
When I run :download --dest (tmpdir)(dirsep)downloads(dirsep)somedir(dirsep) http://localhost:(port)/data/downloads/download.bin
- And I wait for "Asking question <qutebrowser.utils.usertypes.Question default=None mode=<PromptMode.yesno: 1> option=None text='<b>*</b> does not exist. Create it?' title='Create directory?'>, *" in the log
+ And I wait for "Asking question <qutebrowser.utils.usertypes.Question default=None mode=PromptMode.yesno option=None text='<b>*</b> does not exist. Create it?' title='Create directory?'>, *" in the log
And I run :prompt-accept yes
And I wait until the download is finished
Then the downloaded file somedir/download.bin should exist
@@ -279,13 +279,13 @@ Feature: Downloading things from a website.
When I set downloads.location.prompt to true
And I open data/title.html
And I run :download --mhtml
- And I wait for "Asking question <qutebrowser.utils.usertypes.Question default='*' mode=<PromptMode.download: 5> option=None text='Please enter a location for <b>http://localhost:*/data/title.html</b>' title='Save file to:'>, *" in the log
+ And I wait for "Asking question <qutebrowser.utils.usertypes.Question default='*' mode=PromptMode.download option=None text='Please enter a location for <b>http://localhost:*/data/title.html</b>' title='Save file to:'>, *" in the log
And I run :prompt-accept
And I wait for "File successfully written." in the log
And I run :download --mhtml
- And I wait for "Asking question <qutebrowser.utils.usertypes.Question default='*' mode=<PromptMode.download: 5> option=None text='Please enter a location for <b>http://localhost:*/data/title.html</b>' title='Save file to:'>, *" in the log
+ And I wait for "Asking question <qutebrowser.utils.usertypes.Question default='*' mode=PromptMode.download option=None text='Please enter a location for <b>http://localhost:*/data/title.html</b>' title='Save file to:'>, *" in the log
And I run :prompt-accept
- And I wait for "Asking question <qutebrowser.utils.usertypes.Question default=None mode=<PromptMode.yesno: 1> option=None text='<b>*</b> already exists. Overwrite?' title='Overwrite existing file?'>, *" in the log
+ And I wait for "Asking question <qutebrowser.utils.usertypes.Question default=None mode=PromptMode.yesno option=None text='<b>*</b> already exists. Overwrite?' title='Overwrite existing file?'>, *" in the log
And I run :prompt-accept yes
And I wait for "File successfully written." in the log
Then the downloaded file Test title.mhtml should exist
@@ -655,9 +655,9 @@ Feature: Downloading things from a website.
Scenario: Answering a question for a cancelled download (#415)
When I set downloads.location.prompt to true
And I run :download http://localhost:(port)/data/downloads/download.bin
- And I wait for "Asking question <qutebrowser.utils.usertypes.Question default='*' mode=<PromptMode.download: 5> option=None text=* title='Save file to:'>, *" in the log
+ And I wait for "Asking question <qutebrowser.utils.usertypes.Question default='*' mode=PromptMode.download option=None text=* title='Save file to:'>, *" in the log
And I run :download http://localhost:(port)/data/downloads/download2.bin
- And I wait for "Asking question <qutebrowser.utils.usertypes.Question default='*' mode=<PromptMode.download: 5> option=None text=* title='Save file to:'>, *" in the log
+ And I wait for "Asking question <qutebrowser.utils.usertypes.Question default='*' mode=PromptMode.download option=None text=* title='Save file to:'>, *" in the log
And I run :download-cancel with count 2
And I run :prompt-accept
And I wait until the download is finished
diff --git a/tests/end2end/features/misc.feature b/tests/end2end/features/misc.feature
index e6a02e038..3951dd2b0 100644
--- a/tests/end2end/features/misc.feature
+++ b/tests/end2end/features/misc.feature
@@ -196,7 +196,7 @@ Feature: Various utility commands.
# We can't use "When I open" because we don't want to wait for load
# finished
When I run :open http://localhost:(port)/redirect-later?delay=-1
- And I wait for "emitting: cur_load_status_changed(<LoadStatus.loading: *>) (tab *)" in the log
+ And I wait for "emitting: cur_load_status_changed(*loading*) (tab *)" in the log
And I wait 1s
And I run :stop
And I open redirect-later-continue in a new tab
diff --git a/tests/end2end/features/qutescheme.feature b/tests/end2end/features/qutescheme.feature
index 039434f1c..bb556df53 100644
--- a/tests/end2end/features/qutescheme.feature
+++ b/tests/end2end/features/qutescheme.feature
@@ -192,7 +192,7 @@ Feature: Special qute:// pages
And I open data/misc/test.pdf without waiting
And I wait for "[qute://pdfjs/*] PDF * (PDF.js: *)" in the log
And I run :jseval document.getElementById("download").click()
- And I wait for "Asking question <qutebrowser.utils.usertypes.Question default=* mode=<PromptMode.download: 5> option=None text=* title='Save file to:'>, *" in the log
+ And I wait for "Asking question <qutebrowser.utils.usertypes.Question default=* mode=PromptMode.download option=None text=* title='Save file to:'>, *" in the log
And I run :mode-leave
Then no crash should happen
diff --git a/tests/end2end/features/test_downloads_bdd.py b/tests/end2end/features/test_downloads_bdd.py
index 804ed40fe..f7b19b4b0 100644
--- a/tests/end2end/features/test_downloads_bdd.py
+++ b/tests/end2end/features/test_downloads_bdd.py
@@ -28,7 +28,7 @@ bdd.scenarios('downloads.feature')
PROMPT_MSG = ("Asking question <qutebrowser.utils.usertypes.Question "
- "default={!r} mode=<PromptMode.download: 5> option=None "
+ "default={!r} mode=PromptMode.download option=None "
"text=* title='Save file to:'>, *")
diff --git a/tests/unit/utils/test_debug.py b/tests/unit/utils/test_debug.py
index 62d0f4a7b..4fcf781ba 100644
--- a/tests/unit/utils/test_debug.py
+++ b/tests/unit/utils/test_debug.py
@@ -19,6 +19,8 @@
"""Tests for qutebrowser.utils.debug."""
+import sys
+import enum
import logging
import re
import time
diff --git a/tests/unit/utils/test_utils.py b/tests/unit/utils/test_utils.py
index 57adc883c..42b95a1a8 100644
--- a/tests/unit/utils/test_utils.py
+++ b/tests/unit/utils/test_utils.py
@@ -546,6 +546,34 @@ class TestIsEnum:
assert not utils.is_enum(23)
+class SomeEnum(enum.Enum):
+
+ some_value = enum.auto()
+
+
+class TestPyEnumStr:
+
+ @pytest.fixture
+ def val(self):
+ return SomeEnum.some_value
+
+ def test_fake_old_python_version(self, monkeypatch, val):
+ monkeypatch.setattr(sys, 'version_info', (3, 9, 2))
+ assert utils.pyenum_str(val) == str(val)
+
+ def test_fake_new_python_version(self, monkeypatch, val):
+ monkeypatch.setattr(sys, 'version_info', (3, 10, 0))
+ assert utils.pyenum_str(val) == repr(val)
+
+ def test_real_result(self, val):
+ assert utils.pyenum_str(val) == 'SomeEnum.some_value'
+
+ @pytest.mark.skipif(sys.version_info[:2] < (3, 10), reason='Needs Python 3.10+')
+ def test_needed(self, val):
+ """Fail if this change gets revered before the final 3.10 release."""
+ assert str(val) != 'SomeEnum.some_value'
+
+
class TestRaises:
"""Test raises."""