From 25e6f103457f89544f99bfcd62bbd78f8a4ce7f3 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Fri, 11 Oct 2019 12:36:28 +0200 Subject: Handle errors while reading state config --- doc/changelog.asciidoc | 10 ++++++++++ qutebrowser/config/configexc.py | 4 +++- qutebrowser/config/configfiles.py | 9 +++++++-- qutebrowser/config/configinit.py | 11 +++++++++-- tests/unit/config/test_configexc.py | 6 ++++++ tests/unit/config/test_configinit.py | 18 +++++++++++++++++- 6 files changed, 52 insertions(+), 6 deletions(-) diff --git a/doc/changelog.asciidoc b/doc/changelog.asciidoc index dd183a29c..a56a04694 100644 --- a/doc/changelog.asciidoc +++ b/doc/changelog.asciidoc @@ -27,6 +27,16 @@ Fixed deprecated and shows an error. Note that `:config-py-write` did write such invalid lines before v1.8.0, so existing config files might need adjustments. +- The `readability-js` userscript now handles encodings correctly (which it + didn't before for some websites). +- New `tabs.tooltips` setting which can be used to disable hover tooltips for + tabs. +- can now be used to paste text starting with a hyphen. +- Following hints via the number keypad now works properly again. +- The logic for `:restart` has been revisited which should fix issues with + relative basedirs. +- Errors while reading the state file are now displayed instead of causing a + crash. v1.8.1 (2019-09-27) ------------------- diff --git a/qutebrowser/config/configexc.py b/qutebrowser/config/configexc.py index df171c365..d83ca403b 100644 --- a/qutebrowser/config/configexc.py +++ b/qutebrowser/config/configexc.py @@ -141,11 +141,13 @@ class ConfigFileErrors(Error): def __init__(self, basename: str, - errors: typing.Sequence[ConfigErrorDesc]) -> None: + errors: typing.Sequence[ConfigErrorDesc], *, + fatal: bool = False) -> None: super().__init__("Errors occurred while reading {}:\n{}".format( basename, '\n'.join(' {}'.format(e) for e in errors))) self.basename = basename self.errors = errors + self.fatal = fatal for err in errors: if err.traceback: log.config.debug("Config error stack:") diff --git a/qutebrowser/config/configfiles.py b/qutebrowser/config/configfiles.py index f220d2ca4..df7fdaae1 100644 --- a/qutebrowser/config/configfiles.py +++ b/qutebrowser/config/configfiles.py @@ -55,7 +55,6 @@ class StateConfig(configparser.ConfigParser): super().__init__() self._filename = os.path.join(standarddir.data(), 'state') self.read(self._filename, encoding='utf-8') - qt_version = qVersion() # We handle this here, so we can avoid setting qt_version_changed if # the config is brand new, but can still set it when qt_version wasn't @@ -690,7 +689,13 @@ def saved_sys_properties() -> typing.Iterator[None]: def init() -> None: """Initialize config storage not related to the main config.""" global state - state = StateConfig() + + try: + state = StateConfig() + except configparser.Error as e: + msg = "While loading state file from {}".format(standarddir.data()) + desc = configexc.ConfigErrorDesc(msg, e) + raise configexc.ConfigFileErrors('state', [desc], fatal=True) # Set the QSettings path to something like # ~/.config/qutebrowser/qsettings/qutebrowser/qutebrowser.conf so it diff --git a/qutebrowser/config/configinit.py b/qutebrowser/config/configinit.py index 74c07e3ab..3a39e1bc3 100644 --- a/qutebrowser/config/configinit.py +++ b/qutebrowser/config/configinit.py @@ -60,6 +60,7 @@ def early_init(args: argparse.Namespace) -> None: objreg.register('config-commands', config_commands) config_file = standarddir.config_py() + global _init_errors try: if os.path.exists(config_file): @@ -68,10 +69,12 @@ def early_init(args: argparse.Namespace) -> None: configfiles.read_autoconfig() except configexc.ConfigFileErrors as e: log.config.exception("Error while loading {}".format(e.basename)) - global _init_errors _init_errors = e - configfiles.init() + try: + configfiles.init() + except configexc.ConfigFileErrors as e: + _init_errors = e for opt, val in args.temp_settings: try: @@ -149,6 +152,10 @@ def late_init(save_manager: savemanager.SaveManager) -> None: icon=QMessageBox.Warning, plain_text=False) errbox.exec_() + + if _init_errors.fatal: + sys.exit(usertypes.Exit.err_init) + _init_errors = None config.instance.init_save_manager(save_manager) diff --git a/tests/unit/config/test_configexc.py b/tests/unit/config/test_configexc.py index f3f86a6dd..0335d0cee 100644 --- a/tests/unit/config/test_configexc.py +++ b/tests/unit/config/test_configexc.py @@ -126,3 +126,9 @@ Fake traceback """) # Make sure the traceback is not indented assert '
\nFake traceback\n' in html
+
+
+def test_config_file_errors_fatal():
+    err = configexc.ConfigErrorDesc("Text", Exception("Text"))
+    errors = configexc.ConfigFileErrors("state", [err], fatal=True)
+    assert errors.fatal
diff --git a/tests/unit/config/test_configinit.py b/tests/unit/config/test_configinit.py
index 93ca334ef..273c13d43 100644
--- a/tests/unit/config/test_configinit.py
+++ b/tests/unit/config/test_configinit.py
@@ -205,6 +205,12 @@ class TestEarlyInit:
 
         assert dump == '\n'.join(expected)
 
+    def test_state_init_errors(self, init_patch, args, data_tmpdir):
+        state_file = data_tmpdir / 'state'
+        state_file.write_binary(b'\x00')
+        configinit.early_init(args)
+        assert configinit._init_errors.errors
+
     def test_invalid_change_filter(self, init_patch, args):
         config.change_filter('foobar')
         with pytest.raises(configexc.NoOptionError):
@@ -325,16 +331,23 @@ class TestEarlyInit:
         configinit._init_envvars()
 
 
-@pytest.mark.parametrize('errors', [True, False])
+@pytest.mark.parametrize('errors', [True, 'fatal', False])
 def test_late_init(init_patch, monkeypatch, fake_save_manager, args,
                    mocker, errors):
     configinit.early_init(args)
+
     if errors:
         err = configexc.ConfigErrorDesc("Error text", Exception("Exception"))
         errs = configexc.ConfigFileErrors("config.py", [err])
+        if errors == 'fatal':
+            errs.fatal = True
+
         monkeypatch.setattr(configinit, '_init_errors', errs)
+
     msgbox_mock = mocker.patch('qutebrowser.config.configinit.msgbox.msgbox',
                                autospec=True)
+    exit_mock = mocker.patch('qutebrowser.config.configinit.sys.exit',
+                             autospec=True)
 
     configinit.late_init(fake_save_manager)
 
@@ -342,12 +355,15 @@ def test_late_init(init_patch, monkeypatch, fake_save_manager, args,
         'state-config', unittest.mock.ANY)
     fake_save_manager.add_saveable.assert_any_call(
         'yaml-config', unittest.mock.ANY, unittest.mock.ANY)
+
     if errors:
         assert len(msgbox_mock.call_args_list) == 1
         _call_posargs, call_kwargs = msgbox_mock.call_args_list[0]
         text = call_kwargs['text'].strip()
         assert text.startswith('Errors occurred while reading config.py:')
         assert 'Error text: Exception' in text
+
+        assert exit_mock.called == (errors == 'fatal')
     else:
         assert not msgbox_mock.called
 
-- 
cgit v1.2.3-54-g00ecf