summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Goirand <thomas@goirand.fr>2012-10-14 13:19:59 +0000
committerThomas Goirand <thomas@goirand.fr>2012-10-14 13:19:59 +0000
commit9836e013b4494b5e320c81ec4e3f766522639be2 (patch)
tree1bd00e12b2a24a6b06b397e57bd4ab33173e7fdb
parent7e4e7377d2c32bc9d0bff7ece456e38b71548bb3 (diff)
downloadfactory-boy-9836e013b4494b5e320c81ec4e3f766522639be2.tar
factory-boy-9836e013b4494b5e320c81ec4e3f766522639be2.tar.gz
Back to upstream version 1.1.5
l---------ChangeLog1
-rw-r--r--README65
-rw-r--r--docs/_static/.keep_dir0
-rw-r--r--docs/changelog.rst139
-rw-r--r--docs/conf.py19
-rw-r--r--docs/index.rst1
-rw-r--r--docs/subfactory.rst25
-rw-r--r--factory/__init__.py4
-rw-r--r--factory/base.py88
-rw-r--r--factory/containers.py4
-rw-r--r--factory/declarations.py107
-rw-r--r--factory/utils.py32
-rwxr-xr-xsetup.py18
-rw-r--r--tests/cyclic/__init__.py0
-rw-r--r--tests/cyclic/bar.py37
-rw-r--r--tests/cyclic/foo.py38
-rw-r--r--tests/test_base.py59
-rw-r--r--tests/test_containers.py11
-rw-r--r--tests/test_declarations.py31
-rw-r--r--tests/test_using.py374
-rw-r--r--tests/test_utils.py34
21 files changed, 139 insertions, 948 deletions
diff --git a/ChangeLog b/ChangeLog
deleted file mode 120000
index 6f0024c..0000000
--- a/ChangeLog
+++ /dev/null
@@ -1 +0,0 @@
-docs/changelog.rst \ No newline at end of file
diff --git a/README b/README
index b878d00..575c3ae 100644
--- a/README
+++ b/README
@@ -34,9 +34,7 @@ Source::
Defining factories
------------------
-Factories declare a set of attributes used to instantiate an object. The class of the object must be defined in the FACTORY_FOR attribute:
-
-.. code-block:: python
+Factories declare a set of attributes used to instantiate an object. The class of the object must be defined in the FACTORY_FOR attribute::
import factory
from models import User
@@ -59,9 +57,7 @@ Factories declare a set of attributes used to instantiate an object. The class o
Using factories
---------------
-factory_boy supports several different build strategies: build, create, attributes and stub:
-
-.. code-block:: python
+factory_boy supports several different build strategies: build, create, attributes and stub::
# Returns a User instance that's not saved
user = UserFactory.build()
@@ -75,30 +71,22 @@ factory_boy supports several different build strategies: build, create, attribut
# Returns an object with all defined attributes stubbed out:
stub = UserFactory.stub()
-You can use the Factory class as a shortcut for the default build strategy:
-
-.. code-block:: python
+You can use the Factory class as a shortcut for the default build strategy::
# Same as UserFactory.create()
user = UserFactory()
-The default strategy can be overridden:
-
-.. code-block:: python
+The default strategy can be overridden::
UserFactory.default_strategy = factory.BUILD_STRATEGY
user = UserFactory()
-The default strategy can also be overridden for all factories:
-
-.. code-block:: python
+The default strategy can also be overridden for all factories::
# This will set the default strategy for all factories that don't define a default build strategy
factory.Factory.default_strategy = factory.BUILD_STRATEGY
-No matter which strategy is used, it's possible to override the defined attributes by passing keyword arguments:
-
-.. code-block:: python
+No matter which strategy is used, it's possible to override the defined attributes by passing keyword arguments::
# Build a User instance and override first_name
user = UserFactory.build(first_name='Joe')
@@ -108,9 +96,7 @@ No matter which strategy is used, it's possible to override the defined attribut
Lazy Attributes
---------------
-Most factory attributes can be added using static values that are evaluated when the factory is defined, but some attributes (such as associations and other attributes that must be dynamically generated) will need values assigned each time an instance is generated. These "lazy" attributes can be added as follows:
-
-.. code-block:: python
+Most factory attributes can be added using static values that are evaluated when the factory is defined, but some attributes (such as associations and other attributes that must be dynamically generated) will need values assigned each time an instance is generated. These "lazy" attributes can be added as follows::
class UserFactory(factory.Factory):
first_name = 'Joe'
@@ -120,9 +106,7 @@ Most factory attributes can be added using static values that are evaluated when
UserFactory().email
# => 'joe.blow@example.com'
-The function passed to ``LazyAttribute`` is given the attributes defined for the factory up to the point of the LazyAttribute declaration. If a lambda won't cut it, the ``lazy_attribute`` decorator can be used to wrap a function:
-
-.. code-block:: python
+The function passed to ``LazyAttribute`` is given the attributes defined for the factory up to the point of the LazyAttribute declaration. If a lambda won't cut it, the ``lazy_attribute`` decorator can be used to wrap a function::
# Stub factories don't have an associated class.
class SumFactory(factory.StubFactory):
@@ -137,18 +121,14 @@ The function passed to ``LazyAttribute`` is given the attributes defined for the
Associations
------------
-Associated instances can also be generated using ``LazyAttribute``:
-
-.. code-block:: python
+Associated instances can also be generated using ``LazyAttribute``::
from models import Post
class PostFactory(factory.Factory):
author = factory.LazyAttribute(lambda a: UserFactory())
-The associated object's default strategy is always used:
-
-.. code-block:: python
+The associated object's default strategy is always used::
# Builds and saves a User and a Post
post = PostFactory()
@@ -163,9 +143,7 @@ The associated object's default strategy is always used:
Inheritance
-----------
-You can easily create multiple factories for the same class without repeating common attributes by using inheritance:
-
-.. code-block:: python
+You can easily create multiple factories for the same class without repeating common attributes by using inheritance::
class PostFactory(factory.Factory):
title = 'A title'
@@ -177,9 +155,7 @@ You can easily create multiple factories for the same class without repeating co
Sequences
---------
-Unique values in a specific format (for example, e-mail addresses) can be generated using sequences. Sequences are defined by using ``Sequence`` or the decorator ``sequence``:
-
-.. code-block:: python
+Unique values in a specific format (for example, e-mail addresses) can be generated using sequences. Sequences are defined by using ``Sequence`` or the decorator ``sequence``::
class UserFactory(factory.Factory):
email = factory.Sequence(lambda n: 'person{0}@example.com'.format(n))
@@ -187,9 +163,7 @@ Unique values in a specific format (for example, e-mail addresses) can be genera
UserFactory().email # => 'person0@example.com'
UserFactory().email # => 'person1@example.com'
-Sequences can be combined with lazy attributes:
-
-.. code-block:: python
+Sequences can be combined with lazy attributes::
class UserFactory(factory.Factory):
name = 'Mark'
@@ -197,9 +171,7 @@ Sequences can be combined with lazy attributes:
UserFactory().email # => mark+0@example.com
-If you wish to use a custom method to set the initial ID for a sequence, you can override the ``_setup_next_sequence`` class method:
-
-.. code-block:: python
+If you wish to use a custom method to set the initial ID for a sequence, you can override the ``_setup_next_sequence`` class method::
class MyFactory(factory.Factory):
@@ -212,9 +184,7 @@ Customizing creation
Sometimes, the default build/create by keyword arguments doesn't allow for enough
customization of the generated objects. In such cases, you should override the
-Factory._prepare method:
-
-.. code-block:: python
+Factory._prepare method::
class UserFactory(factory.Factory):
@classmethod
@@ -231,9 +201,7 @@ Subfactories
------------
If one of your factories has a field which is another factory, you can declare it as a ``SubFactory``. This allows to define attributes of that field when calling
-the global factory, using a simple syntax : ``field__attr=42`` will set the attribute ``attr`` of the ``SubFactory`` defined in ``field`` to 42:
-
-.. code-block:: python
+the global factory, using a simple syntax : ``field__attr=42`` will set the attribute ``attr`` of the ``SubFactory`` defined in ``field`` to 42::
class InnerFactory(factory.Factory):
foo = 'foo'
@@ -261,7 +229,6 @@ If a ``Factory`` simply defines generic attribute declarations without being bou
it should be marked 'abstract' by declaring ``ABSTRACT_FACTORY = True``.
Such factories cannot be built/created/....
-.. code-block:: python
class AbstractFactory(factory.Factory):
ABSTRACT_FACTORY = True
diff --git a/docs/_static/.keep_dir b/docs/_static/.keep_dir
deleted file mode 100644
index e69de29..0000000
--- a/docs/_static/.keep_dir
+++ /dev/null
diff --git a/docs/changelog.rst b/docs/changelog.rst
deleted file mode 100644
index c64a89a..0000000
--- a/docs/changelog.rst
+++ /dev/null
@@ -1,139 +0,0 @@
-ChangeLog
-=========
-
-2.0.0 (future)
---------------
-
-.. note:: This section lists features planned for v2 of factory_boy. Changes announced here may not have been committed to the repository.
-
-*New:*
-
- - Add support for Python3
- - Clean up documentation
- - Document extension points
- - Add support for ``get_or_create`` in :class:`~factory.DjangoModelFactory`
-
-*Deprecation:*
-
- - Remove associated class discovery
- - Stop defaulting to Django's ``Foo.objects.create()`` when "creating" instances
- - Remove STRATEGY_*
- - Remove :meth:`~factory.Factory.set_building_function` / :meth:`~factory.Factory.set_creation_function`
-
-
-1.2.0 (current)
----------------
-
-*New:*
-
- - Add :class:`~factory.CircularSubFactory` to solve circular dependencies between factories
- - Better creation/building customization hooks at :meth:`factory.Factory._build` and :meth:`factory.Factory.create`.
- - Add support for passing non-kwarg parameters to a :class:`~factory.Factory` wrapped class.
-
-1.1.5 (09/07/2012)
-------------------
-
-*Bugfix:*
-
- - Fix :class:`~factory.PostGenerationDeclaration` and derived classes.
-
-1.1.4 (19/06/2012)
-------------------
-
-*New:*
-
- - Add :meth:`~factory.use_strategy` decorator to override a
- :class:`~factory.Factory`'s default strategy
- - Improve test running (tox, python2.6/2.7)
- - Introduce :class:`~factory.PostGeneration` and
- :class:`~factory.RelatedFactory`
-
-1.1.3 (9/03/2012)
------------------
-
-*Bugfix:*
-
- - Fix packaging rules
-
-1.1.2 (25/02/2012)
-------------------
-
-*New:*
-
- - Add :class:`~factory.Iterator` and :class:`~factory.InfiniteIterator` for :class:`~factory.Factory` attribute declarations.
- - Provide :func:`~factory.Factory.generate` and :func:`~factory.Factory.simple_generate`, that allow specifying the instantiation strategy directly.
- Also provides :func:`~factory.Factory.generate_batch` and :func:`~factory.Factory.simple_generate_batch`.
-
-1.1.1 (24/02/2012)
-------------------
-
-*New:*
-
- - Add :func:`~factory.Factory.build_batch`, :func:`~factory.Factory.create_batch` and :func:`~factory.Factory.stub_batch`, to instantiate factories in batch
-
-1.1.0 (24/02/2012)
-------------------
-
-*New:*
-
- - Improve the :class:`~factory.SelfAttribute` syntax to fetch sub-attributes using the ``foo.bar`` syntax;
- - Add :class:`~factory.ContainerAttribute` to fetch attributes from the container of a :class:`~factory.SubFactory`.
- - Provide the :func:`~factory.make_factory` helper: ``MyClassFactory = make_factory(MyClass, x=3, y=4)``
- - Add :func:`~factory.build`, :func:`~factory.create`, :func:`~factory.stub` helpers
-
-*Bugfix:*
-
- - Allow classmethod/staticmethod on factories
-
-*Deprecation:*
-
- - Auto-discovery of :attr:`~factory.Factory.FACTORY_FOR` based on class name is now deprecated
-
-1.0.4 (21/12/2011)
-------------------
-
-*New:*
-
- - Improve the algorithm for populating a :class:`~factory.Factory` attributes dict
- - Add ``python setup.py test`` command to run the test suite
- - Allow custom build functions
- - Introduce :data:`~factory.MOGO_BUILD` build function
- - Add support for inheriting from multiple :class:`~factory.Factory`
- - Base :class:`~factory.Factory` classes can now be declared :attr:`abstract <factory.Factory.ABSTRACT_FACTORY`.
- - Provide :class:`~factory.DjangoModelFactory`, whose :class:`~factory.Sequence` counter starts at the next free database id
- - Introduce :class:`~factory.SelfAttribute`, a shortcut for ``factory.LazyAttribute(lambda o: o.foo.bar.baz``.
-
-*Bugfix:*
-
- - Handle nested :class:`~factory.SubFactory`
- - Share sequence counter between parent and subclasses
- - Fix :class:`~factory.SubFactory` / :class:`~factory.Sequence` interferences
-
-1.0.2 (16/05/2011)
-------------------
-
-*New:*
-
- - Introduce :class:`~factory.SubFactory`
-
-1.0.1 (13/05/2011)
-------------------
-
-*New:*
-
- - Allow :class:`~factory.Factory` inheritance
- - Improve handling of custom build/create functions
-
-*Bugfix:*
-
- - Fix concurrency between :class:`~factory.LazyAttribute` and :class:`~factory.Sequence`
-
-1.0.0 (22/08/2010)
-------------------
-
-*New:*
-
- - First version of factory_boy
-
-
-.. vim:et:ts=4:sw=4:tw=119:ft=rst:
diff --git a/docs/conf.py b/docs/conf.py
index fd9ded6..db523c3 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -48,23 +48,10 @@ copyright = u'2011, Raphaël Barrois, Mark Sandstrom'
# |version| and |release|, also used in various other places throughout the
# built documents.
#
-root = os.path.abspath(os.path.dirname(__file__))
-def get_version(*module_dir_components):
- import re
- version_re = re.compile(r"^__version__ = ['\"](.*)['\"]$")
- module_root = os.path.join(root, os.pardir, *module_dir_components)
- module_init = os.path.join(module_root, '__init__.py')
- with open(module_init, 'r') as f:
- for line in f:
- match = version_re.match(line[:-1])
- if match:
- return match.groups()[0]
- return '0.1.0'
-
-# The full version, including alpha/beta/rc tags.
-release = get_version('factory')
# The short X.Y version.
-version = '.'.join(release.split('.')[:2])
+version = '1.1'
+# The full version, including alpha/beta/rc tags.
+release = '1.1.2'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/docs/index.rst b/docs/index.rst
index f91b830..f0b5dcc 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -61,7 +61,6 @@ Contents:
subfactory
post_generation
internals
- changelog
Indices and tables
==================
diff --git a/docs/subfactory.rst b/docs/subfactory.rst
index f8642f3..1815312 100644
--- a/docs/subfactory.rst
+++ b/docs/subfactory.rst
@@ -54,28 +54,3 @@ Fields of the SubFactory can also be overridden when instantiating the external
<User: Henry Jones>
>>> c.owner.email
henry.jones@example.org
-
-
-Circular dependencies
----------------------
-
-In order to solve circular dependency issues, Factory Boy provides the :class:`~factory.CircularSubFactory` class.
-
-This class expects a module name and a factory name to import from that module; the given module will be imported
-(as an absolute import) when the factory is first accessed::
-
- # foo/factories.py
- import factory
-
- from bar import factories
-
- class FooFactory(factory.Factory):
- bar = factory.SubFactory(factories.BarFactory)
-
-
- # bar/factories.py
- import factory
-
- class BarFactory(factory.Factory):
- # Avoid circular import
- foo = factory.CircularSubFactory('foo.factories', 'FooFactory', bar=None)
diff --git a/factory/__init__.py b/factory/__init__.py
index d2267f0..3753461 100644
--- a/factory/__init__.py
+++ b/factory/__init__.py
@@ -20,7 +20,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
-__version__ = '1.2.0'
+__version__ = '1.1.5' # Remember to change in setup.py as well!
__author__ = 'Raphaël Barrois <raphael.barrois@polytechnique.org>'
from base import (
@@ -60,9 +60,7 @@ from declarations import (
SelfAttribute,
ContainerAttribute,
SubFactory,
- CircularSubFactory,
PostGeneration,
- PostGenerationMethodCall,
RelatedFactory,
lazy_attribute,
diff --git a/factory/base.py b/factory/base.py
index a3d91b0..c1dbd98 100644
--- a/factory/base.py
+++ b/factory/base.py
@@ -32,12 +32,7 @@ CREATE_STRATEGY = 'create'
STUB_STRATEGY = 'stub'
# Creation functions. Use Factory.set_creation_function() to set a creation function appropriate for your ORM.
-def DJANGO_CREATION(class_to_create, **kwargs):
- warnings.warn(
- "Factories defaulting to Django's Foo.objects.create() is deprecated, "
- "and will be removed in the future. Please inherit from "
- "factory.DjangoModelFactory instead.", PendingDeprecationWarning, 6)
- return class_to_create.objects.create(**kwargs)
+DJANGO_CREATION = lambda class_to_create, **kwargs: class_to_create.objects.create(**kwargs)
# Building functions. Use Factory.set_building_function() to set a building functions appropriate for your ORM.
NAIVE_BUILD = lambda class_to_build, **kwargs: class_to_build(**kwargs)
@@ -187,7 +182,7 @@ class FactoryMetaClass(BaseFactoryMetaClass):
FACTORY_CLASS_DECLARATION,
associated_name,
class_name,
- ), DeprecationWarning, 3)
+ ), PendingDeprecationWarning)
return getattr(factory_module, associated_name)
@@ -266,9 +261,6 @@ class BaseFactory(object):
# class.
_base_factory = None
- # List of arguments that should be passed as *args instead of **kwargs
- FACTORY_ARG_PARAMETERS = ()
-
@classmethod
def _setup_next_sequence(cls):
"""Set up an initial sequence value for Sequence attributes.
@@ -325,36 +317,6 @@ class BaseFactory(object):
return getattr(cls, CLASS_ATTRIBUTE_DECLARATIONS).copy(extra_defs)
@classmethod
- def _build(cls, target_class, *args, **kwargs):
- """Actually build an instance of the target_class.
-
- Customization point, will be called once the full set of args and kwargs
- has been computed.
-
- Args:
- target_class (type): the class for which an instance should be
- built
- args (tuple): arguments to use when building the class
- kwargs (dict): keyword arguments to use when building the class
- """
- return target_class(*args, **kwargs)
-
- @classmethod
- def _create(cls, target_class, *args, **kwargs):
- """Actually create an instance of the target_class.
-
- Customization point, will be called once the full set of args and kwargs
- has been computed.
-
- Args:
- target_class (type): the class for which an instance should be
- created
- args (tuple): arguments to use when creating the class
- kwargs (dict): keyword arguments to use when creating the class
- """
- return target_class(*args, **kwargs)
-
- @classmethod
def build(cls, **kwargs):
"""Build an instance of the associated class, with overriden attrs."""
raise cls.UnsupportedStrategy()
@@ -500,7 +462,7 @@ class Factory(BaseFactory):
# Customizing 'create' strategy, using a tuple to keep the creation function
# from turning it into an instance method.
- _creation_function = (None,)
+ _creation_function = (DJANGO_CREATION,)
@classmethod
def set_creation_function(cls, creation_function):
@@ -512,10 +474,6 @@ class Factory(BaseFactory):
which an instance will be created. The value of the various
fields are passed as keyword arguments.
"""
- warnings.warn(
- "Use of factory.set_creation_function is deprecated, and will be "
- "removed in the future. Please override Factory._create() instead.",
- PendingDeprecationWarning, 2)
cls._creation_function = (creation_function,)
@classmethod
@@ -527,22 +485,11 @@ class Factory(BaseFactory):
an instance will be created, and keyword arguments for the value
of the fields of the instance.
"""
- creation_function = cls._creation_function[0]
- if creation_function:
- return creation_function
- elif cls._create.__func__ == Factory._create.__func__:
- # Backwards compatibility.
- # Default creation_function and default _create() behavior.
- # The best "Vanilla" _create detection algorithm I found is relying
- # on actual method implementation (otherwise, make_factory isn't
- # detected as 'default').
- return DJANGO_CREATION
- else:
- return creation_function
+ return cls._creation_function[0]
# Customizing 'build' strategy, using a tuple to keep the creation function
# from turning it into an instance method.
- _building_function = (None,)
+ _building_function = (NAIVE_BUILD,)
@classmethod
def set_building_function(cls, building_function):
@@ -554,10 +501,6 @@ class Factory(BaseFactory):
which an instance will be built. The value of the various
fields are passed as keyword arguments.
"""
- warnings.warn(
- "Use of factory.set_building_function is deprecated, and will be "
- "removed in the future. Please override Factory._build() instead.",
- PendingDeprecationWarning, 2)
cls._building_function = (building_function,)
@classmethod
@@ -579,23 +522,10 @@ class Factory(BaseFactory):
create: bool, whether to create or to build the object
**kwargs: arguments to pass to the creation function
"""
- target_class = getattr(cls, CLASS_ATTRIBUTE_ASSOCIATED_CLASS)
-
- # Extract *args from **kwargs
- args = tuple(kwargs.pop(key) for key in cls.FACTORY_ARG_PARAMETERS)
-
if create:
- # Backwards compatibility
- creation_function = cls.get_creation_function()
- if creation_function:
- return creation_function(target_class, *args, **kwargs)
- return cls._create(target_class, *args, **kwargs)
+ return cls.get_creation_function()(getattr(cls, CLASS_ATTRIBUTE_ASSOCIATED_CLASS), **kwargs)
else:
- # Backwards compatibility
- building_function = cls.get_building_function()
- if building_function:
- return building_function(target_class, *args, **kwargs)
- return cls._build(target_class, *args, **kwargs)
+ return cls.get_building_function()(getattr(cls, CLASS_ATTRIBUTE_ASSOCIATED_CLASS), **kwargs)
@classmethod
def _generate(cls, create, attrs):
@@ -651,10 +581,6 @@ class DjangoModelFactory(Factory):
except IndexError:
return 1
- def _create(cls, target_class, *args, **kwargs):
- """Create an instance of the model, and save it to the database."""
- return target_class._default_manager.create(*args, **kwargs)
-
def make_factory(klass, **kwargs):
"""Create a new, simple factory for the given class."""
diff --git a/factory/containers.py b/factory/containers.py
index d50cb71..946fbd3 100644
--- a/factory/containers.py
+++ b/factory/containers.py
@@ -124,7 +124,7 @@ class DeclarationDict(dict):
return False
elif isinstance(value, declarations.OrderedDeclaration):
return True
- return (not name.startswith("_") and not name.startswith("FACTORY_"))
+ return (not name.startswith("_"))
def update_with_public(self, d):
"""Updates the DeclarationDict from a class definition dict.
@@ -167,7 +167,7 @@ class PostGenerationDeclarationDict(DeclarationDict):
class LazyValue(object):
"""Some kind of "lazy evaluating" object."""
- def evaluate(self, obj, containers=()): # pragma: no cover
+ def evaluate(self, obj, containers=()):
"""Compute the value, using the given object."""
raise NotImplementedError("This is an abstract method.")
diff --git a/factory/declarations.py b/factory/declarations.py
index 77000f2..83c32ab 100644
--- a/factory/declarations.py
+++ b/factory/declarations.py
@@ -208,115 +208,46 @@ class ContainerAttribute(OrderedDeclaration):
return self.function(obj, containers)
-class ParameteredAttribute(OrderedDeclaration):
- """Base class for attributes expecting parameters.
+class SubFactory(OrderedDeclaration):
+ """Base class for attributes based upon a sub-factory.
Attributes:
- defaults (dict): Default values for the paramters.
- May be overridden by call-time parameters.
-
- Class attributes:
- CONTAINERS_FIELD (str): name of the field, if any, where container
- information (e.g for SubFactory) should be stored. If empty,
- containers data isn't merged into generate() parameters.
+ defaults (dict): Overrides to the defaults defined in the wrapped
+ factory
+ factory (base.Factory): the wrapped factory
"""
- CONTAINERS_FIELD = '__containers'
-
- def __init__(self, **kwargs):
- super(ParameteredAttribute, self).__init__()
+ def __init__(self, factory, **kwargs):
+ super(SubFactory, self).__init__()
self.defaults = kwargs
+ self.factory = factory
def evaluate(self, create, extra, containers):
"""Evaluate the current definition and fill its attributes.
Uses attributes definition in the following order:
- - values defined when defining the ParameteredAttribute
- - additional values defined when instantiating the containing factory
+ - attributes defined in the wrapped factory class
+ - values defined when defining the SubFactory
+ - additional values defined in attributes
Args:
- create (bool): whether the parent factory is being 'built' or
- 'created'
+ create (bool): whether the subfactory should call 'build' or
+ 'create'
extra (containers.DeclarationDict): extra values that should
- override the defaults
+ override the wrapped factory's defaults
containers (list of LazyStub): List of LazyStub for the chain of
factories being evaluated, the calling stub being first.
"""
+
defaults = dict(self.defaults)
if extra:
defaults.update(extra)
- if self.CONTAINERS_FIELD:
- defaults[self.CONTAINERS_FIELD] = containers
+ defaults['__containers'] = containers
- return self.generate(create, defaults)
-
- def generate(self, create, params): # pragma: no cover
- """Actually generate the related attribute.
-
- Args:
- create (bool): whether the calling factory was in 'create' or
- 'build' mode
- params (dict): parameters inherited from init and evaluation-time
- overrides.
-
- Returns:
- Computed value for the current declaration.
- """
- raise NotImplementedError()
-
-
-class SubFactory(ParameteredAttribute):
- """Base class for attributes based upon a sub-factory.
-
- Attributes:
- defaults (dict): Overrides to the defaults defined in the wrapped
- factory
- factory (base.Factory): the wrapped factory
- """
-
- def __init__(self, factory, **kwargs):
- super(SubFactory, self).__init__(**kwargs)
- self.factory = factory
-
- def get_factory(self):
- """Retrieve the wrapped factory.Factory subclass."""
- return self.factory
-
- def generate(self, create, params):
- """Evaluate the current definition and fill its attributes.
-
- Args:
- create (bool): whether the subfactory should call 'build' or
- 'create'
- params (containers.DeclarationDict): extra values that should
- override the wrapped factory's defaults
- """
- subfactory = self.get_factory()
if create:
- return subfactory.create(**params)
+ return self.factory.create(**defaults)
else:
- return subfactory.build(**params)
-
-
-class CircularSubFactory(SubFactory):
- """Use to solve circular dependencies issues."""
- def __init__(self, module_name, factory_name, **kwargs):
- super(CircularSubFactory, self).__init__(None, **kwargs)
- self.module_name = module_name
- self.factory_name = factory_name
-
- def get_factory(self):
- """Retrieve the factory.Factory subclass.
-
- Its value is cached in the 'factory' attribute, and retrieved through
- the factory_getter callable.
- """
- if self.factory is None:
- factory_class = utils.import_object(
- self.module_name, self.factory_name)
-
- self.factory = factory_class
- return self.factory
+ return self.factory.build(**defaults)
class PostGenerationDeclaration(object):
@@ -352,7 +283,7 @@ class PostGenerationDeclaration(object):
kwargs = utils.extract_dict(extract_prefix, attrs)
return extracted, kwargs
- def call(self, obj, create, extracted=None, **kwargs): # pragma: no cover
+ def call(self, obj, create, extracted=None, **kwargs):
"""Call this hook; no return value is expected.
Args:
diff --git a/factory/utils.py b/factory/utils.py
index e7cdf5f..2fcd7ff 100644
--- a/factory/utils.py
+++ b/factory/utils.py
@@ -57,16 +57,20 @@ def extract_dict(prefix, kwargs, pop=True, exclude=()):
return extracted
+def declength_compare(a, b):
+ """Compare objects, choosing longest first."""
+ if len(a) > len(b):
+ return -1
+ elif len(a) < len(b):
+ return 1
+ else:
+ return cmp(a, b)
+
+
def multi_extract_dict(prefixes, kwargs, pop=True, exclude=()):
"""Extracts all values from a given list of prefixes.
- Extraction will start with longer prefixes.
-
- Args:
- prefixes (str list): the prefixes to use for lookups
- kwargs (dict): the dict from which values should be extracted
- pop (bool): whether to use pop (True) or get (False)
- exclude (iterable): list of prefixed keys that shouldn't be extracted
+ Arguments have the same meaning as for extract_dict.
Returns:
dict(str => dict): a dict mapping each prefix to the dict of extracted
@@ -74,22 +78,10 @@ def multi_extract_dict(prefixes, kwargs, pop=True, exclude=()):
"""
results = {}
exclude = list(exclude)
- for prefix in sorted(prefixes, key=lambda x: -len(x)):
+ for prefix in sorted(prefixes, cmp=declength_compare):
extracted = extract_dict(prefix, kwargs, pop=pop, exclude=exclude)
results[prefix] = extracted
exclude.extend(
['%s%s%s' % (prefix, ATTR_SPLITTER, key) for key in extracted])
return results
-
-
-def import_object(module_name, attribute_name):
- """Import an object from its absolute path.
-
- Example:
- >>> import_object('datetime', 'datetime')
- <type 'datetime.datetime'>
- """
- module = __import__(module_name, {}, {}, [attribute_name], 0)
- return getattr(module, attribute_name)
-
diff --git a/setup.py b/setup.py
index 9bff8d1..ace4473 100755
--- a/setup.py
+++ b/setup.py
@@ -1,26 +1,12 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
-import os
-import re
import sys
from distutils.core import setup
from distutils import cmd
-root = os.path.abspath(os.path.dirname(__file__))
-
-def get_version(*module_dir_components):
- version_re = re.compile(r"^__version__ = ['\"](.*)['\"]$")
- module_root = os.path.join(root, *module_dir_components)
- module_init = os.path.join(module_root, '__init__.py')
- with open(module_init, 'r') as f:
- for line in f:
- match = version_re.match(line[:-1])
- if match:
- return match.groups()[0]
- return '0.1.0'
-
-VERSION = get_version('factory')
+# Remember to change in factory/__init__.py as well!
+VERSION = '1.1.5'
class test(cmd.Command):
diff --git a/tests/cyclic/__init__.py b/tests/cyclic/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tests/cyclic/__init__.py
+++ /dev/null
diff --git a/tests/cyclic/bar.py b/tests/cyclic/bar.py
deleted file mode 100644
index cc90930..0000000
--- a/tests/cyclic/bar.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2011-2012 Raphaël Barrois
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-"""Helper to test circular factory dependencies."""
-
-import factory
-
-class Bar(object):
- def __init__(self, foo, y):
- self.foo = foo
- self.y = y
-
-
-class BarFactory(factory.Factory):
- FACTORY_FOR = Bar
-
- y = 13
- foo = factory.CircularSubFactory('cyclic.foo', 'FooFactory')
-
diff --git a/tests/cyclic/foo.py b/tests/cyclic/foo.py
deleted file mode 100644
index e6f8896..0000000
--- a/tests/cyclic/foo.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2011-2012 Raphaël Barrois
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-"""Helper to test circular factory dependencies."""
-
-import factory
-
-from cyclic import bar
-
-class Foo(object):
- def __init__(self, bar, x):
- self.bar = bar
- self.x = x
-
-
-class FooFactory(factory.Factory):
- FACTORY_FOR = Foo
-
- x = 42
- bar = factory.SubFactory(bar.BarFactory)
diff --git a/tests/test_base.py b/tests/test_base.py
index 7ec3d0e..7575ee2 100644
--- a/tests/test_base.py
+++ b/tests/test_base.py
@@ -35,25 +35,19 @@ class TestObject(object):
self.four = four
class FakeDjangoModel(object):
- @classmethod
- def create(cls, **kwargs):
- instance = cls(**kwargs)
- instance.id = 1
- return instance
+ class FakeDjangoManager(object):
+ def create(self, **kwargs):
+ fake_model = FakeDjangoModel(**kwargs)
+ fake_model.id = 1
+ return fake_model
+
+ objects = FakeDjangoManager()
def __init__(self, **kwargs):
for name, value in kwargs.iteritems():
setattr(self, name, value)
self.id = None
-class FakeModelFactory(base.Factory):
- ABSTRACT_FACTORY = True
-
- @classmethod
- def _create(cls, target_class, *args, **kwargs):
- return target_class.create(**kwargs)
-
-
class TestModel(FakeDjangoModel):
pass
@@ -73,8 +67,6 @@ class FactoryTestCase(unittest.TestCase):
def testLazyAttributeNonExistentParam(self):
class TestObjectFactory(base.Factory):
- FACTORY_FOR = TestObject
-
one = declarations.LazyAttribute(lambda a: a.does_not_exist )
self.assertRaises(AttributeError, TestObjectFactory)
@@ -82,13 +74,9 @@ class FactoryTestCase(unittest.TestCase):
def testInheritanceWithSequence(self):
"""Tests that sequence IDs are shared between parent and son."""
class TestObjectFactory(base.Factory):
- FACTORY_FOR = TestObject
-
one = declarations.Sequence(lambda a: a)
class TestSubFactory(TestObjectFactory):
- FACTORY_FOR = TestObject
-
pass
parent = TestObjectFactory.build()
@@ -109,8 +97,6 @@ class FactoryDefaultStrategyTestCase(unittest.TestCase):
base.Factory.default_strategy = base.BUILD_STRATEGY
class TestModelFactory(base.Factory):
- FACTORY_FOR = TestModel
-
one = 'one'
test_model = TestModelFactory()
@@ -120,9 +106,7 @@ class FactoryDefaultStrategyTestCase(unittest.TestCase):
def testCreateStrategy(self):
# Default default_strategy
- class TestModelFactory(FakeModelFactory):
- FACTORY_FOR = TestModel
-
+ class TestModelFactory(base.Factory):
one = 'one'
test_model = TestModelFactory()
@@ -133,8 +117,6 @@ class FactoryDefaultStrategyTestCase(unittest.TestCase):
base.Factory.default_strategy = base.STUB_STRATEGY
class TestModelFactory(base.Factory):
- FACTORY_FOR = TestModel
-
one = 'one'
test_model = TestModelFactory()
@@ -145,16 +127,12 @@ class FactoryDefaultStrategyTestCase(unittest.TestCase):
base.Factory.default_strategy = 'unknown'
class TestModelFactory(base.Factory):
- FACTORY_FOR = TestModel
-
one = 'one'
self.assertRaises(base.Factory.UnknownStrategy, TestModelFactory)
def testStubWithNonStubStrategy(self):
class TestModelFactory(base.StubFactory):
- FACTORY_FOR = TestModel
-
one = 'one'
TestModelFactory.default_strategy = base.CREATE_STRATEGY
@@ -167,8 +145,6 @@ class FactoryDefaultStrategyTestCase(unittest.TestCase):
def test_change_strategy(self):
@base.use_strategy(base.CREATE_STRATEGY)
class TestModelFactory(base.StubFactory):
- FACTORY_FOR = TestModel
-
one = 'one'
self.assertEqual(base.CREATE_STRATEGY, TestModelFactory.default_strategy)
@@ -182,10 +158,8 @@ class FactoryCreationTestCase(unittest.TestCase):
self.assertTrue(isinstance(TestFactory.build(), TestObject))
def testAutomaticAssociatedClassDiscovery(self):
- with warnings.catch_warnings():
- warnings.simplefilter('ignore')
- class TestObjectFactory(base.Factory):
- pass
+ class TestObjectFactory(base.Factory):
+ pass
self.assertTrue(isinstance(TestObjectFactory.build(), TestObject))
@@ -194,7 +168,8 @@ class FactoryCreationTestCase(unittest.TestCase):
with warnings.catch_warnings(record=True) as w:
# Clear the warning registry.
- __warningregistry__.clear()
+ if hasattr(base, '__warningregistry__'):
+ base.__warningregistry__.clear()
warnings.simplefilter('always')
class TestObjectFactory(base.Factory):
@@ -211,8 +186,6 @@ class FactoryCreationTestCase(unittest.TestCase):
def testInheritanceWithStub(self):
class TestObjectFactory(base.StubFactory):
- FACTORY_FOR = TestObject
-
pass
class TestFactory(TestObjectFactory):
@@ -221,9 +194,7 @@ class FactoryCreationTestCase(unittest.TestCase):
self.assertEqual(TestFactory.default_strategy, base.STUB_STRATEGY)
def testCustomCreation(self):
- class TestModelFactory(FakeModelFactory):
- FACTORY_FOR = TestModel
-
+ class TestModelFactory(base.Factory):
@classmethod
def _prepare(cls, create, **kwargs):
kwargs['four'] = 4
@@ -262,16 +233,12 @@ class PostGenerationParsingTestCase(unittest.TestCase):
def test_extraction(self):
class TestObjectFactory(base.Factory):
- FACTORY_FOR = TestObject
-
foo = declarations.PostGenerationDeclaration()
self.assertIn('foo', TestObjectFactory._postgen_declarations)
def test_classlevel_extraction(self):
class TestObjectFactory(base.Factory):
- FACTORY_FOR = TestObject
-
foo = declarations.PostGenerationDeclaration()
foo__bar = 42
diff --git a/tests/test_containers.py b/tests/test_containers.py
index b1ed6ed..797c480 100644
--- a/tests/test_containers.py
+++ b/tests/test_containers.py
@@ -178,17 +178,6 @@ class DeclarationDictTestCase(unittest.TestCase):
self.assertEqual(set(['one', 'three']), set(d))
self.assertEqual(set([1, 3]), set(d.values()))
- def test_update_with_public_ignores_factory_attributes(self):
- """Ensure that a DeclarationDict ignores FACTORY_ keys."""
- d = containers.DeclarationDict()
- d.update_with_public({
- 'one': 1,
- 'FACTORY_FOR': 2,
- 'FACTORY_ARG_PARAMETERS': 3,
- })
- self.assertEqual(['one'], list(d))
- self.assertEqual([1], list(d.values()))
-
class AttributeBuilderTestCase(unittest.TestCase):
def test_empty(self):
diff --git a/tests/test_declarations.py b/tests/test_declarations.py
index c0b3539..1c0502b 100644
--- a/tests/test_declarations.py
+++ b/tests/test_declarations.py
@@ -20,9 +20,8 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
-import datetime
-from factory.declarations import deepgetattr, CircularSubFactory, OrderedDeclaration, \
+from factory.declarations import deepgetattr, OrderedDeclaration, \
PostGenerationDeclaration, Sequence
from .compat import unittest
@@ -74,34 +73,6 @@ class PostGenerationDeclarationTestCase(unittest.TestCase):
self.assertEqual(kwargs, {'baz': 1})
-class CircularSubFactoryTestCase(unittest.TestCase):
- def test_lazyness(self):
- f = CircularSubFactory('factory.declarations', 'Sequence', x=3)
- self.assertEqual(None, f.factory)
-
- self.assertEqual({'x': 3}, f.defaults)
-
- factory_class = f.get_factory()
- self.assertEqual(Sequence, factory_class)
-
- def test_cache(self):
- orig_date = datetime.date
- f = CircularSubFactory('datetime', 'date')
- self.assertEqual(None, f.factory)
-
- factory_class = f.get_factory()
- self.assertEqual(orig_date, factory_class)
-
- try:
- # Modify original value
- datetime.date = None
- # Repeat import
- factory_class = f.get_factory()
- self.assertEqual(orig_date, factory_class)
-
- finally:
- # IMPORTANT: restore attribute.
- datetime.date = orig_date
if __name__ == '__main__':
unittest.main()
diff --git a/tests/test_using.py b/tests/test_using.py
index 7e141eb..f4d5440 100644
--- a/tests/test_using.py
+++ b/tests/test_using.py
@@ -21,11 +21,6 @@
"""Tests using factory."""
-import functools
-import os
-import sys
-import warnings
-
import factory
from .compat import unittest
@@ -39,49 +34,24 @@ class TestObject(object):
self.four = four
self.five = five
-
-class FakeModel(object):
- @classmethod
- def create(cls, **kwargs):
- instance = cls(**kwargs)
- instance.id = 1
- return instance
-
- class FakeModelManager(object):
+class FakeDjangoModel(object):
+ class FakeDjangoManager(object):
def create(self, **kwargs):
- instance = FakeModel.create(**kwargs)
- instance.id = 2
- return instance
+ fake_model = FakeDjangoModel(**kwargs)
+ fake_model.id = 1
+ return fake_model
- objects = FakeModelManager()
+ objects = FakeDjangoManager()
def __init__(self, **kwargs):
for name, value in kwargs.iteritems():
setattr(self, name, value)
self.id = None
-
-class FakeModelFactory(factory.Factory):
- ABSTRACT_FACTORY = True
-
- @classmethod
- def _create(cls, target_class, *args, **kwargs):
- return target_class.create(**kwargs)
-
-
-class TestModel(FakeModel):
+class TestModel(FakeDjangoModel):
pass
-def disable_warnings(fun):
- @functools.wraps(fun)
- def decorated(*args, **kwargs):
- with warnings.catch_warnings():
- warnings.simplefilter('ignore')
- return fun(*args, **kwargs)
- return decorated
-
-
class SimpleBuildTestCase(unittest.TestCase):
"""Tests the minimalist 'factory.build/create' functions."""
@@ -112,21 +82,19 @@ class SimpleBuildTestCase(unittest.TestCase):
self.assertEqual(obj.three, 3)
self.assertEqual(obj.four, None)
- @disable_warnings
def test_create(self):
- obj = factory.create(FakeModel, foo='bar')
- self.assertEqual(obj.id, 2)
+ obj = factory.create(FakeDjangoModel, foo='bar')
+ self.assertEqual(obj.id, 1)
self.assertEqual(obj.foo, 'bar')
- @disable_warnings
def test_create_batch(self):
- objs = factory.create_batch(FakeModel, 4, foo='bar')
+ objs = factory.create_batch(FakeDjangoModel, 4, foo='bar')
self.assertEqual(4, len(objs))
self.assertEqual(4, len(set(objs)))
for obj in objs:
- self.assertEqual(obj.id, 2)
+ self.assertEqual(obj.id, 1)
self.assertEqual(obj.foo, 'bar')
def test_stub(self):
@@ -135,7 +103,7 @@ class SimpleBuildTestCase(unittest.TestCase):
self.assertFalse(hasattr(obj, 'two'))
def test_stub_batch(self):
- objs = factory.stub_batch(FakeModel, 4, foo='bar')
+ objs = factory.stub_batch(FakeDjangoModel, 4, foo='bar')
self.assertEqual(4, len(objs))
self.assertEqual(4, len(set(objs)))
@@ -145,23 +113,22 @@ class SimpleBuildTestCase(unittest.TestCase):
self.assertEqual(obj.foo, 'bar')
def test_generate_build(self):
- obj = factory.generate(FakeModel, factory.BUILD_STRATEGY, foo='bar')
+ obj = factory.generate(FakeDjangoModel, factory.BUILD_STRATEGY, foo='bar')
self.assertEqual(obj.id, None)
self.assertEqual(obj.foo, 'bar')
- @disable_warnings
def test_generate_create(self):
- obj = factory.generate(FakeModel, factory.CREATE_STRATEGY, foo='bar')
- self.assertEqual(obj.id, 2)
+ obj = factory.generate(FakeDjangoModel, factory.CREATE_STRATEGY, foo='bar')
+ self.assertEqual(obj.id, 1)
self.assertEqual(obj.foo, 'bar')
def test_generate_stub(self):
- obj = factory.generate(FakeModel, factory.STUB_STRATEGY, foo='bar')
+ obj = factory.generate(FakeDjangoModel, factory.STUB_STRATEGY, foo='bar')
self.assertFalse(hasattr(obj, 'id'))
self.assertEqual(obj.foo, 'bar')
def test_generate_batch_build(self):
- objs = factory.generate_batch(FakeModel, factory.BUILD_STRATEGY, 20, foo='bar')
+ objs = factory.generate_batch(FakeDjangoModel, factory.BUILD_STRATEGY, 20, foo='bar')
self.assertEqual(20, len(objs))
self.assertEqual(20, len(set(objs)))
@@ -170,19 +137,18 @@ class SimpleBuildTestCase(unittest.TestCase):
self.assertEqual(obj.id, None)
self.assertEqual(obj.foo, 'bar')
- @disable_warnings
def test_generate_batch_create(self):
- objs = factory.generate_batch(FakeModel, factory.CREATE_STRATEGY, 20, foo='bar')
+ objs = factory.generate_batch(FakeDjangoModel, factory.CREATE_STRATEGY, 20, foo='bar')
self.assertEqual(20, len(objs))
self.assertEqual(20, len(set(objs)))
for obj in objs:
- self.assertEqual(obj.id, 2)
+ self.assertEqual(obj.id, 1)
self.assertEqual(obj.foo, 'bar')
def test_generate_batch_stub(self):
- objs = factory.generate_batch(FakeModel, factory.STUB_STRATEGY, 20, foo='bar')
+ objs = factory.generate_batch(FakeDjangoModel, factory.STUB_STRATEGY, 20, foo='bar')
self.assertEqual(20, len(objs))
self.assertEqual(20, len(set(objs)))
@@ -192,18 +158,17 @@ class SimpleBuildTestCase(unittest.TestCase):
self.assertEqual(obj.foo, 'bar')
def test_simple_generate_build(self):
- obj = factory.simple_generate(FakeModel, False, foo='bar')
+ obj = factory.simple_generate(FakeDjangoModel, False, foo='bar')
self.assertEqual(obj.id, None)
self.assertEqual(obj.foo, 'bar')
- @disable_warnings
def test_simple_generate_create(self):
- obj = factory.simple_generate(FakeModel, True, foo='bar')
- self.assertEqual(obj.id, 2)
+ obj = factory.simple_generate(FakeDjangoModel, True, foo='bar')
+ self.assertEqual(obj.id, 1)
self.assertEqual(obj.foo, 'bar')
def test_simple_generate_batch_build(self):
- objs = factory.simple_generate_batch(FakeModel, False, 20, foo='bar')
+ objs = factory.simple_generate_batch(FakeDjangoModel, False, 20, foo='bar')
self.assertEqual(20, len(objs))
self.assertEqual(20, len(set(objs)))
@@ -212,15 +177,14 @@ class SimpleBuildTestCase(unittest.TestCase):
self.assertEqual(obj.id, None)
self.assertEqual(obj.foo, 'bar')
- @disable_warnings
def test_simple_generate_batch_create(self):
- objs = factory.simple_generate_batch(FakeModel, True, 20, foo='bar')
+ objs = factory.simple_generate_batch(FakeDjangoModel, True, 20, foo='bar')
self.assertEqual(20, len(objs))
self.assertEqual(20, len(set(objs)))
for obj in objs:
- self.assertEqual(obj.id, 2)
+ self.assertEqual(obj.id, 1)
self.assertEqual(obj.foo, 'bar')
def test_make_factory(self):
@@ -242,8 +206,6 @@ class SimpleBuildTestCase(unittest.TestCase):
class UsingFactoryTestCase(unittest.TestCase):
def testAttribute(self):
class TestObjectFactory(factory.Factory):
- FACTORY_FOR = TestObject
-
one = 'one'
test_object = TestObjectFactory.build()
@@ -262,8 +224,6 @@ class UsingFactoryTestCase(unittest.TestCase):
def testSequence(self):
class TestObjectFactory(factory.Factory):
- FACTORY_FOR = TestObject
-
one = factory.Sequence(lambda n: 'one' + n)
two = factory.Sequence(lambda n: 'two' + n)
@@ -277,8 +237,6 @@ class UsingFactoryTestCase(unittest.TestCase):
def testSequenceCustomBegin(self):
class TestObjectFactory(factory.Factory):
- FACTORY_FOR = TestObject
-
@classmethod
def _setup_next_sequence(cls):
return 42
@@ -296,8 +254,6 @@ class UsingFactoryTestCase(unittest.TestCase):
def test_sequence_batch(self):
class TestObjectFactory(factory.Factory):
- FACTORY_FOR = TestObject
-
one = factory.Sequence(lambda n: 'one' + n)
two = factory.Sequence(lambda n: 'two' + n)
@@ -311,8 +267,6 @@ class UsingFactoryTestCase(unittest.TestCase):
def testLazyAttribute(self):
class TestObjectFactory(factory.Factory):
- FACTORY_FOR = TestObject
-
one = factory.LazyAttribute(lambda a: 'abc' )
two = factory.LazyAttribute(lambda a: a.one + ' xyz')
@@ -322,8 +276,6 @@ class UsingFactoryTestCase(unittest.TestCase):
def testLazyAttributeSequence(self):
class TestObjectFactory(factory.Factory):
- FACTORY_FOR = TestObject
-
one = factory.LazyAttributeSequence(lambda a, n: 'abc' + n)
two = factory.LazyAttributeSequence(lambda a, n: a.one + ' xyz' + n)
@@ -337,8 +289,6 @@ class UsingFactoryTestCase(unittest.TestCase):
def testLazyAttributeDecorator(self):
class TestObjectFactory(factory.Factory):
- FACTORY_FOR = TestObject
-
@factory.lazy_attribute
def one(a):
return 'one'
@@ -351,8 +301,6 @@ class UsingFactoryTestCase(unittest.TestCase):
n = 3
class TestObjectFactory(factory.Factory):
- FACTORY_FOR = TestObject
-
one = 'xx'
two = factory.SelfAttribute('one')
three = TmpObj()
@@ -367,8 +315,6 @@ class UsingFactoryTestCase(unittest.TestCase):
def testSequenceDecorator(self):
class TestObjectFactory(factory.Factory):
- FACTORY_FOR = TestObject
-
@factory.sequence
def one(n):
return 'one' + n
@@ -378,8 +324,6 @@ class UsingFactoryTestCase(unittest.TestCase):
def testLazyAttributeSequenceDecorator(self):
class TestObjectFactory(factory.Factory):
- FACTORY_FOR = TestObject
-
@factory.lazy_attribute_sequence
def one(a, n):
return 'one' + n
@@ -393,8 +337,6 @@ class UsingFactoryTestCase(unittest.TestCase):
def testBuildWithParameters(self):
class TestObjectFactory(factory.Factory):
- FACTORY_FOR = TestObject
-
one = factory.Sequence(lambda n: 'one' + n)
two = factory.Sequence(lambda n: 'two' + n)
@@ -408,9 +350,7 @@ class UsingFactoryTestCase(unittest.TestCase):
self.assertEqual(test_object1.two, 'two1')
def testCreate(self):
- class TestModelFactory(FakeModelFactory):
- FACTORY_FOR = TestModel
-
+ class TestModelFactory(factory.Factory):
one = 'one'
test_model = TestModelFactory.create()
@@ -418,9 +358,7 @@ class UsingFactoryTestCase(unittest.TestCase):
self.assertTrue(test_model.id)
def test_create_batch(self):
- class TestModelFactory(FakeModelFactory):
- FACTORY_FOR = TestModel
-
+ class TestModelFactory(factory.Factory):
one = 'one'
objs = TestModelFactory.create_batch(20, two=factory.Sequence(int))
@@ -434,9 +372,7 @@ class UsingFactoryTestCase(unittest.TestCase):
self.assertTrue(obj.id)
def test_generate_build(self):
- class TestModelFactory(FakeModelFactory):
- FACTORY_FOR = TestModel
-
+ class TestModelFactory(factory.Factory):
one = 'one'
test_model = TestModelFactory.generate(factory.BUILD_STRATEGY)
@@ -444,9 +380,7 @@ class UsingFactoryTestCase(unittest.TestCase):
self.assertFalse(test_model.id)
def test_generate_create(self):
- class TestModelFactory(FakeModelFactory):
- FACTORY_FOR = TestModel
-
+ class TestModelFactory(factory.Factory):
one = 'one'
test_model = TestModelFactory.generate(factory.CREATE_STRATEGY)
@@ -454,9 +388,7 @@ class UsingFactoryTestCase(unittest.TestCase):
self.assertTrue(test_model.id)
def test_generate_stub(self):
- class TestModelFactory(FakeModelFactory):
- FACTORY_FOR = TestModel
-
+ class TestModelFactory(factory.Factory):
one = 'one'
test_model = TestModelFactory.generate(factory.STUB_STRATEGY)
@@ -464,9 +396,7 @@ class UsingFactoryTestCase(unittest.TestCase):
self.assertFalse(hasattr(test_model, 'id'))
def test_generate_batch_build(self):
- class TestModelFactory(FakeModelFactory):
- FACTORY_FOR = TestModel
-
+ class TestModelFactory(factory.Factory):
one = 'one'
objs = TestModelFactory.generate_batch(factory.BUILD_STRATEGY, 20, two='two')
@@ -480,9 +410,7 @@ class UsingFactoryTestCase(unittest.TestCase):
self.assertFalse(obj.id)
def test_generate_batch_create(self):
- class TestModelFactory(FakeModelFactory):
- FACTORY_FOR = TestModel
-
+ class TestModelFactory(factory.Factory):
one = 'one'
objs = TestModelFactory.generate_batch(factory.CREATE_STRATEGY, 20, two='two')
@@ -496,9 +424,7 @@ class UsingFactoryTestCase(unittest.TestCase):
self.assertTrue(obj.id)
def test_generate_batch_stub(self):
- class TestModelFactory(FakeModelFactory):
- FACTORY_FOR = TestModel
-
+ class TestModelFactory(factory.Factory):
one = 'one'
objs = TestModelFactory.generate_batch(factory.STUB_STRATEGY, 20, two='two')
@@ -512,9 +438,7 @@ class UsingFactoryTestCase(unittest.TestCase):
self.assertFalse(hasattr(obj, 'id'))
def test_simple_generate_build(self):
- class TestModelFactory(FakeModelFactory):
- FACTORY_FOR = TestModel
-
+ class TestModelFactory(factory.Factory):
one = 'one'
test_model = TestModelFactory.simple_generate(False)
@@ -522,9 +446,7 @@ class UsingFactoryTestCase(unittest.TestCase):
self.assertFalse(test_model.id)
def test_simple_generate_create(self):
- class TestModelFactory(FakeModelFactory):
- FACTORY_FOR = TestModel
-
+ class TestModelFactory(factory.Factory):
one = 'one'
test_model = TestModelFactory.simple_generate(True)
@@ -532,9 +454,7 @@ class UsingFactoryTestCase(unittest.TestCase):
self.assertTrue(test_model.id)
def test_simple_generate_batch_build(self):
- class TestModelFactory(FakeModelFactory):
- FACTORY_FOR = TestModel
-
+ class TestModelFactory(factory.Factory):
one = 'one'
objs = TestModelFactory.simple_generate_batch(False, 20, two='two')
@@ -548,9 +468,7 @@ class UsingFactoryTestCase(unittest.TestCase):
self.assertFalse(obj.id)
def test_simple_generate_batch_create(self):
- class TestModelFactory(FakeModelFactory):
- FACTORY_FOR = TestModel
-
+ class TestModelFactory(factory.Factory):
one = 'one'
objs = TestModelFactory.simple_generate_batch(True, 20, two='two')
@@ -565,8 +483,6 @@ class UsingFactoryTestCase(unittest.TestCase):
def test_stub_batch(self):
class TestObjectFactory(factory.Factory):
- FACTORY_FOR = TestObject
-
one = 'one'
two = factory.LazyAttribute(lambda a: a.one + ' two')
three = factory.Sequence(lambda n: int(n))
@@ -584,8 +500,6 @@ class UsingFactoryTestCase(unittest.TestCase):
def testInheritance(self):
class TestObjectFactory(factory.Factory):
- FACTORY_FOR = TestObject
-
one = 'one'
two = factory.LazyAttribute(lambda a: a.one + ' two')
@@ -606,8 +520,6 @@ class UsingFactoryTestCase(unittest.TestCase):
def testInheritanceWithInheritedClass(self):
class TestObjectFactory(factory.Factory):
- FACTORY_FOR = TestObject
-
one = 'one'
two = factory.LazyAttribute(lambda a: a.one + ' two')
@@ -623,8 +535,6 @@ class UsingFactoryTestCase(unittest.TestCase):
def testDualInheritance(self):
class TestObjectFactory(factory.Factory):
- FACTORY_FOR = TestObject
-
one = 'one'
class TestOtherFactory(factory.Factory):
@@ -641,13 +551,12 @@ class UsingFactoryTestCase(unittest.TestCase):
self.assertEqual('three', obj.three)
self.assertEqual('four', obj.four)
- @disable_warnings
def testSetCreationFunction(self):
def creation_function(class_to_create, **kwargs):
return "This doesn't even return an instance of {0}".format(class_to_create.__name__)
- class TestModelFactory(FakeModelFactory):
- FACTORY_FOR = TestModel
+ class TestModelFactory(factory.Factory):
+ pass
TestModelFactory.set_creation_function(creation_function)
@@ -656,8 +565,6 @@ class UsingFactoryTestCase(unittest.TestCase):
def testClassMethodAccessible(self):
class TestObjectFactory(factory.Factory):
- FACTORY_FOR = TestObject
-
@classmethod
def alt_create(cls, **kwargs):
return kwargs
@@ -666,8 +573,6 @@ class UsingFactoryTestCase(unittest.TestCase):
def testStaticMethodAccessible(self):
class TestObjectFactory(factory.Factory):
- FACTORY_FOR = TestObject
-
@staticmethod
def alt_create(**kwargs):
return kwargs
@@ -675,65 +580,16 @@ class UsingFactoryTestCase(unittest.TestCase):
self.assertEqual(TestObjectFactory.alt_create(foo=1), {"foo": 1})
-class NonKwargParametersTestCase(unittest.TestCase):
- def test_build(self):
- class TestObject(object):
- def __init__(self, *args, **kwargs):
- self.args = args
- self.kwargs = kwargs
-
- class TestObjectFactory(factory.Factory):
- FACTORY_FOR = TestObject
- FACTORY_ARG_PARAMETERS = ('one', 'two',)
-
- one = 1
- two = 2
- three = 3
-
- obj = TestObjectFactory.build()
- self.assertEqual((1, 2), obj.args)
- self.assertEqual({'three': 3}, obj.kwargs)
-
- def test_create(self):
- class TestObject(object):
- def __init__(self, *args, **kwargs):
- self.args = None
- self.kwargs = None
-
- @classmethod
- def create(cls, *args, **kwargs):
- inst = cls()
- inst.args = args
- inst.kwargs = kwargs
- return inst
-
- class TestObjectFactory(factory.Factory):
- FACTORY_FOR = TestObject
- FACTORY_ARG_PARAMETERS = ('one', 'two')
-
- one = 1
- two = 2
- three = 3
-
- @classmethod
- def _create(cls, target_class, *args, **kwargs):
- return target_class.create(*args, **kwargs)
-
- obj = TestObjectFactory.create()
- self.assertEqual((1, 2), obj.args)
- self.assertEqual({'three': 3}, obj.kwargs)
-
-
class SubFactoryTestCase(unittest.TestCase):
def testSubFactory(self):
- class TestModel2(FakeModel):
+ class TestModel2(FakeDjangoModel):
pass
- class TestModelFactory(FakeModelFactory):
+ class TestModelFactory(factory.Factory):
FACTORY_FOR = TestModel
one = 3
- class TestModel2Factory(FakeModelFactory):
+ class TestModel2Factory(factory.Factory):
FACTORY_FOR = TestModel2
two = factory.SubFactory(TestModelFactory, one=1)
@@ -743,13 +599,13 @@ class SubFactoryTestCase(unittest.TestCase):
self.assertEqual(1, test_model.two.id)
def testSubFactoryWithLazyFields(self):
- class TestModel2(FakeModel):
+ class TestModel2(FakeDjangoModel):
pass
- class TestModelFactory(FakeModelFactory):
+ class TestModelFactory(factory.Factory):
FACTORY_FOR = TestModel
- class TestModel2Factory(FakeModelFactory):
+ class TestModel2Factory(factory.Factory):
FACTORY_FOR = TestModel2
two = factory.SubFactory(TestModelFactory,
one=factory.Sequence(lambda n: 'x%sx' % n),
@@ -941,85 +797,11 @@ class SubFactoryTestCase(unittest.TestCase):
self.assertEqual(outer.side_a.inner_from_a.a, outer.foo * 2)
self.assertEqual(outer.side_a.inner_from_a.b, 4)
- def test_nonstrict_container_attribute(self):
- class TestModel2(FakeModel):
- pass
-
- class TestModelFactory(FakeModelFactory):
- FACTORY_FOR = TestModel
- one = 3
- two = factory.ContainerAttribute(lambda obj, containers: len(containers or []), strict=False)
-
- class TestModel2Factory(FakeModelFactory):
- FACTORY_FOR = TestModel2
- one = 1
- two = factory.SubFactory(TestModelFactory, one=1)
-
- obj = TestModel2Factory.build()
- self.assertEqual(1, obj.one)
- self.assertEqual(1, obj.two.one)
- self.assertEqual(1, obj.two.two)
-
- obj = TestModelFactory()
- self.assertEqual(3, obj.one)
- self.assertEqual(0, obj.two)
-
- def test_strict_container_attribute(self):
- class TestModel2(FakeModel):
- pass
-
- class TestModelFactory(FakeModelFactory):
- FACTORY_FOR = TestModel
- one = 3
- two = factory.ContainerAttribute(lambda obj, containers: len(containers or []), strict=True)
-
- class TestModel2Factory(FakeModelFactory):
- FACTORY_FOR = TestModel2
- one = 1
- two = factory.SubFactory(TestModelFactory, one=1)
-
- obj = TestModel2Factory.build()
- self.assertEqual(1, obj.one)
- self.assertEqual(1, obj.two.one)
- self.assertEqual(1, obj.two.two)
-
- self.assertRaises(TypeError, TestModelFactory.build)
-
- def test_function_container_attribute(self):
- class TestModel2(FakeModel):
- pass
-
- class TestModelFactory(FakeModelFactory):
- FACTORY_FOR = TestModel
- one = 3
-
- @factory.container_attribute
- def two(self, containers):
- if containers:
- return len(containers)
- return 42
-
- class TestModel2Factory(FakeModelFactory):
- FACTORY_FOR = TestModel2
- one = 1
- two = factory.SubFactory(TestModelFactory, one=1)
-
- obj = TestModel2Factory.build()
- self.assertEqual(1, obj.one)
- self.assertEqual(1, obj.two.one)
- self.assertEqual(1, obj.two.two)
-
- obj = TestModelFactory()
- self.assertEqual(3, obj.one)
- self.assertEqual(42, obj.two)
-
class IteratorTestCase(unittest.TestCase):
def test_iterator(self):
class TestObjectFactory(factory.Factory):
- FACTORY_FOR = TestObject
-
one = factory.Iterator(xrange(10, 30))
objs = TestObjectFactory.build_batch(20)
@@ -1029,8 +811,6 @@ class IteratorTestCase(unittest.TestCase):
def test_infinite_iterator(self):
class TestObjectFactory(factory.Factory):
- FACTORY_FOR = TestObject
-
one = factory.InfiniteIterator(xrange(5))
objs = TestObjectFactory.build_batch(20)
@@ -1040,8 +820,6 @@ class IteratorTestCase(unittest.TestCase):
def test_infinite_iterator_list_comprehension(self):
class TestObjectFactory(factory.Factory):
- FACTORY_FOR = TestObject
-
one = factory.InfiniteIterator([j * 3 for j in xrange(5)])
# Scope bleeding: j will end up in TestObjectFactory's scope.
@@ -1050,8 +828,6 @@ class IteratorTestCase(unittest.TestCase):
def test_infinite_iterator_list_comprehension_protected(self):
class TestObjectFactory(factory.Factory):
- FACTORY_FOR = TestObject
-
one = factory.InfiniteIterator([_j * 3 for _j in xrange(5)])
# Scope bleeding : _j will end up in TestObjectFactory's scope.
@@ -1063,8 +839,6 @@ class IteratorTestCase(unittest.TestCase):
def test_iterator_decorator(self):
class TestObjectFactory(factory.Factory):
- FACTORY_FOR = TestObject
-
@factory.iterator
def one():
for i in xrange(10, 50):
@@ -1077,8 +851,6 @@ class IteratorTestCase(unittest.TestCase):
def test_infinite_iterator_decorator(self):
class TestObjectFactory(factory.Factory):
- FACTORY_FOR = TestObject
-
@factory.infinite_iterator
def one():
for i in xrange(5):
@@ -1093,8 +865,6 @@ class IteratorTestCase(unittest.TestCase):
class PostGenerationTestCase(unittest.TestCase):
def test_post_generation(self):
class TestObjectFactory(factory.Factory):
- FACTORY_FOR = TestObject
-
one = 1
@factory.post_generation()
@@ -1111,8 +881,6 @@ class PostGenerationTestCase(unittest.TestCase):
def test_post_generation_extraction(self):
class TestObjectFactory(factory.Factory):
- FACTORY_FOR = TestObject
-
one = 1
@factory.post_generation()
@@ -1136,40 +904,10 @@ class PostGenerationTestCase(unittest.TestCase):
self.assertEqual(kwargs, {'foo': 13})
class TestObjectFactory(factory.Factory):
- FACTORY_FOR = TestObject
-
bar = factory.PostGeneration(my_lambda)
obj = TestObjectFactory.build(bar=42, bar__foo=13)
- def test_post_generation_method_call(self):
- calls = []
-
- class TestObject(object):
- def __init__(self, one=None, two=None):
- self.one = one
- self.two = two
- self.extra = None
-
- def call(self, *args, **kwargs):
- self.extra = (args, kwargs)
-
- class TestObjectFactory(factory.Factory):
- FACTORY_FOR = TestObject
- one = 3
- two = 2
- post_call = factory.PostGenerationMethodCall('call', one=1)
-
- obj = TestObjectFactory.build()
- self.assertEqual(3, obj.one)
- self.assertEqual(2, obj.two)
- self.assertEqual(((), {'one': 1}), obj.extra)
-
- obj = TestObjectFactory.build(post_call__one=2, post_call__two=3)
- self.assertEqual(3, obj.one)
- self.assertEqual(2, obj.two)
- self.assertEqual(((), {'one': 2, 'two': 3}), obj.extra)
-
def test_related_factory(self):
class TestRelatedObject(object):
def __init__(self, obj=None, one=None, two=None):
@@ -1215,25 +953,5 @@ class PostGenerationTestCase(unittest.TestCase):
self.assertEqual(obj, obj.related.three)
-class CircularTestCase(unittest.TestCase):
- def test_example(self):
- sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
-
- from cyclic import foo
- f = foo.FooFactory.build(bar__foo=None)
- self.assertEqual(42, f.x)
- self.assertEqual(13, f.bar.y)
- self.assertIsNone(f.bar.foo)
-
- from cyclic import bar
- b = bar.BarFactory.build(foo__bar__foo__bar=None)
- self.assertEqual(13, b.y)
- self.assertEqual(42, b.foo.x)
- self.assertEqual(13, b.foo.bar.y)
- self.assertEqual(42, b.foo.bar.foo.x)
- self.assertIsNone(b.foo.bar.foo.bar)
-
-
-
if __name__ == '__main__':
unittest.main()
diff --git a/tests/test_utils.py b/tests/test_utils.py
index 9aaafc1..6fd6ee2 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -25,6 +25,23 @@ from factory import utils
from .compat import unittest
+class DecLengthCompareTestCase(unittest.TestCase):
+ def test_reciprocity(self):
+ self.assertEqual(1, utils.declength_compare('a', 'bb'))
+ self.assertEqual(-1, utils.declength_compare('aa', 'b'))
+
+ def test_not_lexical(self):
+ self.assertEqual(1, utils.declength_compare('abc', 'aaaa'))
+ self.assertEqual(-1, utils.declength_compare('aaaa', 'abc'))
+
+ def test_same_length(self):
+ self.assertEqual(-1, utils.declength_compare('abc', 'abd'))
+ self.assertEqual(1, utils.declength_compare('abe', 'abd'))
+
+ def test_equality(self):
+ self.assertEqual(0, utils.declength_compare('abc', 'abc'))
+ self.assertEqual(0, utils.declength_compare([1, 2, 3], [1, 2, 3]))
+
class ExtractDictTestCase(unittest.TestCase):
def test_empty_dict(self):
@@ -85,7 +102,6 @@ class ExtractDictTestCase(unittest.TestCase):
self.assertIn('foo__bar', d)
self.assertNotIn('foo__foo__bar', d)
-
class MultiExtractDictTestCase(unittest.TestCase):
def test_empty_dict(self):
self.assertEqual({'foo': {}}, utils.multi_extract_dict(['foo'], {}))
@@ -214,19 +230,3 @@ class MultiExtractDictTestCase(unittest.TestCase):
self.assertNotIn('foo__foo__bar', d)
self.assertNotIn('bar__foo', d)
self.assertNotIn('bar__bar__baz', d)
-
-
-class ImportObjectTestCase(unittest.TestCase):
- def test_datetime(self):
- imported = utils.import_object('datetime', 'date')
- import datetime
- d = datetime.date
- self.assertEqual(d, imported)
-
- def test_unknown_attribute(self):
- self.assertRaises(AttributeError, utils.import_object,
- 'datetime', 'foo')
-
- def test_invalid_module(self):
- self.assertRaises(ImportError, utils.import_object,
- 'this-is-an-invalid-module', '__name__')