diff --git a/README.md b/README.md index e87ebd0..3232b17 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![Test Coverage](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status/badges/coverage.svg)](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status/coverage) [![Issue Count](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status/badges/issue_count.svg)](https://codeclimate.com/github/tobi-wan-kenobi/bumblebee-status) -**Many, many thanks to all contributors! As of now, 27 of the modules are from various contributors (!), and only 16 from myself.** +**Many, many thanks to all contributors! As of now, 28 of the modules are from various contributors (!), and only 16 from myself.** ![Solarized Powerline](https://github.com/tobi-wan-kenobi/bumblebee-status/blob/master/screenshots/themes/powerline-solarized.png) diff --git a/bumblebee/modules/nic.py b/bumblebee/modules/nic.py index ca47409..c1c60f8 100644 --- a/bumblebee/modules/nic.py +++ b/bumblebee/modules/nic.py @@ -35,6 +35,8 @@ class Module(bumblebee.engine.Module): self._states["include"].append(state) self._format = self.parameter("format","{intf} {state} {ip} {ssid}"); self._update_widgets(widgets) + self.iwgetid = bumblebee.util.which("iwgetid") + def update(self, widgets): self._update_widgets(widgets) @@ -106,7 +108,7 @@ class Module(bumblebee.engine.Module): def get_ssid(self, intf): if self._iswlan(intf): try: - return subprocess.check_output(["iwgetid","-r",intf]).strip().decode('utf-8') + return subprocess.check_output([self.iwgetid,"-r",intf]).strip().decode('utf-8') except: return "" return "" diff --git a/bumblebee/modules/notmuch_count.py b/bumblebee/modules/notmuch_count.py new file mode 100644 index 0000000..821118a --- /dev/null +++ b/bumblebee/modules/notmuch_count.py @@ -0,0 +1,51 @@ +# pylint: disable=C0111,R0903 + +"""Displays the result of a notmuch count query + default : unread emails which path do not contained "Trash" (notmuch count "tag:unread AND NOT path:/.*Trash.*/") + +Parameters: + * notmuch_count.query: notmuch count query to show result + +Errors: + if the notmuch query failed, the shown value is -1 + +Dependencies: + notmuch (https://notmuchmail.org/) +""" + +import bumblebee.input +import bumblebee.output +import bumblebee.engine +import os + +class Module(bumblebee.engine.Module): + + + def __init__(self, engine, config): + super(Module, self).__init__(engine, config, + bumblebee.output.Widget(full_text=self.output) + ) + self._notmuch_count_query = self.parameter("query", "tag:unread AND NOT path:/.*Trash.*/") + self._notmuch_count = self.count_notmuch() + + + def output(self, widget): + self._notmuch_count = self.count_notmuch() + return str(self._notmuch_count) + + + def state(self, widgets): + if self._notmuch_count == 0: + return "empty" + return "items" + + + def count_notmuch(self): + try: + notmuch_count_cmd = "notmuch count " + self._notmuch_count_query + notmuch_count = int(bumblebee.util.execute(notmuch_count_cmd)) + return notmuch_count + except Exception: + return -1 + +# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/bumblebee/modules/pulseaudio.py b/bumblebee/modules/pulseaudio.py index 2b4fd05..f6b33cf 100644 --- a/bumblebee/modules/pulseaudio.py +++ b/bumblebee/modules/pulseaudio.py @@ -6,6 +6,7 @@ Aliases: pasink (use this to control output instead of input), pasource Parameters: * pulseaudio.autostart: If set to "true" (default is "false"), automatically starts the pulseaudio daemon if it is not running + * pulseaudio.percent_change: How much to change volume by when scrolling on the module (default is 2%) Requires the following executable: * pulseaudio @@ -33,6 +34,13 @@ class Module(bumblebee.engine.Module): bumblebee.util.execute("pulseaudio --start") except Exception: pass + try: + percent_change = int(self.parameter("percent_change","2%").strip("%")) + except: + percent_change = 2 + if percent_change < 0 or percent_change > 100: + percent_change = 2 + self._left = 0 self._right = 0 @@ -51,8 +59,8 @@ class Module(bumblebee.engine.Module): events = [ {"type": "mute", "action": "toggle", "button": bumblebee.input.LEFT_MOUSE}, - {"type": "volume", "action": "+2%", "button": bumblebee.input.WHEEL_UP}, - {"type": "volume", "action": "-2%", "button": bumblebee.input.WHEEL_DOWN}, + {"type": "volume", "action": "+{percent}%".format(percent=percent_change), "button": bumblebee.input.WHEEL_UP}, + {"type": "volume", "action": "-{percent}%".format(percent=percent_change), "button": bumblebee.input.WHEEL_DOWN}, ] for event in events: diff --git a/bumblebee/util.py b/bumblebee/util.py index 8032032..f3545ac 100644 --- a/bumblebee/util.py +++ b/bumblebee/util.py @@ -60,4 +60,23 @@ def durationfmt(duration, shorten=False, suffix=False): return "{}{}".format(res, suf if suffix else "") +def which(program): + import os + def is_exe(fpath): + return os.path.isfile(fpath) and os.access(fpath, os.X_OK) + + fpath, fname = os.path.split(program) + if fpath: + if is_exe(program): + return program + else: + localPATH = os.environ["PATH"].split(os.pathsep) + localPATH += ["/sbin", "/usr/sbin/", "/usr/local/sbin"] + for path in localPATH: + exe_file = os.path.join(path, program) + if is_exe(exe_file): + return exe_file + + return None + # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/runtests.sh b/runtests.sh index 3ae7ddb..549eb4a 100755 --- a/runtests.sh +++ b/runtests.sh @@ -3,7 +3,7 @@ echo "testing with $(python2 -V 2>&1)" python2 $(which nosetests) -v --with-coverage --cover-erase tests/ -if [ $? == 0 ]; then +if test $? -eq 0 ; then echo echo "testing with $(python3 -V 2>&1)" diff --git a/tests/test_util.py b/tests/test_util.py index 1988756..07d6d3a 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -1,11 +1,12 @@ # pylint: disable=C0103,C0111 -import mock import unittest +import re import tests.mocks as mocks -from bumblebee.util import * +import bumblebee.util as bu + class TestUtil(unittest.TestCase): def setUp(self): @@ -17,40 +18,56 @@ class TestUtil(unittest.TestCase): self.popen.cleanup() def test_bytefmt(self): - self.assertEquals(bytefmt(10), "10.00B") - self.assertEquals(bytefmt(15*1024), "15.00KiB") - self.assertEquals(bytefmt(20*1024*1024), "20.00MiB") - self.assertEquals(bytefmt(22*1024*1024*1024), "22.00GiB") - self.assertEquals(bytefmt(35*1024*1024*1024*1024), "35840.00GiB") + self.assertEquals(bu.bytefmt(10), "10.00B") + self.assertEquals(bu.bytefmt(15 * 1024), "15.00KiB") + self.assertEquals(bu.bytefmt(20 * 1024 * 1024), "20.00MiB") + self.assertEquals(bu.bytefmt(22 * 1024 * 1024 * 1024), "22.00GiB") + self.assertEquals(bu.bytefmt(35 * 1024 * 1024 * 1024 * 1024), "35840.00GiB") def test_durationfmt(self): - self.assertEquals(durationfmt(00), "00:00") - self.assertEquals(durationfmt(25), "00:25") - self.assertEquals(durationfmt(60), "01:00") - self.assertEquals(durationfmt(119), "01:59") - self.assertEquals(durationfmt(3600), "01:00:00") - self.assertEquals(durationfmt(7265), "02:01:05") + self.assertEquals(bu.durationfmt(00), "00:00") + self.assertEquals(bu.durationfmt(25), "00:25") + self.assertEquals(bu.durationfmt(60), "01:00") + self.assertEquals(bu.durationfmt(119), "01:59") + self.assertEquals(bu.durationfmt(3600), "01:00:00") + self.assertEquals(bu.durationfmt(7265), "02:01:05") def test_execute(self): - execute(self.some_command_with_args) + bu.execute(self.some_command_with_args) self.assertTrue(self.popen.mock.popen.called) self.popen.mock.popen.assert_call(self.some_command_with_args) self.assertTrue(self.popen.mock.communicate.called) def test_execute_nowait(self): - execute(self.some_command_with_args, False) + bu.execute(self.some_command_with_args, False) self.assertTrue(self.popen.mock.popen.called) self.popen.mock.popen.assert_call(self.some_command_with_args) self.assertFalse(self.popen.mock.communicate.called) def test_execute_utf8(self): - self.popen.mock.communicate.return_value = [ self.some_utf8, None ] + self.popen.mock.communicate.return_value = [self.some_utf8, None] self.test_execute() def test_execute_error(self): self.popen.mock.returncode = 1 with self.assertRaises(RuntimeError): - execute(self.some_command_with_args) + bu.execute(self.some_command_with_args) + + def test_which(self): + # test for a binary that has to be somewhere + print(bu.which("ls")) + self.assertTrue(re.search('/(ls)$', bu.which("ls"))) + + # test for a binary that is not necessarily there + program = "iwgetid" + self.assertTrue( + bu.which(program) is None or + re.search('/(' + program + ')$', bu.which(program)) + ) + + # test if which also works with garbage input + self.assertTrue(bu.which("qwertygarbage") is None) + # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/themes/icons/awesome-fonts.json b/themes/icons/awesome-fonts.json index 8415de5..b6ca8d7 100644 --- a/themes/icons/awesome-fonts.json +++ b/themes/icons/awesome-fonts.json @@ -15,6 +15,9 @@ "load": { "prefix": "" }, "layout": { "prefix": "" }, "layout-xkb": { "prefix": "" }, + "notmuch_count": { "empty": {"prefix": "\uf0e0" }, + "items": {"prefix": "\uf0e0" } + }, "todo": { "empty": {"prefix": "" }, "items": {"prefix": "" }, "uptime": {"prefix": "" }