From f64520357927026ba061a38737af224aa14fd965 Mon Sep 17 00:00:00 2001 From: Tobi-wan Kenobi Date: Thu, 8 Dec 2016 08:44:54 +0100 Subject: [PATCH] [core] Widget creation/update overhaul Until now, widgets were re-created during each iteration. For multiple, reasons, using static widget objects is much easier, so instead of creating new widgets continuously, modules now create the widgets during instantiation and get the list of widgets passed as parameter whenever an update occurs. During the update, they can still manipulate the widget list by removing and adding elements as needed. Advantages: * Less memory fragmentation (fewer (de)allocations) * Easier event management (widgets now have static IDs) * Easier module code (widget contents can simply be the result of a callback) see #23 --- bumblebee/engine.py | 16 ++++++++++------ bumblebee/modules/cpu.py | 11 +++++++---- bumblebee/modules/test.py | 8 +++++--- bumblebee/output.py | 5 ++++- bumblebee/theme.py | 1 + runlint.sh | 2 +- tests/modules/test_cpu.py | 11 +++++++++-- tests/test_module.py | 25 +++++++++++++++++++++++++ tests/util.py | 3 +++ 9 files changed, 65 insertions(+), 17 deletions(-) create mode 100644 tests/test_module.py diff --git a/bumblebee/engine.py b/bumblebee/engine.py index e2b4826..2ba5107 100644 --- a/bumblebee/engine.py +++ b/bumblebee/engine.py @@ -12,8 +12,14 @@ class Module(object): (e.g. CPU utilization, disk usage, etc.) derive from this base class. """ - def __init__(self, engine): - pass + def __init__(self, engine, widgets): + self._widgets = [] + if widgets: + self._widgets = widgets if isinstance(widgets, list) else [widgets] + + def widgets(self): + """Return the widgets to draw for this module""" + return self._widgets class Engine(object): """Engine for driving the application @@ -53,11 +59,9 @@ class Engine(object): """Start the event loop""" self._output.start() while self.running(): - widgets = [] for module in self._modules: - module_widgets = module.widgets() - widgets += module_widgets if isinstance(module_widgets, list) else [module_widgets] - self._output.draw(widgets=widgets, engine=self) + module.update(module.widgets()) + self._output.draw(widgets=module.widgets(), engine=self) self._output.flush() if self.running(): time.sleep(1) diff --git a/bumblebee/modules/cpu.py b/bumblebee/modules/cpu.py index ecc2376..dbee32e 100644 --- a/bumblebee/modules/cpu.py +++ b/bumblebee/modules/cpu.py @@ -7,12 +7,15 @@ import bumblebee.engine class Module(bumblebee.engine.Module): def __init__(self, engine): - super(Module, self).__init__(engine) + super(Module, self).__init__(engine, + bumblebee.output.Widget(full_text=self.utilization) + ) self._utilization = psutil.cpu_percent(percpu=False) - def widgets(self): - self._utilization = psutil.cpu_percent(percpu=False) + def utilization(self): + return "{:05.02f}%".format(self._utilization) - return bumblebee.output.Widget(full_text="{:05.02f}%".format(self._utilization)) + def update(self, widgets): + self._utilization = psutil.cpu_percent(percpu=False) # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/test.py b/bumblebee/modules/test.py index 94b99c4..61af7e9 100644 --- a/bumblebee/modules/test.py +++ b/bumblebee/modules/test.py @@ -6,9 +6,11 @@ import bumblebee.engine class Module(bumblebee.engine.Module): def __init__(self, engine): - super(Module, self).__init__(engine) + super(Module, self).__init__(engine, + bumblebee.output.Widget(full_text="test") + ) - def widgets(self): - return bumblebee.output.Widget(full_text="test") + def update(self, widgets): + pass # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/output.py b/bumblebee/output.py index bd05450..727d634 100644 --- a/bumblebee/output.py +++ b/bumblebee/output.py @@ -12,7 +12,10 @@ class Widget(object): def full_text(self): """Retrieve the full text to display in the widget""" - return self._full_text + if callable(self._full_text): + return self._full_text() + else: + return self._full_text class I3BarOutput(object): """Manage output according to the i3bar protocol""" diff --git a/bumblebee/theme.py b/bumblebee/theme.py index e83ea10..e65bc41 100644 --- a/bumblebee/theme.py +++ b/bumblebee/theme.py @@ -1,6 +1,7 @@ """Theme support""" class Theme(object): + """Represents a collection of icons and colors""" pass # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/runlint.sh b/runlint.sh index 0555628..6902ce9 100755 --- a/runlint.sh +++ b/runlint.sh @@ -1,3 +1,3 @@ #!/bin/sh -find . -name "*.py"|xargs pylint --disable=R0903,R0201 +find . -name "*.py"|xargs pylint --disable=R0903,R0201,C0330 diff --git a/tests/modules/test_cpu.py b/tests/modules/test_cpu.py index 9c3be94..9ec7ecb 100644 --- a/tests/modules/test_cpu.py +++ b/tests/modules/test_cpu.py @@ -10,7 +10,14 @@ class TestCPUModule(unittest.TestCase): self.module = Module(None) def test_widgets(self): - widget = self.module.widgets() - assertWidgetAttributes(self, widget) + widgets = self.module.widgets() + for widget in widgets: + assertWidgetAttributes(self, widget) + + def test_update(self): + widgets = self.module.widgets() + self.module.update(widgets) + self.test_widgets() + self.assertEquals(widgets, self.module.widgets()) # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/test_module.py b/tests/test_module.py new file mode 100644 index 0000000..34aa69d --- /dev/null +++ b/tests/test_module.py @@ -0,0 +1,25 @@ +# pylint: disable=C0103,C0111,W0703 + +import unittest + +from bumblebee.engine import Module +from tests.util import MockWidget + +class TestModule(unittest.TestCase): + def setUp(self): + self.widget = MockWidget("foo") + self.moduleWithoutWidgets = Module(engine=None, widgets=None) + self.moduleWithOneWidget = Module(engine=None, widgets=self.widget) + self.moduleWithMultipleWidgets = Module(engine=None, + widgets=[self.widget, self.widget, self.widget] + ) + + def test_empty_widgets(self): + self.assertEquals(self.moduleWithoutWidgets.widgets(), []) + + def test_single_widget(self): + self.assertEquals(self.moduleWithOneWidget.widgets(), [self.widget]) + + def test_multiple_widgets(self): + for widget in self.moduleWithMultipleWidgets.widgets(): + self.assertEquals(widget, self.widget) diff --git a/tests/util.py b/tests/util.py index 00001d5..e3bef15 100644 --- a/tests/util.py +++ b/tests/util.py @@ -23,6 +23,9 @@ class MockWidget(object): def __init__(self, text): self._text = text + def update(self, widgets): + pass + def full_text(self): return self._text