summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlasdair Nicol <alasdair@thenicols.net>2019-04-04 00:17:25 +0100
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2019-04-25 11:38:35 +0200
commit3c3df7db8e5ce7882d6a8379fc2d0f82330114f1 (patch)
treefa3a3533bd412af7980ee2dc3586ba8fc1914def
parentf24cf51661af21cfe2d90d7cba6557c56778ef20 (diff)
[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 a5accc0368c6575b55976c06af36ed399c85c781 from master
-rw-r--r--django/urls/resolvers.py12
-rw-r--r--docs/ref/checks.txt2
-rw-r--r--docs/releases/2.2.1.txt3
-rw-r--r--tests/check_framework/test_urls.py23
-rw-r--r--tests/check_framework/urls/bad_error_handlers_invalid_path.py6
5 files changed, 44 insertions, 2 deletions
diff --git a/django/urls/resolvers.py b/django/urls/resolvers.py
index 8f59313c93..9d3379a821 100644
--- a/django/urls/resolvers.py
+++ b/django/urls/resolvers.py
@@ -15,7 +15,7 @@ from urllib.parse import quote
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
+from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
from django.utils.datastructures import MultiValueDict
from django.utils.functional import cached_property
from django.utils.http import RFC3986_SUBDELIMS, escape_leading_slashes
@@ -405,7 +405,15 @@ class URLResolver:
# 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)]:
- 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)
args = [None] * num_parameters
try:
diff --git a/docs/ref/checks.txt b/docs/ref/checks.txt
index 6ec3028c35..9d48138076 100644
--- a/docs/ref/checks.txt
+++ b/docs/ref/checks.txt
@@ -464,6 +464,8 @@ The following checks are performed on your URL configuration:
end with a slash.
* **urls.E007**: The custom ``handlerXXX`` view ``'path.to.view'`` does not
take the correct number of arguments (…).
+* **urls.E008**: The custom ``handlerXXX`` view ``'path.to.view'`` could not be
+ imported.
``contrib`` app checks
======================
diff --git a/docs/releases/2.2.1.txt b/docs/releases/2.2.1.txt
index 48cbfb3a8f..0ca76bcbf8 100644
--- a/docs/releases/2.2.1.txt
+++ b/docs/releases/2.2.1.txt
@@ -46,3 +46,6 @@ Bugfixes
* Fixed a regression in Django 2.2 where
:class:`~django.contrib.postgres.search.SearchVector` generates SQL that is
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`).
diff --git a/tests/check_framework/test_urls.py b/tests/check_framework/test_urls.py
index 67de26c690..217b5e7bad 100644
--- a/tests/check_framework/test_urls.py
+++ b/tests/check_framework/test_urls.py
@@ -181,6 +181,29 @@ class CheckCustomErrorHandlersTests(SimpleTestCase):
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')
def test_good_handlers(self):
result = check_url_config(None)
diff --git a/tests/check_framework/urls/bad_error_handlers_invalid_path.py b/tests/check_framework/urls/bad_error_handlers_invalid_path.py
new file mode 100644
index 0000000000..77e0c639e0
--- /dev/null
+++ b/tests/check_framework/urls/bad_error_handlers_invalid_path.py
@@ -0,0 +1,6 @@
+urlpatterns = []
+
+handler400 = 'django.views.bad_handler'
+handler403 = 'django.invalid_module.bad_handler'
+handler404 = 'invalid_module.bad_handler'
+handler500 = 'django'