aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaphaël Barrois <raphael.barrois@polytechnique.org>2015-03-26 22:22:03 +0100
committerRaphaël Barrois <raphael.barrois@polytechnique.org>2015-03-26 22:22:03 +0100
commit69befae5fde1897cf68c4d44a146db5ba642c814 (patch)
tree88d696ef1784cd73552a5ecd13bc3f4af5d2ac2a
parent40d4a4b13d4ca959879d1798f24d510fd7abf4dc (diff)
downloadfactory-boy-69befae5fde1897cf68c4d44a146db5ba642c814.tar
factory-boy-69befae5fde1897cf68c4d44a146db5ba642c814.tar.gz
Allow lazy evaluation of FuzzyChoice's iterators (Closes #184).
This allows the following idiom: ``user = factory.fuzzy.FuzzyChoice(User.objects.all())`` Previously, the ``User.objects.all()`` queryset would have been evaluated *at import time*; it is now evaluated with the first use of the ``FuzzyChoice``.
-rw-r--r--docs/changelog.rst1
-rw-r--r--docs/fuzzy.rst7
-rw-r--r--factory/fuzzy.py12
-rw-r--r--tests/test_fuzzy.py18
4 files changed, 34 insertions, 4 deletions
diff --git a/docs/changelog.rst b/docs/changelog.rst
index ebe9930..13fdd68 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -10,6 +10,7 @@ ChangeLog
*New:*
- Add support for getting/setting :mod:`factory.fuzzy`'s random state (see :issue:`175`, :issue:`185`).
+ - Support lazy evaluation of iterables in :class:`factory.fuzzy.FuzzyChoice` (see :issue:`184`).
*Deprecation:*
diff --git a/docs/fuzzy.rst b/docs/fuzzy.rst
index 0658652..18978e4 100644
--- a/docs/fuzzy.rst
+++ b/docs/fuzzy.rst
@@ -62,8 +62,11 @@ FuzzyChoice
The :class:`FuzzyChoice` fuzzer yields random choices from the given
iterable.
- .. note:: The passed in :attr:`choices` will be converted into a list at
- declaration time.
+ .. 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
diff --git a/factory/fuzzy.py b/factory/fuzzy.py
index 564264e..4e6a03d 100644
--- a/factory/fuzzy.py
+++ b/factory/fuzzy.py
@@ -113,13 +113,21 @@ class FuzzyText(BaseFuzzyAttribute):
class FuzzyChoice(BaseFuzzyAttribute):
- """Handles fuzzy choice of an attribute."""
+ """Handles fuzzy choice of an attribute.
+
+ Args:
+ choices (iterable): An iterable yielding options; will only be unrolled
+ on the first call.
+ """
def __init__(self, choices, **kwargs):
- self.choices = list(choices)
+ self.choices = None
+ self.choices_generator = choices
super(FuzzyChoice, self).__init__(**kwargs)
def fuzz(self):
+ if self.choices is None:
+ self.choices = list(self.choices_generator)
return _random.choice(self.choices)
diff --git a/tests/test_fuzzy.py b/tests/test_fuzzy.py
index fd32705..c7e1106 100644
--- a/tests/test_fuzzy.py
+++ b/tests/test_fuzzy.py
@@ -74,6 +74,24 @@ class FuzzyChoiceTestCase(unittest.TestCase):
res = d.evaluate(2, None, False)
self.assertIn(res, [0, 1, 2])
+ def test_lazy_generator(self):
+ class Gen(object):
+ def __init__(self, options):
+ self.options = options
+ self.unrolled = False
+
+ def __iter__(self):
+ self.unrolled = True
+ return iter(self.options)
+
+ opts = Gen([1, 2, 3])
+ d = fuzzy.FuzzyChoice(opts)
+ self.assertFalse(opts.unrolled)
+
+ res = d.evaluate(2, None, False)
+ self.assertIn(res, [1, 2, 3])
+ self.assertTrue(opts.unrolled)
+
class FuzzyIntegerTestCase(unittest.TestCase):
def test_definition(self):