pytest-factoryboy icon indicating copy to clipboard operation
pytest-factoryboy copied to clipboard

Problems with Maybe / Trait when defined in Params

Open MRigal opened this issue 3 years ago • 3 comments

Especially with FactoryBoy 3.2. See failing tests in https://github.com/pytest-dev/pytest-factoryboy/pull/125

MRigal avatar Jun 24 '21 10:06 MRigal

I'm still facing this issue:

AttributeError: 'Maybe' object has no attribute 'call'


request = <SubRequest 'timesheet' for <Function test_can_include_date>>

    def deferred(request):
>       declaration.call(instance, step, context)
E       AttributeError: 'Maybe' object has no attribute 'call'

../.venv/lib/python3.9/site-packages/pytest_factoryboy/fixture.py:294: AttributeError

Debugging info:

(Pdb) declaration
Maybe(<SelfAttribute('has_entries', default=False)>, yes=<factory.declarations.RelatedFactoryList object at 0x7ffb03b409d0>, no=<factory.declarations.Skip object at 0x7ffb23dcc160>)
(Pdb) type(step)
<class 'factory.builder.BuildStep'>
(Pdb) context
PostGenerationContext(value_provided=True, value=Maybe(<SelfAttribute('has_entries', default=False)>, yes=<factory.declarations.RelatedFactoryList object at 0x7ffb03b409d0>, no=<factory.declarations.Skip object at 0x7ffb23dcc160>), extra={})

Versions in my environment:

factory-boy==3.2.0
pytest==6.2.5
pytest-django==4.4.0
pytest-factoryboy==2.1.0

elgin9507 avatar Sep 12 '21 09:09 elgin9507

I also encountered the same event.

The factory I defined is the one that contains the RelatedFactory in the Trait.

as follows:

import factory

class UserFactory(factory.Factory):
    class Meta:
        model = User

    id = 1

class BookFactory(factory.Factory):
    class Meta:
        model = Book

    class Params:
        user_r = factory.Trait(
            users=factory.RelatedFactoryList("factories.UserFactory"),
            factory_related_name="id",
            size=10,
        )

    name = "book name"

I am not sure about the details of the implementation, but it worked locally by modifying the conditional expression for the decl object in the following location.

https://github.com/pytest-dev/pytest-factoryboy/blob/78844d9f7b97047b94348066933f73f75854839c/pytest_factoryboy/fixture.py#L403

if isinstance(decl, (factory.RelatedFactory, factory.Maybe)):

If the corrections above are sufficient to address the issue, then please fix it!

satodaiki avatar Aug 01 '22 05:08 satodaiki

It's really hard to properly handle Maybe (and also Trait because under the hood it uses as_declarations to override affected fields with Maybe - reference). To properly generate fixtures for Maybe we need to somehow generate a proper dependencies chain, which is really hard, because Maybe.decider can be computed from anything using some declaration, however, the most commonly used are probably the following ones:

  • SimpleParameter (in the case of Trait)
  • SelfAttribute
  • LazyAttribute

Maybes can be also nested, which makes implementation even more complicated.

If you have any idea how to add support for Maybe and/or Params to our code, please share it here!

skarzi avatar Aug 07 '22 13:08 skarzi