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

naming model factory functions #225

Open
drobert opened this issue Oct 4, 2024 · 2 comments
Open

naming model factory functions #225

drobert opened this issue Oct 4, 2024 · 2 comments

Comments

@drobert
Copy link

drobert commented Oct 4, 2024

Non-standard but supported use case in FactoryBoy is using a factory function for the 'model' definition, e.g.:

def _some_factory_func(*args, **kwargs):
  # do some cleanup/advanced logic around the args, e.g.
  if "foo" in kwargs:
    def kwargs["bar"] # contrived example
  return MyModel(*args, **kwargs)
  
@register
@register(_name="my_model") # has no effect
class MyModelFactory(Factory):
  class Meta:
    model: _some_factory_func # this line

  prop1 = ...
  prop2 = ...

elsewhere I have register(MyModelFactory) in a conftest.py file

What pytest sees as registered fixtures include:

  • _some_factory_func
  • _some_factory_func__prop1
  • _some_factory_func__prop2
  • my_model_factory

This does not seem to change even if I use @register(_name="my_model"); the name ultimately renames _some_factory_func.

Similarly, named_model does not succeed as it assumes the model is a type.

Request here is to support a factory function with a model name.

@youtux
Copy link
Contributor

youtux commented Oct 5, 2024

We use model.__name__ to determine the fixture name.

try reassigning _ some_factory_func.__name__ = “MyModel”, it may solve your use case.

I will reopen this if unresolved.

@youtux youtux closed this as completed Oct 5, 2024
@drobert
Copy link
Author

drobert commented Oct 7, 2024

Can you expand on your solution?

In python, you cannot set .__name__ on a top-level function, or else imports would fail.

I've attempted to wrap this one layer:

def _mk_factory():
  def factory(*args, **kwargs) -> MyModel:
    # ...
    return MyModel(...)
   
  factory.__name__ = "MyModel"
  return factory

renamed = _mk_factory()

class MyModelFactory(Factory):
  class Meta:
    model: renamed

But this fails in pytest with TypeError: issubclass() arg 1 must be a class. I've tried something similar using types.FunctionType(_some_factory_func.__code__, _some_factory_func.__globals__, name="MyModel") to the same effect.

Regardless, I don't feel like this ticket should necessarily be 'closed' even if this thread results in a usable syntax (which it thus far has not). At the least this behavior was non-obvious, but it also feels inconsistent. There is built-in support for this for dict using named_model; it would be nice to have a similar utility with function. It also feels awkward at best that @register(_name="...") did not have any effect when using a function.

@youtux youtux reopened this Oct 7, 2024
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