diff options
author | Raphaël Barrois <raphael.barrois@polytechnique.org> | 2015-03-26 22:22:03 +0100 |
---|---|---|
committer | Raphaël Barrois <raphael.barrois@polytechnique.org> | 2015-03-26 22:22:03 +0100 |
commit | 69befae5fde1897cf68c4d44a146db5ba642c814 (patch) | |
tree | 88d696ef1784cd73552a5ecd13bc3f4af5d2ac2a | |
parent | 40d4a4b13d4ca959879d1798f24d510fd7abf4dc (diff) | |
download | factory-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.rst | 1 | ||||
-rw-r--r-- | docs/fuzzy.rst | 7 | ||||
-rw-r--r-- | factory/fuzzy.py | 12 | ||||
-rw-r--r-- | tests/test_fuzzy.py | 18 |
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): |