diff options
Diffstat (limited to 'factory/base.py')
-rw-r--r-- | factory/base.py | 203 |
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) |