Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-django-coverage-plugin for openSUSE:Factory checked in at 2021-12-26 13:30:29 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-django-coverage-plugin (Old) and /work/SRC/openSUSE:Factory/.python-django-coverage-plugin.new.2520 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-django-coverage-plugin" Sun Dec 26 13:30:29 2021 rev:3 rq:942558 version:2.0.2 Changes: -------- --- /work/SRC/openSUSE:Factory/python-django-coverage-plugin/python-django-coverage-plugin.changes 2021-05-20 19:26:00.557708973 +0200 +++ /work/SRC/openSUSE:Factory/.python-django-coverage-plugin.new.2520/python-django-coverage-plugin.changes 2021-12-26 13:30:47.418971252 +0100 @@ -1,0 +2,20 @@ +Sun Dec 26 06:33:30 UTC 2021 - John Vandenberg <jay...@gmail.com> + +- Update to v2.0.2 + * If a non-UTF8 file was found when looking for templates, it + would fail when reading during the reporting phase, ending + execution. This failure is now raised in a way that can be + ignored with a .coveragerc setting of + [report] ignore_errors=True. + * When using source=., an existing coverage HTML report directory + would be found and believed to be unmeasured HTML template files +- from v2.0.0 + * 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 + * Fix an issue on Windows where file names were being compared + case-sensitively, causing templates to be missed + * Fix an issue where tag libraries can't be found if imported + during test collection. + +------------------------------------------------------------------- Old: ---- django_coverage_plugin-1.8.0.tar.gz New: ---- django_coverage_plugin-2.0.2.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-django-coverage-plugin.spec ++++++ --- /var/tmp/diff_new_pack.oMQdzP/_old 2021-12-26 13:30:48.094971722 +0100 +++ /var/tmp/diff_new_pack.oMQdzP/_new 2021-12-26 13:30:48.098971725 +0100 @@ -18,7 +18,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-django-coverage-plugin -Version: 1.8.0 +Version: 2.0.2 Release: 0 Summary: Django template coveragepy plugin License: Apache-2.0 @@ -59,8 +59,8 @@ %pytest %files %{python_files} +%doc README.rst %license LICENSE.txt -%doc HISTORY.rst README.rst %{python_sitelib}/* %changelog ++++++ django_coverage_plugin-1.8.0.tar.gz -> django_coverage_plugin-2.0.2.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django_coverage_plugin-1.8.0/.editorconfig new/django_coverage_plugin-2.0.2/.editorconfig --- old/django_coverage_plugin-1.8.0/.editorconfig 1970-01-01 01:00:00.000000000 +0100 +++ new/django_coverage_plugin-2.0.2/.editorconfig 2021-11-11 15:05:51.000000000 +0100 @@ -0,0 +1,38 @@ +# 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 + +# This file is for unifying the coding style for different editors and IDEs. +# More information at http://EditorConfig.org + +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = space +insert_final_newline = true +max_line_length = 80 +trim_trailing_whitespace = true + +[*.py] +max_line_length = 100 + +[*.yml] +indent_size = 2 + +[*.rst] +max_line_length = 79 + +[Makefile] +indent_style = tab +indent_size = 8 + +[*,cover] +trim_trailing_whitespace = false + +[*.diff] +trim_trailing_whitespace = false + +[.git/*] +trim_trailing_whitespace = false diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django_coverage_plugin-1.8.0/.github/workflows/tests.yml new/django_coverage_plugin-2.0.2/.github/workflows/tests.yml --- old/django_coverage_plugin-1.8.0/.github/workflows/tests.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/django_coverage_plugin-2.0.2/.github/workflows/tests.yml 2021-11-11 15:05:51.000000000 +0100 @@ -0,0 +1,106 @@ +# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 +# For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt + +name: "Tests" + +on: + push: + pull_request: + workflow_dispatch: + schedule: + # Since we test against the tip of Django development, run the tests once a + # week, Sundays at 6:00 UTC. + - cron: "0 6 * * 0" + + +defaults: + run: + shell: bash + +jobs: + tests: + name: "Python ${{ matrix.python-version }} on ${{ matrix.os }}" + runs-on: "${{ matrix.os }}" + + strategy: + matrix: + os: + - ubuntu-latest + - macos-latest + - windows-latest + python-version: + # When changing this list, be sure to check the [gh-actions] list in + # tox.ini so that tox will run properly. + - "2.7" + - "3.6" + - "3.7" + - "3.8" + - "3.9" + - "3.10" + exclude: + # Windows 2.7 doesn't work because Microsoft removed stuff we needed. + - os: windows-latest + python-version: "2.7" + fail-fast: false + + steps: + - name: "Check out the repo" + uses: "actions/checkout@v2" + + - name: "Set up Python" + uses: "actions/setup-python@v2" + with: + python-version: "${{ matrix.python-version }}" + + - name: "Install dependencies" + run: | + set -xe + python -VV + python -m site + python -m pip install -r requirements.txt + python -m pip install tox-gh-actions + + - name: "Run tox for ${{ matrix.python-version }}" + run: | + # GitHub Actions on Windows sets TEMP to a shortname, and HOME to a + # longname. Eventually, filename comparisons fail because of the + # difference. Fix $TEMP. + echo $TEMP + if [ "$RUNNER_OS" == "Windows" ]; then + export TMP=$HOME\\AppData\\Local\\Temp + export TEMP=$HOME\\AppData\\Local\\Temp + fi + echo $TEMP + python -m tox + + checks: + name: "Quality checks" + runs-on: "ubuntu-latest" + + steps: + - name: "Check out the repo" + uses: "actions/checkout@v2" + + - name: "Set up Python" + uses: "actions/setup-python@v2" + with: + python-version: "3.8" + + - name: "Install dependencies" + run: | + set -xe + python -VV + python -m site + python -m pip install -r requirements.txt + + - name: "Run check" + run: | + python -m tox -e check + + - name: "Run pkgcheck" + run: | + python -m tox -e pkgcheck + + - name: "Run doc" + run: | + python -m tox -e doc diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django_coverage_plugin-1.8.0/.travis.yml new/django_coverage_plugin-2.0.2/.travis.yml --- old/django_coverage_plugin-1.8.0/.travis.yml 2020-01-24 02:28:18.000000000 +0100 +++ new/django_coverage_plugin-2.0.2/.travis.yml 1970-01-01 01:00:00.000000000 +0100 @@ -1,11 +0,0 @@ -sudo: false -language: python -python: - - "2.7" - - "3.4" - - "3.5" - - "3.6" - - "3.7" - - "3.8" -install: pip install tox-travis -script: tox diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django_coverage_plugin-1.8.0/HISTORY.rst new/django_coverage_plugin-2.0.2/HISTORY.rst --- old/django_coverage_plugin-1.8.0/HISTORY.rst 2020-01-24 02:28:18.000000000 +0100 +++ new/django_coverage_plugin-2.0.2/HISTORY.rst 1970-01-01 01:00:00.000000000 +0100 @@ -1,138 +0,0 @@ -======= -History -======= - -v1.8.0 --- 2020-01-23 ---------------------- - -Add support for: - -- Coverage 5 - -v1.7.0 --- 2020-01-16 ---------------------- - -Add support for: - -- Python 3.7 & 3.8 -- Django 2.2 & 3.0 - -v1.6.0 --- 2018-09-04 ---------------------- - -Add support for Django 2.1. - - -v1.5.2 --- 2017-10-18 ---------------------- - -Validates support for Django version 2.0b1. Improves discovery of -template files. - - -v1.5.1a --- 2017-04-05 ----------------------- - -Validates support for Django version 1.11. Testing for new package -maintainer Pamela McA'Nulty - - -v1.5.0 --- 2017-02-23 ---------------------- - -Removes support for Django versions below 1.8. Validates support for -Django version 1.11b1 - - -v1.4.2 --- 2017-02-06 ---------------------- - -Fixes another instance of `issue 32`_, which was the result of an -initialization order problem. - - - -v1.4.1 --- 2017-01-25 ---------------------- - -Fixes `issue 32`_, which was the result of an initialization order -problem. - -.. _issue 32: https://github.com/nedbat/django_coverage_plugin/issues/32 - - - -v1.4 --- 2017-01-16 -------------------- - -Django 1.10.5 is now supported. - -Checking settings configuration is deferred so that settings.py is -included in coverage reporting. Fixes `issue 28`_. - -Only the ``django.template.backends.django.DjangoTemplates`` template -engine is supported, and it must be configured with -``['OPTIONS']['debug'] = True``. Fixes `issue 27`_. - -.. _issue 28: https://github.com/nedbat/django_coverage_plugin/issues/28 -.. _issue 27: https://github.com/nedbat/django_coverage_plugin/issues/27 - - - -v1.3.1 --- 2016-06-02 ---------------------- - -Settings are read slightly differently, so as to not interfere with -programs that don't need settings. Fixes `issue 18`_. - -.. _issue 18: https://github.com/nedbat/django_coverage_plugin/issues/18 - - - -v1.3 --- 2016-04-03 -------------------- - -Multiple template engines are allowed. Thanks, Simon Charette. - - - -v1.2.2 --- 2016-02-01 ---------------------- - -No change in code, but Django 1.9.2 is now supported. - - - -v1.2.1 --- 2016-01-28 ---------------------- - -The template debug settings are checked properly for people still using -``TEMPLATE_DEBUG`` in newer versions of Django. - - - -v1.2 --- 2016-01-16 -------------------- - -Check if template debugging is enabled in the settings, and raise a -visible warning if not. This prevents mysterious failures of the -plugin, and fixes `issue 17`_. - -Potential Django 1.9 support is included, but the patch to Django hasn't -been applied yet. - -.. _issue 17: https://github.com/nedbat/django_coverage_plugin/issues/17 - - - -v1.1 --- 2015-11-12 -------------------- - -Explicitly configure settings if need be to get things to work. - - - -v1.0 --- 2015-09-20 -------------------- - -First version :) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django_coverage_plugin-1.8.0/MANIFEST.in new/django_coverage_plugin-2.0.2/MANIFEST.in --- old/django_coverage_plugin-1.8.0/MANIFEST.in 2020-01-24 02:28:18.000000000 +0100 +++ new/django_coverage_plugin-2.0.2/MANIFEST.in 2021-11-11 15:05:51.000000000 +0100 @@ -7,8 +7,8 @@ exclude Makefile exclude requirements.txt exclude tox.ini +exclude .editorconfig include AUTHORS.txt -include HISTORY.rst include LICENSE.txt include NOTICE.txt include README.rst diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django_coverage_plugin-1.8.0/Makefile new/django_coverage_plugin-2.0.2/Makefile --- old/django_coverage_plugin-1.8.0/Makefile 2020-01-24 02:28:18.000000000 +0100 +++ new/django_coverage_plugin-2.0.2/Makefile 2021-11-11 15:05:51.000000000 +0100 @@ -3,13 +3,14 @@ # Makefile for django_coverage_plugin -default: - @echo "* No default action *" +help: ## Show this help. + @echo "Available targets:" + @grep '^[a-zA-Z]' $(MAKEFILE_LIST) | sort | awk -F ':.*?## ' 'NF==2 {printf " %-26s%s\n", $$1, $$2}' -test: - tox +test: ## Run all the tests. + tox -q -- -q -clean: +clean: ## Remove non-source files. -rm -rf *.egg-info -rm -rf build dist -rm -f *.pyc */*.pyc */*/*.pyc */*/*/*.pyc */*/*/*/*.pyc */*/*/*/*/*.pyc @@ -20,13 +21,13 @@ -rm -f .coverage .coverage.* coverage.xml -rm -f setuptools-*.egg distribute-*.egg distribute-*.tar.gz -sterile: clean +sterile: clean ## Remove all non-controlled content, even if expensive. -rm -rf .tox* -SDIST_CMD = python setup.py sdist --formats=gztar -kit: - $(SDIST_CMD) +kit: ## Make the source distribution. + python -m build + python -m twine check dist/* -kit_upload: - twine upload dist/* +kit_upload: ## Upload the built distributions to PyPI. + twine upload --verbose dist/* diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django_coverage_plugin-1.8.0/NOTICE.txt new/django_coverage_plugin-2.0.2/NOTICE.txt --- old/django_coverage_plugin-1.8.0/NOTICE.txt 2020-01-24 02:28:18.000000000 +0100 +++ new/django_coverage_plugin-2.0.2/NOTICE.txt 2021-11-11 15:05:51.000000000 +0100 @@ -1,4 +1,4 @@ -Copyright 2015-2020 Ned Batchelder. All rights reserved. +Copyright 2015-2021 Ned Batchelder. All rights reserved. Except where noted otherwise, this software is licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django_coverage_plugin-1.8.0/README.rst new/django_coverage_plugin-2.0.2/README.rst --- old/django_coverage_plugin-1.8.0/README.rst 2020-01-24 02:28:18.000000000 +0100 +++ new/django_coverage_plugin-2.0.2/README.rst 2021-11-11 15:05:51.000000000 +0100 @@ -26,11 +26,11 @@ A `coverage.py`_ plugin to measure test coverage of Django templates. -Supported Python versions: 2.7, 3.4, 3.5, 3.6, 3.7 and 3.8. +Supported Python versions: 2.7, and 3.6 through 3.10. -Supported Django versions: 1.8, 1.11, 2.0, 2.1, 2.2 and 3.0. +Supported Django versions: 1.8, 1.11, 2.x and 3.x. -Supported coverage.py version 4.x or 5.x. +Supported coverage.py versions: 4.x or higher. The plugin is pip installable:: @@ -39,8 +39,7 @@ To run it, add this setting to your ``.coveragerc`` file:: [run] - plugins = - django_coverage_plugin + plugins = django_coverage_plugin Then run your tests under `coverage.py`_. @@ -51,14 +50,51 @@ If you get a :code:`django.core.exceptions.ImproperlyConfigured` error, you need to set the :code:`DJANGO_SETTINGS_MODULE` environment variable. +Template coverage only works if your Django templates have debugging enabled. +If you get :code:`django_coverage_plugin.plugin.DjangoTemplatePluginException: +Template debugging must be enabled in settings`, or if no templates get +measured, make sure you have :code:`TEMPLATES.OPTIONS.debug` set to True in +your settings file: + +.. code-block:: python + + TEMPLATES = [ + { + ... + 'OPTIONS': { + 'debug': True, + }, + }, + ] + Configuration ~~~~~~~~~~~~~ The Django template plugin uses some existing settings from your -.coveragerc file. The ``source=``, ``include=``, and ``omit=`` options +``.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 + +If you use ``pyproject.toml`` for tool configuration use:: + + [tool.coverage.run] + plugins = [ + 'django_coverage_plugin', + ] + + [tool.coverage.django_coverage_plugin] + template_extensions = 'html, txt, tex, email' Caveats ~~~~~~~ @@ -90,5 +126,182 @@ $ pip install -r requirements.txt $ tox + +History +~~~~~~~ + +v2.0.2 ??? 2021-11-11 +------------------- + +If a non-UTF8 file was found when looking for templates, it would fail when +reading during the reporting phase, ending execution. This failure is now +raised in a way that can be ignored with a .coveragerc setting of ``[report] +ignore_errors=True`` (`issue 78`_). + +When using ``source=.``, an existing coverage HTML report directory would be +found and believed to be unmeasured HTML template files. This is now fixed. + +.. _issue 78: https://github.com/nedbat/django_coverage_plugin/issues/78 + + +v2.0.1 ??? 2021-10-06 +------------------- + +Test and claim our support on Python 3.10. + +v2.0.0 ??? 2021-06-08 +------------------- + +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`_). + +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 +------------------- + +Add support for: + +- Coverage 5 + +v1.7.0 ??? 2020-01-16 +------------------- + +Add support for: + +- Python 3.7 & 3.8 +- Django 2.2 & 3.0 + +v1.6.0 ??? 2018-09-04 +------------------- + +Add support for Django 2.1. + + +v1.5.2 ??? 2017-10-18 +------------------- + +Validates support for Django version 2.0b1. Improves discovery of +template files. + + +v1.5.1a ??? 2017-04-05 +-------------------- + +Validates support for Django version 1.11. Testing for new package +maintainer Pamela McA'Nulty + + +v1.5.0 ??? 2017-02-23 +------------------- + +Removes support for Django versions below 1.8. Validates support for +Django version 1.11b1 + + +v1.4.2 ??? 2017-02-06 +------------------- + +Fixes another instance of `issue 32`_, which was the result of an +initialization order problem. + + + +v1.4.1 ??? 2017-01-25 +------------------- + +Fixes `issue 32`_, which was the result of an initialization order +problem. + +.. _issue 32: https://github.com/nedbat/django_coverage_plugin/issues/32 + + + +v1.4 ??? 2017-01-16 +----------------- + +Django 1.10.5 is now supported. + +Checking settings configuration is deferred so that settings.py is +included in coverage reporting. Fixes `issue 28`_. + +Only the ``django.template.backends.django.DjangoTemplates`` template +engine is supported, and it must be configured with +``['OPTIONS']['debug'] = True``. Fixes `issue 27`_. + +.. _issue 28: https://github.com/nedbat/django_coverage_plugin/issues/28 +.. _issue 27: https://github.com/nedbat/django_coverage_plugin/issues/27 + + + +v1.3.1 ??? 2016-06-02 +------------------- + +Settings are read slightly differently, so as to not interfere with +programs that don't need settings. Fixes `issue 18`_. + +.. _issue 18: https://github.com/nedbat/django_coverage_plugin/issues/18 + + + +v1.3 ??? 2016-04-03 +----------------- + +Multiple template engines are allowed. Thanks, Simon Charette. + + + +v1.2.2 ??? 2016-02-01 +------------------- + +No change in code, but Django 1.9.2 is now supported. + + + +v1.2.1 ??? 2016-01-28 +------------------- + +The template debug settings are checked properly for people still using +``TEMPLATE_DEBUG`` in newer versions of Django. + + + +v1.2 ??? 2016-01-16 +----------------- + +Check if template debugging is enabled in the settings, and raise a +visible warning if not. This prevents mysterious failures of the +plugin, and fixes `issue 17`_. + +Potential Django 1.9 support is included, but the patch to Django hasn't +been applied yet. + +.. _issue 17: https://github.com/nedbat/django_coverage_plugin/issues/17 + + + +v1.1 ??? 2015-11-12 +----------------- + +Explicitly configure settings if need be to get things to work. + + + +v1.0 ??? 2015-09-20 +----------------- + +First version :) + .. _coverage.py: http://nedbatchelder.com/code/coverage .. _dtcov: https://github.com/traff/dtcov diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django_coverage_plugin-1.8.0/django_coverage_plugin/__init__.py new/django_coverage_plugin-2.0.2/django_coverage_plugin/__init__.py --- old/django_coverage_plugin-1.8.0/django_coverage_plugin/__init__.py 2020-01-24 02:28:18.000000000 +0100 +++ new/django_coverage_plugin-2.0.2/django_coverage_plugin/__init__.py 2021-11-11 15:05:51.000000000 +0100 @@ -3,9 +3,11 @@ """Django Template Coverage Plugin""" +from .plugin import DjangoTemplatePluginException # noqa from .plugin import DjangoTemplatePlugin -from .plugin import DjangoTemplatePluginException # noqa def coverage_init(reg, options): - reg.add_file_tracer(DjangoTemplatePlugin()) + plugin = DjangoTemplatePlugin(options) + reg.add_file_tracer(plugin) + reg.add_configurer(plugin) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django_coverage_plugin-1.8.0/django_coverage_plugin/plugin.py new/django_coverage_plugin-2.0.2/django_coverage_plugin/plugin.py --- old/django_coverage_plugin-1.8.0/django_coverage_plugin/plugin.py 2020-01-24 02:28:18.000000000 +0100 +++ new/django_coverage_plugin-2.0.2/django_coverage_plugin/plugin.py 2021-11-11 15:05:51.000000000 +0100 @@ -8,6 +8,11 @@ import os.path import re +try: + from coverage.exceptions import NoSource +except ImportError: + # for coverage 5.x + from coverage.misc import NoSource import coverage.plugin import django import django.template @@ -25,7 +30,10 @@ except ImportError: # Django <2.1 uses separate constants for token types from django.template.base import ( - TOKEN_BLOCK, TOKEN_MAPPING, TOKEN_TEXT, TOKEN_VAR + TOKEN_BLOCK, + TOKEN_MAPPING, + TOKEN_TEXT, + TOKEN_VAR, ) class TokenType: @@ -75,6 +83,8 @@ return False if not hasattr(django.template.backends.django, "DjangoTemplates"): raise DjangoTemplatePluginException("Can't use non-Django templates.") + if not django.template.engines._engines: + return False for engine in django.template.engines.all(): if not isinstance(engine, django.template.backends.django.DjangoTemplates): @@ -150,12 +160,15 @@ 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.realpath( + self.django_template_dir = os.path.normcase(os.path.realpath( os.path.dirname(django.template.__file__) - ) + )) self.source_map = {} @@ -171,8 +184,11 @@ )), ] + def configure(self, config): + self.html_report_dir = os.path.abspath(config.get_option("html:directory")) + def file_tracer(self, filename): - if filename.startswith(self.django_template_dir): + if os.path.normcase(filename).startswith(self.django_template_dir): if not self.debug_checked: # Keep calling check_debug until it returns True, which it # will only do after settings have been configured @@ -185,12 +201,17 @@ 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): + if dirpath == self.html_report_dir: + # Don't confuse the HTML report with HTML templates. + continue 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 @@ -198,8 +219,12 @@ def has_dynamic_source_filename(self): return True + # "render" is the public method, but "render_annotated" is an internal + # method sometimes implemented directly on nodes. + RENDER_METHODS = {"render", "render_annotated"} + def dynamic_source_filename(self, filename, frame): - if frame.f_code.co_name != 'render': + if frame.f_code.co_name not in self.RENDER_METHODS: return None if 0: @@ -214,7 +239,7 @@ return None def line_number_range(self, frame): - assert frame.f_code.co_name == 'render' + assert frame.f_code.co_name in self.RENDER_METHODS if 0: dump_frame(frame, label="line_number_range") @@ -289,7 +314,10 @@ def source(self): if self._source is None: - self._source = read_template_source(self.filename) + try: + self._source = read_template_source(self.filename) + except (IOError, UnicodeError) as exc: + raise NoSource("Couldn't read {}: {}".format(self.filename, exc)) return self._source def lines(self): @@ -387,7 +415,7 @@ def make_line_map(text): - line_lengths = [len(l) for l in text.splitlines(True)] + line_lengths = [len(line) for line in text.splitlines(True)] line_map = list(running_sum(line_lengths)) return line_map diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django_coverage_plugin-1.8.0/howto.txt new/django_coverage_plugin-2.0.2/howto.txt --- old/django_coverage_plugin-1.8.0/howto.txt 2020-01-24 02:28:18.000000000 +0100 +++ new/django_coverage_plugin-2.0.2/howto.txt 2021-11-11 15:05:51.000000000 +0100 @@ -8,8 +8,8 @@ Development Status :: 5 - Production/Stable - Copyright date in NOTICE.txt - Update README.rst with latest changes -- Update HISTORY.rst with latest changes - Kits: - $ make kit + $ make clean kit $ make kit_upload - tag git +- make a new gh release: https://github.com/nedbat/django_coverage_plugin/releases/new diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django_coverage_plugin-1.8.0/requirements.txt new/django_coverage_plugin-2.0.2/requirements.txt --- old/django_coverage_plugin-1.8.0/requirements.txt 2020-01-24 02:28:18.000000000 +0100 +++ new/django_coverage_plugin-2.0.2/requirements.txt 2021-11-11 15:05:51.000000000 +0100 @@ -1,3 +1,4 @@ # To run tests, we just need tox. tox >= 1.8 +build twine diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django_coverage_plugin-1.8.0/setup.cfg new/django_coverage_plugin-2.0.2/setup.cfg --- old/django_coverage_plugin-1.8.0/setup.cfg 1970-01-01 01:00:00.000000000 +0100 +++ new/django_coverage_plugin-2.0.2/setup.cfg 2021-11-11 15:05:51.000000000 +0100 @@ -0,0 +1,10 @@ +# 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 + +[tool:pytest] +# How come these warnings are suppressed successfully here, but not in conftest.py?? +filterwarnings = + # ignore all DeprecationWarnings... + ignore::DeprecationWarning + # ...but show them if they are from our code. + default::DeprecationWarning:django_coverage_plugin diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django_coverage_plugin-1.8.0/setup.py new/django_coverage_plugin-2.0.2/setup.py --- old/django_coverage_plugin-1.8.0/setup.py 2020-01-24 02:28:18.000000000 +0100 +++ new/django_coverage_plugin-2.0.2/setup.py 2021-11-11 15:05:51.000000000 +0100 @@ -33,11 +33,11 @@ License :: OSI Approved :: Apache Software License Operating System :: OS Independent Programming Language :: Python :: 2.7 -Programming Language :: Python :: 3.4 -Programming Language :: Python :: 3.5 Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 +Programming Language :: Python :: 3.9 +Programming Language :: Python :: 3.10 Programming Language :: Python :: Implementation :: CPython Programming Language :: Python :: Implementation :: PyPy Topic :: Software Development :: Quality Assurance @@ -46,15 +46,13 @@ Framework :: Django Framework :: Django :: 1.8 Framework :: Django :: 1.11 -Framework :: Django :: 2.0 -Framework :: Django :: 2.1 Framework :: Django :: 2.2 -Framework :: Django :: 3.0 +Framework :: Django :: 3.2 """ setup( name='django_coverage_plugin', - version='1.8.0', + version='2.0.2', description='Django template coverage.py plugin', long_description=( re.compile( @@ -62,6 +60,7 @@ re.M | re.S, ).sub('', read('README.rst')) ), + long_description_content_type='text/x-rst', author='Ned Batchelder', author_email='n...@nedbatchelder.com', url='https://github.com/nedbat/django_coverage_plugin', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django_coverage_plugin-1.8.0/tests/__init__.py new/django_coverage_plugin-2.0.2/tests/__init__.py --- old/django_coverage_plugin-1.8.0/tests/__init__.py 2020-01-24 02:28:18.000000000 +0100 +++ new/django_coverage_plugin-2.0.2/tests/__init__.py 2021-11-11 15:05:51.000000000 +0100 @@ -5,7 +5,10 @@ # Define URLs here so we can use ROOT_URLCONF="tests" -from django.conf.urls import url +try: + from django.urls import re_path +except ImportError: + from django.conf.urls import url as re_path def index(request): @@ -14,5 +17,5 @@ urlpatterns = [ - url(r'^home$', index, name='index'), + re_path(r'^home$', index, name='index'), ] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django_coverage_plugin-1.8.0/tests/conftest.py new/django_coverage_plugin-2.0.2/tests/conftest.py --- old/django_coverage_plugin-1.8.0/tests/conftest.py 1970-01-01 01:00:00.000000000 +0100 +++ new/django_coverage_plugin-2.0.2/tests/conftest.py 2021-11-11 15:05:51.000000000 +0100 @@ -0,0 +1,38 @@ +# 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 + +""" +Pytest auto configuration. + +This module is run automatically by pytest, to define and enable fixtures. +""" + +import re +import warnings + +import django.utils.deprecation +import pytest + + +@pytest.fixture(autouse=True) +def set_warnings(): + """Configure warnings to show while running tests.""" + warnings.simplefilter("default") + warnings.simplefilter("once", DeprecationWarning) + + # Warnings to suppress: + # How come these warnings are successfully suppressed here, but not in setup.cfg?? + + # We know we do tricky things with Django settings, don't warn us about it. + warnings.filterwarnings( + "ignore", + category=UserWarning, + message=r"Overriding setting DATABASES can lead to unexpected behavior.", + ) + + # Django has warnings like RemovedInDjango40Warning. We use features that are going to be + # deprecated, so we don't need to see those warnings. But the specific warning classes change + # in every release. Find them and ignore them. + for name, obj in vars(django.utils.deprecation).items(): + if re.match(r"RemovedInDjango\d+Warning", name): + warnings.filterwarnings("ignore", category=obj) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django_coverage_plugin-1.8.0/tests/plugin_test.py new/django_coverage_plugin-2.0.2/tests/plugin_test.py --- old/django_coverage_plugin-1.8.0/tests/plugin_test.py 2020-01-24 02:28:18.000000000 +0100 +++ new/django_coverage_plugin-2.0.2/tests/plugin_test.py 2021-11-11 15:05:51.000000000 +0100 @@ -52,7 +52,7 @@ if django.VERSION < (1, 10): # for {% ssi %} - the_settings['TEMPLATES'][0]['OPTIONS']['allowed_include_roots'] = ['/'] + the_settings['TEMPLATES'][0]['OPTIONS']['allowed_include_roots'] = [""] return the_settings @@ -176,9 +176,15 @@ _, executable, _, missing, _ = analysis return executable, missing - def measured_files(self): - """Get the list of measured files, in relative form.""" - return [os.path.relpath(f) for f in self.cov.get_data().measured_files()] + def assert_measured_files(self, *template_files): + """Assert that the measured files are `template_files`. + + The names in `template_files` are the base names of files + in the templates directory. + """ + measured = {os.path.relpath(f) for f in self.cov.get_data().measured_files()} + expected = {os.path.join("templates", f) for f in template_files} + self.assertEqual(measured, expected) def assert_analysis(self, executable, missing=None, name=None): """Assert that the analysis for `name` is right.""" @@ -225,19 +231,27 @@ """Assert that our plugin was disabled during an operation.""" # self.run_django_coverage will raise PluginDisabled if the plugin # was disabled. - with self.assertRaises(PluginDisabled): - yield - stderr = self.stderr() + # Coverage.py 6.0 made the warnings real warnings, so we have to adapt + # how we test the warnings based on the version. + if coverage.version.version_info >= (6, 0): + import coverage.exceptions as cov_exc + ctxmgr = self.assertWarns(cov_exc.CoverageWarning) + else: + ctxmgr = nullcontext() + with ctxmgr as cw: + with self.assertRaises(PluginDisabled): + yield + + if cw is not None: + warn_text = "\n".join(str(w.message) for w in cw.warnings) + else: + warn_text = self.stderr() self.assertIn( - "Coverage.py warning: " "Disabling plug-in 'django_coverage_plugin.DjangoTemplatePlugin' " "due to an exception:", - stderr - ) - self.assertIn( - "DjangoTemplatePluginException: " + msg, - stderr + warn_text ) + self.assertIn("DjangoTemplatePluginException: " + msg, warn_text) def squashed(s): @@ -276,3 +290,9 @@ class PluginDisabled(Exception): """Raised if we find that our plugin has been disabled.""" pass + + +@contextlib.contextmanager +def nullcontext(): + """For when we need a context manager to do nothing.""" + yield None diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django_coverage_plugin-1.8.0/tests/test_extends.py new/django_coverage_plugin-2.0.2/tests/test_extends.py --- old/django_coverage_plugin-1.8.0/tests/test_extends.py 2020-01-24 02:28:18.000000000 +0100 +++ new/django_coverage_plugin-2.0.2/tests/test_extends.py 2021-11-11 15:05:51.000000000 +0100 @@ -168,10 +168,7 @@ text = self.run_django_coverage(name="outer.html", context={'a': 17}) self.assertEqual(text, "First\nInside {{ a }}\nJob\n\nLast\n") self.assert_analysis([1, 2, 3], name="outer.html") - self.assertEqual( - set(self.measured_files()), - set(["templates/outer.html", "templates/nested.html"]) - ) + self.assert_measured_files("outer.html", "nested.html") def test_ssi_parsed(self): nested = self.make_template(name="nested.html", text="""\ @@ -188,7 +185,4 @@ text = self.run_django_coverage(name="outer.html", context={'a': 17}) self.assertEqual(text, "First\nInside 17\nJob\n\nLast\n") self.assert_analysis([1, 2, 3], name="outer.html") - self.assertEqual( - set(self.measured_files()), - set(["templates/outer.html", "templates/nested.html"]) - ) + self.assert_measured_files("outer.html", "nested.html") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django_coverage_plugin-1.8.0/tests/test_flow.py new/django_coverage_plugin-2.0.2/tests/test_flow.py --- old/django_coverage_plugin-1.8.0/tests/test_flow.py 2020-01-24 02:28:18.000000000 +0100 +++ new/django_coverage_plugin-2.0.2/tests/test_flow.py 2021-11-11 15:05:51.000000000 +0100 @@ -5,7 +5,7 @@ import textwrap -from .plugin_test import DjangoPluginTestCase, squashed +from .plugin_test import DjangoPluginTestCase, django_stop_before, squashed class IfTest(DjangoPluginTestCase): @@ -173,6 +173,7 @@ self.assert_analysis([1, 2, 3, 4, 5]) +@django_stop_before(4, 0) class IfEqualTest(DjangoPluginTestCase): def test_ifequal(self): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django_coverage_plugin-1.8.0/tests/test_html.py new/django_coverage_plugin-2.0.2/tests/test_html.py --- old/django_coverage_plugin-1.8.0/tests/test_html.py 2020-01-24 02:28:18.000000000 +0100 +++ new/django_coverage_plugin-2.0.2/tests/test_html.py 2021-11-11 15:05:51.000000000 +0100 @@ -4,6 +4,8 @@ """Tests of HTML reporting for django_coverage_plugin.""" +import glob + from .plugin_test import DjangoPluginTestCase @@ -16,6 +18,7 @@ self.run_django_coverage() self.cov.html_report() - with open("htmlcov/templates_test_simple_html.html") as fhtml: + html_file = glob.glob("htmlcov/*_test_simple_html.html")[0] + with open(html_file) as fhtml: html = fhtml.read() self.assertIn('<span class="txt">Simple © 2015</span>', html) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django_coverage_plugin-1.8.0/tests/test_source.py new/django_coverage_plugin-2.0.2/tests/test_source.py --- old/django_coverage_plugin-1.8.0/tests/test_source.py 1970-01-01 01:00:00.000000000 +0100 +++ new/django_coverage_plugin-2.0.2/tests/test_source.py 2021-11-11 15:05:51.000000000 +0100 @@ -0,0 +1,174 @@ +# 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.""" + +import os + +try: + from coverage.exceptions import NoSource +except ImportError: + # for coverage 5.x + from coverage.misc import NoSource + +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") + + def test_non_utf8_error(self): + # A non-UTF8 text file will raise an error. + self.make_file(".coveragerc", """\ + [run] + plugins = django_coverage_plugin + source = . + """) + # This is a template that is rendered. + self.make_template(name="main.html", text="Hello") + # Extra file containing a word encoded in CP-1252 + self.make_file(self._path("static/changelog.txt"), bytes=b"sh\xf6n") + + text = self.run_django_coverage(name="main.html") + self.assertEqual(text, "Hello") + + self.assert_measured_files("main.html", "static{}changelog.txt".format(os.sep)) + self.assert_analysis([1], name="main.html") + with self.assertRaisesRegexp(NoSource, r"changelog.txt.*invalid start byte"): + self.cov.html_report() + + def test_non_utf8_omitted(self): + # If we omit the directory with the non-UTF8 file, all is well. + self.make_file(".coveragerc", """\ + [run] + plugins = django_coverage_plugin + source = . + [report] + omit = */static/* + """) + # This is a template that is rendered. + self.make_template(name="main.html", text="Hello") + # Extra file containing a word encoded in CP-1252 + self.make_file(self._path("static/changelog.txt"), bytes=b"sh\xf6n") + + text = self.run_django_coverage(name="main.html") + self.assertEqual(text, "Hello") + + self.assert_measured_files("main.html", "static{}changelog.txt".format(os.sep)) + self.assert_analysis([1], name="main.html") + self.cov.html_report() + + def test_non_utf8_ignored(self): + # If we ignore reporting errors, a non-UTF8 text file is fine. + self.make_file(".coveragerc", """\ + [run] + plugins = django_coverage_plugin + source = . + [report] + ignore_errors = True + """) + # This is a template that is rendered. + self.make_template(name="main.html", text="Hello") + # Extra file containing a word encoded in CP-1252 + self.make_file(self._path("static/changelog.txt"), bytes=b"sh\xf6n") + + text = self.run_django_coverage(name="main.html") + self.assertEqual(text, "Hello") + + self.assert_measured_files("main.html", "static{}changelog.txt".format(os.sep)) + self.assert_analysis([1], name="main.html") + self.cov.html_report() + + def test_htmlcov_isnt_measured(self): + # We used to find the HTML report and think it was template files. + self.make_file(".coveragerc", """\ + [run] + plugins = django_coverage_plugin + source = . + """) + self.make_template(name="main.html", text="Hello") + text = self.run_django_coverage(name="main.html") + self.assertEqual(text, "Hello") + + self.assert_measured_files("main.html") + self.cov.html_report() + + # Run coverage again with an HTML report on disk. + text = self.run_django_coverage(name="main.html") + self.assert_measured_files("main.html") + + def test_custom_html_report_isnt_measured(self): + # We used to find the HTML report and think it was template files. + self.make_file(".coveragerc", """\ + [run] + plugins = django_coverage_plugin + source = . + [html] + directory = my_html_report + """) + self.make_template(name="main.html", text="Hello") + text = self.run_django_coverage(name="main.html") + self.assertEqual(text, "Hello") + + self.assert_measured_files("main.html") + self.cov.html_report() + + # Run coverage again with an HTML report on disk. + text = self.run_django_coverage(name="main.html") + self.assert_measured_files("main.html") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django_coverage_plugin-1.8.0/tox.ini new/django_coverage_plugin-2.0.2/tox.ini --- old/django_coverage_plugin-1.8.0/tox.ini 2020-01-24 02:28:18.000000000 +0100 +++ new/django_coverage_plugin-2.0.2/tox.ini 2021-11-11 15:05:51.000000000 +0100 @@ -14,30 +14,27 @@ [tox] envlist = - py27-django{18,19,110,111}, - py34-django{18,19,110,111,20}, - py35-django{18,19,110,111,20,21,22}, - py36-django{18,19,110,111,20,21,22,30,tip}, - py37-django{20,21,22,30,tip}, - py38-django{22,30,tip}, + py27-django{18,111}, + py36-django{18,111,22,32}, + py37-django{22,32}, + py38-django{22,32,tip}, + py39-django{22,32,tip}, + py310-django{32,tip}, check,pkgcheck,doc [testenv] deps = + pytest unittest-mixins==1.6 django18: Django>=1.8,<1.9 - django19: Django>=1.9,<1.10 - django110: Django>=1.10,<1.11 django111: Django>=1.11,<2.0 - django20: Django>=2.0,<2.1 - django21: Django>=2.1,<2.2 django22: Django>=2.2,<3.0 - django30: Django>=3.0,<3.1 - djangotip: https://github.com/django/django/archive/master.tar.gz + django32: Django>=3.2,<4.0 + djangotip: https://github.com/django/django/archive/main.tar.gz commands = python -c "import tests.banner" - python -m unittest {posargs:discover -b} + python -m pytest {posargs} usedevelop = True @@ -50,17 +47,20 @@ commands = flake8 --max-line-length=100 setup.py django_coverage_plugin tests setup.py - isort --verbose --check-only --diff --recursive django_coverage_plugin tests setup.py + isort --check-only --diff django_coverage_plugin tests setup.py [testenv:pkgcheck] skip_install = true deps = + build docutils check-manifest readme-renderer + twine commands = - python setup.py check --strict --metadata --restructuredtext + python -m build --config-setting=--quiet + twine check dist/* check-manifest {toxinidir} [testenv:doc] @@ -69,3 +69,12 @@ commands = rst2html.py --strict README.rst /tmp/django_coverage_plugin_README.html + +[gh-actions] +python = + 2.7: py27 + 3.6: py36 + 3.7: py37 + 3.8: py38 + 3.9: py39 + 3.10: py310