[patchew-devel] [PATCH 4/6] add custom template tags for manipulating testing logs

  • From: Paolo Bonzini <pbonzini@xxxxxxxxxx>
  • To: patchew-devel@xxxxxxxxxxxxx
  • Date: Mon, 5 Mar 2018 10:16:32 +0100

These can be used to make test report emails shorter and more readable.

Signed-off-by: Paolo Bonzini <pbonzini@xxxxxxxxxx>
---
 patchew/tags.py           |  77 ++++++++++++++++++++++++++++++++++
 tests/test_custom_tags.py | 102 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 179 insertions(+)

diff --git a/patchew/tags.py b/patchew/tags.py
index 22d64b0..4847cb4 100644
--- a/patchew/tags.py
+++ b/patchew/tags.py
@@ -10,6 +10,57 @@
 
 from django import template
 from patchew import logviewer
+from collections import deque
+import io
+import operator
+import re
+
+# The basic implementation uses generators.  The filters simply apply join
+# to the result of the generators.
+
+def lines_iter(value):
+    if not isinstance(value, io.IOBase):
+        # StringIO provides a generator to split lines.
+        value = io.StringIO(value)
+    # "chomp" the newlines on each line.  Using operator and map does
+    # everything in the interpreter, avoiding the overhead of a generator.
+    return map(operator.methodcaller('rstrip', '\r\n'), value)
+
+# To understand grep_iter, it may help to first study this implementation
+# of a "tail" iterator, which is based on the same circular array idea:
+#
+#    def tail_lines_iter(value, n):
+#        lines = [None] * n
+#        lineno = 0
+#        for line in lines_iter(value):
+#            lines[lineno % n] = line
+#            lineno += 1
+#
+#        for i in range(max(lineno - n, 0), lineno):
+#            yield lines[i % n]
+#
+# Basic "grep" prints one line when the match is on the last line, so
+# "grep" is a variation on tail_lines with n=1; likewise, "grep -B1" is
+# a variantion on tail_lines with n=2, etc.
+
+def grep_iter(value, regex, n_before, n_after, sep):
+    n = n_before + 1
+    lines = [None] * n
+    stop = lineno = 0
+    for line in lines_iter(value):
+        # Print the (lineno - n)-th line.  Each element of lines[] is used
+        # just before it is thrown away.
+        if lineno - n >= 0 and lineno - n < stop:
+            yield lines[lineno % n]
+        if re.search(regex, line):
+            if lineno - n >= stop and sep is not None and stop > 0:
+                yield sep
+            stop = lineno + n_after + 1
+        lines[lineno % n] = line
+        lineno += 1
+
+    for i in range(max(lineno - n, 0), min(stop, lineno)):
+        yield lines[i % n]
 
 register = template.Library()
 
@@ -17,3 +68,29 @@ register = template.Library()
 @register.filter
 def ansi2text(value):
     return ''.join(logviewer.ansi2text(value))
+
+@register.simple_tag
+@register.filter
+def tail_lines(value, n):
+    lines = deque(lines_iter(value), n)
+    return '\n'.join(lines)
+
+@register.simple_tag
+@register.filter
+def grep(value, regex, sep=None):
+    return '\n'.join(grep_iter(value, regex, 0, 0, sep))
+
+@register.simple_tag
+@register.filter
+def grep_A(value, regex, n=3, sep='---'):
+    return '\n'.join(grep_iter(value, regex, 0, n, sep))
+
+@register.simple_tag
+@register.filter
+def grep_B(value, regex, n=3, sep='---'):
+    return '\n'.join(grep_iter(value, regex, n, 0, sep))
+
+@register.simple_tag
+@register.filter
+def grep_C(value, regex, n=3, sep='---'):
+    return '\n'.join(grep_iter(value, regex, n, n, sep))
diff --git a/tests/test_custom_tags.py b/tests/test_custom_tags.py
index ec875c8..aa828be 100755
--- a/tests/test_custom_tags.py
+++ b/tests/test_custom_tags.py
@@ -9,6 +9,7 @@
 # http://opensource.org/licenses/MIT.
 
 from django.template import Context, Template
+from patchew.tags import tail_lines, grep_A, grep_B, grep_C, grep
 import patchewtest
 import unittest
 
@@ -19,9 +20,110 @@ class CustomTagsTest(unittest.TestCase):
 
     def test_template_filters(self):
         self.assertTemplate('{{s|ansi2text}}', 'dbc', s='abc\rd')
+        self.assertTemplate('{{s|grep:"[0-9]"}}', '0\n9', s='0\na\n9')
+        self.assertTemplate('{{s|grep_A:"b"}}',
+                            'b\nc\nd\ne\n---\nb',
+                             s='a\nb\nc\nd\ne\nf\nx\ny\nz\nb')
+        self.assertTemplate('{{s|grep_B:"b"}}',
+                            'a\nb\n---\nx\ny\nz\nb',
+                             s='a\nb\nc\nd\ne\nf\nx\ny\nz\nb')
+        self.assertTemplate('{{s|grep_C:"b"}}',
+                            'a\nb\nc\nd\ne\n---\nx\ny\nz\nb',
+                             s='a\nb\nc\nd\ne\nf\nx\ny\nz\nb')
+        self.assertTemplate('{{s|tail_lines:3}}', 'b\nc\nd', s='a\nb\nc\nd')
 
     def test_template_tags(self):
         self.assertTemplate('{% ansi2text s %}', 'dbc', s='abc\rd')
+        self.assertTemplate('{% grep s "[0-9]" %}', '0\n9', s='0\na\n9')
+        self.assertTemplate('{% grep_A s regex="[bc]" n=1 %}', 'b\nc\nd', 
s='a\nb\nc\nd')
+        self.assertTemplate('{% grep_B s regex="[bc]" n=1 %}', 'a\nb\nc', 
s='a\nb\nc\nd')
+        self.assertTemplate('{% grep_C s "b" n=1 %}', 'a\nb\nc', 
s='a\nb\nc\nd')
+        self.assertTemplate('{% tail_lines s n=3 %}', 'b\nc\nd', 
s='a\nb\nc\nd')
+
+    def test_grep(self):
+        self.assertEqual(grep('0\na\n9', '[0-9]'), '0\n9')
+        self.assertEqual(grep('0\na\n9', '[0-9]', '---'), '0\n---\n9')
+
+    def test_grep_A(self):
+        self.assertEqual(grep_A('a\nb\nc\nd', 'b', 1, None), 'b\nc')
+        self.assertEqual(grep_A('a\nb\nc\nd', 'b', 2, None), 'b\nc\nd')
+        self.assertEqual(grep_A('a\nb\nc\nd\nb\ne', 'b', 1, None), 
'b\nc\nb\ne')
+        self.assertEqual(grep_A('a\nb\nc\nd\nb\ne', 'b', 2, None), 
'b\nc\nd\nb\ne')
+        self.assertEqual(grep_A('a\nb\nc\nd\nz\nb\ne', 'b', 1, None), 
'b\nc\nb\ne')
+        self.assertEqual(grep_A('a\nb\nc\nd\nz\nb\ne', 'b', 2, None), 
'b\nc\nd\nb\ne')
+        self.assertEqual(grep_A('a\nb\nc\nz\nb\nb\ne', 'b', 1, None), 
'b\nc\nb\nb\ne')
+        self.assertEqual(grep_A('b\nc\nz\nb\nb\ne', 'b', 1, None), 
'b\nc\nb\nb\ne')
+        self.assertEqual(grep_A('b\n', 'b', 1, None), 'b')
+
+    def test_grep_A_sep(self):
+        self.assertEqual(grep_A('a\nb\nc\nd', 'b', 1), 'b\nc')
+        self.assertEqual(grep_A('a\nb\nc\nd', 'b', 2), 'b\nc\nd')
+        self.assertEqual(grep_A('a\nb\nc\nd\nb\ne', 'b', 1), 'b\nc\n---\nb\ne')
+        self.assertEqual(grep_A('a\nb\nc\nd\nb\ne', 'b', 2), 'b\nc\nd\nb\ne')
+        self.assertEqual(grep_A('a\nb\nc\nd\nz\nb\ne', 'b', 1), 
'b\nc\n---\nb\ne')
+        self.assertEqual(grep_A('a\nb\nc\nd\nz\nb\nb\ne', 'b', 1), 
'b\nc\n---\nb\nb\ne')
+        self.assertEqual(grep_A('b\nc\nz\nb\nb\ne', 'b', 1), 
'b\nc\n---\nb\nb\ne')
+        self.assertEqual(grep_A('b\n', 'b', 1), 'b')
+
+    def test_grep_B(self):
+        self.assertEqual(grep_B('a\nb\nc\nd', 'b', 1, None), 'a\nb')
+        self.assertEqual(grep_B('a\nb\nc\nd', 'b', 2, None), 'a\nb')
+        self.assertEqual(grep_B('a\nb\nc\nd\nb\ne', 'b', 1, None), 
'a\nb\nd\nb')
+        self.assertEqual(grep_B('a\nb\nc\nd\nz\nb\ne', 'b', 1, None), 
'a\nb\nz\nb')
+        self.assertEqual(grep_B('a\nb\nc\nd\nz\nb\ne', 'b', 2, None), 
'a\nb\nd\nz\nb')
+        self.assertEqual(grep_B('a\nb\nc\nz\nb\nb\ne', 'b', 1, None), 
'a\nb\nz\nb\nb')
+        self.assertEqual(grep_B('b\nc\nz\nb\nb\ne', 'b', 1, None), 
'b\nz\nb\nb')
+        self.assertEqual(grep_B('b\n', 'b', 1, None), 'b')
+
+    def test_grep_B_sep(self):
+        self.assertEqual(grep_B('a\nb\nc\nd', 'b', 1), 'a\nb')
+        self.assertEqual(grep_B('a\nb\nc\nd', 'b', 2), 'a\nb')
+        self.assertEqual(grep_B('a\nb\nc\nd\nb\ne', 'b', 1), 'a\nb\n---\nd\nb')
+        self.assertEqual(grep_B('a\nb\nc\nd\nz\nb\ne', 'b', 1), 
'a\nb\n---\nz\nb')
+        self.assertEqual(grep_B('a\nb\nc\nd\nz\nb\ne', 'b', 2), 
'a\nb\n---\nd\nz\nb')
+        self.assertEqual(grep_B('a\nb\nc\nz\nb\nb\ne', 'b', 1), 
'a\nb\n---\nz\nb\nb')
+        self.assertEqual(grep_B('b\nc\nz\nb\nb\ne', 'b', 1), 'b\n---\nz\nb\nb')
+        self.assertEqual(grep_B('b\n', 'b', 1), 'b')
+
+    def test_grep_C(self):
+        self.assertEqual(grep_C('a\nb\nc\nd', 'b', 1, None), 'a\nb\nc')
+        self.assertEqual(grep_C('a\nb\nc\nd', 'b', 2, None), 'a\nb\nc\nd')
+        self.assertEqual(grep_C('a\nb\nc\nd\nb\ne', 'b', 1, None), 
'a\nb\nc\nd\nb\ne')
+        self.assertEqual(grep_C('a\nb\nc\nd\nz\nb\ne', 'b', 1, None), 
'a\nb\nc\nz\nb\ne')
+        self.assertEqual(grep_C('a\nb\nc\nd\nz\nb\ne', 'b', 2, None), 
'a\nb\nc\nd\nz\nb\ne')
+        self.assertEqual(grep_C('a\nb\nc\nz\nb\nb\ne', 'b', 1, None), 
'a\nb\nc\nz\nb\nb\ne')
+        self.assertEqual(grep_C('b\nc\nz\nb\nb\ne', 'b', 1, None), 
'b\nc\nz\nb\nb\ne')
+        self.assertEqual(grep_C('b\n', 'b', 1, None), 'b')
+
+    def test_grep_C_sep(self):
+        self.assertEqual(grep_C('a\nb\nc\nd', 'b', 1), 'a\nb\nc')
+        self.assertEqual(grep_C('a\nb\nc\nd', 'b', 2), 'a\nb\nc\nd')
+        self.assertEqual(grep_C('a\nb\nc\nd\nb\ne', 'b', 1), 
'a\nb\nc\nd\nb\ne')
+        self.assertEqual(grep_C('a\nb\nc\nd\nz\nb\ne', 'b', 1), 
'a\nb\nc\n---\nz\nb\ne')
+        self.assertEqual(grep_C('a\nb\nc\nd\nz\nb\ne', 'b', 2), 
'a\nb\nc\nd\nz\nb\ne')
+        self.assertEqual(grep_C('a\nb\nc\nz\nb\nb\ne', 'b', 1), 
'a\nb\nc\nz\nb\nb\ne')
+        self.assertEqual(grep_C('b\nc\nz\nb\nb\ne', 'b', 1), 
'b\nc\nz\nb\nb\ne')
+        self.assertEqual(grep_C('b\n', 'b', 1), 'b')
+
+    def test_tail_lines(self):
+        self.assertEqual(tail_lines('', 0), '')
+        self.assertEqual(tail_lines('', 1), '')
+        self.assertEqual(tail_lines('', 2), '')
+        self.assertEqual(tail_lines('', 4), '')
+
+        self.assertEqual(tail_lines('a\nb\n', 0), '')
+        self.assertEqual(tail_lines('a\nb\n', 1), 'b')
+        self.assertEqual(tail_lines('a\nb\n', 2), 'a\nb')
+
+        self.assertEqual(tail_lines('a\nb\nc\n', 2), 'b\nc')
+        self.assertEqual(tail_lines('a\nb\nc\n', 4), 'a\nb\nc')
+
+        self.assertEqual(tail_lines('a\nb\nc\nd\n', 2), 'c\nd')
+
+        self.assertEqual(tail_lines('\n\n\n', 2), '\n')
+        self.assertEqual(tail_lines('\n\n\nbc', 2), '\nbc')
+        self.assertEqual(tail_lines('\n\nbc', 3), '\n\nbc')
+        self.assertEqual(tail_lines('\n\n\n\nbc', 3), '\n\nbc')
 
 if __name__ == '__main__':
     unittest.main()
-- 
2.14.3



Other related posts:

  • » [patchew-devel] [PATCH 4/6] add custom template tags for manipulating testing logs - Paolo Bonzini