summaryrefslogtreecommitdiff
path: root/factory/base.py
diff options
context:
space:
mode:
Diffstat (limited to 'factory/base.py')
-rw-r--r--factory/base.py203
1 files changed, 189 insertions, 14 deletions
diff --git a/factory/base.py b/factory/base.py
index 3f3261b..62131fb 100644
--- a/factory/base.py
+++ b/factory/base.py
@@ -22,6 +22,7 @@
import re
import sys
+import warnings
from factory import containers
@@ -156,28 +157,36 @@ class FactoryMetaClass(BaseFactoryMetaClass):
if FACTORY_CLASS_DECLARATION in attrs:
return attrs[FACTORY_CLASS_DECLARATION]
- factory_module = sys.modules[attrs['__module__']]
- if class_name.endswith('Factory'):
- # Try a module lookup
- used_auto_discovery = True
- associated_class_name = class_name[:-len('Factory')]
- if associated_class_name:
- # Class name was longer than just 'Factory'.
- try:
- return getattr(factory_module, associated_class_name)
- except AttributeError:
- pass
-
- # Unable to guess a good option; return the inherited class.
+ # No specific associated calss was given, and one was defined for our
+ # parent, use it.
if inherited is not None:
return inherited
+ if '__module__' in attrs:
+ factory_module = sys.modules[attrs['__module__']]
+ if class_name.endswith('Factory'):
+ # Try a module lookup
+ used_auto_discovery = True
+ associated_name = class_name[:-len('Factory')]
+ if associated_name and hasattr(factory_module, associated_name):
+ warnings.warn(
+ "Auto-discovery of associated class is deprecated, and "
+ "will be removed in the future. Please set '%s = %s' "
+ "in the %s class definition." % (
+ FACTORY_CLASS_DECLARATION,
+ associated_name,
+ class_name,
+ ), PendingDeprecationWarning)
+
+ return getattr(factory_module, associated_name)
+
+ # Unable to guess a good option; return the inherited class.
# Unable to find an associated class; fail.
if used_auto_discovery:
raise Factory.AssociatedClassError(
FactoryMetaClass.ERROR_MESSAGE_AUTODISCOVERY.format(
FACTORY_CLASS_DECLARATION,
- associated_class_name,
+ associated_name,
class_name,
factory_module,))
else:
@@ -300,11 +309,35 @@ class BaseFactory(object):
raise cls.UnsupportedStrategy()
@classmethod
+ def build_batch(cls, size, **kwargs):
+ """Build a batch of instances of the given class, with overriden attrs.
+
+ Args:
+ size (int): the number of instances to build
+
+ Returns:
+ object list: the built instances
+ """
+ return [cls.build(**kwargs) for _ in xrange(size)]
+
+ @classmethod
def create(cls, **kwargs):
"""Create an instance of the associated class, with overriden attrs."""
raise cls.UnsupportedStrategy()
@classmethod
+ def create_batch(cls, size, **kwargs):
+ """Create a batch of instances of the given class, with overriden attrs.
+
+ Args:
+ size (int): the number of instances to create
+
+ Returns:
+ object list: the created instances
+ """
+ return [cls.create(**kwargs) for _ in xrange(size)]
+
+ @classmethod
def stub(cls, **kwargs):
"""Retrieve a stub of the associated class, with overriden attrs.
@@ -316,6 +349,84 @@ class BaseFactory(object):
setattr(stub_object, name, value)
return stub_object
+ @classmethod
+ def stub_batch(cls, size, **kwargs):
+ """Stub a batch of instances of the given class, with overriden attrs.
+
+ Args:
+ size (int): the number of instances to stub
+
+ Returns:
+ object list: the stubbed instances
+ """
+ return [cls.stub(**kwargs) for _ in xrange(size)]
+
+ @classmethod
+ def generate(cls, strategy, **kwargs):
+ """Generate a new instance.
+
+ The instance will be created with the given strategy (one of
+ BUILD_STRATEGY, CREATE_STRATEGY, STUB_STRATEGY).
+
+ Args:
+ strategy (str): the strategy to use for generating the instance.
+
+ Returns:
+ object: the generated instance
+ """
+ assert strategy in (STUB_STRATEGY, BUILD_STRATEGY, CREATE_STRATEGY)
+ action = getattr(cls, strategy)
+ return action(**kwargs)
+
+ @classmethod
+ def generate_batch(cls, strategy, size, **kwargs):
+ """Generate a batch of instances.
+
+ The instances will be created with the given strategy (one of
+ BUILD_STRATEGY, CREATE_STRATEGY, STUB_STRATEGY).
+
+ Args:
+ strategy (str): the strategy to use for generating the instance.
+ size (int): the number of instances to generate
+
+ Returns:
+ object list: the generated instances
+ """
+ assert strategy in (STUB_STRATEGY, BUILD_STRATEGY, CREATE_STRATEGY)
+ batch_action = getattr(cls, '%s_batch' % strategy)
+ return batch_action(size, **kwargs)
+
+ @classmethod
+ def simple_generate(cls, create, **kwargs):
+ """Generate a new instance.
+
+ The instance will be either 'built' or 'created'.
+
+ Args:
+ create (bool): whether to 'build' or 'create' the instance.
+
+ Returns:
+ object: the generated instance
+ """
+ strategy = CREATE_STRATEGY if create else BUILD_STRATEGY
+ return cls.generate(strategy, **kwargs)
+
+ @classmethod
+ def simple_generate_batch(cls, create, size, **kwargs):
+ """Generate a batch of instances.
+
+ These instances will be either 'built' or 'created'.
+
+ Args:
+ size (int): the number of instances to generate
+ create (bool): whether to 'build' or 'create' the instances.
+
+ Returns:
+ object list: the generated instances
+ """
+ strategy = CREATE_STRATEGY if create else BUILD_STRATEGY
+ return cls.generate_batch(strategy, size, **kwargs)
+
class StubFactory(BaseFactory):
__metaclass__ = BaseFactoryMetaClass
@@ -340,6 +451,10 @@ class Factory(BaseFactory):
# from turning it into an instance method.
_creation_function = (DJANGO_CREATION,)
+ def __str__(self):
+ return '<%s for %s>' % (self.__class__.__name__,
+ getattr(self, CLASS_ATTRIBUTE_ASSOCIATED_CLASS).__name__)
+
@classmethod
def set_creation_function(cls, creation_function):
"""Set the creation function for this class.
@@ -439,3 +554,63 @@ class DjangoModelFactory(Factory):
).order_by('-id')[0]
except IndexError:
return 1
+
+
+def make_factory(klass, **kwargs):
+ """Create a new, simple factory for the given class."""
+ factory_name = '%sFactory' % klass.__name__
+ kwargs[FACTORY_CLASS_DECLARATION] = klass
+ factory_class = type(Factory).__new__(type(Factory), factory_name, (Factory,), kwargs)
+ factory_class.__name__ = '%sFactory' % klass.__name__
+ factory_class.__doc__ = 'Auto-generated factory for class %s' % klass
+ return factory_class
+
+
+def build(klass, **kwargs):
+ """Create a factory for the given class, and build an instance."""
+ return make_factory(klass, **kwargs).build()
+
+
+def build_batch(klass, size, **kwargs):
+ """Create a factory for the given class, and build a batch of instances."""
+ return make_factory(klass, **kwargs).build_batch(size)
+
+
+def create(klass, **kwargs):
+ """Create a factory for the given class, and create an instance."""
+ return make_factory(klass, **kwargs).create()
+
+
+def create_batch(klass, size, **kwargs):
+ """Create a factory for the given class, and create a batch of instances."""
+ return make_factory(klass, **kwargs).create_batch(size)
+
+
+def stub(klass, **kwargs):
+ """Create a factory for the given class, and stub an instance."""
+ return make_factory(klass, **kwargs).stub()
+
+
+def stub_batch(klass, size, **kwargs):
+ """Create a factory for the given class, and stub a batch of instances."""
+ return make_factory(klass, **kwargs).stub_batch(size)
+
+
+def generate(klass, strategy, **kwargs):
+ """Create a factory for the given class, and generate an instance."""
+ return make_factory(klass, **kwargs).generate(strategy)
+
+
+def generate_batch(klass, strategy, size, **kwargs):
+ """Create a factory for the given class, and generate instances."""
+ return make_factory(klass, **kwargs).generate_batch(strategy, size)
+
+
+def simple_generate(klass, create, **kwargs):
+ """Create a factory for the given class, and simple_generate an instance."""
+ return make_factory(klass, **kwargs).simple_generate(create)
+
+
+def simple_generate_batch(klass, create, size, **kwargs):
+ """Create a factory for the given class, and simple_generate instances."""
+ return make_factory(klass, **kwargs).simple_generate_batch(create, size)