瀏覽代碼

Fixed #32987 -- Added system check for template tag modules with the same name.

Co-authored-by: Daniel Fairhead <daniel@dev.ngo>
Shreya Bamne 3 年之前
父節點
當前提交
004b4620f6

+ 2 - 0
AUTHORS

@@ -223,6 +223,7 @@ answer newbie questions, and generally made Django that much better:
     Daniel Alves Barbosa de Oliveira Vaz <danielvaz@gmail.com>
     Daniel Duan <DaNmarner@gmail.com>
     Daniele Procida <daniele@vurt.org>
+    Daniel Fairhead <danthedeckie@gmail.com>
     Daniel Greenfeld
     dAniel hAhler
     Daniel Jilg <daniel@breakthesystem.org>
@@ -860,6 +861,7 @@ answer newbie questions, and generally made Django that much better:
     Shai Berger <shai@platonix.com>
     Shannon -jj Behrens <https://www.jjinux.com/>
     Shawn Milochik <shawn@milochik.com>
+    Shreya Bamne <shreya.bamne@gmail.com>
     Silvan Spross <silvan.spross@gmail.com>
     Simeon Visser <http://simeonvisser.com>
     Simon Blanchard

+ 32 - 0
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

+ 2 - 0
docs/ref/checks.txt

@@ -541,6 +541,8 @@ configured:
 * **templates.E002**: ``string_if_invalid`` in :setting:`TEMPLATES`
   :setting:`OPTIONS <TEMPLATES-OPTIONS>` must be a string but got: ``{value}``
   (``{type}``).
+* **templates.E003**:``<name>`` is used for multiple template tag modules:
+  ``<module list>``.
 
 Translation
 -----------

+ 0 - 0
tests/check_framework/template_test_apps/__init__.py


+ 0 - 0
tests/check_framework/template_test_apps/different_tags_app/__init__.py


+ 5 - 0
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'

+ 0 - 0
tests/check_framework/template_test_apps/different_tags_app/templatetags/__init__.py


+ 3 - 0
tests/check_framework/template_test_apps/different_tags_app/templatetags/different_tags.py

@@ -0,0 +1,3 @@
+from django.template import Library
+
+register = Library()

+ 0 - 0
tests/check_framework/template_test_apps/same_tags_app_1/__init__.py


+ 5 - 0
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'

+ 0 - 0
tests/check_framework/template_test_apps/same_tags_app_1/templatetags/__init__.py


+ 3 - 0
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()

+ 0 - 0
tests/check_framework/template_test_apps/same_tags_app_2/__init__.py


+ 5 - 0
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'

+ 0 - 0
tests/check_framework/template_test_apps/same_tags_app_2/templatetags/__init__.py


+ 3 - 0
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()

+ 85 - 2
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), [])