Skip to content
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

Allow functions as models #1072

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

instanceofmel
Copy link

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

@rbarrois
Copy link
Member

rbarrois commented Apr 9, 2024

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 ;)

@instanceofmel
Copy link
Author

instanceofmel commented Apr 24, 2024

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

@rbarrois
Copy link
Member

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

@instanceofmel instanceofmel force-pushed the allow-functions-as-models branch 3 times, most recently from 6a0825f to 4712853 Compare April 26, 2024 08:29
@instanceofmel
Copy link
Author

Done @rbarrois

@instanceofmel
Copy link
Author

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

Facilitates the use of a factory function, that may create several
related objects at once.
@instanceofmel
Copy link
Author

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

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

Successfully merging this pull request may close these issues.

2 participants