API

Declarative

class sqlalchemy_model_factory.declarative.DeclarativeMF

Provide an alternative to the class decorator for declarative base factories.

Today there’s no meaningful difference between the decorator and the subclass method, except the interface.

Examples

>>> class ModelFactory(DeclarativeMF):
...    def default(id: int = None):
...        return Foo(id=id)

or

>>> registry = Registry()
>>>
>>> class ModelFactory(DeclarativeMF, registry=registry):
...    def default(id: int = None):
...        return Foo(id=id)
sqlalchemy_model_factory.declarative.declarative(_cls=None, *, registry=None)

Decorate a base object on which factory functions reside.

The primary benefit of declaratively specifying the factory function tree is that it enables references to the factory to be type aware, enabling things like “Go to Definition”.

Note interior classes to the decorator, including both the root class, as well as any nested class or attributes which are raw types, will be instantiated. This is notable, primarily in the event that an __init__ is defined on the class for whatever reason. Each class will be instantiated once without arguments.

Examples

>>> @declarative
... class ModelFactory:
...     class namespace:
...         def fn():
...             ...
>>> from sqlalchemy_model_factory.pytest import create_registry_fixture
>>> mf_registry = create_registry_fixture(ModelFactory)
>>> def test_factory(mf: ModelFactory):
...    ...

Alternatively, a registry can be provided to the decorator directly, if you have one pre-constructed.

>>> registry = Registry()
>>>
>>> @declarative(registry=registry)
... class ModelFactory:
...     def fn():
...         ...

Note due to the dynamic nature of fixtures, you must annotate the fixture argument to have the type of the root, declarative class.

Factory Utilities

sqlalchemy_model_factory.utils.autoincrement(fn=None, *, start=1)

Decorate registered callables to provide them with a source of uniqueness.

Parameters
  • fn (Optional[Callable]) – The callable

  • start (int) – The starting number of the sequence to generate

Examples

>>> @autoincrement
... def new(autoincrement=1):
...     return autoincrement
>>> new()
1
>>> new()
2
>>> @autoincrement(start=4)
... def new(autoincrement=1):
...     return autoincrement
>>> new()
4
>>> new()
5
class sqlalchemy_model_factory.utils.fluent(fn, signature=None, pending_args=None)

Decorate a function with fluent to enable it to be called in a “fluent” style.

Examples

>>> @fluent
... def foo(a, b=None, *args, c=3, **kwargs):
...     print(f'(a={a}, b={b}, c={c}, args={args}, kwargs={kwargs})')
>>> foo.kwargs(much=True, surprise='wow').a(4).bind()
(a=4, b=None, c=3, args=(), kwargs={'much': True, 'surprise': 'wow'})
>>> foo.args(True, 'wow').a(5).bind()
(a=5, b=None, c=3, args=(True, 'wow'), kwargs={})
>>> partial = foo.a(1)
>>> partial.b(5).bind()
(a=1, b=5, c=3, args=(), kwargs={})
>>> partial.b(6).bind()
(a=1, b=6, c=3, args=(), kwargs={})
bind(*, call_before=None, call_after=None)

Finalize the call chain for a fluently called factory.

Parameters
  • call_before (Optional[Callable]) – When provided, calls the given callable, supplying the args and kwargs being sent into the factory function before actually calling it. If the call_before function returns anything, the 2-tuple of (args, kwargs) will be replaced with the ones passed into the call_before function.

  • call_after (Optional[Callable]) – When provided, calls the given callable, supplying the result of the factory function call after having called it. If the call_after function returns anything, the result of call_after will be replaced with the result of the factory function.

sqlalchemy_model_factory.utils.for_model(typ)

Decorate a factory that returns a Mapping type in order to coerce it into the typ.

This decorator is only invoked in the context of model factory usage. The intent is that a factory function could be more generally useful, such as to create API inputs, that also happen to correspond to the creation of a model when invoked during a test.

Examples

>>> class Model:
...     def __init__(self, **kwargs):
...         self.kw = kwargs
...
...     def __repr__(self):
...         return f"Model(a={self.kw['a']}, b={self.kw['b']}, c={self.kw['c']})"
>>> @for_model(Model)
... def new_model(a, b, c):
...     return {'a': a, 'b': b, 'c': c}
>>> new_model(1, 2, 3)
{'a': 1, 'b': 2, 'c': 3}
>>> new_model.for_model(1, 2, 3)
Model(a=1, b=2, c=3)

Pytest Plugin

A pytest plugin as a simplified way to use the ModelFactory.

General usage requires the user to define either a mf_engine or a mf_session fixture. Once defined, they can have their tests depend on the exposed mf fixture, which should give them access to any factory functions on which they’ve called register_at.

sqlalchemy_model_factory.pytest.mf(mf_registry, mf_session, mf_config)

Define a fixture for use of the ModelFactory in tests.

sqlalchemy_model_factory.pytest.mf_config()

Define a default fixture in for the model factory configuration.

sqlalchemy_model_factory.pytest.mf_engine()

Define a default fixture in for the database engine.

sqlalchemy_model_factory.pytest.mf_registry()

Define a default fixture for the general case where the default registry is used.

sqlalchemy_model_factory.pytest.mf_session(mf_engine)

Define a default fixture in for the session, in case the user defines only mf_engine.

class sqlalchemy_model_factory.pytest.pytest

Guard against pytest not being installed.

The below function will simply act as a normal function if pytest is not installed.