summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Bruhin <me@the-compiler.org>2022-05-09 10:58:00 +0200
committerFlorian Bruhin <me@the-compiler.org>2022-05-09 11:48:41 +0200
commitc9380605a1240748769c012403520323b4d2c3be (patch)
tree6ea50b5f77532902a3d90746f0314bd7f05ca70e
parentb76104da79846e73bbb390432b3aabf7d52515a3 (diff)
downloadqutebrowser-c9380605a1240748769c012403520323b4d2c3be.tar.gz
qutebrowser-c9380605a1240748769c012403520323b4d2c3be.zip
Display close matches for invalid settings
-rw-r--r--qutebrowser/config/config.py6
-rw-r--r--qutebrowser/config/configexc.py10
-rw-r--r--tests/unit/config/test_config.py4
-rw-r--r--tests/unit/config/test_configexc.py25
4 files changed, 35 insertions, 10 deletions
diff --git a/qutebrowser/config/config.py b/qutebrowser/config/config.py
index 834709ae6..918c9b894 100644
--- a/qutebrowser/config/config.py
+++ b/qutebrowser/config/config.py
@@ -373,7 +373,11 @@ class Config(QObject):
deleted = name in configdata.MIGRATIONS.deleted
renamed = configdata.MIGRATIONS.renamed.get(name)
exception = configexc.NoOptionError(
- name, deleted=deleted, renamed=renamed)
+ name,
+ deleted=deleted,
+ renamed=renamed,
+ all_names=list(configdata.DATA),
+ )
raise exception from None
def ensure_has_opt(self, name: str) -> None:
diff --git a/qutebrowser/config/configexc.py b/qutebrowser/config/configexc.py
index 27a1001b5..58e5ad67a 100644
--- a/qutebrowser/config/configexc.py
+++ b/qutebrowser/config/configexc.py
@@ -19,8 +19,9 @@
"""Exceptions related to config parsing."""
+import difflib
import dataclasses
-from typing import Any, Mapping, Optional, Sequence, Union
+from typing import Any, Mapping, Optional, Sequence, Union, List
from qutebrowser.utils import usertypes, log
@@ -91,6 +92,7 @@ class NoOptionError(Error):
"""Raised when an option was not found."""
def __init__(self, option: str, *,
+ all_names: List[str] = None,
deleted: bool = False,
renamed: str = None) -> None:
if deleted:
@@ -98,6 +100,12 @@ class NoOptionError(Error):
suffix = ' (this option was removed from qutebrowser)'
elif renamed is not None:
suffix = ' (this option was renamed to {!r})'.format(renamed)
+ elif all_names:
+ matches = difflib.get_close_matches(option, all_names, n=1)
+ if matches:
+ suffix = f' (did you mean {matches[0]!r}?)'
+ else:
+ suffix = ''
else:
suffix = ''
diff --git a/tests/unit/config/test_config.py b/tests/unit/config/test_config.py
index b88bc2f8d..ab1fba789 100644
--- a/tests/unit/config/test_config.py
+++ b/tests/unit/config/test_config.py
@@ -782,7 +782,7 @@ class TestContainer:
assert len(configapi.errors) == 1
error = configapi.errors[0]
assert error.text == "While getting 'tabs.foobar'"
- assert str(error.exception) == "No option 'tabs.foobar'"
+ assert str(error.exception).startswith("No option 'tabs.foobar'")
def test_confapi_missing_prefix(self, container):
configapi = types.SimpleNamespace(errors=[])
@@ -793,7 +793,7 @@ class TestContainer:
error1 = configapi.errors[0]
assert error1.text == "While getting 'content.host_blocking'"
- assert str(error1.exception) == "No option 'content.host_blocking'"
+ assert str(error1.exception).startswith("No option 'content.host_blocking'")
error2 = configapi.errors[1]
assert error2.text == "While setting 'content.host_blocking.lists'"
diff --git a/tests/unit/config/test_configexc.py b/tests/unit/config/test_configexc.py
index a236494f9..0c64cf8c6 100644
--- a/tests/unit/config/test_configexc.py
+++ b/tests/unit/config/test_configexc.py
@@ -32,13 +32,26 @@ def test_validation_error():
assert str(e) == "Invalid value 'val' - msg"
-@pytest.mark.parametrize('deleted, renamed, expected', [
- (False, None, "No option 'opt'"),
- (True, None, "No option 'opt' (this option was removed from qutebrowser)"),
- (False, 'new', "No option 'opt' (this option was renamed to 'new')"),
+@pytest.mark.parametrize('deleted, renamed, all_names, expected', [
+ (False, None, [], "No option 'opt'"),
+ (True, None, [], "No option 'opt' (this option was removed from qutebrowser)"),
+ (False, 'new', [], "No option 'opt' (this option was renamed to 'new')"),
+ (False, None, ["opto"], "No option 'opt' (did you mean 'opto'?)"),
+ (
+ True,
+ None,
+ ["opto"],
+ "No option 'opt' (this option was removed from qutebrowser)",
+ ),
+ (False, 'new', ["opto"], "No option 'opt' (this option was renamed to 'new')"),
])
-def test_no_option_error(deleted, renamed, expected):
- e = configexc.NoOptionError('opt', deleted=deleted, renamed=renamed)
+def test_no_option_error(deleted, renamed, all_names, expected):
+ e = configexc.NoOptionError(
+ 'opt',
+ deleted=deleted,
+ renamed=renamed,
+ all_names=all_names,
+ )
assert e.option == 'opt'
assert str(e) == expected