From 07970d93a1a0af9cb3621e3e698faf8b3ee58986 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Tue, 8 Jun 2021 08:44:08 -0400 Subject: [PATCH] feat: template file extensions are configurable. #60 --- HISTORY.rst | 5 +++ README.rst | 11 +++++ django_coverage_plugin/__init__.py | 2 +- django_coverage_plugin/plugin.py | 15 ++++--- tests/test_source.py | 66 ++++++++++++++++++++++++++++++ 5 files changed, 93 insertions(+), 6 deletions(-) create mode 100644 tests/test_source.py diff --git a/HISTORY.rst b/HISTORY.rst index 6033c74..40ae0ad 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -7,6 +7,10 @@ Unreleased Drop support for Python 3.4 and 3.5. +A setting is available: ``template_extensions`` lets you set the file +extensions that will be considered when looking for unused templates +(requested in `issue 60`_). + Fix an issue on Windows where file names were being compared case-sensitively, causing templates to be missed (`issue 46`_). @@ -14,6 +18,7 @@ Fix an issue (`issue 63`_) where tag libraries can't be found if imported during test collection. Thanks to Daniel Izquierdo for the fix. .. _issue 46: https://github.com/nedbat/django_coverage_plugin/issues/46 +.. _issue 60: https://github.com/nedbat/django_coverage_plugin/issues/60 .. _issue 63: https://github.com/nedbat/django_coverage_plugin/issues/63 v1.8.0 --- 2020-01-23 diff --git a/README.rst b/README.rst index 43dc170..e1d5b62 100644 --- a/README.rst +++ b/README.rst @@ -75,6 +75,17 @@ The Django template plugin uses some existing settings from your .coveragerc file. The ``source=``, ``include=``, and ``omit=`` options control what template files are included in the report. +The plugin can find unused template and include them in your results. By +default, it will look for files in your templates directory with an extension +of .html, .htm, or .txt. You can configure it to look for a different set of +extensions if you like:: + + [run] + plugins = django_coverage_plugin + + [django_coverage_plugin] + template_extensions = html, txt, tex, email + Caveats ~~~~~~~ diff --git a/django_coverage_plugin/__init__.py b/django_coverage_plugin/__init__.py index 04b4b90..e51c14e 100644 --- a/django_coverage_plugin/__init__.py +++ b/django_coverage_plugin/__init__.py @@ -8,4 +8,4 @@ def coverage_init(reg, options): - reg.add_file_tracer(DjangoTemplatePlugin()) + reg.add_file_tracer(DjangoTemplatePlugin(options)) diff --git a/django_coverage_plugin/plugin.py b/django_coverage_plugin/plugin.py index ac36681..a3e4867 100644 --- a/django_coverage_plugin/plugin.py +++ b/django_coverage_plugin/plugin.py @@ -155,7 +155,10 @@ class DjangoTemplatePlugin( coverage.plugin.FileTracer, ): - def __init__(self): + def __init__(self, options): + extensions = options.get("template_extensions", "html,htm,txt") + self.extensions = [e.strip() for e in extensions.split(",")] + self.debug_checked = False self.django_template_dir = os.path.normcase(os.path.realpath( @@ -190,12 +193,14 @@ def file_reporter(self, filename): return FileReporter(filename) def find_executable_files(self, src_dir): + # We're only interested in files that look like reasonable HTML + # files: Must end with one of our extensions, and must not have + # funny characters that probably mean they are editor junk. + rx = r"^[^.#~!$@%^&*()+=,]+\.(" + "|".join(self.extensions) + r")$" + for (dirpath, dirnames, filenames) in os.walk(src_dir): for filename in filenames: - # We're only interested in files that look like reasonable HTML - # files: Must end with .htm or .html, and must not have certain - # funny characters that probably mean they are editor junk. - if re.match(r"^[^.#~!$@%^&*()+=,]+\.html?$", filename): + if re.search(rx, filename): yield os.path.join(dirpath, filename) # --- FileTracer methods diff --git a/tests/test_source.py b/tests/test_source.py new file mode 100644 index 0000000..76992d3 --- /dev/null +++ b/tests/test_source.py @@ -0,0 +1,66 @@ +# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 +# For details: https://github.com/nedbat/django_coverage_plugin/blob/master/NOTICE.txt + +"""Tests of template inheritance for django_coverage_plugin.""" + +from .plugin_test import DjangoPluginTestCase + + +class FindSourceTest(DjangoPluginTestCase): + + def test_finding_source(self): + # This is a template that is rendered. + self.make_template(name="main.html", text="Hello") + # These are templates that aren't rendered, but are considered renderable. + self.make_template(name="unused.html", text="Not used") + self.make_template(name="unused.htm", text="Not used") + self.make_template(name="unused.txt", text="Not used") + # These are things left behind by an editor. + self.make_template(name="~unused.html", text="junk") + self.make_template(name="unused=.html", text="junk") + self.make_template(name="unused.html,", text="junk") + # This is some other file format we don't recognize. + self.make_template(name="phd.tex", text="Too complicated to read") + + text = self.run_django_coverage(name="main.html") + self.assertEqual(text, "Hello") + + # The rendered file has data, and was measured. + self.assert_analysis([1], name="main.html") + # The unrendered files have data, and were not measured. + self.assert_analysis([1], name="unused.html", missing=[1]) + self.assert_analysis([1], name="unused.htm", missing=[1]) + self.assert_analysis([1], name="unused.txt", missing=[1]) + # The editor leave-behinds are not in the measured files. + self.assert_measured_files("main.html", "unused.html", "unused.htm", "unused.txt") + + def test_customized_extensions(self): + self.make_file(".coveragerc", """\ + [run] + plugins = django_coverage_plugin + [django_coverage_plugin] + template_extensions = html, tex + """) + # This is a template that is rendered. + self.make_template(name="main.html", text="Hello") + # These are templates that aren't rendered, but are considered renderable. + self.make_template(name="unused.html", text="Not used") + self.make_template(name="phd.tex", text="Too complicated to read") + # These are things left behind by an editor. + self.make_template(name="~unused.html", text="junk") + self.make_template(name="unused=.html", text="junk") + self.make_template(name="unused.html,", text="junk") + # This is some other file format we don't recognize. + self.make_template(name="unused.htm", text="Not used") + self.make_template(name="unused.txt", text="Not used") + + text = self.run_django_coverage(name="main.html") + self.assertEqual(text, "Hello") + + # The rendered file has data, and was measured. + self.assert_analysis([1], name="main.html") + # The unrendered files have data, and were not measured. + self.assert_analysis([1], name="unused.html", missing=[1]) + self.assert_analysis([1], name="phd.tex", missing=[1]) + # The editor leave-behinds are not in the measured files. + self.assert_measured_files("main.html", "unused.html", "phd.tex")