Search code examples
pythondjangofactory-boy

Wrong inheritance behavior in factory boy factories


I have several factories with structure like this:

AbstractFactoryMinimal(DjangoModelFactory):
    comment = ''

AbstractFactoryFull(AbstractFactoryMinimal):
    comment = Faker(provider='text', max_nb_chars=2000)

FactoryMinimal(AbstractFactoryMinimal):
    field = ''

    class Meta(object):
        model = SomeModel

FactoryFull(FactoryMinimal, AbstractFactoryFull):
    field = Faker(provider='text', max_nb_chars=2000)

obj = FactoryFull()
print(obj.comment) # expect some text from faker, but got '' instead
print(obj.field)   # works like expected, return some random text

In models I have

AbstractModel(TimeStampedModel)

and

SomeModel(AbstractModel)

I even look at mro and it's looks like exactly how I expected it to look:

(FactoryFull,
FactoryMinimal,
AbstractFactoryFull,
AbstractFactoryMinimal,
factory.django.DjangoModelFactory,
factory.base.Factory,
factory.base.BaseFactory,
object)

So "comment" field should be generated by faker and not just set with ''. Why it is work this way? How I can implement factories to see expected behavior?

EDIT: I can change inheritance order in last factory to this:

FactoryFull(AbstractFactoryFull, FactoryMinimal)

it will work but then, if I want to override field in FactoryMinimal it wouldn't work. And sometimes I need exactly this feature. And anyway, this isn't normal inheritance behavior in Python in first place.


Solution

  • So I found some workaround.

    Basically, I change inheritance order and repeat some code. Like this:

    FactoryMinimal(AbstractFactoryMinimal):
        field = ''
    
        class Meta(object):
            model = SomeModel
    
    FactoryFull(AbstractFactoryFull, FactoryMinimal):
        field = Faker(provider='text', max_nb_chars=2000)
    
        class Meta(object):
            model = SomeModel
    

    And if I need to override something from base class I use MixIn class for this:

    CommentFieldMixIn(DjangoModelFactory):
        comment = 'Something Completely Different'
    
    FactoryMinimal(AbstractFactoryMinimal):
        field = ''
    
        class Meta(object):
            model = SomeModel
    
    FactoryFull(CommentFieldMixIn, AbstractFactoryFull, FactoryMinimal):
        field = Faker(provider='text', max_nb_chars=2000)
    
        class Meta(object):
            model = SomeModel
    

    Only one problem remain: how I can say anyone who would maintain my code why I do this in every factory.