Add functionality to mute specific receivers of signals (not just all signals)
The problem
As described at https://factoryboy.readthedocs.io/en/latest/orms.html#disabling-signals, it is possible to mute all signals of a certain type using the factory.django.mute_signals decorator. In my use case, hwoever, I have a specific receiver of post_save signals which calls an external API, and I would like to mute only this receiver (and not all post_save signals).
Proposed solution
We could write a mute_receivers decorator/context manager along the lines of mute_signals which does this.
Hi,
I understand the interest of that suggestion; however, I feel that the mute_signals helper is already quite complex, and would rather avoid adding more of those helpers in the codebase.
Do you have some example of what such a mute_receivers decorator/context manager would look like?
I had this problem too and solved it by overriding _create factory method:
@receiver(post_save, sender=MyModel)
def signal_handler(sender, instance, **kwargs):
...
class MyModelFactory(factory.DjangoModelFactory):
class Meta:
model = MyModel
@classmethod
def _create(cls, *args, **kwargs):
post_save.disconnect(signal_handler, sender=MyModel)
try:
instance = super()._create(*args, **kwargs)
finally:
post_save.connect(signal_handler, sender=MyModel)
return instance
Is there a way to utilize the above _create overwrite but at the same time using Param? Can I access a Param in _create?
I'd to implement a context manager to mute a specific receiver and restore it after the block of code is executed.
from contextlib import contextmanager
from django.dispatch import Signal
from typing import Any, Type
@contextmanager
def muted_receiver(
signal: Type[Signal],
receiver: callable,
sender: Any,
dispatch_uid=None,
weak: bool = True,
failsafe=False,
):
disconnected = signal.disconnect(
receiver=receiver,
sender=sender,
dispatch_uid=dispatch_uid,
)
if not disconnected and not failsafe:
raise ValueError(f"Couldn't disconnect {signal}.")
yield
# restore the signal
signal.connect(
receiver=receiver,
sender=sender,
weak=weak,
dispatch_uid=dispatch_uid,
)
assert receiver in signal._live_receivers(sender=sender)