summaryrefslogtreecommitdiff
path: root/docs/reference.rst
diff options
context:
space:
mode:
Diffstat (limited to 'docs/reference.rst')
-rw-r--r--docs/reference.rst233
1 files changed, 228 insertions, 5 deletions
diff --git a/docs/reference.rst b/docs/reference.rst
index b5ccd16..a060f75 100644
--- a/docs/reference.rst
+++ b/docs/reference.rst
@@ -11,6 +11,9 @@ For internals and customization points, please refer to the :doc:`internals` sec
The :class:`Factory` class
--------------------------
+Meta options
+""""""""""""
+
.. class:: FactoryOptions
.. versionadded:: 2.4.0
@@ -90,7 +93,7 @@ The :class:`Factory` class
model = Order
exclude = ('now',)
- now = factory.LazyAttribute(lambda o: datetime.datetime.utcnow())
+ now = factory.LazyFunction(datetime.datetime.utcnow)
started_at = factory.LazyAttribute(lambda o: o.now - datetime.timedelta(hours=1))
paid_at = factory.LazyAttribute(lambda o: o.now - datetime.timedelta(minutes=50))
@@ -108,7 +111,7 @@ The :class:`Factory` class
.. attribute:: rename
- Sometimes, a model expect a field with a name already used by one
+ Sometimes, a model expects a field with a name already used by one
of :class:`Factory`'s methods.
In this case, the :attr:`rename` attributes allows to define renaming
@@ -135,11 +138,16 @@ The :class:`Factory` class
+Attributes and methods
+""""""""""""""""""""""
+
+
.. class:: Factory
**Class-level attributes:**
+ .. attribute:: Meta
.. attribute:: _meta
.. versionadded:: 2.4.0
@@ -147,6 +155,14 @@ The :class:`Factory` class
The :class:`FactoryOptions` instance attached to a :class:`Factory` class is available
as a :attr:`_meta` attribute.
+ .. attribute:: Params
+
+ .. versionadded:: 2.7.0
+
+ The extra parameters attached to a :class:`Factory` are declared through a :attr:`Params`
+ class.
+ See :ref:`the "Parameters" section <parameters>` for more information.
+
.. attribute:: _options_class
.. versionadded:: 2.4.0
@@ -353,6 +369,175 @@ The :class:`Factory` class
factory in the chain.
+.. _parameters:
+
+Parameters
+""""""""""
+
+.. versionadded:: 2.7.0
+
+Some models have many fields that can be summarized by a few parameters; for instance,
+a train with many cars — each complete with serial number, manufacturer, ...;
+or an order that can be pending/shipped/received, with a few fields to describe each step.
+
+When building instances of such models, a couple of parameters can be enough to determine
+all other fields; this is handled by the :class:`~Factory.Params` section of a :class:`Factory` declaration.
+
+
+Simple parameters
+~~~~~~~~~~~~~~~~~
+
+Some factories only need little data:
+
+.. code-block:: python
+
+ class ConferenceFactory(factory.Factory):
+ class Meta:
+ model = Conference
+
+ class Params:
+ duration = 'short' # Or 'long'
+
+ start_date = factory.fuzzy.FuzzyDate()
+ end_date = factory.LazyAttribute(
+ lambda o: o.start_date + datetime.timedelta(days=2 if o.duration == 'short' else 7)
+ )
+ sprints_start = factory.LazyAttribute(
+ lambda o: o.end_date - datetime.timedelta(days=0 if o.duration == 'short' else 1)
+ )
+
+.. code-block:: pycon
+
+ >>> Conference(duration='short')
+ <Conference: DUTH 2015 (2015-11-05 - 2015-11-08, sprints 2015-11-08)>
+ >>> Conference(duration='long')
+ <Conference: DjangoConEU 2016 (2016-03-30 - 2016-04-03, sprints 2016-04-02)>
+
+
+Any simple parameter provided to the :class:`Factory.Params` section is available to the whole factory,
+but not passed to the final class (similar to the :attr:`~FactoryOptions.exclude` behavior).
+
+
+Traits
+~~~~~~
+
+.. class:: Trait(**kwargs)
+
+ .. OHAI VIM**
+
+ .. versionadded:: 2.7.0
+
+ A trait's parameters are the fields it sohuld alter when enabled.
+
+
+For more complex situations, it is helpful to override a few fields at once:
+
+.. code-block:: python
+
+ class OrderFactory(factory.Factory):
+ class Meta:
+ model = Order
+
+ state = 'pending'
+ shipped_on = None
+ shipped_by = None
+
+ class Params:
+ shipped = factory.Trait(
+ state='shipped',
+ shipped_on=datetime.date.today,
+ shipped_by=factory.SubFactory(EmployeeFactory),
+ )
+
+Such a :class:`Trait` is activated or disabled by a single boolean field:
+
+
+.. code-block:: pycon
+
+ >>> OrderFactory()
+ <Order: pending>
+ Order(state='pending')
+ >>> OrderFactory(shipped=True)
+ <Order: shipped by John Doe on 2016-04-02>
+
+
+A :class:`Trait` can be enabled/disabled by a :class:`Factory` subclass:
+
+.. code-block:: python
+
+ class ShippedOrderFactory(OrderFactory):
+ shipped = True
+
+
+Values set in a :class:`Trait` can be overridden by call-time values:
+
+.. code-block:: pycon
+
+ >>> OrderFactory(shipped=True, shipped_on=last_year)
+ <Order: shipped by John Doe on 2015-04-20>
+
+
+:class:`Traits <Trait>` can be chained:
+
+.. code-block:: python
+
+ class OrderFactory(factory.Factory):
+ class Meta:
+ model = Order
+
+ # Can be pending/shipping/received
+ state = 'pending'
+ shipped_on = None
+ shipped_by = None
+ received_on = None
+ received_by = None
+
+ class Params:
+ shipped = factory.Trait(
+ state='shipped',
+ shipped_on=datetime.date.today,
+ shipped_by=factory.SubFactory(EmployeeFactory),
+ )
+ received = factory.Trait(
+ shipped=True,
+ state='received',
+ shipped_on=datetime.date.today - datetime.timedelta(days=4),
+ received_on=datetime.date.today,
+ received_by=factory.SubFactory(CustomerFactory),
+ )
+
+.. code-block:: pycon
+
+ >>> OrderFactory(received=True)
+ <Order: shipped by John Doe on 2016-03-20, received by Joan Smith on 2016-04-02>
+
+
+
+A :class:`Trait` might be overridden in :class:`Factory` subclasses:
+
+.. code-block:: python
+
+ class LocalOrderFactory(OrderFactory):
+
+ class Params:
+ received = factory.Trait(
+ shipped=True,
+ state='received',
+ shipped_on=datetime.date.today - datetime.timedelta(days=1),
+ received_on=datetime.date.today,
+ received_by=factory.SubFactory(CustomerFactory),
+ )
+
+
+.. code-block:: pycon
+
+ >>> LocalOrderFactory(received=True)
+ <Order: shipped by John Doe on 2016-04-01, received by Joan Smith on 2016-04-02>
+
+
+.. note:: When overriding a :class:`Trait`, the whole declaration **MUST** be replaced.
+
+
.. _strategies:
Strategies
@@ -551,6 +736,42 @@ Faker
smiley = factory.Faker('smiley')
+LazyFunction
+""""""""""""
+
+.. class:: LazyFunction(method_to_call)
+
+The :class:`LazyFunction` is the simplest case where the value of an attribute
+does not depend on the object being built.
+
+It takes as argument a method to call (function, lambda...); that method should
+not take any argument, though keyword arguments are safe but unused,
+and return a value.
+
+.. code-block:: python
+
+ class LogFactory(factory.Factory):
+ class Meta:
+ model = models.Log
+
+ timestamp = factory.LazyFunction(datetime.now)
+
+.. code-block:: pycon
+
+ >>> LogFactory()
+ <Log: log at 2016-02-12 17:02:34>
+
+ >>> # The LazyFunction can be overriden
+ >>> LogFactory(timestamp=now - timedelta(days=1))
+ <Log: log at 2016-02-11 17:02:34>
+
+Decorator
+~~~~~~~~~
+
+The class :class:`LazyFunction` does not provide a decorator.
+
+For complex cases, use :meth:`LazyAttribute.lazy_attribute` directly.
+
LazyAttribute
"""""""""""""
@@ -711,8 +932,9 @@ The sequence counter is shared across all :class:`Sequence` attributes of the
Inheritance
~~~~~~~~~~~
-When a :class:`Factory` inherits from another :class:`Factory`, their
-sequence counter is shared:
+When a :class:`Factory` inherits from another :class:`Factory` and the `model`
+of the subclass inherits from the `model` of the parent, the sequence counter
+is shared across the :class:`Factory` classes:
.. code-block:: python
@@ -1041,7 +1263,7 @@ gains an "upward" semantic through the double-dot notation, as used in Python im
>>> company.owner.language
'fr'
-Obviously, this "follow parents" hability also handles overriding some attributes on call:
+Obviously, this "follow parents" ability also handles overriding some attributes on call:
.. code-block:: pycon
@@ -1262,6 +1484,7 @@ with the :class:`Dict` and :class:`List` attributes:
argument, if another type (tuple, set, ...) is required.
+
Post-generation hooks
"""""""""""""""""""""