From a1aec8fff6323e5b0709645da75ebd8e42097ecf Mon Sep 17 00:00:00 2001 From: Tobias Witek Date: Sun, 1 Mar 2020 14:08:16 +0100 Subject: [PATCH] [core/module] Add error widgets if a module throws Module should have to care less about thrown exceptions. --- bumblebee-status | 2 +- core/module.py | 8 ++++++++ core/output.py | 10 ++++++++-- core/widget.py | 1 + doc/NOTES.md | 2 +- tests/core/test_module.py | 9 +++++++++ tests/core/test_output.py | 8 ++++++++ 7 files changed, 36 insertions(+), 4 deletions(-) diff --git a/bumblebee-status b/bumblebee-status index 112a704..3e11ea2 100755 --- a/bumblebee-status +++ b/bumblebee-status @@ -46,7 +46,7 @@ def main(): config = core.config.Config(sys.argv[1:]) theme = core.theme.Theme(config.theme(), config.iconset()) - output = core.output.i3(theme) + output = core.output.i3(theme, config) modules = [] input_thread = threading.Thread(target=handle_input, args=(output,)) diff --git a/core/module.py b/core/module.py index 0017b0e..30f544c 100644 --- a/core/module.py +++ b/core/module.py @@ -38,6 +38,14 @@ class Module(core.input.Object): def update(self): pass + def update_wrapper(self): + try: + self.update() + except Exception as e: + module = Error(self._config, 'error', str(e)) + self._widgets = [module.widgets()[0]] + self.update = module.update + def name(self): return self._name if self._name else self.module_name() diff --git a/core/output.py b/core/output.py index 3d47678..62436df 100644 --- a/core/output.py +++ b/core/output.py @@ -6,14 +6,20 @@ import core.theme import core.event class i3(object): - def __init__(self, theme=core.theme.Theme()): + def __init__(self, theme=core.theme.Theme(), config=None): self._modules = [] self._status = {} self._theme = theme + self._config = config core.event.register('start', self.draw, 'start') core.event.register('update', self.draw, 'statusline') core.event.register('stop', self.draw, 'stop') + def theme(self, new_theme=None): + if new_theme: + self._theme = new_theme + return self._theme + def modules(self, modules=None): if not modules: return self._modules @@ -96,7 +102,7 @@ class i3(object): for module in self._modules: if affected_modules and not module.id() in affected_modules: continue - module.update() + module.update_wrapper() for widget in module.widgets(): self._status[widget] = widget.full_text() diff --git a/core/widget.py b/core/widget.py index 43814bf..45ee3f5 100644 --- a/core/widget.py +++ b/core/widget.py @@ -1,4 +1,5 @@ import core.input +import core.decorators import util.store class Widget(util.store.Store, core.input.Object): diff --git a/doc/NOTES.md b/doc/NOTES.md index a36cf27..1ad3a97 100644 --- a/doc/NOTES.md +++ b/doc/NOTES.md @@ -23,5 +23,5 @@ ## Improvements - pango output (improve - maybe autodetect? see #531) -- only update specific, affected modules when clicking - allow handlers to specify whether to update or not (e.g. scroll) +- error handling: don't catch too many exceptions in a module (pulseaudio!), instead, propagate them as error widgets diff --git a/tests/core/test_module.py b/tests/core/test_module.py index 724dacc..58c96c7 100644 --- a/tests/core/test_module.py +++ b/tests/core/test_module.py @@ -26,11 +26,20 @@ class module(unittest.TestCase): module = core.module.load(module_name=self.validModuleName) self.assertEqual('modules.{}'.format(self.validModuleName), module.__class__.__module__, 'module must be a modules. object') self.assertEqual('Module', module.__class__.__name__, 'a valid module must have a Module class') + self.assertEqual([], module.state(None), 'default state of module is empty') def test_empty_widgets(self): module = core.module.Module(widgets=[]) self.assertEqual([], module.widgets()) + def test_error_widget(self): + cfg = core.config.Config(shlex.split('-p test_module.foo=5')) + module = core.module.Error(cfg, 'test-mod', 'xyz') + self.assertEqual(['critical'], module.state(None), 'error module must have critical state') + full_text = module.full_text(module.widgets()[0]) + self.assertTrue('test-mod' in full_text) + self.assertTrue('xyz' in full_text) + def test_single_widget(self): module = core.module.Module(widgets=self.someWidget) self.assertEqual([self.someWidget], module.widgets()) diff --git a/tests/core/test_output.py b/tests/core/test_output.py index 3205633..d870157 100644 --- a/tests/core/test_output.py +++ b/tests/core/test_output.py @@ -13,6 +13,9 @@ class i3(unittest.TestCase): widget = unittest.mock.MagicMock() widget.full_text.return_value = "test" self.someModule = TestModule(widgets=[widget, widget, widget]) + self.paddedTheme = core.theme.Theme(raw_data = { + 'defaults': { 'padding': ' ' } + }); def test_start(self): core.event.clear() @@ -55,4 +58,9 @@ class i3(unittest.TestCase): data = self.i3.statusline() self.assertEqual(len(self.someModule.widgets())*3, len(data['data']), 'wrong number of widgets') + def test_padding(self): + self.i3.theme(self.paddedTheme) + result = self.i3.__pad(self.someModule, self.someModule.widgets()[0], 'abc') + self.assertEqual(' abc ', result) + # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4