From 004b4620f6f4ad87261e149898940f2dcd5757ef Mon Sep 17 00:00:00 2001 From: Shreya Bamne Date: Tue, 3 Aug 2021 15:20:49 +0100 Subject: [PATCH] Fixed #32987 -- Added system check for template tag modules with the same name. Co-authored-by: Daniel Fairhead --- AUTHORS | 2 + django/core/checks/templates.py | 32 +++++++ docs/ref/checks.txt | 2 + .../template_test_apps/__init__.py | 0 .../different_tags_app/__init__.py | 0 .../different_tags_app/apps.py | 5 ++ .../templatetags/__init__.py | 0 .../templatetags/different_tags.py | 3 + .../same_tags_app_1/__init__.py | 0 .../same_tags_app_1/apps.py | 5 ++ .../same_tags_app_1/templatetags/__init__.py | 0 .../same_tags_app_1/templatetags/same_tags.py | 3 + .../same_tags_app_2/__init__.py | 0 .../same_tags_app_2/apps.py | 5 ++ .../same_tags_app_2/templatetags/__init__.py | 0 .../same_tags_app_2/templatetags/same_tags.py | 3 + tests/check_framework/test_templates.py | 87 ++++++++++++++++++- 17 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 tests/check_framework/template_test_apps/__init__.py create mode 100644 tests/check_framework/template_test_apps/different_tags_app/__init__.py create mode 100644 tests/check_framework/template_test_apps/different_tags_app/apps.py create mode 100644 tests/check_framework/template_test_apps/different_tags_app/templatetags/__init__.py create mode 100644 tests/check_framework/template_test_apps/different_tags_app/templatetags/different_tags.py create mode 100644 tests/check_framework/template_test_apps/same_tags_app_1/__init__.py create mode 100644 tests/check_framework/template_test_apps/same_tags_app_1/apps.py create mode 100644 tests/check_framework/template_test_apps/same_tags_app_1/templatetags/__init__.py create mode 100644 tests/check_framework/template_test_apps/same_tags_app_1/templatetags/same_tags.py create mode 100644 tests/check_framework/template_test_apps/same_tags_app_2/__init__.py create mode 100644 tests/check_framework/template_test_apps/same_tags_app_2/apps.py create mode 100644 tests/check_framework/template_test_apps/same_tags_app_2/templatetags/__init__.py create mode 100644 tests/check_framework/template_test_apps/same_tags_app_2/templatetags/same_tags.py diff --git a/AUTHORS b/AUTHORS index 55e6579840..01adc8575a 100644 --- a/AUTHORS +++ b/AUTHORS @@ -223,6 +223,7 @@ answer newbie questions, and generally made Django that much better: Daniel Alves Barbosa de Oliveira Vaz Daniel Duan Daniele Procida + Daniel Fairhead Daniel Greenfeld dAniel hAhler Daniel Jilg @@ -860,6 +861,7 @@ answer newbie questions, and generally made Django that much better: Shai Berger Shannon -jj Behrens Shawn Milochik + Shreya Bamne Silvan Spross Simeon Visser Simon Blanchard diff --git a/django/core/checks/templates.py b/django/core/checks/templates.py index 8c4b7c172b..14325bd3e0 100644 --- a/django/core/checks/templates.py +++ b/django/core/checks/templates.py @@ -1,6 +1,8 @@ import copy +from collections import defaultdict from django.conf import settings +from django.template.backends.django import get_template_tag_modules from . import Error, Tags, register @@ -13,6 +15,10 @@ E002 = Error( "'string_if_invalid' in TEMPLATES OPTIONS must be a string but got: {} ({}).", id="templates.E002", ) +E003 = Error( + '{} is used for multiple template tag modules: {}', + id='templates.E003', +) @register(Tags.templates) @@ -33,3 +39,29 @@ def check_string_if_invalid_is_string(app_configs, **kwargs): error.msg = error.msg.format(string_if_invalid, type(string_if_invalid).__name__) errors.append(error) return errors + + +@register(Tags.templates) +def check_for_template_tags_with_the_same_name(app_configs, **kwargs): + errors = [] + libraries = defaultdict(list) + + for conf in settings.TEMPLATES: + custom_libraries = conf.get('OPTIONS', {}).get('libraries', {}) + for module_name, module_path in custom_libraries.items(): + libraries[module_name].append(module_path) + + for module_name, module_path in get_template_tag_modules(): + libraries[module_name].append(module_path) + + for library_name, items in libraries.items(): + if len(items) > 1: + errors.append(Error( + E003.msg.format( + repr(library_name), + ', '.join(repr(item) for item in items), + ), + id=E003.id, + )) + + return errors diff --git a/docs/ref/checks.txt b/docs/ref/checks.txt index 727d16b772..6c95b9376d 100644 --- a/docs/ref/checks.txt +++ b/docs/ref/checks.txt @@ -541,6 +541,8 @@ configured: * **templates.E002**: ``string_if_invalid`` in :setting:`TEMPLATES` :setting:`OPTIONS ` must be a string but got: ``{value}`` (``{type}``). +* **templates.E003**:```` is used for multiple template tag modules: + ````. Translation ----------- diff --git a/tests/check_framework/template_test_apps/__init__.py b/tests/check_framework/template_test_apps/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/check_framework/template_test_apps/different_tags_app/__init__.py b/tests/check_framework/template_test_apps/different_tags_app/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/check_framework/template_test_apps/different_tags_app/apps.py b/tests/check_framework/template_test_apps/different_tags_app/apps.py new file mode 100644 index 0000000000..90d54b3d50 --- /dev/null +++ b/tests/check_framework/template_test_apps/different_tags_app/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class DifferentTagsAppAppConfig(AppConfig): + name = 'check_framework.template_test_apps.different_tags_app' diff --git a/tests/check_framework/template_test_apps/different_tags_app/templatetags/__init__.py b/tests/check_framework/template_test_apps/different_tags_app/templatetags/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/check_framework/template_test_apps/different_tags_app/templatetags/different_tags.py b/tests/check_framework/template_test_apps/different_tags_app/templatetags/different_tags.py new file mode 100644 index 0000000000..9bec93d8e5 --- /dev/null +++ b/tests/check_framework/template_test_apps/different_tags_app/templatetags/different_tags.py @@ -0,0 +1,3 @@ +from django.template import Library + +register = Library() diff --git a/tests/check_framework/template_test_apps/same_tags_app_1/__init__.py b/tests/check_framework/template_test_apps/same_tags_app_1/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/check_framework/template_test_apps/same_tags_app_1/apps.py b/tests/check_framework/template_test_apps/same_tags_app_1/apps.py new file mode 100644 index 0000000000..44149177a0 --- /dev/null +++ b/tests/check_framework/template_test_apps/same_tags_app_1/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class SameTagsApp1AppConfig(AppConfig): + name = 'check_framework.template_test_apps.same_tags_app_1' diff --git a/tests/check_framework/template_test_apps/same_tags_app_1/templatetags/__init__.py b/tests/check_framework/template_test_apps/same_tags_app_1/templatetags/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/check_framework/template_test_apps/same_tags_app_1/templatetags/same_tags.py b/tests/check_framework/template_test_apps/same_tags_app_1/templatetags/same_tags.py new file mode 100644 index 0000000000..9bec93d8e5 --- /dev/null +++ b/tests/check_framework/template_test_apps/same_tags_app_1/templatetags/same_tags.py @@ -0,0 +1,3 @@ +from django.template import Library + +register = Library() diff --git a/tests/check_framework/template_test_apps/same_tags_app_2/__init__.py b/tests/check_framework/template_test_apps/same_tags_app_2/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/check_framework/template_test_apps/same_tags_app_2/apps.py b/tests/check_framework/template_test_apps/same_tags_app_2/apps.py new file mode 100644 index 0000000000..d90c800d1f --- /dev/null +++ b/tests/check_framework/template_test_apps/same_tags_app_2/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class SameTagsApp2AppConfig(AppConfig): + name = 'check_framework.template_test_apps.same_tags_app_2' diff --git a/tests/check_framework/template_test_apps/same_tags_app_2/templatetags/__init__.py b/tests/check_framework/template_test_apps/same_tags_app_2/templatetags/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/check_framework/template_test_apps/same_tags_app_2/templatetags/same_tags.py b/tests/check_framework/template_test_apps/same_tags_app_2/templatetags/same_tags.py new file mode 100644 index 0000000000..9bec93d8e5 --- /dev/null +++ b/tests/check_framework/template_test_apps/same_tags_app_2/templatetags/same_tags.py @@ -0,0 +1,3 @@ +from django.template import Library + +register = Library() diff --git a/tests/check_framework/test_templates.py b/tests/check_framework/test_templates.py index 955c863822..88c0479436 100644 --- a/tests/check_framework/test_templates.py +++ b/tests/check_framework/test_templates.py @@ -1,8 +1,9 @@ from copy import copy, deepcopy +from django.core.checks import Error from django.core.checks.templates import ( - E001, E002, check_setting_app_dirs_loaders, - check_string_if_invalid_is_string, + E001, E002, E003, check_for_template_tags_with_the_same_name, + check_setting_app_dirs_loaders, check_string_if_invalid_is_string, ) from django.test import SimpleTestCase from django.test.utils import override_settings @@ -87,3 +88,85 @@ class CheckTemplateStringIfInvalidTest(SimpleTestCase): del TEMPLATES[1]['OPTIONS']['string_if_invalid'] with self.settings(TEMPLATES=TEMPLATES): self.assertEqual(check_string_if_invalid_is_string(None), [self.error1]) + + +class CheckTemplateTagLibrariesWithSameName(SimpleTestCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.error_same_tags = Error( + E003.msg.format( + "'same_tags'", + "'check_framework.template_test_apps.same_tags_app_1." + "templatetags.same_tags', " + "'check_framework.template_test_apps.same_tags_app_2." + "templatetags.same_tags'", + ), + id=E003.id, + ) + + @staticmethod + def get_settings(module_name, module_path): + return { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'OPTIONS': { + 'libraries': { + module_name: f'check_framework.template_test_apps.{module_path}', + }, + }, + } + + @override_settings(INSTALLED_APPS=[ + 'check_framework.template_test_apps.same_tags_app_1', + 'check_framework.template_test_apps.same_tags_app_2', + ]) + def test_template_tags_with_same_name(self): + self.assertEqual( + check_for_template_tags_with_the_same_name(None), + [self.error_same_tags], + ) + + def test_template_tags_with_same_library_name(self): + with self.settings(TEMPLATES=[ + self.get_settings('same_tags', 'same_tags_app_1.templatetags.same_tags'), + self.get_settings('same_tags', 'same_tags_app_2.templatetags.same_tags'), + ]): + self.assertEqual( + check_for_template_tags_with_the_same_name(None), + [self.error_same_tags], + ) + + @override_settings(INSTALLED_APPS=[ + 'check_framework.template_test_apps.same_tags_app_1' + ]) + def test_template_tags_with_same_library_name_and_module_name(self): + with self.settings(TEMPLATES=[ + self.get_settings( + 'same_tags', + 'different_tags_app.templatetags.different_tags', + ), + ]): + self.assertEqual(check_for_template_tags_with_the_same_name(None), [Error( + E003.msg.format( + "'same_tags'", + "'check_framework.template_test_apps.different_tags_app." + "templatetags.different_tags', " + "'check_framework.template_test_apps.same_tags_app_1." + "templatetags.same_tags'", + ), + id=E003.id, + )]) + + def test_template_tags_with_different_library_name(self): + with self.settings(TEMPLATES=[ + self.get_settings('same_tags', 'same_tags_app_1.templatetags.same_tags'), + self.get_settings('not_same_tags', 'same_tags_app_2.templatetags.same_tags'), + ]): + self.assertEqual(check_for_template_tags_with_the_same_name(None), []) + + @override_settings(INSTALLED_APPS=[ + 'check_framework.template_test_apps.same_tags_app_1', + 'check_framework.template_test_apps.different_tags_app', + ]) + def test_template_tags_with_different_name(self): + self.assertEqual(check_for_template_tags_with_the_same_name(None), [])