diff --git a/django/contrib/auth/signals.py b/django/contrib/auth/signals.py index 6415da45fa..ed669f9c6e 100644 --- a/django/contrib/auth/signals.py +++ b/django/contrib/auth/signals.py @@ -1,5 +1,5 @@ from django.dispatch import Signal -user_logged_in = Signal(providing_args=['request', 'user']) -user_login_failed = Signal(providing_args=['credentials', 'request']) -user_logged_out = Signal(providing_args=['request', 'user']) +user_logged_in = Signal() +user_login_failed = Signal() +user_logged_out = Signal() diff --git a/django/core/signals.py b/django/core/signals.py index c4288edeb5..960f5c355b 100644 --- a/django/core/signals.py +++ b/django/core/signals.py @@ -1,6 +1,6 @@ from django.dispatch import Signal -request_started = Signal(providing_args=["environ", "scope"]) +request_started = Signal() request_finished = Signal() -got_request_exception = Signal(providing_args=["request"]) -setting_changed = Signal(providing_args=["setting", "value", "enter"]) +got_request_exception = Signal() +setting_changed = Signal() diff --git a/django/db/backends/signals.py b/django/db/backends/signals.py index c16a63f9f6..a8079d0d76 100644 --- a/django/db/backends/signals.py +++ b/django/db/backends/signals.py @@ -1,3 +1,3 @@ from django.dispatch import Signal -connection_created = Signal(providing_args=["connection"]) +connection_created = Signal() diff --git a/django/db/models/signals.py b/django/db/models/signals.py index 3b20874148..d14eaaf91d 100644 --- a/django/db/models/signals.py +++ b/django/db/models/signals.py @@ -3,7 +3,7 @@ from functools import partial from django.db.models.utils import make_model_tuple from django.dispatch import Signal -class_prepared = Signal(providing_args=["class"]) +class_prepared = Signal() class ModelSignal(Signal): @@ -34,20 +34,16 @@ class ModelSignal(Signal): ) -pre_init = ModelSignal(providing_args=["instance", "args", "kwargs"], use_caching=True) -post_init = ModelSignal(providing_args=["instance"], use_caching=True) +pre_init = ModelSignal(use_caching=True) +post_init = ModelSignal(use_caching=True) -pre_save = ModelSignal(providing_args=["instance", "raw", "using", "update_fields"], - use_caching=True) -post_save = ModelSignal(providing_args=["instance", "raw", "created", "using", "update_fields"], use_caching=True) +pre_save = ModelSignal(use_caching=True) +post_save = ModelSignal(use_caching=True) -pre_delete = ModelSignal(providing_args=["instance", "using"], use_caching=True) -post_delete = ModelSignal(providing_args=["instance", "using"], use_caching=True) +pre_delete = ModelSignal(use_caching=True) +post_delete = ModelSignal(use_caching=True) -m2m_changed = ModelSignal( - providing_args=["action", "instance", "reverse", "model", "pk_set", "using"], - use_caching=True, -) +m2m_changed = ModelSignal(use_caching=True) -pre_migrate = Signal(providing_args=["app_config", "verbosity", "interactive", "using", "apps", "plan"]) -post_migrate = Signal(providing_args=["app_config", "verbosity", "interactive", "using", "apps", "plan"]) +pre_migrate = Signal() +post_migrate = Signal() diff --git a/django/dispatch/dispatcher.py b/django/dispatch/dispatcher.py index 910024371b..b7d9d26389 100644 --- a/django/dispatch/dispatcher.py +++ b/django/dispatch/dispatcher.py @@ -1,6 +1,8 @@ import threading +import warnings import weakref +from django.utils.deprecation import RemovedInDjango40Warning from django.utils.inspect import func_accepts_kwargs @@ -28,14 +30,16 @@ class Signal: def __init__(self, providing_args=None, use_caching=False): """ Create a new signal. - - providing_args - A list of the arguments this signal can pass along in a send() call. """ self.receivers = [] - if providing_args is None: - providing_args = [] - self.providing_args = set(providing_args) + if providing_args is not None: + warnings.warn( + 'The providing_args argument is deprecated. As it is purely ' + 'documentational, it has no replacement. If you rely on this ' + 'argument as documentation, you can move the text to a code ' + 'comment or docstring.', + RemovedInDjango40Warning, stacklevel=2, + ) self.lock = threading.Lock() self.use_caching = use_caching # For convenience we create empty caches even if they are not used. @@ -187,9 +191,7 @@ class Signal: occur). named - Named arguments which will be passed to receivers. These - arguments must be a subset of the argument names defined in - providing_args. + Named arguments which will be passed to receivers. Return a list of tuple pairs [(receiver, response), ... ]. diff --git a/django/test/signals.py b/django/test/signals.py index 3503fc08e1..2ddb425f4c 100644 --- a/django/test/signals.py +++ b/django/test/signals.py @@ -14,7 +14,7 @@ from django.utils import timezone from django.utils.formats import FORMAT_SETTINGS, reset_format_cache from django.utils.functional import empty -template_rendered = Signal(providing_args=["template", "context"]) +template_rendered = Signal() # Most setting_changed receivers are supposed to be added below, # except for cases where the receiver is related to a contrib app. diff --git a/django/utils/autoreload.py b/django/utils/autoreload.py index d5445e5f3f..845c46c8d4 100644 --- a/django/utils/autoreload.py +++ b/django/utils/autoreload.py @@ -21,7 +21,7 @@ from django.utils.functional import cached_property from django.utils.version import get_version_tuple autoreload_started = Signal() -file_changed = Signal(providing_args=['file_path', 'kind']) +file_changed = Signal() DJANGO_AUTORELOAD_ENV = 'RUN_MAIN' diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt index 3774afa59e..a56730aef7 100644 --- a/docs/internals/deprecation.txt +++ b/docs/internals/deprecation.txt @@ -58,6 +58,9 @@ details on these changes. ``django.utils.deprecation.MiddlewareMixin.__init__()`` will be required and won't accept ``None``. +* The ``providing_args`` argument for ``django.dispatch.Signal`` will be + removed. + See the :ref:`Django 3.1 release notes ` for more details on these changes. diff --git a/docs/releases/3.1.txt b/docs/releases/3.1.txt index b1ae1134cb..88b355c9cf 100644 --- a/docs/releases/3.1.txt +++ b/docs/releases/3.1.txt @@ -546,6 +546,11 @@ Miscellaneous older versions of Django. Support for the old format remains until Django 4.0. +* The purely documentational ``providing_args`` argument for + :class:`~django.dispatch.Signal` is deprecated. If you rely on this + argument as documentation, you can move the text to a code comment or + docstring. + .. _removed-features-3.1: Features removed in 3.1 diff --git a/docs/topics/signals.txt b/docs/topics/signals.txt index ee097f9faa..30c8299fae 100644 --- a/docs/topics/signals.txt +++ b/docs/topics/signals.txt @@ -216,24 +216,17 @@ its own signals. Defining signals ---------------- -.. class:: Signal(providing_args=list) +.. class:: Signal() -All signals are :class:`django.dispatch.Signal` instances. The -``providing_args`` is a list of the names of arguments the signal will provide -to listeners. This is purely documentational, however, as there is nothing that -checks that the signal actually provides these arguments to its listeners. +All signals are :class:`django.dispatch.Signal` instances. For example:: import django.dispatch - pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"]) + pizza_done = django.dispatch.Signal() -This declares a ``pizza_done`` signal that will provide receivers with -``toppings`` and ``size`` arguments. - -Remember that you're allowed to change this list of arguments at any time, so -getting the API right on the first try isn't necessary. +This declares a ``pizza_done`` signal. Sending signals --------------- diff --git a/tests/dispatch/tests.py b/tests/dispatch/tests.py index 2377dcff8a..9b5482ed58 100644 --- a/tests/dispatch/tests.py +++ b/tests/dispatch/tests.py @@ -29,10 +29,10 @@ class Callable: return val -a_signal = Signal(providing_args=["val"]) -b_signal = Signal(providing_args=["val"]) -c_signal = Signal(providing_args=["val"]) -d_signal = Signal(providing_args=["val"], use_caching=True) +a_signal = Signal() +b_signal = Signal() +c_signal = Signal() +d_signal = Signal(use_caching=True) class DispatcherTests(SimpleTestCase): diff --git a/tests/signals/test_deprecation.py b/tests/signals/test_deprecation.py new file mode 100644 index 0000000000..b961dafd8a --- /dev/null +++ b/tests/signals/test_deprecation.py @@ -0,0 +1,22 @@ +import warnings + +from django.dispatch import Signal +from django.test import SimpleTestCase +from django.utils.deprecation import RemovedInDjango40Warning + + +class SignalDeprecationTests(SimpleTestCase): + def test_providing_args_warning(self): + msg = ( + 'The providing_args argument is deprecated. As it is purely ' + 'documentational, it has no replacement. If you rely on this ' + 'argument as documentation, you can move the text to a code ' + 'comment or docstring.' + ) + with self.assertWarnsMessage(RemovedInDjango40Warning, msg): + Signal(providing_args=['arg1', 'arg2']) + + def test_without_providing_args_does_not_warn(self): + with warnings.catch_warnings(record=True) as recorded: + Signal() + self.assertEqual(len(recorded), 0)