Opened 10 hours ago
#36600 new Bug
Misleading wording in description of dispatch_uid
Reported by: | Roman Donchenko | Owned by: | |
---|---|---|---|
Component: | Documentation | Version: | 5.2 |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
The documentation for signals currently says the following:
In some circumstances, the code connecting receivers to signals may run multiple times. This can cause your receiver function to be registered more than once, and thus called as many times for a signal event. For example, the
ready()
method may be executed more than once during testing. More generally, this occurs everywhere your project imports the module where you define the signals, because signal registration runs as many times as it is imported.
There are a few problems here. First, the last sentence just seems wrong. Importing a module multiple times does not run its code multiple times; therefore it should be completely safe to do this with a module containing signal handlers.
It seems that dispatch_uid
was originally introduced to work around a problem where a module would be imported multiple times with different names (#3951), but that problem has long been fixed (#15372).
Moreover, even if the signal handler is registered directly in ready()
, and ready()
is called multiple times, it appears that in many cases dispatch_uid
is still unnecessary. When it's unspecified, the implementation effectively uses a default dispatch_uid
of (id(target.__self__), id(target.__func__))
when the target is a method, or id(target)
in all other cases. This means that code like this should work fine:
def my_handler(): ... class MyAppConfig(AppConfig): def ready(self): my_signal.connect(my_handler)
However, this is not explained in the docs.
Because of these problems, the docs end up encouraging users to use dispatch_uid
everywhere, even though it's really only necessary in some specific cases (i.e., when the handler is not a global function or a static/class method of a global class). I think they should be edited to explain the use case more clearly.