diff options
author | django-bot <ops@djangoproject.com> | 2022-02-03 20:24:19 +0100 |
---|---|---|
committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2022-02-07 20:37:05 +0100 |
commit | 9c19aff7c7561e3a82978a272ecdaad40dda5c00 (patch) | |
tree | f0506b668a013d0063e5fba3dbf4863b466713ba /tests/view_tests | |
parent | f68fa8b45dfac545cfc4111d4e52804c86db68d3 (diff) | |
download | django-9c19aff7c7561e3a82978a272ecdaad40dda5c00.tar.gz |
Refs #33476 -- Reformatted code with Black.
Diffstat (limited to 'tests/view_tests')
-rw-r--r-- | tests/view_tests/default_urls.py | 2 | ||||
-rw-r--r-- | tests/view_tests/generic_urls.py | 36 | ||||
-rw-r--r-- | tests/view_tests/models.py | 8 | ||||
-rw-r--r-- | tests/view_tests/regression_21530_urls.py | 2 | ||||
-rw-r--r-- | tests/view_tests/tests/test_csrf.py | 106 | ||||
-rw-r--r-- | tests/view_tests/tests/test_debug.py | 1122 | ||||
-rw-r--r-- | tests/view_tests/tests/test_defaults.py | 170 | ||||
-rw-r--r-- | tests/view_tests/tests/test_i18n.py | 438 | ||||
-rw-r--r-- | tests/view_tests/tests/test_json.py | 21 | ||||
-rw-r--r-- | tests/view_tests/tests/test_specials.py | 7 | ||||
-rw-r--r-- | tests/view_tests/tests/test_static.py | 145 | ||||
-rw-r--r-- | tests/view_tests/urls.py | 105 | ||||
-rw-r--r-- | tests/view_tests/views.py | 132 |
13 files changed, 1292 insertions, 1002 deletions
diff --git a/tests/view_tests/default_urls.py b/tests/view_tests/default_urls.py index beb2bdc1d4..983d0c0db7 100644 --- a/tests/view_tests/default_urls.py +++ b/tests/view_tests/default_urls.py @@ -3,5 +3,5 @@ from django.urls import path urlpatterns = [ # This is the same as in the default project template - path('admin/', admin.site.urls), + path("admin/", admin.site.urls), ] diff --git a/tests/view_tests/generic_urls.py b/tests/view_tests/generic_urls.py index 8befa86ff5..247e8ba740 100644 --- a/tests/view_tests/generic_urls.py +++ b/tests/view_tests/generic_urls.py @@ -6,39 +6,45 @@ from . import views from .models import Article, DateArticle date_based_info_dict = { - 'queryset': Article.objects.all(), - 'date_field': 'date_created', - 'month_format': '%m', + "queryset": Article.objects.all(), + "date_field": "date_created", + "month_format": "%m", } object_list_dict = { - 'queryset': Article.objects.all(), - 'paginate_by': 2, + "queryset": Article.objects.all(), + "paginate_by": 2, } object_list_no_paginate_by = { - 'queryset': Article.objects.all(), + "queryset": Article.objects.all(), } -numeric_days_info_dict = dict(date_based_info_dict, day_format='%d') +numeric_days_info_dict = dict(date_based_info_dict, day_format="%d") -date_based_datefield_info_dict = dict(date_based_info_dict, queryset=DateArticle.objects.all()) +date_based_datefield_info_dict = dict( + date_based_info_dict, queryset=DateArticle.objects.all() +) urlpatterns = [ - path('accounts/login/', auth_views.LoginView.as_view(template_name='login.html')), - path('accounts/logout/', auth_views.LogoutView.as_view()), - + path("accounts/login/", auth_views.LoginView.as_view(template_name="login.html")), + path("accounts/logout/", auth_views.LogoutView.as_view()), # Special URLs for particular regression cases. - path('中文/target/', views.index_page), + path("中文/target/", views.index_page), ] # redirects, both temporary and permanent, with non-ASCII targets urlpatterns += [ - path('nonascii_redirect/', RedirectView.as_view(url='/中文/target/', permanent=False)), - path('permanent_nonascii_redirect/', RedirectView.as_view(url='/中文/target/', permanent=True)), + path( + "nonascii_redirect/", RedirectView.as_view(url="/中文/target/", permanent=False) + ), + path( + "permanent_nonascii_redirect/", + RedirectView.as_view(url="/中文/target/", permanent=True), + ), ] # json response urlpatterns += [ - path('json/response/', views.json_response_view), + path("json/response/", views.json_response_view), ] diff --git a/tests/view_tests/models.py b/tests/view_tests/models.py index a9c0b358b4..17d7dad215 100644 --- a/tests/view_tests/models.py +++ b/tests/view_tests/models.py @@ -9,7 +9,7 @@ class Author(models.Model): name = models.CharField(max_length=100) def get_absolute_url(self): - return '/authors/%s/' % self.id + return "/authors/%s/" % self.id class BaseArticle(models.Model): @@ -17,6 +17,7 @@ class BaseArticle(models.Model): An abstract article Model so that we can create article models with and without a get_absolute_url method (for create_update generic views tests). """ + title = models.CharField(max_length=100) slug = models.SlugField() author = models.ForeignKey(Author, models.CASCADE) @@ -33,10 +34,12 @@ class UrlArticle(BaseArticle): """ An Article class with a get_absolute_url defined. """ + date_created = models.DateTimeField() def get_absolute_url(self): - return '/urlarticles/%s/' % self.slug + return "/urlarticles/%s/" % self.slug + get_absolute_url.purge = True @@ -45,4 +48,5 @@ class DateArticle(BaseArticle): An article Model with a DateField instead of DateTimeField, for testing #7602 """ + date_created = models.DateField() diff --git a/tests/view_tests/regression_21530_urls.py b/tests/view_tests/regression_21530_urls.py index c30cd1ed37..7179f2d71f 100644 --- a/tests/view_tests/regression_21530_urls.py +++ b/tests/view_tests/regression_21530_urls.py @@ -3,5 +3,5 @@ from django.urls import path from . import views urlpatterns = [ - path('index/', views.index_page, name='index'), + path("index/", views.index_page, name="index"), ] diff --git a/tests/view_tests/tests/test_csrf.py b/tests/view_tests/tests/test_csrf.py index 7afed336ea..c0f812431d 100644 --- a/tests/view_tests/tests/test_csrf.py +++ b/tests/view_tests/tests/test_csrf.py @@ -1,14 +1,11 @@ from django.template import TemplateDoesNotExist -from django.test import ( - Client, RequestFactory, SimpleTestCase, override_settings, -) +from django.test import Client, RequestFactory, SimpleTestCase, override_settings from django.utils.translation import override from django.views.csrf import CSRF_FAILURE_TEMPLATE_NAME, csrf_failure -@override_settings(ROOT_URLCONF='view_tests.urls') +@override_settings(ROOT_URLCONF="view_tests.urls") class CsrfViewTests(SimpleTestCase): - def setUp(self): super().setUp() self.client = Client(enforce_csrf_checks=True) @@ -16,50 +13,54 @@ class CsrfViewTests(SimpleTestCase): @override_settings( USE_I18N=True, MIDDLEWARE=[ - 'django.middleware.locale.LocaleMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', + "django.middleware.locale.LocaleMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", ], ) def test_translation(self): """An invalid request is rejected with a localized error message.""" - response = self.client.post('/') - self.assertContains(response, 'Forbidden', status_code=403) - self.assertContains(response, 'CSRF verification failed. Request aborted.', status_code=403) + response = self.client.post("/") + self.assertContains(response, "Forbidden", status_code=403) + self.assertContains( + response, "CSRF verification failed. Request aborted.", status_code=403 + ) - with self.settings(LANGUAGE_CODE='nl'), override('en-us'): - response = self.client.post('/') - self.assertContains(response, 'Verboden', status_code=403) - self.assertContains(response, 'CSRF-verificatie mislukt. Verzoek afgebroken.', status_code=403) + with self.settings(LANGUAGE_CODE="nl"), override("en-us"): + response = self.client.post("/") + self.assertContains(response, "Verboden", status_code=403) + self.assertContains( + response, + "CSRF-verificatie mislukt. Verzoek afgebroken.", + status_code=403, + ) - @override_settings( - SECURE_PROXY_SSL_HEADER=('HTTP_X_FORWARDED_PROTO', 'https') - ) + @override_settings(SECURE_PROXY_SSL_HEADER=("HTTP_X_FORWARDED_PROTO", "https")) def test_no_referer(self): """ Referer header is strictly checked for POST over HTTPS. Trigger the exception by sending an incorrect referer. """ - response = self.client.post('/', HTTP_X_FORWARDED_PROTO='https') + response = self.client.post("/", HTTP_X_FORWARDED_PROTO="https") self.assertContains( response, - 'You are seeing this message because this HTTPS site requires a ' - '“Referer header” to be sent by your web browser, but ' - 'none was sent.', + "You are seeing this message because this HTTPS site requires a " + "“Referer header” to be sent by your web browser, but " + "none was sent.", status_code=403, ) self.assertContains( response, - 'If you have configured your browser to disable “Referer” ' - 'headers, please re-enable them, at least for this site, or for ' - 'HTTPS connections, or for “same-origin” requests.', + "If you have configured your browser to disable “Referer” " + "headers, please re-enable them, at least for this site, or for " + "HTTPS connections, or for “same-origin” requests.", status_code=403, ) self.assertContains( response, - 'If you are using the <meta name="referrer" ' - 'content="no-referrer"> tag or including the ' - '“Referrer-Policy: no-referrer” header, please remove them.', + "If you are using the <meta name="referrer" " + "content="no-referrer"> tag or including the " + "“Referrer-Policy: no-referrer” header, please remove them.", status_code=403, ) @@ -68,13 +69,13 @@ class CsrfViewTests(SimpleTestCase): The CSRF cookie is checked for POST. Failure to send this cookie should provide a nice error message. """ - response = self.client.post('/') + response = self.client.post("/") self.assertContains( response, - 'You are seeing this message because this site requires a CSRF ' - 'cookie when submitting forms. This cookie is required for ' - 'security reasons, to ensure that your browser is not being ' - 'hijacked by third parties.', + "You are seeing this message because this site requires a CSRF " + "cookie when submitting forms. This cookie is required for " + "security reasons, to ensure that your browser is not being " + "hijacked by third parties.", status_code=403, ) @@ -83,27 +84,34 @@ class CsrfViewTests(SimpleTestCase): """ The CSRF view doesn't depend on the TEMPLATES configuration (#24388). """ - response = self.client.post('/') - self.assertContains(response, 'Forbidden', status_code=403) + response = self.client.post("/") + self.assertContains(response, "Forbidden", status_code=403) - @override_settings(TEMPLATES=[{ - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'OPTIONS': { - 'loaders': [ - ('django.template.loaders.locmem.Loader', { - CSRF_FAILURE_TEMPLATE_NAME: 'Test template for CSRF failure' - }), - ], - }, - }]) + @override_settings( + TEMPLATES=[ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "OPTIONS": { + "loaders": [ + ( + "django.template.loaders.locmem.Loader", + { + CSRF_FAILURE_TEMPLATE_NAME: "Test template for CSRF failure" + }, + ), + ], + }, + } + ] + ) def test_custom_template(self): """A custom CSRF_FAILURE_TEMPLATE_NAME is used.""" - response = self.client.post('/') - self.assertContains(response, 'Test template for CSRF failure', status_code=403) + response = self.client.post("/") + self.assertContains(response, "Test template for CSRF failure", status_code=403) def test_custom_template_does_not_exist(self): """An exception is raised if a nonexistent template is supplied.""" factory = RequestFactory() - request = factory.post('/') + request = factory.post("/") with self.assertRaises(TemplateDoesNotExist): - csrf_failure(request, template_name='nonexistent.html') + csrf_failure(request, template_name="nonexistent.html") diff --git a/tests/view_tests/tests/test_debug.py b/tests/view_tests/tests/test_debug.py index 1484c071c5..1bf395ce37 100644 --- a/tests/view_tests/tests/test_debug.py +++ b/tests/view_tests/tests/test_debug.py @@ -23,35 +23,45 @@ from django.utils.functional import SimpleLazyObject from django.utils.regex_helper import _lazy_re_compile from django.utils.safestring import mark_safe from django.views.debug import ( - CallableSettingWrapper, ExceptionCycleWarning, ExceptionReporter, - Path as DebugPath, SafeExceptionReporterFilter, default_urlconf, - get_default_exception_reporter_filter, technical_404_response, - technical_500_response, + CallableSettingWrapper, + ExceptionCycleWarning, + ExceptionReporter, ) -from django.views.decorators.debug import ( - sensitive_post_parameters, sensitive_variables, +from django.views.debug import Path as DebugPath +from django.views.debug import ( + SafeExceptionReporterFilter, + default_urlconf, + get_default_exception_reporter_filter, + technical_404_response, + technical_500_response, ) +from django.views.decorators.debug import sensitive_post_parameters, sensitive_variables from ..views import ( - custom_exception_reporter_filter_view, index_page, - multivalue_dict_key_error, non_sensitive_view, paranoid_view, - sensitive_args_function_caller, sensitive_kwargs_function_caller, - sensitive_method_view, sensitive_view, + custom_exception_reporter_filter_view, + index_page, + multivalue_dict_key_error, + non_sensitive_view, + paranoid_view, + sensitive_args_function_caller, + sensitive_kwargs_function_caller, + sensitive_method_view, + sensitive_view, ) class User: def __str__(self): - return 'jacob' + return "jacob" class WithoutEmptyPathUrls: - urlpatterns = [path('url/', index_page, name='url')] + urlpatterns = [path("url/", index_page, name="url")] class CallableSettingWrapperTests(SimpleTestCase): - """ Unittests for CallableSettingWrapper - """ + """Unittests for CallableSettingWrapper""" + def test_repr(self): class WrappedCallable: def __repr__(self): @@ -64,64 +74,74 @@ class CallableSettingWrapperTests(SimpleTestCase): self.assertEqual(actual, "repr from the wrapped callable") -@override_settings(DEBUG=True, ROOT_URLCONF='view_tests.urls') +@override_settings(DEBUG=True, ROOT_URLCONF="view_tests.urls") class DebugViewTests(SimpleTestCase): - def test_files(self): - with self.assertLogs('django.request', 'ERROR'): - response = self.client.get('/raises/') + with self.assertLogs("django.request", "ERROR"): + response = self.client.get("/raises/") self.assertEqual(response.status_code, 500) data = { - 'file_data.txt': SimpleUploadedFile('file_data.txt', b'haha'), + "file_data.txt": SimpleUploadedFile("file_data.txt", b"haha"), } - with self.assertLogs('django.request', 'ERROR'): - response = self.client.post('/raises/', data) - self.assertContains(response, 'file_data.txt', status_code=500) - self.assertNotContains(response, 'haha', status_code=500) + with self.assertLogs("django.request", "ERROR"): + response = self.client.post("/raises/", data) + self.assertContains(response, "file_data.txt", status_code=500) + self.assertNotContains(response, "haha", status_code=500) def test_400(self): # When DEBUG=True, technical_500_template() is called. - with self.assertLogs('django.security', 'WARNING'): - response = self.client.get('/raises400/') + with self.assertLogs("django.security", "WARNING"): + response = self.client.get("/raises400/") self.assertContains(response, '<div class="context" id="', status_code=400) def test_400_bad_request(self): # When DEBUG=True, technical_500_template() is called. - with self.assertLogs('django.request', 'WARNING') as cm: - response = self.client.get('/raises400_bad_request/') + with self.assertLogs("django.request", "WARNING") as cm: + response = self.client.get("/raises400_bad_request/") self.assertContains(response, '<div class="context" id="', status_code=400) self.assertEqual( cm.records[0].getMessage(), - 'Malformed request syntax: /raises400_bad_request/', + "Malformed request syntax: /raises400_bad_request/", ) # Ensure no 403.html template exists to test the default case. - @override_settings(TEMPLATES=[{ - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - }]) + @override_settings( + TEMPLATES=[ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + } + ] + ) def test_403(self): - response = self.client.get('/raises403/') - self.assertContains(response, '<h1>403 Forbidden</h1>', status_code=403) + response = self.client.get("/raises403/") + self.assertContains(response, "<h1>403 Forbidden</h1>", status_code=403) # Set up a test 403.html template. - @override_settings(TEMPLATES=[{ - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'OPTIONS': { - 'loaders': [ - ('django.template.loaders.locmem.Loader', { - '403.html': 'This is a test template for a 403 error ({{ exception }}).', - }), - ], - }, - }]) + @override_settings( + TEMPLATES=[ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "OPTIONS": { + "loaders": [ + ( + "django.template.loaders.locmem.Loader", + { + "403.html": "This is a test template for a 403 error ({{ exception }}).", + }, + ), + ], + }, + } + ] + ) def test_403_template(self): - response = self.client.get('/raises403/') - self.assertContains(response, 'test template', status_code=403) - self.assertContains(response, '(Insufficient Permissions).', status_code=403) + response = self.client.get("/raises403/") + self.assertContains(response, "test template", status_code=403) + self.assertContains(response, "(Insufficient Permissions).", status_code=403) def test_404(self): - response = self.client.get('/raises404/') + response = self.client.get("/raises404/") self.assertNotContains( response, '<pre class="exception_value">', @@ -129,30 +149,34 @@ class DebugViewTests(SimpleTestCase): ) self.assertContains( response, - '<p>The current path, <code>not-in-urls</code>, didn’t match any ' - 'of these.</p>', + "<p>The current path, <code>not-in-urls</code>, didn’t match any " + "of these.</p>", status_code=404, html=True, ) def test_404_not_in_urls(self): - response = self.client.get('/not-in-urls') + response = self.client.get("/not-in-urls") self.assertNotContains(response, "Raised by:", status_code=404) self.assertNotContains( response, '<pre class="exception_value">', status_code=404, ) - self.assertContains(response, "Django tried these URL patterns", status_code=404) + self.assertContains( + response, "Django tried these URL patterns", status_code=404 + ) self.assertContains( response, - '<p>The current path, <code>not-in-urls</code>, didn’t match any ' - 'of these.</p>', + "<p>The current path, <code>not-in-urls</code>, didn’t match any " + "of these.</p>", status_code=404, html=True, ) # Pattern and view name of a RegexURLPattern appear. - self.assertContains(response, r"^regex-post/(?P<pk>[0-9]+)/$", status_code=404) + self.assertContains( + response, r"^regex-post/(?P<pk>[0-9]+)/$", status_code=404 + ) self.assertContains(response, "[name='regex-post']", status_code=404) # Pattern and view name of a RoutePattern appear. self.assertContains(response, r"path-post/<int:pk>/", status_code=404) @@ -160,16 +184,16 @@ class DebugViewTests(SimpleTestCase): @override_settings(ROOT_URLCONF=WithoutEmptyPathUrls) def test_404_empty_path_not_in_urls(self): - response = self.client.get('/') + response = self.client.get("/") self.assertContains( response, - '<p>The empty path didn’t match any of these.</p>', + "<p>The empty path didn’t match any of these.</p>", status_code=404, html=True, ) def test_technical_404(self): - response = self.client.get('/technical404/') + response = self.client.get("/technical404/") self.assertContains( response, '<pre class="exception_value">Testing technical 404.</pre>', @@ -179,57 +203,57 @@ class DebugViewTests(SimpleTestCase): self.assertContains(response, "Raised by:", status_code=404) self.assertContains( response, - '<td>view_tests.views.technical404</td>', + "<td>view_tests.views.technical404</td>", status_code=404, ) self.assertContains( response, - '<p>The current path, <code>technical404/</code>, matched the ' - 'last one.</p>', + "<p>The current path, <code>technical404/</code>, matched the " + "last one.</p>", status_code=404, html=True, ) def test_classbased_technical_404(self): - response = self.client.get('/classbased404/') + response = self.client.get("/classbased404/") self.assertContains( response, - '<th>Raised by:</th><td>view_tests.views.Http404View</td>', + "<th>Raised by:</th><td>view_tests.views.Http404View</td>", status_code=404, html=True, ) def test_technical_500(self): - with self.assertLogs('django.request', 'ERROR'): - response = self.client.get('/raises500/') + with self.assertLogs("django.request", "ERROR"): + response = self.client.get("/raises500/") self.assertContains( response, - '<th>Raised during:</th><td>view_tests.views.raises500</td>', + "<th>Raised during:</th><td>view_tests.views.raises500</td>", status_code=500, html=True, ) - with self.assertLogs('django.request', 'ERROR'): - response = self.client.get('/raises500/', HTTP_ACCEPT='text/plain') + with self.assertLogs("django.request", "ERROR"): + response = self.client.get("/raises500/", HTTP_ACCEPT="text/plain") self.assertContains( response, - 'Raised during: view_tests.views.raises500', + "Raised during: view_tests.views.raises500", status_code=500, ) def test_classbased_technical_500(self): - with self.assertLogs('django.request', 'ERROR'): - response = self.client.get('/classbased500/') + with self.assertLogs("django.request", "ERROR"): + response = self.client.get("/classbased500/") self.assertContains( response, - '<th>Raised during:</th><td>view_tests.views.Raises500View</td>', + "<th>Raised during:</th><td>view_tests.views.Raises500View</td>", status_code=500, html=True, ) - with self.assertLogs('django.request', 'ERROR'): - response = self.client.get('/classbased500/', HTTP_ACCEPT='text/plain') + with self.assertLogs("django.request", "ERROR"): + response = self.client.get("/classbased500/", HTTP_ACCEPT="text/plain") self.assertContains( response, - 'Raised during: view_tests.views.Raises500View', + "Raised during: view_tests.views.Raises500View", status_code=500, ) @@ -238,48 +262,51 @@ class DebugViewTests(SimpleTestCase): Numeric IDs and fancy traceback context blocks line numbers shouldn't be localized. """ with self.settings(DEBUG=True): - with self.assertLogs('django.request', 'ERROR'): - response = self.client.get('/raises500/') + with self.assertLogs("django.request", "ERROR"): + response = self.client.get("/raises500/") # We look for a HTML fragment of the form # '<div class="context" id="c38123208">', not '<div class="context" id="c38,123,208"' self.assertContains(response, '<div class="context" id="', status_code=500) - match = re.search(b'<div class="context" id="(?P<id>[^"]+)">', response.content) + match = re.search( + b'<div class="context" id="(?P<id>[^"]+)">', response.content + ) self.assertIsNotNone(match) - id_repr = match['id'] + id_repr = match["id"] self.assertFalse( - re.search(b'[^c0-9]', id_repr), - "Numeric IDs in debug response HTML page shouldn't be localized (value: %s)." % id_repr.decode() + re.search(b"[^c0-9]", id_repr), + "Numeric IDs in debug response HTML page shouldn't be localized (value: %s)." + % id_repr.decode(), ) def test_template_exceptions(self): - with self.assertLogs('django.request', 'ERROR'): + with self.assertLogs("django.request", "ERROR"): try: - self.client.get(reverse('template_exception')) + self.client.get(reverse("template_exception")) except Exception: raising_loc = inspect.trace()[-1][-2][0].strip() self.assertNotEqual( raising_loc.find('raise Exception("boom")'), -1, "Failed to find 'raise Exception' in last frame of " - "traceback, instead found: %s" % raising_loc + "traceback, instead found: %s" % raising_loc, ) @skipIf( - sys.platform == 'win32', - 'Raises OSError instead of TemplateDoesNotExist on Windows.', + sys.platform == "win32", + "Raises OSError instead of TemplateDoesNotExist on Windows.", ) def test_safestring_in_exception(self): - with self.assertLogs('django.request', 'ERROR'): - response = self.client.get('/safestring_exception/') + with self.assertLogs("django.request", "ERROR"): + response = self.client.get("/safestring_exception/") self.assertNotContains( response, - '<script>alert(1);</script>', + "<script>alert(1);</script>", status_code=500, html=True, ) self.assertContains( response, - '<script>alert(1);</script>', + "<script>alert(1);</script>", count=3, status_code=500, html=True, @@ -291,17 +318,31 @@ class DebugViewTests(SimpleTestCase): with tempfile.NamedTemporaryFile(prefix=template_name) as tmpfile: tempdir = os.path.dirname(tmpfile.name) template_path = os.path.join(tempdir, template_name) - with override_settings(TEMPLATES=[{ - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [tempdir], - }]), self.assertLogs('django.request', 'ERROR'): - response = self.client.get(reverse('raises_template_does_not_exist', kwargs={"path": template_name})) - self.assertContains(response, "%s (Source does not exist)" % template_path, status_code=500, count=2) + with override_settings( + TEMPLATES=[ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [tempdir], + } + ] + ), self.assertLogs("django.request", "ERROR"): + response = self.client.get( + reverse( + "raises_template_does_not_exist", kwargs={"path": template_name} + ) + ) + self.assertContains( + response, + "%s (Source does not exist)" % template_path, + status_code=500, + count=2, + ) # Assert as HTML. self.assertContains( response, - '<li><code>django.template.loaders.filesystem.Loader</code>: ' - '%s (Source does not exist)</li>' % os.path.join(tempdir, 'notfound.html'), + "<li><code>django.template.loaders.filesystem.Loader</code>: " + "%s (Source does not exist)</li>" + % os.path.join(tempdir, "notfound.html"), status_code=500, html=True, ) @@ -310,23 +351,22 @@ class DebugViewTests(SimpleTestCase): """ Make sure if you don't specify a template, the debug view doesn't blow up. """ - with self.assertLogs('django.request', 'ERROR'): + with self.assertLogs("django.request", "ERROR"): with self.assertRaises(TemplateDoesNotExist): - self.client.get('/render_no_template/') + self.client.get("/render_no_template/") - @override_settings(ROOT_URLCONF='view_tests.default_urls') + @override_settings(ROOT_URLCONF="view_tests.default_urls") def test_default_urlconf_template(self): """ Make sure that the default URLconf template is shown instead of the technical 404 page, if the user has not altered their URLconf yet. """ - response = self.client.get('/') + response = self.client.get("/") self.assertContains( - response, - "<h1>The install worked successfully! Congratulations!</h1>" + response, "<h1>The install worked successfully! Congratulations!</h1>" ) - @override_settings(ROOT_URLCONF='view_tests.regression_21530_urls') + @override_settings(ROOT_URLCONF="view_tests.regression_21530_urls") def test_regression_21530(self): """ Regression test for bug #21530. @@ -336,11 +376,9 @@ class DebugViewTests(SimpleTestCase): The bug here was that an AttributeError caused a 500 response. """ - response = self.client.get('/') + response = self.client.get("/") self.assertContains( - response, - "Page not found <span>(404)</span>", - status_code=404 + response, "Page not found <span>(404)</span>", status_code=404 ) def test_template_encoding(self): @@ -349,48 +387,52 @@ class DebugViewTests(SimpleTestCase): should be opened as utf-8 charset as is the default specified on template engines. """ - with mock.patch.object(DebugPath, 'open') as m: + with mock.patch.object(DebugPath, "open") as m: default_urlconf(None) - m.assert_called_once_with(encoding='utf-8') + m.assert_called_once_with(encoding="utf-8") m.reset_mock() technical_404_response(mock.MagicMock(), mock.Mock()) - m.assert_called_once_with(encoding='utf-8') + m.assert_called_once_with(encoding="utf-8") def test_technical_404_converter_raise_404(self): - with mock.patch.object(IntConverter, 'to_python', side_effect=Http404): - response = self.client.get('/path-post/1/') - self.assertContains(response, 'Page not found', status_code=404) + with mock.patch.object(IntConverter, "to_python", side_effect=Http404): + response = self.client.get("/path-post/1/") + self.assertContains(response, "Page not found", status_code=404) def test_exception_reporter_from_request(self): - with self.assertLogs('django.request', 'ERROR'): - response = self.client.get('/custom_reporter_class_view/') - self.assertContains(response, 'custom traceback text', status_code=500) + with self.assertLogs("django.request", "ERROR"): + response = self.client.get("/custom_reporter_class_view/") + self.assertContains(response, "custom traceback text", status_code=500) - @override_settings(DEFAULT_EXCEPTION_REPORTER='view_tests.views.CustomExceptionReporter') + @override_settings( + DEFAULT_EXCEPTION_REPORTER="view_tests.views.CustomExceptionReporter" + ) def test_exception_reporter_from_settings(self): - with self.assertLogs('django.request', 'ERROR'): - response = self.client.get('/raises500/') - self.assertContains(response, 'custom traceback text', status_code=500) + with self.assertLogs("django.request", "ERROR"): + response = self.client.get("/raises500/") + self.assertContains(response, "custom traceback text", status_code=500) - @override_settings(DEFAULT_EXCEPTION_REPORTER='view_tests.views.TemplateOverrideExceptionReporter') + @override_settings( + DEFAULT_EXCEPTION_REPORTER="view_tests.views.TemplateOverrideExceptionReporter" + ) def test_template_override_exception_reporter(self): - with self.assertLogs('django.request', 'ERROR'): - response = self.client.get('/raises500/') + with self.assertLogs("django.request", "ERROR"): + response = self.client.get("/raises500/") self.assertContains( response, - '<h1>Oh no, an error occurred!</h1>', + "<h1>Oh no, an error occurred!</h1>", status_code=500, html=True, ) - with self.assertLogs('django.request', 'ERROR'): - response = self.client.get('/raises500/', HTTP_ACCEPT='text/plain') - self.assertContains(response, 'Oh dear, an error occurred!', status_code=500) + with self.assertLogs("django.request", "ERROR"): + response = self.client.get("/raises500/", HTTP_ACCEPT="text/plain") + self.assertContains(response, "Oh dear, an error occurred!", status_code=500) class DebugViewQueriesAllowedTests(SimpleTestCase): # May need a query to initialize MySQL connection - databases = {'default'} + databases = {"default"} def test_handle_db_exception(self): """ @@ -399,53 +441,56 @@ class DebugViewQueriesAllowedTests(SimpleTestCase): """ with connection.cursor() as cursor: try: - cursor.execute('INVALID SQL') + cursor.execute("INVALID SQL") except DatabaseError: exc_info = sys.exc_info() rf = RequestFactory() - response = technical_500_response(rf.get('/'), *exc_info) - self.assertContains(response, 'OperationalError at /', status_code=500) + response = technical_500_response(rf.get("/"), *exc_info) + self.assertContains(response, "OperationalError at /", status_code=500) @override_settings( DEBUG=True, - ROOT_URLCONF='view_tests.urls', + ROOT_URLCONF="view_tests.urls", # No template directories are configured, so no templates will be found. - TEMPLATES=[{ - 'BACKEND': 'django.template.backends.dummy.TemplateStrings', - }], + TEMPLATES=[ + { + "BACKEND": "django.template.backends.dummy.TemplateStrings", + } + ], ) class NonDjangoTemplatesDebugViewTests(SimpleTestCase): - def test_400(self): # When DEBUG=True, technical_500_template() is called. - with self.assertLogs('django.security', 'WARNING'): - response = self.client.get('/raises400/') + with self.assertLogs("django.security", "WARNING"): + response = self.client.get("/raises400/") self.assertContains(response, '<div class="context" id="', status_code=400) def test_400_bad_request(self): # When DEBUG=True, technical_500_template() is called. - with self.assertLogs('django.request', 'WARNING') as cm: - response = self.client.get('/raises400_bad_request/') + with self.assertLogs("django.request", "WARNING") as cm: + response = self.client.get("/raises400_bad_request/") self.assertContains(response, '<div class="context" id="', status_code=400) self.assertEqual( cm.records[0].getMessage(), - 'Malformed request syntax: /raises400_bad_request/', + "Malformed request syntax: /raises400_bad_request/", ) def test_403(self): - response = self.client.get('/raises403/') - self.assertContains(response, '<h1>403 Forbidden</h1>', status_code=403) + response = self.client.get("/raises403/") + self.assertContains(response, "<h1>403 Forbidden</h1>", status_code=403) def test_404(self): - response = self.client.get('/raises404/') + response = self.client.get("/raises404/") self.assertEqual(response.status_code, 404) def test_template_not_found_error(self): # Raises a TemplateDoesNotExist exception and shows the debug view. - url = reverse('raises_template_does_not_exist', kwargs={"path": "notfound.html"}) - with self.assertLogs('django.request', 'ERROR'): + url = reverse( + "raises_template_does_not_exist", kwargs={"path": "notfound.html"} + ) + with self.assertLogs("django.request", "ERROR"): response = self.client.get(url) self.assertContains(response, '<div class="context" id="', status_code=500) @@ -456,25 +501,27 @@ class ExceptionReporterTests(SimpleTestCase): def test_request_and_exception(self): "A simple exception report can be generated" try: - request = self.rf.get('/test_view/') + request = self.rf.get("/test_view/") request.user = User() raise ValueError("Can't find my keys") except ValueError: exc_type, exc_value, tb = sys.exc_info() reporter = ExceptionReporter(request, exc_type, exc_value, tb) html = reporter.get_traceback_html() - self.assertInHTML('<h1>ValueError at /test_view/</h1>', html) - self.assertIn('<pre class="exception_value">Can't find my keys</pre>', html) - self.assertIn('<th>Request Method:</th>', html) - self.assertIn('<th>Request URL:</th>', html) + self.assertInHTML("<h1>ValueError at /test_view/</h1>", html) + self.assertIn( + '<pre class="exception_value">Can't find my keys</pre>', html + ) + self.assertIn("<th>Request Method:</th>", html) + self.assertIn("<th>Request URL:</th>", html) self.assertIn('<h3 id="user-info">USER</h3>', html) - self.assertIn('<p>jacob</p>', html) - self.assertIn('<th>Exception Type:</th>', html) - self.assertIn('<th>Exception Value:</th>', html) - self.assertIn('<h2>Traceback ', html) - self.assertIn('<h2>Request information</h2>', html) - self.assertNotIn('<p>Request data not supplied</p>', html) - self.assertIn('<p>No POST data</p>', html) + self.assertIn("<p>jacob</p>", html) + self.assertIn("<th>Exception Type:</th>", html) + self.assertIn("<th>Exception Value:</th>", html) + self.assertIn("<h2>Traceback ", html) + self.assertIn("<h2>Request information</h2>", html) + self.assertNotIn("<p>Request data not supplied</p>", html) + self.assertIn("<p>No POST data</p>", html) def test_no_request(self): "An exception report can be generated without request" @@ -484,20 +531,22 @@ class ExceptionReporterTests(SimpleTestCase): exc_type, exc_value, tb = sys.exc_info() reporter = ExceptionReporter(None, exc_type, exc_value, tb) html = reporter.get_traceback_html() - self.assertInHTML('<h1>ValueError</h1>', html) - self.assertIn('<pre class="exception_value">Can't find my keys</pre>', html) - self.assertNotIn('<th>Request Method:</th>', html) - self.assertNotIn('<th>Request URL:</th>', html) + self.assertInHTML("<h1>ValueError</h1>", html) + self.assertIn( + '<pre class="exception_value">Can't find my keys</pre>', html + ) + self.assertNotIn("<th>Request Method:</th>", html) + self.assertNotIn("<th>Request URL:</th>", html) self.assertNotIn('<h3 id="user-info">USER</h3>', html) - self.assertIn('<th>Exception Type:</th>', html) - self.assertIn('<th>Exception Value:</th>', html) - self.assertIn('<h2>Traceback ', html) - self.assertIn('<h2>Request information</h2>', html) - self.assertIn('<p>Request data not supplied</p>', html) + self.assertIn("<th>Exception Type:</th>", html) + self.assertIn("<th>Exception Value:</th>", html) + self.assertIn("<h2>Traceback ", html) + self.assertIn("<h2>Request information</h2>", html) + self.assertIn("<p>Request data not supplied</p>", html) def test_sharing_traceback(self): try: - raise ValueError('Oops') + raise ValueError("Oops") except ValueError: exc_type, exc_value, tb = sys.exc_info() reporter = ExceptionReporter(None, exc_type, exc_value, tb) @@ -510,10 +559,10 @@ class ExceptionReporterTests(SimpleTestCase): def test_eol_support(self): """The ExceptionReporter supports Unix, Windows and Macintosh EOL markers""" - LINES = ['print %d' % i for i in range(1, 6)] + LINES = ["print %d" % i for i in range(1, 6)] reporter = ExceptionReporter(None, None, None, None) - for newline in ['\n', '\r\n', '\r']: + for newline in ["\n", "\r\n", "\r"]: fd, filename = tempfile.mkstemp(text=False) os.write(fd, (newline.join(LINES) + newline).encode()) os.close(fd) @@ -521,25 +570,27 @@ class ExceptionReporterTests(SimpleTestCase): try: self.assertEqual( reporter._get_lines_from_file(filename, 3, 2), - (1, LINES[1:3], LINES[3], LINES[4:]) + (1, LINES[1:3], LINES[3], LINES[4:]), ) finally: os.unlink(filename) def test_no_exception(self): "An exception report can be generated for just a request" - request = self.rf.get('/test_view/') + request = self.rf.get("/test_view/") reporter = ExceptionReporter(request, None, None, None) html = reporter.get_traceback_html() - self.assertInHTML('<h1>Report at /test_view/</h1>', html) - self.assertIn('<pre class="exception_value">No exception message supplied</pre>', html) - self.assertIn('<th>Request Method:</th>', html) - self.assertIn('<th>Request URL:</th>', html) - self.assertNotIn('<th>Exception Type:</th>', html) - self.assertNotIn('<th>Exception Value:</th>', html) - self.assertNotIn('<h2>Traceback ', html) - self.assertIn('<h2>Request information</h2>', html) - self.assertNotIn('<p>Request data not supplied</p>', html) + self.assertInHTML("<h1>Report at /test_view/</h1>", html) + self.assertIn( + '<pre class="exception_value">No exception message supplied</pre>', html + ) + self.assertIn("<th>Request Method:</th>", html) + self.assertIn("<th>Request URL:</th>", html) + self.assertNotIn("<th>Exception Type:</th>", html) + self.assertNotIn("<th>Exception Value:</th>", html) + self.assertNotIn("<h2>Traceback ", html) + self.assertIn("<h2>Request information</h2>", html) + self.assertNotIn("<p>Request data not supplied</p>", html) def test_suppressed_context(self): try: @@ -552,21 +603,23 @@ class ExceptionReporterTests(SimpleTestCase): reporter = ExceptionReporter(None, exc_type, exc_value, tb) html = reporter.get_traceback_html() - self.assertInHTML('<h1>ValueError</h1>', html) - self.assertIn('<pre class="exception_value">Can't find my keys</pre>', html) - self.assertIn('<th>Exception Type:</th>', html) - self.assertIn('<th>Exception Value:</th>', html) - self.assertIn('<h2>Traceback ', html) - self.assertIn('<h2>Request information</h2>', html) - self.assertIn('<p>Request data not supplied</p>', html) - self.assertNotIn('During handling of the above exception', html) + self.assertInHTML("<h1>ValueError</h1>", html) + self.assertIn( + '<pre class="exception_value">Can't find my keys</pre>', html + ) + self.assertIn("<th>Exception Type:</th>", html) + self.assertIn("<th>Exception Value:</th>", html) + self.assertIn("<h2>Traceback ", html) + self.assertIn("<h2>Request information</h2>", html) + self.assertIn("<p>Request data not supplied</p>", html) + self.assertNotIn("During handling of the above exception", html) def test_innermost_exception_without_traceback(self): try: try: - raise RuntimeError('Oops') + raise RuntimeError("Oops") except Exception as exc: - new_exc = RuntimeError('My context') + new_exc = RuntimeError("My context") exc.__context__ = new_exc raise except Exception: @@ -576,111 +629,119 @@ class ExceptionReporterTests(SimpleTestCase): frames = reporter.get_traceback_frames() self.assertEqual(len(frames), 2) html = reporter.get_traceback_html() - self.assertInHTML('<h1>RuntimeError</h1>', html) + self.assertInHTML("<h1>RuntimeError</h1>", html) self.assertIn('<pre class="exception_value">Oops</pre>', html) - self.assertIn('<th>Exception Type:</th>', html) - self.assertIn('<th>Exception Value:</th>', html) - self.assertIn('<h2>Traceback ', html) - self.assertIn('<h2>Request information</h2>', html) - self.assertIn('<p>Request data not supplied</p>', html) + self.assertIn("<th>Exception Type:</th>", html) + self.assertIn("<th>Exception Value:</th>", html) + self.assertIn("<h2>Traceback ", html) + self.assertIn("<h2>Request information</h2>", html) + self.assertIn("<p>Request data not supplied</p>", html) self.assertIn( - 'During handling of the above exception (My context), another ' - 'exception occurred', + "During handling of the above exception (My context), another " + "exception occurred", html, ) self.assertInHTML('<li class="frame user">None</li>', html) - self.assertIn('Traceback (most recent call last):\n None', html) + self.assertIn("Traceback (most recent call last):\n None", html) text = reporter.get_traceback_text() - self.assertIn('Exception Type: RuntimeError', text) - self.assertIn('Exception Value: Oops', text) - self.assertIn('Traceback (most recent call last):\n None', text) + self.assertIn("Exception Type: RuntimeError", text) + self.assertIn("Exception Value: Oops", text) + self.assertIn("Traceback (most recent call last):\n None", text) self.assertIn( - 'During handling of the above exception (My context), another ' - 'exception occurred', + "During handling of the above exception (My context), another " + "exception occurred", text, ) def test_mid_stack_exception_without_traceback(self): try: try: - raise RuntimeError('Inner Oops') + raise RuntimeError("Inner Oops") except Exception as exc: - new_exc = RuntimeError('My context') + new_exc = RuntimeError("My context") new_exc.__context__ = exc - raise RuntimeError('Oops') from new_exc + raise RuntimeError("Oops") from new_exc except Exception: exc_type, exc_value, tb = sys.exc_info() reporter = ExceptionReporter(None, exc_type, exc_value, tb) html = reporter.get_traceback_html() - self.assertInHTML('<h1>RuntimeError</h1>', html) + self.assertInHTML("<h1>RuntimeError</h1>", html) self.assertIn('<pre class="exception_value">Oops</pre>', html) - self.assertIn('<th>Exception Type:</th>', html) - self.assertIn('<th>Exception Value:</th>', html) - self.assertIn('<h2>Traceback ', html) + self.assertIn("<th>Exception Type:</th>", html) + self.assertIn("<th>Exception Value:</th>", html) + self.assertIn("<h2>Traceback ", html) self.assertInHTML('<li class="frame user">Traceback: None</li>', html) self.assertIn( - 'During handling of the above exception (Inner Oops), another ' - 'exception occurred:\n Traceback: None', + "During handling of the above exception (Inner Oops), another " + "exception occurred:\n Traceback: None", html, ) text = reporter.get_traceback_text() - self.assertIn('Exception Type: RuntimeError', text) - self.assertIn('Exception Value: Oops', text) - self.assertIn('Traceback (most recent call last):', text) + self.assertIn("Exception Type: RuntimeError", text) + self.assertIn("Exception Value: Oops", text) + self.assertIn("Traceback (most recent call last):", text) self.assertIn( - 'During handling of the above exception (Inner Oops), another ' - 'exception occurred:\n Traceback: None', + "During handling of the above exception (Inner Oops), another " + "exception occurred:\n Traceback: None", text, ) def test_reporting_of_nested_exceptions(self): - request = self.rf.get('/test_view/') + request = self.rf.get("/test_view/") try: try: - raise AttributeError(mark_safe('<p>Top level</p>')) + raise AttributeError(mark_safe("<p>Top level</p>")) except AttributeError as explicit: try: - raise ValueError(mark_safe('<p>Second exception</p>')) from explicit + raise ValueError(mark_safe("<p>Second exception</p>")) from explicit except ValueError: - raise IndexError(mark_safe('<p>Final exception</p>')) + raise IndexError(mark_safe("<p>Final exception</p>")) except Exception: # Custom exception handler, just pass it into ExceptionReporter exc_type, exc_value, tb = sys.exc_info() - explicit_exc = 'The above exception ({0}) was the direct cause of the following exception:' - implicit_exc = 'During handling of the above exception ({0}), another exception occurred:' + explicit_exc = ( + "The above exception ({0}) was the direct cause of the following exception:" + ) + implicit_exc = ( + "During handling of the above exception ({0}), another exception occurred:" + ) reporter = ExceptionReporter(request, exc_type, exc_value, tb) html = reporter.get_traceback_html() # Both messages are twice on page -- one rendered as html, # one as plain text (for pastebin) - self.assertEqual(2, html.count(explicit_exc.format('<p>Top level</p>'))) - self.assertEqual(2, html.count(implicit_exc.format('<p>Second exception</p>'))) - self.assertEqual(10, html.count('<p>Final exception</p>')) + self.assertEqual( + 2, html.count(explicit_exc.format("<p>Top level</p>")) + ) + self.assertEqual( + 2, html.count(implicit_exc.format("<p>Second exception</p>")) + ) + self.assertEqual(10, html.count("<p>Final exception</p>")) text = reporter.get_traceback_text() - self.assertIn(explicit_exc.format('<p>Top level</p>'), text) - self.assertIn(implicit_exc.format('<p>Second exception</p>'), text) - self.assertEqual(3, text.count('<p>Final exception</p>')) + self.assertIn(explicit_exc.format("<p>Top level</p>"), text) + self.assertIn(implicit_exc.format("<p>Second exception</p>"), text) + self.assertEqual(3, text.count("<p>Final exception</p>")) def test_reporting_frames_without_source(self): try: source = "def funcName():\n raise Error('Whoops')\nfuncName()" namespace = {} - code = compile(source, 'generated', 'exec') + code = compile(source, "generated", "exec") exec(code, namespace) except Exception: exc_type, exc_value, tb = sys.exc_info() - request = self.rf.get('/test_view/') + request = self.rf.get("/test_view/") reporter = ExceptionReporter(request, exc_type, exc_value, tb) frames = reporter.get_traceback_frames() last_frame = frames[-1] - self.assertEqual(last_frame['context_line'], '<source code not available>') - self.assertEqual(last_frame['filename'], 'generated') - self.assertEqual(last_frame['function'], 'funcName') - self.assertEqual(last_frame['lineno'], 2) + self.assertEqual(last_frame["context_line"], "<source code not available>") + self.assertEqual(last_frame["filename"], "generated") + self.assertEqual(last_frame["function"], "funcName") + self.assertEqual(last_frame["lineno"], 2) html = reporter.get_traceback_html() self.assertIn( '<span class="fname">generated</span>, line 2, in funcName', @@ -704,22 +765,22 @@ class ExceptionReporterTests(SimpleTestCase): try: source = "def funcName():\n raise Error('Whoops')\nfuncName()" namespace = {} - code = compile(source, 'generated', 'exec') + code = compile(source, "generated", "exec") exec(code, namespace) except Exception: exc_type, exc_value, tb = sys.exc_info() with mock.patch( - 'django.views.debug.ExceptionReporter._get_source', - return_value=['wrong source'], + "django.views.debug.ExceptionReporter._get_source", + return_value=["wrong source"], ): - request = self.rf.get('/test_view/') + request = self.rf.get("/test_view/") reporter = ExceptionReporter(request, exc_type, exc_value, tb) frames = reporter.get_traceback_frames() last_frame = frames[-1] - self.assertEqual(last_frame['context_line'], '<source code not available>') - self.assertEqual(last_frame['filename'], 'generated') - self.assertEqual(last_frame['function'], 'funcName') - self.assertEqual(last_frame['lineno'], 2) + self.assertEqual(last_frame["context_line"], "<source code not available>") + self.assertEqual(last_frame["filename"], "generated") + self.assertEqual(last_frame["function"], "funcName") + self.assertEqual(last_frame["lineno"], 2) html = reporter.get_traceback_html() self.assertIn( '<span class="fname">generated</span>, line 2, in funcName', @@ -741,15 +802,17 @@ class ExceptionReporterTests(SimpleTestCase): def test_reporting_frames_for_cyclic_reference(self): try: + def test_func(): try: - raise RuntimeError('outer') from RuntimeError('inner') + raise RuntimeError("outer") from RuntimeError("inner") except RuntimeError as exc: raise exc.__cause__ + test_func() except Exception: exc_type, exc_value, tb = sys.exc_info() - request = self.rf.get('/test_view/') + request = self.rf.get("/test_view/") reporter = ExceptionReporter(request, exc_type, exc_value, tb) def generate_traceback_frames(*args, **kwargs): @@ -772,75 +835,86 @@ class ExceptionReporterTests(SimpleTestCase): # reporter.get_traceback_frames() exit early. exc_value.__traceback__ = exc_value.__context__ = exc_value.__cause__ = None tb_generator.join() - self.fail('Cyclic reference in Exception Reporter.get_traceback_frames()') + self.fail("Cyclic reference in Exception Reporter.get_traceback_frames()") if tb_frames is None: # can happen if the thread generating traceback got killed # or exception while generating the traceback - self.fail('Traceback generation failed') + self.fail("Traceback generation failed") last_frame = tb_frames[-1] - self.assertIn('raise exc.__cause__', last_frame['context_line']) - self.assertEqual(last_frame['filename'], __file__) - self.assertEqual(last_frame['function'], 'test_func') + self.assertIn("raise exc.__cause__", last_frame["context_line"]) + self.assertEqual(last_frame["filename"], __file__) + self.assertEqual(last_frame["function"], "test_func") def test_request_and_message(self): "A message can be provided in addition to a request" - request = self.rf.get('/test_view/') + request = self.rf.get("/test_view/") reporter = ExceptionReporter(request, None, "I'm a little teapot", None) html = reporter.get_traceback_html() - self.assertInHTML('<h1>Report at /test_view/</h1>', html) - self.assertIn('<pre class="exception_value">I'm a little teapot</pre>', html) - self.assertIn('<th>Request Method:</th>', html) - self.assertIn('<th>Request URL:</th>', html) - self.assertNotIn('<th>Exception Type:</th>', html) - self.assertNotIn('<th>Exception Value:</th>', html) - self.assertIn('<h2>Traceback ', html) - self.assertIn('<h2>Request information</h2>', html) - self.assertNotIn('<p>Request data not supplied</p>', html) + self.assertInHTML("<h1>Report at /test_view/</h1>", html) + self.assertIn( + '<pre class="exception_value">I'm a little teapot</pre>', html + ) + self.assertIn("<th>Request Method:</th>", html) + self.assertIn("<th>Request URL:</th>", html) + self.assertNotIn("<th>Exception Type:</th>", html) + self.assertNotIn("<th>Exception Value:</th>", html) + self.assertIn("<h2>Traceback ", html) + self.assertIn("<h2>Request information</h2>", html) + self.assertNotIn("<p>Request data not supplied</p>", html) def test_message_only(self): reporter = ExceptionReporter(None, None, "I'm a little teapot", None) html = reporter.get_traceback_html() - self.assertInHTML('<h1>Report</h1>', html) - self.assertIn('<pre class="exception_value">I'm a little teapot</pre>', html) - self.assertNotIn('<th>Request Method:</th>', html) - self.assertNotIn('<th>Request URL:</th>', html) - self.assertNotIn('<th>Exception Type:</th>', html) - self.assertNotIn('<th>Exception Value:</th>', html) - self.assertIn('<h2>Traceback ', html) - self.assertIn('<h2>Request information</h2>', html) - self.assertIn('<p>Request data not supplied</p>', html) + self.assertInHTML("<h1>Report</h1>", html) + self.assertIn( + '<pre class="exception_value">I'm a little teapot</pre>', html + ) + self.assertNotIn("<th>Request Method:</th>", html) + self.assertNotIn("<th>Request URL:</th>", html) + self.assertNotIn("<th>Exception Type:</th>", html) + self.assertNotIn("<th>Exception Value:</th>", html) + self.assertIn("<h2>Traceback ", html) + self.assertIn("<h2>Request information</h2>", html) + self.assertIn("<p>Request data not supplied</p>", html) def test_non_utf8_values_handling(self): "Non-UTF-8 exceptions/values should not make the output generation choke." try: + class NonUtf8Output(Exception): def __repr__(self): - return b'EXC\xe9EXC' - somevar = b'VAL\xe9VAL' # NOQA + return b"EXC\xe9EXC" + + somevar = b"VAL\xe9VAL" # NOQA raise NonUtf8Output() except Exception: exc_type, exc_value, tb = sys.exc_info() reporter = ExceptionReporter(None, exc_type, exc_value, tb) html = reporter.get_traceback_html() - self.assertIn('VAL\\xe9VAL', html) - self.assertIn('EXC\\xe9EXC', html) + self.assertIn("VAL\\xe9VAL", html) + self.assertIn("EXC\\xe9EXC", html) def test_local_variable_escaping(self): """Safe strings in local variables are escaped.""" try: - local = mark_safe('<p>Local variable</p>') + local = mark_safe("<p>Local variable</p>") raise ValueError(local) except Exception: exc_type, exc_value, tb = sys.exc_info() html = ExceptionReporter(None, exc_type, exc_value, tb).get_traceback_html() - self.assertIn('<td class="code"><pre>'<p>Local variable</p>'</pre></td>', html) + self.assertIn( + '<td class="code"><pre>'<p>Local variable</p>'</pre></td>', + html, + ) def test_unprintable_values_handling(self): "Unprintable values should not make the output generation choke." try: + class OomOutput: def __repr__(self): - raise MemoryError('OOM') + raise MemoryError("OOM") + oomvalue = OomOutput() # NOQA raise ValueError() except Exception: @@ -852,11 +926,13 @@ class ExceptionReporterTests(SimpleTestCase): def test_too_large_values_handling(self): "Large values should not create a large HTML." large = 256 * 1024 - repr_of_str_adds = len(repr('')) + repr_of_str_adds = len(repr("")) try: + class LargeOutput: def __repr__(self): - return repr('A' * large) + return repr("A" * large) + largevalue = LargeOutput() # NOQA raise ValueError() except Exception: @@ -864,7 +940,9 @@ class ExceptionReporterTests(SimpleTestCase): reporter = ExceptionReporter(None, exc_type, exc_value, tb) html = reporter.get_traceback_html() self.assertEqual(len(html) // 1024 // 128, 0) # still fit in 128Kb - self.assertIn('<trimmed %d bytes string>' % (large + repr_of_str_adds,), html) + self.assertIn( + "<trimmed %d bytes string>" % (large + repr_of_str_adds,), html + ) def test_encoding_error(self): """ @@ -872,14 +950,14 @@ class ExceptionReporterTests(SimpleTestCase): safe strings is escaped. """ try: - mark_safe('abcdefghijkl<p>mnὀp</p>qrstuwxyz').encode('ascii') + mark_safe("abcdefghijkl<p>mnὀp</p>qrstuwxyz").encode("ascii") except Exception: exc_type, exc_value, tb = sys.exc_info() reporter = ExceptionReporter(None, exc_type, exc_value, tb) html = reporter.get_traceback_html() - self.assertIn('<h2>Unicode error hint</h2>', html) - self.assertIn('The string that could not be encoded/decoded was: ', html) - self.assertIn('<strong><p>mnὀp</p></strong>', html) + self.assertIn("<h2>Unicode error hint</h2>", html) + self.assertIn("The string that could not be encoded/decoded was: ", html) + self.assertIn("<strong><p>mnὀp</p></strong>", html) def test_unfrozen_importlib(self): """ @@ -887,26 +965,27 @@ class ExceptionReporterTests(SimpleTestCase): results in an ImportError. Refs #21443. """ try: - request = self.rf.get('/test_view/') - importlib.import_module('abc.def.invalid.name') + request = self.rf.get("/test_view/") + importlib.import_module("abc.def.invalid.name") except Exception: exc_type, exc_value, tb = sys.exc_info() reporter = ExceptionReporter(request, exc_type, exc_value, tb) html = reporter.get_traceback_html() - self.assertInHTML('<h1>ModuleNotFoundError at /test_view/</h1>', html) + self.assertInHTML("<h1>ModuleNotFoundError at /test_view/</h1>", html) def test_ignore_traceback_evaluation_exceptions(self): """ Don't trip over exceptions generated by crafted objects when evaluating them while cleansing (#24455). """ + class BrokenEvaluation(Exception): pass def broken_setup(): raise BrokenEvaluation - request = self.rf.get('/test_view/') + request = self.rf.get("/test_view/") broken_lazy = SimpleLazyObject(broken_setup) try: bool(broken_lazy) @@ -916,13 +995,13 @@ class ExceptionReporterTests(SimpleTestCase): self.assertIn( "BrokenEvaluation", ExceptionReporter(request, exc_type, exc_value, tb).get_traceback_html(), - "Evaluation exception reason not mentioned in traceback" + "Evaluation exception reason not mentioned in traceback", ) - @override_settings(ALLOWED_HOSTS='example.com') + @override_settings(ALLOWED_HOSTS="example.com") def test_disallowed_host(self): "An exception report can be generated even for a disallowed host." - request = self.rf.get('/', HTTP_HOST='evil.com') + request = self.rf.get("/", HTTP_HOST="evil.com") reporter = ExceptionReporter(request, None, None, None) html = reporter.get_traceback_html() self.assertIn("http://evil.com/", html) @@ -934,59 +1013,62 @@ class ExceptionReporterTests(SimpleTestCase): """ value = '<td>items</td><td class="code"><pre>'Oops'</pre></td>' # GET - request = self.rf.get('/test_view/?items=Oops') + request = self.rf.get("/test_view/?items=Oops") reporter = ExceptionReporter(request, None, None, None) html = reporter.get_traceback_html() self.assertInHTML(value, html) # POST - request = self.rf.post('/test_view/', data={'items': 'Oops'}) + request = self.rf.post("/test_view/", data={"items": "Oops"}) reporter = ExceptionReporter(request, None, None, None) html = reporter.get_traceback_html() self.assertInHTML(value, html) # FILES - fp = StringIO('filecontent') - request = self.rf.post('/test_view/', data={'name': 'filename', 'items': fp}) + fp = StringIO("filecontent") + request = self.rf.post("/test_view/", data={"name": "filename", "items": fp}) reporter = ExceptionReporter(request, None, None, None) html = reporter.get_traceback_html() self.assertInHTML( '<td>items</td><td class="code"><pre><InMemoryUploadedFile: ' - 'items (application/octet-stream)></pre></td>', - html + "items (application/octet-stream)></pre></td>", + html, ) # COOKIES rf = RequestFactory() - rf.cookies['items'] = 'Oops' - request = rf.get('/test_view/') + rf.cookies["items"] = "Oops" + request = rf.get("/test_view/") reporter = ExceptionReporter(request, None, None, None) html = reporter.get_traceback_html() - self.assertInHTML('<td>items</td><td class="code"><pre>'Oops'</pre></td>', html) + self.assertInHTML( + '<td>items</td><td class="code"><pre>'Oops'</pre></td>', html + ) def test_exception_fetching_user(self): """ The error page can be rendered if the current user can't be retrieved (such as when the database is unavailable). """ + class ExceptionUser: def __str__(self): raise Exception() - request = self.rf.get('/test_view/') + request = self.rf.get("/test_view/") request.user = ExceptionUser() try: - raise ValueError('Oops') + raise ValueError("Oops") except ValueError: exc_type, exc_value, tb = sys.exc_info() reporter = ExceptionReporter(request, exc_type, exc_value, tb) html = reporter.get_traceback_html() - self.assertInHTML('<h1>ValueError at /test_view/</h1>', html) + self.assertInHTML("<h1>ValueError at /test_view/</h1>", html) self.assertIn('<pre class="exception_value">Oops</pre>', html) self.assertIn('<h3 id="user-info">USER</h3>', html) - self.assertIn('<p>[unable to retrieve the current user]</p>', html) + self.assertIn("<p>[unable to retrieve the current user]</p>", html) text = reporter.get_traceback_text() - self.assertIn('USER: [unable to retrieve the current user]', text) + self.assertIn("USER: [unable to retrieve the current user]", text) def test_template_encoding(self): """ @@ -995,20 +1077,20 @@ class ExceptionReporterTests(SimpleTestCase): template engines. """ reporter = ExceptionReporter(None, None, None, None) - with mock.patch.object(DebugPath, 'open') as m: + with mock.patch.object(DebugPath, "open") as m: reporter.get_traceback_html() - m.assert_called_once_with(encoding='utf-8') + m.assert_called_once_with(encoding="utf-8") m.reset_mock() reporter.get_traceback_text() - m.assert_called_once_with(encoding='utf-8') + m.assert_called_once_with(encoding="utf-8") - @override_settings(ALLOWED_HOSTS=['example.com']) + @override_settings(ALLOWED_HOSTS=["example.com"]) def test_get_raw_insecure_uri(self): - factory = RequestFactory(HTTP_HOST='evil.com') + factory = RequestFactory(HTTP_HOST="evil.com") tests = [ - ('////absolute-uri', 'http://evil.com//absolute-uri'), - ('/?foo=bar', 'http://evil.com/?foo=bar'), - ('/path/with:colons', 'http://evil.com/path/with:colons'), + ("////absolute-uri", "http://evil.com//absolute-uri"), + ("/?foo=bar", "http://evil.com/?foo=bar"), + ("/path/with:colons", "http://evil.com/path/with:colons"), ] for url, expected in tests: with self.subTest(url=url): @@ -1023,23 +1105,23 @@ class PlainTextReportTests(SimpleTestCase): def test_request_and_exception(self): "A simple exception report can be generated" try: - request = self.rf.get('/test_view/') + request = self.rf.get("/test_view/") request.user = User() raise ValueError("Can't find my keys") except ValueError: exc_type, exc_value, tb = sys.exc_info() reporter = ExceptionReporter(request, exc_type, exc_value, tb) text = reporter.get_traceback_text() - self.assertIn('ValueError at /test_view/', text) + self.assertIn("ValueError at /test_view/", text) self.assertIn("Can't find my keys", text) - self.assertIn('Request Method:', text) - self.assertIn('Request URL:', text) - self.assertIn('USER: jacob', text) - self.assertIn('Exception Type:', text) - self.assertIn('Exception Value:', text) - self.assertIn('Traceback (most recent call last):', text) - self.assertIn('Request information:', text) - self.assertNotIn('Request data not supplied', text) + self.assertIn("Request Method:", text) + self.assertIn("Request URL:", text) + self.assertIn("USER: jacob", text) + self.assertIn("Exception Type:", text) + self.assertIn("Exception Value:", text) + self.assertIn("Traceback (most recent call last):", text) + self.assertIn("Request information:", text) + self.assertNotIn("Request data not supplied", text) def test_no_request(self): "An exception report can be generated without request" @@ -1049,46 +1131,48 @@ class PlainTextReportTests(SimpleTestCase): exc_type, exc_value, tb = sys.exc_info() reporter = ExceptionReporter(None, exc_type, exc_value, tb) text = reporter.get_traceback_text() - self.assertIn('ValueError', text) + self.assertIn("ValueError", text) self.assertIn("Can't find my keys", text) - self.assertNotIn('Request Method:', text) - self.assertNotIn('Request URL:', text) - self.assertNotIn('USER:', text) - self.assertIn('Exception Type:', text) - self.assertIn('Exception Value:', text) - self.assertIn('Traceback (most recent call last):', text) - self.assertIn('Request data not supplied', text) + self.assertNotIn("Request Method:", text) + self.assertNotIn("Request URL:", text) + self.assertNotIn("USER:", text) + self.assertIn("Exception Type:", text) + self.assertIn("Exception Value:", text) + self.assertIn("Traceback (most recent call last):", text) + self.assertIn("Request data not supplied", text) def test_no_exception(self): "An exception report can be generated for just a request" - request = self.rf.get('/test_view/') + request = self.rf.get("/test_view/") reporter = ExceptionReporter(request, None, None, None) reporter.get_traceback_text() def test_request_and_message(self): "A message can be provided in addition to a request" - request = self.rf.get('/test_view/') + request = self.rf.get("/test_view/") reporter = ExceptionReporter(request, None, "I'm a little teapot", None) reporter.get_traceback_text() @override_settings(DEBUG=True) def test_template_exception(self): - request = self.rf.get('/test_view/') + request = self.rf.get("/test_view/") try: - render(request, 'debug/template_error.html') + render(request, "debug/template_error.html") except Exception: exc_type, exc_value, tb = sys.exc_info() reporter = ExceptionReporter(request, exc_type, exc_value, tb) text = reporter.get_traceback_text() - templ_path = Path(Path(__file__).parents[1], 'templates', 'debug', 'template_error.html') + templ_path = Path( + Path(__file__).parents[1], "templates", "debug", "template_error.html" + ) self.assertIn( - 'Template error:\n' - 'In template %(path)s, error at line 2\n' - ' \'cycle\' tag requires at least two arguments\n' - ' 1 : Template with error:\n' - ' 2 : {%% cycle %%} \n' - ' 3 : ' % {'path': templ_path}, - text + "Template error:\n" + "In template %(path)s, error at line 2\n" + " 'cycle' tag requires at least two arguments\n" + " 1 : Template with error:\n" + " 2 : {%% cycle %%} \n" + " 3 : " % {"path": templ_path}, + text, ) def test_request_with_items_key(self): @@ -1097,25 +1181,25 @@ class PlainTextReportTests(SimpleTestCase): request GET, POST, FILES, or COOKIES QueryDicts. """ # GET - request = self.rf.get('/test_view/?items=Oops') + request = self.rf.get("/test_view/?items=Oops") reporter = ExceptionReporter(request, None, None, None) text = reporter.get_traceback_text() self.assertIn("items = 'Oops'", text) # POST - request = self.rf.post('/test_view/', data={'items': 'Oops'}) + request = self.rf.post("/test_view/", data={"items": "Oops"}) reporter = ExceptionReporter(request, None, None, None) text = reporter.get_traceback_text() self.assertIn("items = 'Oops'", text) # FILES - fp = StringIO('filecontent') - request = self.rf.post('/test_view/', data={'name': 'filename', 'items': fp}) + fp = StringIO("filecontent") + request = self.rf.post("/test_view/", data={"name": "filename", "items": fp}) reporter = ExceptionReporter(request, None, None, None) text = reporter.get_traceback_text() - self.assertIn('items = <InMemoryUploadedFile:', text) + self.assertIn("items = <InMemoryUploadedFile:", text) # COOKIES rf = RequestFactory() - rf.cookies['items'] = 'Oops' - request = rf.get('/test_view/') + rf.cookies["items"] = "Oops" + request = rf.get("/test_view/") reporter = ExceptionReporter(request, None, None, None) text = reporter.get_traceback_text() self.assertIn("items = 'Oops'", text) @@ -1124,10 +1208,10 @@ class PlainTextReportTests(SimpleTestCase): reporter = ExceptionReporter(None, None, "I'm a little teapot", None) reporter.get_traceback_text() - @override_settings(ALLOWED_HOSTS='example.com') + @override_settings(ALLOWED_HOSTS="example.com") def test_disallowed_host(self): "An exception report can be generated even for a disallowed host." - request = self.rf.get('/', HTTP_HOST='evil.com') + request = self.rf.get("/", HTTP_HOST="evil.com") reporter = ExceptionReporter(request, None, None, None) text = reporter.get_traceback_text() self.assertIn("http://evil.com/", text) @@ -1137,69 +1221,72 @@ class ExceptionReportTestMixin: # Mixin used in the ExceptionReporterFilterTests and # AjaxResponseExceptionReporterFilter tests below breakfast_data = { - 'sausage-key': 'sausage-value', - 'baked-beans-key': 'baked-beans-value', - 'hash-brown-key': 'hash-brown-value', - 'bacon-key': 'bacon-value', + "sausage-key": "sausage-value", + "baked-beans-key": "baked-beans-value", + "hash-brown-key": "hash-brown-value", + "bacon-key": "bacon-value", } - def verify_unsafe_response(self, view, check_for_vars=True, - check_for_POST_params=True): + def verify_unsafe_response( + self, view, check_for_vars=True, check_for_POST_params=True + ): """ Asserts that potentially sensitive info are displayed in the response. """ - request = self.rf.post('/some_url/', self.breakfast_data) + request = self.rf.post("/some_url/", self.breakfast_data) response = view(request) if check_for_vars: # All variables are shown. - self.assertContains(response, 'cooked_eggs', status_code=500) - self.assertContains(response, 'scrambled', status_code=500) - self.assertContains(response, 'sauce', status_code=500) - self.assertContains(response, 'worcestershire', status_code=500) + self.assertContains(response, "cooked_eggs", status_code=500) + self.assertContains(response, "scrambled", status_code=500) + self.assertContains(response, "sauce", status_code=500) + self.assertContains(response, "worcestershire", status_code=500) if check_for_POST_params: for k, v in self.breakfast_data.items(): # All POST parameters are shown. self.assertContains(response, k, status_code=500) self.assertContains(response, v, status_code=500) - def verify_safe_response(self, view, check_for_vars=True, - check_for_POST_params=True): + def verify_safe_response( + self, view, check_for_vars=True, check_for_POST_params=True + ): """ Asserts that certain sensitive info are not displayed in the response. """ - request = self.rf.post('/some_url/', self.breakfast_data) + request = self.rf.post("/some_url/", self.breakfast_data) response = view(request) if check_for_vars: # Non-sensitive variable's name and value are shown. - self.assertContains(response, 'cooked_eggs', status_code=500) - self.assertContains(response, 'scrambled', status_code=500) + self.assertContains(response, "cooked_eggs", status_code=500) + self.assertContains(response, "scrambled", status_code=500) # Sensitive variable's name is shown but not its value. - self.assertContains(response, 'sauce', status_code=500) - self.assertNotContains(response, 'worcestershire', status_code=500) + self.assertContains(response, "sauce", status_code=500) + self.assertNotContains(response, "worcestershire", status_code=500) if check_for_POST_params: for k in self.breakfast_data: # All POST parameters' names are shown. self.assertContains(response, k, status_code=500) # Non-sensitive POST parameters' values are shown. - self.assertContains(response, 'baked-beans-value', status_code=500) - self.assertContains(response, 'hash-brown-value', status_code=500) + self.assertContains(response, "baked-beans-value", status_code=500) + self.assertContains(response, "hash-brown-value", status_code=500) # Sensitive POST parameters' values are not shown. - self.assertNotContains(response, 'sausage-value', status_code=500) - self.assertNotContains(response, 'bacon-value', status_code=500) + self.assertNotContains(response, "sausage-value", status_code=500) + self.assertNotContains(response, "bacon-value", status_code=500) - def verify_paranoid_response(self, view, check_for_vars=True, - check_for_POST_params=True): + def verify_paranoid_response( + self, view, check_for_vars=True, check_for_POST_params=True + ): """ Asserts that no variables or POST parameters are displayed in the response. """ - request = self.rf.post('/some_url/', self.breakfast_data) + request = self.rf.post("/some_url/", self.breakfast_data) response = view(request) if check_for_vars: # Show variable names but not their values. - self.assertContains(response, 'cooked_eggs', status_code=500) - self.assertNotContains(response, 'scrambled', status_code=500) - self.assertContains(response, 'sauce', status_code=500) - self.assertNotContains(response, 'worcestershire', status_code=500) + self.assertContains(response, "cooked_eggs", status_code=500) + self.assertNotContains(response, "scrambled", status_code=500) + self.assertContains(response, "sauce", status_code=500) + self.assertNotContains(response, "worcestershire", status_code=500) if check_for_POST_params: for k, v in self.breakfast_data.items(): # All POST parameters' names are shown. @@ -1211,26 +1298,26 @@ class ExceptionReportTestMixin: """ Asserts that potentially sensitive info are displayed in the email report. """ - with self.settings(ADMINS=[('Admin', 'admin@fattie-breakie.com')]): + with self.settings(ADMINS=[("Admin", "admin@fattie-breakie.com")]): mail.outbox = [] # Empty outbox - request = self.rf.post('/some_url/', self.breakfast_data) + request = self.rf.post("/some_url/", self.breakfast_data) view(request) self.assertEqual(len(mail.outbox), 1) email = mail.outbox[0] # Frames vars are never shown in plain text email reports. body_plain = str(email.body) - self.assertNotIn('cooked_eggs', body_plain) - self.assertNotIn('scrambled', body_plain) - self.assertNotIn('sauce', body_plain) - self.assertNotIn('worcestershire', body_plain) + self.assertNotIn("cooked_eggs", body_plain) + self.assertNotIn("scrambled", body_plain) + self.assertNotIn("sauce", body_plain) + self.assertNotIn("worcestershire", body_plain) # Frames vars are shown in html email reports. body_html = str(email.alternatives[0][0]) - self.assertIn('cooked_eggs', body_html) - self.assertIn('scrambled', body_html) - self.assertIn('sauce', body_html) - self.assertIn('worcestershire', body_html) + self.assertIn("cooked_eggs", body_html) + self.assertIn("scrambled", body_html) + self.assertIn("sauce", body_html) + self.assertIn("worcestershire", body_html) if check_for_POST_params: for k, v in self.breakfast_data.items(): @@ -1244,58 +1331,58 @@ class ExceptionReportTestMixin: """ Asserts that certain sensitive info are not displayed in the email report. """ - with self.settings(ADMINS=[('Admin', 'admin@fattie-breakie.com')]): + with self.settings(ADMINS=[("Admin", "admin@fattie-breakie.com")]): mail.outbox = [] # Empty outbox - request = self.rf.post('/some_url/', self.breakfast_data) + request = self.rf.post("/some_url/", self.breakfast_data) view(request) self.assertEqual(len(mail.outbox), 1) email = mail.outbox[0] # Frames vars are never shown in plain text email reports. body_plain = str(email.body) - self.assertNotIn('cooked_eggs', body_plain) - self.assertNotIn('scrambled', body_plain) - self.assertNotIn('sauce', body_plain) - self.assertNotIn('worcestershire', body_plain) + self.assertNotIn("cooked_eggs", body_plain) + self.assertNotIn("scrambled", body_plain) + self.assertNotIn("sauce", body_plain) + self.assertNotIn("worcestershire", body_plain) # Frames vars are shown in html email reports. body_html = str(email.alternatives[0][0]) - self.assertIn('cooked_eggs', body_html) - self.assertIn('scrambled', body_html) - self.assertIn('sauce', body_html) - self.assertNotIn('worcestershire', body_html) + self.assertIn("cooked_eggs", body_html) + self.assertIn("scrambled", body_html) + self.assertIn("sauce", body_html) + self.assertNotIn("worcestershire", body_html) if check_for_POST_params: for k in self.breakfast_data: # All POST parameters' names are shown. self.assertIn(k, body_plain) # Non-sensitive POST parameters' values are shown. - self.assertIn('baked-beans-value', body_plain) - self.assertIn('hash-brown-value', body_plain) - self.assertIn('baked-beans-value', body_html) - self.assertIn('hash-brown-value', body_html) + self.assertIn("baked-beans-value", body_plain) + self.assertIn("hash-brown-value", body_plain) + self.assertIn("baked-beans-value", body_html) + self.assertIn("hash-brown-value", body_html) # Sensitive POST parameters' values are not shown. - self.assertNotIn('sausage-value', body_plain) - self.assertNotIn('bacon-value', body_plain) - self.assertNotIn('sausage-value', body_html) - self.assertNotIn('bacon-value', body_html) + self.assertNotIn("sausage-value", body_plain) + self.assertNotIn("bacon-value", body_plain) + self.assertNotIn("sausage-value", body_html) + self.assertNotIn("bacon-value", body_html) def verify_paranoid_email(self, view): """ Asserts that no variables or POST parameters are displayed in the email report. """ - with self.settings(ADMINS=[('Admin', 'admin@fattie-breakie.com')]): + with self.settings(ADMINS=[("Admin", "admin@fattie-breakie.com")]): mail.outbox = [] # Empty outbox - request = self.rf.post('/some_url/', self.breakfast_data) + request = self.rf.post("/some_url/", self.breakfast_data) view(request) self.assertEqual(len(mail.outbox), 1) email = mail.outbox[0] # Frames vars are never shown in plain text email reports. body = str(email.body) - self.assertNotIn('cooked_eggs', body) - self.assertNotIn('scrambled', body) - self.assertNotIn('sauce', body) - self.assertNotIn('worcestershire', body) + self.assertNotIn("cooked_eggs", body) + self.assertNotIn("scrambled", body) + self.assertNotIn("sauce", body) + self.assertNotIn("worcestershire", body) for k, v in self.breakfast_data.items(): # All POST parameters' names are shown. self.assertIn(k, body) @@ -1303,11 +1390,14 @@ class ExceptionReportTestMixin: self.assertNotIn(v, body) -@override_settings(ROOT_URLCONF='view_tests.urls') -class ExceptionReporterFilterTests(ExceptionReportTestMixin, LoggingCaptureMixin, SimpleTestCase): +@override_settings(ROOT_URLCONF="view_tests.urls") +class ExceptionReporterFilterTests( + ExceptionReportTestMixin, LoggingCaptureMixin, SimpleTestCase +): """ Sensitive information can be filtered out of error reports (#14614). """ + rf = RequestFactory() def test_non_sensitive_request(self): @@ -1380,11 +1470,15 @@ class ExceptionReporterFilterTests(ExceptionReportTestMixin, LoggingCaptureMixin The sensitive_variables decorator works with object methods. """ with self.settings(DEBUG=True): - self.verify_unsafe_response(sensitive_method_view, check_for_POST_params=False) + self.verify_unsafe_response( + sensitive_method_view, check_for_POST_params=False + ) self.verify_unsafe_email(sensitive_method_view, check_for_POST_params=False) with self.settings(DEBUG=False): - self.verify_safe_response(sensitive_method_view, check_for_POST_params=False) + self.verify_safe_response( + sensitive_method_view, check_for_POST_params=False + ) self.verify_safe_email(sensitive_method_view, check_for_POST_params=False) def test_sensitive_function_arguments(self): @@ -1398,8 +1492,12 @@ class ExceptionReporterFilterTests(ExceptionReportTestMixin, LoggingCaptureMixin self.verify_unsafe_email(sensitive_args_function_caller) with self.settings(DEBUG=False): - self.verify_safe_response(sensitive_args_function_caller, check_for_POST_params=False) - self.verify_safe_email(sensitive_args_function_caller, check_for_POST_params=False) + self.verify_safe_response( + sensitive_args_function_caller, check_for_POST_params=False + ) + self.verify_safe_email( + sensitive_args_function_caller, check_for_POST_params=False + ) def test_sensitive_function_keyword_arguments(self): """ @@ -1412,24 +1510,33 @@ class ExceptionReporterFilterTests(ExceptionReportTestMixin, LoggingCaptureMixin self.verify_unsafe_email(sensitive_kwargs_function_caller) with self.settings(DEBUG=False): - self.verify_safe_response(sensitive_kwargs_function_caller, check_for_POST_params=False) - self.verify_safe_email(sensitive_kwargs_function_caller, check_for_POST_params=False) + self.verify_safe_response( + sensitive_kwargs_function_caller, check_for_POST_params=False + ) + self.verify_safe_email( + sensitive_kwargs_function_caller, check_for_POST_params=False + ) def test_callable_settings(self): """ Callable settings should not be evaluated in the debug page (#21345). """ + def callable_setting(): return "This should not be displayed" + with self.settings(DEBUG=True, FOOBAR=callable_setting): - response = self.client.get('/raises500/') - self.assertNotContains(response, "This should not be displayed", status_code=500) + response = self.client.get("/raises500/") + self.assertNotContains( + response, "This should not be displayed", status_code=500 + ) def test_callable_settings_forbidding_to_set_attributes(self): """ Callable settings which forbid to set attributes should not break the debug page (#23070). """ + class CallableSettingWithSlots: __slots__ = [] @@ -1437,8 +1544,10 @@ class ExceptionReporterFilterTests(ExceptionReportTestMixin, LoggingCaptureMixin return "This should not be displayed" with self.settings(DEBUG=True, WITH_SLOTS=CallableSettingWithSlots()): - response = self.client.get('/raises500/') - self.assertNotContains(response, "This should not be displayed", status_code=500) + response = self.client.get("/raises500/") + self.assertNotContains( + response, "This should not be displayed", status_code=500 + ) def test_dict_setting_with_non_str_key(self): """ @@ -1446,8 +1555,8 @@ class ExceptionReporterFilterTests(ExceptionReportTestMixin, LoggingCaptureMixin debug page (#12744). """ with self.settings(DEBUG=True, FOOBAR={42: None}): - response = self.client.get('/raises500/') - self.assertContains(response, 'FOOBAR', status_code=500) + response = self.client.get("/raises500/") + self.assertContains(response, "FOOBAR", status_code=500) def test_sensitive_settings(self): """ @@ -1455,16 +1564,18 @@ class ExceptionReporterFilterTests(ExceptionReportTestMixin, LoggingCaptureMixin (password, secret key, ...). """ sensitive_settings = [ - 'SECRET_KEY', - 'SECRET_KEY_FALLBACKS', - 'PASSWORD', - 'API_KEY', - 'AUTH_TOKEN', + "SECRET_KEY", + "SECRET_KEY_FALLBACKS", + "PASSWORD", + "API_KEY", + "AUTH_TOKEN", ] for setting in sensitive_settings: with self.settings(DEBUG=True, **{setting: "should not be displayed"}): - response = self.client.get('/raises500/') - self.assertNotContains(response, 'should not be displayed', status_code=500) + response = self.client.get("/raises500/") + self.assertNotContains( + response, "should not be displayed", status_code=500 + ) def test_settings_with_sensitive_keys(self): """ @@ -1472,53 +1583,55 @@ class ExceptionReporterFilterTests(ExceptionReportTestMixin, LoggingCaptureMixin dict settings. """ sensitive_settings = [ - 'SECRET_KEY', - 'SECRET_KEY_FALLBACKS', - 'PASSWORD', - 'API_KEY', - 'AUTH_TOKEN', + "SECRET_KEY", + "SECRET_KEY_FALLBACKS", + "PASSWORD", + "API_KEY", + "AUTH_TOKEN", ] for setting in sensitive_settings: FOOBAR = { setting: "should not be displayed", - 'recursive': {setting: "should not be displayed"}, + "recursive": {setting: "should not be displayed"}, } with self.settings(DEBUG=True, FOOBAR=FOOBAR): - response = self.client.get('/raises500/') - self.assertNotContains(response, 'should not be displayed', status_code=500) + response = self.client.get("/raises500/") + self.assertNotContains( + response, "should not be displayed", status_code=500 + ) def test_cleanse_setting_basic(self): reporter_filter = SafeExceptionReporterFilter() - self.assertEqual(reporter_filter.cleanse_setting('TEST', 'TEST'), 'TEST') + self.assertEqual(reporter_filter.cleanse_setting("TEST", "TEST"), "TEST") self.assertEqual( - reporter_filter.cleanse_setting('PASSWORD', 'super_secret'), + reporter_filter.cleanse_setting("PASSWORD", "super_secret"), reporter_filter.cleansed_substitute, ) def test_cleanse_setting_ignore_case(self): reporter_filter = SafeExceptionReporterFilter() self.assertEqual( - reporter_filter.cleanse_setting('password', 'super_secret'), + reporter_filter.cleanse_setting("password", "super_secret"), reporter_filter.cleansed_substitute, ) def test_cleanse_setting_recurses_in_dictionary(self): reporter_filter = SafeExceptionReporterFilter() - initial = {'login': 'cooper', 'password': 'secret'} + initial = {"login": "cooper", "password": "secret"} self.assertEqual( - reporter_filter.cleanse_setting('SETTING_NAME', initial), - {'login': 'cooper', 'password': reporter_filter.cleansed_substitute}, + reporter_filter.cleanse_setting("SETTING_NAME", initial), + {"login": "cooper", "password": reporter_filter.cleansed_substitute}, ) def test_cleanse_setting_recurses_in_dictionary_with_non_string_key(self): reporter_filter = SafeExceptionReporterFilter() - initial = {('localhost', 8000): {'login': 'cooper', 'password': 'secret'}} + initial = {("localhost", 8000): {"login": "cooper", "password": "secret"}} self.assertEqual( - reporter_filter.cleanse_setting('SETTING_NAME', initial), + reporter_filter.cleanse_setting("SETTING_NAME", initial), { - ('localhost', 8000): { - 'login': 'cooper', - 'password': reporter_filter.cleansed_substitute, + ("localhost", 8000): { + "login": "cooper", + "password": reporter_filter.cleansed_substitute, }, }, ) @@ -1527,64 +1640,66 @@ class ExceptionReporterFilterTests(ExceptionReportTestMixin, LoggingCaptureMixin reporter_filter = SafeExceptionReporterFilter() initial = [ { - 'login': 'cooper', - 'password': 'secret', - 'apps': ( - {'name': 'app1', 'api_key': 'a06b-c462cffae87a'}, - {'name': 'app2', 'api_key': 'a9f4-f152e97ad808'}, + "login": "cooper", + "password": "secret", + "apps": ( + {"name": "app1", "api_key": "a06b-c462cffae87a"}, + {"name": "app2", "api_key": "a9f4-f152e97ad808"}, ), - 'tokens': ['98b37c57-ec62-4e39', '8690ef7d-8004-4916'], + "tokens": ["98b37c57-ec62-4e39", "8690ef7d-8004-4916"], }, - {'SECRET_KEY': 'c4d77c62-6196-4f17-a06b-c462cffae87a'}, + {"SECRET_KEY": "c4d77c62-6196-4f17-a06b-c462cffae87a"}, ] cleansed = [ { - 'login': 'cooper', - 'password': reporter_filter.cleansed_substitute, - 'apps': ( - {'name': 'app1', 'api_key': reporter_filter.cleansed_substitute}, - {'name': 'app2', 'api_key': reporter_filter.cleansed_substitute}, + "login": "cooper", + "password": reporter_filter.cleansed_substitute, + "apps": ( + {"name": "app1", "api_key": reporter_filter.cleansed_substitute}, + {"name": "app2", "api_key": reporter_filter.cleansed_substitute}, ), - 'tokens': reporter_filter.cleansed_substitute, + "tokens": reporter_filter.cleansed_substitute, }, - {'SECRET_KEY': reporter_filter.cleansed_substitute}, + {"SECRET_KEY": reporter_filter.cleansed_substitute}, ] self.assertEqual( - reporter_filter.cleanse_setting('SETTING_NAME', initial), + reporter_filter.cleanse_setting("SETTING_NAME", initial), cleansed, ) self.assertEqual( - reporter_filter.cleanse_setting('SETTING_NAME', tuple(initial)), + reporter_filter.cleanse_setting("SETTING_NAME", tuple(initial)), tuple(cleansed), ) def test_request_meta_filtering(self): - request = self.rf.get('/', HTTP_SECRET_HEADER='super_secret') + request = self.rf.get("/", HTTP_SECRET_HEADER="super_secret") reporter_filter = SafeExceptionReporterFilter() self.assertEqual( - reporter_filter.get_safe_request_meta(request)['HTTP_SECRET_HEADER'], + reporter_filter.get_safe_request_meta(request)["HTTP_SECRET_HEADER"], reporter_filter.cleansed_substitute, ) def test_exception_report_uses_meta_filtering(self): - response = self.client.get('/raises500/', HTTP_SECRET_HEADER='super_secret') - self.assertNotIn(b'super_secret', response.content) + response = self.client.get("/raises500/", HTTP_SECRET_HEADER="super_secret") + self.assertNotIn(b"super_secret", response.content) response = self.client.get( - '/raises500/', - HTTP_SECRET_HEADER='super_secret', - HTTP_ACCEPT='application/json', + "/raises500/", + HTTP_SECRET_HEADER="super_secret", + HTTP_ACCEPT="application/json", ) - self.assertNotIn(b'super_secret', response.content) + self.assertNotIn(b"super_secret", response.content) class CustomExceptionReporterFilter(SafeExceptionReporterFilter): - cleansed_substitute = 'XXXXXXXXXXXXXXXXXXXX' - hidden_settings = _lazy_re_compile('API|TOKEN|KEY|SECRET|PASS|SIGNATURE|DATABASE_URL', flags=re.I) + cleansed_substitute = "XXXXXXXXXXXXXXXXXXXX" + hidden_settings = _lazy_re_compile( + "API|TOKEN|KEY|SECRET|PASS|SIGNATURE|DATABASE_URL", flags=re.I + ) @override_settings( - ROOT_URLCONF='view_tests.urls', - DEFAULT_EXCEPTION_REPORTER_FILTER='%s.CustomExceptionReporterFilter' % __name__, + ROOT_URLCONF="view_tests.urls", + DEFAULT_EXCEPTION_REPORTER_FILTER="%s.CustomExceptionReporterFilter" % __name__, ) class CustomExceptionReporterFilterTests(SimpleTestCase): def setUp(self): @@ -1602,19 +1717,21 @@ class CustomExceptionReporterFilterTests(SimpleTestCase): def test_cleansed_substitute_override(self): reporter_filter = get_default_exception_reporter_filter() self.assertEqual( - reporter_filter.cleanse_setting('password', 'super_secret'), + reporter_filter.cleanse_setting("password", "super_secret"), reporter_filter.cleansed_substitute, ) def test_hidden_settings_override(self): reporter_filter = get_default_exception_reporter_filter() self.assertEqual( - reporter_filter.cleanse_setting('database_url', 'super_secret'), + reporter_filter.cleanse_setting("database_url", "super_secret"), reporter_filter.cleansed_substitute, ) -class NonHTMLResponseExceptionReporterFilter(ExceptionReportTestMixin, LoggingCaptureMixin, SimpleTestCase): +class NonHTMLResponseExceptionReporterFilter( + ExceptionReportTestMixin, LoggingCaptureMixin, SimpleTestCase +): """ Sensitive information can be filtered out of error reports. @@ -1624,7 +1741,8 @@ class NonHTMLResponseExceptionReporterFilter(ExceptionReportTestMixin, LoggingCa response content because they're not included in these error pages. Refs #14614. """ - rf = RequestFactory(HTTP_ACCEPT='application/json') + + rf = RequestFactory(HTTP_ACCEPT="application/json") def test_non_sensitive_request(self): """ @@ -1665,35 +1783,41 @@ class NonHTMLResponseExceptionReporterFilter(ExceptionReportTestMixin, LoggingCa the request to bypass the one set in DEFAULT_EXCEPTION_REPORTER_FILTER. """ with self.settings(DEBUG=True): - self.verify_unsafe_response(custom_exception_reporter_filter_view, check_for_vars=False) + self.verify_unsafe_response( + custom_exception_reporter_filter_view, check_for_vars=False + ) with self.settings(DEBUG=False): - self.verify_unsafe_response(custom_exception_reporter_filter_view, check_for_vars=False) + self.verify_unsafe_response( + custom_exception_reporter_filter_view, check_for_vars=False + ) - @override_settings(DEBUG=True, ROOT_URLCONF='view_tests.urls') + @override_settings(DEBUG=True, ROOT_URLCONF="view_tests.urls") def test_non_html_response_encoding(self): - response = self.client.get('/raises500/', HTTP_ACCEPT='application/json') - self.assertEqual(response.headers['Content-Type'], 'text/plain; charset=utf-8') + response = self.client.get("/raises500/", HTTP_ACCEPT="application/json") + self.assertEqual(response.headers["Content-Type"], "text/plain; charset=utf-8") class DecoratorsTests(SimpleTestCase): def test_sensitive_variables_not_called(self): msg = ( - 'sensitive_variables() must be called to use it as a decorator, ' - 'e.g., use @sensitive_variables(), not @sensitive_variables.' + "sensitive_variables() must be called to use it as a decorator, " + "e.g., use @sensitive_variables(), not @sensitive_variables." ) with self.assertRaisesMessage(TypeError, msg): + @sensitive_variables def test_func(password): pass def test_sensitive_post_parameters_not_called(self): msg = ( - 'sensitive_post_parameters() must be called to use it as a ' - 'decorator, e.g., use @sensitive_post_parameters(), not ' - '@sensitive_post_parameters.' + "sensitive_post_parameters() must be called to use it as a " + "decorator, e.g., use @sensitive_post_parameters(), not " + "@sensitive_post_parameters." ) with self.assertRaisesMessage(TypeError, msg): + @sensitive_post_parameters def test_func(request): return index_page(request) diff --git a/tests/view_tests/tests/test_defaults.py b/tests/view_tests/tests/test_defaults.py index 94255e517c..0c4fc7c7da 100644 --- a/tests/view_tests/tests/test_defaults.py +++ b/tests/view_tests/tests/test_defaults.py @@ -6,63 +6,82 @@ from django.template import TemplateDoesNotExist from django.test import RequestFactory, TestCase from django.test.utils import override_settings from django.views.defaults import ( - bad_request, page_not_found, permission_denied, server_error, + bad_request, + page_not_found, + permission_denied, + server_error, ) from ..models import Article, Author, UrlArticle -@override_settings(ROOT_URLCONF='view_tests.urls') +@override_settings(ROOT_URLCONF="view_tests.urls") class DefaultsTests(TestCase): """Test django views in django/views/defaults.py""" + nonexistent_urls = [ - '/nonexistent_url/', # this is in urls.py - '/other_nonexistent_url/', # this NOT in urls.py + "/nonexistent_url/", # this is in urls.py + "/other_nonexistent_url/", # this NOT in urls.py ] request_factory = RequestFactory() @classmethod def setUpTestData(cls): - author = Author.objects.create(name='Boris') + author = Author.objects.create(name="Boris") Article.objects.create( - title='Old Article', slug='old_article', author=author, - date_created=datetime.datetime(2001, 1, 1, 21, 22, 23) + title="Old Article", + slug="old_article", + author=author, + date_created=datetime.datetime(2001, 1, 1, 21, 22, 23), ) Article.objects.create( - title='Current Article', slug='current_article', author=author, - date_created=datetime.datetime(2007, 9, 17, 21, 22, 23) + title="Current Article", + slug="current_article", + author=author, + date_created=datetime.datetime(2007, 9, 17, 21, 22, 23), ) Article.objects.create( - title='Future Article', slug='future_article', author=author, - date_created=datetime.datetime(3000, 1, 1, 21, 22, 23) + title="Future Article", + slug="future_article", + author=author, + date_created=datetime.datetime(3000, 1, 1, 21, 22, 23), ) cls.urlarticle = UrlArticle.objects.create( - title='Old Article', slug='old_article', author=author, - date_created=datetime.datetime(2001, 1, 1, 21, 22, 23) + title="Old Article", + slug="old_article", + author=author, + date_created=datetime.datetime(2001, 1, 1, 21, 22, 23), ) - Site(id=1, domain='testserver', name='testserver').save() + Site(id=1, domain="testserver", name="testserver").save() def test_page_not_found(self): "A 404 status is returned by the page_not_found view" for url in self.nonexistent_urls: response = self.client.get(url) self.assertEqual(response.status_code, 404) - self.assertIn(b'<h1>Not Found</h1>', response.content) + self.assertIn(b"<h1>Not Found</h1>", response.content) self.assertIn( - b'<p>The requested resource was not found on this server.</p>', + b"<p>The requested resource was not found on this server.</p>", response.content, ) - @override_settings(TEMPLATES=[{ - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'OPTIONS': { - 'loaders': [ - ('django.template.loaders.locmem.Loader', { - '404.html': '{{ csrf_token }}', - }), - ], - }, - }]) + @override_settings( + TEMPLATES=[ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "OPTIONS": { + "loaders": [ + ( + "django.template.loaders.locmem.Loader", + { + "404.html": "{{ csrf_token }}", + }, + ), + ], + }, + } + ] + ) def test_csrf_token_in_404(self): """ The 404 page should have the csrf_token available in the context @@ -70,81 +89,94 @@ class DefaultsTests(TestCase): # See ticket #14565 for url in self.nonexistent_urls: response = self.client.get(url) - self.assertNotEqual(response.content, b'NOTPROVIDED') - self.assertNotEqual(response.content, b'') + self.assertNotEqual(response.content, b"NOTPROVIDED") + self.assertNotEqual(response.content, b"") def test_server_error(self): "The server_error view raises a 500 status" - response = self.client.get('/server_error/') - self.assertContains(response, b'<h1>Server Error (500)</h1>', status_code=500) + response = self.client.get("/server_error/") + self.assertContains(response, b"<h1>Server Error (500)</h1>", status_code=500) def test_bad_request(self): - request = self.request_factory.get('/') + request = self.request_factory.get("/") response = bad_request(request, Exception()) - self.assertContains(response, b'<h1>Bad Request (400)</h1>', status_code=400) - - @override_settings(TEMPLATES=[{ - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'OPTIONS': { - 'loaders': [ - ('django.template.loaders.locmem.Loader', { - '404.html': 'This is a test template for a 404 error ' - '(path: {{ request_path }}, exception: {{ exception }}).', - '500.html': 'This is a test template for a 500 error.', - }), - ], - }, - }]) + self.assertContains(response, b"<h1>Bad Request (400)</h1>", status_code=400) + + @override_settings( + TEMPLATES=[ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "OPTIONS": { + "loaders": [ + ( + "django.template.loaders.locmem.Loader", + { + "404.html": "This is a test template for a 404 error " + "(path: {{ request_path }}, exception: {{ exception }}).", + "500.html": "This is a test template for a 500 error.", + }, + ), + ], + }, + } + ] + ) def test_custom_templates(self): """ 404.html and 500.html templates are picked by their respective handler. """ - response = self.client.get('/server_error/') + response = self.client.get("/server_error/") self.assertContains(response, "test template for a 500 error", status_code=500) - response = self.client.get('/no_such_url/') - self.assertContains(response, 'path: /no_such_url/', status_code=404) - self.assertContains(response, 'exception: Resolver404', status_code=404) - response = self.client.get('/technical404/') - self.assertContains(response, 'exception: Testing technical 404.', status_code=404) + response = self.client.get("/no_such_url/") + self.assertContains(response, "path: /no_such_url/", status_code=404) + self.assertContains(response, "exception: Resolver404", status_code=404) + response = self.client.get("/technical404/") + self.assertContains( + response, "exception: Testing technical 404.", status_code=404 + ) def test_get_absolute_url_attributes(self): "A model can set attributes on the get_absolute_url method" - self.assertTrue(getattr(UrlArticle.get_absolute_url, 'purge', False), - 'The attributes of the original get_absolute_url must be added.') + self.assertTrue( + getattr(UrlArticle.get_absolute_url, "purge", False), + "The attributes of the original get_absolute_url must be added.", + ) article = UrlArticle.objects.get(pk=self.urlarticle.pk) - self.assertTrue(getattr(article.get_absolute_url, 'purge', False), - 'The attributes of the original get_absolute_url must be added.') + self.assertTrue( + getattr(article.get_absolute_url, "purge", False), + "The attributes of the original get_absolute_url must be added.", + ) def test_custom_templates_wrong(self): """ Default error views should raise TemplateDoesNotExist when passed a template that doesn't exist. """ - request = self.request_factory.get('/') + request = self.request_factory.get("/") with self.assertRaises(TemplateDoesNotExist): - bad_request(request, Exception(), template_name='nonexistent') + bad_request(request, Exception(), template_name="nonexistent") with self.assertRaises(TemplateDoesNotExist): - permission_denied(request, Exception(), template_name='nonexistent') + permission_denied(request, Exception(), template_name="nonexistent") with self.assertRaises(TemplateDoesNotExist): - page_not_found(request, Http404(), template_name='nonexistent') + page_not_found(request, Http404(), template_name="nonexistent") with self.assertRaises(TemplateDoesNotExist): - server_error(request, template_name='nonexistent') + server_error(request, template_name="nonexistent") def test_error_pages(self): - request = self.request_factory.get('/') + request = self.request_factory.get("/") for response, title in ( - (bad_request(request, Exception()), b'Bad Request (400)'), - (permission_denied(request, Exception()), b'403 Forbidden'), - (page_not_found(request, Http404()), b'Not Found'), - (server_error(request), b'Server Error (500)'), + (bad_request(request, Exception()), b"Bad Request (400)"), + (permission_denied(request, Exception()), b"403 Forbidden"), + (page_not_found(request, Http404()), b"Not Found"), + (server_error(request), b"Server Error (500)"), ): with self.subTest(title=title): - self.assertIn(b'<!doctype html>', response.content) + self.assertIn(b"<!doctype html>", response.content) self.assertIn(b'<html lang="en">', response.content) - self.assertIn(b'<head>', response.content) - self.assertIn(b'<title>%s</title>' % title, response.content) - self.assertIn(b'<body>', response.content) + self.assertIn(b"<head>", response.content) + self.assertIn(b"<title>%s</title>" % title, response.content) + self.assertIn(b"<body>", response.content) diff --git a/tests/view_tests/tests/test_i18n.py b/tests/view_tests/tests/test_i18n.py index 26a415ec48..6c8e0f8c91 100644 --- a/tests/view_tests/tests/test_i18n.py +++ b/tests/view_tests/tests/test_i18n.py @@ -4,7 +4,10 @@ from os import path from django.conf import settings from django.test import ( - RequestFactory, SimpleTestCase, TestCase, modify_settings, + RequestFactory, + SimpleTestCase, + TestCase, + modify_settings, override_settings, ) from django.test.selenium import SeleniumTestCase @@ -15,14 +18,16 @@ from django.views.i18n import JavaScriptCatalog, get_formats from ..urls import locale_dir -@override_settings(ROOT_URLCONF='view_tests.urls') +@override_settings(ROOT_URLCONF="view_tests.urls") class SetLanguageTests(TestCase): """Test the django.views.i18n.set_language view.""" def _get_inactive_language_code(self): """Return language code for a language which is not activated.""" current_language = get_language() - return [code for code, name in settings.LANGUAGES if code != current_language][0] + return [code for code, name in settings.LANGUAGES if code != current_language][ + 0 + ] def test_setlang(self): """ @@ -31,18 +36,20 @@ class SetLanguageTests(TestCase): The user is redirected to the 'next' argument if provided. """ lang_code = self._get_inactive_language_code() - post_data = {'language': lang_code, 'next': '/'} - response = self.client.post('/i18n/setlang/', post_data, HTTP_REFERER='/i_should_not_be_used/') - self.assertRedirects(response, '/') + post_data = {"language": lang_code, "next": "/"} + response = self.client.post( + "/i18n/setlang/", post_data, HTTP_REFERER="/i_should_not_be_used/" + ) + self.assertRedirects(response, "/") # The language is set in a cookie. language_cookie = self.client.cookies[settings.LANGUAGE_COOKIE_NAME] self.assertEqual(language_cookie.value, lang_code) - self.assertEqual(language_cookie['domain'], '') - self.assertEqual(language_cookie['path'], '/') - self.assertEqual(language_cookie['max-age'], '') - self.assertEqual(language_cookie['httponly'], '') - self.assertEqual(language_cookie['samesite'], '') - self.assertEqual(language_cookie['secure'], '') + self.assertEqual(language_cookie["domain"], "") + self.assertEqual(language_cookie["path"], "/") + self.assertEqual(language_cookie["max-age"], "") + self.assertEqual(language_cookie["httponly"], "") + self.assertEqual(language_cookie["samesite"], "") + self.assertEqual(language_cookie["secure"], "") def test_setlang_unsafe_next(self): """ @@ -50,10 +57,12 @@ class SetLanguageTests(TestCase): "safe". """ lang_code = self._get_inactive_language_code() - post_data = {'language': lang_code, 'next': '//unsafe/redirection/'} - response = self.client.post('/i18n/setlang/', data=post_data) - self.assertEqual(response.url, '/') - self.assertEqual(self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, lang_code) + post_data = {"language": lang_code, "next": "//unsafe/redirection/"} + response = self.client.post("/i18n/setlang/", data=post_data) + self.assertEqual(response.url, "/") + self.assertEqual( + self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, lang_code + ) def test_setlang_http_next(self): """ @@ -61,16 +70,22 @@ class SetLanguageTests(TestCase): "safe" and its scheme is HTTPS if the request was sent over HTTPS. """ lang_code = self._get_inactive_language_code() - non_https_next_url = 'http://testserver/redirection/' - post_data = {'language': lang_code, 'next': non_https_next_url} + non_https_next_url = "http://testserver/redirection/" + post_data = {"language": lang_code, "next": non_https_next_url} # Insecure URL in POST data. - response = self.client.post('/i18n/setlang/', data=post_data, secure=True) - self.assertEqual(response.url, '/') - self.assertEqual(self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, lang_code) + response = self.client.post("/i18n/setlang/", data=post_data, secure=True) + self.assertEqual(response.url, "/") + self.assertEqual( + self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, lang_code + ) # Insecure URL in HTTP referer. - response = self.client.post('/i18n/setlang/', secure=True, HTTP_REFERER=non_https_next_url) - self.assertEqual(response.url, '/') - self.assertEqual(self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, lang_code) + response = self.client.post( + "/i18n/setlang/", secure=True, HTTP_REFERER=non_https_next_url + ) + self.assertEqual(response.url, "/") + self.assertEqual( + self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, lang_code + ) def test_setlang_redirect_to_referer(self): """ @@ -78,10 +93,12 @@ class SetLanguageTests(TestCase): there isn't a "next" parameter. """ lang_code = self._get_inactive_language_code() - post_data = {'language': lang_code} - response = self.client.post('/i18n/setlang/', post_data, HTTP_REFERER='/i18n/') - self.assertRedirects(response, '/i18n/', fetch_redirect_response=False) - self.assertEqual(self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, lang_code) + post_data = {"language": lang_code} + response = self.client.post("/i18n/setlang/", post_data, HTTP_REFERER="/i18n/") + self.assertRedirects(response, "/i18n/", fetch_redirect_response=False) + self.assertEqual( + self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, lang_code + ) def test_setlang_default_redirect(self): """ @@ -89,10 +106,12 @@ class SetLanguageTests(TestCase): "next" parameter. """ lang_code = self._get_inactive_language_code() - post_data = {'language': lang_code} - response = self.client.post('/i18n/setlang/', post_data) - self.assertRedirects(response, '/') - self.assertEqual(self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, lang_code) + post_data = {"language": lang_code} + response = self.client.post("/i18n/setlang/", post_data) + self.assertRedirects(response, "/") + self.assertEqual( + self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, lang_code + ) def test_setlang_performs_redirect_for_ajax_if_explicitly_requested(self): """ @@ -100,10 +119,14 @@ class SetLanguageTests(TestCase): not accepting HTML response content. """ lang_code = self._get_inactive_language_code() - post_data = {'language': lang_code, 'next': '/'} - response = self.client.post('/i18n/setlang/', post_data, HTTP_ACCEPT='application/json') - self.assertRedirects(response, '/') - self.assertEqual(self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, lang_code) + post_data = {"language": lang_code, "next": "/"} + response = self.client.post( + "/i18n/setlang/", post_data, HTTP_ACCEPT="application/json" + ) + self.assertRedirects(response, "/") + self.assertEqual( + self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, lang_code + ) def test_setlang_doesnt_perform_a_redirect_to_referer_for_ajax(self): """ @@ -111,11 +134,13 @@ class SetLanguageTests(TestCase): the request doesn't accept HTML response content. """ lang_code = self._get_inactive_language_code() - post_data = {'language': lang_code} - headers = {'HTTP_REFERER': '/', 'HTTP_ACCEPT': 'application/json'} - response = self.client.post('/i18n/setlang/', post_data, **headers) + post_data = {"language": lang_code} + headers = {"HTTP_REFERER": "/", "HTTP_ACCEPT": "application/json"} + response = self.client.post("/i18n/setlang/", post_data, **headers) self.assertEqual(response.status_code, 204) - self.assertEqual(self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, lang_code) + self.assertEqual( + self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, lang_code + ) def test_setlang_doesnt_perform_a_default_redirect_for_ajax(self): """ @@ -123,10 +148,14 @@ class SetLanguageTests(TestCase): HTML response content. """ lang_code = self._get_inactive_language_code() - post_data = {'language': lang_code} - response = self.client.post('/i18n/setlang/', post_data, HTTP_ACCEPT='application/json') + post_data = {"language": lang_code} + response = self.client.post( + "/i18n/setlang/", post_data, HTTP_ACCEPT="application/json" + ) self.assertEqual(response.status_code, 204) - self.assertEqual(self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, lang_code) + self.assertEqual( + self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, lang_code + ) def test_setlang_unsafe_next_for_ajax(self): """ @@ -134,38 +163,42 @@ class SetLanguageTests(TestCase): not accepting HTML response content. """ lang_code = self._get_inactive_language_code() - post_data = {'language': lang_code, 'next': '//unsafe/redirection/'} - response = self.client.post('/i18n/setlang/', post_data, HTTP_ACCEPT='application/json') - self.assertEqual(response.url, '/') - self.assertEqual(self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, lang_code) + post_data = {"language": lang_code, "next": "//unsafe/redirection/"} + response = self.client.post( + "/i18n/setlang/", post_data, HTTP_ACCEPT="application/json" + ) + self.assertEqual(response.url, "/") + self.assertEqual( + self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, lang_code + ) def test_setlang_reversal(self): - self.assertEqual(reverse('set_language'), '/i18n/setlang/') + self.assertEqual(reverse("set_language"), "/i18n/setlang/") def test_setlang_cookie(self): # we force saving language to a cookie rather than a session # by excluding session middleware and those which do require it test_settings = { - 'MIDDLEWARE': ['django.middleware.common.CommonMiddleware'], - 'LANGUAGE_COOKIE_NAME': 'mylanguage', - 'LANGUAGE_COOKIE_AGE': 3600 * 7 * 2, - 'LANGUAGE_COOKIE_DOMAIN': '.example.com', - 'LANGUAGE_COOKIE_PATH': '/test/', - 'LANGUAGE_COOKIE_HTTPONLY': True, - 'LANGUAGE_COOKIE_SAMESITE': 'Strict', - 'LANGUAGE_COOKIE_SECURE': True, + "MIDDLEWARE": ["django.middleware.common.CommonMiddleware"], + "LANGUAGE_COOKIE_NAME": "mylanguage", + "LANGUAGE_COOKIE_AGE": 3600 * 7 * 2, + "LANGUAGE_COOKIE_DOMAIN": ".example.com", + "LANGUAGE_COOKIE_PATH": "/test/", + "LANGUAGE_COOKIE_HTTPONLY": True, + "LANGUAGE_COOKIE_SAMESITE": "Strict", + "LANGUAGE_COOKIE_SECURE": True, } with self.settings(**test_settings): - post_data = {'language': 'pl', 'next': '/views/'} - response = self.client.post('/i18n/setlang/', data=post_data) - language_cookie = response.cookies.get('mylanguage') - self.assertEqual(language_cookie.value, 'pl') - self.assertEqual(language_cookie['domain'], '.example.com') - self.assertEqual(language_cookie['path'], '/test/') - self.assertEqual(language_cookie['max-age'], 3600 * 7 * 2) - self.assertIs(language_cookie['httponly'], True) - self.assertEqual(language_cookie['samesite'], 'Strict') - self.assertIs(language_cookie['secure'], True) + post_data = {"language": "pl", "next": "/views/"} + response = self.client.post("/i18n/setlang/", data=post_data) + language_cookie = response.cookies.get("mylanguage") + self.assertEqual(language_cookie.value, "pl") + self.assertEqual(language_cookie["domain"], ".example.com") + self.assertEqual(language_cookie["path"], "/test/") + self.assertEqual(language_cookie["max-age"], 3600 * 7 * 2) + self.assertIs(language_cookie["httponly"], True) + self.assertEqual(language_cookie["samesite"], "Strict") + self.assertIs(language_cookie["secure"], True) def test_setlang_decodes_http_referer_url(self): """ @@ -173,81 +206,104 @@ class SetLanguageTests(TestCase): encoded query string. """ # The URL & view must exist for this to work as a regression test. - self.assertEqual(reverse('with_parameter', kwargs={'parameter': 'x'}), '/test-setlang/x/') + self.assertEqual( + reverse("with_parameter", kwargs={"parameter": "x"}), "/test-setlang/x/" + ) lang_code = self._get_inactive_language_code() # %C3%A4 decodes to ä, %26 to &. - encoded_url = '/test-setlang/%C3%A4/?foo=bar&baz=alpha%26omega' - response = self.client.post('/i18n/setlang/', {'language': lang_code}, HTTP_REFERER=encoded_url) + encoded_url = "/test-setlang/%C3%A4/?foo=bar&baz=alpha%26omega" + response = self.client.post( + "/i18n/setlang/", {"language": lang_code}, HTTP_REFERER=encoded_url + ) self.assertRedirects(response, encoded_url, fetch_redirect_response=False) - self.assertEqual(self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, lang_code) + self.assertEqual( + self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, lang_code + ) - @modify_settings(MIDDLEWARE={ - 'append': 'django.middleware.locale.LocaleMiddleware', - }) + @modify_settings( + MIDDLEWARE={ + "append": "django.middleware.locale.LocaleMiddleware", + } + ) def test_lang_from_translated_i18n_pattern(self): response = self.client.post( - '/i18n/setlang/', data={'language': 'nl'}, - follow=True, HTTP_REFERER='/en/translated/' + "/i18n/setlang/", + data={"language": "nl"}, + follow=True, + HTTP_REFERER="/en/translated/", ) - self.assertEqual(self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, 'nl') - self.assertRedirects(response, '/nl/vertaald/') + self.assertEqual(self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, "nl") + self.assertRedirects(response, "/nl/vertaald/") # And reverse response = self.client.post( - '/i18n/setlang/', data={'language': 'en'}, - follow=True, HTTP_REFERER='/nl/vertaald/' + "/i18n/setlang/", + data={"language": "en"}, + follow=True, + HTTP_REFERER="/nl/vertaald/", ) - self.assertRedirects(response, '/en/translated/') + self.assertRedirects(response, "/en/translated/") -@override_settings(ROOT_URLCONF='view_tests.urls') +@override_settings(ROOT_URLCONF="view_tests.urls") class I18NViewTests(SimpleTestCase): """Test django.views.i18n views other than set_language.""" - @override_settings(LANGUAGE_CODE='de') + + @override_settings(LANGUAGE_CODE="de") def test_get_formats(self): formats = get_formats() # Test 3 possible types in get_formats: integer, string, and list. - self.assertEqual(formats['FIRST_DAY_OF_WEEK'], 1) - self.assertEqual(formats['DECIMAL_SEPARATOR'], ',') - self.assertEqual(formats['TIME_INPUT_FORMATS'], ['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']) + self.assertEqual(formats["FIRST_DAY_OF_WEEK"], 1) + self.assertEqual(formats["DECIMAL_SEPARATOR"], ",") + self.assertEqual( + formats["TIME_INPUT_FORMATS"], ["%H:%M:%S", "%H:%M:%S.%f", "%H:%M"] + ) def test_jsi18n(self): """The javascript_catalog can be deployed with language settings""" - for lang_code in ['es', 'fr', 'ru']: + for lang_code in ["es", "fr", "ru"]: with override(lang_code): - catalog = gettext.translation('djangojs', locale_dir, [lang_code]) - trans_txt = catalog.gettext('this is to be translated') - response = self.client.get('/jsi18n/') - self.assertEqual(response.headers['Content-Type'], 'text/javascript; charset="utf-8"') + catalog = gettext.translation("djangojs", locale_dir, [lang_code]) + trans_txt = catalog.gettext("this is to be translated") + response = self.client.get("/jsi18n/") + self.assertEqual( + response.headers["Content-Type"], 'text/javascript; charset="utf-8"' + ) # response content must include a line like: # "this is to be translated": <value of trans_txt Python variable> # json.dumps() is used to be able to check Unicode strings. self.assertContains(response, json.dumps(trans_txt), 1) - if lang_code == 'fr': + if lang_code == "fr": # Message with context (msgctxt) self.assertContains(response, '"month name\\u0004May": "mai"', 1) @override_settings(USE_I18N=False) def test_jsi18n_USE_I18N_False(self): - response = self.client.get('/jsi18n/') + response = self.client.get("/jsi18n/") # default plural function - self.assertContains(response, 'django.pluralidx = function(count) { return (count == 1) ? 0 : 1; };') - self.assertNotContains(response, 'var newcatalog =') + self.assertContains( + response, + "django.pluralidx = function(count) { return (count == 1) ? 0 : 1; };", + ) + self.assertNotContains(response, "var newcatalog =") def test_jsoni18n(self): """ The json_catalog returns the language catalog and settings as JSON. """ - with override('de'): - response = self.client.get('/jsoni18n/') + with override("de"): + response = self.client.get("/jsoni18n/") data = json.loads(response.content.decode()) - self.assertIn('catalog', data) - self.assertIn('formats', data) - self.assertEqual(data['formats']['TIME_INPUT_FORMATS'], ['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']) - self.assertEqual(data['formats']['FIRST_DAY_OF_WEEK'], 1) - self.assertIn('plural', data) - self.assertEqual(data['catalog']['month name\x04May'], 'Mai') - self.assertIn('DATETIME_FORMAT', data['formats']) - self.assertEqual(data['plural'], '(n != 1)') + self.assertIn("catalog", data) + self.assertIn("formats", data) + self.assertEqual( + data["formats"]["TIME_INPUT_FORMATS"], + ["%H:%M:%S", "%H:%M:%S.%f", "%H:%M"], + ) + self.assertEqual(data["formats"]["FIRST_DAY_OF_WEEK"], 1) + self.assertIn("plural", data) + self.assertEqual(data["catalog"]["month name\x04May"], "Mai") + self.assertIn("DATETIME_FORMAT", data["formats"]) + self.assertEqual(data["plural"], "(n != 1)") def test_jsi18n_with_missing_en_files(self): """ @@ -259,33 +315,33 @@ class I18NViewTests(SimpleTestCase): languages and you've set settings.LANGUAGE_CODE to some other language than English. """ - with self.settings(LANGUAGE_CODE='es'), override('en-us'): - response = self.client.get('/jsi18n/') - self.assertNotContains(response, 'esto tiene que ser traducido') + with self.settings(LANGUAGE_CODE="es"), override("en-us"): + response = self.client.get("/jsi18n/") + self.assertNotContains(response, "esto tiene que ser traducido") def test_jsoni18n_with_missing_en_files(self): """ Same as above for the json_catalog view. Here we also check for the expected JSON format. """ - with self.settings(LANGUAGE_CODE='es'), override('en-us'): - response = self.client.get('/jsoni18n/') + with self.settings(LANGUAGE_CODE="es"), override("en-us"): + response = self.client.get("/jsoni18n/") data = json.loads(response.content.decode()) - self.assertIn('catalog', data) - self.assertIn('formats', data) - self.assertIn('plural', data) - self.assertEqual(data['catalog'], {}) - self.assertIn('DATETIME_FORMAT', data['formats']) - self.assertIsNone(data['plural']) + self.assertIn("catalog", data) + self.assertIn("formats", data) + self.assertIn("plural", data) + self.assertEqual(data["catalog"], {}) + self.assertIn("DATETIME_FORMAT", data["formats"]) + self.assertIsNone(data["plural"]) def test_jsi18n_fallback_language(self): """ Let's make sure that the fallback language is still working properly in cases where the selected language cannot be found. """ - with self.settings(LANGUAGE_CODE='fr'), override('fi'): - response = self.client.get('/jsi18n/') - self.assertContains(response, 'il faut le traduire') + with self.settings(LANGUAGE_CODE="fr"), override("fi"): + response = self.client.get("/jsi18n/") + self.assertContains(response, "il faut le traduire") self.assertNotContains(response, "Untranslated string") def test_i18n_fallback_language_plural(self): @@ -293,33 +349,33 @@ class I18NViewTests(SimpleTestCase): The fallback to a language with less plural forms maintains the real language's number of plural forms and correct translations. """ - with self.settings(LANGUAGE_CODE='pt'), override('ru'): - response = self.client.get('/jsi18n/') + with self.settings(LANGUAGE_CODE="pt"), override("ru"): + response = self.client.get("/jsi18n/") self.assertEqual( - response.context['catalog']['{count} plural3'], - ['{count} plural3 p3', '{count} plural3 p3s', '{count} plural3 p3t'] + response.context["catalog"]["{count} plural3"], + ["{count} plural3 p3", "{count} plural3 p3s", "{count} plural3 p3t"], ) self.assertEqual( - response.context['catalog']['{count} plural2'], - ['{count} plural2', '{count} plural2s', ''] + response.context["catalog"]["{count} plural2"], + ["{count} plural2", "{count} plural2s", ""], ) - with self.settings(LANGUAGE_CODE='ru'), override('pt'): - response = self.client.get('/jsi18n/') + with self.settings(LANGUAGE_CODE="ru"), override("pt"): + response = self.client.get("/jsi18n/") self.assertEqual( - response.context['catalog']['{count} plural3'], - ['{count} plural3', '{count} plural3s'] + response.context["catalog"]["{count} plural3"], + ["{count} plural3", "{count} plural3s"], ) self.assertEqual( - response.context['catalog']['{count} plural2'], - ['{count} plural2', '{count} plural2s'] + response.context["catalog"]["{count} plural2"], + ["{count} plural2", "{count} plural2s"], ) def test_i18n_english_variant(self): - with override('en-gb'): - response = self.client.get('/jsi18n/') + with override("en-gb"): + response = self.client.get("/jsi18n/") self.assertIn( '"this color is to be translated": "this colour is to be translated"', - response.context['catalog_str'] + response.context["catalog_str"], ) def test_i18n_language_non_english_default(self): @@ -329,46 +385,46 @@ class I18NViewTests(SimpleTestCase): is English and there is not 'en' translation available. See #13388, #3594 and #13726 for more details. """ - with self.settings(LANGUAGE_CODE='fr'), override('en-us'): - response = self.client.get('/jsi18n/') - self.assertNotContains(response, 'Choisir une heure') + with self.settings(LANGUAGE_CODE="fr"), override("en-us"): + response = self.client.get("/jsi18n/") + self.assertNotContains(response, "Choisir une heure") - @modify_settings(INSTALLED_APPS={'append': 'view_tests.app0'}) + @modify_settings(INSTALLED_APPS={"append": "view_tests.app0"}) def test_non_english_default_english_userpref(self): """ Same as above with the difference that there IS an 'en' translation available. The JavaScript i18n view must return a NON empty language catalog with the proper English translations. See #13726 for more details. """ - with self.settings(LANGUAGE_CODE='fr'), override('en-us'): - response = self.client.get('/jsi18n_english_translation/') - self.assertContains(response, 'this app0 string is to be translated') + with self.settings(LANGUAGE_CODE="fr"), override("en-us"): + response = self.client.get("/jsi18n_english_translation/") + self.assertContains(response, "this app0 string is to be translated") def test_i18n_language_non_english_fallback(self): """ Makes sure that the fallback language is still working properly in cases where the selected language cannot be found. """ - with self.settings(LANGUAGE_CODE='fr'), override('none'): - response = self.client.get('/jsi18n/') - self.assertContains(response, 'Choisir une heure') + with self.settings(LANGUAGE_CODE="fr"), override("none"): + response = self.client.get("/jsi18n/") + self.assertContains(response, "Choisir une heure") def test_escaping(self): # Force a language via GET otherwise the gettext functions are a noop! - response = self.client.get('/jsi18n_admin/?language=de') - self.assertContains(response, '\\x04') + response = self.client.get("/jsi18n_admin/?language=de") + self.assertContains(response, "\\x04") - @modify_settings(INSTALLED_APPS={'append': ['view_tests.app5']}) + @modify_settings(INSTALLED_APPS={"append": ["view_tests.app5"]}) def test_non_BMP_char(self): """ Non-BMP characters should not break the javascript_catalog (#21725). """ - with self.settings(LANGUAGE_CODE='en-us'), override('fr'): - response = self.client.get('/jsi18n/app5/') - self.assertContains(response, 'emoji') - self.assertContains(response, '\\ud83d\\udca9') + with self.settings(LANGUAGE_CODE="en-us"), override("fr"): + response = self.client.get("/jsi18n/app5/") + self.assertContains(response, "emoji") + self.assertContains(response, "\\ud83d\\udca9") - @modify_settings(INSTALLED_APPS={'append': ['view_tests.app1', 'view_tests.app2']}) + @modify_settings(INSTALLED_APPS={"append": ["view_tests.app1", "view_tests.app2"]}) def test_i18n_language_english_default(self): """ Check if the JavaScript i18n view returns a complete language catalog @@ -377,69 +433,74 @@ class I18NViewTests(SimpleTestCase): translations of multiple Python packages is requested. See #13388, #3594 and #13514 for more details. """ - base_trans_string = 'il faut traduire cette cha\\u00eene de caract\\u00e8res de ' - app1_trans_string = base_trans_string + 'app1' - app2_trans_string = base_trans_string + 'app2' - with self.settings(LANGUAGE_CODE='en-us'), override('fr'): - response = self.client.get('/jsi18n_multi_packages1/') + base_trans_string = ( + "il faut traduire cette cha\\u00eene de caract\\u00e8res de " + ) + app1_trans_string = base_trans_string + "app1" + app2_trans_string = base_trans_string + "app2" + with self.settings(LANGUAGE_CODE="en-us"), override("fr"): + response = self.client.get("/jsi18n_multi_packages1/") self.assertContains(response, app1_trans_string) self.assertContains(response, app2_trans_string) - response = self.client.get('/jsi18n/app1/') + response = self.client.get("/jsi18n/app1/") self.assertContains(response, app1_trans_string) self.assertNotContains(response, app2_trans_string) - response = self.client.get('/jsi18n/app2/') + response = self.client.get("/jsi18n/app2/") self.assertNotContains(response, app1_trans_string) self.assertContains(response, app2_trans_string) - @modify_settings(INSTALLED_APPS={'append': ['view_tests.app3', 'view_tests.app4']}) + @modify_settings(INSTALLED_APPS={"append": ["view_tests.app3", "view_tests.app4"]}) def test_i18n_different_non_english_languages(self): """ Similar to above but with neither default or requested language being English. """ - with self.settings(LANGUAGE_CODE='fr'), override('es-ar'): - response = self.client.get('/jsi18n_multi_packages2/') - self.assertContains(response, 'este texto de app3 debe ser traducido') + with self.settings(LANGUAGE_CODE="fr"), override("es-ar"): + response = self.client.get("/jsi18n_multi_packages2/") + self.assertContains(response, "este texto de app3 debe ser traducido") def test_i18n_with_locale_paths(self): extended_locale_paths = settings.LOCALE_PATHS + [ path.join( path.dirname(path.dirname(path.abspath(__file__))), - 'app3', - 'locale', + "app3", + "locale", ), ] - with self.settings(LANGUAGE_CODE='es-ar', LOCALE_PATHS=extended_locale_paths): - with override('es-ar'): - response = self.client.get('/jsi18n/') - self.assertContains(response, 'este texto de app3 debe ser traducido') + with self.settings(LANGUAGE_CODE="es-ar", LOCALE_PATHS=extended_locale_paths): + with override("es-ar"): + response = self.client.get("/jsi18n/") + self.assertContains(response, "este texto de app3 debe ser traducido") def test_i18n_unknown_package_error(self): view = JavaScriptCatalog.as_view() - request = RequestFactory().get('/') - msg = 'Invalid package(s) provided to JavaScriptCatalog: unknown_package' + request = RequestFactory().get("/") + msg = "Invalid package(s) provided to JavaScriptCatalog: unknown_package" with self.assertRaisesMessage(ValueError, msg): - view(request, packages='unknown_package') - msg += ',unknown_package2' + view(request, packages="unknown_package") + msg += ",unknown_package2" with self.assertRaisesMessage(ValueError, msg): - view(request, packages='unknown_package+unknown_package2') + view(request, packages="unknown_package+unknown_package2") -@override_settings(ROOT_URLCONF='view_tests.urls') +@override_settings(ROOT_URLCONF="view_tests.urls") class I18nSeleniumTests(SeleniumTestCase): # The test cases use fixtures & translations from these apps. available_apps = [ - 'django.contrib.admin', 'django.contrib.auth', - 'django.contrib.contenttypes', 'view_tests', + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "view_tests", ] - @override_settings(LANGUAGE_CODE='de') + @override_settings(LANGUAGE_CODE="de") def test_javascript_gettext(self): from selenium.webdriver.common.by import By - self.selenium.get(self.live_server_url + '/jsi18n_template/') + + self.selenium.get(self.live_server_url + "/jsi18n_template/") elem = self.selenium.find_element(By.ID, "gettext") self.assertEqual(elem.text, "Entfernen") elem = self.selenium.find_element(By.ID, "ngettext_sing") @@ -457,15 +518,20 @@ class I18nSeleniumTests(SeleniumTestCase): elem = self.selenium.find_element(By.ID, "formats") self.assertEqual( elem.text, - "DATE_INPUT_FORMATS is an object; DECIMAL_SEPARATOR is a string; FIRST_DAY_OF_WEEK is a number;" + "DATE_INPUT_FORMATS is an object; DECIMAL_SEPARATOR is a string; FIRST_DAY_OF_WEEK is a number;", ) - @modify_settings(INSTALLED_APPS={'append': ['view_tests.app1', 'view_tests.app2']}) - @override_settings(LANGUAGE_CODE='fr') + @modify_settings(INSTALLED_APPS={"append": ["view_tests.app1", "view_tests.app2"]}) + @override_settings(LANGUAGE_CODE="fr") def test_multiple_catalogs(self): from selenium.webdriver.common.by import By - self.selenium.get(self.live_server_url + '/jsi18n_multi_catalogs/') - elem = self.selenium.find_element(By.ID, 'app1string') - self.assertEqual(elem.text, 'il faut traduire cette chaîne de caractères de app1') - elem = self.selenium.find_element(By.ID, 'app2string') - self.assertEqual(elem.text, 'il faut traduire cette chaîne de caractères de app2') + + self.selenium.get(self.live_server_url + "/jsi18n_multi_catalogs/") + elem = self.selenium.find_element(By.ID, "app1string") + self.assertEqual( + elem.text, "il faut traduire cette chaîne de caractères de app1" + ) + elem = self.selenium.find_element(By.ID, "app2string") + self.assertEqual( + elem.text, "il faut traduire cette chaîne de caractères de app2" + ) diff --git a/tests/view_tests/tests/test_json.py b/tests/view_tests/tests/test_json.py index e1074bf630..145e6e05a4 100644 --- a/tests/view_tests/tests/test_json.py +++ b/tests/view_tests/tests/test_json.py @@ -3,17 +3,18 @@ import json from django.test import SimpleTestCase, override_settings -@override_settings(ROOT_URLCONF='view_tests.generic_urls') +@override_settings(ROOT_URLCONF="view_tests.generic_urls") class JsonResponseTests(SimpleTestCase): - def test_json_response(self): - response = self.client.get('/json/response/') + response = self.client.get("/json/response/") self.assertEqual(response.status_code, 200) + self.assertEqual(response.headers["content-type"], "application/json") self.assertEqual( - response.headers['content-type'], 'application/json') - self.assertEqual(json.loads(response.content.decode()), { - 'a': [1, 2, 3], - 'foo': {'bar': 'baz'}, - 'timestamp': '2013-05-19T20:00:00', - 'value': '3.14', - }) + json.loads(response.content.decode()), + { + "a": [1, 2, 3], + "foo": {"bar": "baz"}, + "timestamp": "2013-05-19T20:00:00", + "value": "3.14", + }, + ) diff --git a/tests/view_tests/tests/test_specials.py b/tests/view_tests/tests/test_specials.py index 70ffb1d23e..d1bedf45b9 100644 --- a/tests/view_tests/tests/test_specials.py +++ b/tests/view_tests/tests/test_specials.py @@ -1,23 +1,24 @@ from django.test import SimpleTestCase, override_settings -@override_settings(ROOT_URLCONF='view_tests.generic_urls') +@override_settings(ROOT_URLCONF="view_tests.generic_urls") class URLHandling(SimpleTestCase): """ Tests for URL handling in views and responses. """ + redirect_target = "/%E4%B8%AD%E6%96%87/target/" def test_nonascii_redirect(self): """ A non-ASCII argument to HttpRedirect is handled properly. """ - response = self.client.get('/nonascii_redirect/') + response = self.client.get("/nonascii_redirect/") self.assertRedirects(response, self.redirect_target) def test_permanent_nonascii_redirect(self): """ A non-ASCII argument to HttpPermanentRedirect is handled properly. """ - response = self.client.get('/permanent_nonascii_redirect/') + response = self.client.get("/permanent_nonascii_redirect/") self.assertRedirects(response, self.redirect_target, status_code=301) diff --git a/tests/view_tests/tests/test_static.py b/tests/view_tests/tests/test_static.py index a5e811e5d6..5ec054bf30 100644 --- a/tests/view_tests/tests/test_static.py +++ b/tests/view_tests/tests/test_static.py @@ -14,27 +14,32 @@ from .. import urls from ..urls import media_dir -@override_settings(DEBUG=True, ROOT_URLCONF='view_tests.urls') +@override_settings(DEBUG=True, ROOT_URLCONF="view_tests.urls") class StaticTests(SimpleTestCase): """Tests django views in django/views/static.py""" - prefix = 'site_media' + prefix = "site_media" def test_serve(self): "The static view can serve static media" - media_files = ['file.txt', 'file.txt.gz', '%2F.txt'] + media_files = ["file.txt", "file.txt.gz", "%2F.txt"] for filename in media_files: - response = self.client.get('/%s/%s' % (self.prefix, quote(filename))) - response_content = b''.join(response) + response = self.client.get("/%s/%s" % (self.prefix, quote(filename))) + response_content = b"".join(response) file_path = path.join(media_dir, filename) - with open(file_path, 'rb') as fp: + with open(file_path, "rb") as fp: self.assertEqual(fp.read(), response_content) - self.assertEqual(len(response_content), int(response.headers['Content-Length'])) - self.assertEqual(mimetypes.guess_type(file_path)[1], response.get('Content-Encoding', None)) + self.assertEqual( + len(response_content), int(response.headers["Content-Length"]) + ) + self.assertEqual( + mimetypes.guess_type(file_path)[1], + response.get("Content-Encoding", None), + ) def test_chunked(self): "The static view should stream files in chunks to avoid large memory usage" - response = self.client.get('/%s/%s' % (self.prefix, 'long-line.txt')) + response = self.client.get("/%s/%s" % (self.prefix, "long-line.txt")) first_chunk = next(response.streaming_content) self.assertEqual(len(first_chunk), FileResponse.block_size) second_chunk = next(response.streaming_content) @@ -43,32 +48,32 @@ class StaticTests(SimpleTestCase): self.assertEqual(len(second_chunk.strip()), 1449) def test_unknown_mime_type(self): - response = self.client.get('/%s/file.unknown' % self.prefix) - self.assertEqual('application/octet-stream', response.headers['Content-Type']) + response = self.client.get("/%s/file.unknown" % self.prefix) + self.assertEqual("application/octet-stream", response.headers["Content-Type"]) response.close() def test_copes_with_empty_path_component(self): - file_name = 'file.txt' - response = self.client.get('/%s//%s' % (self.prefix, file_name)) - response_content = b''.join(response) - with open(path.join(media_dir, file_name), 'rb') as fp: + file_name = "file.txt" + response = self.client.get("/%s//%s" % (self.prefix, file_name)) + response_content = b"".join(response) + with open(path.join(media_dir, file_name), "rb") as fp: self.assertEqual(fp.read(), response_content) def test_is_modified_since(self): - file_name = 'file.txt' + file_name = "file.txt" response = self.client.get( - '/%s/%s' % (self.prefix, file_name), - HTTP_IF_MODIFIED_SINCE='Thu, 1 Jan 1970 00:00:00 GMT' + "/%s/%s" % (self.prefix, file_name), + HTTP_IF_MODIFIED_SINCE="Thu, 1 Jan 1970 00:00:00 GMT", ) - response_content = b''.join(response) - with open(path.join(media_dir, file_name), 'rb') as fp: + response_content = b"".join(response) + with open(path.join(media_dir, file_name), "rb") as fp: self.assertEqual(fp.read(), response_content) def test_not_modified_since(self): - file_name = 'file.txt' + file_name = "file.txt" response = self.client.get( - '/%s/%s' % (self.prefix, file_name), - HTTP_IF_MODIFIED_SINCE='Mon, 18 Jan 2038 05:14:07 GMT' + "/%s/%s" % (self.prefix, file_name), + HTTP_IF_MODIFIED_SINCE="Mon, 18 Jan 2038 05:14:07 GMT" # This is 24h before max Unix time. Remember to fix Django and # update this test well before 2038 :) ) @@ -80,14 +85,15 @@ class StaticTests(SimpleTestCase): Assume that a file is modified since an invalid timestamp as per RFC 2616, section 14.25. """ - file_name = 'file.txt' - invalid_date = 'Mon, 28 May 999999999999 28:25:26 GMT' - response = self.client.get('/%s/%s' % (self.prefix, file_name), - HTTP_IF_MODIFIED_SINCE=invalid_date) - response_content = b''.join(response) - with open(path.join(media_dir, file_name), 'rb') as fp: + file_name = "file.txt" + invalid_date = "Mon, 28 May 999999999999 28:25:26 GMT" + response = self.client.get( + "/%s/%s" % (self.prefix, file_name), HTTP_IF_MODIFIED_SINCE=invalid_date + ) + response_content = b"".join(response) + with open(path.join(media_dir, file_name), "rb") as fp: self.assertEqual(fp.read(), response_content) - self.assertEqual(len(response_content), int(response.headers['Content-Length'])) + self.assertEqual(len(response_content), int(response.headers["Content-Length"])) def test_invalid_if_modified_since2(self): """Handle even more bogus If-Modified-Since values gracefully @@ -95,75 +101,86 @@ class StaticTests(SimpleTestCase): Assume that a file is modified since an invalid timestamp as per RFC 2616, section 14.25. """ - file_name = 'file.txt' - invalid_date = ': 1291108438, Wed, 20 Oct 2010 14:05:00 GMT' - response = self.client.get('/%s/%s' % (self.prefix, file_name), - HTTP_IF_MODIFIED_SINCE=invalid_date) - response_content = b''.join(response) - with open(path.join(media_dir, file_name), 'rb') as fp: + file_name = "file.txt" + invalid_date = ": 1291108438, Wed, 20 Oct 2010 14:05:00 GMT" + response = self.client.get( + "/%s/%s" % (self.prefix, file_name), HTTP_IF_MODIFIED_SINCE=invalid_date + ) + response_content = b"".join(response) + with open(path.join(media_dir, file_name), "rb") as fp: self.assertEqual(fp.read(), response_content) - self.assertEqual(len(response_content), int(response.headers['Content-Length'])) + self.assertEqual(len(response_content), int(response.headers["Content-Length"])) def test_404(self): - response = self.client.get('/%s/nonexistent_resource' % self.prefix) + response = self.client.get("/%s/nonexistent_resource" % self.prefix) self.assertEqual(404, response.status_code) def test_index(self): - response = self.client.get('/%s/' % self.prefix) - self.assertContains(response, 'Index of ./') + response = self.client.get("/%s/" % self.prefix) + self.assertContains(response, "Index of ./") # Directories have a trailing slash. - self.assertIn('subdir/', response.context['file_list']) + self.assertIn("subdir/", response.context["file_list"]) def test_index_subdir(self): - response = self.client.get('/%s/subdir/' % self.prefix) - self.assertContains(response, 'Index of subdir/') + response = self.client.get("/%s/subdir/" % self.prefix) + self.assertContains(response, "Index of subdir/") # File with a leading dot (e.g. .hidden) aren't displayed. - self.assertEqual(response.context['file_list'], ['visible']) - - @override_settings(TEMPLATES=[{ - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'OPTIONS': { - 'loaders': [ - ('django.template.loaders.locmem.Loader', { - 'static/directory_index.html': 'Test index', - }), - ], - }, - }]) + self.assertEqual(response.context["file_list"], ["visible"]) + + @override_settings( + TEMPLATES=[ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "OPTIONS": { + "loaders": [ + ( + "django.template.loaders.locmem.Loader", + { + "static/directory_index.html": "Test index", + }, + ), + ], + }, + } + ] + ) def test_index_custom_template(self): - response = self.client.get('/%s/' % self.prefix) - self.assertEqual(response.content, b'Test index') + response = self.client.get("/%s/" % self.prefix) + self.assertEqual(response.content, b"Test index") class StaticHelperTest(StaticTests): """ Test case to make sure the static URL pattern helper works as expected """ + def setUp(self): super().setUp() self._old_views_urlpatterns = urls.urlpatterns[:] - urls.urlpatterns += static('media/', document_root=media_dir) + urls.urlpatterns += static("media/", document_root=media_dir) def tearDown(self): super().tearDown() urls.urlpatterns = self._old_views_urlpatterns def test_prefix(self): - self.assertEqual(static('test')[0].pattern.regex.pattern, '^test(?P<path>.*)$') + self.assertEqual(static("test")[0].pattern.regex.pattern, "^test(?P<path>.*)$") @override_settings(DEBUG=False) def test_debug_off(self): """No URLs are served if DEBUG=False.""" - self.assertEqual(static('test'), []) + self.assertEqual(static("test"), []) def test_empty_prefix(self): - with self.assertRaisesMessage(ImproperlyConfigured, 'Empty static prefix not permitted'): - static('') + with self.assertRaisesMessage( + ImproperlyConfigured, "Empty static prefix not permitted" + ): + static("") def test_special_prefix(self): """No URLs are served if prefix contains a netloc part.""" - self.assertEqual(static('http://example.org'), []) - self.assertEqual(static('//example.org'), []) + self.assertEqual(static("http://example.org"), []) + self.assertEqual(static("//example.org"), []) class StaticUtilsTests(unittest.TestCase): diff --git a/tests/view_tests/urls.py b/tests/view_tests/urls.py index 159f353ee6..cec156b5da 100644 --- a/tests/view_tests/urls.py +++ b/tests/view_tests/urls.py @@ -9,70 +9,81 @@ from django.views import defaults, i18n, static from . import views base_dir = os.path.dirname(os.path.abspath(__file__)) -media_dir = os.path.join(base_dir, 'media') -locale_dir = os.path.join(base_dir, 'locale') +media_dir = os.path.join(base_dir, "media") +locale_dir = os.path.join(base_dir, "locale") urlpatterns = [ - path('', views.index_page), - + path("", views.index_page), # Default views - path('nonexistent_url/', partial(defaults.page_not_found, exception=None)), - path('server_error/', defaults.server_error), - + path("nonexistent_url/", partial(defaults.page_not_found, exception=None)), + path("server_error/", defaults.server_error), # a view that raises an exception for the debug view - path('raises/', views.raises), - - path('raises400/', views.raises400), - path('raises400_bad_request/', views.raises400_bad_request), - path('raises403/', views.raises403), - path('raises404/', views.raises404), - path('raises500/', views.raises500), - path('custom_reporter_class_view/', views.custom_reporter_class_view), - - path('technical404/', views.technical404, name='my404'), - path('classbased404/', views.Http404View.as_view()), - path('classbased500/', views.Raises500View.as_view()), - + path("raises/", views.raises), + path("raises400/", views.raises400), + path("raises400_bad_request/", views.raises400_bad_request), + path("raises403/", views.raises403), + path("raises404/", views.raises404), + path("raises500/", views.raises500), + path("custom_reporter_class_view/", views.custom_reporter_class_view), + path("technical404/", views.technical404, name="my404"), + path("classbased404/", views.Http404View.as_view()), + path("classbased500/", views.Raises500View.as_view()), # i18n views - path('i18n/', include('django.conf.urls.i18n')), - path('jsi18n/', i18n.JavaScriptCatalog.as_view(packages=['view_tests'])), - path('jsi18n/app1/', i18n.JavaScriptCatalog.as_view(packages=['view_tests.app1'])), - path('jsi18n/app2/', i18n.JavaScriptCatalog.as_view(packages=['view_tests.app2'])), - path('jsi18n/app5/', i18n.JavaScriptCatalog.as_view(packages=['view_tests.app5'])), - path('jsi18n_english_translation/', i18n.JavaScriptCatalog.as_view(packages=['view_tests.app0'])), - path('jsi18n_multi_packages1/', - i18n.JavaScriptCatalog.as_view(packages=['view_tests.app1', 'view_tests.app2'])), - path('jsi18n_multi_packages2/', - i18n.JavaScriptCatalog.as_view(packages=['view_tests.app3', 'view_tests.app4'])), - path('jsi18n_admin/', - i18n.JavaScriptCatalog.as_view(packages=['django.contrib.admin', 'view_tests'])), - path('jsi18n_template/', views.jsi18n), - path('jsi18n_multi_catalogs/', views.jsi18n_multi_catalogs), - path('jsoni18n/', i18n.JSONCatalog.as_view(packages=['view_tests'])), - + path("i18n/", include("django.conf.urls.i18n")), + path("jsi18n/", i18n.JavaScriptCatalog.as_view(packages=["view_tests"])), + path("jsi18n/app1/", i18n.JavaScriptCatalog.as_view(packages=["view_tests.app1"])), + path("jsi18n/app2/", i18n.JavaScriptCatalog.as_view(packages=["view_tests.app2"])), + path("jsi18n/app5/", i18n.JavaScriptCatalog.as_view(packages=["view_tests.app5"])), + path( + "jsi18n_english_translation/", + i18n.JavaScriptCatalog.as_view(packages=["view_tests.app0"]), + ), + path( + "jsi18n_multi_packages1/", + i18n.JavaScriptCatalog.as_view(packages=["view_tests.app1", "view_tests.app2"]), + ), + path( + "jsi18n_multi_packages2/", + i18n.JavaScriptCatalog.as_view(packages=["view_tests.app3", "view_tests.app4"]), + ), + path( + "jsi18n_admin/", + i18n.JavaScriptCatalog.as_view(packages=["django.contrib.admin", "view_tests"]), + ), + path("jsi18n_template/", views.jsi18n), + path("jsi18n_multi_catalogs/", views.jsi18n_multi_catalogs), + path("jsoni18n/", i18n.JSONCatalog.as_view(packages=["view_tests"])), # Static views - re_path(r'^site_media/(?P<path>.*)$', static.serve, {'document_root': media_dir, 'show_indexes': True}), + re_path( + r"^site_media/(?P<path>.*)$", + static.serve, + {"document_root": media_dir, "show_indexes": True}, + ), ] urlpatterns += i18n_patterns( - re_path(_(r'^translated/$'), views.index_page, name='i18n_prefixed'), + re_path(_(r"^translated/$"), views.index_page, name="i18n_prefixed"), ) urlpatterns += [ path( - 'safestring_exception/', + "safestring_exception/", views.safestring_in_template_exception, - name='safestring_exception', + name="safestring_exception", ), - path('template_exception/', views.template_exception, name='template_exception'), + path("template_exception/", views.template_exception, name="template_exception"), path( - 'raises_template_does_not_exist/<path:path>', + "raises_template_does_not_exist/<path:path>", views.raises_template_does_not_exist, - name='raises_template_does_not_exist' + name="raises_template_does_not_exist", + ), + path("render_no_template/", views.render_no_template, name="render_no_template"), + re_path( + r"^test-setlang/(?P<parameter>[^/]+)/$", + views.with_parameter, + name="with_parameter", ), - path('render_no_template/', views.render_no_template, name='render_no_template'), - re_path(r'^test-setlang/(?P<parameter>[^/]+)/$', views.with_parameter, name='with_parameter'), # Patterns to test the technical 404. - re_path(r'^regex-post/(?P<pk>[0-9]+)/$', views.index_page, name='regex-post'), - path('path-post/<int:pk>/', views.index_page, name='path-post'), + re_path(r"^regex-post/(?P<pk>[0-9]+)/$", views.index_page, name="regex-post"), + path("path-post/<int:pk>/", views.index_page, name="path-post"), ] diff --git a/tests/view_tests/views.py b/tests/view_tests/views.py index 8cf9ab4dde..43057af3a1 100644 --- a/tests/view_tests/views.py +++ b/tests/view_tests/views.py @@ -4,31 +4,29 @@ import logging import sys from pathlib import Path -from django.core.exceptions import ( - BadRequest, PermissionDenied, SuspiciousOperation, -) +from django.core.exceptions import BadRequest, PermissionDenied, SuspiciousOperation from django.http import Http404, HttpResponse, JsonResponse from django.shortcuts import render from django.template import Context, Template, TemplateDoesNotExist from django.urls import get_resolver from django.views import View from django.views.debug import ( - ExceptionReporter, SafeExceptionReporterFilter, technical_500_response, -) -from django.views.decorators.debug import ( - sensitive_post_parameters, sensitive_variables, + ExceptionReporter, + SafeExceptionReporterFilter, + technical_500_response, ) +from django.views.decorators.debug import sensitive_post_parameters, sensitive_variables -TEMPLATES_PATH = Path(__file__).resolve().parent / 'templates' +TEMPLATES_PATH = Path(__file__).resolve().parent / "templates" def index_page(request): """Dummy index page""" - return HttpResponse('<html><body>Dummy page</body></html>') + return HttpResponse("<html><body>Dummy page</body></html>") def with_parameter(request, parameter): - return HttpResponse('ok') + return HttpResponse("ok") def raises(request): @@ -36,6 +34,7 @@ def raises(request): # local vars won't hijack the technical 500 response (#15025). def callable(): raise Exception + try: raise Exception except Exception: @@ -64,7 +63,7 @@ def raises400(request): def raises400_bad_request(request): - raise BadRequest('Malformed request syntax') + raise BadRequest("Malformed request syntax") def raises403(request): @@ -73,7 +72,7 @@ def raises403(request): def raises404(request): resolver = get_resolver(None) - resolver.resolve('/not-in-urls') + resolver.resolve("/not-in-urls") def technical404(request): @@ -86,7 +85,7 @@ class Http404View(View): def template_exception(request): - return render(request, 'debug/template_exception.html') + return render(request, "debug/template_exception.html") def safestring_in_template_exception(request): @@ -102,14 +101,14 @@ def safestring_in_template_exception(request): def jsi18n(request): - return render(request, 'jsi18n.html') + return render(request, "jsi18n.html") def jsi18n_multi_catalogs(request): - return render(request, 'jsi18n-multi-catalogs.html') + return render(request, "jsi18n-multi-catalogs.html") -def raises_template_does_not_exist(request, path='i_dont_exist.html'): +def raises_template_does_not_exist(request, path="i_dont_exist.html"): # We need to inspect the HTML generated by the fancy 500 debug view but # the test client ignores it, so we send it explicitly. try: @@ -125,22 +124,22 @@ def render_no_template(request): def send_log(request, exc_info): - logger = logging.getLogger('django') + logger = logging.getLogger("django") # The default logging config has a logging filter to ensure admin emails are # only sent with DEBUG=False, but since someone might choose to remove that # filter, we still want to be able to test the behavior of error emails # with DEBUG=True. So we need to remove the filter temporarily. admin_email_handler = [ - h for h in logger.handlers - if h.__class__.__name__ == "AdminEmailHandler" + h for h in logger.handlers if h.__class__.__name__ == "AdminEmailHandler" ][0] orig_filters = admin_email_handler.filters admin_email_handler.filters = [] admin_email_handler.include_html = True logger.error( - 'Internal Server Error: %s', request.path, + "Internal Server Error: %s", + request.path, exc_info=exc_info, - extra={'status_code': 500, 'request': request}, + extra={"status_code": 500, "request": request}, ) admin_email_handler.filters = orig_filters @@ -149,8 +148,10 @@ def non_sensitive_view(request): # Do not just use plain strings for the variables' values in the code # so that the tests don't return false positives when the function's source # is displayed in the exception report. - cooked_eggs = ''.join(['s', 'c', 'r', 'a', 'm', 'b', 'l', 'e', 'd']) # NOQA - sauce = ''.join(['w', 'o', 'r', 'c', 'e', 's', 't', 'e', 'r', 's', 'h', 'i', 'r', 'e']) # NOQA + cooked_eggs = "".join(["s", "c", "r", "a", "m", "b", "l", "e", "d"]) # NOQA + sauce = "".join( + ["w", "o", "r", "c", "e", "s", "t", "e", "r", "s", "h", "i", "r", "e"] + ) # NOQA try: raise Exception except Exception: @@ -159,14 +160,16 @@ def non_sensitive_view(request): return technical_500_response(request, *exc_info) -@sensitive_variables('sauce') -@sensitive_post_parameters('bacon-key', 'sausage-key') +@sensitive_variables("sauce") +@sensitive_post_parameters("bacon-key", "sausage-key") def sensitive_view(request): # Do not just use plain strings for the variables' values in the code # so that the tests don't return false positives when the function's source # is displayed in the exception report. - cooked_eggs = ''.join(['s', 'c', 'r', 'a', 'm', 'b', 'l', 'e', 'd']) # NOQA - sauce = ''.join(['w', 'o', 'r', 'c', 'e', 's', 't', 'e', 'r', 's', 'h', 'i', 'r', 'e']) # NOQA + cooked_eggs = "".join(["s", "c", "r", "a", "m", "b", "l", "e", "d"]) # NOQA + sauce = "".join( + ["w", "o", "r", "c", "e", "s", "t", "e", "r", "s", "h", "i", "r", "e"] + ) # NOQA try: raise Exception except Exception: @@ -181,8 +184,10 @@ def paranoid_view(request): # Do not just use plain strings for the variables' values in the code # so that the tests don't return false positives when the function's source # is displayed in the exception report. - cooked_eggs = ''.join(['s', 'c', 'r', 'a', 'm', 'b', 'l', 'e', 'd']) # NOQA - sauce = ''.join(['w', 'o', 'r', 'c', 'e', 's', 't', 'e', 'r', 's', 'h', 'i', 'r', 'e']) # NOQA + cooked_eggs = "".join(["s", "c", "r", "a", "m", "b", "l", "e", "d"]) # NOQA + sauce = "".join( + ["w", "o", "r", "c", "e", "s", "t", "e", "r", "s", "h", "i", "r", "e"] + ) # NOQA try: raise Exception except Exception: @@ -193,37 +198,45 @@ def paranoid_view(request): def sensitive_args_function_caller(request): try: - sensitive_args_function(''.join(['w', 'o', 'r', 'c', 'e', 's', 't', 'e', 'r', 's', 'h', 'i', 'r', 'e'])) + sensitive_args_function( + "".join( + ["w", "o", "r", "c", "e", "s", "t", "e", "r", "s", "h", "i", "r", "e"] + ) + ) except Exception: exc_info = sys.exc_info() send_log(request, exc_info) return technical_500_response(request, *exc_info) -@sensitive_variables('sauce') +@sensitive_variables("sauce") def sensitive_args_function(sauce): # Do not just use plain strings for the variables' values in the code # so that the tests don't return false positives when the function's source # is displayed in the exception report. - cooked_eggs = ''.join(['s', 'c', 'r', 'a', 'm', 'b', 'l', 'e', 'd']) # NOQA + cooked_eggs = "".join(["s", "c", "r", "a", "m", "b", "l", "e", "d"]) # NOQA raise Exception def sensitive_kwargs_function_caller(request): try: - sensitive_kwargs_function(''.join(['w', 'o', 'r', 'c', 'e', 's', 't', 'e', 'r', 's', 'h', 'i', 'r', 'e'])) + sensitive_kwargs_function( + "".join( + ["w", "o", "r", "c", "e", "s", "t", "e", "r", "s", "h", "i", "r", "e"] + ) + ) except Exception: exc_info = sys.exc_info() send_log(request, exc_info) return technical_500_response(request, *exc_info) -@sensitive_variables('sauce') +@sensitive_variables("sauce") def sensitive_kwargs_function(sauce=None): # Do not just use plain strings for the variables' values in the code # so that the tests don't return false positives when the function's source # is displayed in the exception report. - cooked_eggs = ''.join(['s', 'c', 'r', 'a', 'm', 'b', 'l', 'e', 'd']) # NOQA + cooked_eggs = "".join(["s", "c", "r", "a", "m", "b", "l", "e", "d"]) # NOQA raise Exception @@ -245,8 +258,10 @@ def custom_exception_reporter_filter_view(request): # Do not just use plain strings for the variables' values in the code # so that the tests don't return false positives when the function's source # is displayed in the exception report. - cooked_eggs = ''.join(['s', 'c', 'r', 'a', 'm', 'b', 'l', 'e', 'd']) # NOQA - sauce = ''.join(['w', 'o', 'r', 'c', 'e', 's', 't', 'e', 'r', 's', 'h', 'i', 'r', 'e']) # NOQA + cooked_eggs = "".join(["s", "c", "r", "a", "m", "b", "l", "e", "d"]) # NOQA + sauce = "".join( + ["w", "o", "r", "c", "e", "s", "t", "e", "r", "s", "h", "i", "r", "e"] + ) # NOQA request.exception_reporter_filter = UnsafeExceptionReporterFilter() try: raise Exception @@ -257,15 +272,15 @@ def custom_exception_reporter_filter_view(request): class CustomExceptionReporter(ExceptionReporter): - custom_traceback_text = 'custom traceback text' + custom_traceback_text = "custom traceback text" def get_traceback_html(self): return self.custom_traceback_text class TemplateOverrideExceptionReporter(ExceptionReporter): - html_template_path = TEMPLATES_PATH / 'my_technical_500.html' - text_template_path = TEMPLATES_PATH / 'my_technical_500.txt' + html_template_path = TEMPLATES_PATH / "my_technical_500.html" + text_template_path = TEMPLATES_PATH / "my_technical_500.txt" def custom_reporter_class_view(request): @@ -278,14 +293,15 @@ def custom_reporter_class_view(request): class Klass: - - @sensitive_variables('sauce') + @sensitive_variables("sauce") def method(self, request): # Do not just use plain strings for the variables' values in the code # so that the tests don't return false positives when the function's # source is displayed in the exception report. - cooked_eggs = ''.join(['s', 'c', 'r', 'a', 'm', 'b', 'l', 'e', 'd']) # NOQA - sauce = ''.join(['w', 'o', 'r', 'c', 'e', 's', 't', 'e', 'r', 's', 'h', 'i', 'r', 'e']) # NOQA + cooked_eggs = "".join(["s", "c", "r", "a", "m", "b", "l", "e", "d"]) # NOQA + sauce = "".join( + ["w", "o", "r", "c", "e", "s", "t", "e", "r", "s", "h", "i", "r", "e"] + ) # NOQA try: raise Exception except Exception: @@ -298,13 +314,15 @@ def sensitive_method_view(request): return Klass().method(request) -@sensitive_variables('sauce') -@sensitive_post_parameters('bacon-key', 'sausage-key') +@sensitive_variables("sauce") +@sensitive_post_parameters("bacon-key", "sausage-key") def multivalue_dict_key_error(request): - cooked_eggs = ''.join(['s', 'c', 'r', 'a', 'm', 'b', 'l', 'e', 'd']) # NOQA - sauce = ''.join(['w', 'o', 'r', 'c', 'e', 's', 't', 'e', 'r', 's', 'h', 'i', 'r', 'e']) # NOQA + cooked_eggs = "".join(["s", "c", "r", "a", "m", "b", "l", "e", "d"]) # NOQA + sauce = "".join( + ["w", "o", "r", "c", "e", "s", "t", "e", "r", "s", "h", "i", "r", "e"] + ) # NOQA try: - request.POST['bar'] + request.POST["bar"] except Exception: exc_info = sys.exc_info() send_log(request, exc_info) @@ -312,10 +330,12 @@ def multivalue_dict_key_error(request): def json_response_view(request): - return JsonResponse({ - 'a': [1, 2, 3], - 'foo': {'bar': 'baz'}, - # Make sure datetime and Decimal objects would be serialized properly - 'timestamp': datetime.datetime(2013, 5, 19, 20), - 'value': decimal.Decimal('3.14'), - }) + return JsonResponse( + { + "a": [1, 2, 3], + "foo": {"bar": "baz"}, + # Make sure datetime and Decimal objects would be serialized properly + "timestamp": datetime.datetime(2013, 5, 19, 20), + "value": decimal.Decimal("3.14"), + } + ) |