factory_boy icon indicating copy to clipboard operation
factory_boy copied to clipboard

Allow functions as models

Open instanceofmel opened this issue 1 year ago • 7 comments

Hi,

in our project, we're using factories for our models:

# domain/factories.py
from . import model, events

def item_factory(sku: str, price: float):
    obj = model.Item(sku, price)
    obj.events.append(events.ItemCreated())
    return obj

Now, in our tests we want factory boy to call those factories instead of the model classes directly, which works perfectly except in this case:

# tests/factories.py
class ItemFactory(factory.Factory):
    class Meta:
        model = factories.item_factory
    sku = ...
    price = ...

class SpecialItemFactory(ItemFactory):  # Inherits from the factory above
    sku = "special"

When a factory inherits from another factory, FactoryOptions._get_counter_reference expects the assigned model to be a class, because issubclass raises:

TypeError: issubclass() arg 1 must be a class

We couldn't find a fix for this case so I've opened this PR. If my solution is wrong or if anything is missing in my commit, please don't hesitate to let me know.

BR

instanceofmel avatar Apr 09 '24 09:04 instanceofmel

Hello,

Thanks for the feedback! That's indeed likely to be a bug.

Would it be possible to have a minimal example of code where this breaks, to add to our test suite?

NB: This is one of the reasons why I prefer to see an issue first, before jumping in the code — our issue templates make it easier for us to gather all details we need to move forward ;)

rbarrois avatar Apr 09 '24 17:04 rbarrois

Hey, sorry for the late reply. You mean something like this?

import factory


class Item:
    def __init__(self, sku, price):
        self.sku = sku
        self.price = price


def item_factory(sku, price):
    obj = model.Item(sku, price)
    return obj


class ItemFactory(factory.Factory):
    class Meta:
        model = item_factory

    sku = "foo"
    price = "bar"


class SpecialItemFactory(ItemFactory):
    sku = "special"


item = SpecialItemFactory()  # TypeError: issubclass() arg 1 must be a class

Should I add a test case to the test suite?

BR

instanceofmel avatar Apr 24 '24 11:04 instanceofmel

Yes please! That's exactly what I had in mind ;)

rbarrois avatar Apr 25 '24 08:04 rbarrois

Done @rbarrois

instanceofmel avatar Apr 26 '24 08:04 instanceofmel

@rbarrois Could you please merge this when you have a chance? Thank you.

instanceofmel avatar May 21 '24 10:05 instanceofmel

Hi @rbarrois, let me know if there's anything left to do for me in order to get this merged 🙏

instanceofmel avatar Oct 10 '24 15:10 instanceofmel