These can be used to make test report emails shorter and more readable.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
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 variation 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
_______________________________________________
Patchew-devel mailing list
Patchew-devel@redhat.com
https://www.redhat.com/mailman/listinfo/patchew-devel
© 2016 - 2023 Red Hat, Inc.