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

Conditional kwargs not working for nested factories #533

Open
fdegiuli opened this issue Oct 27, 2018 · 2 comments
Open

Conditional kwargs not working for nested factories #533

fdegiuli opened this issue Oct 27, 2018 · 2 comments

Comments

@fdegiuli
Copy link

Description

This seems to be a continuation of #466

It seems like defining a trait will let you pass kwargs, but only one level deep.
Here is an example:

To Reproduce

import factory


class Thing(object):
    def __init__(self, nested=None):
        self.nested = nested or []


class ThingFactory(factory.Factory):
    class Meta:
        model = Thing

    class Params:
        with_nested = factory.Trait(
            nested__count=1,
            nested__nested__count=1
        )

    @factory.post_generation
    def nested(obj, create, extracted, count=0, **kwargs):
        if not create:
            return

        if count > 0:
            obj.nested = ThingFactory.create_batch(count, **kwargs)


if __name__ == '__main__':
    value = ThingFactory()

This (naturally) fails:

Traceback (most recent call last):
  File "test.py", line 29, in <module>
    value = ThingFactory()
  File "/usr/local/lib/python3.6/site-packages/factory/base.py", line 46, in __call__
    return cls.create(**kwargs)
  File "/usr/local/lib/python3.6/site-packages/factory/base.py", line 563, in create
    return cls._generate(enums.CREATE_STRATEGY, kwargs)
  File "/usr/local/lib/python3.6/site-packages/factory/base.py", line 500, in _generate
    return step.build()
  File "/usr/local/lib/python3.6/site-packages/factory/builder.py", line 288, in build
    context=declaration.context,
  File "/usr/local/lib/python3.6/site-packages/factory/declarations.py", line 41, in unroll_context
    return step.recurse(subfactory, context, force_sequence=step.sequence)
  File "/usr/local/lib/python3.6/site-packages/factory/builder.py", line 233, in recurse
    return builder.build(parent_step=self, force_sequence=force_sequence)
  File "/usr/local/lib/python3.6/site-packages/factory/builder.py", line 257, in build
    base_post=self.factory_meta.post_declarations,
  File "/usr/local/lib/python3.6/site-packages/factory/builder.py", line 198, in parse_declarations
    for k, v in extra_maybenonpost.items()
  File "/usr/local/lib/python3.6/site-packages/factory/builder.py", line 92, in update
    sorted(self.declarations),
factory.errors.InvalidDeclarationError: Received deep context for unknown fields: 
{'nested__count': Maybe(<SelfAttribute('with_nested', default=False)>, yes=1, no=<factory.declarations.Skip object at 0x1068cdf28>)} 
(known=['count'])

It seems like the second param isn't being extracted properly. I don't understand the code well enough to diagnose exactly why this happens, so I won't put any half-baked theories in here.

The issue

I think this issue is a symptom of a deeper problem: there's no standard way to override the arguments passed to a post_generation hook. (I don't know if this is also the case for subfactories.)
Doing it in a Trait seems a little dirty, since (at least according to the docs) it's meant to override fields.
It seems like it could belong in _alter_kwargs(), but it that method doesn't actually alter the raw kwargs.
If it's meant to stay in a Trait, updating the docs to reflect that would be very helpful.

@fdegiuli
Copy link
Author

Possibly related to #550 as well.

@roman-karpovich
Copy link

same issue for me. after migration from 2.8.0 to 2.11.1 all traits seems broken. i widely used deep arguments in code to provide additional context in dependency of object status.

for example

    class Params:
            reported = Trait(
                report_attachments__count=1,
                report_attachments__file_type__name='report',
            )

Does any way exists to refactor code without bloody mess?

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

No branches or pull requests

2 participants