Forráskód Böngészése

Refs #33348 -- Removed support for passing response object and form/formset name to SimpleTestCase.assertFormError()/assertFormSetError().

Per deprecation timeline.
Mariusz Felisiak 2 éve
szülő
commit
71d1203b07
4 módosított fájl, 6 hozzáadás és 389 törlés
  1. 1 130
      django/test/testcases.py
  2. 4 0
      docs/releases/5.0.txt
  3. 0 12
      docs/topics/testing/tools.txt
  4. 1 247
      tests/test_utils/tests.py

+ 1 - 130
django/test/testcases.py

@@ -1,5 +1,4 @@
 import difflib
-import inspect
 import json
 import logging
 import posixpath
@@ -42,7 +41,6 @@ from django.db import DEFAULT_DB_ALIAS, connection, connections, transaction
 from django.forms.fields import CharField
 from django.http import QueryDict
 from django.http.request import split_domain_port, validate_host
-from django.http.response import HttpResponseBase
 from django.test.client import AsyncClient, Client
 from django.test.html import HTMLParseError, parse_html
 from django.test.signals import template_rendered
@@ -53,7 +51,7 @@ from django.test.utils import (
     modify_settings,
     override_settings,
 )
-from django.utils.deprecation import RemovedInDjango50Warning, RemovedInDjango51Warning
+from django.utils.deprecation import RemovedInDjango51Warning
 from django.utils.functional import classproperty
 from django.utils.version import PY310
 from django.views.static import serve
@@ -168,127 +166,6 @@ class _DatabaseFailure:
         raise DatabaseOperationForbidden(self.message)
 
 
-# RemovedInDjango50Warning
-class _AssertFormErrorDeprecationHelper:
-    @staticmethod
-    def assertFormError(self, response, form, field, errors, msg_prefix=""):
-        """
-        Search through all the rendered contexts of the `response` for a form named
-        `form` then dispatch to the new assertFormError() using that instance.
-        If multiple contexts contain the form, they're all checked in order and any
-        failure will abort (this matches the old behavior).
-        """
-        warning_msg = (
-            f"Passing response to assertFormError() is deprecated. Use the form object "
-            f"directly: assertFormError(response.context[{form!r}], {field!r}, ...)"
-        )
-        warnings.warn(warning_msg, RemovedInDjango50Warning, stacklevel=2)
-
-        full_msg_prefix = f"{msg_prefix}: " if msg_prefix else ""
-        contexts = to_list(response.context) if response.context is not None else []
-        if not contexts:
-            self.fail(
-                f"{full_msg_prefix}Response did not use any contexts to render the "
-                f"response"
-            )
-        # Search all contexts for the error.
-        found_form = False
-        for i, context in enumerate(contexts):
-            if form not in context:
-                continue
-            found_form = True
-            self.assertFormError(context[form], field, errors, msg_prefix=msg_prefix)
-        if not found_form:
-            self.fail(
-                f"{full_msg_prefix}The form '{form}' was not used to render the "
-                f"response"
-            )
-
-    @staticmethod
-    def assertFormSetError(
-        self, response, formset, form_index, field, errors, msg_prefix=""
-    ):
-        """
-        Search for a formset named "formset" in the "response" and dispatch to
-        the new assertFormSetError() using that instance. If the name is found
-        in multiple contexts they're all checked in order and any failure will
-        abort the test.
-        """
-        warning_msg = (
-            f"Passing response to assertFormSetError() is deprecated. Use the formset "
-            f"object directly: assertFormSetError(response.context[{formset!r}], "
-            f"{form_index!r}, ...)"
-        )
-        warnings.warn(warning_msg, RemovedInDjango50Warning, stacklevel=2)
-
-        full_msg_prefix = f"{msg_prefix}: " if msg_prefix else ""
-        contexts = to_list(response.context) if response.context is not None else []
-        if not contexts:
-            self.fail(
-                f"{full_msg_prefix}Response did not use any contexts to render the "
-                f"response"
-            )
-        found_formset = False
-        for i, context in enumerate(contexts):
-            if formset not in context or not hasattr(context[formset], "forms"):
-                continue
-            found_formset = True
-            self.assertFormSetError(
-                context[formset], form_index, field, errors, msg_prefix
-            )
-        if not found_formset:
-            self.fail(
-                f"{full_msg_prefix}The formset '{formset}' was not used to render the "
-                f"response"
-            )
-
-    @classmethod
-    def patch_signature(cls, new_method):
-        """
-        Replace the decorated method with a new one that inspects the passed
-        args/kwargs and dispatch to the old implementation (with deprecation
-        warning) when it detects the old signature.
-        """
-
-        @wraps(new_method)
-        def patched_method(self, *args, **kwargs):
-            old_method = getattr(cls, new_method.__name__)
-            old_signature = inspect.signature(old_method)
-            try:
-                old_bound_args = old_signature.bind(self, *args, **kwargs)
-            except TypeError:
-                # If old signature doesn't match then either:
-                # 1) new signature will match
-                # 2) or a TypeError will be raised showing the user information
-                # about the new signature.
-                return new_method(self, *args, **kwargs)
-
-            new_signature = inspect.signature(new_method)
-            try:
-                new_bound_args = new_signature.bind(self, *args, **kwargs)
-            except TypeError:
-                # Old signature matches but not the new one (because of
-                # previous try/except).
-                return old_method(self, *args, **kwargs)
-
-            # If both signatures match, decide on which method to call by
-            # inspecting the first arg (arg[0] = self).
-            assert old_bound_args.args[1] == new_bound_args.args[1]
-            if hasattr(
-                old_bound_args.args[1], "context"
-            ):  # Looks like a response object => old method.
-                return old_method(self, *args, **kwargs)
-            elif isinstance(old_bound_args.args[1], HttpResponseBase):
-                raise ValueError(
-                    f"{old_method.__name__}() is only usable on responses fetched "
-                    f"using the Django test Client."
-                )
-            else:
-                return new_method(self, *args, **kwargs)
-
-        return patched_method
-
-
 class SimpleTestCase(unittest.TestCase):
 
     # The class we'll use for the test client self.client.
@@ -711,9 +588,6 @@ class SimpleTestCase(unittest.TestCase):
 
         self.assertEqual(field_errors, errors, msg_prefix + failure_message)
 
-    # RemovedInDjango50Warning: When the deprecation ends, remove the
-    # decorator.
-    @_AssertFormErrorDeprecationHelper.patch_signature
     def assertFormError(self, form, field, errors, msg_prefix=""):
         """
         Assert that a field named "field" on the given form object has specific
@@ -738,9 +612,6 @@ class SimpleTestCase(unittest.TestCase):
         )
         return self.assertFormSetError(*args, **kw)
 
-    # RemovedInDjango50Warning: When the deprecation ends, remove the
-    # decorator.
-    @_AssertFormErrorDeprecationHelper.patch_signature
     def assertFormSetError(self, formset, form_index, field, errors, msg_prefix=""):
         """
         Similar to assertFormError() but for formsets.

+ 4 - 0
docs/releases/5.0.txt

@@ -334,3 +334,7 @@ to remove usage of these features.
 
 * The ``django.utils.timezone.utc`` alias to ``datetime.timezone.utc`` is
   removed.
+
+* Passing a response object and a form/formset name to
+  ``SimpleTestCase.assertFormError()`` and ``assertFormSetError()`` is no
+  longer allowed.

+ 0 - 12
docs/topics/testing/tools.txt

@@ -1601,12 +1601,6 @@ your test suite.
     which means that ``errors='error message'`` is the same as
     ``errors=['error message']``.
 
-    .. deprecated:: 4.1
-
-        Support for passing a response object and a form name to
-        ``assertFormError()`` is deprecated and will be removed in Django 5.0.
-        Use the form instance directly instead.
-
 .. method:: SimpleTestCase.assertFormSetError(formset, form_index, field, errors, msg_prefix='')
 
     Asserts that the ``formset`` raises the provided list of errors when
@@ -1624,12 +1618,6 @@ your test suite.
     ``field`` and ``errors`` have the same meaning as the parameters to
     ``assertFormError()``.
 
-    .. deprecated:: 4.1
-
-        Support for passing a response object and a formset name to
-        ``assertFormSetError()`` is deprecated and will be removed in Django
-        5.0. Use the formset instance directly instead.
-
     .. deprecated:: 4.2
 
         The ``assertFormsetError()`` assertion method is deprecated. Use

+ 1 - 247
tests/test_utils/tests.py

@@ -46,7 +46,7 @@ from django.test.utils import (
     setup_test_environment,
 )
 from django.urls import NoReverseMatch, path, reverse, reverse_lazy
-from django.utils.deprecation import RemovedInDjango50Warning, RemovedInDjango51Warning
+from django.utils.deprecation import RemovedInDjango51Warning
 from django.utils.log import DEFAULT_LOGGING
 from django.utils.version import PY311
 
@@ -1383,44 +1383,6 @@ class TestFormset(formset_factory(TestForm)):
 
 
 class AssertFormErrorTests(SimpleTestCase):
-    @ignore_warnings(category=RemovedInDjango50Warning)
-    def test_non_client_response(self):
-        msg = (
-            "assertFormError() is only usable on responses fetched using the "
-            "Django test Client."
-        )
-        response = HttpResponse()
-        with self.assertRaisesMessage(ValueError, msg):
-            self.assertFormError(response, "form", "field", "invalid value")
-
-    @ignore_warnings(category=RemovedInDjango50Warning)
-    def test_response_with_no_context(self):
-        msg = "Response did not use any contexts to render the response"
-        response = mock.Mock(context=[])
-        with self.assertRaisesMessage(AssertionError, msg):
-            self.assertFormError(response, "form", "field", "invalid value")
-        msg_prefix = "Custom prefix"
-        with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"):
-            self.assertFormError(
-                response,
-                "form",
-                "field",
-                "invalid value",
-                msg_prefix=msg_prefix,
-            )
-
-    @ignore_warnings(category=RemovedInDjango50Warning)
-    def test_form_not_in_context(self):
-        msg = "The form 'form' was not used to render the response"
-        response = mock.Mock(context=[{}])
-        with self.assertRaisesMessage(AssertionError, msg):
-            self.assertFormError(response, "form", "field", "invalid value")
-        msg_prefix = "Custom prefix"
-        with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"):
-            self.assertFormError(
-                response, "form", "field", "invalid value", msg_prefix=msg_prefix
-            )
-
     def test_single_error(self):
         self.assertFormError(TestForm.invalid(), "field", "invalid value")
 
@@ -1523,35 +1485,6 @@ class AssertFormErrorTests(SimpleTestCase):
 
 
 class AssertFormSetErrorTests(SimpleTestCase):
-    @ignore_warnings(category=RemovedInDjango50Warning)
-    def test_non_client_response(self):
-        msg = (
-            "assertFormSetError() is only usable on responses fetched using "
-            "the Django test Client."
-        )
-        response = HttpResponse()
-        with self.assertRaisesMessage(ValueError, msg):
-            self.assertFormSetError(response, "formset", 0, "field", "invalid value")
-
-    @ignore_warnings(category=RemovedInDjango50Warning)
-    def test_response_with_no_context(self):
-        msg = "Response did not use any contexts to render the response"
-        response = mock.Mock(context=[])
-        with self.assertRaisesMessage(AssertionError, msg):
-            self.assertFormSetError(response, "formset", 0, "field", "invalid value")
-
-    @ignore_warnings(category=RemovedInDjango50Warning)
-    def test_formset_not_in_context(self):
-        msg = "The formset 'formset' was not used to render the response"
-        response = mock.Mock(context=[{}])
-        with self.assertRaisesMessage(AssertionError, msg):
-            self.assertFormSetError(response, "formset", 0, "field", "invalid value")
-        msg_prefix = "Custom prefix"
-        with self.assertRaisesMessage(AssertionError, f"{msg_prefix}: {msg}"):
-            self.assertFormSetError(
-                response, "formset", 0, "field", "invalid value", msg_prefix=msg_prefix
-            )
-
     def test_rename_assertformseterror_deprecation_warning(self):
         msg = "assertFormsetError() is deprecated in favor of assertFormSetError()."
         with self.assertRaisesMessage(RemovedInDjango51Warning, msg):
@@ -1762,185 +1695,6 @@ class AssertFormSetErrorTests(SimpleTestCase):
             self.assertFormSetError(formset, 2, "field", "error")
 
 
-# RemovedInDjango50Warning
-class AssertFormErrorDeprecationTests(SimpleTestCase):
-    """
-    Exhaustively test all possible combinations of args/kwargs for the old
-    signature.
-    """
-
-    def _assert_form_error_old_api_cases(self, form, field, errors, msg_prefix):
-        response = mock.Mock(context=[{"form": TestForm.invalid()}])
-        return (
-            ((response, form, field, errors), {}),
-            ((response, form, field, errors, msg_prefix), {}),
-            ((response, form, field, errors), {"msg_prefix": msg_prefix}),
-            ((response, form, field), {"errors": errors}),
-            ((response, form, field), {"errors": errors, "msg_prefix": msg_prefix}),
-            ((response, form), {"field": field, "errors": errors}),
-            (
-                (response, form),
-                {"field": field, "errors": errors, "msg_prefix": msg_prefix},
-            ),
-            ((response,), {"form": form, "field": field, "errors": errors}),
-            (
-                (response,),
-                {
-                    "form": form,
-                    "field": field,
-                    "errors": errors,
-                    "msg_prefix": msg_prefix,
-                },
-            ),
-            (
-                (),
-                {"response": response, "form": form, "field": field, "errors": errors},
-            ),
-            (
-                (),
-                {
-                    "response": response,
-                    "form": form,
-                    "field": field,
-                    "errors": errors,
-                    "msg_prefix": msg_prefix,
-                },
-            ),
-        )
-
-    def test_assert_form_error_old_api(self):
-        deprecation_msg = (
-            "Passing response to assertFormError() is deprecated. Use the form object "
-            "directly: assertFormError(response.context['form'], 'field', ...)"
-        )
-        for args, kwargs in self._assert_form_error_old_api_cases(
-            form="form",
-            field="field",
-            errors=["invalid value"],
-            msg_prefix="Custom prefix",
-        ):
-            with self.subTest(args=args, kwargs=kwargs):
-                with self.assertWarnsMessage(RemovedInDjango50Warning, deprecation_msg):
-                    self.assertFormError(*args, **kwargs)
-
-    @ignore_warnings(category=RemovedInDjango50Warning)
-    def test_assert_form_error_old_api_assertion_error(self):
-        for args, kwargs in self._assert_form_error_old_api_cases(
-            form="form",
-            field="field",
-            errors=["other error"],
-            msg_prefix="Custom prefix",
-        ):
-            with self.subTest(args=args, kwargs=kwargs):
-                with self.assertRaises(AssertionError):
-                    self.assertFormError(*args, **kwargs)
-
-    def _assert_formset_error_old_api_cases(
-        self, formset, form_index, field, errors, msg_prefix
-    ):
-        response = mock.Mock(context=[{"formset": TestFormset.invalid()}])
-        return (
-            ((response, formset, form_index, field, errors), {}),
-            ((response, formset, form_index, field, errors, msg_prefix), {}),
-            (
-                (response, formset, form_index, field, errors),
-                {"msg_prefix": msg_prefix},
-            ),
-            ((response, formset, form_index, field), {"errors": errors}),
-            (
-                (response, formset, form_index, field),
-                {"errors": errors, "msg_prefix": msg_prefix},
-            ),
-            ((response, formset, form_index), {"field": field, "errors": errors}),
-            (
-                (response, formset, form_index),
-                {"field": field, "errors": errors, "msg_prefix": msg_prefix},
-            ),
-            (
-                (response, formset),
-                {"form_index": form_index, "field": field, "errors": errors},
-            ),
-            (
-                (response, formset),
-                {
-                    "form_index": form_index,
-                    "field": field,
-                    "errors": errors,
-                    "msg_prefix": msg_prefix,
-                },
-            ),
-            (
-                (response,),
-                {
-                    "formset": formset,
-                    "form_index": form_index,
-                    "field": field,
-                    "errors": errors,
-                },
-            ),
-            (
-                (response,),
-                {
-                    "formset": formset,
-                    "form_index": form_index,
-                    "field": field,
-                    "errors": errors,
-                    "msg_prefix": msg_prefix,
-                },
-            ),
-            (
-                (),
-                {
-                    "response": response,
-                    "formset": formset,
-                    "form_index": form_index,
-                    "field": field,
-                    "errors": errors,
-                },
-            ),
-            (
-                (),
-                {
-                    "response": response,
-                    "formset": formset,
-                    "form_index": form_index,
-                    "field": field,
-                    "errors": errors,
-                    "msg_prefix": msg_prefix,
-                },
-            ),
-        )
-
-    def test_assert_formset_error_old_api(self):
-        deprecation_msg = (
-            "Passing response to assertFormSetError() is deprecated. Use the formset "
-            "object directly: assertFormSetError(response.context['formset'], 0, ...)"
-        )
-        for args, kwargs in self._assert_formset_error_old_api_cases(
-            formset="formset",
-            form_index=0,
-            field="field",
-            errors=["invalid value"],
-            msg_prefix="Custom prefix",
-        ):
-            with self.subTest(args=args, kwargs=kwargs):
-                with self.assertWarnsMessage(RemovedInDjango50Warning, deprecation_msg):
-                    self.assertFormSetError(*args, **kwargs)
-
-    @ignore_warnings(category=RemovedInDjango50Warning)
-    def test_assert_formset_error_old_api_assertion_error(self):
-        for args, kwargs in self._assert_formset_error_old_api_cases(
-            formset="formset",
-            form_index=0,
-            field="field",
-            errors=["other error"],
-            msg_prefix="Custom prefix",
-        ):
-            with self.subTest(args=args, kwargs=kwargs):
-                with self.assertRaises(AssertionError):
-                    self.assertFormSetError(*args, **kwargs)
-
-
 class FirstUrls:
     urlpatterns = [path("first/", empty_response, name="first")]