
Fuzzy attributes
****************

Some tests may be interested in testing with fuzzy, random values.

This is handled by the "factory.fuzzy" module, which provides a few
random declarations.

Note: Use "import factory.fuzzy" to load this module.


FuzzyAttribute
==============

class class factory.fuzzy.FuzzyAttribute

   The "FuzzyAttribute" uses an arbitrary callable as fuzzer. It is
   expected that successive calls of that function return various
   values.

   fuzzer

      The callable that generates random values


FuzzyText
=========

class class factory.fuzzy.FuzzyText(length=12, chars=string.ascii_letters, prefix='')

   The "FuzzyText" fuzzer yields random strings beginning with the
   given "prefix", followed by "length" charactes chosen from the
   "chars" character set, and ending with the given "suffix".

   length

      int, the length of the random part

   prefix

      text, an optional prefix to prepend to the random part

   suffix

      text, an optional suffix to append to the random part

   chars

      char iterable, the chars to choose from; defaults to the list of
      ascii
         letters and numbers.


FuzzyChoice
===========

class class factory.fuzzy.FuzzyChoice(choices)

   The "FuzzyChoice" fuzzer yields random choices from the given
   iterable.

   Note: The passed in "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.

   choices

      The list of choices to select randomly


FuzzyInteger
============

class class factory.fuzzy.FuzzyInteger(low[, high[, step]])

   The "FuzzyInteger" fuzzer generates random integers within a given
   inclusive range.

   The "low" bound may be omitted, in which case it defaults to 0:

      >>> fi = FuzzyInteger(0, 42)
      >>> fi.low, fi.high
      0, 42

      >>> fi = FuzzyInteger(42)
      >>> fi.low, fi.high
      0, 42

   low

      int, the inclusive lower bound of generated integers

   high

      int, the inclusive higher bound of generated integers

   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 class factory.fuzzy.FuzzyDecimal(low[, high[, precision=2]])

   The "FuzzyDecimal" fuzzer generates random "decimals" within a
   given inclusive range.

   The "low" bound may be omitted, in which case it defaults to 0:

      >>> 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

   low

      decimal, the inclusive lower bound of generated decimals

   high

      decimal, the inclusive higher bound of generated decimals

   precision
   int, the number of digits to generate after the dot. The default is 2 digits.


FuzzyFloat
==========

class class factory.fuzzy.FuzzyFloat(low[, high])

   The "FuzzyFloat" fuzzer provides random "float" objects within a
   given inclusive range.

      >>> 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

   low

      decimal, the inclusive lower bound of generated floats

   high

      decimal, the inclusive higher bound of generated floats


FuzzyDate
=========

class class factory.fuzzy.FuzzyDate(start_date[, end_date])

   The "FuzzyDate" fuzzer generates random dates within a given
   inclusive range.

   The "end_date" bound may be omitted, in which case it defaults to
   the current date:

      >>> fd = FuzzyDate(datetime.date(2008, 1, 1))
      >>> fd.start_date, fd.end_date
      datetime.date(2008, 1, 1), datetime.date(2013, 4, 16)

   start_date

      "datetime.date", the inclusive lower bound of generated dates

   end_date

      "datetime.date", the inclusive higher bound of generated dates


FuzzyDateTime
=============

class class factory.fuzzy.FuzzyDateTime(start_dt[, end_dt], tz=UTC, force_year=None, force_month=None, force_day=None, force_hour=None, force_minute=None, force_second=None, force_microsecond=None)

   The "FuzzyDateTime" fuzzer generates random timezone-aware datetime
   within a given inclusive range.

   The "end_dt" bound may be omitted, in which case it defaults to
   "datetime.datetime.now()" localized into the UTC timezone.

      >>> 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:

      >>> 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)

   start_dt

      "datetime.datetime", the inclusive lower bound of generated
      datetimes

   end_dt

      "datetime.datetime", the inclusive upper bound of generated
      datetimes

   force_year

      int or None; if set, forces the "year" of generated datetime.

   force_month

      int or None; if set, forces the "month" of generated datetime.

   force_day

      int or None; if set, forces the "day" of generated datetime.

   force_hour

      int or None; if set, forces the "hour" of generated datetime.

   force_minute

      int or None; if set, forces the "minute" of generated datetime.

   force_second

      int or None; if set, forces the "second" of generated datetime.

   force_microsecond

      int or None; if set, forces the "microsecond" of generated
      datetime.


FuzzyNaiveDateTime
==================

class class factory.fuzzy.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 "FuzzyNaiveDateTime" fuzzer generates random naive datetime
   within a given inclusive range.

   The "end_dt" bound may be omitted, in which case it defaults to
   "datetime.datetime.now()":

      >>> 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:

      >>> 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)

   start_dt

      "datetime.datetime", the inclusive lower bound of generated
      datetimes

   end_dt

      "datetime.datetime", the inclusive upper bound of generated
      datetimes

   force_year

      int or None; if set, forces the "year" of generated datetime.

   force_month

      int or None; if set, forces the "month" of generated datetime.

   force_day

      int or None; if set, forces the "day" of generated datetime.

   force_hour

      int or None; if set, forces the "hour" of generated datetime.

   force_minute

      int or None; if set, forces the "minute" of generated datetime.

   force_second

      int or None; if set, forces the "second" of generated datetime.

   force_microsecond

      int or None; if set, forces the "microsecond" of generated
      datetime.


Custom fuzzy fields
===================

Alternate fuzzy fields may be defined. They should inherit from the
"BaseFuzzyAttribute" class, and override its "fuzz()" method.

class class factory.fuzzy.BaseFuzzyAttribute

   Base class for all fuzzy attributes.

   fuzz(self)

      The method responsible for generating random values. *Must* be
      overridden in subclasses.


Managing randomness
===================

Using "random" in factories allows to "fuzz" a program efficiently.
However, it's sometimes required to *reproduce* a failing test.

"factory.fuzzy" uses a separate instance of "random.Random", and
provides a few helpers for this:

factory.fuzzy.get_random_state()

   Call "get_random_state()" to retrieve the random generator's
   current state.

factory.fuzzy.set_random_state(state)

   Use "set_random_state()" to set a custom state into the random
   generator (fetched from "get_random_state()" in a previous run, for
   instance)

factory.fuzzy.reseed_random(seed)

   The "reseed_random()" function allows to load a chosen seed into
   the random generator.

Custom "BaseFuzzyAttribute" subclasses **SHOULD** use
"factory.fuzzy._random" as a randomness source; this ensures that data
they generate can be regenerated using the simple state from
"get_random_state()".
