Fuzzy attributes
================
.. module:: factory.fuzzy
.. note:: Now that FactoryBoy includes the :class:`factory.Faker` class, most of
these built-in fuzzers are deprecated in favor of their
`Faker `_ equivalents. Further
discussion here:
``_
Some tests may be interested in testing with fuzzy, random values.
This is handled by the :mod:`factory.fuzzy` module, which provides a few
random declarations.
.. note:: Use ``import factory.fuzzy`` to load this module.
FuzzyAttribute
--------------
.. class:: FuzzyAttribute
The :class:`FuzzyAttribute` uses an arbitrary callable as fuzzer.
It is expected that successive calls of that function return various
values.
.. attribute:: fuzzer
The callable that generates random values
FuzzyText
---------
.. class:: FuzzyText(length=12, chars=string.ascii_letters, prefix='')
The :class:`FuzzyText` fuzzer yields random strings beginning with
the given :attr:`prefix`, followed by :attr:`length` charactes chosen
from the :attr:`chars` character set,
and ending with the given :attr:`suffix`.
.. attribute:: length
int, the length of the random part
.. attribute:: prefix
text, an optional prefix to prepend to the random part
.. attribute:: suffix
text, an optional suffix to append to the random part
.. attribute:: chars
char iterable, the chars to choose from; defaults to the list of ascii
letters and numbers.
FuzzyChoice
-----------
.. class:: FuzzyChoice(choices)
The :class:`FuzzyChoice` fuzzer yields random choices from the given
iterable.
.. note:: The passed in :attr:`choices` will be converted into a list upon
first use, not at declaration time.
This allows passing in, for instance, a Django queryset that will
only hit the database during the database, not at import time.
.. attribute:: choices
The list of choices to select randomly
FuzzyInteger
------------
.. class:: FuzzyInteger(low[, high[, step]])
The :class:`FuzzyInteger` fuzzer generates random integers within a given
inclusive range.
The :attr:`low` bound may be omitted, in which case it defaults to 0:
.. code-block:: pycon
>>> fi = FuzzyInteger(0, 42)
>>> fi.low, fi.high
0, 42
>>> fi = FuzzyInteger(42)
>>> fi.low, fi.high
0, 42
.. attribute:: low
int, the inclusive lower bound of generated integers
.. attribute:: high
int, the inclusive higher bound of generated integers
.. attribute:: step
int, the step between values in the range; for instance, a ``FuzzyInteger(0, 42, step=3)``
might only yield values from ``[0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42]``.
FuzzyDecimal
------------
.. class:: FuzzyDecimal(low[, high[, precision=2]])
The :class:`FuzzyDecimal` fuzzer generates random :class:`decimals ` within a given
inclusive range.
The :attr:`low` bound may be omitted, in which case it defaults to 0:
.. code-block:: pycon
>>> FuzzyDecimal(0.5, 42.7)
>>> fi.low, fi.high
0.5, 42.7
>>> fi = FuzzyDecimal(42.7)
>>> fi.low, fi.high
0.0, 42.7
>>> fi = FuzzyDecimal(0.5, 42.7, 3)
>>> fi.low, fi.high, fi.precision
0.5, 42.7, 3
.. attribute:: low
decimal, the inclusive lower bound of generated decimals
.. attribute:: high
decimal, the inclusive higher bound of generated decimals
.. attribute:: precision
int, the number of digits to generate after the dot. The default is 2 digits.
FuzzyFloat
----------
.. class:: FuzzyFloat(low[, high])
The :class:`FuzzyFloat` fuzzer provides random :class:`float` objects within a given inclusive range.
.. code-block:: pycon
>>> FuzzyFloat(0.5, 42.7)
>>> fi.low, fi.high
0.5, 42.7
>>> fi = FuzzyFloat(42.7)
>>> fi.low, fi.high
0.0, 42.7
.. attribute:: low
decimal, the inclusive lower bound of generated floats
.. attribute:: high
decimal, the inclusive higher bound of generated floats
FuzzyDate
---------
.. class:: FuzzyDate(start_date[, end_date])
The :class:`FuzzyDate` fuzzer generates random dates within a given
inclusive range.
The :attr:`end_date` bound may be omitted, in which case it defaults to the current date:
.. code-block:: pycon
>>> fd = FuzzyDate(datetime.date(2008, 1, 1))
>>> fd.start_date, fd.end_date
datetime.date(2008, 1, 1), datetime.date(2013, 4, 16)
.. attribute:: start_date
:class:`datetime.date`, the inclusive lower bound of generated dates
.. attribute:: end_date
:class:`datetime.date`, the inclusive higher bound of generated dates
FuzzyDateTime
-------------
.. class:: FuzzyDateTime(start_dt[, end_dt], force_year=None, force_month=None, force_day=None, force_hour=None, force_minute=None, force_second=None, force_microsecond=None)
The :class:`FuzzyDateTime` fuzzer generates random timezone-aware datetime within a given
inclusive range.
The :attr:`end_dt` bound may be omitted, in which case it defaults to ``datetime.datetime.now()``
localized into the UTC timezone.
.. code-block:: pycon
>>> fdt = FuzzyDateTime(datetime.datetime(2008, 1, 1, tzinfo=UTC))
>>> fdt.start_dt, fdt.end_dt
datetime.datetime(2008, 1, 1, tzinfo=UTC), datetime.datetime(2013, 4, 21, 19, 13, 32, 458487, tzinfo=UTC)
The ``force_XXX`` keyword arguments force the related value of generated datetimes:
.. code-block:: pycon
>>> fdt = FuzzyDateTime(datetime.datetime(2008, 1, 1, tzinfo=UTC), datetime.datetime(2009, 1, 1, tzinfo=UTC),
... force_day=3, force_second=42)
>>> fdt.evaluate(2, None, False) # Actual code used by ``SomeFactory.build()``
datetime.datetime(2008, 5, 3, 12, 13, 42, 124848, tzinfo=UTC)
.. attribute:: start_dt
:class:`datetime.datetime`, the inclusive lower bound of generated datetimes
.. attribute:: end_dt
:class:`datetime.datetime`, the inclusive upper bound of generated datetimes
.. attribute:: force_year
int or None; if set, forces the :attr:`~datetime.datetime.year` of generated datetime.
.. attribute:: force_month
int or None; if set, forces the :attr:`~datetime.datetime.month` of generated datetime.
.. attribute:: force_day
int or None; if set, forces the :attr:`~datetime.datetime.day` of generated datetime.
.. attribute:: force_hour
int or None; if set, forces the :attr:`~datetime.datetime.hour` of generated datetime.
.. attribute:: force_minute
int or None; if set, forces the :attr:`~datetime.datetime.minute` of generated datetime.
.. attribute:: force_second
int or None; if set, forces the :attr:`~datetime.datetime.second` of generated datetime.
.. attribute:: force_microsecond
int or None; if set, forces the :attr:`~datetime.datetime.microsecond` of generated datetime.
FuzzyNaiveDateTime
------------------
.. class:: FuzzyNaiveDateTime(start_dt[, end_dt], force_year=None, force_month=None, force_day=None, force_hour=None, force_minute=None, force_second=None, force_microsecond=None)
The :class:`FuzzyNaiveDateTime` fuzzer generates random naive datetime within a given
inclusive range.
The :attr:`end_dt` bound may be omitted, in which case it defaults to ``datetime.datetime.now()``:
.. code-block:: pycon
>>> fdt = FuzzyNaiveDateTime(datetime.datetime(2008, 1, 1))
>>> fdt.start_dt, fdt.end_dt
datetime.datetime(2008, 1, 1), datetime.datetime(2013, 4, 21, 19, 13, 32, 458487)
The ``force_XXX`` keyword arguments force the related value of generated datetimes:
.. code-block:: pycon
>>> fdt = FuzzyNaiveDateTime(datetime.datetime(2008, 1, 1), datetime.datetime(2009, 1, 1),
... force_day=3, force_second=42)
>>> fdt.evaluate(2, None, False) # Actual code used by ``SomeFactory.build()``
datetime.datetime(2008, 5, 3, 12, 13, 42, 124848)
.. attribute:: start_dt
:class:`datetime.datetime`, the inclusive lower bound of generated datetimes
.. attribute:: end_dt
:class:`datetime.datetime`, the inclusive upper bound of generated datetimes
.. attribute:: force_year
int or None; if set, forces the :attr:`~datetime.datetime.year` of generated datetime.
.. attribute:: force_month
int or None; if set, forces the :attr:`~datetime.datetime.month` of generated datetime.
.. attribute:: force_day
int or None; if set, forces the :attr:`~datetime.datetime.day` of generated datetime.
.. attribute:: force_hour
int or None; if set, forces the :attr:`~datetime.datetime.hour` of generated datetime.
.. attribute:: force_minute
int or None; if set, forces the :attr:`~datetime.datetime.minute` of generated datetime.
.. attribute:: force_second
int or None; if set, forces the :attr:`~datetime.datetime.second` of generated datetime.
.. attribute:: force_microsecond
int or None; if set, forces the :attr:`~datetime.datetime.microsecond` of generated datetime.
Custom fuzzy fields
-------------------
Alternate fuzzy fields may be defined.
They should inherit from the :class:`BaseFuzzyAttribute` class, and override its
:meth:`~BaseFuzzyAttribute.fuzz` method.
.. class:: BaseFuzzyAttribute
Base class for all fuzzy attributes.
.. method:: fuzz(self)
The method responsible for generating random values.
*Must* be overridden in subclasses.
Managing randomness
-------------------
Using :mod:`random` in factories allows to "fuzz" a program efficiently.
However, it's sometimes required to *reproduce* a failing test.
:mod:`factory.fuzzy` uses a separate instance of :class:`random.Random`,
and provides a few helpers for this:
.. method:: get_random_state()
Call :meth:`get_random_state` to retrieve the random generator's current
state.
.. method:: set_random_state(state)
Use :meth:`set_random_state` to set a custom state into the random generator
(fetched from :meth:`get_random_state` in a previous run, for instance)
.. method:: reseed_random(seed)
The :meth:`reseed_random` function allows to load a chosen seed into the random generator.
Custom :class:`BaseFuzzyAttribute` subclasses **SHOULD**
use :obj:`factory.fuzzy._random` as a randomness source; this ensures that
data they generate can be regenerated using the simple state from
:meth:`get_random_state`.