.. currentmodule:: factory
Behind the scenes: steps performed when parsing a factory declaration, and when calling it.
This section will be based on the following factory declaration:
.. literalinclude:: ../tests/test_docs_internals.py :pyobject: UserFactory
Parsing, Step 1: Metaclass and type declaration
Python parses the declaration and calls (thanks to the metaclass declaration):
factory.base.BaseFactory.__new__( 'UserFactory', (factory.Factory,), attributes, )
It initializes a :class:`FactoryOptions` object, and links it to the class
Parsing, Step 2: adapting the class definition
- The :class:`FactoryOptions` reads the options from the :attr:`class Meta <Factory.Meta>` declaration
- It finds a few specific pointer (loading the model class, finding the reference factory for the sequence counter, etc.)
- It copies declarations and parameters from parent classes
- It scans current class attributes (from
vars()) to detect pre/post declarations
- Declarations are split among pre-declarations and post-declarations (a raw value shadowing a post-declaration is seen as a post-declaration)
A declaration for
foo__bar will be converted into parameter
Instantiating, Step 1: Converging entrypoints
First, decide the strategy:
- If the entrypoint is specific to a strategy (:meth:`~Factory.build`, :meth:`~Factory.create_batch`, ...), use it
- If it is generic (:meth:`~Factory.generate`, :meth:`Factory.__call__`), use the strategy defined at the :attr:`class Meta <Factory.Meta>` level
Then, we'll pass the strategy and passed-in overrides to the :meth:`~Factory._generate` method.
According to the project roadmap, a future version will use a :meth:`~Factory._generate_batch`` at its core instead.
A factory's :meth:`~Factory._generate` function actually delegates to a
This object will carry the overall "build an object" context (strategy, depth, and possibly other).
Instantiating, Step 2: Preparing values
StepBuildermerges overrides with the class-level declarations
- The sequence counter for this instance is initialized
Resolveris set up with all those declarations, and parses them in order; it will call each value's
evaluate()method, including extra parameters.
- If needed, the
Resolvermight recurse (through the
StepBuilder, e.g when encountering a :class:`SubFactory`.
Instantiating, Step 3: Building the object
StepBuilderfetches the attributes computed by the
- It applies renaming/adjustment rules
- It passes them to the :meth:`FactoryOptions.instantiate` method, which forwards to the proper methods.
- Post-declaration are applied (in declaration order)
This document discusses implementation details; there is no guarantee that the described methods names and signatures will be kept as is.