mirror of
https://github.com/django/django.git
synced 2024-12-22 09:05:43 +00:00
Fixed #35229 -- Made URL custom error handler check run once.
This commit is contained in:
parent
5e80390add
commit
28a3fbe004
@ -1,6 +1,8 @@
|
||||
import inspect
|
||||
from collections import Counter
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ViewDoesNotExist
|
||||
|
||||
from . import Error, Tags, Warning, register
|
||||
|
||||
@ -115,3 +117,43 @@ def E006(name):
|
||||
"The {} setting must end with a slash.".format(name),
|
||||
id="urls.E006",
|
||||
)
|
||||
|
||||
|
||||
@register(Tags.urls)
|
||||
def check_custom_error_handlers(app_configs, **kwargs):
|
||||
if not getattr(settings, "ROOT_URLCONF", None):
|
||||
return []
|
||||
|
||||
from django.urls import get_resolver
|
||||
|
||||
resolver = get_resolver()
|
||||
|
||||
errors = []
|
||||
# All handlers take (request, exception) arguments except handler500
|
||||
# which takes (request).
|
||||
for status_code, num_parameters in [(400, 2), (403, 2), (404, 2), (500, 1)]:
|
||||
try:
|
||||
handler = resolver.resolve_error_handler(status_code)
|
||||
except (ImportError, ViewDoesNotExist) as e:
|
||||
path = getattr(resolver.urlconf_module, "handler%s" % status_code)
|
||||
msg = (
|
||||
"The custom handler{status_code} view '{path}' could not be "
|
||||
"imported."
|
||||
).format(status_code=status_code, path=path)
|
||||
errors.append(Error(msg, hint=str(e), id="urls.E008"))
|
||||
continue
|
||||
signature = inspect.signature(handler)
|
||||
args = [None] * num_parameters
|
||||
try:
|
||||
signature.bind(*args)
|
||||
except TypeError:
|
||||
msg = (
|
||||
"The custom handler{status_code} view '{path}' does not "
|
||||
"take the correct number of arguments ({args})."
|
||||
).format(
|
||||
status_code=status_code,
|
||||
path=handler.__module__ + "." + handler.__qualname__,
|
||||
args="request, exception" if num_parameters == 2 else "request",
|
||||
)
|
||||
errors.append(Error(msg, id="urls.E007"))
|
||||
return errors
|
||||
|
@ -19,7 +19,7 @@ from asgiref.local import Local
|
||||
from django.conf import settings
|
||||
from django.core.checks import Error, Warning
|
||||
from django.core.checks.urls import check_resolver
|
||||
from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.utils.datastructures import MultiValueDict
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.http import RFC3986_SUBDELIMS, escape_leading_slashes
|
||||
@ -518,40 +518,8 @@ class URLResolver:
|
||||
messages = []
|
||||
for pattern in self.url_patterns:
|
||||
messages.extend(check_resolver(pattern))
|
||||
messages.extend(self._check_custom_error_handlers())
|
||||
return messages or self.pattern.check()
|
||||
|
||||
def _check_custom_error_handlers(self):
|
||||
messages = []
|
||||
# All handlers take (request, exception) arguments except handler500
|
||||
# which takes (request).
|
||||
for status_code, num_parameters in [(400, 2), (403, 2), (404, 2), (500, 1)]:
|
||||
try:
|
||||
handler = self.resolve_error_handler(status_code)
|
||||
except (ImportError, ViewDoesNotExist) as e:
|
||||
path = getattr(self.urlconf_module, "handler%s" % status_code)
|
||||
msg = (
|
||||
"The custom handler{status_code} view '{path}' could not be "
|
||||
"imported."
|
||||
).format(status_code=status_code, path=path)
|
||||
messages.append(Error(msg, hint=str(e), id="urls.E008"))
|
||||
continue
|
||||
signature = inspect.signature(handler)
|
||||
args = [None] * num_parameters
|
||||
try:
|
||||
signature.bind(*args)
|
||||
except TypeError:
|
||||
msg = (
|
||||
"The custom handler{status_code} view '{path}' does not "
|
||||
"take the correct number of arguments ({args})."
|
||||
).format(
|
||||
status_code=status_code,
|
||||
path=handler.__module__ + "." + handler.__qualname__,
|
||||
args="request, exception" if num_parameters == 2 else "request",
|
||||
)
|
||||
messages.append(Error(msg, id="urls.E007"))
|
||||
return messages
|
||||
|
||||
def _populate(self):
|
||||
# Short-circuit if called recursively in this thread to prevent
|
||||
# infinite recursion. Concurrent threads may call this at the same
|
||||
|
@ -2,6 +2,7 @@ from django.conf import settings
|
||||
from django.core.checks.messages import Error, Warning
|
||||
from django.core.checks.urls import (
|
||||
E006,
|
||||
check_custom_error_handlers,
|
||||
check_url_config,
|
||||
check_url_namespaces_unique,
|
||||
check_url_settings,
|
||||
@ -243,7 +244,7 @@ class CheckCustomErrorHandlersTests(SimpleTestCase):
|
||||
ROOT_URLCONF="check_framework.urls.bad_function_based_error_handlers",
|
||||
)
|
||||
def test_bad_function_based_handlers(self):
|
||||
result = check_url_config(None)
|
||||
result = check_custom_error_handlers(None)
|
||||
self.assertEqual(len(result), 4)
|
||||
for code, num_params, error in zip([400, 403, 404, 500], [2, 2, 2, 1], result):
|
||||
with self.subTest("handler{}".format(code)):
|
||||
@ -264,7 +265,7 @@ class CheckCustomErrorHandlersTests(SimpleTestCase):
|
||||
ROOT_URLCONF="check_framework.urls.bad_class_based_error_handlers",
|
||||
)
|
||||
def test_bad_class_based_handlers(self):
|
||||
result = check_url_config(None)
|
||||
result = check_custom_error_handlers(None)
|
||||
self.assertEqual(len(result), 4)
|
||||
for code, num_params, error in zip([400, 403, 404, 500], [2, 2, 2, 1], result):
|
||||
with self.subTest("handler%s" % code):
|
||||
@ -287,7 +288,7 @@ class CheckCustomErrorHandlersTests(SimpleTestCase):
|
||||
ROOT_URLCONF="check_framework.urls.bad_error_handlers_invalid_path"
|
||||
)
|
||||
def test_bad_handlers_invalid_path(self):
|
||||
result = check_url_config(None)
|
||||
result = check_custom_error_handlers(None)
|
||||
paths = [
|
||||
"django.views.bad_handler",
|
||||
"django.invalid_module.bad_handler",
|
||||
@ -318,14 +319,14 @@ class CheckCustomErrorHandlersTests(SimpleTestCase):
|
||||
ROOT_URLCONF="check_framework.urls.good_function_based_error_handlers",
|
||||
)
|
||||
def test_good_function_based_handlers(self):
|
||||
result = check_url_config(None)
|
||||
result = check_custom_error_handlers(None)
|
||||
self.assertEqual(result, [])
|
||||
|
||||
@override_settings(
|
||||
ROOT_URLCONF="check_framework.urls.good_class_based_error_handlers",
|
||||
)
|
||||
def test_good_class_based_handlers(self):
|
||||
result = check_url_config(None)
|
||||
result = check_custom_error_handlers(None)
|
||||
self.assertEqual(result, [])
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user