New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question about @mute_signals with @post_generation function #183

Closed
romgar opened this Issue Feb 10, 2015 · 0 comments

Comments

Projects
None yet
1 participant
@romgar

romgar commented Feb 10, 2015

Hi,

I'm experiencing some troublesome issue when using @mute_signals decorator and custom code in a @post_generation function.

That's my current base factory, and all other factories are inheriting from this one to mute signals in every ones :

import factory
from django.db.models import signals

from my_app.models import MyModel

@factory.django.mute_signals(signals.pre_save, signals.post_save)
class BaseFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = MyModel

Then I have created other factories that are subclasses of BaseFactory, and everything works fine: signals are perfectly muted/restored.
Except on that special factory :

class MyClassWithPostGenerationFactory(BaseFactory):

    @factory.post_generation
    def my_post_generation_function(self, create, extracted, **kwargs):
        AnotherFactory.create(fkey=self)

class AnotherFactory(BaseFactory):
    pass

Signals are correctly muted, but are not restored after MyClassWithPostGenerationFactory.create() call.

I have tried to guess what was happening in @mute_signals, and I have discovered that signal receivers were saved in a class attribute (self.paused), that can be a problem in this nested factory situation :

  1. Entering MyClassWithPostGenerationFactory
    • Calling __ enter __() on @mute_signals
    • signals.receivers are saved in self.paused => OK (self.paused = {signal: receivers_list, ...})
    • setting signal.receivers to [] to mute them => OK (self.paused = {signal: receivers_list], signal.receivers = [])
  2. Entering AnotherFactory on @post_generation
    • Calling __ enter __() on @mute_signals
    • signal.receivers is empty for each signal (from last step of 1.), and saved in self.paused => NOK (self.paused = {})
    • setting signal.receivers to [] to mute them => NOK (self.paused = {}, signal.receivers = [])
  3. Getting out of AnotherFactory
    • Calling __ exit __() on @mute_signals
    • Setting back signal.receivers with saved self.paused, which is empty => NOK (self.paused = {}, signal.receivers = [])
  4. Getting out of MyClassWithPostGenerationFactory
    • Calling __ exit __() on @mute_signals
    • Setting back signal.receivers with saved self.paused, which is empty => NOK (self.paused = {}, signal.receivers = [])

But maybe I'm not doing something well ?
It is not a good idea to call factories in a @post_generate ?

Currently, I have subclassed @mute_signals decorator and updated self.paused to manage signals saving depending on nested 'depth', to be sure that we are not erasing parent signal savings.
It's working as expected now, but not sure that's the most elegant way to do.

Any advices about that ?

@rbarrois rbarrois closed this in 72fd943 Mar 26, 2015

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment