From 35d262f1fbf21164db246d60020d5ada78a95aaf Mon Sep 17 00:00:00 2001 From: Becky Smith Date: Wed, 21 Feb 2024 14:00:33 +0000 Subject: [PATCH 1/2] Config option to exclude block tags by regex --- README.rst | 16 +++++++++------- django_coverage_plugin/plugin.py | 26 ++++++++++++++++++++++++-- tests/test_simple.py | 27 +++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 9 deletions(-) diff --git a/README.rst b/README.rst index 7ce3fd4..6321a76 100644 --- a/README.rst +++ b/README.rst @@ -91,15 +91,17 @@ extensions if you like:: [django_coverage_plugin] template_extensions = html, txt, tex, email -If you use ``pyproject.toml`` for tool configuration use:: +To exclude specific individual lines in a template, use the usual +``# pragma: no cover`` notation inline. Template tags can also be excluded using regexes to +match the block content; for example, to exclude a custom template tag +``{% my_tag ... %}``, use:: - [tool.coverage.run] - plugins = [ - 'django_coverage_plugin', - ] + [run] + plugins = django_coverage_plugin + + [django_coverage_plugin] + exclude_blocks = ["my_tag.+"] - [tool.coverage.django_coverage_plugin] - template_extensions = 'html, txt, tex, email' Caveats ~~~~~~~ diff --git a/django_coverage_plugin/plugin.py b/django_coverage_plugin/plugin.py index 158ee9a..51a92e2 100644 --- a/django_coverage_plugin/plugin.py +++ b/django_coverage_plugin/plugin.py @@ -6,6 +6,8 @@ import os.path import re +from coverage.misc import join_regex + try: from coverage.exceptions import NoSource except ImportError: @@ -149,6 +151,8 @@ class DjangoTemplatePlugin( def __init__(self, options): extensions = options.get("template_extensions", "html,htm,txt") self.extensions = [e.strip() for e in extensions.split(",")] + + self.exclude_blocks = options.get("exclude_blocks") self.debug_checked = False @@ -184,7 +188,7 @@ def file_tracer(self, filename): return None def file_reporter(self, filename): - return FileReporter(filename) + return FileReporter(filename, self.exclude_blocks) def find_executable_files(self, src_dir): # We're only interested in files that look like reasonable HTML @@ -292,10 +296,16 @@ def get_line_map(self, filename): class FileReporter(coverage.plugin.FileReporter): - def __init__(self, filename): + def __init__(self, filename, exclude_blocks): super().__init__(filename) # TODO: html filenames are absolute. + if exclude_blocks: + self.exclude_blocks_regex = re.compile(join_regex(exclude_blocks)) + else: + self.exclude_blocks_regex = None + self._excluded = set() + self._source = None def source(self): @@ -351,6 +361,12 @@ def lines(self): # In an inheriting template, ignore all tags outside of # blocks. continue + + # Ignore any block token content that has been explcitly + # excluded in config + if self.exclude_block_token(token): + self._excluded.add(token.lineno) + continue if token.contents == "comment": comment = True @@ -389,6 +405,12 @@ def lines(self): return source_lines + def excluded_lines(self): + return self._excluded + + def exclude_block_token(self, token): + if self.exclude_blocks_regex: + return self.exclude_blocks_regex.search(token.contents) def running_sum(seq): total = 0 diff --git a/tests/test_simple.py b/tests/test_simple.py index a09ecb7..1034b25 100644 --- a/tests/test_simple.py +++ b/tests/test_simple.py @@ -264,3 +264,30 @@ def test_with_branch_enabled(self): ) self.assertEqual(text, 'Hello\nWorld\n\nGoodbye') self.assert_analysis([1, 2, 3, 4]) + + +class ExcludeTest(DjangoPluginTestCase): + """Tests of excluding block tokens by regex.""" + + def test_exclude_block(self): + self.make_template("""\ + First + {% with foo='bar' %} + {{ foo }} + {% endwith %} + Last + """) + text = self.run_django_coverage() + self.assertEqual(text, "First\n\n bar\n\nLast\n") + self.assert_analysis([1, 2, 3, 5]) + + self.make_file(".coveragerc", """\ + [run] + plugins = django_coverage_plugin + [django_coverage_plugin] + exclude_blocks = [".+foo.+"] + """) + + text = self.run_django_coverage() + self.assertEqual(text, "First\n\n bar\n\nLast\n") + self.assert_analysis([1, 3, 5]) From 0c842c278b27609361ae02b5458f4846110661e3 Mon Sep 17 00:00:00 2001 From: Becky Smith Date: Wed, 21 Feb 2024 14:00:33 +0000 Subject: [PATCH 2/2] Update README --- README.rst | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index 6321a76..7801649 100644 --- a/README.rst +++ b/README.rst @@ -91,10 +91,8 @@ extensions if you like:: [django_coverage_plugin] template_extensions = html, txt, tex, email -To exclude specific individual lines in a template, use the usual -``# pragma: no cover`` notation inline. Template tags can also be excluded using regexes to -match the block content; for example, to exclude a custom template tag -``{% my_tag ... %}``, use:: +Block tags can be excluded using regexes to match the block content; +for example, to exclude a custom template tag ``{% my_tag ... %}``, use:: [run] plugins = django_coverage_plugin