From aacc56a4e27e3cba239beff5370d449157c7129c Mon Sep 17 00:00:00 2001 From: Tobi-wan Kenobi Date: Sun, 4 Dec 2016 17:45:42 +0100 Subject: [PATCH] [modules/cpu] Add initial version of CPU utilization module Re-enable the CPU utilization module as proof-of-concept for the new core engine. see #23 --- bumblebee/engine.py | 8 +++++--- bumblebee/modules/cpu.py | 18 ++++++++++++++++++ bumblebee/modules/test.py | 2 +- bumblebee/output.py | 13 +++++++++++-- tests/modules/__init__.py | 0 tests/modules/test_cpu.py | 16 ++++++++++++++++ tests/test_engine.py | 13 ++++++++++++- tests/test_i3baroutput.py | 4 ++-- tests/util.py | 21 ++++++++++++++++++++- 9 files changed, 85 insertions(+), 10 deletions(-) create mode 100644 bumblebee/modules/cpu.py create mode 100644 tests/modules/__init__.py create mode 100644 tests/modules/test_cpu.py diff --git a/bumblebee/engine.py b/bumblebee/engine.py index 3c07d98..e2b4826 100644 --- a/bumblebee/engine.py +++ b/bumblebee/engine.py @@ -55,10 +55,12 @@ class Engine(object): while self.running(): widgets = [] for module in self._modules: - widgets += module.widgets() - self._output.draw(widgets) + module_widgets = module.widgets() + widgets += module_widgets if isinstance(module_widgets, list) else [module_widgets] + self._output.draw(widgets=widgets, engine=self) self._output.flush() - time.sleep(1) + if self.running(): + time.sleep(1) self._output.stop() diff --git a/bumblebee/modules/cpu.py b/bumblebee/modules/cpu.py new file mode 100644 index 0000000..ecc2376 --- /dev/null +++ b/bumblebee/modules/cpu.py @@ -0,0 +1,18 @@ +# pylint: disable=C0111,R0903 + +"""Displays CPU utilization across all CPUs.""" + +import psutil +import bumblebee.engine + +class Module(bumblebee.engine.Module): + def __init__(self, engine): + super(Module, self).__init__(engine) + self._utilization = psutil.cpu_percent(percpu=False) + + def widgets(self): + self._utilization = psutil.cpu_percent(percpu=False) + + return bumblebee.output.Widget(full_text="{:05.02f}%".format(self._utilization)) + +# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/test.py b/bumblebee/modules/test.py index 79c0ec9..94b99c4 100644 --- a/bumblebee/modules/test.py +++ b/bumblebee/modules/test.py @@ -9,6 +9,6 @@ class Module(bumblebee.engine.Module): super(Module, self).__init__(engine) def widgets(self): - return [] + return bumblebee.output.Widget(full_text="test") # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/output.py b/bumblebee/output.py index 96ebe0b..bd05450 100644 --- a/bumblebee/output.py +++ b/bumblebee/output.py @@ -5,6 +5,15 @@ import sys import json +class Widget(object): + """Represents a single visible block in the status bar""" + def __init__(self, full_text): + self._full_text = full_text + + def full_text(self): + """Retrieve the full text to display in the widget""" + return self._full_text + class I3BarOutput(object): """Manage output according to the i3bar protocol""" def __init__(self): @@ -18,14 +27,14 @@ class I3BarOutput(object): """Finish i3bar protocol""" sys.stdout.write("]\n") - def draw(self, widgets): + def draw(self, widgets, engine=None): """Draw a number of widgets""" if not isinstance(widgets, list): widgets = [widgets] result = [] for widget in widgets: result.append({ - u"full_text": widget.text() + u"full_text": widget.full_text() }) sys.stdout.write(json.dumps(result)) diff --git a/tests/modules/__init__.py b/tests/modules/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/modules/test_cpu.py b/tests/modules/test_cpu.py new file mode 100644 index 0000000..9c3be94 --- /dev/null +++ b/tests/modules/test_cpu.py @@ -0,0 +1,16 @@ +# pylint: disable=C0103,C0111 + +import unittest + +from bumblebee.modules.cpu import Module +from tests.util import assertWidgetAttributes + +class TestCPUModule(unittest.TestCase): + def setUp(self): + self.module = Module(None) + + def test_widgets(self): + widget = self.module.widgets() + assertWidgetAttributes(self, widget) + +# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/test_engine.py b/tests/test_engine.py index 2cb5ea3..03f8334 100644 --- a/tests/test_engine.py +++ b/tests/test_engine.py @@ -1,13 +1,17 @@ # pylint: disable=C0103,C0111 + import unittest from bumblebee.error import ModuleLoadError from bumblebee.engine import Engine from bumblebee.config import Config +from tests.util import MockOutput + class TestEngine(unittest.TestCase): def setUp(self): - self.engine = Engine(Config()) + self.engine = Engine(config=Config(), output=MockOutput()) + self.singleWidgetModule = [{"module": "test"}] self.testModule = "test" self.invalidModule = "no-such-module" self.testModuleSpec = "bumblebee.modules.{}".format(self.testModule) @@ -41,4 +45,11 @@ class TestEngine(unittest.TestCase): [self.testModuleSpec for module in modules] ) + def test_run(self): + self.engine.load_modules(self.singleWidgetModule) + try: + self.engine.run() + except Exception as e: + self.fail(e) + # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/tests/test_i3baroutput.py b/tests/test_i3baroutput.py index c8e01e0..4a277ae 100644 --- a/tests/test_i3baroutput.py +++ b/tests/test_i3baroutput.py @@ -32,14 +32,14 @@ class TestI3BarOutput(unittest.TestCase): def test_draw_single_widget(self, stdout): self.output.draw(self.someWidget) result = json.loads(stdout.getvalue())[0] - self.assertEquals(result["full_text"], self.someWidget.text()) + self.assertEquals(result["full_text"], self.someWidget.full_text()) @mock.patch("sys.stdout", new_callable=StringIO) def test_draw_multiple_widgets(self, stdout): self.output.draw([self.someWidget, self.someWidget]) result = json.loads(stdout.getvalue()) for res in result: - self.assertEquals(res["full_text"], self.someWidget.text()) + self.assertEquals(res["full_text"], self.someWidget.full_text()) @mock.patch("sys.stdout", new_callable=StringIO) def test_flush(self, stdout): diff --git a/tests/util.py b/tests/util.py index 202da49..542b220 100644 --- a/tests/util.py +++ b/tests/util.py @@ -1,10 +1,29 @@ # pylint: disable=C0103,C0111 +from bumblebee.output import Widget + +def assertWidgetAttributes(test, widget): + test.assertTrue(isinstance(widget, Widget)) + test.assertTrue(hasattr(widget, "full_text")) + +class MockOutput(object): + def start(self): + pass + + def stop(self): + pass + + def draw(self, widgets, engine): + engine.stop() + + def flush(self): + pass + class MockWidget(object): def __init__(self, text): self._text = text - def text(self): + def full_text(self): return self._text # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4