[2.2.x] Fixed #30318 -- Added check for importability of arguments of custom error handler views.

Thanks to Jon on Stack Overflow for reporting the issue.

Backport of a5accc0368 from master
This commit is contained in:
Alasdair Nicol 2019-04-04 00:17:25 +01:00 committed by Mariusz Felisiak
parent f24cf51661
commit 3c3df7db8e
5 changed files with 44 additions and 2 deletions

View File

@ -15,7 +15,7 @@ from urllib.parse import quote
from django.conf import settings from django.conf import settings
from django.core.checks import Error, Warning from django.core.checks import Error, Warning
from django.core.checks.urls import check_resolver from django.core.checks.urls import check_resolver
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
from django.utils.datastructures import MultiValueDict from django.utils.datastructures import MultiValueDict
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.http import RFC3986_SUBDELIMS, escape_leading_slashes from django.utils.http import RFC3986_SUBDELIMS, escape_leading_slashes
@ -405,7 +405,15 @@ class URLResolver:
# All handlers take (request, exception) arguments except handler500 # All handlers take (request, exception) arguments except handler500
# which takes (request). # which takes (request).
for status_code, num_parameters in [(400, 2), (403, 2), (404, 2), (500, 1)]: for status_code, num_parameters in [(400, 2), (403, 2), (404, 2), (500, 1)]:
handler, param_dict = self.resolve_error_handler(status_code) try:
handler, param_dict = 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) signature = inspect.signature(handler)
args = [None] * num_parameters args = [None] * num_parameters
try: try:

View File

@ -464,6 +464,8 @@ The following checks are performed on your URL configuration:
end with a slash. end with a slash.
* **urls.E007**: The custom ``handlerXXX`` view ``'path.to.view'`` does not * **urls.E007**: The custom ``handlerXXX`` view ``'path.to.view'`` does not
take the correct number of arguments (…). take the correct number of arguments (…).
* **urls.E008**: The custom ``handlerXXX`` view ``'path.to.view'`` could not be
imported.
``contrib`` app checks ``contrib`` app checks
====================== ======================

View File

@ -46,3 +46,6 @@ Bugfixes
* Fixed a regression in Django 2.2 where * Fixed a regression in Django 2.2 where
:class:`~django.contrib.postgres.search.SearchVector` generates SQL that is :class:`~django.contrib.postgres.search.SearchVector` generates SQL that is
not indexable (:ticket:`30385`). not indexable (:ticket:`30385`).
* Fixed a regression in Django 2.2 that caused an exception to be raised when
a custom error handler could not be imported (:ticket:`30318`).

View File

@ -181,6 +181,29 @@ class CheckCustomErrorHandlersTests(SimpleTestCase):
id='urls.E007', id='urls.E007',
)) ))
@override_settings(ROOT_URLCONF='check_framework.urls.bad_error_handlers_invalid_path')
def test_bad_handlers_invalid_path(self):
result = check_url_config(None)
paths = [
'django.views.bad_handler',
'django.invalid_module.bad_handler',
'invalid_module.bad_handler',
'django',
]
hints = [
"Could not import '{}'. View does not exist in module django.views.",
"Could not import '{}'. Parent module django.invalid_module does not exist.",
"No module named 'invalid_module'",
"Could not import '{}'. The path must be fully qualified.",
]
for code, path, hint, error in zip([400, 403, 404, 500], paths, hints, result):
with self.subTest('handler{}'.format(code)):
self.assertEqual(error, Error(
"The custom handler{} view '{}' could not be imported.".format(code, path),
hint=hint.format(path),
id='urls.E008',
))
@override_settings(ROOT_URLCONF='check_framework.urls.good_error_handlers') @override_settings(ROOT_URLCONF='check_framework.urls.good_error_handlers')
def test_good_handlers(self): def test_good_handlers(self):
result = check_url_config(None) result = check_url_config(None)

View File

@ -0,0 +1,6 @@
urlpatterns = []
handler400 = 'django.views.bad_handler'
handler403 = 'django.invalid_module.bad_handler'
handler404 = 'invalid_module.bad_handler'
handler500 = 'django'