Browse Source

Refs #33348 -- Deprecated passing errors=None to SimpleTestCase.assertFormError()/assertFormsetErrors().

Baptiste Mispelon 3 years ago
parent
commit
c67e1cf44f
4 changed files with 61 additions and 10 deletions
  1. 22 9
      django/test/testcases.py
  2. 4 0
      docs/internals/deprecation.txt
  3. 5 0
      docs/releases/4.1.txt
  4. 30 1
      tests/test_utils/tests.py

+ 22 - 9
django/test/testcases.py

@@ -6,6 +6,7 @@ import posixpath
 import sys
 import threading
 import unittest
+import warnings
 from collections import Counter
 from contextlib import contextmanager
 from copy import copy, deepcopy
@@ -41,6 +42,7 @@ from django.test.utils import (
     CaptureQueriesContext, ContextList, compare_xml, modify_settings,
     override_settings,
 )
+from django.utils.deprecation import RemovedInDjango50Warning
 from django.utils.functional import classproperty
 from django.utils.version import PY310
 from django.views.static import serve
@@ -50,13 +52,8 @@ __all__ = ('TestCase', 'TransactionTestCase',
 
 
 def to_list(value):
-    """
-    Put value into a list if it's not already one. Return an empty list if
-    value is None.
-    """
-    if value is None:
-        value = []
-    elif not isinstance(value, list):
+    """Put value into a list if it's not already one."""
+    if not isinstance(value, list):
         value = [value]
     return value
 
@@ -493,10 +490,18 @@ class SimpleTestCase(unittest.TestCase):
             msg_prefix += ": "
 
         # Put context(s) into a list to simplify processing.
-        contexts = to_list(response.context)
+        contexts = [] if response.context is None else to_list(response.context)
         if not contexts:
             self.fail(msg_prefix + "Response did not use any contexts to render the response")
 
+        if errors is None:
+            warnings.warn(
+                'Passing errors=None to assertFormError() is deprecated, use '
+                'errors=[] instead.',
+                RemovedInDjango50Warning,
+                stacklevel=2,
+            )
+            errors = []
         # Put error(s) into a list to simplify processing.
         errors = to_list(errors)
 
@@ -556,11 +561,19 @@ class SimpleTestCase(unittest.TestCase):
             msg_prefix += ": "
 
         # Put context(s) into a list to simplify processing.
-        contexts = to_list(response.context)
+        contexts = [] if response.context is None else to_list(response.context)
         if not contexts:
             self.fail(msg_prefix + 'Response did not use any contexts to '
                       'render the response')
 
+        if errors is None:
+            warnings.warn(
+                'Passing errors=None to assertFormsetError() is deprecated, '
+                'use errors=[] instead.',
+                RemovedInDjango50Warning,
+                stacklevel=2,
+            )
+            errors = []
         # Put error(s) into a list to simplify processing.
         errors = to_list(errors)
 

+ 4 - 0
docs/internals/deprecation.txt

@@ -75,6 +75,10 @@ details on these changes.
 * The ``opclasses`` argument of
   ``django.contrib.postgres.constraints.ExclusionConstraint`` will be removed.
 
+* The undocumented ability to pass ``errors=None`` to
+  ``SimpleTestCase.assertFormError()`` and ``assertFormsetError()`` will be
+  removed.
+
 .. _deprecation-removed-in-4.1:
 
 4.1

+ 5 - 0
docs/releases/4.1.txt

@@ -385,6 +385,11 @@ Miscellaneous
             ),
         ]
 
+* The undocumented ability to pass ``errors=None`` to
+  :meth:`.SimpleTestCase.assertFormError` and
+  :meth:`~.SimpleTestCase.assertFormsetError` is deprecated. Use ``errors=[]``
+  instead.
+
 Features removed in 4.1
 =======================
 

+ 30 - 1
tests/test_utils/tests.py

@@ -26,10 +26,11 @@ from django.test import (
 from django.test.html import HTMLParseError, parse_html
 from django.test.testcases import DatabaseOperationForbidden
 from django.test.utils import (
-    CaptureQueriesContext, TestContextDecorator, isolate_apps,
+    CaptureQueriesContext, TestContextDecorator, ignore_warnings, isolate_apps,
     override_settings, setup_test_environment,
 )
 from django.urls import NoReverseMatch, path, reverse, reverse_lazy
+from django.utils.deprecation import RemovedInDjango50Warning
 from django.utils.log import DEFAULT_LOGGING
 
 from .models import Car, Person, PossessedCar
@@ -1418,6 +1419,20 @@ class AssertFormErrorTests(SimpleTestCase):
         response = mock.Mock(context=[{'form': TestForm.invalid(nonfield=True)}])
         self.assertFormError(response, 'form', None, 'non-field error')
 
+    @ignore_warnings(category=RemovedInDjango50Warning)
+    def test_errors_none(self):
+        response = mock.Mock(context=[{'form': TestForm.invalid()}])
+        self.assertFormError(response, 'form', 'field', None)
+
+    def test_errors_none_warning(self):
+        response = mock.Mock(context=[{'form': TestForm.invalid()}])
+        msg = (
+            'Passing errors=None to assertFormError() is deprecated, use '
+            'errors=[] instead.'
+        )
+        with self.assertWarnsMessage(RemovedInDjango50Warning, msg):
+            self.assertFormError(response, 'form', 'value', None)
+
 
 class AssertFormsetErrorTests(SimpleTestCase):
     def _get_formset_data(self, field_value):
@@ -1560,6 +1575,20 @@ class AssertFormsetErrorTests(SimpleTestCase):
         ])
         self.assertFormsetError(response, 'form', 0, 'field', 'invalid value')
 
+    @ignore_warnings(category=RemovedInDjango50Warning)
+    def test_errors_none(self):
+        response = mock.Mock(context=[{'formset': TestFormset.invalid()}])
+        self.assertFormsetError(response, 'formset', 0, 'field', None)
+
+    def test_errors_none_warning(self):
+        response = mock.Mock(context=[{'formset': TestFormset.invalid()}])
+        msg = (
+            'Passing errors=None to assertFormsetError() is deprecated, use '
+            'errors=[] instead.'
+        )
+        with self.assertWarnsMessage(RemovedInDjango50Warning, msg):
+            self.assertFormsetError(response, 'formset', 0, 'field', None)
+
 
 class FirstUrls:
     urlpatterns = [path('first/', empty_response, name='first')]