summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaphaël Barrois <raphael.barrois@polytechnique.org>2013-04-03 01:17:26 +0200
committerRaphaël Barrois <raphael.barrois@polytechnique.org>2013-04-03 01:19:45 +0200
commit8c1784e8c1eac65f66b4a1ecc4b8b0ddd5de9327 (patch)
tree0b1d368f114de4235dc3d88e2dfc41b3403d16ef
parent3aee208ee7cdf480cbc173cf3084ce2217a5944f (diff)
downloadfactory-boy-8c1784e8c1eac65f66b4a1ecc4b8b0ddd5de9327.tar
factory-boy-8c1784e8c1eac65f66b4a1ecc4b8b0ddd5de9327.tar.gz
Pylint.
-rw-r--r--.pylintrc240
-rw-r--r--Makefile18
-rw-r--r--factory/__init__.py28
-rw-r--r--factory/base.py123
-rw-r--r--factory/compat.py10
-rw-r--r--factory/containers.py7
-rw-r--r--factory/declarations.py39
-rw-r--r--factory/helpers.py123
-rw-r--r--tests/test_declarations.py3
9 files changed, 445 insertions, 146 deletions
diff --git a/.pylintrc b/.pylintrc
new file mode 100644
index 0000000..e9f43c9
--- /dev/null
+++ b/.pylintrc
@@ -0,0 +1,240 @@
+[MASTER]
+
+# Specify a configuration file.
+#rcfile=
+
+# Python code to execute, usually for sys.path manipulation such as
+# pygtk.require().
+init-hook='import os, sys; sys.path.append(os.getcwd())'
+
+# Profiled execution.
+profile=no
+
+# Add <file or directory> to the black list. It should be a base name, not a
+# path. You may set this option multiple times.
+ignore=
+
+# Pickle collected data for later comparisons.
+persistent=yes
+
+# List of plugins (as comma separated values of python modules names) to load,
+# usually to register additional checkers.
+load-plugins=
+
+
+[MESSAGES CONTROL]
+
+# Enable the message, report, category or checker with the given id(s). You can
+# either give multiple identifier separated by comma (,) or put this option
+# multiple time.
+#enable=
+
+# Disable the message, report, category or checker with the given id(s). You
+# can either give multiple identifier separated by comma (,) or put this option
+# multiple time (only on the command line, not in the configuration file where
+# it should appear only once).
+#disable=C0103,C0111,C0302,E1002,E1101,E1102,E1103,I0011,I0013,R0201,R0801,R0901,R0902,R0903,R0904,R0912,R0914,R0915,R0921,R0923,W0108,W0212,W0232,W0141,W0142,W0401,W0613,R0924
+disable=C0103,C0111,I0011,R0201,R0903,R0922,W0142,W0212,W0232,W0613
+# see http://www.logilab.org/card/pylintfeatures
+
+
+[REPORTS]
+
+# Set the output format. Available formats are text, parseable, colorized, msvs
+# (visual studio) and html
+output-format=text
+
+# Include message's id in output
+include-ids=yes
+
+# Put messages in a separate file for each module / package specified on the
+# command line instead of printing them on stdout. Reports (if any) will be
+# written in a file name "pylint_global.[txt|html]".
+files-output=no
+
+# Tells whether to display a full report or only the messages
+reports=yes
+
+# Python expression which should return a note less than 10 (10 is the highest
+# note). You have access to the variables errors warning, statement which
+# respectively contain the number of errors / warnings messages and the total
+# number of statements analyzed. This is used by the global evaluation report
+# (RP0004).
+evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
+
+# Add a comment according to your evaluation note. This is used by the global
+# evaluation report (RP0004).
+comment=no
+
+
+[BASIC]
+
+# Required attributes for module, separated by a comma
+required-attributes=
+
+# List of builtins function names that should not be used, separated by a comma
+bad-functions=map,filter,apply,input
+
+# Regular expression which should only match correct module names
+module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
+
+# Regular expression which should only match correct module level names
+const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
+
+# Regular expression which should only match correct class names
+class-rgx=[A-Z_][a-zA-Z0-9]+$
+
+# Regular expression which should only match correct function names
+function-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Regular expression which should only match correct method names
+method-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Regular expression which should only match correct instance attribute names
+attr-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Regular expression which should only match correct argument names
+argument-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Regular expression which should only match correct variable names
+variable-rgx=[a-z_][a-z0-9_]{2,30}$
+
+# Regular expression which should only match correct list comprehension /
+# generator expression variable names
+inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
+
+# Good variable names which should always be accepted, separated by a comma
+good-names=i,j,k,ex,Run,_
+
+# Bad variable names which should always be refused, separated by a comma
+bad-names=foo,bar,baz,toto,tutu,tata
+
+# Regular expression which should only match functions or classes name which do
+# not require a docstring
+no-docstring-rgx=__.*__
+
+
+[FORMAT]
+
+# Maximum number of characters on a single line.
+max-line-length=80
+
+# Maximum number of lines in a module
+max-module-lines=1200
+
+# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
+# tab).
+indent-string=' '
+
+
+[MISCELLANEOUS]
+
+# List of note tags to take in consideration, separated by a comma.
+notes=FIXME,XXX,TODO
+
+
+[SIMILARITIES]
+
+# Minimum lines number of a similarity.
+min-similarity-lines=4
+
+# Ignore comments when computing similarities.
+ignore-comments=yes
+
+# Ignore docstrings when computing similarities.
+ignore-docstrings=yes
+
+
+[TYPECHECK]
+
+# Tells whether missing members accessed in mixin class should be ignored. A
+# mixin class is detected if its name ends with "mixin" (case insensitive).
+ignore-mixin-members=yes
+
+# List of classes names for which member attributes should not be checked
+# (useful for classes with attributes dynamically set).
+ignored-classes=SQLObject
+
+# When zope mode is activated, add a predefined set of Zope acquired attributes
+# to generated-members.
+zope=no
+
+# List of members which are set dynamically and missed by pylint inference
+# system, and so shouldn't trigger E0201 when accessed.
+generated-members=REQUEST,acl_users,aq_parent
+
+
+[VARIABLES]
+
+# Tells whether we should check for unused import in __init__ files.
+init-import=no
+
+# A regular expression matching the beginning of the name of dummy variables
+# (i.e. not used).
+dummy-variables-rgx=_|dummy
+
+# List of additional names supposed to be defined in builtins. Remember that
+# you should avoid to define new builtins when possible.
+additional-builtins=
+
+
+[CLASSES]
+
+# List of interface methods to ignore, separated by a comma. This is used for
+# instance to not check methods defines in Zope's Interface base class.
+ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by
+
+# List of method names used to declare (i.e. assign) instance attributes.
+defining-attr-methods=__init__,__new__,setUp
+
+
+[DESIGN]
+
+# Maximum number of arguments for function / method
+max-args=8
+
+# Argument names that match this expression will be ignored. Default to name
+# with leading underscore
+ignored-argument-names=_.*
+
+# Maximum number of locals for function / method body
+max-locals=15
+
+# Maximum number of return / yield for function / method body
+max-returns=6
+
+# Maximum number of branch for function / method body
+max-branchs=12
+
+# Maximum number of statements in function / method body
+max-statements=50
+
+# Maximum number of parents for a class (see R0901).
+max-parents=10
+
+# Maximum number of attributes for a class (see R0902).
+max-attributes=10
+
+# Minimum number of public methods for a class (see R0903).
+min-public-methods=2
+
+# Maximum number of public methods for a class (see R0904).
+max-public-methods=20
+
+
+[IMPORTS]
+
+# Deprecated modules which should not be used, separated by a comma
+deprecated-modules=regsub,string,TERMIOS,Bastion,rexec
+
+# Create a graph of every (i.e. internal and external) dependencies in the
+# given file (report RP0402 must not be disabled)
+import-graph=
+
+# Create a graph of external dependencies in the given file (report RP0402 must
+# not be disabled)
+ext-import-graph=
+
+# Create a graph of internal dependencies in the given file (report RP0402 must
+# not be disabled)
+int-import-graph=
diff --git a/Makefile b/Makefile
index f9c27c0..274ee32 100644
--- a/Makefile
+++ b/Makefile
@@ -1,3 +1,8 @@
+PACKAGE=factory
+TESTS_DIR=tests
+DOC_DIR=docs
+
+
all: default
@@ -11,14 +16,17 @@ clean:
test:
python -W default setup.py test
+pylint:
+ pylint --rcfile=.pylintrc --report=no $(PACKAGE)/
+
coverage:
coverage erase
- coverage run "--include=factory/*.py,tests/*.py" --branch setup.py test
- coverage report "--include=factory/*.py,tests/*.py"
- coverage html "--include=factory/*.py,tests/*.py"
+ coverage run "--include=$(PACKAGE)/*.py,$(TESTS_DIR)/*.py" --branch setup.py test
+ coverage report "--include=$(PACKAGE)/*.py,$(TESTS_DIR)/*.py"
+ coverage html "--include=$(PACKAGE)/*.py,$(TESTS_DIR)/*.py"
doc:
- $(MAKE) -C docs html
+ $(MAKE) -C $(DOC_DIR) html
-.PHONY: all default clean coverage doc test
+.PHONY: all default clean coverage doc pylint test
diff --git a/factory/__init__.py b/factory/__init__.py
index adcf9c9..beb422e 100644
--- a/factory/__init__.py
+++ b/factory/__init__.py
@@ -28,19 +28,6 @@ from .base import (
StubFactory,
DjangoModelFactory,
- build,
- create,
- stub,
- generate,
- simple_generate,
- make_factory,
-
- build_batch,
- create_batch,
- stub_batch,
- generate_batch,
- simple_generate_batch,
-
BUILD_STRATEGY,
CREATE_STRATEGY,
STUB_STRATEGY,
@@ -58,6 +45,21 @@ from .declarations import (
PostGeneration,
PostGenerationMethodCall,
RelatedFactory,
+)
+
+from .helpers import (
+ build,
+ create,
+ stub,
+ generate,
+ simple_generate,
+ make_factory,
+
+ build_batch,
+ create_batch,
+ stub_batch,
+ generate_batch,
+ simple_generate_batch,
lazy_attribute,
iterator,
diff --git a/factory/base.py b/factory/base.py
index 71c2eb1..13a0623 100644
--- a/factory/base.py
+++ b/factory/base.py
@@ -20,10 +20,6 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
-import re
-import sys
-import warnings
-
from . import containers
# Strategies
@@ -68,7 +64,7 @@ class FactoryMetaClass(type):
"""Factory metaclass for handling ordered declarations."""
def __call__(cls, **kwargs):
- """Override the default Factory() syntax to call the default build strategy.
+ """Override the default Factory() syntax to call the default strategy.
Returns an instance of the associated class.
"""
@@ -80,10 +76,11 @@ class FactoryMetaClass(type):
elif cls.FACTORY_STRATEGY == STUB_STRATEGY:
return cls.stub(**kwargs)
else:
- raise UnknownStrategy('Unknown FACTORY_STRATEGY: {0}'.format(cls.FACTORY_STRATEGY))
+ raise UnknownStrategy('Unknown FACTORY_STRATEGY: {0}'.format(
+ cls.FACTORY_STRATEGY))
@classmethod
- def _discover_associated_class(cls, class_name, attrs, inherited=None):
+ def _discover_associated_class(mcs, class_name, attrs, inherited=None):
"""Try to find the class associated with this factory.
In order, the following tests will be performed:
@@ -104,8 +101,6 @@ class FactoryMetaClass(type):
AssociatedClassError: If we were unable to associate this factory
to a class.
"""
- own_associated_class = None
-
if FACTORY_CLASS_DECLARATION in attrs:
return attrs[FACTORY_CLASS_DECLARATION]
@@ -120,7 +115,7 @@ class FactoryMetaClass(type):
class_name)
@classmethod
- def _extract_declarations(cls, bases, attributes):
+ def _extract_declarations(mcs, bases, attributes):
"""Extract declarations from a class definition.
Args:
@@ -141,7 +136,8 @@ class FactoryMetaClass(type):
postgen_declarations.update_with_public(
getattr(base, CLASS_ATTRIBUTE_POSTGEN_DECLARATIONS, {}))
# Import all 'public' attributes (avoid those starting with _)
- declarations.update_with_public(getattr(base, CLASS_ATTRIBUTE_DECLARATIONS, {}))
+ declarations.update_with_public(
+ getattr(base, CLASS_ATTRIBUTE_DECLARATIONS, {}))
# Import attributes from the class definition
attributes = postgen_declarations.update_with_public(attributes)
@@ -154,7 +150,7 @@ class FactoryMetaClass(type):
return attributes
- def __new__(cls, class_name, bases, attrs, extra_attrs=None):
+ def __new__(mcs, class_name, bases, attrs, extra_attrs=None):
"""Record attributes as a pattern for later instance construction.
This is called when a new Factory subclass is defined; it will collect
@@ -174,7 +170,8 @@ class FactoryMetaClass(type):
"""
parent_factories = get_factory_bases(bases)
if not parent_factories:
- return super(FactoryMetaClass, cls).__new__(cls, class_name, bases, attrs)
+ return super(FactoryMetaClass, mcs).__new__(
+ mcs, class_name, bases, attrs)
is_abstract = attrs.pop('ABSTRACT_FACTORY', False)
extra_attrs = {}
@@ -185,7 +182,7 @@ class FactoryMetaClass(type):
inherited_associated_class = getattr(base,
CLASS_ATTRIBUTE_ASSOCIATED_CLASS, None)
- associated_class = cls._discover_associated_class(class_name, attrs,
+ associated_class = mcs._discover_associated_class(class_name, attrs,
inherited_associated_class)
# If inheriting the factory from a parent, keep a link to it.
@@ -193,22 +190,23 @@ class FactoryMetaClass(type):
if associated_class == inherited_associated_class:
attrs['_base_factory'] = base
- # The CLASS_ATTRIBUTE_ASSOCIATED_CLASS must *not* be taken into account
- # when parsing the declared attributes of the new class.
+ # The CLASS_ATTRIBUTE_ASSOCIATED_CLASS must *not* be taken into
+ # account when parsing the declared attributes of the new class.
extra_attrs = {CLASS_ATTRIBUTE_ASSOCIATED_CLASS: associated_class}
# Extract pre- and post-generation declarations
- attributes = cls._extract_declarations(parent_factories, attrs)
+ attributes = mcs._extract_declarations(parent_factories, attrs)
# Add extra args if provided.
if extra_attrs:
attributes.update(extra_attrs)
- return super(FactoryMetaClass, cls).__new__(cls, class_name, bases, attributes)
+ return super(FactoryMetaClass, mcs).__new__(
+ mcs, class_name, bases, attributes)
- def __str__(self):
- return '<%s for %s>' % (self.__name__,
- getattr(self, CLASS_ATTRIBUTE_ASSOCIATED_CLASS).__name__)
+ def __str__(cls):
+ return '<%s for %s>' % (cls.__name__,
+ getattr(cls, CLASS_ATTRIBUTE_ASSOCIATED_CLASS).__name__)
# Factory base classes
@@ -216,6 +214,7 @@ class FactoryMetaClass(type):
class BaseFactory(object):
"""Factory base support for sequences, attributes and stubs."""
+ # Backwards compatibility
UnknownStrategy = UnknownStrategy
UnsupportedStrategy = UnsupportedStrategy
@@ -231,6 +230,9 @@ class BaseFactory(object):
# class.
_base_factory = None
+ # Holds the target class, once resolved.
+ _associated_class = None
+
# List of arguments that should be passed as *args instead of **kwargs
FACTORY_ARG_PARAMETERS = ()
@@ -329,7 +331,8 @@ class BaseFactory(object):
attrs (dict): attributes to use for generating the object
"""
# Extract declarations used for post-generation
- postgen_declarations = getattr(cls, CLASS_ATTRIBUTE_POSTGEN_DECLARATIONS)
+ postgen_declarations = getattr(cls,
+ CLASS_ATTRIBUTE_POSTGEN_DECLARATIONS)
postgen_attributes = {}
for name, decl in sorted(postgen_declarations.items()):
postgen_attributes[name] = decl.extract(name, attrs)
@@ -341,7 +344,8 @@ class BaseFactory(object):
results = {}
for name, decl in sorted(postgen_declarations.items()):
extracted, extracted_kwargs = postgen_attributes[name]
- results[name] = decl.call(obj, create, extracted, **extracted_kwargs)
+ results[name] = decl.call(obj, create, extracted,
+ **extracted_kwargs)
cls._after_postgeneration(obj, create, results)
@@ -527,7 +531,7 @@ Factory = FactoryMetaClass('Factory', (BaseFactory,), {
# Backwards compatibility
-Factory.AssociatedClassError = AssociatedClassError
+Factory.AssociatedClassError = AssociatedClassError # pylint: disable=W0201
class StubFactory(Factory):
@@ -547,7 +551,7 @@ class StubFactory(Factory):
class DjangoModelFactory(Factory):
"""Factory for Django models.
- This makes sure that the 'sequence' field of created objects is an unused id.
+ This makes sure that the 'sequence' field of created objects is a new id.
Possible improvement: define a new 'attribute' type, AutoField, which would
handle those for non-numerical primary keys.
@@ -559,7 +563,7 @@ class DjangoModelFactory(Factory):
@classmethod
def _get_manager(cls, target_class):
try:
- return target_class._default_manager
+ return target_class._default_manager # pylint: disable=W0212
except AttributeError:
return target_class.objects
@@ -567,7 +571,8 @@ class DjangoModelFactory(Factory):
def _setup_next_sequence(cls):
"""Compute the next available PK, based on the 'pk' database field."""
- manager = cls._get_manager(cls._associated_class)
+ model = cls._associated_class # pylint: disable=E1101
+ manager = cls._get_manager(model)
try:
return 1 + manager.values_list('pk', flat=True
@@ -590,7 +595,7 @@ class DjangoModelFactory(Factory):
key_fields[field] = kwargs.pop(field)
key_fields['defaults'] = kwargs
- obj, created = manager.get_or_create(*args, **key_fields)
+ obj, _created = manager.get_or_create(*args, **key_fields)
return obj
@classmethod
@@ -610,68 +615,6 @@ class MogoFactory(Factory):
return target_class.new(*args, **kwargs)
-def make_factory(klass, **kwargs):
- """Create a new, simple factory for the given class."""
- factory_name = '%sFactory' % klass.__name__
- kwargs[FACTORY_CLASS_DECLARATION] = klass
- base_class = kwargs.pop('FACTORY_CLASS', Factory)
-
- factory_class = type(Factory).__new__(type(Factory), factory_name, (base_class,), 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)
-
-
def use_strategy(new_strategy):
"""Force the use of a different strategy.
diff --git a/factory/compat.py b/factory/compat.py
index a924de0..84f31b7 100644
--- a/factory/compat.py
+++ b/factory/compat.py
@@ -25,9 +25,11 @@
import sys
-is_python2 = (sys.version_info[0] == 2)
+PY2 = (sys.version_info[0] == 2)
-if is_python2:
- string_types = (str, unicode)
+if PY2:
+ def is_string(obj):
+ return isinstance(obj, (str, unicode))
else:
- string_types = (str,)
+ def is_string(obj):
+ return isinstance(obj, str)
diff --git a/factory/containers.py b/factory/containers.py
index dc3a457..e02f9f9 100644
--- a/factory/containers.py
+++ b/factory/containers.py
@@ -228,9 +228,12 @@ class AttributeBuilder(object):
self._containers = extra.pop('__containers', ())
self._attrs = factory.declarations(extra)
- attrs_with_subfields = [k for k, v in self._attrs.items() if self.has_subfields(v)]
+ attrs_with_subfields = [
+ k for k, v in self._attrs.items()
+ if self.has_subfields(v)]
- self._subfields = utils.multi_extract_dict(attrs_with_subfields, self._attrs)
+ self._subfields = utils.multi_extract_dict(
+ attrs_with_subfields, self._attrs)
def has_subfields(self, value):
return isinstance(value, declarations.SubFactory)
diff --git a/factory/declarations.py b/factory/declarations.py
index 15d8d5b..3d76960 100644
--- a/factory/declarations.py
+++ b/factory/declarations.py
@@ -21,9 +21,7 @@
# THE SOFTWARE.
-import collections
import itertools
-import warnings
from . import compat
from . import utils
@@ -179,7 +177,7 @@ class Sequence(OrderedDeclaration):
type (function): A function converting an integer into the expected kind
of counter for the 'function' attribute.
"""
- def __init__(self, function, type=int):
+ def __init__(self, function, type=int): # pylint: disable=W0622
super(Sequence, self).__init__()
self.function = function
self.type = type
@@ -318,7 +316,7 @@ class SubFactory(ParameteredAttribute):
self.factory_module = self.factory_name = ''
else:
# Must be a string
- if not isinstance(factory, compat.string_types) or '.' not in factory:
+ if not (compat.is_string(factory) and '.' in factory):
raise ValueError(
"The argument of a SubFactory must be either a class "
"or the fully qualified path to a Factory class; got "
@@ -330,7 +328,8 @@ class SubFactory(ParameteredAttribute):
"""Retrieve the wrapped factory.Factory subclass."""
if self.factory is None:
# Must be a module path
- self.factory = utils.import_object(self.factory_module, self.factory_name)
+ self.factory = utils.import_object(
+ self.factory_module, self.factory_name)
return self.factory
def generate(self, create, params):
@@ -390,10 +389,6 @@ class PostGeneration(PostGenerationDeclaration):
return self.function(obj, create, extracted, **kwargs)
-def post_generation(fun):
- return PostGeneration(fun)
-
-
class RelatedFactory(PostGenerationDeclaration):
"""Calls a factory once the object has been generated.
@@ -414,7 +409,7 @@ class RelatedFactory(PostGenerationDeclaration):
self.factory_module = self.factory_name = ''
else:
# Must be a string
- if not isinstance(factory, compat.string_types) or '.' not in factory:
+ if not (compat.is_string(factory) and '.' in factory):
raise ValueError(
"The argument of a SubFactory must be either a class "
"or the fully qualified path to a Factory class; got "
@@ -426,7 +421,8 @@ class RelatedFactory(PostGenerationDeclaration):
"""Retrieve the wrapped factory.Factory subclass."""
if self.factory is None:
# Must be a module path
- self.factory = utils.import_object(self.factory_module, self.factory_name)
+ self.factory = utils.import_object(
+ self.factory_module, self.factory_name)
return self.factory
def call(self, obj, create, extracted=None, **kwargs):
@@ -450,7 +446,7 @@ class PostGenerationMethodCall(PostGenerationDeclaration):
Example:
class UserFactory(factory.Factory):
...
- password = factory.PostGenerationMethodCall('set_password', password='')
+ password = factory.PostGenerationMethodCall('set_pass', password='')
"""
def __init__(self, method_name, *args, **kwargs):
super(PostGenerationMethodCall, self).__init__()
@@ -472,22 +468,3 @@ class PostGenerationMethodCall(PostGenerationDeclaration):
passed_kwargs.update(kwargs)
method = getattr(obj, self.method_name)
method(*passed_args, **passed_kwargs)
-
-
-# Decorators... in case lambdas don't cut it
-
-def lazy_attribute(func):
- return LazyAttribute(func)
-
-def iterator(func):
- """Turn a generator function into an iterator attribute."""
- return Iterator(func())
-
-def sequence(func):
- return Sequence(func)
-
-def lazy_attribute_sequence(func):
- return LazyAttributeSequence(func)
-
-def container_attribute(func):
- return ContainerAttribute(func, strict=False)
diff --git a/factory/helpers.py b/factory/helpers.py
new file mode 100644
index 0000000..8f0d161
--- /dev/null
+++ b/factory/helpers.py
@@ -0,0 +1,123 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2010 Mark Sandstrom
+# Copyright (c) 2011-2013 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.
+
+
+"""Simple wrappers around Factory class definition."""
+
+
+from . import base
+from . import declarations
+
+
+def make_factory(klass, **kwargs):
+ """Create a new, simple factory for the given class."""
+ factory_name = '%sFactory' % klass.__name__
+ kwargs[base.FACTORY_CLASS_DECLARATION] = klass
+ base_class = kwargs.pop('FACTORY_CLASS', base.Factory)
+
+ factory_class = type(base.Factory).__new__(
+ type(base.Factory), factory_name, (base_class,), 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)
+
+
+# We're reusing 'create' as a keyword.
+# pylint: disable=W0621
+
+
+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)
+
+
+# pylint: enable=W0621
+
+
+def lazy_attribute(func):
+ return declarations.LazyAttribute(func)
+
+
+def iterator(func):
+ """Turn a generator function into an iterator attribute."""
+ return declarations.Iterator(func())
+
+
+def sequence(func):
+ return declarations.Sequence(func)
+
+
+def lazy_attribute_sequence(func):
+ return declarations.LazyAttributeSequence(func)
+
+
+def container_attribute(func):
+ return declarations.ContainerAttribute(func, strict=False)
+
+
+def post_generation(fun):
+ return declarations.PostGeneration(fun)
diff --git a/tests/test_declarations.py b/tests/test_declarations.py
index 7b9b0af..4c08dfa 100644
--- a/tests/test_declarations.py
+++ b/tests/test_declarations.py
@@ -25,6 +25,7 @@ import itertools
import warnings
from factory import declarations
+from factory import helpers
from .compat import mock, unittest
from . import tools
@@ -124,7 +125,7 @@ class PostGenerationDeclarationTestCase(unittest.TestCase):
def test_decorator_simple(self):
call_params = []
- @declarations.post_generation
+ @helpers.post_generation
def foo(*args, **kwargs):
call_params.append(args)
call_params.append(kwargs)