summaryrefslogtreecommitdiff
path: root/factory
diff options
context:
space:
mode:
Diffstat (limited to 'factory')
-rw-r--r--factory/django.py68
-rw-r--r--factory/fuzzy.py22
-rw-r--r--factory/helpers.py1
3 files changed, 89 insertions, 2 deletions
diff --git a/factory/django.py b/factory/django.py
index fee8e52..a3dfdfc 100644
--- a/factory/django.py
+++ b/factory/django.py
@@ -25,6 +25,9 @@ from __future__ import absolute_import
from __future__ import unicode_literals
import os
+import types
+import logging
+import functools
"""factory_boy extensions for use with the Django framework."""
@@ -39,6 +42,9 @@ from . import base
from . import declarations
from .compat import BytesIO, is_string
+logger = logging.getLogger('factory.generate')
+
+
def require_django():
"""Simple helper to ensure Django is available."""
@@ -214,3 +220,65 @@ class ImageField(FileField):
thumb.save(thumb_io, format=image_format)
return thumb_io.getvalue()
+
+class mute_signals(object):
+ """Temporarily disables and then restores any django signals.
+
+ Args:
+ *signals (django.dispatch.dispatcher.Signal): any django signals
+
+ Examples:
+ with mute_signals(pre_init):
+ user = UserFactory.build()
+ ...
+
+ @mute_signals(pre_save, post_save)
+ class UserFactory(factory.Factory):
+ ...
+
+ @mute_signals(post_save)
+ def generate_users():
+ UserFactory.create_batch(10)
+ """
+
+ def __init__(self, *signals):
+ self.signals = signals
+ self.paused = {}
+
+ def __enter__(self):
+ for signal in self.signals:
+ logger.debug('mute_signals: Disabling signal handlers %r',
+ signal.receivers)
+
+ self.paused[signal] = signal.receivers
+ signal.receivers = []
+
+ def __exit__(self, exc_type, exc_value, traceback):
+ for signal, receivers in self.paused.items():
+ logger.debug('mute_signals: Restoring signal handlers %r',
+ receivers)
+
+ signal.receivers = receivers
+ self.paused = {}
+
+ def __call__(self, callable_obj):
+ if isinstance(callable_obj, base.FactoryMetaClass):
+ # Retrieve __func__, the *actual* callable object.
+ generate_method = callable_obj._generate.__func__
+
+ @classmethod
+ @functools.wraps(generate_method)
+ def wrapped_generate(*args, **kwargs):
+ with self:
+ return generate_method(*args, **kwargs)
+
+ callable_obj._generate = wrapped_generate
+ return callable_obj
+
+ else:
+ @functools.wraps(callable_obj)
+ def wrapper(*args, **kwargs):
+ with self:
+ return callable_obj(*args, **kwargs)
+ return wrapper
+
diff --git a/factory/fuzzy.py b/factory/fuzzy.py
index 34949c5..94599b7 100644
--- a/factory/fuzzy.py
+++ b/factory/fuzzy.py
@@ -107,18 +107,19 @@ class FuzzyChoice(BaseFuzzyAttribute):
class FuzzyInteger(BaseFuzzyAttribute):
"""Random integer within a given range."""
- def __init__(self, low, high=None, **kwargs):
+ def __init__(self, low, high=None, step=1, **kwargs):
if high is None:
high = low
low = 0
self.low = low
self.high = high
+ self.step = step
super(FuzzyInteger, self).__init__(**kwargs)
def fuzz(self):
- return random.randint(self.low, self.high)
+ return random.randrange(self.low, self.high + 1, self.step)
class FuzzyDecimal(BaseFuzzyAttribute):
@@ -140,6 +141,23 @@ class FuzzyDecimal(BaseFuzzyAttribute):
return base.quantize(decimal.Decimal(10) ** -self.precision)
+class FuzzyFloat(BaseFuzzyAttribute):
+ """Random float within a given range."""
+
+ def __init__(self, low, high=None, **kwargs):
+ if high is None:
+ high = low
+ low = 0
+
+ self.low = low
+ self.high = high
+
+ super(FuzzyFloat, self).__init__(**kwargs)
+
+ def fuzz(self):
+ return random.uniform(self.low, self.high)
+
+
class FuzzyDate(BaseFuzzyAttribute):
"""Random date within a given date range."""
diff --git a/factory/helpers.py b/factory/helpers.py
index 37b41bf..4a2a254 100644
--- a/factory/helpers.py
+++ b/factory/helpers.py
@@ -28,6 +28,7 @@ import logging
from . import base
from . import declarations
+from . import django
@contextlib.contextmanager