Skip to content

Commit e70bcf5

Browse files
committed
Config option to exclude block tags by regex
1 parent 53d114a commit e70bcf5

3 files changed

Lines changed: 59 additions & 9 deletions

File tree

README.rst

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -97,15 +97,17 @@ extensions if you like::
9797
[django_coverage_plugin]
9898
template_extensions = html, txt, tex, email
9999

100-
If you use ``pyproject.toml`` for tool configuration use::
100+
To exclude specific individual lines in a template, use the usual
101+
``# pragma: no cover`` notation inline. Template tags can also be excluded using regexes to
102+
match the block content; for example, to exclude a custom template tag
103+
``{% my_tag ... %}``, use::
101104

102-
[tool.coverage.run]
103-
plugins = [
104-
'django_coverage_plugin',
105-
]
105+
[run]
106+
plugins = django_coverage_plugin
107+
108+
[django_coverage_plugin]
109+
exclude_blocks = ["my_tag.+"]
106110

107-
[tool.coverage.django_coverage_plugin]
108-
template_extensions = 'html, txt, tex, email'
109111

110112
Caveats
111113
~~~~~~~

django_coverage_plugin/plugin.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import django
1111
import django.template
1212
from coverage.exceptions import NoSource
13+
from coverage.misc import join_regex
1314
from django.template.base import Lexer, NodeList, Template, TextNode, TokenType
1415
from django.template.defaulttags import VerbatimNode
1516
from django.templatetags.i18n import BlockTranslateNode
@@ -116,6 +117,8 @@ class DjangoTemplatePlugin(
116117
def __init__(self, options):
117118
extensions = options.get("template_extensions", "html,htm,txt")
118119
self.extensions = [e.strip() for e in extensions.split(",")]
120+
121+
self.exclude_blocks = options.get("exclude_blocks")
119122

120123
self.debug_checked = False
121124

@@ -151,7 +154,7 @@ def file_tracer(self, filename):
151154
return None
152155

153156
def file_reporter(self, filename):
154-
return FileReporter(filename)
157+
return FileReporter(filename, self.exclude_blocks)
155158

156159
def find_executable_files(self, src_dir):
157160
# We're only interested in files that look like reasonable HTML
@@ -259,10 +262,16 @@ def get_line_map(self, filename):
259262

260263

261264
class FileReporter(coverage.plugin.FileReporter):
262-
def __init__(self, filename):
265+
def __init__(self, filename, exclude_blocks):
263266
super().__init__(filename)
264267
# TODO: html filenames are absolute.
265268

269+
if exclude_blocks:
270+
self.exclude_blocks_regex = re.compile(join_regex(exclude_blocks))
271+
else:
272+
self.exclude_blocks_regex = None
273+
self._excluded = set()
274+
266275
self._source = None
267276

268277
def source(self):
@@ -318,6 +327,12 @@ def lines(self):
318327
# In an inheriting template, ignore all tags outside of
319328
# blocks.
320329
continue
330+
331+
# Ignore any block token content that has been explcitly
332+
# excluded in config
333+
if self.exclude_block_token(token):
334+
self._excluded.add(token.lineno)
335+
continue
321336

322337
if token.contents == "comment":
323338
comment = True
@@ -356,6 +371,12 @@ def lines(self):
356371

357372
return source_lines
358373

374+
def excluded_lines(self):
375+
return self._excluded
376+
377+
def exclude_block_token(self, token):
378+
if self.exclude_blocks_regex:
379+
return self.exclude_blocks_regex.search(token.contents)
359380

360381
def running_sum(seq):
361382
total = 0

tests/test_simple.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,3 +264,30 @@ def test_with_branch_enabled(self):
264264
)
265265
self.assertEqual(text, 'Hello\nWorld\n\nGoodbye')
266266
self.assert_analysis([1, 2, 3, 4])
267+
268+
269+
class ExcludeTest(DjangoPluginTestCase):
270+
"""Tests of excluding block tokens by regex."""
271+
272+
def test_exclude_block(self):
273+
self.make_template("""\
274+
First
275+
{% with foo='bar' %}
276+
{{ foo }}
277+
{% endwith %}
278+
Last
279+
""")
280+
text = self.run_django_coverage()
281+
self.assertEqual(text, "First\n\n bar\n\nLast\n")
282+
self.assert_analysis([1, 2, 3, 5])
283+
284+
self.make_file(".coveragerc", """\
285+
[run]
286+
plugins = django_coverage_plugin
287+
[django_coverage_plugin]
288+
exclude_blocks = [".+foo.+"]
289+
""")
290+
291+
text = self.run_django_coverage()
292+
self.assertEqual(text, "First\n\n bar\n\nLast\n")
293+
self.assert_analysis([1, 3, 5])

0 commit comments

Comments
 (0)