Revision 339be5a8
b/lib/utils.py | ||
---|---|---|
45 | 45 |
import signal |
46 | 46 |
import datetime |
47 | 47 |
import calendar |
48 |
import collections |
|
48 | 49 |
|
49 | 50 |
from cStringIO import StringIO |
50 | 51 |
|
... | ... | |
2761 | 2762 |
"Failed to unlock %s" % self.filename) |
2762 | 2763 |
|
2763 | 2764 |
|
2765 |
class LineSplitter: |
|
2766 |
"""Splits data chunks into lines separated by newline. |
|
2767 |
|
|
2768 |
Instances provide a file-like interface. |
|
2769 |
|
|
2770 |
""" |
|
2771 |
def __init__(self, line_fn, *args): |
|
2772 |
"""Initializes this class. |
|
2773 |
|
|
2774 |
@type line_fn: callable |
|
2775 |
@param line_fn: Function called for each line, first parameter is line |
|
2776 |
@param args: Extra arguments for L{line_fn} |
|
2777 |
|
|
2778 |
""" |
|
2779 |
assert callable(line_fn) |
|
2780 |
|
|
2781 |
if args: |
|
2782 |
# Python 2.4 doesn't have functools.partial yet |
|
2783 |
self._line_fn = \ |
|
2784 |
lambda line: line_fn(line, *args) # pylint: disable-msg=W0142 |
|
2785 |
else: |
|
2786 |
self._line_fn = line_fn |
|
2787 |
|
|
2788 |
self._lines = collections.deque() |
|
2789 |
self._buffer = "" |
|
2790 |
|
|
2791 |
def write(self, data): |
|
2792 |
parts = (self._buffer + data).split("\n") |
|
2793 |
self._buffer = parts.pop() |
|
2794 |
self._lines.extend(parts) |
|
2795 |
|
|
2796 |
def flush(self): |
|
2797 |
while self._lines: |
|
2798 |
self._line_fn(self._lines.popleft().rstrip("\r\n")) |
|
2799 |
|
|
2800 |
def close(self): |
|
2801 |
self.flush() |
|
2802 |
if self._buffer: |
|
2803 |
self._line_fn(self._buffer) |
|
2804 |
|
|
2805 |
|
|
2764 | 2806 |
def SignalHandled(signums): |
2765 | 2807 |
"""Signal Handled decoration. |
2766 | 2808 |
|
b/test/ganeti.utils_unittest.py | ||
---|---|---|
1558 | 1558 |
self.fail("Didn't detect inner loop's exception") |
1559 | 1559 |
|
1560 | 1560 |
|
1561 |
class TestLineSplitter(unittest.TestCase): |
|
1562 |
def test(self): |
|
1563 |
lines = [] |
|
1564 |
ls = utils.LineSplitter(lines.append) |
|
1565 |
ls.write("Hello World\n") |
|
1566 |
self.assertEqual(lines, []) |
|
1567 |
ls.write("Foo\n Bar\r\n ") |
|
1568 |
ls.write("Baz") |
|
1569 |
ls.write("Moo") |
|
1570 |
self.assertEqual(lines, []) |
|
1571 |
ls.flush() |
|
1572 |
self.assertEqual(lines, ["Hello World", "Foo", " Bar"]) |
|
1573 |
ls.close() |
|
1574 |
self.assertEqual(lines, ["Hello World", "Foo", " Bar", " BazMoo"]) |
|
1575 |
|
|
1576 |
def _testExtra(self, line, all_lines, p1, p2): |
|
1577 |
self.assertEqual(p1, 999) |
|
1578 |
self.assertEqual(p2, "extra") |
|
1579 |
all_lines.append(line) |
|
1580 |
|
|
1581 |
def testExtraArgsNoFlush(self): |
|
1582 |
lines = [] |
|
1583 |
ls = utils.LineSplitter(self._testExtra, lines, 999, "extra") |
|
1584 |
ls.write("\n\nHello World\n") |
|
1585 |
ls.write("Foo\n Bar\r\n ") |
|
1586 |
ls.write("") |
|
1587 |
ls.write("Baz") |
|
1588 |
ls.write("Moo\n\nx\n") |
|
1589 |
self.assertEqual(lines, []) |
|
1590 |
ls.close() |
|
1591 |
self.assertEqual(lines, ["", "", "Hello World", "Foo", " Bar", " BazMoo", |
|
1592 |
"", "x"]) |
|
1593 |
|
|
1594 |
|
|
1561 | 1595 |
if __name__ == '__main__': |
1562 | 1596 |
testutils.GanetiTestProgram() |
Also available in: Unified diff