diff options
author | Lars Wirzenius <liw@liw.fi> | 2011-08-31 16:23:57 +0100 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2011-08-31 16:23:57 +0100 |
commit | 13b08556b2ed9533fc78ead7747af3c4297e8fcb (patch) | |
tree | 733933243d5ed09a9f6b957b71e9f5379135ca55 | |
parent | 31cb8821d1aa08bce246864554f18accd8873774 (diff) | |
parent | 0d93553e914d8aeb7eaf5d903f2d082ee7ec5a83 (diff) | |
download | python-ttystatus-13b08556b2ed9533fc78ead7747af3c4297e8fcb.tar.gz |
Add format string support.
-rw-r--r-- | NEWS | 2 | ||||
-rw-r--r-- | doc/index.rst | 7 | ||||
-rw-r--r-- | example.py | 7 | ||||
-rw-r--r-- | ttystatus/__init__.py | 2 | ||||
-rw-r--r-- | ttystatus/fmt.py | 66 | ||||
-rw-r--r-- | ttystatus/fmt_tests.py | 71 | ||||
-rw-r--r-- | ttystatus/status.py | 12 | ||||
-rw-r--r-- | ttystatus/status_tests.py | 6 |
8 files changed, 163 insertions, 10 deletions
@@ -8,6 +8,8 @@ Version 0.14, released XXXXXXXXXX * A method for printing error messages is provided. They are printed to the standard error. * The `PercentDone` class handles zero total amounts better now. +* Widgets may now be added using a simple format string. See + `ttystatus.TerminalStatus.format` method. Version 0.13, released 2011-08-18 --------------------------------- diff --git a/doc/index.rst b/doc/index.rst index 5f671bf..7119d5d 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -25,11 +25,8 @@ Here's an example program that searches for symlinks in a directory tree:: import ttystatus ts = ttystatus.TerminalStatus(period=0.1) - ts.add(ttystatus.ElapsedTime()) - ts.add(ttystatus.Literal(' Looking for files: ')) - ts.add(ttystatus.Counter('pathname')) - ts.add(ttystatus.Literal(' found, currently in ')) - ts.add(ttystatus.Pathname('dirname')) + ts.format('%ElapsedTime() Looking for files: %Counter(pathname) found, ' + 'currently in %Pathname(dirname)') pathnames = [] for dirname, subdirs, basenames in os.walk(sys.argv[1]): @@ -25,11 +25,8 @@ import ttystatus def main(): ts = ttystatus.TerminalStatus(period=0.1) - ts.add(ttystatus.ElapsedTime()) - ts.add(ttystatus.Literal(' Looking for files: ')) - ts.add(ttystatus.Counter('pathname')) - ts.add(ttystatus.Literal(' found, currently in ')) - ts.add(ttystatus.Pathname('dirname')) + ts.format('%ElapsedTime() Looking for files: %Counter(pathname) found, ' + 'currently in %Pathname(dirname)') pathnames = [] for dirname, subdirs, basenames in os.walk(sys.argv[1]): diff --git a/ttystatus/__init__.py b/ttystatus/__init__.py index 794f0ee..c2cfebc 100644 --- a/ttystatus/__init__.py +++ b/ttystatus/__init__.py @@ -33,4 +33,6 @@ from remtime import RemainingTime from elapsed import ElapsedTime from bytespeed import ByteSpeed +import fmt + __all__ = locals() diff --git a/ttystatus/fmt.py b/ttystatus/fmt.py new file mode 100644 index 0000000..bc0bbe8 --- /dev/null +++ b/ttystatus/fmt.py @@ -0,0 +1,66 @@ +# Copyright 2011 Lars Wirzenius +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +import inspect +import re + +import ttystatus + + +def _find_widgets(): + names = dir(ttystatus) + objs = [getattr(ttystatus, x) for x in names] + classes = [o for o in objs if inspect.isclass(o)] + widgets = [c for c in classes if issubclass(c, ttystatus.Widget)] + subclasses = [w for w in widgets if w != ttystatus.Widget] + return subclasses + +widgets = _find_widgets() + + +def parse(fmt): + '''Parse format string.''' + + names = [x.__name__ for x in widgets] + namespat = '|'.join(names) + argspat = r'[0-9a-zA-Z,_-]*' + pat = r'%%(?P<class>%s)\((?P<args>%s)\)' % (namespat, argspat) + pat = re.compile(pat) + + result = [] + prefix = '' + while fmt: + m = pat.match(fmt) + if m: + if prefix: + result.append(ttystatus.Literal(prefix)) + prefix = '' + klass = getattr(ttystatus, m.group('class')) + argnames = m.group('args').split(',') + argnames = [x for x in argnames if x] + result.append(klass(*argnames)) + fmt = fmt[m.end():] + elif fmt.startswith('%%'): + prefix += '%' + fmt = fmt[2:] + else: + prefix += fmt[0] + fmt = fmt[1:] + + if prefix: + result.append(ttystatus.Literal(prefix)) + return result + diff --git a/ttystatus/fmt_tests.py b/ttystatus/fmt_tests.py new file mode 100644 index 0000000..af39948 --- /dev/null +++ b/ttystatus/fmt_tests.py @@ -0,0 +1,71 @@ +# Copyright 2011 Lars Wirzenius +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +import unittest + +import ttystatus + + +class FormatTests(unittest.TestCase): + + def test_knows_widgets(self): + self.assertEqual(type(ttystatus.fmt.widgets), list) + self.assert_(len(ttystatus.fmt.widgets) > 0) + for widget in ttystatus.fmt.widgets: + self.assert_(issubclass(widget, ttystatus.Widget)) + self.assertNotEqual(widget, ttystatus.Widget) + + def test_parses_string_without_widgets(self): + x = ttystatus.fmt.parse('hello, world') + self.assertEqual(len(x), 1) + self.assertEqual(type(x[0]), ttystatus.Literal) + self.assertEqual(str(x[0]), 'hello, world') + + def test_parses_escaped_pecent(self): + x = ttystatus.fmt.parse('%%') + self.assertEqual(len(x), 1) + self.assertEqual(type(x[0]), ttystatus.Literal) + self.assertEqual(str(x[0]), '%') + + def test_parses_parameterless_widget(self): + x = ttystatus.fmt.parse('%ElapsedTime()') + + self.assertEqual(len(x), 1) + self.assertEqual(type(x[0]), ttystatus.ElapsedTime) + + def test_parses_widget_with_one_parameter(self): + x = ttystatus.fmt.parse('%String(name)') + + self.assertEqual(len(x), 1) + + self.assertEqual(type(x[0]), ttystatus.String) + self.assertEqual(x[0]._key, 'name') + + def test_parses_some_widgets(self): + x = ttystatus.fmt.parse('hello, %String(name): %ElapsedTime()') + + self.assertEqual(len(x), 4) + + self.assertEqual(type(x[0]), ttystatus.Literal) + self.assertEqual(str(x[0]), 'hello, ') + + self.assertEqual(type(x[1]), ttystatus.String) + + self.assertEqual(type(x[2]), ttystatus.Literal) + self.assertEqual(str(x[2]), ': ') + + self.assertEqual(type(x[3]), ttystatus.ElapsedTime) + diff --git a/ttystatus/status.py b/ttystatus/status.py index b5d743a..24f369b 100644 --- a/ttystatus/status.py +++ b/ttystatus/status.py @@ -44,6 +44,18 @@ class TerminalStatus(object): else: for key in widget.interesting_keys: self._interests[key] = self._interests.get(key, []) + [widget] + + def format(self, format_string): + '''Add new widgets based on format string. + + The format string is taken literally, except that ``%%`` is a + literal percent character, and ``%Foo(a,b,c)`` is a widget + of type ``Foo`` with parameters a, b, and c. For example: + ``format("hello, %String(name)")``. + + ''' + for widget in ttystatus.fmt.parse(format_string): + self.add(widget) def clear(self): '''Remove all widgets.''' diff --git a/ttystatus/status_tests.py b/ttystatus/status_tests.py index 9e6d0ac..3583028 100644 --- a/ttystatus/status_tests.py +++ b/ttystatus/status_tests.py @@ -78,6 +78,12 @@ class TerminalStatusTests(unittest.TestCase): w = W() self.ts.add(w) self.assert_(w in self.ts._wildcards) + + def test_adds_widgets_from_format_string(self): + self.ts.format('hello, %String(name)') + self.assertEqual(len(self.ts._widgets), 2) + self.assertEqual(type(self.ts._widgets[0]), ttystatus.Literal) + self.assertEqual(type(self.ts._widgets[1]), ttystatus.String) def test_removes_all_widgets(self): self.ts.add(ttystatus.Literal('foo')) |