diff options
author | Florian Bruhin <me@the-compiler.org> | 2022-05-09 10:58:00 +0200 |
---|---|---|
committer | Florian Bruhin <me@the-compiler.org> | 2022-05-09 11:48:41 +0200 |
commit | c9380605a1240748769c012403520323b4d2c3be (patch) | |
tree | 6ea50b5f77532902a3d90746f0314bd7f05ca70e | |
parent | b76104da79846e73bbb390432b3aabf7d52515a3 (diff) | |
download | qutebrowser-c9380605a1240748769c012403520323b4d2c3be.tar.gz qutebrowser-c9380605a1240748769c012403520323b4d2c3be.zip |
Display close matches for invalid settings
-rw-r--r-- | qutebrowser/config/config.py | 6 | ||||
-rw-r--r-- | qutebrowser/config/configexc.py | 10 | ||||
-rw-r--r-- | tests/unit/config/test_config.py | 4 | ||||
-rw-r--r-- | tests/unit/config/test_configexc.py | 25 |
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 |