From 02e4cfd9bb0e0d1124385f52108bb709fc5d72bf Mon Sep 17 00:00:00 2001 From: Ilya Pirogov Date: Fri, 27 Dec 2013 13:07:34 +0400 Subject: Added FuzzyInteger support for step --- factory/fuzzy.py | 5 +++-- tests/test_fuzzy.py | 22 ++++++++++++++++------ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/factory/fuzzy.py b/factory/fuzzy.py index 34949c5..2ea544a 100644 --- a/factory/fuzzy.py +++ b/factory/fuzzy.py @@ -107,18 +107,19 @@ class FuzzyChoice(BaseFuzzyAttribute): class FuzzyInteger(BaseFuzzyAttribute): """Random integer within a given range.""" - def __init__(self, low, high=None, **kwargs): + def __init__(self, low, high=None, step=1, **kwargs): if high is None: high = low low = 0 self.low = low self.high = high + self.step = step super(FuzzyInteger, self).__init__(**kwargs) def fuzz(self): - return random.randint(self.low, self.high) + return random.randrange(self.low, self.high + 1, self.step) class FuzzyDecimal(BaseFuzzyAttribute): diff --git a/tests/test_fuzzy.py b/tests/test_fuzzy.py index d6f33bb..1caeb0a 100644 --- a/tests/test_fuzzy.py +++ b/tests/test_fuzzy.py @@ -89,24 +89,34 @@ class FuzzyIntegerTestCase(unittest.TestCase): self.assertIn(res, [0, 1, 2, 3, 4]) def test_biased(self): - fake_randint = lambda low, high: low + high + fake_randrange = lambda low, high, step: (low + high) * step fuzz = fuzzy.FuzzyInteger(2, 8) - with mock.patch('random.randint', fake_randint): + with mock.patch('random.randrange', fake_randrange): res = fuzz.evaluate(2, None, False) - self.assertEqual(10, res) + self.assertEqual((2 + 8 + 1) * 1, res) def test_biased_high_only(self): - fake_randint = lambda low, high: low + high + fake_randrange = lambda low, high, step: (low + high) * step fuzz = fuzzy.FuzzyInteger(8) - with mock.patch('random.randint', fake_randint): + with mock.patch('random.randrange', fake_randrange): + res = fuzz.evaluate(2, None, False) + + self.assertEqual((0 + 8 + 1) * 1, res) + + def test_biased_with_step(self): + fake_randrange = lambda low, high, step: (low + high) * step + + fuzz = fuzzy.FuzzyInteger(5, 8, 3) + + with mock.patch('random.randrange', fake_randrange): res = fuzz.evaluate(2, None, False) - self.assertEqual(8, res) + self.assertEqual((5 + 8 + 1) * 3, res) class FuzzyDecimalTestCase(unittest.TestCase): -- cgit v1.2.3 From 874b5361d2972dd6feb2d26b74e37eba2434ba04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Mon, 30 Dec 2013 14:08:03 +0100 Subject: Document FuzzyInteger.step --- docs/changelog.rst | 9 +++++++++ docs/fuzzy.rst | 10 ++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index adb42a8..6658a96 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -2,6 +2,15 @@ ChangeLog ========= +.. _v2.4.0: + +2.4.0 (master) +-------------- + +*New:* + + - Add support for :attr:`factory.fuzzy.FuzzyInteger.step`, thanks to `ilya-pirogov `_ (:issue:`120`) + .. _v2.3.0: 2.3.0 (2013-12-25) diff --git a/docs/fuzzy.rst b/docs/fuzzy.rst index b94dfa5..2fe60b8 100644 --- a/docs/fuzzy.rst +++ b/docs/fuzzy.rst @@ -73,7 +73,7 @@ FuzzyChoice FuzzyInteger ------------ -.. class:: FuzzyInteger(low[, high]) +.. class:: FuzzyInteger(low[, high[, step]]) The :class:`FuzzyInteger` fuzzer generates random integers within a given inclusive range. @@ -82,7 +82,7 @@ FuzzyInteger .. code-block:: pycon - >>> FuzzyInteger(0, 42) + >>> fi = FuzzyInteger(0, 42) >>> fi.low, fi.high 0, 42 @@ -98,6 +98,12 @@ FuzzyInteger int, the inclusive higher bound of generated integers + .. attribute:: step + + int, the step between values in the range; for instance, a ``FuzzyInteger(0, 42, step=3)`` + might only yield values from ``[0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42]``. + + FuzzyDecimal ------------ -- cgit v1.2.3 From c404da5080c92527e26c6b82d5cc5d7d88ba3d9a Mon Sep 17 00:00:00 2001 From: Robrecht De Rouck Date: Wed, 25 Dec 2013 01:46:22 +0100 Subject: Document custom manager method recipe (Closes #119). --- docs/recipes.rst | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/docs/recipes.rst b/docs/recipes.rst index c1f3700..9e07413 100644 --- a/docs/recipes.rst +++ b/docs/recipes.rst @@ -291,3 +291,25 @@ Here, we want: name = "ACME, Inc." country = factory.SubFactory(CountryFactory) owner = factory.SubFactory(UserFactory, country=factory.SelfAttribute('..country')) + + +Custom manager methods +---------------------- + +Sometimes you need a factory to call a specific manager method other then the +default :meth:`Model.objects.create() ` method: + +.. code-block:: python + + class UserFactory(factory.DjangoModelFactory): + FACTORY_FOR = UserenaSignup + username = "l7d8s" + email = "my_name@example.com" + password = "my_password" + + @classmethod + def _create(cls, target_class, *args, **kwargs): + """Override the default ``_create`` with our custom call.""" + manager = cls._get_manager(target_class) + # The default would use ``manager.create(*args, **kwargs)`` + return manager.create_user(*args, **kwargs) -- cgit v1.2.3 From 9323fbeea374394833987cb710ac9becb7726a44 Mon Sep 17 00:00:00 2001 From: Ilya Pirogov Date: Mon, 13 Jan 2014 17:53:03 +0400 Subject: Added "prevent_signals" decorator/context manager --- factory/__init__.py | 2 ++ factory/django.py | 60 ++++++++++++++++++++++++++++++++++++++ factory/helpers.py | 5 ++++ tests/djapp/models.py | 4 +++ tests/test_django.py | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 150 insertions(+), 1 deletion(-) diff --git a/factory/__init__.py b/factory/__init__.py index b4e63be..251306a 100644 --- a/factory/__init__.py +++ b/factory/__init__.py @@ -79,5 +79,7 @@ from .helpers import ( lazy_attribute_sequence, container_attribute, post_generation, + + prevent_signals, ) diff --git a/factory/django.py b/factory/django.py index fee8e52..b502923 100644 --- a/factory/django.py +++ b/factory/django.py @@ -25,6 +25,9 @@ from __future__ import absolute_import from __future__ import unicode_literals import os +import types +import logging +import functools """factory_boy extensions for use with the Django framework.""" @@ -39,6 +42,9 @@ from . import base from . import declarations from .compat import BytesIO, is_string +logger = logging.getLogger('factory.generate') + + def require_django(): """Simple helper to ensure Django is available.""" @@ -214,3 +220,57 @@ class ImageField(FileField): thumb.save(thumb_io, format=image_format) return thumb_io.getvalue() + +class PreventSignals(object): + """Temporarily disables and then restores any django signals. + + Args: + *signals (django.dispatch.dispatcher.Signal): any django signals + + Examples: + with prevent_signals(pre_init): + user = UserFactory.build() + ... + + @prevent_signals(pre_save, post_save) + class UserFactory(factory.Factory): + ... + + @prevent_signals(post_save) + def generate_users(): + UserFactory.create_batch(10) + """ + + def __init__(self, *signals): + self.signals = signals + self.paused = {} + + def __enter__(self): + for signal in self.signals: + logger.debug('PreventSignals: Disabling signal handlers %r', + signal.receivers) + + self.paused[signal] = signal.receivers + signal.receivers = [] + + def __exit__(self, exc_type, exc_value, traceback): + for signal, receivers in self.paused.items(): + logger.debug('PreventSignals: Restoring signal handlers %r', + receivers) + + signal.receivers = receivers + self.paused = {} + + def __call__(self, func): + if isinstance(func, types.FunctionType): + @functools.wraps(func) + def wrapper(*args, **kwargs): + with self: + return func(*args, **kwargs) + return wrapper + + generate_method = getattr(func, '_generate', None) + if generate_method: + func._generate = classmethod(self(generate_method.__func__)) + + return func \ No newline at end of file diff --git a/factory/helpers.py b/factory/helpers.py index 37b41bf..719d76d 100644 --- a/factory/helpers.py +++ b/factory/helpers.py @@ -28,6 +28,7 @@ import logging from . import base from . import declarations +from . import django @contextlib.contextmanager @@ -139,3 +140,7 @@ def container_attribute(func): def post_generation(fun): return declarations.PostGeneration(fun) + + +def prevent_signals(*signals): + return django.PreventSignals(*signals) \ No newline at end of file diff --git a/tests/djapp/models.py b/tests/djapp/models.py index e98279d..a65b50a 100644 --- a/tests/djapp/models.py +++ b/tests/djapp/models.py @@ -74,3 +74,7 @@ if Image is not None: # PIL is available else: class WithImage(models.Model): pass + + +class WithSignals(models.Model): + foo = models.CharField(max_length=20) \ No newline at end of file diff --git a/tests/test_django.py b/tests/test_django.py index e4bbc2b..18ffa6b 100644 --- a/tests/test_django.py +++ b/tests/test_django.py @@ -24,6 +24,7 @@ import os import factory import factory.django +from factory.helpers import prevent_signals try: @@ -42,7 +43,7 @@ except ImportError: # pragma: no cover Image = None -from .compat import is_python2, unittest +from .compat import is_python2, unittest, mock from . import testdata from . import tools @@ -55,6 +56,7 @@ if django is not None: from django.db import models as django_models from django.test import simple as django_test_simple from django.test import utils as django_test_utils + from django.db.models import signals from .djapp import models else: # pragma: no cover django_test = unittest @@ -70,6 +72,7 @@ else: # pragma: no cover models.NonIntegerPk = Fake models.WithFile = Fake models.WithImage = Fake + models.WithSignals = Fake test_state = {} @@ -142,6 +145,10 @@ class WithImageFactory(factory.django.DjangoModelFactory): animage = factory.django.ImageField() +class WithSignalsFactory(factory.django.DjangoModelFactory): + FACTORY_FOR = models.WithSignals + + @unittest.skipIf(django is None, "Django not installed.") class DjangoPkSequenceTestCase(django_test.TestCase): def setUp(self): @@ -511,5 +518,76 @@ class DjangoImageFieldTestCase(unittest.TestCase): self.assertFalse(o.animage) +@unittest.skipIf(django is None, "Django not installed.") +class PreventSignalsTestCase(unittest.TestCase): + def setUp(self): + self.handlers = mock.MagicMock() + + signals.pre_init.connect(self.handlers.pre_init) + signals.pre_save.connect(self.handlers.pre_save) + signals.post_save.connect(self.handlers.post_save) + + def tearDown(self): + signals.pre_init.disconnect(self.handlers.pre_init) + signals.pre_save.disconnect(self.handlers.pre_save) + signals.post_save.disconnect(self.handlers.post_save) + + def test_signals(self): + WithSignalsFactory() + + self.assertEqual(self.handlers.pre_save.call_count, 1) + self.assertEqual(self.handlers.post_save.call_count, 1) + + def test_context_manager(self): + with prevent_signals(signals.pre_save, signals.post_save): + WithSignalsFactory() + + self.assertEqual(self.handlers.pre_init.call_count, 1) + self.assertFalse(self.handlers.pre_save.called) + self.assertFalse(self.handlers.post_save.called) + + self.test_signals() + + def test_class_decorator(self): + @prevent_signals(signals.pre_save, signals.post_save) + class WithSignalsDecoratedFactory(factory.django.DjangoModelFactory): + FACTORY_FOR = models.WithSignals + + WithSignalsDecoratedFactory() + + self.assertEqual(self.handlers.pre_init.call_count, 1) + self.assertFalse(self.handlers.pre_save.called) + self.assertFalse(self.handlers.post_save.called) + + self.test_signals() + + def test_function_decorator(self): + @prevent_signals(signals.pre_save, signals.post_save) + def foo(): + WithSignalsFactory() + + foo() + + self.assertEqual(self.handlers.pre_init.call_count, 1) + self.assertFalse(self.handlers.pre_save.called) + self.assertFalse(self.handlers.post_save.called) + + self.test_signals() + + def test_classmethod_decorator(self): + class Foo(object): + @classmethod + @prevent_signals(signals.pre_save, signals.post_save) + def generate(cls): + WithSignalsFactory() + + Foo.generate() + + self.assertEqual(self.handlers.pre_init.call_count, 1) + self.assertFalse(self.handlers.pre_save.called) + self.assertFalse(self.handlers.post_save.called) + + self.test_signals() + if __name__ == '__main__': # pragma: no cover unittest.main() -- cgit v1.2.3 From dccb37f551d19d9dba68d35a888941cde64f861e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Tue, 21 Jan 2014 23:21:03 +0100 Subject: Improve mute_signals (Closes #122). --- factory/__init__.py | 2 -- factory/django.py | 36 +++++++++++++++++++++--------------- factory/helpers.py | 4 ---- tests/test_django.py | 32 ++++++++++++++++++++++---------- 4 files changed, 43 insertions(+), 31 deletions(-) diff --git a/factory/__init__.py b/factory/__init__.py index 251306a..b4e63be 100644 --- a/factory/__init__.py +++ b/factory/__init__.py @@ -79,7 +79,5 @@ from .helpers import ( lazy_attribute_sequence, container_attribute, post_generation, - - prevent_signals, ) diff --git a/factory/django.py b/factory/django.py index b502923..6f39c34 100644 --- a/factory/django.py +++ b/factory/django.py @@ -221,22 +221,22 @@ class ImageField(FileField): return thumb_io.getvalue() -class PreventSignals(object): +class mute_signals(object): """Temporarily disables and then restores any django signals. Args: *signals (django.dispatch.dispatcher.Signal): any django signals Examples: - with prevent_signals(pre_init): + with mute_signals(pre_init): user = UserFactory.build() ... - @prevent_signals(pre_save, post_save) + @mute_signals(pre_save, post_save) class UserFactory(factory.Factory): ... - @prevent_signals(post_save) + @mute_signals(post_save) def generate_users(): UserFactory.create_batch(10) """ @@ -247,7 +247,7 @@ class PreventSignals(object): def __enter__(self): for signal in self.signals: - logger.debug('PreventSignals: Disabling signal handlers %r', + logger.debug('mute_signals: Disabling signal handlers %r', signal.receivers) self.paused[signal] = signal.receivers @@ -255,22 +255,28 @@ class PreventSignals(object): def __exit__(self, exc_type, exc_value, traceback): for signal, receivers in self.paused.items(): - logger.debug('PreventSignals: Restoring signal handlers %r', + logger.debug('mute_signals: Restoring signal handlers %r', receivers) signal.receivers = receivers self.paused = {} - def __call__(self, func): - if isinstance(func, types.FunctionType): - @functools.wraps(func) + def __call__(self, callable_obj): + if isinstance(callable_obj, base.FactoryMetaClass): + generate_method = getattr(callable_obj, '_generate') + + @functools.wraps(generate_method) + def wrapped_generate(*args, **kwargs): + with self: + return generate_method(*args, **kwargs) + + callable_obj._generate = wrapped_generate + return callable_obj + + else: + @functools.wraps(callable_obj) def wrapper(*args, **kwargs): with self: - return func(*args, **kwargs) + return callable_obj(*args, **kwargs) return wrapper - generate_method = getattr(func, '_generate', None) - if generate_method: - func._generate = classmethod(self(generate_method.__func__)) - - return func \ No newline at end of file diff --git a/factory/helpers.py b/factory/helpers.py index 719d76d..4a2a254 100644 --- a/factory/helpers.py +++ b/factory/helpers.py @@ -140,7 +140,3 @@ def container_attribute(func): def post_generation(fun): return declarations.PostGeneration(fun) - - -def prevent_signals(*signals): - return django.PreventSignals(*signals) \ No newline at end of file diff --git a/tests/test_django.py b/tests/test_django.py index 18ffa6b..50a67a3 100644 --- a/tests/test_django.py +++ b/tests/test_django.py @@ -24,7 +24,6 @@ import os import factory import factory.django -from factory.helpers import prevent_signals try: @@ -532,24 +531,24 @@ class PreventSignalsTestCase(unittest.TestCase): signals.pre_save.disconnect(self.handlers.pre_save) signals.post_save.disconnect(self.handlers.post_save) - def test_signals(self): + def assertSignalsReactivated(self): WithSignalsFactory() self.assertEqual(self.handlers.pre_save.call_count, 1) self.assertEqual(self.handlers.post_save.call_count, 1) def test_context_manager(self): - with prevent_signals(signals.pre_save, signals.post_save): + with factory.django.mute_signals(signals.pre_save, signals.post_save): WithSignalsFactory() self.assertEqual(self.handlers.pre_init.call_count, 1) self.assertFalse(self.handlers.pre_save.called) self.assertFalse(self.handlers.post_save.called) - self.test_signals() + self.assertSignalsReactivated() def test_class_decorator(self): - @prevent_signals(signals.pre_save, signals.post_save) + @factory.django.mute_signals(signals.pre_save, signals.post_save) class WithSignalsDecoratedFactory(factory.django.DjangoModelFactory): FACTORY_FOR = models.WithSignals @@ -559,10 +558,23 @@ class PreventSignalsTestCase(unittest.TestCase): self.assertFalse(self.handlers.pre_save.called) self.assertFalse(self.handlers.post_save.called) - self.test_signals() + self.assertSignalsReactivated() + + def test_class_decorator_build(self): + @factory.django.mute_signals(signals.pre_save, signals.post_save) + class WithSignalsDecoratedFactory(factory.django.DjangoModelFactory): + FACTORY_FOR = models.WithSignals + + WithSignalsDecoratedFactory.build() + + self.assertEqual(self.handlers.pre_init.call_count, 1) + self.assertFalse(self.handlers.pre_save.called) + self.assertFalse(self.handlers.post_save.called) + + self.assertSignalsReactivated() def test_function_decorator(self): - @prevent_signals(signals.pre_save, signals.post_save) + @factory.django.mute_signals(signals.pre_save, signals.post_save) def foo(): WithSignalsFactory() @@ -572,12 +584,12 @@ class PreventSignalsTestCase(unittest.TestCase): self.assertFalse(self.handlers.pre_save.called) self.assertFalse(self.handlers.post_save.called) - self.test_signals() + self.assertSignalsReactivated() def test_classmethod_decorator(self): class Foo(object): @classmethod - @prevent_signals(signals.pre_save, signals.post_save) + @factory.django.mute_signals(signals.pre_save, signals.post_save) def generate(cls): WithSignalsFactory() @@ -587,7 +599,7 @@ class PreventSignalsTestCase(unittest.TestCase): self.assertFalse(self.handlers.pre_save.called) self.assertFalse(self.handlers.post_save.called) - self.test_signals() + self.assertSignalsReactivated() if __name__ == '__main__': # pragma: no cover unittest.main() -- cgit v1.2.3 From 86718596359110b7fce5efbb7c28cba10f11b77d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Tue, 21 Jan 2014 23:33:02 +0100 Subject: Add doc for factory.django.mute_signals. --- docs/changelog.rst | 1 + docs/orms.rst | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index 0bf0eb3..c051916 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -10,6 +10,7 @@ ChangeLog *New:* - Add support for :attr:`factory.fuzzy.FuzzyInteger.step`, thanks to `ilya-pirogov `_ (:issue:`120`) + - Add :meth:`~factory.django.mute_signals` decorator to temporarily disable some signals, thanks to `ilya-pirogov `_ (:issue:`122`) .. _v2.3.1: diff --git a/docs/orms.rst b/docs/orms.rst index e50e706..c893cac 100644 --- a/docs/orms.rst +++ b/docs/orms.rst @@ -89,6 +89,10 @@ All factories for a Django :class:`~django.db.models.Model` should use the Otherwise, factory_boy will try to get the 'next PK' counter from the abstract model. +Extra fields +"""""""""""" + + .. class:: FileField Custom declarations for :class:`django.db.models.FileField` @@ -157,6 +161,43 @@ All factories for a Django :class:`~django.db.models.Model` should use the None +Disabling signals +""""""""""""""""" + +Signals are often used to plug some custom code into external components code; +for instance to create ``Profile`` objects on-the-fly when a new ``User`` object is saved. + +This may interfere with finely tuned :class:`factories `, which would +create both using :class:`~factory.RelatedFactory`. + +To work around this problem, use the :meth:`mute_signals()` decorator/context manager: + +.. method:: mute_signals(signal1, ...) + + Disable the list of selected signals when calling the factory, and reactivate them upon leaving. + +.. code-block:: python + + # foo/factories.py + + import factory + import factory.django + + from . import models + from . import signals + + @factory.django.mute_signals(signals.pre_save, signals.post_save) + class FooFactory(factory.django.DjangoModelFactory): + FACTORY_FOR = models.Foo + + # ... + + def make_chain(): + with factory.django.mute_signals(signals.pre_save, signals.post_save): + # pre_save/post_save won't be called here. + return SomeFactory(), SomeOtherFactory() + + Mogo ---- -- cgit v1.2.3 From 5cd2ba8b89a1dc575b818f8c7be20dd3f0f6c05a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Tue, 21 Jan 2014 23:20:26 +0100 Subject: Update requirements --- dev_requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dev_requirements.txt b/dev_requirements.txt index e828644..bdc23d0 100644 --- a/dev_requirements.txt +++ b/dev_requirements.txt @@ -2,4 +2,5 @@ coverage Django Pillow sqlalchemy -mongoengine \ No newline at end of file +mongoengine +mock -- cgit v1.2.3 From f907c405cf233b4ef14817952c11979125b4732c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Wed, 22 Jan 2014 00:03:10 +0100 Subject: Fix log_pprint (Closes #123). --- factory/utils.py | 21 +++++++++++++++++++-- tests/test_utils.py | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 69 insertions(+), 3 deletions(-) diff --git a/factory/utils.py b/factory/utils.py index 48c6eed..b27fd77 100644 --- a/factory/utils.py +++ b/factory/utils.py @@ -20,6 +20,8 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. +from __future__ import unicode_literals + import collections #: String for splitting an attribute name into a @@ -96,11 +98,26 @@ def import_object(module_name, attribute_name): return getattr(module, attribute_name) +def _safe_repr(obj): + try: + obj_repr = repr(obj) + except UnicodeError: + return '' % id(obj) + + try: # Convert to "text type" (= unicode) + return '%s' % obj_repr + except UnicodeError: # non-ascii bytes repr on Py2 + return obj_repr.decode('utf-8') + + def log_pprint(args=(), kwargs=None): kwargs = kwargs or {} return ', '.join( - [str(arg) for arg in args] + - ['%s=%r' % item for item in kwargs.items()] + [repr(arg) for arg in args] + + [ + '%s=%s' % (key, _safe_repr(value)) + for key, value in kwargs.items() + ] ) diff --git a/tests/test_utils.py b/tests/test_utils.py index 8c73935..d321c2a 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -20,11 +20,14 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. +from __future__ import unicode_literals + + import itertools from factory import utils -from .compat import unittest +from .compat import is_python2, unittest class ExtractDictTestCase(unittest.TestCase): @@ -233,6 +236,52 @@ class ImportObjectTestCase(unittest.TestCase): 'this-is-an-invalid-module', '__name__') +class LogPPrintTestCase(unittest.TestCase): + def test_nothing(self): + txt = utils.log_pprint() + self.assertEqual('', txt) + + def test_only_args(self): + txt = utils.log_pprint((1, 2, 3)) + self.assertEqual('1, 2, 3', txt) + + def test_only_kwargs(self): + txt = utils.log_pprint(kwargs={'a': 1, 'b': 2}) + self.assertIn(txt, ['a=1, b=2', 'b=2, a=1']) + + def test_bytes_args(self): + txt = utils.log_pprint((b'\xe1\xe2',)) + expected = "b'\\xe1\\xe2'" + if is_python2: + expected = expected.lstrip('b') + self.assertEqual(expected, txt) + + def test_text_args(self): + txt = utils.log_pprint(('ŧêßŧ',)) + expected = "'ŧêßŧ'" + if is_python2: + expected = "u'\\u0167\\xea\\xdf\\u0167'" + self.assertEqual(expected, txt) + + def test_bytes_kwargs(self): + txt = utils.log_pprint(kwargs={'x': b'\xe1\xe2', 'y': b'\xe2\xe1'}) + expected1 = "x=b'\\xe1\\xe2', y=b'\\xe2\\xe1'" + expected2 = "y=b'\\xe2\\xe1', x=b'\\xe1\\xe2'" + if is_python2: + expected1 = expected1.replace('b', '') + expected2 = expected2.replace('b', '') + self.assertIn(txt, (expected1, expected2)) + + def test_text_kwargs(self): + txt = utils.log_pprint(kwargs={'x': 'ŧêßŧ', 'y': 'ŧßêŧ'}) + expected1 = "x='ŧêßŧ', y='ŧßêŧ'" + expected2 = "y='ŧßêŧ', x='ŧêßŧ'" + if is_python2: + expected1 = "x=u'\\u0167\\xea\\xdf\\u0167', y=u'\\u0167\\xdf\\xea\\u0167'" + expected2 = "y=u'\\u0167\\xdf\\xea\\u0167', x=u'\\u0167\\xea\\xdf\\u0167'" + self.assertIn(txt, (expected1, expected2)) + + class ResetableIteratorTestCase(unittest.TestCase): def test_no_reset(self): i = utils.ResetableIterator([1, 2, 3]) -- cgit v1.2.3 From e72d94b45312443d076d01ca833f19e8a5295847 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Wed, 22 Jan 2014 00:23:57 +0100 Subject: Fix mute_signals' decorator. --- factory/django.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/factory/django.py b/factory/django.py index 6f39c34..a3dfdfc 100644 --- a/factory/django.py +++ b/factory/django.py @@ -263,8 +263,10 @@ class mute_signals(object): def __call__(self, callable_obj): if isinstance(callable_obj, base.FactoryMetaClass): - generate_method = getattr(callable_obj, '_generate') + # Retrieve __func__, the *actual* callable object. + generate_method = callable_obj._generate.__func__ + @classmethod @functools.wraps(generate_method) def wrapped_generate(*args, **kwargs): with self: -- cgit v1.2.3 From ecbe5557f99f2f4b14b6c9b4bb79993269906fa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Wed, 22 Jan 2014 22:41:28 +0100 Subject: Fix log_pprint for *args (Closes #127). --- docs/changelog.rst | 2 +- factory/utils.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index b86d865..57b29c4 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -21,7 +21,7 @@ ChangeLog - Fix badly written assert containing state-changing code, spotted by `chsigi `_ (:issue:`126`) - Don't crash when handling objects whose __repr__ is non-pure-ascii bytes on Py2, - discovered by `mbertheau `_ (:issue:`123`) + discovered by `mbertheau `_ (:issue:`123`) and `strycore `_ (:issue:`127`) .. _v2.3.0: diff --git a/factory/utils.py b/factory/utils.py index b27fd77..276977a 100644 --- a/factory/utils.py +++ b/factory/utils.py @@ -113,7 +113,7 @@ def _safe_repr(obj): def log_pprint(args=(), kwargs=None): kwargs = kwargs or {} return ', '.join( - [repr(arg) for arg in args] + + [_safe_repr(arg) for arg in args] + [ '%s=%s' % (key, _safe_repr(value)) for key, value in kwargs.items() -- cgit v1.2.3 From 39383fea8bd5bd58b063d9c9fbb44301e781fd80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Wed, 22 Jan 2014 22:47:11 +0100 Subject: fuzzy: Add FuzzyFloat (Closes #124). As suggested by @savingschampion --- docs/changelog.rst | 1 + docs/fuzzy.rst | 30 ++++++++++++++++++++++++++++-- factory/fuzzy.py | 17 +++++++++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 57b29c4..aba1d76 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -11,6 +11,7 @@ ChangeLog - Add support for :attr:`factory.fuzzy.FuzzyInteger.step`, thanks to `ilya-pirogov `_ (:issue:`120`) - Add :meth:`~factory.django.mute_signals` decorator to temporarily disable some signals, thanks to `ilya-pirogov `_ (:issue:`122`) + - Add :class:`~factory.fuzzy.FuzzyFloat` (:issue:`124`) .. _v2.3.1: diff --git a/docs/fuzzy.rst b/docs/fuzzy.rst index 2fe60b8..1480419 100644 --- a/docs/fuzzy.rst +++ b/docs/fuzzy.rst @@ -107,9 +107,9 @@ FuzzyInteger FuzzyDecimal ------------ -.. class:: FuzzyDecimal(low[, high]) +.. class:: FuzzyDecimal(low[, high[, precision=2]]) - The :class:`FuzzyDecimal` fuzzer generates random integers within a given + The :class:`FuzzyDecimal` fuzzer generates random :class:`decimals ` within a given inclusive range. The :attr:`low` bound may be omitted, in which case it defaults to 0: @@ -140,6 +140,32 @@ FuzzyDecimal int, the number of digits to generate after the dot. The default is 2 digits. +FuzzyFloat +---------- + +.. class:: FuzzyFloat(low[, high]) + + The :class:`FuzzyFloat` fuzzer provides random :class:`float` objects within a given inclusive range. + + .. code-block:: pycon + + >>> FuzzyFloat(0.5, 42.7) + >>> fi.low, fi.high + 0.5, 42.7 + + >>> fi = FuzzyFloat(42.7) + >>> fi.low, fi.high + 0.0, 42.7 + + + .. attribute:: low + + decimal, the inclusive lower bound of generated floats + + .. attribute:: high + + decimal, the inclusive higher bound of generated floats + FuzzyDate --------- diff --git a/factory/fuzzy.py b/factory/fuzzy.py index 2ea544a..94599b7 100644 --- a/factory/fuzzy.py +++ b/factory/fuzzy.py @@ -141,6 +141,23 @@ class FuzzyDecimal(BaseFuzzyAttribute): return base.quantize(decimal.Decimal(10) ** -self.precision) +class FuzzyFloat(BaseFuzzyAttribute): + """Random float within a given range.""" + + def __init__(self, low, high=None, **kwargs): + if high is None: + high = low + low = 0 + + self.low = low + self.high = high + + super(FuzzyFloat, self).__init__(**kwargs) + + def fuzz(self): + return random.uniform(self.low, self.high) + + class FuzzyDate(BaseFuzzyAttribute): """Random date within a given date range.""" -- cgit v1.2.3 From 420bd3703717623491e710cc63ba57fa1561ab8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Sun, 26 Jan 2014 23:46:13 +0100 Subject: Typo --- docs/recipes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/recipes.rst b/docs/recipes.rst index 9e07413..7a6bf23 100644 --- a/docs/recipes.rst +++ b/docs/recipes.rst @@ -66,7 +66,7 @@ Example: Django's Profile """"""""""""""""""""""""" Django (<1.5) provided a mechanism to attach a ``Profile`` to a ``User`` instance, -using a :class:`~django.db.models.ForeignKey` from the ``Profile`` to the ``User``. +using a :class:`~django.db.models.OneToOneField` from the ``Profile`` to the ``User``. A typical way to create those profiles was to hook a post-save signal to the ``User`` model. -- cgit v1.2.3 From e23b48847dddb27e7dc7400b994c3fd830b0f48f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Fri, 28 Feb 2014 00:07:30 +0100 Subject: Add test ensuring that classmethods aren't altered (See #135). --- tests/test_base.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/test_base.py b/tests/test_base.py index 8cea6fc..ba69164 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -88,6 +88,20 @@ class AbstractFactoryTestCase(unittest.TestCase): self.assertRaises(base.FactoryError, TestObjectFactory.create) +class DeclarationParsingTests(unittest.TestCase): + def test_classmethod(self): + class TestObjectFactory(base.Factory): + FACTORY_FOR = TestObject + + @classmethod + def some_classmethod(cls): + return cls.create() + + self.assertTrue(hasattr(TestObjectFactory, 'some_classmethod')) + obj = TestObjectFactory.some_classmethod() + self.assertEqual(TestObject, obj.__class__) + + class FactoryTestCase(unittest.TestCase): def test_factory_for(self): class TestObjectFactory(base.Factory): -- cgit v1.2.3 From 42d3d4b8c543850668186440d5a3ce93e2832c5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Sun, 20 Apr 2014 11:59:10 +0200 Subject: Fix 'gif' image tests. The latest pillow has changed the default gif palette, so we'll use a normalized RGB palette instead. --- tests/test_django.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_django.py b/tests/test_django.py index 50a67a3..29453e6 100644 --- a/tests/test_django.py +++ b/tests/test_django.py @@ -445,9 +445,9 @@ class DjangoImageFieldTestCase(unittest.TestCase): self.assertEqual('django/example.jpg', o.animage.name) i = Image.open(os.path.join(settings.MEDIA_ROOT, o.animage.name)) - colors = i.getcolors() - # 169 pixels with color 190 from the GIF palette - self.assertEqual([(169, 190)], colors) + colors = i.convert('RGB').getcolors() + # 169 pixels with rgb(0, 0, 255) + self.assertEqual([(169, (0, 0, 255))], colors) self.assertEqual('GIF', i.format) def test_with_file(self): -- cgit v1.2.3 From 1fdba9d9417e8f69b39784ee19129a6c43128620 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Sat, 17 May 2014 14:49:09 +0200 Subject: Improve README. --- README.rst | 51 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/README.rst b/README.rst index 0371b28..b35adc5 100644 --- a/README.rst +++ b/README.rst @@ -6,20 +6,61 @@ factory_boy factory_boy is a fixtures replacement based on thoughtbot's `factory_girl `_. -Its features include: +As a fixtures replacement tool, it aims to replace static, hard to maintain fixtures +with easy-to-use factories for complex object. -- Straightforward syntax +Instead of building an exhaustive test setup with every possible combination of corner cases, +``factory_boy`` allows you to use objects customized for the current test, +while only declaring the test-specific fields: + +.. code-block:: python + + class FooTests(unittest.TestCase): + + def test_with_factory_boy(self): + # We need a 200€, paid order, shipping to australia, for a VIP customer + order = OrderFactory( + amount=200, + status='PAID', + customer__is_vip=True, + address__country='AU', + ) + # Run the tests here + + def test_without_factory_boy(self): + address = Address( + street="42 fubar street", + zipcode="42Z42", + city="Sydney", + country="AU", + ) + customer = Customer( + first_name="John", + last_name="Doe", + phone="+1234", + email="john.doe@example.org", + active=True, + is_vip=True, + address=address, + ) + # etc. + +factory_boy is designed to work well with various ORMs (Django, Mogo, SQLAlchemy), +and can easily be extended for other libraries. + +Its main features include: + +- Straightforward declarative syntax +- Chaining factory calls while retaining the global context - Support for multiple build strategies (saved/unsaved instances, attribute dicts, stubbed objects) -- Powerful helpers for common cases (sequences, sub-factories, reverse dependencies, circular factories, ...) - Multiple factories per class support, including inheritance -- Support for various ORMs (currently Django, Mogo, SQLAlchemy) Links ----- * Documentation: http://factoryboy.readthedocs.org/ -* Official repository: https://github.com/rbarrois/factory_boy +* Repository: https://github.com/rbarrois/factory_boy * Package: https://pypi.python.org/pypi/factory_boy/ factory_boy supports Python 2.6, 2.7, 3.2 and 3.3, as well as PyPy; it requires only the standard Python library. -- cgit v1.2.3 From 69894fce7977ea55f8cc3ad141840bab49330859 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Sat, 17 May 2014 18:47:04 +0200 Subject: Switch FACTORY_FOR and related to 'class Meta'. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is easier to declare, avoids cluttering the namespace, and provides entry points for ORM-specific customization. Signed-off-by: Raphaël Barrois --- factory/base.py | 350 ++++++++++++++++++++++++++++++---------------------- factory/django.py | 31 +++-- factory/helpers.py | 4 +- setup.py | 2 +- tests/alter_time.py | 2 +- tests/test_base.py | 30 ++--- 6 files changed, 244 insertions(+), 175 deletions(-) diff --git a/factory/base.py b/factory/base.py index 3c6571c..cc1fb57 100644 --- a/factory/base.py +++ b/factory/base.py @@ -23,6 +23,7 @@ import logging from . import containers +from . import declarations from . import utils logger = logging.getLogger('factory.generate') @@ -33,15 +34,6 @@ CREATE_STRATEGY = 'create' STUB_STRATEGY = 'stub' -# Special declarations -FACTORY_CLASS_DECLARATION = 'FACTORY_FOR' - -# Factory class attributes -CLASS_ATTRIBUTE_DECLARATIONS = '_declarations' -CLASS_ATTRIBUTE_POSTGEN_DECLARATIONS = '_postgen_declarations' -CLASS_ATTRIBUTE_ASSOCIATED_CLASS = '_associated_class' -CLASS_ATTRIBUTE_IS_ABSTRACT = '_abstract_factory' - class FactoryError(Exception): """Any exception raised by factory_boy.""" @@ -66,6 +58,14 @@ def get_factory_bases(bases): return [b for b in bases if issubclass(b, BaseFactory)] +def resolve_attribute(name, bases, default=None): + """Find the first definition of an attribute according to MRO order.""" + for base in bases: + if hasattr(base, name): + return getattr(base, name) + return default + + class FactoryMetaClass(type): """Factory metaclass for handling ordered declarations.""" @@ -75,142 +75,194 @@ class FactoryMetaClass(type): Returns an instance of the associated class. """ - if cls.FACTORY_STRATEGY == BUILD_STRATEGY: + if cls._meta.strategy == BUILD_STRATEGY: return cls.build(**kwargs) - elif cls.FACTORY_STRATEGY == CREATE_STRATEGY: + elif cls._meta.strategy == CREATE_STRATEGY: return cls.create(**kwargs) - elif cls.FACTORY_STRATEGY == STUB_STRATEGY: + elif cls._meta.strategy == STUB_STRATEGY: return cls.stub(**kwargs) else: raise UnknownStrategy('Unknown FACTORY_STRATEGY: {0}'.format( - cls.FACTORY_STRATEGY)) + cls._meta.strategy)) - @classmethod - def _discover_associated_class(mcs, class_name, attrs, inherited=None): - """Try to find the class associated with this factory. + def __new__(mcs, class_name, bases, attrs): + """Record attributes as a pattern for later instance construction. - In order, the following tests will be performed: - - Lookup the FACTORY_CLASS_DECLARATION attribute - - If an inherited associated class was provided, use it. + This is called when a new Factory subclass is defined; it will collect + attribute declaration from the class definition. Args: - class_name (str): the name of the factory class being created - attrs (dict): the dict of attributes from the factory class + class_name (str): the name of the class being created + bases (list of class): the parents of the class being created + attrs (str => obj dict): the attributes as defined in the class definition - inherited (class): the optional associated class inherited from a - parent factory Returns: - class: the class to associate with this factory + A new class """ - if FACTORY_CLASS_DECLARATION in attrs: - return attrs[FACTORY_CLASS_DECLARATION] + parent_factories = get_factory_bases(bases) + if parent_factories: + base_factory = parent_factories[0] + else: + base_factory = None - # No specific associated class was given, and one was defined for our - # parent, use it. - if inherited is not None: - return inherited + attrs_meta = attrs.pop('Meta', None) - # Nothing found, return None. - return None + oldstyle_attrs = {} + for old_name, new_name in base_factory._OLDSTYLE_ATTRIBUTES.items(): + if old_name in attrs: + oldstyle_attrs[new_name] = attrs.pop(old_name) + if oldstyle_attrs: + attrs_meta = type('Meta', (object,), oldstyle_attrs) - @classmethod - def _extract_declarations(mcs, bases, attributes): - """Extract declarations from a class definition. + base_meta = resolve_attribute('_meta', bases) + options_class = resolve_attribute('_options_class', bases, FactoryOptions) - Args: - bases (class list): parent Factory subclasses - attributes (dict): attributes declared in the class definition + meta = options_class() + attrs['_meta'] = meta - Returns: - dict: the original attributes, where declarations have been moved to - _declarations and post-generation declarations to - _postgen_declarations. - """ - declarations = containers.DeclarationDict() - postgen_declarations = containers.PostGenerationDeclarationDict() + new_class = super(FactoryMetaClass, mcs).__new__( + mcs, class_name, bases, attrs) - # Add parent declarations in reverse order. - for base in reversed(bases): - # Import parent PostGenerationDeclaration - 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, {})) + meta.contribute_to_class(new_class, + meta=attrs_meta, + base_meta=base_meta, + base_factory=base_factory, + ) - # Import attributes from the class definition - attributes = postgen_declarations.update_with_public(attributes) - # Store protected/private attributes in 'non_factory_attrs'. - attributes = declarations.update_with_public(attributes) + return new_class - # Store the DeclarationDict in the attributes of the newly created class - attributes[CLASS_ATTRIBUTE_DECLARATIONS] = declarations - attributes[CLASS_ATTRIBUTE_POSTGEN_DECLARATIONS] = postgen_declarations + def __str__(cls): + if cls._meta.abstract: + return '<%s (abstract)>' % cls.__name__ + else: + return '<%s for %s>' % (cls.__name__, cls._meta.target) - return attributes - def __new__(mcs, class_name, bases, attrs): - """Record attributes as a pattern for later instance construction. +class BaseMeta: + abstract = True + strategy = CREATE_STRATEGY - This is called when a new Factory subclass is defined; it will collect - attribute declaration from the class definition. - Args: - class_name (str): the name of the class being created - bases (list of class): the parents of the class being created - attrs (str => obj dict): the attributes as defined in the class - definition +class OptionDefault(object): + def __init__(self, name, value, inherit=False): + self.name = name + self.value = value + self.inherit = inherit - Returns: - A new class - """ - parent_factories = get_factory_bases(bases) - if not parent_factories: - return super(FactoryMetaClass, mcs).__new__( - mcs, class_name, bases, attrs) - - extra_attrs = {} + def apply(self, meta, base_meta): + value = self.value + if self.inherit and base_meta is not None: + value = getattr(base_meta, self.name, value) + if meta is not None: + value = getattr(meta, self.name, value) + return value - is_abstract = attrs.pop('ABSTRACT_FACTORY', False) + def __str__(self): + return '%s(%r, %r, inherit=%r)' % ( + self.__class__.__name__, + self.name, self.value, self.inherit) - base = parent_factories[0] - inherited_associated_class = base._get_target_class() - associated_class = mcs._discover_associated_class(class_name, attrs, - inherited_associated_class) - # Invoke 'lazy-loading' hooks. - associated_class = base._load_target_class(associated_class) +class FactoryOptions(object): + def __init__(self): + self.factory = None + self.base_factory = None + self.declarations = {} + self.postgen_declarations = {} - if associated_class is None: - is_abstract = True + def _build_default_options(self): + """"Provide the default value for all allowed fields. + Custom FactoryOptions classes should override this method + to update() its return value. + """ + return [ + OptionDefault('target', None, inherit=True), + OptionDefault('abstract', False, inherit=False), + OptionDefault('strategy', CREATE_STRATEGY, inherit=True), + OptionDefault('arg_parameters', (), inherit=True), + OptionDefault('hidden_args', (), inherit=True), + ] + + def _fill_from_meta(self, meta, base_meta): + # Exclude private/protected fields from the meta + if meta is None: + meta_attrs = {} + else: + meta_attrs = dict((k, v) + for (k, v) in vars(meta).items() + if not k.startswith('_') + ) + + for option in self._build_default_options(): + assert not hasattr(self, option.name), "Can't override field %s." % option.name + value = option.apply(meta, base_meta) + meta_attrs.pop(option.name, None) + setattr(self, option.name, value) + + if meta_attrs: + # Some attributes in the Meta aren't allowed here + raise TypeError("'class Meta' for %r got unknown attribute(s) %s" + % (self.factory, ','.join(sorted(meta_attrs.keys())))) + + def contribute_to_class(self, factory, + meta=None, base_meta=None, base_factory=None): + + self.factory = factory + self.base_factory = base_factory + + self._fill_from_meta(meta=meta, base_meta=base_meta) + + self.target = self.factory._load_target_class(self.target) + if self.target is None: + self.abstract = True + + if (self.target is not None + and self.base_factory is not None + and self.base_factory._meta.target is not None + and issubclass(self.target, base_factory._meta.target)): + self.counter_reference = self.base_factory else: - # If inheriting the factory from a parent, keep a link to it. - # This allows to use the sequence counters from the parents. - if (inherited_associated_class is not None - and issubclass(associated_class, inherited_associated_class)): - attrs['_base_factory'] = base + self.counter_reference = self.factory - # 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 + for parent in self.factory.__mro__[1:]: + if not hasattr(parent, '_meta'): + continue + self.declarations.update(parent._meta.declarations) + self.postgen_declarations.update(parent._meta.postgen_declarations) - extra_attrs[CLASS_ATTRIBUTE_IS_ABSTRACT] = is_abstract + for k, v in vars(self.factory).items(): + if self._is_declaration(k, v): + self.declarations[k] = v + if self._is_postgen_declaration(k, v): + self.postgen_declarations[k] = v - # Extract pre- and post-generation declarations - attributes = mcs._extract_declarations(parent_factories, attrs) - attributes.update(extra_attrs) + def _is_declaration(self, name, value): + """Determines if a class attribute is a field value declaration. - return super(FactoryMetaClass, mcs).__new__( - mcs, class_name, bases, attributes) + Based on the name and value of the class attribute, return ``True`` if + it looks like a declaration of a default field value, ``False`` if it + is private (name starts with '_') or a classmethod or staticmethod. - def __str__(cls): - if cls._abstract_factory: - return '<%s (abstract)>' - else: - return '<%s for %s>' % (cls.__name__, - getattr(cls, CLASS_ATTRIBUTE_ASSOCIATED_CLASS).__name__) + """ + if isinstance(value, (classmethod, staticmethod)): + return False + elif isinstance(value, declarations.OrderedDeclaration): + return True + elif isinstance(value, declarations.PostGenerationDeclaration): + return False + return not name.startswith("_") + + def _is_postgen_declaration(self, name, value): + """Captures instances of PostGenerationDeclaration.""" + return isinstance(value, declarations.PostGenerationDeclaration) + + def __str__(self): + return "<%s for %s>" % (self.__class__.__name__, self.factory.__class__.__name__) + + def __repr__(self): + return str(self) # Factory base classes @@ -252,25 +304,18 @@ class BaseFactory(object): """Would be called if trying to instantiate the class.""" raise FactoryError('You cannot instantiate BaseFactory') - # ID to use for the next 'declarations.Sequence' attribute. - _counter = None - - # Base factory, if this class was inherited from another factory. This is - # used for sharing the sequence _counter among factories for the same - # class. - _base_factory = None - - # Holds the target class, once resolved. - _associated_class = None + _meta = FactoryOptions() - # Whether this factory is considered "abstract", thus uncallable. - _abstract_factory = False + _OLDSTYLE_ATTRIBUTES = { + 'FACTORY_FOR': 'target', + 'ABSTRACT_FACTORY': 'abstract', + 'FACTORY_STRATEGY': 'strategy', + 'FACTORY_ARG_PARAMETERS': 'arg_parameters', + 'FACTORY_HIDDEN_ARGS': 'hidden_args', + } - # List of arguments that should be passed as *args instead of **kwargs - FACTORY_ARG_PARAMETERS = () - - # List of attributes that should not be passed to the underlying class - FACTORY_HIDDEN_ARGS = () + # ID to use for the next 'declarations.Sequence' attribute. + _counter = None @classmethod def reset_sequence(cls, value=None, force=False): @@ -282,9 +327,9 @@ class BaseFactory(object): force (bool): whether to force-reset parent sequence counters in a factory inheritance chain. """ - if cls._base_factory: + if cls._meta.counter_reference is not cls: if force: - cls._base_factory.reset_sequence(value=value) + cls._meta.base_factory.reset_sequence(value=value) else: raise ValueError( "Cannot reset the sequence of a factory subclass. " @@ -330,9 +375,9 @@ class BaseFactory(object): """ # Rely upon our parents - if cls._base_factory and not cls._base_factory._abstract_factory: - logger.debug("%r: reusing sequence from %r", cls, cls._base_factory) - return cls._base_factory._generate_next_sequence() + if cls._meta.counter_reference is not cls: + logger.debug("%r: reusing sequence from %r", cls, cls._meta.base_factory) + return cls._meta.base_factory._generate_next_sequence() # Make sure _counter is initialized cls._setup_counter() @@ -373,7 +418,9 @@ class BaseFactory(object): extra_defs (dict): additional definitions to insert into the retrieved DeclarationDict. """ - return getattr(cls, CLASS_ATTRIBUTE_DECLARATIONS).copy(extra_defs) + decls = cls._meta.declarations.copy() + decls.update(extra_defs) + return decls @classmethod def _adjust_kwargs(cls, **kwargs): @@ -392,7 +439,7 @@ class BaseFactory(object): @classmethod def _get_target_class(cls): """Retrieve the actual, associated target class.""" - definition = getattr(cls, CLASS_ATTRIBUTE_ASSOCIATED_CLASS, None) + definition = cls._meta.target return cls._load_target_class(definition) @classmethod @@ -407,11 +454,11 @@ class BaseFactory(object): kwargs = cls._adjust_kwargs(**kwargs) # Remove 'hidden' arguments. - for arg in cls.FACTORY_HIDDEN_ARGS: + for arg in cls._meta.hidden_args: del kwargs[arg] # Extract *args from **kwargs - args = tuple(kwargs.pop(key) for key in cls.FACTORY_ARG_PARAMETERS) + args = tuple(kwargs.pop(key) for key in cls._meta.arg_parameters) logger.debug('BaseFactory: Generating %s.%s(%s)', cls.__module__, @@ -431,15 +478,14 @@ class BaseFactory(object): create (bool): whether to 'build' or 'create' the object attrs (dict): attributes to use for generating the object """ - if cls._abstract_factory: + if cls._meta.abstract: raise FactoryError( "Cannot generate instances of abstract factory %(f)s; " - "Ensure %(f)s.FACTORY_FOR is set and %(f)s.ABSTRACT_FACTORY " - "is either not set or False." % dict(f=cls)) + "Ensure %(f)s.Meta.target is set and %(f)s.Meta.abstract " + "is either not set or False." % dict(f=cls.__name__)) # Extract declarations used for post-generation - postgen_declarations = getattr(cls, - CLASS_ATTRIBUTE_POSTGEN_DECLARATIONS) + postgen_declarations = cls._meta.postgen_declarations postgen_attributes = {} for name, decl in sorted(postgen_declarations.items()): postgen_attributes[name] = decl.extract(name, attrs) @@ -626,8 +672,7 @@ class BaseFactory(object): Factory = FactoryMetaClass('Factory', (BaseFactory,), { - 'ABSTRACT_FACTORY': True, - 'FACTORY_STRATEGY': CREATE_STRATEGY, + 'Meta': BaseMeta, '__doc__': """Factory base with build and create support. This class has the ability to support multiple ORMs by using custom creation @@ -642,8 +687,9 @@ Factory.AssociatedClassError = AssociatedClassError # pylint: disable=W0201 class StubFactory(Factory): - FACTORY_STRATEGY = STUB_STRATEGY - FACTORY_FOR = containers.StubObject + class Meta: + strategy = STUB_STRATEGY + target = containers.StubObject @classmethod def build(cls, **kwargs): @@ -656,13 +702,14 @@ class StubFactory(Factory): class BaseDictFactory(Factory): """Factory for dictionary-like classes.""" - ABSTRACT_FACTORY = True + class Meta: + abstract = True @classmethod def _build(cls, target_class, *args, **kwargs): if args: raise ValueError( - "DictFactory %r does not support FACTORY_ARG_PARAMETERS.", cls) + "DictFactory %r does not support Meta.arg_parameters.", cls) return target_class(**kwargs) @classmethod @@ -671,18 +718,20 @@ class BaseDictFactory(Factory): class DictFactory(BaseDictFactory): - FACTORY_FOR = dict + class Meta: + target = dict class BaseListFactory(Factory): """Factory for list-like classes.""" - ABSTRACT_FACTORY = True + class Meta: + abstract = True @classmethod def _build(cls, target_class, *args, **kwargs): if args: raise ValueError( - "ListFactory %r does not support FACTORY_ARG_PARAMETERS.", cls) + "ListFactory %r does not support Meta.arg_parameters.", cls) values = [v for k, v in sorted(kwargs.items())] return target_class(values) @@ -693,7 +742,8 @@ class BaseListFactory(Factory): class ListFactory(BaseListFactory): - FACTORY_FOR = list + class Meta: + target = list def use_strategy(new_strategy): @@ -702,6 +752,6 @@ def use_strategy(new_strategy): This is an alternative to setting default_strategy in the class definition. """ def wrapped_class(klass): - klass.FACTORY_STRATEGY = new_strategy + klass._meta.strategy = new_strategy return klass return wrapped_class diff --git a/factory/django.py b/factory/django.py index a3dfdfc..9a4e07a 100644 --- a/factory/django.py +++ b/factory/django.py @@ -52,6 +52,13 @@ def require_django(): raise import_failure +class DjangoOptions(base.FactoryOptions): + def _build_default_options(self): + return super(DjangoOptions, self)._build_default_options() + [ + base.OptionDefault('django_get_or_create', (), inherit=True), + ] + + class DjangoModelFactory(base.Factory): """Factory for Django models. @@ -61,8 +68,18 @@ class DjangoModelFactory(base.Factory): handle those for non-numerical primary keys. """ - ABSTRACT_FACTORY = True # Optional, but explicit. - FACTORY_DJANGO_GET_OR_CREATE = () + _options_class = DjangoOptions + class Meta: + abstract = True # Optional, but explicit. + + @classmethod + def _get_blank_options(cls): + return DjangoOptions() + + _OLDSTYLE_ATTRIBUTES = base.Factory._OLDSTYLE_ATTRIBUTES.copy() + _OLDSTYLE_ATTRIBUTES.update({ + 'FACTORY_DJANGO_GET_OR_CREATE': 'django_get_or_create', + }) @classmethod def _load_target_class(cls, definition): @@ -101,13 +118,13 @@ class DjangoModelFactory(base.Factory): """Create an instance of the model through objects.get_or_create.""" manager = cls._get_manager(target_class) - assert 'defaults' not in cls.FACTORY_DJANGO_GET_OR_CREATE, ( + assert 'defaults' not in cls._meta.django_get_or_create, ( "'defaults' is a reserved keyword for get_or_create " - "(in %s.FACTORY_DJANGO_GET_OR_CREATE=%r)" - % (cls, cls.FACTORY_DJANGO_GET_OR_CREATE)) + "(in %s._meta.django_get_or_create=%r)" + % (cls, cls._meta.django_get_or_create)) key_fields = {} - for field in cls.FACTORY_DJANGO_GET_OR_CREATE: + for field in cls._meta.django_get_or_create: key_fields[field] = kwargs.pop(field) key_fields['defaults'] = kwargs @@ -119,7 +136,7 @@ class DjangoModelFactory(base.Factory): """Create an instance of the model, and save it to the database.""" manager = cls._get_manager(target_class) - if cls.FACTORY_DJANGO_GET_OR_CREATE: + if cls._meta.django_get_or_create: return cls._get_or_create(target_class, *args, **kwargs) return manager.create(*args, **kwargs) diff --git a/factory/helpers.py b/factory/helpers.py index 4a2a254..0c387d0 100644 --- a/factory/helpers.py +++ b/factory/helpers.py @@ -50,7 +50,9 @@ def debug(logger='factory', stream=None): 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 + class Meta: + target = klass + kwargs['Meta'] = Meta base_class = kwargs.pop('FACTORY_CLASS', base.Factory) factory_class = type(base.Factory).__new__( diff --git a/setup.py b/setup.py index 54e4caa..f637a48 100755 --- a/setup.py +++ b/setup.py @@ -48,7 +48,7 @@ setup( 'setuptools>=0.8', ], tests_require=[ - 'mock', + #'mock', ], classifiers=[ "Development Status :: 5 - Production/Stable", diff --git a/tests/alter_time.py b/tests/alter_time.py index db0a611..aa2db3b 100644 --- a/tests/alter_time.py +++ b/tests/alter_time.py @@ -7,7 +7,7 @@ from __future__ import print_function import datetime -import mock +from .compat import mock real_datetime_class = datetime.datetime diff --git a/tests/test_base.py b/tests/test_base.py index ba69164..2edf829 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -107,7 +107,7 @@ class FactoryTestCase(unittest.TestCase): class TestObjectFactory(base.Factory): FACTORY_FOR = TestObject - self.assertEqual(TestObject, TestObjectFactory.FACTORY_FOR) + self.assertEqual(TestObject, TestObjectFactory._meta.target) obj = TestObjectFactory.build() self.assertFalse(hasattr(obj, 'FACTORY_FOR')) @@ -226,13 +226,13 @@ class FactorySequenceTestCase(unittest.TestCase): class FactoryDefaultStrategyTestCase(unittest.TestCase): def setUp(self): - self.default_strategy = base.Factory.FACTORY_STRATEGY + self.default_strategy = base.Factory._meta.strategy def tearDown(self): - base.Factory.FACTORY_STRATEGY = self.default_strategy + base.Factory._meta.strategy = self.default_strategy def test_build_strategy(self): - base.Factory.FACTORY_STRATEGY = base.BUILD_STRATEGY + base.Factory._meta.strategy = base.BUILD_STRATEGY class TestModelFactory(base.Factory): FACTORY_FOR = TestModel @@ -256,7 +256,7 @@ class FactoryDefaultStrategyTestCase(unittest.TestCase): self.assertTrue(test_model.id) def test_stub_strategy(self): - base.Factory.FACTORY_STRATEGY = base.STUB_STRATEGY + base.Factory._meta.strategy = base.STUB_STRATEGY class TestModelFactory(base.Factory): FACTORY_FOR = TestModel @@ -268,7 +268,7 @@ class FactoryDefaultStrategyTestCase(unittest.TestCase): self.assertFalse(hasattr(test_model, 'id')) # We should have a plain old object def test_unknown_strategy(self): - base.Factory.FACTORY_STRATEGY = 'unknown' + base.Factory._meta.strategy = 'unknown' class TestModelFactory(base.Factory): FACTORY_FOR = TestModel @@ -283,11 +283,11 @@ class FactoryDefaultStrategyTestCase(unittest.TestCase): one = 'one' - TestModelFactory.FACTORY_STRATEGY = base.CREATE_STRATEGY + TestModelFactory._meta.strategy = base.CREATE_STRATEGY self.assertRaises(base.StubFactory.UnsupportedStrategy, TestModelFactory) - TestModelFactory.FACTORY_STRATEGY = base.BUILD_STRATEGY + TestModelFactory._meta.strategy = base.BUILD_STRATEGY self.assertRaises(base.StubFactory.UnsupportedStrategy, TestModelFactory) def test_change_strategy(self): @@ -297,7 +297,7 @@ class FactoryDefaultStrategyTestCase(unittest.TestCase): one = 'one' - self.assertEqual(base.CREATE_STRATEGY, TestModelFactory.FACTORY_STRATEGY) + self.assertEqual(base.CREATE_STRATEGY, TestModelFactory._meta.strategy) class FactoryCreationTestCase(unittest.TestCase): @@ -311,7 +311,7 @@ class FactoryCreationTestCase(unittest.TestCase): class TestFactory(base.StubFactory): pass - self.assertEqual(TestFactory.FACTORY_STRATEGY, base.STUB_STRATEGY) + self.assertEqual(TestFactory._meta.strategy, base.STUB_STRATEGY) def test_inheritance_with_stub(self): class TestObjectFactory(base.StubFactory): @@ -322,7 +322,7 @@ class FactoryCreationTestCase(unittest.TestCase): class TestFactory(TestObjectFactory): pass - self.assertEqual(TestFactory.FACTORY_STRATEGY, base.STUB_STRATEGY) + self.assertEqual(TestFactory._meta.strategy, base.STUB_STRATEGY) def test_custom_creation(self): class TestModelFactory(FakeModelFactory): @@ -349,7 +349,7 @@ class FactoryCreationTestCase(unittest.TestCase): class Test(base.Factory): pass - self.assertTrue(Test._abstract_factory) + self.assertTrue(Test._meta.abstract) class PostGenerationParsingTestCase(unittest.TestCase): @@ -360,7 +360,7 @@ class PostGenerationParsingTestCase(unittest.TestCase): foo = declarations.PostGenerationDeclaration() - self.assertIn('foo', TestObjectFactory._postgen_declarations) + self.assertIn('foo', TestObjectFactory._meta.postgen_declarations) def test_classlevel_extraction(self): class TestObjectFactory(base.Factory): @@ -369,8 +369,8 @@ class PostGenerationParsingTestCase(unittest.TestCase): foo = declarations.PostGenerationDeclaration() foo__bar = 42 - self.assertIn('foo', TestObjectFactory._postgen_declarations) - self.assertIn('foo__bar', TestObjectFactory._declarations) + self.assertIn('foo', TestObjectFactory._meta.postgen_declarations) + self.assertIn('foo__bar', TestObjectFactory._meta.declarations) -- cgit v1.2.3 From 80eaa0c8711f2c3ca82eb7953db49c7c61bd9ffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Sun, 18 May 2014 12:16:51 +0200 Subject: factory.django: Fix counter inheritance with abstract models. --- factory/base.py | 19 ++++++++++++------- factory/django.py | 16 ++++++++++++---- tests/djapp/models.py | 11 ++++++++++- tests/test_django.py | 17 +++++++++++++++-- 4 files changed, 49 insertions(+), 14 deletions(-) diff --git a/factory/base.py b/factory/base.py index cc1fb57..d255dbf 100644 --- a/factory/base.py +++ b/factory/base.py @@ -218,13 +218,7 @@ class FactoryOptions(object): if self.target is None: self.abstract = True - if (self.target is not None - and self.base_factory is not None - and self.base_factory._meta.target is not None - and issubclass(self.target, base_factory._meta.target)): - self.counter_reference = self.base_factory - else: - self.counter_reference = self.factory + self.counter_reference = self._get_counter_reference() for parent in self.factory.__mro__[1:]: if not hasattr(parent, '_meta'): @@ -238,6 +232,17 @@ class FactoryOptions(object): if self._is_postgen_declaration(k, v): self.postgen_declarations[k] = v + def _get_counter_reference(self): + """Identify which factory should be used for a shared counter.""" + + if (self.target is not None + and self.base_factory is not None + and self.base_factory._meta.target is not None + and issubclass(self.target, self.base_factory._meta.target)): + return self.base_factory + else: + return self.factory + def _is_declaration(self, name, value): """Determines if a class attribute is a field value declaration. diff --git a/factory/django.py b/factory/django.py index 9a4e07a..77afd8c 100644 --- a/factory/django.py +++ b/factory/django.py @@ -58,6 +58,18 @@ class DjangoOptions(base.FactoryOptions): base.OptionDefault('django_get_or_create', (), inherit=True), ] + def _get_counter_reference(self): + counter_reference = super(DjangoOptions, self)._get_counter_reference() + if (counter_reference == self.base_factory + and self.base_factory._meta.target is not None + and self.base_factory._meta.target._meta.abstract + and self.target is not None + and not self.target._meta.abstract): + # Target factory is for an abstract model, yet we're for another, + # concrete subclass => don't reuse the counter. + return self.factory + return counter_reference + class DjangoModelFactory(base.Factory): """Factory for Django models. @@ -72,10 +84,6 @@ class DjangoModelFactory(base.Factory): class Meta: abstract = True # Optional, but explicit. - @classmethod - def _get_blank_options(cls): - return DjangoOptions() - _OLDSTYLE_ATTRIBUTES = base.Factory._OLDSTYLE_ATTRIBUTES.copy() _OLDSTYLE_ATTRIBUTES.update({ 'FACTORY_DJANGO_GET_OR_CREATE': 'django_get_or_create', diff --git a/tests/djapp/models.py b/tests/djapp/models.py index a65b50a..9b21181 100644 --- a/tests/djapp/models.py +++ b/tests/djapp/models.py @@ -55,6 +55,15 @@ class ConcreteSon(AbstractBase): pass +class AbstractSon(AbstractBase): + class Meta: + abstract = True + + +class ConcreteGrandSon(AbstractSon): + pass + + class StandardSon(StandardModel): pass @@ -77,4 +86,4 @@ else: class WithSignals(models.Model): - foo = models.CharField(max_length=20) \ No newline at end of file + foo = models.CharField(max_length=20) diff --git a/tests/test_django.py b/tests/test_django.py index 29453e6..37bf7a5 100644 --- a/tests/test_django.py +++ b/tests/test_django.py @@ -130,6 +130,14 @@ class ConcreteSonFactory(AbstractBaseFactory): FACTORY_FOR = models.ConcreteSon +class AbstractSonFactory(AbstractBaseFactory): + FACTORY_FOR = models.AbstractSon + + +class ConcreteGrandSonFactory(AbstractBaseFactory): + FACTORY_FOR = models.ConcreteGrandSon + + class WithFileFactory(factory.django.DjangoModelFactory): FACTORY_FOR = models.WithFile @@ -307,8 +315,13 @@ class DjangoNonIntegerPkTestCase(django_test.TestCase): @unittest.skipIf(django is None, "Django not installed.") class DjangoAbstractBaseSequenceTestCase(django_test.TestCase): def test_auto_sequence(self): - with factory.debug(): - obj = ConcreteSonFactory() + """The sequence of the concrete son of an abstract model should be autonomous.""" + obj = ConcreteSonFactory() + self.assertEqual(1, obj.pk) + + def test_auto_sequence(self): + """The sequence of the concrete grandson of an abstract model should be autonomous.""" + obj = ConcreteGrandSonFactory() self.assertEqual(1, obj.pk) -- cgit v1.2.3 From 92bb395e7f6d422ce239b2ef7303424fde43ab1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Sun, 18 May 2014 12:17:19 +0200 Subject: Migrate factory.alchemy to class Meta --- factory/alchemy.py | 23 ++++++++++++++++++----- tests/test_alchemy.py | 4 ++-- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/factory/alchemy.py b/factory/alchemy.py index cec15c9..b956d7e 100644 --- a/factory/alchemy.py +++ b/factory/alchemy.py @@ -24,17 +24,30 @@ from sqlalchemy.sql.functions import max from . import base +class SQLAlchemyOptions(base.FactoryOptions): + def _build_default_options(self): + return super(SQLAlchemyOptions, self)._build_default_options() + [ + base.OptionDefault('sqlalchemy_session', None, inherit=True), + ] + + class SQLAlchemyModelFactory(base.Factory): """Factory for SQLAlchemy models. """ - ABSTRACT_FACTORY = True - FACTORY_SESSION = None + _options_class = SQLAlchemyOptions + class Meta: + abstract = True + + _OLDSTYLE_ATTRIBUTES = base.Factory._OLDSTYLE_ATTRIBUTES.copy() + _OLDSTYLE_ATTRIBUTES.update({ + 'FACTORY_SESSION': 'sqlalchemy_session', + }) @classmethod def _setup_next_sequence(cls, *args, **kwargs): """Compute the next available PK, based on the 'pk' database field.""" - session = cls.FACTORY_SESSION - model = cls.FACTORY_FOR + session = cls._meta.sqlalchemy_session + model = cls._meta.target pk = getattr(model, model.__mapper__.primary_key[0].name) max_pk = session.query(max(pk)).one()[0] if isinstance(max_pk, int): @@ -45,7 +58,7 @@ class SQLAlchemyModelFactory(base.Factory): @classmethod def _create(cls, target_class, *args, **kwargs): """Create an instance of the model, and save it to the database.""" - session = cls.FACTORY_SESSION + session = cls._meta.sqlalchemy_session obj = target_class(*args, **kwargs) session.add(obj) return obj diff --git a/tests/test_alchemy.py b/tests/test_alchemy.py index 4255417..c94e425 100644 --- a/tests/test_alchemy.py +++ b/tests/test_alchemy.py @@ -66,7 +66,7 @@ class SQLAlchemyPkSequenceTestCase(unittest.TestCase): def setUp(self): super(SQLAlchemyPkSequenceTestCase, self).setUp() StandardFactory.reset_sequence(1) - NonIntegerPkFactory.FACTORY_SESSION.rollback() + NonIntegerPkFactory._meta.sqlalchemy_session.rollback() def test_pk_first(self): std = StandardFactory.build() @@ -104,7 +104,7 @@ class SQLAlchemyNonIntegerPkTestCase(unittest.TestCase): def setUp(self): super(SQLAlchemyNonIntegerPkTestCase, self).setUp() NonIntegerPkFactory.reset_sequence() - NonIntegerPkFactory.FACTORY_SESSION.rollback() + NonIntegerPkFactory._meta.sqlalchemy_session.rollback() def test_first(self): nonint = NonIntegerPkFactory.build() -- cgit v1.2.3 From 47b34e933f94e71e7aabd81cd1e065a807a55276 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Sun, 18 May 2014 12:26:08 +0200 Subject: Add tests for class Meta --- tests/test_base.py | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 118 insertions(+), 5 deletions(-) diff --git a/tests/test_base.py b/tests/test_base.py index 2edf829..be36363 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -67,18 +67,21 @@ class SafetyTestCase(unittest.TestCase): class AbstractFactoryTestCase(unittest.TestCase): def test_factory_for_optional(self): - """Ensure that FACTORY_FOR is optional for ABSTRACT_FACTORY.""" + """Ensure that target= is optional for abstract=True.""" class TestObjectFactory(base.Factory): - ABSTRACT_FACTORY = True + class Meta: + abstract = True - # Passed + self.assertTrue(TestObjectFactory._meta.abstract) + self.assertIsNone(TestObjectFactory._meta.target) def test_factory_for_and_abstract_factory_optional(self): - """Ensure that ABSTRACT_FACTORY is optional.""" + """Ensure that Meta.abstract is optional.""" class TestObjectFactory(base.Factory): pass - # passed + self.assertTrue(TestObjectFactory._meta.abstract) + self.assertIsNone(TestObjectFactory._meta.target) def test_abstract_factory_cannot_be_called(self): class TestObjectFactory(base.Factory): @@ -87,6 +90,116 @@ class AbstractFactoryTestCase(unittest.TestCase): self.assertRaises(base.FactoryError, TestObjectFactory.build) self.assertRaises(base.FactoryError, TestObjectFactory.create) + def test_abstract_factory_not_inherited(self): + """abstract=True isn't propagated to child classes.""" + + class TestObjectFactory(base.Factory): + class Meta: + abstract = True + target = TestObject + + class TestObjectChildFactory(TestObjectFactory): + pass + + self.assertFalse(TestObjectChildFactory._meta.abstract) + + def test_abstract_or_target_is_required(self): + class TestObjectFactory(base.Factory): + class Meta: + abstract = False + target = None + + self.assertRaises(base.FactoryError, TestObjectFactory.build) + self.assertRaises(base.FactoryError, TestObjectFactory.create) + + +class OptionsTests(unittest.TestCase): + def test_base_attrs(self): + class AbstractFactory(base.Factory): + pass + + # Declarative attributes + self.assertTrue(AbstractFactory._meta.abstract) + self.assertIsNone(AbstractFactory._meta.target) + self.assertEqual((), AbstractFactory._meta.arg_parameters) + self.assertEqual((), AbstractFactory._meta.hidden_args) + self.assertEqual(base.CREATE_STRATEGY, AbstractFactory._meta.strategy) + + # Non-declarative attributes + self.assertEqual({}, AbstractFactory._meta.declarations) + self.assertEqual({}, AbstractFactory._meta.postgen_declarations) + self.assertEqual(AbstractFactory, AbstractFactory._meta.factory) + self.assertEqual(base.Factory, AbstractFactory._meta.base_factory) + self.assertEqual(AbstractFactory, AbstractFactory._meta.counter_reference) + + def test_declaration_collecting(self): + lazy = declarations.LazyAttribute(lambda _o: 1) + postgen = declarations.PostGenerationDeclaration() + + class AbstractFactory(base.Factory): + x = 1 + y = lazy + z = postgen + + # Declarations aren't removed + self.assertEqual(1, AbstractFactory.x) + self.assertEqual(lazy, AbstractFactory.y) + self.assertEqual(postgen, AbstractFactory.z) + + # And are available in class Meta + self.assertEqual({'x': 1, 'y': lazy}, AbstractFactory._meta.declarations) + self.assertEqual({'z': postgen}, AbstractFactory._meta.postgen_declarations) + + def test_inherited_declaration_collecting(self): + lazy = declarations.LazyAttribute(lambda _o: 1) + lazy2 = declarations.LazyAttribute(lambda _o: 2) + postgen = declarations.PostGenerationDeclaration() + postgen2 = declarations.PostGenerationDeclaration() + + class AbstractFactory(base.Factory): + x = 1 + y = lazy + z = postgen + + class OtherFactory(AbstractFactory): + a = lazy2 + b = postgen2 + + # Declarations aren't removed + self.assertEqual(lazy2, OtherFactory.a) + self.assertEqual(postgen2, OtherFactory.b) + self.assertEqual(1, OtherFactory.x) + self.assertEqual(lazy, OtherFactory.y) + self.assertEqual(postgen, OtherFactory.z) + + # And are available in class Meta + self.assertEqual({'x': 1, 'y': lazy, 'a': lazy2}, OtherFactory._meta.declarations) + self.assertEqual({'z': postgen, 'b': postgen2}, OtherFactory._meta.postgen_declarations) + + def test_inherited_declaration_shadowing(self): + lazy = declarations.LazyAttribute(lambda _o: 1) + lazy2 = declarations.LazyAttribute(lambda _o: 2) + postgen = declarations.PostGenerationDeclaration() + postgen2 = declarations.PostGenerationDeclaration() + + class AbstractFactory(base.Factory): + x = 1 + y = lazy + z = postgen + + class OtherFactory(AbstractFactory): + y = lazy2 + z = postgen2 + + # Declarations aren't removed + self.assertEqual(1, OtherFactory.x) + self.assertEqual(lazy2, OtherFactory.y) + self.assertEqual(postgen2, OtherFactory.z) + + # And are available in class Meta + self.assertEqual({'x': 1, 'y': lazy2}, OtherFactory._meta.declarations) + self.assertEqual({'z': postgen2}, OtherFactory._meta.postgen_declarations) + class DeclarationParsingTests(unittest.TestCase): def test_classmethod(self): -- cgit v1.2.3 From 395744736691b3412dbedaffa8735e248a70c3c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Sun, 18 May 2014 12:34:19 +0200 Subject: Switch tests to class Meta. --- factory/base.py | 4 +- factory/mogo.py | 3 +- factory/mongoengine.py | 4 +- tests/cyclic/bar.py | 3 +- tests/cyclic/foo.py | 3 +- tests/test_alchemy.py | 13 +- tests/test_base.py | 64 +++++--- tests/test_django.py | 58 ++++--- tests/test_mongoengine.py | 6 +- tests/test_using.py | 380 ++++++++++++++++++++++++++++++---------------- 10 files changed, 353 insertions(+), 185 deletions(-) diff --git a/factory/base.py b/factory/base.py index d255dbf..7db0c76 100644 --- a/factory/base.py +++ b/factory/base.py @@ -40,7 +40,7 @@ class FactoryError(Exception): class AssociatedClassError(FactoryError): - """Exception for Factory subclasses lacking FACTORY_FOR.""" + """Exception for Factory subclasses lacking Meta.target.""" class UnknownStrategy(FactoryError): @@ -82,7 +82,7 @@ class FactoryMetaClass(type): elif cls._meta.strategy == STUB_STRATEGY: return cls.stub(**kwargs) else: - raise UnknownStrategy('Unknown FACTORY_STRATEGY: {0}'.format( + raise UnknownStrategy('Unknown Meta.strategy: {0}'.format( cls._meta.strategy)) def __new__(mcs, class_name, bases, attrs): diff --git a/factory/mogo.py b/factory/mogo.py index 48d9677..0214119 100644 --- a/factory/mogo.py +++ b/factory/mogo.py @@ -32,7 +32,8 @@ from . import base class MogoFactory(base.Factory): """Factory for mogo objects.""" - ABSTRACT_FACTORY = True + class Meta: + abstract = True @classmethod def _build(cls, target_class, *args, **kwargs): diff --git a/factory/mongoengine.py b/factory/mongoengine.py index 462f5f2..729ebb1 100644 --- a/factory/mongoengine.py +++ b/factory/mongoengine.py @@ -32,7 +32,9 @@ from . import base class MongoEngineFactory(base.Factory): """Factory for mongoengine objects.""" - ABSTRACT_FACTORY = True + + class Meta: + abstract = True @classmethod def _build(cls, target_class, *args, **kwargs): diff --git a/tests/cyclic/bar.py b/tests/cyclic/bar.py index fed0602..8674c4d 100644 --- a/tests/cyclic/bar.py +++ b/tests/cyclic/bar.py @@ -30,7 +30,8 @@ class Bar(object): class BarFactory(factory.Factory): - FACTORY_FOR = Bar + class Meta: + target = Bar y = 13 foo = factory.SubFactory('cyclic.foo.FooFactory') diff --git a/tests/cyclic/foo.py b/tests/cyclic/foo.py index e584ed1..5310b1e 100644 --- a/tests/cyclic/foo.py +++ b/tests/cyclic/foo.py @@ -32,7 +32,8 @@ class Foo(object): class FooFactory(factory.Factory): - FACTORY_FOR = Foo + class Meta: + target = Foo x = 42 bar = factory.SubFactory(bar_mod.BarFactory) diff --git a/tests/test_alchemy.py b/tests/test_alchemy.py index c94e425..4526ad1 100644 --- a/tests/test_alchemy.py +++ b/tests/test_alchemy.py @@ -36,7 +36,8 @@ if sqlalchemy: else: class Fake(object): - FACTORY_SESSION = None + class Meta: + sqlalchemy_session = None models = Fake() models.StandardModel = Fake() @@ -46,16 +47,18 @@ else: class StandardFactory(SQLAlchemyModelFactory): - FACTORY_FOR = models.StandardModel - FACTORY_SESSION = models.session + class Meta: + target = models.StandardModel + sqlalchemy_session = models.session id = factory.Sequence(lambda n: n) foo = factory.Sequence(lambda n: 'foo%d' % n) class NonIntegerPkFactory(SQLAlchemyModelFactory): - FACTORY_FOR = models.NonIntegerPk - FACTORY_SESSION = models.session + class Meta: + target = models.NonIntegerPk + sqlalchemy_session = models.session id = factory.Sequence(lambda n: 'foo%d' % n) diff --git a/tests/test_base.py b/tests/test_base.py index be36363..c44ebd5 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -49,7 +49,8 @@ class FakeDjangoModel(object): class FakeModelFactory(base.Factory): - ABSTRACT_FACTORY = True + class Meta: + abstract = True @classmethod def _create(cls, target_class, *args, **kwargs): @@ -204,7 +205,8 @@ class OptionsTests(unittest.TestCase): class DeclarationParsingTests(unittest.TestCase): def test_classmethod(self): class TestObjectFactory(base.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject @classmethod def some_classmethod(cls): @@ -216,24 +218,28 @@ class DeclarationParsingTests(unittest.TestCase): class FactoryTestCase(unittest.TestCase): - def test_factory_for(self): + def test_magic_happens(self): + """Calling a FooFactory doesn't yield a FooFactory instance.""" class TestObjectFactory(base.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject self.assertEqual(TestObject, TestObjectFactory._meta.target) obj = TestObjectFactory.build() - self.assertFalse(hasattr(obj, 'FACTORY_FOR')) + self.assertFalse(hasattr(obj, '_meta')) def test_display(self): class TestObjectFactory(base.Factory): - FACTORY_FOR = FakeDjangoModel + class Meta: + target = FakeDjangoModel self.assertIn('TestObjectFactory', str(TestObjectFactory)) self.assertIn('FakeDjangoModel', str(TestObjectFactory)) def test_lazy_attribute_non_existent_param(self): class TestObjectFactory(base.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = declarations.LazyAttribute(lambda a: a.does_not_exist ) @@ -242,12 +248,14 @@ class FactoryTestCase(unittest.TestCase): def test_inheritance_with_sequence(self): """Tests that sequence IDs are shared between parent and son.""" class TestObjectFactory(base.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = declarations.Sequence(lambda a: a) class TestSubFactory(TestObjectFactory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject pass @@ -264,7 +272,8 @@ class FactorySequenceTestCase(unittest.TestCase): super(FactorySequenceTestCase, self).setUp() class TestObjectFactory(base.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = declarations.Sequence(lambda n: n) self.TestObjectFactory = TestObjectFactory @@ -348,7 +357,8 @@ class FactoryDefaultStrategyTestCase(unittest.TestCase): base.Factory._meta.strategy = base.BUILD_STRATEGY class TestModelFactory(base.Factory): - FACTORY_FOR = TestModel + class Meta: + target = TestModel one = 'one' @@ -357,10 +367,11 @@ class FactoryDefaultStrategyTestCase(unittest.TestCase): self.assertFalse(test_model.id) def test_create_strategy(self): - # Default FACTORY_STRATEGY + # Default Meta.strategy class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + target = TestModel one = 'one' @@ -372,7 +383,8 @@ class FactoryDefaultStrategyTestCase(unittest.TestCase): base.Factory._meta.strategy = base.STUB_STRATEGY class TestModelFactory(base.Factory): - FACTORY_FOR = TestModel + class Meta: + target = TestModel one = 'one' @@ -384,7 +396,8 @@ class FactoryDefaultStrategyTestCase(unittest.TestCase): base.Factory._meta.strategy = 'unknown' class TestModelFactory(base.Factory): - FACTORY_FOR = TestModel + class Meta: + target = TestModel one = 'one' @@ -392,7 +405,8 @@ class FactoryDefaultStrategyTestCase(unittest.TestCase): def test_stub_with_non_stub_strategy(self): class TestModelFactory(base.StubFactory): - FACTORY_FOR = TestModel + class Meta: + target = TestModel one = 'one' @@ -406,7 +420,8 @@ class FactoryDefaultStrategyTestCase(unittest.TestCase): def test_change_strategy(self): @base.use_strategy(base.CREATE_STRATEGY) class TestModelFactory(base.StubFactory): - FACTORY_FOR = TestModel + class Meta: + target = TestModel one = 'one' @@ -416,7 +431,8 @@ class FactoryDefaultStrategyTestCase(unittest.TestCase): class FactoryCreationTestCase(unittest.TestCase): def test_factory_for(self): class TestFactory(base.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject self.assertTrue(isinstance(TestFactory.build(), TestObject)) @@ -428,7 +444,8 @@ class FactoryCreationTestCase(unittest.TestCase): def test_inheritance_with_stub(self): class TestObjectFactory(base.StubFactory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject pass @@ -439,7 +456,8 @@ class FactoryCreationTestCase(unittest.TestCase): def test_custom_creation(self): class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + target = TestModel @classmethod def _prepare(cls, create, **kwargs): @@ -469,7 +487,8 @@ class PostGenerationParsingTestCase(unittest.TestCase): def test_extraction(self): class TestObjectFactory(base.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject foo = declarations.PostGenerationDeclaration() @@ -477,7 +496,8 @@ class PostGenerationParsingTestCase(unittest.TestCase): def test_classlevel_extraction(self): class TestObjectFactory(base.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject foo = declarations.PostGenerationDeclaration() foo__bar = 42 diff --git a/tests/test_django.py b/tests/test_django.py index 37bf7a5..2bc5fe2 100644 --- a/tests/test_django.py +++ b/tests/test_django.py @@ -99,61 +99,71 @@ def tearDownModule(): class StandardFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = models.StandardModel + class Meta: + target = models.StandardModel foo = factory.Sequence(lambda n: "foo%d" % n) class StandardFactoryWithPKField(factory.django.DjangoModelFactory): - FACTORY_FOR = models.StandardModel - FACTORY_DJANGO_GET_OR_CREATE = ('pk',) + class Meta: + target = models.StandardModel + django_get_or_create = ('pk',) foo = factory.Sequence(lambda n: "foo%d" % n) pk = None class NonIntegerPkFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = models.NonIntegerPk + class Meta: + target = models.NonIntegerPk foo = factory.Sequence(lambda n: "foo%d" % n) bar = '' class AbstractBaseFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = models.AbstractBase - ABSTRACT_FACTORY = True + class Meta: + target = models.AbstractBase + abstract = True foo = factory.Sequence(lambda n: "foo%d" % n) class ConcreteSonFactory(AbstractBaseFactory): - FACTORY_FOR = models.ConcreteSon + class Meta: + target = models.ConcreteSon class AbstractSonFactory(AbstractBaseFactory): - FACTORY_FOR = models.AbstractSon + class Meta: + target = models.AbstractSon class ConcreteGrandSonFactory(AbstractBaseFactory): - FACTORY_FOR = models.ConcreteGrandSon + class Meta: + target = models.ConcreteGrandSon class WithFileFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = models.WithFile + class Meta: + target = models.WithFile if django is not None: afile = factory.django.FileField() class WithImageFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = models.WithImage + class Meta: + target = models.WithImage if django is not None: animage = factory.django.ImageField() class WithSignalsFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = models.WithSignals + class Meta: + target = models.WithSignals @unittest.skipIf(django is None, "Django not installed.") @@ -220,17 +230,20 @@ class DjangoPkForceTestCase(django_test.TestCase): @unittest.skipIf(django is None, "Django not installed.") class DjangoModelLoadingTestCase(django_test.TestCase): - """Tests FACTORY_FOR = 'app.Model' pattern.""" + """Tests class Meta: + target = 'app.Model' pattern.""" def test_loading(self): class ExampleFactory(factory.DjangoModelFactory): - FACTORY_FOR = 'djapp.StandardModel' + class Meta: + target = 'djapp.StandardModel' self.assertEqual(models.StandardModel, ExampleFactory._get_target_class()) def test_building(self): class ExampleFactory(factory.DjangoModelFactory): - FACTORY_FOR = 'djapp.StandardModel' + class Meta: + target = 'djapp.StandardModel' e = ExampleFactory.build() self.assertEqual(models.StandardModel, e.__class__) @@ -241,7 +254,8 @@ class DjangoModelLoadingTestCase(django_test.TestCase): See https://github.com/rbarrois/factory_boy/issues/109. """ class ExampleFactory(factory.DjangoModelFactory): - FACTORY_FOR = 'djapp.StandardModel' + class Meta: + target = 'djapp.StandardModel' class Example2Factory(ExampleFactory): pass @@ -255,12 +269,14 @@ class DjangoModelLoadingTestCase(django_test.TestCase): See https://github.com/rbarrois/factory_boy/issues/109. """ class ExampleFactory(factory.DjangoModelFactory): - FACTORY_FOR = 'djapp.StandardModel' + class Meta: + target = 'djapp.StandardModel' foo = factory.Sequence(lambda n: n) class Example2Factory(ExampleFactory): - FACTORY_FOR = 'djapp.StandardSon' + class Meta: + target = 'djapp.StandardSon' self.assertEqual(models.StandardSon, Example2Factory._get_target_class()) @@ -563,7 +579,8 @@ class PreventSignalsTestCase(unittest.TestCase): def test_class_decorator(self): @factory.django.mute_signals(signals.pre_save, signals.post_save) class WithSignalsDecoratedFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = models.WithSignals + class Meta: + target = models.WithSignals WithSignalsDecoratedFactory() @@ -576,7 +593,8 @@ class PreventSignalsTestCase(unittest.TestCase): def test_class_decorator_build(self): @factory.django.mute_signals(signals.pre_save, signals.post_save) class WithSignalsDecoratedFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = models.WithSignals + class Meta: + target = models.WithSignals WithSignalsDecoratedFactory.build() diff --git a/tests/test_mongoengine.py b/tests/test_mongoengine.py index 803607a..39594c0 100644 --- a/tests/test_mongoengine.py +++ b/tests/test_mongoengine.py @@ -42,12 +42,14 @@ if mongoengine: address = mongoengine.EmbeddedDocumentField(Address) class AddressFactory(MongoEngineFactory): - FACTORY_FOR = Address + class Meta: + target = Address street = factory.Sequence(lambda n: 'street%d' % n) class PersonFactory(MongoEngineFactory): - FACTORY_FOR = Person + class Meta: + target = Person name = factory.Sequence(lambda n: 'name%d' % n) address = factory.SubFactory(AddressFactory) diff --git a/tests/test_using.py b/tests/test_using.py index 3979cd0..6e7ed64 100644 --- a/tests/test_using.py +++ b/tests/test_using.py @@ -78,7 +78,8 @@ class FakeModel(object): class FakeModelFactory(factory.Factory): - ABSTRACT_FACTORY = True + class Meta: + abstract = True @classmethod def _create(cls, target_class, *args, **kwargs): @@ -292,7 +293,8 @@ class SimpleBuildTestCase(unittest.TestCase): class UsingFactoryTestCase(unittest.TestCase): def test_attribute(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = 'one' @@ -302,7 +304,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_inheriting_target_class(self): @factory.use_strategy(factory.BUILD_STRATEGY) class TestObjectFactory(factory.Factory, TestObject): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = 'one' @@ -311,18 +314,22 @@ class UsingFactoryTestCase(unittest.TestCase): def test_abstract(self): class SomeAbstractFactory(factory.Factory): - ABSTRACT_FACTORY = True + class Meta: + abstract = True + one = 'one' class InheritedFactory(SomeAbstractFactory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject test_object = InheritedFactory.build() self.assertEqual(test_object.one, 'one') def test_sequence(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = factory.Sequence(lambda n: 'one%d' % n) two = factory.Sequence(lambda n: 'two%d' % n) @@ -337,7 +344,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_sequence_custom_begin(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject @classmethod def _setup_next_sequence(cls): @@ -356,7 +364,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_sequence_override(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = factory.Sequence(lambda n: 'one%d' % n) @@ -372,7 +381,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_custom_create(self): class TestModelFactory(factory.Factory): - FACTORY_FOR = TestModel + class Meta: + target = TestModel two = 2 @@ -395,7 +405,8 @@ class UsingFactoryTestCase(unittest.TestCase): self.y = y class NonDjangoFactory(factory.Factory): - FACTORY_FOR = NonDjango + class Meta: + target = NonDjango x = 3 @@ -405,7 +416,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_sequence_batch(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = factory.Sequence(lambda n: 'one%d' % n) two = factory.Sequence(lambda n: 'two%d' % n) @@ -420,7 +432,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_lazy_attribute(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = factory.LazyAttribute(lambda a: 'abc' ) two = factory.LazyAttribute(lambda a: a.one + ' xyz') @@ -431,7 +444,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_lazy_attribute_sequence(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = factory.LazyAttributeSequence(lambda a, n: 'abc%d' % n) two = factory.LazyAttributeSequence(lambda a, n: a.one + ' xyz%d' % n) @@ -446,7 +460,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_lazy_attribute_decorator(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject @factory.lazy_attribute def one(a): @@ -460,7 +475,8 @@ class UsingFactoryTestCase(unittest.TestCase): n = 3 class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = 'xx' two = factory.SelfAttribute('one') @@ -479,12 +495,14 @@ class UsingFactoryTestCase(unittest.TestCase): pass class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + target = TestModel one = 3 three = factory.SelfAttribute('..bar') class TestModel2Factory(FakeModelFactory): - FACTORY_FOR = TestModel2 + class Meta: + target = TestModel2 bar = 4 two = factory.SubFactory(TestModelFactory, one=1) @@ -493,7 +511,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_sequence_decorator(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject @factory.sequence def one(n): @@ -504,7 +523,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_lazy_attribute_sequence_decorator(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject @factory.lazy_attribute_sequence def one(a, n): @@ -519,7 +539,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_build_with_parameters(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = factory.Sequence(lambda n: 'one%d' % n) two = factory.Sequence(lambda n: 'two%d' % n) @@ -535,7 +556,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_create(self): class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + target = TestModel one = 'one' @@ -545,7 +567,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_create_batch(self): class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + target = TestModel one = 'one' @@ -561,7 +584,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_generate_build(self): class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + target = TestModel one = 'one' @@ -571,7 +595,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_generate_create(self): class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + target = TestModel one = 'one' @@ -581,7 +606,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_generate_stub(self): class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + target = TestModel one = 'one' @@ -591,7 +617,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_generate_batch_build(self): class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + target = TestModel one = 'one' @@ -607,7 +634,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_generate_batch_create(self): class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + target = TestModel one = 'one' @@ -623,7 +651,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_generate_batch_stub(self): class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + target = TestModel one = 'one' @@ -639,7 +668,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_simple_generate_build(self): class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + target = TestModel one = 'one' @@ -649,7 +679,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_simple_generate_create(self): class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + target = TestModel one = 'one' @@ -659,7 +690,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_simple_generate_batch_build(self): class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + target = TestModel one = 'one' @@ -675,7 +707,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_simple_generate_batch_create(self): class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + target = TestModel one = 'one' @@ -691,7 +724,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_stub_batch(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = 'one' two = factory.LazyAttribute(lambda a: a.one + ' two') @@ -710,13 +744,15 @@ class UsingFactoryTestCase(unittest.TestCase): def test_inheritance(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = 'one' two = factory.LazyAttribute(lambda a: a.one + ' two') class TestObjectFactory2(TestObjectFactory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject three = 'three' four = factory.LazyAttribute(lambda a: a.three + ' four') @@ -733,12 +769,14 @@ class UsingFactoryTestCase(unittest.TestCase): def test_inheritance_and_sequences(self): """Sequence counters should be kept within an inheritance chain.""" class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = factory.Sequence(lambda n: n) class TestObjectFactory2(TestObjectFactory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject to1a = TestObjectFactory() self.assertEqual(0, to1a.one) @@ -755,12 +793,14 @@ class UsingFactoryTestCase(unittest.TestCase): pass class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = factory.Sequence(lambda n: n) class TestObjectFactory2(TestObjectFactory): - FACTORY_FOR = TestObject2 + class Meta: + target = TestObject2 to1a = TestObjectFactory() self.assertEqual(0, to1a.one) @@ -785,12 +825,14 @@ class UsingFactoryTestCase(unittest.TestCase): self.one = one class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = factory.Sequence(lambda n: n) class TestObjectFactory2(TestObjectFactory): - FACTORY_FOR = TestObject2 + class Meta: + target = TestObject2 to1a = TestObjectFactory() self.assertEqual(0, to1a.one) @@ -804,7 +846,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_inheritance_with_inherited_class(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = 'one' two = factory.LazyAttribute(lambda a: a.one + ' two') @@ -821,12 +864,14 @@ class UsingFactoryTestCase(unittest.TestCase): def test_dual_inheritance(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = 'one' class TestOtherFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject two = 'two' four = 'four' @@ -841,7 +886,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_class_method_accessible(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject @classmethod def alt_create(cls, **kwargs): @@ -851,7 +897,8 @@ class UsingFactoryTestCase(unittest.TestCase): def test_static_method_accessible(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject @staticmethod def alt_create(**kwargs): @@ -866,8 +913,9 @@ class UsingFactoryTestCase(unittest.TestCase): self.kwargs = kwargs class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject - FACTORY_ARG_PARAMETERS = ('x', 'y') + class Meta: + target = TestObject + arg_parameters = ('x', 'y') x = 1 y = 2 @@ -885,8 +933,9 @@ class UsingFactoryTestCase(unittest.TestCase): self.kwargs = kwargs class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject - FACTORY_HIDDEN_ARGS = ('x', 'z') + class Meta: + target = TestObject + hidden_args = ('x', 'z') x = 1 y = 2 @@ -904,9 +953,10 @@ class UsingFactoryTestCase(unittest.TestCase): self.kwargs = kwargs class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject - FACTORY_HIDDEN_ARGS = ('x', 'z') - FACTORY_ARG_PARAMETERS = ('y',) + class Meta: + target = TestObject + hidden_args = ('x', 'z') + arg_parameters = ('y',) x = 1 y = 2 @@ -927,8 +977,9 @@ class NonKwargParametersTestCase(unittest.TestCase): self.kwargs = kwargs class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject - FACTORY_ARG_PARAMETERS = ('one', 'two',) + class Meta: + target = TestObject + arg_parameters = ('one', 'two',) one = 1 two = 2 @@ -952,8 +1003,9 @@ class NonKwargParametersTestCase(unittest.TestCase): return inst class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject - FACTORY_ARG_PARAMETERS = ('one', 'two') + class Meta: + target = TestObject + arg_parameters = ('one', 'two') one = 1 two = 2 @@ -978,7 +1030,8 @@ class KwargAdjustTestCase(unittest.TestCase): self.kwargs = kwargs class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject @classmethod def _adjust_kwargs(cls, **kwargs): @@ -996,11 +1049,13 @@ class SubFactoryTestCase(unittest.TestCase): pass class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + target = TestModel one = 3 class TestModel2Factory(FakeModelFactory): - FACTORY_FOR = TestModel2 + class Meta: + target = TestModel2 two = factory.SubFactory(TestModelFactory, one=1) test_model = TestModel2Factory(two__one=4) @@ -1013,10 +1068,12 @@ class SubFactoryTestCase(unittest.TestCase): pass class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + target = TestModel class TestModel2Factory(FakeModelFactory): - FACTORY_FOR = TestModel2 + class Meta: + target = TestModel2 two = factory.SubFactory(TestModelFactory, one=factory.Sequence(lambda n: 'x%dx' % n), two=factory.LazyAttribute(lambda o: '%s%s' % (o.one, o.one)), @@ -1033,12 +1090,14 @@ class SubFactoryTestCase(unittest.TestCase): setattr(self, k, v) class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = factory.Sequence(lambda n: int(n)) class WrappingTestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject wrapped = factory.SubFactory(TestObjectFactory) @@ -1054,7 +1113,8 @@ class SubFactoryTestCase(unittest.TestCase): setattr(self, k, v) class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject class OtherTestObject(object): @@ -1063,7 +1123,8 @@ class SubFactoryTestCase(unittest.TestCase): setattr(self, k, v) class WrappingTestObjectFactory(factory.Factory): - FACTORY_FOR = OtherTestObject + class Meta: + target = OtherTestObject wrapped = factory.SubFactory(TestObjectFactory, two=2, four=4) wrapped__two = 4 @@ -1083,16 +1144,19 @@ class SubFactoryTestCase(unittest.TestCase): setattr(self, k, v) class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject class WrappingTestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject wrapped = factory.SubFactory(TestObjectFactory) wrapped_bis = factory.SubFactory(TestObjectFactory, one=1) class OuterWrappingTestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject wrap = factory.SubFactory(WrappingTestObjectFactory, wrapped__two=2) @@ -1109,17 +1173,20 @@ class SubFactoryTestCase(unittest.TestCase): setattr(self, k, v) class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject two = 'two' class WrappingTestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject wrapped = factory.SubFactory(TestObjectFactory) friend = factory.LazyAttribute(lambda o: o.wrapped.two.four + 1) class OuterWrappingTestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject wrap = factory.SubFactory(WrappingTestObjectFactory, wrapped__two=factory.SubFactory(TestObjectFactory, four=4)) @@ -1139,12 +1206,14 @@ class SubFactoryTestCase(unittest.TestCase): # Innermost factory class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject two = 'two' # Intermediary factory class WrappingTestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject wrapped = factory.SubFactory(TestObjectFactory) wrapped__two = 'three' @@ -1162,11 +1231,13 @@ class SubFactoryTestCase(unittest.TestCase): setattr(self, k, v) class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject two = 'two' class WrappingTestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject wrapped = factory.SubFactory(TestObjectFactory) friend = factory.LazyAttribute(lambda o: o.wrapped.two + 1) @@ -1200,20 +1271,24 @@ class SubFactoryTestCase(unittest.TestCase): self.side_b = side_b class InnerMostFactory(factory.Factory): - FACTORY_FOR = InnerMost + class Meta: + target = InnerMost a = 15 b = 20 class SideAFactory(factory.Factory): - FACTORY_FOR = SideA + class Meta: + target = SideA inner_from_a = factory.SubFactory(InnerMostFactory, a=20) class SideBFactory(factory.Factory): - FACTORY_FOR = SideB + class Meta: + target = SideB inner_from_b = factory.SubFactory(InnerMostFactory, b=15) class OuterMostFactory(factory.Factory): - FACTORY_FOR = OuterMost + class Meta: + target = OuterMost foo = 30 side_a = factory.SubFactory(SideAFactory, @@ -1238,12 +1313,14 @@ class SubFactoryTestCase(unittest.TestCase): pass class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + target = TestModel one = 3 two = factory.ContainerAttribute(lambda obj, containers: len(containers or []), strict=False) class TestModel2Factory(FakeModelFactory): - FACTORY_FOR = TestModel2 + class Meta: + target = TestModel2 one = 1 two = factory.SubFactory(TestModelFactory, one=1) @@ -1261,12 +1338,14 @@ class SubFactoryTestCase(unittest.TestCase): pass class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + target = TestModel one = 3 two = factory.ContainerAttribute(lambda obj, containers: len(containers or []), strict=True) class TestModel2Factory(FakeModelFactory): - FACTORY_FOR = TestModel2 + class Meta: + target = TestModel2 one = 1 two = factory.SubFactory(TestModelFactory, one=1) @@ -1282,7 +1361,8 @@ class SubFactoryTestCase(unittest.TestCase): pass class TestModelFactory(FakeModelFactory): - FACTORY_FOR = TestModel + class Meta: + target = TestModel one = 3 @factory.container_attribute @@ -1292,7 +1372,8 @@ class SubFactoryTestCase(unittest.TestCase): return 42 class TestModel2Factory(FakeModelFactory): - FACTORY_FOR = TestModel2 + class Meta: + target = TestModel2 one = 1 two = factory.SubFactory(TestModelFactory, one=1) @@ -1310,7 +1391,8 @@ class IteratorTestCase(unittest.TestCase): def test_iterator(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = factory.Iterator(range(10, 30)) @@ -1323,7 +1405,8 @@ class IteratorTestCase(unittest.TestCase): @tools.disable_warnings def test_iterator_list_comprehension_scope_bleeding(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = factory.Iterator([j * 3 for j in range(5)]) @@ -1334,7 +1417,8 @@ class IteratorTestCase(unittest.TestCase): @tools.disable_warnings def test_iterator_list_comprehension_protected(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = factory.Iterator([_j * 3 for _j in range(5)]) @@ -1347,7 +1431,8 @@ class IteratorTestCase(unittest.TestCase): def test_iterator_decorator(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject @factory.iterator def one(): @@ -1397,7 +1482,8 @@ class BetterFakeModel(object): class DjangoModelFactoryTestCase(unittest.TestCase): def test_simple(self): class FakeModelFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = FakeModel + class Meta: + target = FakeModel obj = FakeModelFactory(one=1) self.assertEqual(1, obj.one) @@ -1411,8 +1497,9 @@ class DjangoModelFactoryTestCase(unittest.TestCase): objects = BetterFakeModelManager({'x': 1}, prev) class MyFakeModelFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = MyFakeModel - FACTORY_DJANGO_GET_OR_CREATE = ('x',) + class Meta: + target = MyFakeModel + django_get_or_create = ('x',) x = 1 y = 4 z = 6 @@ -1432,8 +1519,9 @@ class DjangoModelFactoryTestCase(unittest.TestCase): objects = BetterFakeModelManager({'x': 1, 'y': 2, 'z': 3}, prev) class MyFakeModelFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = MyFakeModel - FACTORY_DJANGO_GET_OR_CREATE = ('x', 'y', 'z') + class Meta: + target = MyFakeModel + django_get_or_create = ('x', 'y', 'z') x = 1 y = 4 z = 6 @@ -1453,8 +1541,9 @@ class DjangoModelFactoryTestCase(unittest.TestCase): objects = BetterFakeModelManager({'x': 1}, prev) class MyFakeModelFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = MyFakeModel - FACTORY_DJANGO_GET_OR_CREATE = ('x',) + class Meta: + target = MyFakeModel + django_get_or_create = ('x',) x = 1 y = 4 z = 6 @@ -1474,8 +1563,9 @@ class DjangoModelFactoryTestCase(unittest.TestCase): objects = BetterFakeModelManager({'x': 1, 'y': 2, 'z': 3}, prev) class MyFakeModelFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = MyFakeModel - FACTORY_DJANGO_GET_OR_CREATE = ('x', 'y', 'z') + class Meta: + target = MyFakeModel + django_get_or_create = ('x', 'y', 'z') x = 1 y = 4 z = 6 @@ -1489,7 +1579,8 @@ class DjangoModelFactoryTestCase(unittest.TestCase): def test_sequence(self): class TestModelFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = TestModel + class Meta: + target = TestModel a = factory.Sequence(lambda n: 'foo_%s' % n) @@ -1507,7 +1598,8 @@ class DjangoModelFactoryTestCase(unittest.TestCase): def test_no_get_or_create(self): class TestModelFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = TestModel + class Meta: + target = TestModel a = factory.Sequence(lambda n: 'foo_%s' % n) @@ -1518,8 +1610,9 @@ class DjangoModelFactoryTestCase(unittest.TestCase): def test_get_or_create(self): class TestModelFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = TestModel - FACTORY_DJANGO_GET_OR_CREATE = ('a', 'b') + class Meta: + target = TestModel + django_get_or_create = ('a', 'b') a = factory.Sequence(lambda n: 'foo_%s' % n) b = 2 @@ -1537,8 +1630,9 @@ class DjangoModelFactoryTestCase(unittest.TestCase): def test_full_get_or_create(self): """Test a DjangoModelFactory with all fields in get_or_create.""" class TestModelFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = TestModel - FACTORY_DJANGO_GET_OR_CREATE = ('a', 'b', 'c', 'd') + class Meta: + target = TestModel + django_get_or_create = ('a', 'b', 'c', 'd') a = factory.Sequence(lambda n: 'foo_%s' % n) b = 2 @@ -1557,7 +1651,8 @@ class DjangoModelFactoryTestCase(unittest.TestCase): class PostGenerationTestCase(unittest.TestCase): def test_post_generation(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = 1 @@ -1575,7 +1670,8 @@ class PostGenerationTestCase(unittest.TestCase): def test_post_generation_hook(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = 1 @@ -1596,7 +1692,8 @@ class PostGenerationTestCase(unittest.TestCase): def test_post_generation_extraction(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = 1 @@ -1621,7 +1718,8 @@ class PostGenerationTestCase(unittest.TestCase): self.assertEqual(kwargs, {'foo': 13}) class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject bar = factory.PostGeneration(my_lambda) @@ -1640,7 +1738,8 @@ class PostGenerationTestCase(unittest.TestCase): self.extra = (args, kwargs) class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = 3 two = 2 post_call = factory.PostGenerationMethodCall('call', one=1) @@ -1664,12 +1763,14 @@ class PostGenerationTestCase(unittest.TestCase): self.three = obj class TestRelatedObjectFactory(factory.Factory): - FACTORY_FOR = TestRelatedObject + class Meta: + target = TestRelatedObject one = 1 two = factory.LazyAttribute(lambda o: o.one + 1) class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = 3 two = 2 three = factory.RelatedFactory(TestRelatedObjectFactory, name='obj') @@ -1709,12 +1810,14 @@ class PostGenerationTestCase(unittest.TestCase): self.three = obj class TestRelatedObjectFactory(factory.Factory): - FACTORY_FOR = TestRelatedObject + class Meta: + target = TestRelatedObject one = 1 two = factory.LazyAttribute(lambda o: o.one + 1) class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = 3 two = 2 three = factory.RelatedFactory(TestRelatedObjectFactory) @@ -1755,10 +1858,12 @@ class RelatedFactoryExtractionTestCase(unittest.TestCase): obj.related = subself class TestRelatedObjectFactory(factory.Factory): - FACTORY_FOR = TestRelatedObject + class Meta: + target = TestRelatedObject class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = factory.RelatedFactory(TestRelatedObjectFactory, 'obj') self.TestRelatedObject = TestRelatedObject @@ -1805,7 +1910,8 @@ class CircularTestCase(unittest.TestCase): class DictTestCase(unittest.TestCase): def test_empty_dict(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = factory.Dict({}) o = TestObjectFactory() @@ -1813,7 +1919,8 @@ class DictTestCase(unittest.TestCase): def test_naive_dict(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = factory.Dict({'a': 1}) o = TestObjectFactory() @@ -1821,7 +1928,8 @@ class DictTestCase(unittest.TestCase): def test_sequence_dict(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = factory.Dict({'a': factory.Sequence(lambda n: n + 2)}) o1 = TestObjectFactory() @@ -1832,7 +1940,8 @@ class DictTestCase(unittest.TestCase): def test_dict_override(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = factory.Dict({'a': 1}) o = TestObjectFactory(one__a=2) @@ -1840,7 +1949,8 @@ class DictTestCase(unittest.TestCase): def test_dict_extra_key(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = factory.Dict({'a': 1}) o = TestObjectFactory(one__b=2) @@ -1848,7 +1958,8 @@ class DictTestCase(unittest.TestCase): def test_dict_merged_fields(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject two = 13 one = factory.Dict({ 'one': 1, @@ -1861,7 +1972,8 @@ class DictTestCase(unittest.TestCase): def test_nested_dicts(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = 1 two = factory.Dict({ 'one': 3, @@ -1889,7 +2001,8 @@ class DictTestCase(unittest.TestCase): class ListTestCase(unittest.TestCase): def test_empty_list(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = factory.List([]) o = TestObjectFactory() @@ -1897,7 +2010,8 @@ class ListTestCase(unittest.TestCase): def test_naive_list(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = factory.List([1]) o = TestObjectFactory() @@ -1905,7 +2019,8 @@ class ListTestCase(unittest.TestCase): def test_sequence_list(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = factory.List([factory.Sequence(lambda n: n + 2)]) o1 = TestObjectFactory() @@ -1916,7 +2031,8 @@ class ListTestCase(unittest.TestCase): def test_list_override(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = factory.List([1]) o = TestObjectFactory(one__0=2) @@ -1924,7 +2040,8 @@ class ListTestCase(unittest.TestCase): def test_list_extra_key(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject one = factory.List([1]) o = TestObjectFactory(one__1=2) @@ -1932,7 +2049,8 @@ class ListTestCase(unittest.TestCase): def test_list_merged_fields(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject two = 13 one = factory.List([ 1, @@ -1945,7 +2063,9 @@ class ListTestCase(unittest.TestCase): def test_nested_lists(self): class TestObjectFactory(factory.Factory): - FACTORY_FOR = TestObject + class Meta: + target = TestObject + one = 1 two = factory.List([ 3, -- cgit v1.2.3 From d26f41368e7c8936306cf1c34d73fff40d958128 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Sun, 18 May 2014 12:40:25 +0200 Subject: Remove containers.DeclarationsDict. Now replaced with a simple dict. --- factory/containers.py | 55 -------------------------- tests/test_containers.py | 101 +---------------------------------------------- 2 files changed, 1 insertion(+), 155 deletions(-) diff --git a/factory/containers.py b/factory/containers.py index 4537e44..c0c5e24 100644 --- a/factory/containers.py +++ b/factory/containers.py @@ -121,61 +121,6 @@ class LazyStub(object): raise AttributeError('Setting of object attributes is not allowed') -class DeclarationDict(dict): - """Slightly extended dict to work with OrderedDeclaration.""" - - def is_declaration(self, name, value): - """Determines if a class attribute is a field value declaration. - - Based on the name and value of the class attribute, return ``True`` if - it looks like a declaration of a default field value, ``False`` if it - is private (name starts with '_') or a classmethod or staticmethod. - - """ - if isinstance(value, (classmethod, staticmethod)): - return False - elif isinstance(value, declarations.OrderedDeclaration): - return True - return (not name.startswith("_") and not name.startswith("FACTORY_")) - - def update_with_public(self, d): - """Updates the DeclarationDict from a class definition dict. - - Takes into account all public attributes and OrderedDeclaration - instances; ignores all class/staticmethods and private attributes - (starting with '_'). - - Returns a dict containing all remaining elements. - """ - remaining = {} - for k, v in d.items(): - if self.is_declaration(k, v): - self[k] = v - else: - remaining[k] = v - return remaining - - def copy(self, extra=None): - """Copy this DeclarationDict into another one, including extra values. - - Args: - extra (dict): additional attributes to include in the copy. - """ - new = self.__class__() - new.update(self) - if extra: - new.update(extra) - return new - - -class PostGenerationDeclarationDict(DeclarationDict): - """Alternate DeclarationDict for PostGenerationDeclaration.""" - - def is_declaration(self, name, value): - """Captures instances of PostGenerationDeclaration.""" - return isinstance(value, declarations.PostGenerationDeclaration) - - class LazyValue(object): """Some kind of "lazy evaluating" object.""" diff --git a/tests/test_containers.py b/tests/test_containers.py index 8b78dc7..8a9e990 100644 --- a/tests/test_containers.py +++ b/tests/test_containers.py @@ -100,105 +100,6 @@ class LazyStubTestCase(unittest.TestCase): self.assertIn('one', str(stub)) -class OrderedDeclarationMock(declarations.OrderedDeclaration): - pass - - -class DeclarationDictTestCase(unittest.TestCase): - def test_basics(self): - one = OrderedDeclarationMock() - two = 2 - three = OrderedDeclarationMock() - - d = containers.DeclarationDict(dict(one=one, two=two, three=three)) - - self.assertTrue('one' in d) - self.assertTrue('two' in d) - self.assertTrue('three' in d) - - self.assertEqual(one, d['one']) - self.assertEqual(two, d['two']) - self.assertEqual(three, d['three']) - - self.assertEqual(one, d.pop('one')) - self.assertFalse('one' in d) - - d['one'] = one - self.assertTrue('one' in d) - self.assertEqual(one, d['one']) - - self.assertEqual(set(['one', 'two', 'three']), - set(d)) - - def test_insert(self): - one = OrderedDeclarationMock() - two = 2 - three = OrderedDeclarationMock() - four = OrderedDeclarationMock() - - d = containers.DeclarationDict(dict(one=one, two=two, four=four)) - - self.assertEqual(set(['two', 'one', 'four']), set(d)) - - d['three'] = three - self.assertEqual(set(['two', 'one', 'three', 'four']), set(d)) - - def test_replace(self): - one = OrderedDeclarationMock() - two = 2 - three = OrderedDeclarationMock() - four = OrderedDeclarationMock() - - d = containers.DeclarationDict(dict(one=one, two=two, three=three)) - - self.assertEqual(set(['two', 'one', 'three']), set(d)) - - d['three'] = four - self.assertEqual(set(['two', 'one', 'three']), set(d)) - self.assertEqual(set([two, one, four]), set(d.values())) - - def test_copy(self): - one = OrderedDeclarationMock() - two = 2 - three = OrderedDeclarationMock() - four = OrderedDeclarationMock() - - d = containers.DeclarationDict(dict(one=one, two=two, three=three)) - d2 = d.copy({'five': 5}) - - self.assertEqual(5, d2['five']) - self.assertFalse('five' in d) - - d.pop('one') - self.assertEqual(one, d2['one']) - - d2['two'] = four - self.assertEqual(four, d2['two']) - self.assertEqual(two, d['two']) - - def test_update_with_public(self): - d = containers.DeclarationDict() - d.update_with_public({ - 'one': 1, - '_two': 2, - 'three': 3, - 'classmethod': classmethod(lambda c: 1), - 'staticmethod': staticmethod(lambda: 1), - }) - 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): @@ -320,7 +221,7 @@ class AttributeBuilderTestCase(unittest.TestCase): class FakeFactory(object): @classmethod def declarations(cls, extra): - d = containers.DeclarationDict({'one': 1, 'two': la}) + d = {'one': 1, 'two': la} d.update(extra) return d -- cgit v1.2.3 From c7b2ac71acd93b5afdf5cb4d958ffa1bbcd464e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Sun, 18 May 2014 12:54:39 +0200 Subject: Add DeprecationWarning for FACTORY_* kwargs --- factory/base.py | 15 +++++++++++++-- tests/__init__.py | 1 + tests/test_deprecation.py | 49 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 tests/test_deprecation.py diff --git a/factory/base.py b/factory/base.py index 7db0c76..862556e 100644 --- a/factory/base.py +++ b/factory/base.py @@ -21,6 +21,7 @@ # THE SOFTWARE. import logging +import warnings from . import containers from . import declarations @@ -109,11 +110,21 @@ class FactoryMetaClass(type): attrs_meta = attrs.pop('Meta', None) oldstyle_attrs = {} + converted_attrs = {} for old_name, new_name in base_factory._OLDSTYLE_ATTRIBUTES.items(): if old_name in attrs: - oldstyle_attrs[new_name] = attrs.pop(old_name) + oldstyle_attrs[old_name] = new_name + converted_attrs[new_name] = attrs.pop(old_name) if oldstyle_attrs: - attrs_meta = type('Meta', (object,), oldstyle_attrs) + warnings.warn( + "Declaring any of %s at class-level is deprecated" + " and will be removed in the future. Please set them" + " as %s attributes of a 'class Meta' attribute." % ( + ', '.join(oldstyle_attrs.keys()), + ', '.join(oldstyle_attrs.values()), + ), + PendingDeprecationWarning, 2) + attrs_meta = type('Meta', (object,), converted_attrs) base_meta = resolve_attribute('_meta', bases) options_class = resolve_attribute('_options_class', bases, FactoryOptions) diff --git a/tests/__init__.py b/tests/__init__.py index 5b6fc55..855beea 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -4,6 +4,7 @@ from .test_base import * from .test_containers import * from .test_declarations import * +from .test_deprecation import * from .test_django import * from .test_fuzzy import * from .test_helpers import * diff --git a/tests/test_deprecation.py b/tests/test_deprecation.py new file mode 100644 index 0000000..bccc351 --- /dev/null +++ b/tests/test_deprecation.py @@ -0,0 +1,49 @@ +# -*- 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. + +"""Tests for deprecated features.""" + +import warnings + +import factory + +from .compat import mock, unittest +from . import tools + + +class DeprecationTests(unittest.TestCase): + def test_factory_for(self): + class Foo(object): + pass + + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter('always') + class FooFactory(factory.Factory): + FACTORY_FOR = Foo + + self.assertEqual(1, len(w)) + warning = w[0] + # Message is indeed related to the current file + # This is to ensure error messages are readable by end users. + self.assertEqual(__file__, warning.filename) + self.assertIn('FACTORY_FOR', str(warning.message)) + self.assertIn('target', str(warning.message)) -- cgit v1.2.3 From fd3d2583580fc18ff1531b5be02238c8c2addccc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Sun, 18 May 2014 14:20:26 +0200 Subject: Update ChangeLog --- docs/changelog.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index 47d1139..e5d76c7 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -12,6 +12,11 @@ ChangeLog - Add support for :attr:`factory.fuzzy.FuzzyInteger.step`, thanks to `ilya-pirogov `_ (:issue:`120`) - Add :meth:`~factory.django.mute_signals` decorator to temporarily disable some signals, thanks to `ilya-pirogov `_ (:issue:`122`) - Add :class:`~factory.fuzzy.FuzzyFloat` (:issue:`124`) + - Declare target model and other non-declaration fields in a ``class Meta`` section. + +*Deprecation:* + + - Use of ``FACTORY_FOR`` and other ``FACTORY`` class-level attributes is deprecated and will be removed in 2.5. .. _v2.3.1: -- cgit v1.2.3 From b245a83019a8735d0c80c07275cd426bc60dd9f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Sun, 18 May 2014 14:46:03 +0200 Subject: Update docs for class Meta. --- README.rst | 21 +++-- docs/examples.rst | 6 +- docs/introduction.rst | 41 ++++++---- docs/orms.rst | 47 +++++++---- docs/recipes.rst | 40 ++++++--- docs/reference.rst | 219 +++++++++++++++++++++++++++++++++++++------------- 6 files changed, 265 insertions(+), 109 deletions(-) diff --git a/README.rst b/README.rst index b35adc5..787d754 100644 --- a/README.rst +++ b/README.rst @@ -94,7 +94,8 @@ Usage 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: +Factories declare a set of attributes used to instantiate an object. +The class of the object must be defined in the ``target`` field of a ``class Meta:`` attribute: .. code-block:: python @@ -102,7 +103,8 @@ Factories declare a set of attributes used to instantiate an object. The class o from . import models class UserFactory(factory.Factory): - FACTORY_FOR = models.User + class Meta: + target = models.User first_name = 'John' last_name = 'Doe' @@ -110,7 +112,8 @@ Factories declare a set of attributes used to instantiate an object. The class o # Another, different, factory for the same object class AdminFactory(factory.Factory): - FACTORY_FOR = models.User + class Meta: + target = models.User first_name = 'Admin' last_name = 'User' @@ -164,7 +167,9 @@ These "lazy" attributes can be added as follows: .. code-block:: python class UserFactory(factory.Factory): - FACTORY_FOR = models.User + class Meta: + target = models.User + first_name = 'Joe' last_name = 'Blow' email = factory.LazyAttribute(lambda a: '{0}.{1}@example.com'.format(a.first_name, a.last_name).lower()) @@ -183,7 +188,9 @@ Unique values in a specific format (for example, e-mail addresses) can be genera .. code-block:: python class UserFactory(factory.Factory): - FACTORY_FOR = models.User + class Meta: + target = models.User + email = factory.Sequence(lambda n: 'person{0}@example.com'.format(n)) >>> UserFactory().email @@ -201,7 +208,9 @@ This is handled by the ``SubFactory`` helper: .. code-block:: python class PostFactory(factory.Factory): - FACTORY_FOR = models.Post + class Meta: + target = models.Post + author = factory.SubFactory(UserFactory) diff --git a/docs/examples.rst b/docs/examples.rst index aab990a..52a5ef6 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -56,14 +56,16 @@ And now, we'll define the related factories: class AccountFactory(factory.Factory): - FACTORY_FOR = objects.Account + class Meta: + target = objects.Account username = factory.Sequence(lambda n: 'john%s' % n) email = factory.LazyAttribute(lambda o: '%s@example.org' % o.username) class ProfileFactory(factory.Factory): - FACTORY_FOR = objects.Profile + class Meta: + target = objects.Profile account = factory.SubFactory(AccountFactory) gender = factory.Iterator([objects.Profile.GENDER_MALE, objects.Profile.GENDER_FEMALE]) diff --git a/docs/introduction.rst b/docs/introduction.rst index 86e2046..6ea6b5e 100644 --- a/docs/introduction.rst +++ b/docs/introduction.rst @@ -18,10 +18,11 @@ Basic usage ----------- -Factories declare a set of attributes used to instantiate an object, whose class is defined in the FACTORY_FOR attribute: +Factories declare a set of attributes used to instantiate an object, whose class is defined in the ``class Meta``'s ``target`` attribute: - Subclass ``factory.Factory`` (or a more suitable subclass) -- Set its ``FACTORY_FOR`` attribute to the target class +- Add a ``class Meta:`` block +- Set its ``target`` attribute to the target class - Add defaults for keyword args to pass to the associated class' ``__init__`` method @@ -31,7 +32,8 @@ Factories declare a set of attributes used to instantiate an object, whose class from . import base class UserFactory(factory.Factory): - FACTORY_FOR = base.User + class Meta: + target = base.User firstname = "John" lastname = "Doe" @@ -56,7 +58,8 @@ A given class may be associated to many :class:`~factory.Factory` subclasses: .. code-block:: python class EnglishUserFactory(factory.Factory): - FACTORY_FOR = base.User + class Meta: + target = base.User firstname = "John" lastname = "Doe" @@ -64,7 +67,8 @@ A given class may be associated to many :class:`~factory.Factory` subclasses: class FrenchUserFactory(factory.Factory): - FACTORY_FOR = base.User + class Meta: + target = base.User firstname = "Jean" lastname = "Dupont" @@ -88,7 +92,8 @@ This is achieved with the :class:`~factory.Sequence` declaration: .. code-block:: python class UserFactory(factory.Factory): - FACTORY_FOR = models.User + class Meta: + target = models.User username = factory.Sequence(lambda n: 'user%d' % n) @@ -104,7 +109,8 @@ This is achieved with the :class:`~factory.Sequence` declaration: .. code-block:: python class UserFactory(factory.Factory): - FACTORY_FOR = models.User + class Meta: + target = models.User @factory.sequence def username(n): @@ -121,7 +127,8 @@ taking the object being built and returning the value for the field: .. code-block:: python class UserFactory(factory.Factory): - FACTORY_FOR = models.User + class Meta: + target = models.User username = factory.Sequence(lambda n: 'user%d' % n) email = factory.LazyAttribute(lambda obj: '%s@example.com' % obj.username) @@ -146,7 +153,8 @@ taking the object being built and returning the value for the field: .. code-block:: python class UserFactory(factory.Factory): - FACTORY_FOR = models.User + class Meta: + target = models.User username = factory.Sequence(lambda n: 'user%d' % n) @@ -168,7 +176,8 @@ and update them with its own declarations: .. code-block:: python class UserFactory(factory.Factory): - FACTORY_FOR = base.User + class Meta: + target = base.User firstname = "John" lastname = "Doe" @@ -209,13 +218,14 @@ Non-kwarg arguments Some classes take a few, non-kwarg arguments first. -This is handled by the :data:`~factory.Factory.FACTORY_ARG_PARAMETERS` attribute: +This is handled by the :data:`~factory.FactoryOptions.arg_parameters` attribute: .. code-block:: python class MyFactory(factory.Factory): - FACTORY_FOR = MyClass - FACTORY_ARG_PARAMETERS = ('x', 'y') + class Meta: + target = MyClass + arg_parameters = ('x', 'y') x = 1 y = 2 @@ -251,7 +261,8 @@ Calling a :class:`~factory.Factory` subclass will provide an object through the .. code-block:: python class MyFactory(factory.Factory): - FACTORY_FOR = MyClass + class Meta: + target = MyClass .. code-block:: pycon @@ -265,6 +276,6 @@ Calling a :class:`~factory.Factory` subclass will provide an object through the -The default strategy can be changed by setting the class-level :attr:`~factory.Factory.FACTORY_STRATEGY` attribute. +The default strategy can be changed by setting the ``class Meta`` :attr:`~factory.FactoryOptions.strategy` attribute. diff --git a/docs/orms.rst b/docs/orms.rst index c893cac..5ef8568 100644 --- a/docs/orms.rst +++ b/docs/orms.rst @@ -32,7 +32,7 @@ All factories for a Django :class:`~django.db.models.Model` should use the This class provides the following features: - * The :attr:`~factory.Factory.FACTORY_FOR` attribute also supports the ``'app.Model'`` + * The :attr:`~factory.FactoryOption.target` attribute also supports the ``'app.Model'`` syntax * :func:`~factory.Factory.create()` uses :meth:`Model.objects.create() ` * :func:`~factory.Factory._setup_next_sequence()` selects the next unused primary key value @@ -40,7 +40,12 @@ All factories for a Django :class:`~django.db.models.Model` should use the attributes, the base object will be :meth:`saved ` once all post-generation hooks have run. - .. attribute:: FACTORY_DJANGO_GET_OR_CREATE + +.. class:: DjangoOptions(factory.base.FactoryOptions) + + The ``class Meta`` on a :class:`~DjangoModelFactory` supports an extra parameter: + + .. attribute:: django_get_or_create Fields whose name are passed in this list will be used to perform a :meth:`Model.objects.get_or_create() ` @@ -49,8 +54,9 @@ All factories for a Django :class:`~django.db.models.Model` should use the .. code-block:: python class UserFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = 'myapp.User' # Equivalent to ``FACTORY_FOR = myapp.models.User`` - FACTORY_DJANGO_GET_OR_CREATE = ('username',) + class Meta: + target = 'myapp.User' # Equivalent to ``target = myapp.models.User`` + django_get_or_create = ('username',) username = 'john' @@ -80,11 +86,13 @@ All factories for a Django :class:`~django.db.models.Model` should use the .. code-block:: python class MyAbstractModelFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = models.MyAbstractModel - ABSTRACT_FACTORY = True + class Meta: + target = models.MyAbstractModel + abstract = True class MyConcreteModelFactory(MyAbstractModelFactory): - FACTORY_FOR = models.MyConcreteModel + class Meta: + target = models.MyConcreteModel Otherwise, factory_boy will try to get the 'next PK' counter from the abstract model. @@ -112,7 +120,8 @@ Extra fields .. code-block:: python class MyFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = models.MyModel + class Meta: + target = models.MyModel the_file = factory.django.FileField(filename='the_file.dat') @@ -149,7 +158,8 @@ Extra fields .. code-block:: python class MyFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = models.MyModel + class Meta: + target = models.MyModel the_image = factory.django.ImageField(color='blue') @@ -188,7 +198,8 @@ To work around this problem, use the :meth:`mute_signals()` decorator/context ma @factory.django.mute_signals(signals.pre_save, signals.post_save) class FooFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = models.Foo + class Meta: + target = models.Foo # ... @@ -241,7 +252,7 @@ factory_boy supports `MongoEngine`_-style models, through the :class:`MongoEngin * :func:`~factory.Factory.create()` builds an instance through ``__init__`` then saves it. - .. note:: If the :attr:`associated class ` is a :class:`mongoengine.EmbeddedDocument`, + .. note:: If the :attr:`associated class ` is a :class:`mongoengine.EmbeddedDocument`, the :meth:`~MongoEngineFactory.create` function won't "save" it, since this wouldn't make sense. This feature makes it possible to use :class:`~factory.SubFactory` to create embedded document. @@ -255,7 +266,7 @@ SQLAlchemy Factoy_boy also supports `SQLAlchemy`_ models through the :class:`SQLAlchemyModelFactory` class. -To work, this class needs an `SQLAlchemy`_ session object affected to "FACTORY_SESSION" class attribute. +To work, this class needs an `SQLAlchemy`_ session object affected to the ``Meta.sqlalchemy_session`` attribute. .. _SQLAlchemy: http://www.sqlalchemy.org/ @@ -268,7 +279,12 @@ To work, this class needs an `SQLAlchemy`_ session object affected to "FACTORY_S * :func:`~factory.Factory.create()` uses :meth:`sqlalchemy.orm.session.Session.add` * :func:`~factory.Factory._setup_next_sequence()` selects the next unused primary key value - .. attribute:: FACTORY_SESSION +.. class:: SQLAlchemyOptions(factory.base.FactoryOptions) + + In addition to the usual parameters available in :class:`class Meta `, + a :class:`SQLAlchemyModelFactory` also supports the following settings: + + .. attribute:: sqlalchemy_session Fields whose SQLAlchemy session object are passed will be used to communicate with the database @@ -297,8 +313,9 @@ A (very) simple exemple: class UserFactory(SQLAlchemyModelFactory): - FACTORY_FOR = User - FACTORY_SESSION = session # the SQLAlchemy session object + class Meta: + target = User + sqlalchemy_session = session # the SQLAlchemy session object id = factory.Sequence(lambda n: n) name = factory.Sequence(lambda n: u'User %d' % n) diff --git a/docs/recipes.rst b/docs/recipes.rst index 7a6bf23..917bc3c 100644 --- a/docs/recipes.rst +++ b/docs/recipes.rst @@ -26,7 +26,8 @@ use the :class:`~factory.SubFactory` declaration: from . import models class UserFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = models.User + class Meta: + target = models.User first_name = factory.Sequence(lambda n: "Agent %03d" % n) group = factory.SubFactory(GroupFactory) @@ -53,7 +54,8 @@ use a :class:`~factory.RelatedFactory` declaration: # factories.py class UserFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = models.User + class Meta: + target = models.User log = factory.RelatedFactory(UserLogFactory, 'user', action=models.UserLog.ACTION_CREATE) @@ -75,7 +77,8 @@ factory_boy allows to define attributes of such profiles dynamically when creati .. code-block:: python class ProfileFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = my_models.Profile + class Meta: + target = my_models.Profile title = 'Dr' # We pass in profile=None to prevent UserFactory from creating another profile @@ -83,7 +86,8 @@ factory_boy allows to define attributes of such profiles dynamically when creati user = factory.SubFactory('app.factories.UserFactory', profile=None) class UserFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = auth_models.User + class Meta: + target = auth_models.User username = factory.Sequence(lambda n: "user_%d" % n) @@ -145,12 +149,14 @@ hook: # factories.py class GroupFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = models.Group + class Meta: + target = models.Group name = factory.Sequence(lambda n: "Group #%s" % n) class UserFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = models.User + class Meta: + target = models.User name = "John Doe" @@ -200,17 +206,20 @@ If more links are needed, simply add more :class:`RelatedFactory` declarations: # factories.py class UserFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = models.User + class Meta: + target = models.User name = "John Doe" class GroupFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = models.Group + class Meta: + target = models.Group name = "Admins" class GroupLevelFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = models.GroupLevel + class Meta: + target = models.GroupLevel user = factory.SubFactory(UserFactory) group = factory.SubFactory(GroupFactory) @@ -273,20 +282,23 @@ Here, we want: # factories.py class CountryFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = models.Country + class Meta: + target = models.Country name = factory.Iterator(["France", "Italy", "Spain"]) lang = factory.Iterator(['fr', 'it', 'es']) class UserFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = models.User + class Meta: + target = models.User name = "John" lang = factory.SelfAttribute('country.lang') country = factory.SubFactory(CountryFactory) class CompanyFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = models.Company + class Meta: + target = models.Company name = "ACME, Inc." country = factory.SubFactory(CountryFactory) @@ -302,7 +314,9 @@ default :meth:`Model.objects.create() ` .. code-block:: python class UserFactory(factory.DjangoModelFactory): - FACTORY_FOR = UserenaSignup + class Meta: + target = UserenaSignup + username = "l7d8s" email = "my_name@example.com" password = "my_password" diff --git a/docs/reference.rst b/docs/reference.rst index 53584a0..f19b44e 100644 --- a/docs/reference.rst +++ b/docs/reference.rst @@ -11,37 +11,54 @@ For internals and customization points, please refer to the :doc:`internals` sec The :class:`Factory` class -------------------------- -.. class:: Factory +.. class:: FactoryOptions + + .. versionadded:: 2.4.0 + + A :class:`Factory`'s behaviour can be tuned through a few settings. + + For convenience, they are declared in a single ``class Meta`` attribute: - The :class:`Factory` class is the base of factory_boy features. + .. code-block:: python - It accepts a few specific attributes (must be specified on class declaration): + class MyFactory(factory.Factory): + class Meta: + target = MyObject + abstract = False - .. attribute:: FACTORY_FOR + .. attribute:: target This optional attribute describes the class of objects to generate. If unset, it will be inherited from parent :class:`Factory` subclasses. - .. attribute:: ABSTRACT_FACTORY + .. versionadded:: 2.4.0 + + .. attribute:: abstract This attribute indicates that the :class:`Factory` subclass should not be used to generate objects, but instead provides some extra defaults. It will be automatically set to ``True`` if neither the :class:`Factory` - subclass nor its parents define the :attr:`~Factory.FACTORY_FOR` attribute. + subclass nor its parents define the :attr:`~FactoryOptions.target` attribute. + + .. warning:: This flag is reset to ``False`` When a :class:`Factory` subclasses + another one if a :attr:`~FactoryOptions.target` is set. + + .. versionadded:: 2.4.0 - .. attribute:: FACTORY_ARG_PARAMETERS + .. attribute:: arg_parameters Some factories require non-keyword arguments to their :meth:`~object.__init__`. - They should be listed, in order, in the :attr:`FACTORY_ARG_PARAMETERS` + They should be listed, in order, in the :attr:`arg_parameters` attribute: .. code-block:: python class UserFactory(factory.Factory): - FACTORY_FOR = User - FACTORY_ARG_PARAMETERS = ('login', 'email') + class Meta: + target = User + arg_parameters = ('login', 'email') login = 'john' email = factory.LazyAttribute(lambda o: '%s@example.com' % o.login) @@ -53,22 +70,25 @@ The :class:`Factory` class >>> User('john', 'john@example.com', firstname="John") # actual call - .. attribute:: FACTORY_HIDDEN_ARGS + .. versionadded:: 2.4.0 + + .. attribute:: hidden_args While writing a :class:`Factory` for some object, it may be useful to have general fields helping defining others, but that should not be passed to the target class; for instance, a field named 'now' that would hold a reference time used by other objects. - Factory fields whose name are listed in :attr:`FACTORY_HIDDEN_ARGS` will + Factory fields whose name are listed in :attr:`hidden_args` will be removed from the set of args/kwargs passed to the underlying class; they can be any valid factory_boy declaration: .. code-block:: python class OrderFactory(factory.Factory): - FACTORY_FOR = Order - FACTORY_HIDDEN_ARGS = ('now',) + class Meta: + target = Order + hidden_args = ('now',) now = factory.LazyAttribute(lambda o: datetime.datetime.utcnow()) started_at = factory.LazyAttribute(lambda o: o.now - datetime.timedelta(hours=1)) @@ -83,6 +103,55 @@ The :class:`Factory` class >>> OrderFactory(now=datetime.datetime(2013, 4, 1, 10)) + .. versionadded:: 2.4.0 + + +.. class:: Factory + + .. note:: In previous versions, the fields of :class:`class Meta ` were + defined as class attributes on :class:`Factory`. This is now deprecated and will be removed + in 2.5.0. + + .. attribute:: FACTORY_FOR + + .. deprecated:: 2.4.0 + See :attr:`FactoryOptions.target`. + + .. attribute:: ABSTRACT_FACTORY + + .. deprecated:: 2.4.0 + See :attr:`FactoryOptions.abstract`. + + .. attribute:: FACTORY_ARG_PARAMETERS + + .. deprecated:: 2.4.0 + See :attr:`FactoryOptions.arg_parameters`. + + .. attribute:: FACTORY_HIDDEN_ARGS + + .. deprecated:: 2.4.0 + See :attr:`FactoryOptions.hidden_args`. + + + **Class-level attributes:** + + .. attribute:: _meta + + .. versionadded:: 2.4.0 + + The :class:`FactoryOptions` instance attached to a :class:`Factory` class is available + as a :attr:`_meta` attribute. + + .. attribute:: _options_class + + .. versionadded:: 2.4.0 + + If a :class:`Factory` subclass needs to define additional, extra options, it has to + provide a custom :class:`FactoryOptions` subclass. + + A pointer to that custom class should be provided as :attr:`_options_class` so that + the :class:`Factory`-building metaclass can use it instead. + **Base functions:** @@ -162,7 +231,7 @@ The :class:`Factory` class The :meth:`_adjust_kwargs` extension point allows for late fields tuning. It is called once keyword arguments have been resolved and post-generation - items removed, but before the :attr:`FACTORY_ARG_PARAMETERS` extraction + items removed, but before the :attr:`~FactoryOptions.arg_parameters` extraction phase. .. code-block:: python @@ -194,7 +263,7 @@ The :class:`Factory` class .. OHAI_VIM* This class method is called whenever a new instance needs to be built. - It receives the target class (provided to :attr:`FACTORY_FOR`), and + It receives the target class (provided to :attr:`~FactoryOptions.target`), and the positional and keyword arguments to use for the class once all has been computed. @@ -214,7 +283,8 @@ The :class:`Factory` class .. code-block:: python class BaseBackendFactory(factory.Factory): - ABSTRACT_FACTORY = True # Optional + class Meta: + abstract = True # Optional def _create(cls, target_class, *args, **kwargs): obj = target_class(*args, **kwargs) @@ -254,7 +324,7 @@ The :class:`Factory` class >>> SomeFactory._next_sequence 4 - Since subclasses of a non-:attr:`abstract ` + Since subclasses of a non-:attr:`abstract ` :class:`~factory.Factory` share the same sequence counter, special care needs to be taken when resetting the counter of such a subclass. @@ -293,7 +363,7 @@ factory_boy supports two main strategies for generating instances, plus stubs. but not persisted to any datastore. It is usually a simple call to the :meth:`~object.__init__` method of the - :attr:`~Factory.FACTORY_FOR` class. + :attr:`~FactoryOptions.target` class. .. data:: CREATE_STRATEGY @@ -316,7 +386,7 @@ factory_boy supports two main strategies for generating instances, plus stubs. when using the ``create`` strategy. That policy will be used if the - :attr:`associated class ` has an ``objects`` + :attr:`associated class ` has an ``objects`` attribute *and* the :meth:`~Factory._create` classmethod of the :class:`Factory` wasn't overridden. @@ -337,7 +407,7 @@ factory_boy supports two main strategies for generating instances, plus stubs. .. data:: STUB_STRATEGY The 'stub' strategy is an exception in the factory_boy world: it doesn't return - an instance of the :attr:`~Factory.FACTORY_FOR` class, and actually doesn't + an instance of the :attr:`~FactoryOptions.target` class, and actually doesn't require one to be present. Instead, it returns an instance of :class:`StubObject` whose attributes have been @@ -359,7 +429,7 @@ factory_boy supports two main strategies for generating instances, plus stubs. .. class:: StubFactory(Factory) - An :attr:`abstract ` :class:`Factory`, + An :attr:`abstract ` :class:`Factory`, with a default strategy set to :data:`STUB_STRATEGY`. @@ -414,7 +484,8 @@ accept the object being built as sole argument, and return a value. .. code-block:: python class UserFactory(factory.Factory): - FACTORY_FOR = User + class Meta: + target = User username = 'john' email = factory.LazyAttribute(lambda o: '%s@example.com' % o.username) @@ -449,7 +520,8 @@ return value of the method: .. code-block:: python class UserFactory(factory.Factory) - FACTORY_FOR = User + class Meta: + target = User name = u"Jean" @@ -487,7 +559,8 @@ This declaration takes a single argument, a function accepting a single paramete .. code-block:: python class UserFactory(factory.Factory) - FACTORY_FOR = User + class Meta: + target = User phone = factory.Sequence(lambda n: '123-555-%04d' % n) @@ -512,7 +585,8 @@ be the sequence counter - this might be confusing: .. code-block:: python class UserFactory(factory.Factory) - FACTORY_FOR = User + class Meta: + target = User @factory.sequence def phone(n): @@ -537,7 +611,8 @@ The sequence counter is shared across all :class:`Sequence` attributes of the .. code-block:: python class UserFactory(factory.Factory): - FACTORY_FOR = User + class Meta: + target = User phone = factory.Sequence(lambda n: '%04d' % n) office = factory.Sequence(lambda n: 'A23-B%03d' % n) @@ -561,7 +636,8 @@ sequence counter is shared: .. code-block:: python class UserFactory(factory.Factory): - FACTORY_FOR = User + class Meta: + target = User phone = factory.Sequence(lambda n: '123-555-%04d' % n) @@ -596,7 +672,8 @@ class-level value. .. code-block:: python class UserFactory(factory.Factory): - FACTORY_FOR = User + class Meta: + target = User uid = factory.Sequence(int) @@ -631,7 +708,8 @@ It takes a single argument, a function whose two parameters are, in order: .. code-block:: python class UserFactory(factory.Factory): - FACTORY_FOR = User + class Meta: + target = User login = 'john' email = factory.LazyAttributeSequence(lambda o, n: '%s@s%d.example.com' % (o.login, n)) @@ -655,7 +733,8 @@ handles more complex cases: .. code-block:: python class UserFactory(factory.Factory): - FACTORY_FOR = User + class Meta: + target = User login = 'john' @@ -692,7 +771,8 @@ The :class:`SubFactory` attribute should be called with: .. code-block:: python class FooFactory(factory.Factory): - FACTORY_FOR = Foo + class Meta: + target = Foo bar = factory.SubFactory(BarFactory) # Not BarFactory() @@ -705,7 +785,8 @@ Definition # A standard factory class UserFactory(factory.Factory): - FACTORY_FOR = User + class Meta: + target = User # Various fields first_name = 'John' @@ -714,7 +795,8 @@ Definition # A factory for an object with a 'User' field class CompanyFactory(factory.Factory): - FACTORY_FOR = Company + class Meta: + target = Company name = factory.Sequence(lambda n: 'FactoryBoyz' + 'z' * n) @@ -794,13 +876,15 @@ This issue can be handled by passing the absolute import path to the target .. code-block:: python class UserFactory(factory.Factory): - FACTORY_FOR = User + class Meta: + target = User username = 'john' main_group = factory.SubFactory('users.factories.GroupFactory') class GroupFactory(factory.Factory): - FACTORY_FOR = Group + class Meta: + target = Group name = "MyGroup" owner = factory.SubFactory(UserFactory) @@ -828,7 +912,8 @@ That declaration takes a single argument, a dot-delimited path to the attribute .. code-block:: python class UserFactory(factory.Factory) - FACTORY_FOR = User + class Meta: + target = User birthdate = factory.Sequence(lambda n: datetime.date(2000, 1, 1) + datetime.timedelta(days=n)) birthmonth = factory.SelfAttribute('birthdate.month') @@ -854,13 +939,15 @@ gains an "upward" semantic through the double-dot notation, as used in Python im .. code-block:: python class UserFactory(factory.Factory): - FACTORY_FOR = User + class Meta: + target = User language = 'en' class CompanyFactory(factory.Factory): - FACTORY_FOR = Company + class Meta: + target = Company country = factory.SubFactory(CountryFactory) owner = factory.SubFactory(UserFactory, language=factory.SelfAttribute('..country.language')) @@ -888,7 +975,8 @@ through the :attr:`~containers.LazyStub.factory_parent` attribute of the passed- .. code-block:: python class CompanyFactory(factory.Factory): - FACTORY_FOR = Company + class Meta: + target = Company country = factory.SubFactory(CountryFactory) owner = factory.SubFactory(UserFactory, language=factory.LazyAttribute(lambda user: user.factory_parent.country.language), @@ -966,7 +1054,8 @@ adequate value. .. code-block:: python class UserFactory(factory.Factory): - FACTORY_FOR = User + class Meta: + target = User # CATEGORY_CHOICES is a list of (key, title) tuples category = factory.Iterator(User.CATEGORY_CHOICES, getter=lambda c: c[0]) @@ -987,7 +1076,8 @@ use the :func:`iterator` decorator: .. code-block:: python class UserFactory(factory.Factory): - FACTORY_FOR = User + class Meta: + target = User @factory.iterator def name(): @@ -1030,7 +1120,8 @@ with the :class:`Dict` and :class:`List` attributes: .. code-block:: python class UserFactory(factory.Factory): - FACTORY_FOR = User + class Meta: + target = User is_superuser = False roles = factory.Dict({ @@ -1066,7 +1157,8 @@ with the :class:`Dict` and :class:`List` attributes: .. code-block:: python class UserFactory(factory.Factory): - FACTORY_FOR = User + class Meta: + target = User flags = factory.List([ 'user', @@ -1113,7 +1205,8 @@ For instance, a :class:`PostGeneration` hook is declared as ``post``: .. code-block:: python class SomeFactory(factory.Factory): - FACTORY_FOR = SomeObject + class Meta: + target = SomeObject @post_generation def post(self, create, extracted, **kwargs): @@ -1128,7 +1221,7 @@ When calling the factory, some arguments will be extracted for this method: - Any argument starting with ``post__XYZ`` will be extracted, its ``post__`` prefix removed, and added to the kwargs passed to the post-generation hook. -Extracted arguments won't be passed to the :attr:`~Factory.FACTORY_FOR` class. +Extracted arguments won't be passed to the :attr:`~FactoryOptions.target` class. Thus, in the following call: @@ -1142,7 +1235,7 @@ Thus, in the following call: ) The ``post`` hook will receive ``1`` as ``extracted`` and ``{'y': 3, 'z__t': 42}`` -as keyword arguments; ``{'post_x': 2}`` will be passed to ``SomeFactory.FACTORY_FOR``. +as keyword arguments; ``{'post_x': 2}`` will be passed to ``SomeFactory._meta.target``. RelatedFactory @@ -1184,7 +1277,8 @@ RelatedFactory .. code-block:: python class FooFactory(factory.Factory): - FACTORY_FOR = Foo + class Meta: + target = Foo bar = factory.RelatedFactory(BarFactory) # Not BarFactory() @@ -1192,13 +1286,15 @@ RelatedFactory .. code-block:: python class CityFactory(factory.Factory): - FACTORY_FOR = City + class Meta: + target = City capital_of = None name = "Toronto" class CountryFactory(factory.Factory): - FACTORY_FOR = Country + class Meta: + target = Country lang = 'fr' capital_city = factory.RelatedFactory(CityFactory, 'capital_of', name="Paris") @@ -1260,7 +1356,8 @@ as ``callable(obj, create, extracted, **kwargs)``, where: .. code-block:: python class UserFactory(factory.Factory): - FACTORY_FOR = User + class Meta: + target = User login = 'john' make_mbox = factory.PostGeneration( @@ -1280,7 +1377,8 @@ A decorator is also provided, decorating a single method accepting the same .. code-block:: python class UserFactory(factory.Factory): - FACTORY_FOR = User + class Meta: + target = User login = 'john' @@ -1316,7 +1414,7 @@ PostGenerationMethodCall .. attribute:: method_name - The name of the method to call on the :attr:`~Factory.FACTORY_FOR` object + The name of the method to call on the :attr:`~FactoryOptions.target` object .. attribute:: args @@ -1340,7 +1438,8 @@ attribute like below: .. code-block:: python class UserFactory(factory.Factory): - FACTORY_FOR = User + class Meta: + target = User username = 'user' password = factory.PostGenerationMethodCall('set_password', @@ -1390,7 +1489,8 @@ factory during instantiation. .. code-block:: python class UserFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = User + class Meta: + target = User username = 'user' password = factory.PostGenerationMethodCall('set_password', @@ -1404,7 +1504,8 @@ example, if we declared the ``password`` attribute like the following, .. code-block:: python class UserFactory(factory.Factory): - FACTORY_FOR = User + class Meta: + target = User username = 'user' password = factory.PostGenerationMethodCall('set_password', '', 'sha1') @@ -1467,7 +1568,8 @@ Lightweight factory declaration # This is equivalent to: class UserFactory(factory.Factory): - FACTORY_FOR = User + class Meta: + target = User login = 'john' email = factory.LazyAttribute(lambda u: '%s@example.com' % u.login) @@ -1486,7 +1588,8 @@ Lightweight factory declaration # This is equivalent to: class UserFactory(factory.django.DjangoModelFactory): - FACTORY_FOR = models.User + class Meta: + target = models.User login = 'john' email = factory.LazyAttribute(lambda u: '%s@example.com' % u.login) -- cgit v1.2.3 From 3a5709527d362a960a1a35769375412e4536839e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Sun, 18 May 2014 15:10:56 +0200 Subject: Rename 'target' to 'model'. --- README.rst | 12 +-- docs/examples.rst | 4 +- docs/introduction.rst | 24 ++--- docs/orms.rst | 18 ++-- docs/recipes.rst | 30 +++--- docs/reference.rst | 106 ++++++++++---------- factory/alchemy.py | 6 +- factory/base.py | 76 +++++++------- factory/containers.py | 14 +-- factory/declarations.py | 4 +- factory/django.py | 28 +++--- factory/helpers.py | 2 +- factory/mogo.py | 8 +- factory/mongoengine.py | 8 +- tests/cyclic/bar.py | 2 +- tests/cyclic/foo.py | 2 +- tests/test_alchemy.py | 4 +- tests/test_base.py | 56 +++++------ tests/test_containers.py | 2 +- tests/test_deprecation.py | 2 +- tests/test_django.py | 40 ++++---- tests/test_mongoengine.py | 4 +- tests/test_using.py | 246 +++++++++++++++++++++++----------------------- 23 files changed, 349 insertions(+), 349 deletions(-) diff --git a/README.rst b/README.rst index 787d754..b4ba689 100644 --- a/README.rst +++ b/README.rst @@ -95,7 +95,7 @@ Defining factories """""""""""""""""" Factories declare a set of attributes used to instantiate an object. -The class of the object must be defined in the ``target`` field of a ``class Meta:`` attribute: +The class of the object must be defined in the ``model`` field of a ``class Meta:`` attribute: .. code-block:: python @@ -104,7 +104,7 @@ The class of the object must be defined in the ``target`` field of a ``class Met class UserFactory(factory.Factory): class Meta: - target = models.User + model = models.User first_name = 'John' last_name = 'Doe' @@ -113,7 +113,7 @@ The class of the object must be defined in the ``target`` field of a ``class Met # Another, different, factory for the same object class AdminFactory(factory.Factory): class Meta: - target = models.User + model = models.User first_name = 'Admin' last_name = 'User' @@ -168,7 +168,7 @@ These "lazy" attributes can be added as follows: class UserFactory(factory.Factory): class Meta: - target = models.User + model = models.User first_name = 'Joe' last_name = 'Blow' @@ -189,7 +189,7 @@ Unique values in a specific format (for example, e-mail addresses) can be genera class UserFactory(factory.Factory): class Meta: - target = models.User + model = models.User email = factory.Sequence(lambda n: 'person{0}@example.com'.format(n)) @@ -209,7 +209,7 @@ This is handled by the ``SubFactory`` helper: class PostFactory(factory.Factory): class Meta: - target = models.Post + model = models.Post author = factory.SubFactory(UserFactory) diff --git a/docs/examples.rst b/docs/examples.rst index 52a5ef6..a57080e 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -57,7 +57,7 @@ And now, we'll define the related factories: class AccountFactory(factory.Factory): class Meta: - target = objects.Account + model = objects.Account username = factory.Sequence(lambda n: 'john%s' % n) email = factory.LazyAttribute(lambda o: '%s@example.org' % o.username) @@ -65,7 +65,7 @@ And now, we'll define the related factories: class ProfileFactory(factory.Factory): class Meta: - target = objects.Profile + model = objects.Profile account = factory.SubFactory(AccountFactory) gender = factory.Iterator([objects.Profile.GENDER_MALE, objects.Profile.GENDER_FEMALE]) diff --git a/docs/introduction.rst b/docs/introduction.rst index 6ea6b5e..5e3b4d8 100644 --- a/docs/introduction.rst +++ b/docs/introduction.rst @@ -18,11 +18,11 @@ Basic usage ----------- -Factories declare a set of attributes used to instantiate an object, whose class is defined in the ``class Meta``'s ``target`` attribute: +Factories declare a set of attributes used to instantiate an object, whose class is defined in the ``class Meta``'s ``model`` attribute: - Subclass ``factory.Factory`` (or a more suitable subclass) - Add a ``class Meta:`` block -- Set its ``target`` attribute to the target class +- Set its ``model`` attribute to the target class - Add defaults for keyword args to pass to the associated class' ``__init__`` method @@ -33,7 +33,7 @@ Factories declare a set of attributes used to instantiate an object, whose class class UserFactory(factory.Factory): class Meta: - target = base.User + model = base.User firstname = "John" lastname = "Doe" @@ -59,7 +59,7 @@ A given class may be associated to many :class:`~factory.Factory` subclasses: class EnglishUserFactory(factory.Factory): class Meta: - target = base.User + model = base.User firstname = "John" lastname = "Doe" @@ -68,7 +68,7 @@ A given class may be associated to many :class:`~factory.Factory` subclasses: class FrenchUserFactory(factory.Factory): class Meta: - target = base.User + model = base.User firstname = "Jean" lastname = "Dupont" @@ -93,7 +93,7 @@ This is achieved with the :class:`~factory.Sequence` declaration: class UserFactory(factory.Factory): class Meta: - target = models.User + model = models.User username = factory.Sequence(lambda n: 'user%d' % n) @@ -110,7 +110,7 @@ This is achieved with the :class:`~factory.Sequence` declaration: class UserFactory(factory.Factory): class Meta: - target = models.User + model = models.User @factory.sequence def username(n): @@ -128,7 +128,7 @@ taking the object being built and returning the value for the field: class UserFactory(factory.Factory): class Meta: - target = models.User + model = models.User username = factory.Sequence(lambda n: 'user%d' % n) email = factory.LazyAttribute(lambda obj: '%s@example.com' % obj.username) @@ -154,7 +154,7 @@ taking the object being built and returning the value for the field: class UserFactory(factory.Factory): class Meta: - target = models.User + model = models.User username = factory.Sequence(lambda n: 'user%d' % n) @@ -177,7 +177,7 @@ and update them with its own declarations: class UserFactory(factory.Factory): class Meta: - target = base.User + model = base.User firstname = "John" lastname = "Doe" @@ -224,7 +224,7 @@ This is handled by the :data:`~factory.FactoryOptions.arg_parameters` attribute: class MyFactory(factory.Factory): class Meta: - target = MyClass + model = MyClass arg_parameters = ('x', 'y') x = 1 @@ -262,7 +262,7 @@ Calling a :class:`~factory.Factory` subclass will provide an object through the class MyFactory(factory.Factory): class Meta: - target = MyClass + model = MyClass .. code-block:: pycon diff --git a/docs/orms.rst b/docs/orms.rst index 5ef8568..d3d98c9 100644 --- a/docs/orms.rst +++ b/docs/orms.rst @@ -32,7 +32,7 @@ All factories for a Django :class:`~django.db.models.Model` should use the This class provides the following features: - * The :attr:`~factory.FactoryOption.target` attribute also supports the ``'app.Model'`` + * The :attr:`~factory.FactoryOptions.model` attribute also supports the ``'app.Model'`` syntax * :func:`~factory.Factory.create()` uses :meth:`Model.objects.create() ` * :func:`~factory.Factory._setup_next_sequence()` selects the next unused primary key value @@ -55,7 +55,7 @@ All factories for a Django :class:`~django.db.models.Model` should use the class UserFactory(factory.django.DjangoModelFactory): class Meta: - target = 'myapp.User' # Equivalent to ``target = myapp.models.User`` + model = 'myapp.User' # Equivalent to ``model = myapp.models.User`` django_get_or_create = ('username',) username = 'john' @@ -87,12 +87,12 @@ All factories for a Django :class:`~django.db.models.Model` should use the class MyAbstractModelFactory(factory.django.DjangoModelFactory): class Meta: - target = models.MyAbstractModel + model = models.MyAbstractModel abstract = True class MyConcreteModelFactory(MyAbstractModelFactory): class Meta: - target = models.MyConcreteModel + model = models.MyConcreteModel Otherwise, factory_boy will try to get the 'next PK' counter from the abstract model. @@ -121,7 +121,7 @@ Extra fields class MyFactory(factory.django.DjangoModelFactory): class Meta: - target = models.MyModel + model = models.MyModel the_file = factory.django.FileField(filename='the_file.dat') @@ -159,7 +159,7 @@ Extra fields class MyFactory(factory.django.DjangoModelFactory): class Meta: - target = models.MyModel + model = models.MyModel the_image = factory.django.ImageField(color='blue') @@ -199,7 +199,7 @@ To work around this problem, use the :meth:`mute_signals()` decorator/context ma @factory.django.mute_signals(signals.pre_save, signals.post_save) class FooFactory(factory.django.DjangoModelFactory): class Meta: - target = models.Foo + model = models.Foo # ... @@ -252,7 +252,7 @@ factory_boy supports `MongoEngine`_-style models, through the :class:`MongoEngin * :func:`~factory.Factory.create()` builds an instance through ``__init__`` then saves it. - .. note:: If the :attr:`associated class ` is a :class:`mongoengine.EmbeddedDocument`, + .. note:: If the :attr:`associated class ` class UserFactory(factory.DjangoModelFactory): class Meta: - target = UserenaSignup + model = UserenaSignup username = "l7d8s" email = "my_name@example.com" password = "my_password" @classmethod - def _create(cls, target_class, *args, **kwargs): + def _create(cls, model_class, *args, **kwargs): """Override the default ``_create`` with our custom call.""" - manager = cls._get_manager(target_class) + manager = cls._get_manager(model_class) # The default would use ``manager.create(*args, **kwargs)`` return manager.create_user(*args, **kwargs) diff --git a/docs/reference.rst b/docs/reference.rst index f19b44e..d616d1c 100644 --- a/docs/reference.rst +++ b/docs/reference.rst @@ -23,10 +23,10 @@ The :class:`Factory` class class MyFactory(factory.Factory): class Meta: - target = MyObject + model = MyObject abstract = False - .. attribute:: target + .. attribute:: model This optional attribute describes the class of objects to generate. @@ -40,10 +40,10 @@ The :class:`Factory` class be used to generate objects, but instead provides some extra defaults. It will be automatically set to ``True`` if neither the :class:`Factory` - subclass nor its parents define the :attr:`~FactoryOptions.target` attribute. + subclass nor its parents define the :attr:`~FactoryOptions.model` attribute. .. warning:: This flag is reset to ``False`` When a :class:`Factory` subclasses - another one if a :attr:`~FactoryOptions.target` is set. + another one if a :attr:`~FactoryOptions.model` is set. .. versionadded:: 2.4.0 @@ -57,7 +57,7 @@ The :class:`Factory` class class UserFactory(factory.Factory): class Meta: - target = User + model = User arg_parameters = ('login', 'email') login = 'john' @@ -76,7 +76,7 @@ The :class:`Factory` class While writing a :class:`Factory` for some object, it may be useful to have general fields helping defining others, but that should not be - passed to the target class; for instance, a field named 'now' that would + passed to the model class; for instance, a field named 'now' that would hold a reference time used by other objects. Factory fields whose name are listed in :attr:`hidden_args` will @@ -87,7 +87,7 @@ The :class:`Factory` class class OrderFactory(factory.Factory): class Meta: - target = Order + model = Order hidden_args = ('now',) now = factory.LazyAttribute(lambda o: datetime.datetime.utcnow()) @@ -115,7 +115,7 @@ The :class:`Factory` class .. attribute:: FACTORY_FOR .. deprecated:: 2.4.0 - See :attr:`FactoryOptions.target`. + See :attr:`FactoryOptions.model`. .. attribute:: ABSTRACT_FACTORY @@ -258,19 +258,19 @@ The :class:`Factory` class Subclasses may fetch the next free ID from the database, for instance. - .. classmethod:: _build(cls, target_class, *args, **kwargs) + .. classmethod:: _build(cls, model_class, *args, **kwargs) .. OHAI_VIM* This class method is called whenever a new instance needs to be built. - It receives the target class (provided to :attr:`~FactoryOptions.target`), and + It receives the model class (provided to :attr:`~FactoryOptions.model`), and the positional and keyword arguments to use for the class once all has been computed. Subclasses may override this for custom APIs. - .. classmethod:: _create(cls, target_class, *args, **kwargs) + .. classmethod:: _create(cls, model_class, *args, **kwargs) .. OHAI_VIM* @@ -286,8 +286,8 @@ The :class:`Factory` class class Meta: abstract = True # Optional - def _create(cls, target_class, *args, **kwargs): - obj = target_class(*args, **kwargs) + def _create(cls, model_class, *args, **kwargs): + obj = model_class(*args, **kwargs) obj.save() return obj @@ -363,7 +363,7 @@ factory_boy supports two main strategies for generating instances, plus stubs. but not persisted to any datastore. It is usually a simple call to the :meth:`~object.__init__` method of the - :attr:`~FactoryOptions.target` class. + :attr:`~FactoryOptions.model` class. .. data:: CREATE_STRATEGY @@ -386,7 +386,7 @@ factory_boy supports two main strategies for generating instances, plus stubs. when using the ``create`` strategy. That policy will be used if the - :attr:`associated class ` has an ``objects`` + :attr:`associated class ' % cls.__name__ else: - return '<%s for %s>' % (cls.__name__, cls._meta.target) + return '<%s for %s>' % (cls.__name__, cls._meta.model) class BaseMeta: @@ -189,7 +189,7 @@ class FactoryOptions(object): to update() its return value. """ return [ - OptionDefault('target', None, inherit=True), + OptionDefault('model', None, inherit=True), OptionDefault('abstract', False, inherit=False), OptionDefault('strategy', CREATE_STRATEGY, inherit=True), OptionDefault('arg_parameters', (), inherit=True), @@ -225,8 +225,8 @@ class FactoryOptions(object): self._fill_from_meta(meta=meta, base_meta=base_meta) - self.target = self.factory._load_target_class(self.target) - if self.target is None: + self.model = self.factory._load_model_class(self.model) + if self.model is None: self.abstract = True self.counter_reference = self._get_counter_reference() @@ -246,10 +246,10 @@ class FactoryOptions(object): def _get_counter_reference(self): """Identify which factory should be used for a shared counter.""" - if (self.target is not None + if (self.model is not None and self.base_factory is not None - and self.base_factory._meta.target is not None - and issubclass(self.target, self.base_factory._meta.target)): + and self.base_factory._meta.model is not None + and issubclass(self.model, self.base_factory._meta.model)): return self.base_factory else: return self.factory @@ -323,7 +323,7 @@ class BaseFactory(object): _meta = FactoryOptions() _OLDSTYLE_ATTRIBUTES = { - 'FACTORY_FOR': 'target', + 'FACTORY_FOR': 'model', 'ABSTRACT_FACTORY': 'abstract', 'FACTORY_STRATEGY': 'strategy', 'FACTORY_ARG_PARAMETERS': 'arg_parameters', @@ -444,8 +444,8 @@ class BaseFactory(object): return kwargs @classmethod - def _load_target_class(cls, class_definition): - """Extension point for loading target classes. + def _load_model_class(cls, class_definition): + """Extension point for loading model classes. This can be overridden in framework-specific subclasses to hook into existing model repositories, for instance. @@ -453,10 +453,10 @@ class BaseFactory(object): return class_definition @classmethod - def _get_target_class(cls): - """Retrieve the actual, associated target class.""" - definition = cls._meta.target - return cls._load_target_class(definition) + def _get_model_class(cls): + """Retrieve the actual, associated model class.""" + definition = cls._meta.model + return cls._load_model_class(definition) @classmethod def _prepare(cls, create, **kwargs): @@ -466,7 +466,7 @@ class BaseFactory(object): create: bool, whether to create or to build the object **kwargs: arguments to pass to the creation function """ - target_class = cls._get_target_class() + model_class = cls._get_model_class() kwargs = cls._adjust_kwargs(**kwargs) # Remove 'hidden' arguments. @@ -482,9 +482,9 @@ class BaseFactory(object): utils.log_pprint(args, kwargs), ) if create: - return cls._create(target_class, *args, **kwargs) + return cls._create(model_class, *args, **kwargs) else: - return cls._build(target_class, *args, **kwargs) + return cls._build(model_class, *args, **kwargs) @classmethod def _generate(cls, create, attrs): @@ -497,7 +497,7 @@ class BaseFactory(object): if cls._meta.abstract: raise FactoryError( "Cannot generate instances of abstract factory %(f)s; " - "Ensure %(f)s.Meta.target is set and %(f)s.Meta.abstract " + "Ensure %(f)s.Meta.model is set and %(f)s.Meta.abstract " "is either not set or False." % dict(f=cls.__name__)) # Extract declarations used for post-generation @@ -531,34 +531,34 @@ class BaseFactory(object): pass @classmethod - def _build(cls, target_class, *args, **kwargs): - """Actually build an instance of the target_class. + def _build(cls, model_class, *args, **kwargs): + """Actually build an instance of the model_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 + model_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) + return model_class(*args, **kwargs) @classmethod - def _create(cls, target_class, *args, **kwargs): - """Actually create an instance of the target_class. + def _create(cls, model_class, *args, **kwargs): + """Actually create an instance of the model_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 + model_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) + return model_class(*args, **kwargs) @classmethod def build(cls, **kwargs): @@ -705,7 +705,7 @@ class StubFactory(Factory): class Meta: strategy = STUB_STRATEGY - target = containers.StubObject + model = containers.StubObject @classmethod def build(cls, **kwargs): @@ -722,20 +722,20 @@ class BaseDictFactory(Factory): abstract = True @classmethod - def _build(cls, target_class, *args, **kwargs): + def _build(cls, model_class, *args, **kwargs): if args: raise ValueError( "DictFactory %r does not support Meta.arg_parameters.", cls) - return target_class(**kwargs) + return model_class(**kwargs) @classmethod - def _create(cls, target_class, *args, **kwargs): - return cls._build(target_class, *args, **kwargs) + def _create(cls, model_class, *args, **kwargs): + return cls._build(model_class, *args, **kwargs) class DictFactory(BaseDictFactory): class Meta: - target = dict + model = dict class BaseListFactory(Factory): @@ -744,22 +744,22 @@ class BaseListFactory(Factory): abstract = True @classmethod - def _build(cls, target_class, *args, **kwargs): + def _build(cls, model_class, *args, **kwargs): if args: raise ValueError( "ListFactory %r does not support Meta.arg_parameters.", cls) values = [v for k, v in sorted(kwargs.items())] - return target_class(values) + return model_class(values) @classmethod - def _create(cls, target_class, *args, **kwargs): - return cls._build(target_class, *args, **kwargs) + def _create(cls, model_class, *args, **kwargs): + return cls._build(model_class, *args, **kwargs) class ListFactory(BaseListFactory): class Meta: - target = list + model = list def use_strategy(new_strategy): diff --git a/factory/containers.py b/factory/containers.py index c0c5e24..5116320 100644 --- a/factory/containers.py +++ b/factory/containers.py @@ -47,27 +47,27 @@ class LazyStub(object): __containers (LazyStub list): "parents" of the LazyStub being built. This allows to have the field of a field depend on the value of another field - __target_class (type): the target class to build. + __model_class (type): the model class to build. """ __initialized = False - def __init__(self, attrs, containers=(), target_class=object, log_ctx=None): + def __init__(self, attrs, containers=(), model_class=object, log_ctx=None): self.__attrs = attrs self.__values = {} self.__pending = [] self.__containers = containers - self.__target_class = target_class - self.__log_ctx = log_ctx or '%s.%s' % (target_class.__module__, target_class.__name__) + self.__model_class = model_class + self.__log_ctx = log_ctx or '%s.%s' % (model_class.__module__, model_class.__name__) self.factory_parent = containers[0] if containers else None self.__initialized = True def __repr__(self): - return '' % (self.__target_class.__module__, self.__target_class.__name__) + return '' % (self.__model_class.__module__, self.__model_class.__name__) def __str__(self): return '' % ( - self.__target_class.__name__, list(self.__attrs.keys())) + self.__model_class.__name__, list(self.__attrs.keys())) def __fill__(self): """Fill this LazyStub, computing values of all defined attributes. @@ -224,7 +224,7 @@ class AttributeBuilder(object): wrapped_attrs[k] = v stub = LazyStub(wrapped_attrs, containers=self._containers, - target_class=self.factory, log_ctx=self._log_ctx) + model_class=self.factory, log_ctx=self._log_ctx) return stub.__fill__() diff --git a/factory/declarations.py b/factory/declarations.py index 037a679..5e7e734 100644 --- a/factory/declarations.py +++ b/factory/declarations.py @@ -50,7 +50,7 @@ class OrderedDeclaration(object): attributes containers (list of containers.LazyStub): The chain of SubFactory which led to building this object. - create (bool): whether the target class should be 'built' or + create (bool): whether the model class should be 'built' or 'created' extra (DeclarationDict or None): extracted key/value extracted from the attribute prefix @@ -434,7 +434,7 @@ class ExtractionContext(object): class PostGenerationDeclaration(object): - """Declarations to be called once the target object has been generated.""" + """Declarations to be called once the model object has been generated.""" def extract(self, name, attrs): """Extract relevant attributes from a dict. diff --git a/factory/django.py b/factory/django.py index 77afd8c..6090145 100644 --- a/factory/django.py +++ b/factory/django.py @@ -61,10 +61,10 @@ class DjangoOptions(base.FactoryOptions): def _get_counter_reference(self): counter_reference = super(DjangoOptions, self)._get_counter_reference() if (counter_reference == self.base_factory - and self.base_factory._meta.target is not None - and self.base_factory._meta.target._meta.abstract - and self.target is not None - and not self.target._meta.abstract): + and self.base_factory._meta.model is not None + and self.base_factory._meta.model._meta.abstract + and self.model is not None + and not self.model._meta.abstract): # Target factory is for an abstract model, yet we're for another, # concrete subclass => don't reuse the counter. return self.factory @@ -90,7 +90,7 @@ class DjangoModelFactory(base.Factory): }) @classmethod - def _load_target_class(cls, definition): + def _load_model_class(cls, definition): if is_string(definition) and '.' in definition: app, model = definition.split('.', 1) @@ -100,17 +100,17 @@ class DjangoModelFactory(base.Factory): return definition @classmethod - def _get_manager(cls, target_class): + def _get_manager(cls, model_class): try: - return target_class._default_manager # pylint: disable=W0212 + return model_class._default_manager # pylint: disable=W0212 except AttributeError: - return target_class.objects + return model_class.objects @classmethod def _setup_next_sequence(cls): """Compute the next available PK, based on the 'pk' database field.""" - model = cls._get_target_class() # pylint: disable=E1101 + model = cls._get_model_class() # pylint: disable=E1101 manager = cls._get_manager(model) try: @@ -122,9 +122,9 @@ class DjangoModelFactory(base.Factory): return 1 @classmethod - def _get_or_create(cls, target_class, *args, **kwargs): + def _get_or_create(cls, model_class, *args, **kwargs): """Create an instance of the model through objects.get_or_create.""" - manager = cls._get_manager(target_class) + manager = cls._get_manager(model_class) assert 'defaults' not in cls._meta.django_get_or_create, ( "'defaults' is a reserved keyword for get_or_create " @@ -140,12 +140,12 @@ class DjangoModelFactory(base.Factory): return obj @classmethod - def _create(cls, target_class, *args, **kwargs): + def _create(cls, model_class, *args, **kwargs): """Create an instance of the model, and save it to the database.""" - manager = cls._get_manager(target_class) + manager = cls._get_manager(model_class) if cls._meta.django_get_or_create: - return cls._get_or_create(target_class, *args, **kwargs) + return cls._get_or_create(model_class, *args, **kwargs) return manager.create(*args, **kwargs) diff --git a/factory/helpers.py b/factory/helpers.py index 0c387d0..19431df 100644 --- a/factory/helpers.py +++ b/factory/helpers.py @@ -51,7 +51,7 @@ def make_factory(klass, **kwargs): """Create a new, simple factory for the given class.""" factory_name = '%sFactory' % klass.__name__ class Meta: - target = klass + model = klass kwargs['Meta'] = Meta base_class = kwargs.pop('FACTORY_CLASS', base.Factory) diff --git a/factory/mogo.py b/factory/mogo.py index 0214119..5541043 100644 --- a/factory/mogo.py +++ b/factory/mogo.py @@ -36,11 +36,11 @@ class MogoFactory(base.Factory): abstract = True @classmethod - def _build(cls, target_class, *args, **kwargs): - return target_class.new(*args, **kwargs) + def _build(cls, model_class, *args, **kwargs): + return model_class.new(*args, **kwargs) @classmethod - def _create(cls, target_class, *args, **kwargs): - instance = target_class.new(*args, **kwargs) + def _create(cls, model_class, *args, **kwargs): + instance = model_class.new(*args, **kwargs) instance.save() return instance diff --git a/factory/mongoengine.py b/factory/mongoengine.py index 729ebb1..e3ab99c 100644 --- a/factory/mongoengine.py +++ b/factory/mongoengine.py @@ -37,12 +37,12 @@ class MongoEngineFactory(base.Factory): abstract = True @classmethod - def _build(cls, target_class, *args, **kwargs): - return target_class(*args, **kwargs) + def _build(cls, model_class, *args, **kwargs): + return model_class(*args, **kwargs) @classmethod - def _create(cls, target_class, *args, **kwargs): - instance = target_class(*args, **kwargs) + def _create(cls, model_class, *args, **kwargs): + instance = model_class(*args, **kwargs) if instance._is_document: instance.save() return instance diff --git a/tests/cyclic/bar.py b/tests/cyclic/bar.py index 8674c4d..a5e6bf1 100644 --- a/tests/cyclic/bar.py +++ b/tests/cyclic/bar.py @@ -31,7 +31,7 @@ class Bar(object): class BarFactory(factory.Factory): class Meta: - target = Bar + model = Bar y = 13 foo = factory.SubFactory('cyclic.foo.FooFactory') diff --git a/tests/cyclic/foo.py b/tests/cyclic/foo.py index 5310b1e..18de362 100644 --- a/tests/cyclic/foo.py +++ b/tests/cyclic/foo.py @@ -33,7 +33,7 @@ class Foo(object): class FooFactory(factory.Factory): class Meta: - target = Foo + model = Foo x = 42 bar = factory.SubFactory(bar_mod.BarFactory) diff --git a/tests/test_alchemy.py b/tests/test_alchemy.py index 4526ad1..b9222eb 100644 --- a/tests/test_alchemy.py +++ b/tests/test_alchemy.py @@ -48,7 +48,7 @@ else: class StandardFactory(SQLAlchemyModelFactory): class Meta: - target = models.StandardModel + model = models.StandardModel sqlalchemy_session = models.session id = factory.Sequence(lambda n: n) @@ -57,7 +57,7 @@ class StandardFactory(SQLAlchemyModelFactory): class NonIntegerPkFactory(SQLAlchemyModelFactory): class Meta: - target = models.NonIntegerPk + model = models.NonIntegerPk sqlalchemy_session = models.session id = factory.Sequence(lambda n: 'foo%d' % n) diff --git a/tests/test_base.py b/tests/test_base.py index c44ebd5..d93bf29 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -53,8 +53,8 @@ class FakeModelFactory(base.Factory): abstract = True @classmethod - def _create(cls, target_class, *args, **kwargs): - return target_class.create(**kwargs) + def _create(cls, model_class, *args, **kwargs): + return model_class.create(**kwargs) class TestModel(FakeDjangoModel): @@ -68,13 +68,13 @@ class SafetyTestCase(unittest.TestCase): class AbstractFactoryTestCase(unittest.TestCase): def test_factory_for_optional(self): - """Ensure that target= is optional for abstract=True.""" + """Ensure that model= is optional for abstract=True.""" class TestObjectFactory(base.Factory): class Meta: abstract = True self.assertTrue(TestObjectFactory._meta.abstract) - self.assertIsNone(TestObjectFactory._meta.target) + self.assertIsNone(TestObjectFactory._meta.model) def test_factory_for_and_abstract_factory_optional(self): """Ensure that Meta.abstract is optional.""" @@ -82,7 +82,7 @@ class AbstractFactoryTestCase(unittest.TestCase): pass self.assertTrue(TestObjectFactory._meta.abstract) - self.assertIsNone(TestObjectFactory._meta.target) + self.assertIsNone(TestObjectFactory._meta.model) def test_abstract_factory_cannot_be_called(self): class TestObjectFactory(base.Factory): @@ -97,18 +97,18 @@ class AbstractFactoryTestCase(unittest.TestCase): class TestObjectFactory(base.Factory): class Meta: abstract = True - target = TestObject + model = TestObject class TestObjectChildFactory(TestObjectFactory): pass self.assertFalse(TestObjectChildFactory._meta.abstract) - def test_abstract_or_target_is_required(self): + def test_abstract_or_model_is_required(self): class TestObjectFactory(base.Factory): class Meta: abstract = False - target = None + model = None self.assertRaises(base.FactoryError, TestObjectFactory.build) self.assertRaises(base.FactoryError, TestObjectFactory.create) @@ -121,7 +121,7 @@ class OptionsTests(unittest.TestCase): # Declarative attributes self.assertTrue(AbstractFactory._meta.abstract) - self.assertIsNone(AbstractFactory._meta.target) + self.assertIsNone(AbstractFactory._meta.model) self.assertEqual((), AbstractFactory._meta.arg_parameters) self.assertEqual((), AbstractFactory._meta.hidden_args) self.assertEqual(base.CREATE_STRATEGY, AbstractFactory._meta.strategy) @@ -206,7 +206,7 @@ class DeclarationParsingTests(unittest.TestCase): def test_classmethod(self): class TestObjectFactory(base.Factory): class Meta: - target = TestObject + model = TestObject @classmethod def some_classmethod(cls): @@ -222,16 +222,16 @@ class FactoryTestCase(unittest.TestCase): """Calling a FooFactory doesn't yield a FooFactory instance.""" class TestObjectFactory(base.Factory): class Meta: - target = TestObject + model = TestObject - self.assertEqual(TestObject, TestObjectFactory._meta.target) + self.assertEqual(TestObject, TestObjectFactory._meta.model) obj = TestObjectFactory.build() self.assertFalse(hasattr(obj, '_meta')) def test_display(self): class TestObjectFactory(base.Factory): class Meta: - target = FakeDjangoModel + model = FakeDjangoModel self.assertIn('TestObjectFactory', str(TestObjectFactory)) self.assertIn('FakeDjangoModel', str(TestObjectFactory)) @@ -239,7 +239,7 @@ class FactoryTestCase(unittest.TestCase): def test_lazy_attribute_non_existent_param(self): class TestObjectFactory(base.Factory): class Meta: - target = TestObject + model = TestObject one = declarations.LazyAttribute(lambda a: a.does_not_exist ) @@ -249,13 +249,13 @@ class FactoryTestCase(unittest.TestCase): """Tests that sequence IDs are shared between parent and son.""" class TestObjectFactory(base.Factory): class Meta: - target = TestObject + model = TestObject one = declarations.Sequence(lambda a: a) class TestSubFactory(TestObjectFactory): class Meta: - target = TestObject + model = TestObject pass @@ -273,7 +273,7 @@ class FactorySequenceTestCase(unittest.TestCase): class TestObjectFactory(base.Factory): class Meta: - target = TestObject + model = TestObject one = declarations.Sequence(lambda n: n) self.TestObjectFactory = TestObjectFactory @@ -358,7 +358,7 @@ class FactoryDefaultStrategyTestCase(unittest.TestCase): class TestModelFactory(base.Factory): class Meta: - target = TestModel + model = TestModel one = 'one' @@ -371,7 +371,7 @@ class FactoryDefaultStrategyTestCase(unittest.TestCase): class TestModelFactory(FakeModelFactory): class Meta: - target = TestModel + model = TestModel one = 'one' @@ -384,7 +384,7 @@ class FactoryDefaultStrategyTestCase(unittest.TestCase): class TestModelFactory(base.Factory): class Meta: - target = TestModel + model = TestModel one = 'one' @@ -397,7 +397,7 @@ class FactoryDefaultStrategyTestCase(unittest.TestCase): class TestModelFactory(base.Factory): class Meta: - target = TestModel + model = TestModel one = 'one' @@ -406,7 +406,7 @@ class FactoryDefaultStrategyTestCase(unittest.TestCase): def test_stub_with_non_stub_strategy(self): class TestModelFactory(base.StubFactory): class Meta: - target = TestModel + model = TestModel one = 'one' @@ -421,7 +421,7 @@ class FactoryDefaultStrategyTestCase(unittest.TestCase): @base.use_strategy(base.CREATE_STRATEGY) class TestModelFactory(base.StubFactory): class Meta: - target = TestModel + model = TestModel one = 'one' @@ -432,7 +432,7 @@ class FactoryCreationTestCase(unittest.TestCase): def test_factory_for(self): class TestFactory(base.Factory): class Meta: - target = TestObject + model = TestObject self.assertTrue(isinstance(TestFactory.build(), TestObject)) @@ -445,7 +445,7 @@ class FactoryCreationTestCase(unittest.TestCase): def test_inheritance_with_stub(self): class TestObjectFactory(base.StubFactory): class Meta: - target = TestObject + model = TestObject pass @@ -457,7 +457,7 @@ class FactoryCreationTestCase(unittest.TestCase): def test_custom_creation(self): class TestModelFactory(FakeModelFactory): class Meta: - target = TestModel + model = TestModel @classmethod def _prepare(cls, create, **kwargs): @@ -488,7 +488,7 @@ class PostGenerationParsingTestCase(unittest.TestCase): def test_extraction(self): class TestObjectFactory(base.Factory): class Meta: - target = TestObject + model = TestObject foo = declarations.PostGenerationDeclaration() @@ -497,7 +497,7 @@ class PostGenerationParsingTestCase(unittest.TestCase): def test_classlevel_extraction(self): class TestObjectFactory(base.Factory): class Meta: - target = TestObject + model = TestObject foo = declarations.PostGenerationDeclaration() foo__bar = 42 diff --git a/tests/test_containers.py b/tests/test_containers.py index 8a9e990..bd7019e 100644 --- a/tests/test_containers.py +++ b/tests/test_containers.py @@ -94,7 +94,7 @@ class LazyStubTestCase(unittest.TestCase): class RandomObj(object): pass - stub = containers.LazyStub({'one': 1, 'two': 2}, target_class=RandomObj) + stub = containers.LazyStub({'one': 1, 'two': 2}, model_class=RandomObj) self.assertIn('RandomObj', repr(stub)) self.assertIn('RandomObj', str(stub)) self.assertIn('one', str(stub)) diff --git a/tests/test_deprecation.py b/tests/test_deprecation.py index bccc351..bad6104 100644 --- a/tests/test_deprecation.py +++ b/tests/test_deprecation.py @@ -46,4 +46,4 @@ class DeprecationTests(unittest.TestCase): # This is to ensure error messages are readable by end users. self.assertEqual(__file__, warning.filename) self.assertIn('FACTORY_FOR', str(warning.message)) - self.assertIn('target', str(warning.message)) + self.assertIn('model', str(warning.message)) diff --git a/tests/test_django.py b/tests/test_django.py index 2bc5fe2..84b0933 100644 --- a/tests/test_django.py +++ b/tests/test_django.py @@ -100,14 +100,14 @@ def tearDownModule(): class StandardFactory(factory.django.DjangoModelFactory): class Meta: - target = models.StandardModel + model = models.StandardModel foo = factory.Sequence(lambda n: "foo%d" % n) class StandardFactoryWithPKField(factory.django.DjangoModelFactory): class Meta: - target = models.StandardModel + model = models.StandardModel django_get_or_create = ('pk',) foo = factory.Sequence(lambda n: "foo%d" % n) @@ -116,7 +116,7 @@ class StandardFactoryWithPKField(factory.django.DjangoModelFactory): class NonIntegerPkFactory(factory.django.DjangoModelFactory): class Meta: - target = models.NonIntegerPk + model = models.NonIntegerPk foo = factory.Sequence(lambda n: "foo%d" % n) bar = '' @@ -124,7 +124,7 @@ class NonIntegerPkFactory(factory.django.DjangoModelFactory): class AbstractBaseFactory(factory.django.DjangoModelFactory): class Meta: - target = models.AbstractBase + model = models.AbstractBase abstract = True foo = factory.Sequence(lambda n: "foo%d" % n) @@ -132,22 +132,22 @@ class AbstractBaseFactory(factory.django.DjangoModelFactory): class ConcreteSonFactory(AbstractBaseFactory): class Meta: - target = models.ConcreteSon + model = models.ConcreteSon class AbstractSonFactory(AbstractBaseFactory): class Meta: - target = models.AbstractSon + model = models.AbstractSon class ConcreteGrandSonFactory(AbstractBaseFactory): class Meta: - target = models.ConcreteGrandSon + model = models.ConcreteGrandSon class WithFileFactory(factory.django.DjangoModelFactory): class Meta: - target = models.WithFile + model = models.WithFile if django is not None: afile = factory.django.FileField() @@ -155,7 +155,7 @@ class WithFileFactory(factory.django.DjangoModelFactory): class WithImageFactory(factory.django.DjangoModelFactory): class Meta: - target = models.WithImage + model = models.WithImage if django is not None: animage = factory.django.ImageField() @@ -163,7 +163,7 @@ class WithImageFactory(factory.django.DjangoModelFactory): class WithSignalsFactory(factory.django.DjangoModelFactory): class Meta: - target = models.WithSignals + model = models.WithSignals @unittest.skipIf(django is None, "Django not installed.") @@ -231,19 +231,19 @@ class DjangoPkForceTestCase(django_test.TestCase): @unittest.skipIf(django is None, "Django not installed.") class DjangoModelLoadingTestCase(django_test.TestCase): """Tests class Meta: - target = 'app.Model' pattern.""" + model = 'app.Model' pattern.""" def test_loading(self): class ExampleFactory(factory.DjangoModelFactory): class Meta: - target = 'djapp.StandardModel' + model = 'djapp.StandardModel' - self.assertEqual(models.StandardModel, ExampleFactory._get_target_class()) + self.assertEqual(models.StandardModel, ExampleFactory._get_model_class()) def test_building(self): class ExampleFactory(factory.DjangoModelFactory): class Meta: - target = 'djapp.StandardModel' + model = 'djapp.StandardModel' e = ExampleFactory.build() self.assertEqual(models.StandardModel, e.__class__) @@ -255,7 +255,7 @@ class DjangoModelLoadingTestCase(django_test.TestCase): """ class ExampleFactory(factory.DjangoModelFactory): class Meta: - target = 'djapp.StandardModel' + model = 'djapp.StandardModel' class Example2Factory(ExampleFactory): pass @@ -270,15 +270,15 @@ class DjangoModelLoadingTestCase(django_test.TestCase): """ class ExampleFactory(factory.DjangoModelFactory): class Meta: - target = 'djapp.StandardModel' + model = 'djapp.StandardModel' foo = factory.Sequence(lambda n: n) class Example2Factory(ExampleFactory): class Meta: - target = 'djapp.StandardSon' + model = 'djapp.StandardSon' - self.assertEqual(models.StandardSon, Example2Factory._get_target_class()) + self.assertEqual(models.StandardSon, Example2Factory._get_model_class()) e1 = ExampleFactory.build() e2 = Example2Factory.build() @@ -580,7 +580,7 @@ class PreventSignalsTestCase(unittest.TestCase): @factory.django.mute_signals(signals.pre_save, signals.post_save) class WithSignalsDecoratedFactory(factory.django.DjangoModelFactory): class Meta: - target = models.WithSignals + model = models.WithSignals WithSignalsDecoratedFactory() @@ -594,7 +594,7 @@ class PreventSignalsTestCase(unittest.TestCase): @factory.django.mute_signals(signals.pre_save, signals.post_save) class WithSignalsDecoratedFactory(factory.django.DjangoModelFactory): class Meta: - target = models.WithSignals + model = models.WithSignals WithSignalsDecoratedFactory.build() diff --git a/tests/test_mongoengine.py b/tests/test_mongoengine.py index 39594c0..988c179 100644 --- a/tests/test_mongoengine.py +++ b/tests/test_mongoengine.py @@ -43,13 +43,13 @@ if mongoengine: class AddressFactory(MongoEngineFactory): class Meta: - target = Address + model = Address street = factory.Sequence(lambda n: 'street%d' % n) class PersonFactory(MongoEngineFactory): class Meta: - target = Person + model = Person name = factory.Sequence(lambda n: 'name%d' % n) address = factory.SubFactory(AddressFactory) diff --git a/tests/test_using.py b/tests/test_using.py index 6e7ed64..5486d33 100644 --- a/tests/test_using.py +++ b/tests/test_using.py @@ -82,8 +82,8 @@ class FakeModelFactory(factory.Factory): abstract = True @classmethod - def _create(cls, target_class, *args, **kwargs): - return target_class.create(**kwargs) + def _create(cls, model_class, *args, **kwargs): + return model_class.create(**kwargs) class TestModel(FakeModel): @@ -294,18 +294,18 @@ class UsingFactoryTestCase(unittest.TestCase): def test_attribute(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = 'one' test_object = TestObjectFactory.build() self.assertEqual(test_object.one, 'one') - def test_inheriting_target_class(self): + def test_inheriting_model_class(self): @factory.use_strategy(factory.BUILD_STRATEGY) class TestObjectFactory(factory.Factory, TestObject): class Meta: - target = TestObject + model = TestObject one = 'one' @@ -321,7 +321,7 @@ class UsingFactoryTestCase(unittest.TestCase): class InheritedFactory(SomeAbstractFactory): class Meta: - target = TestObject + model = TestObject test_object = InheritedFactory.build() self.assertEqual(test_object.one, 'one') @@ -329,7 +329,7 @@ class UsingFactoryTestCase(unittest.TestCase): def test_sequence(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = factory.Sequence(lambda n: 'one%d' % n) two = factory.Sequence(lambda n: 'two%d' % n) @@ -345,7 +345,7 @@ class UsingFactoryTestCase(unittest.TestCase): def test_sequence_custom_begin(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject @classmethod def _setup_next_sequence(cls): @@ -365,7 +365,7 @@ class UsingFactoryTestCase(unittest.TestCase): def test_sequence_override(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = factory.Sequence(lambda n: 'one%d' % n) @@ -382,13 +382,13 @@ class UsingFactoryTestCase(unittest.TestCase): def test_custom_create(self): class TestModelFactory(factory.Factory): class Meta: - target = TestModel + model = TestModel two = 2 @classmethod - def _create(cls, target_class, *args, **kwargs): - obj = target_class.create(**kwargs) + def _create(cls, model_class, *args, **kwargs): + obj = model_class.create(**kwargs) obj.properly_created = True return obj @@ -406,7 +406,7 @@ class UsingFactoryTestCase(unittest.TestCase): class NonDjangoFactory(factory.Factory): class Meta: - target = NonDjango + model = NonDjango x = 3 @@ -417,7 +417,7 @@ class UsingFactoryTestCase(unittest.TestCase): def test_sequence_batch(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = factory.Sequence(lambda n: 'one%d' % n) two = factory.Sequence(lambda n: 'two%d' % n) @@ -433,7 +433,7 @@ class UsingFactoryTestCase(unittest.TestCase): def test_lazy_attribute(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = factory.LazyAttribute(lambda a: 'abc' ) two = factory.LazyAttribute(lambda a: a.one + ' xyz') @@ -445,7 +445,7 @@ class UsingFactoryTestCase(unittest.TestCase): def test_lazy_attribute_sequence(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = factory.LazyAttributeSequence(lambda a, n: 'abc%d' % n) two = factory.LazyAttributeSequence(lambda a, n: a.one + ' xyz%d' % n) @@ -461,7 +461,7 @@ class UsingFactoryTestCase(unittest.TestCase): def test_lazy_attribute_decorator(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject @factory.lazy_attribute def one(a): @@ -476,7 +476,7 @@ class UsingFactoryTestCase(unittest.TestCase): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = 'xx' two = factory.SelfAttribute('one') @@ -496,13 +496,13 @@ class UsingFactoryTestCase(unittest.TestCase): class TestModelFactory(FakeModelFactory): class Meta: - target = TestModel + model = TestModel one = 3 three = factory.SelfAttribute('..bar') class TestModel2Factory(FakeModelFactory): class Meta: - target = TestModel2 + model = TestModel2 bar = 4 two = factory.SubFactory(TestModelFactory, one=1) @@ -512,7 +512,7 @@ class UsingFactoryTestCase(unittest.TestCase): def test_sequence_decorator(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject @factory.sequence def one(n): @@ -524,7 +524,7 @@ class UsingFactoryTestCase(unittest.TestCase): def test_lazy_attribute_sequence_decorator(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject @factory.lazy_attribute_sequence def one(a, n): @@ -540,7 +540,7 @@ class UsingFactoryTestCase(unittest.TestCase): def test_build_with_parameters(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = factory.Sequence(lambda n: 'one%d' % n) two = factory.Sequence(lambda n: 'two%d' % n) @@ -557,7 +557,7 @@ class UsingFactoryTestCase(unittest.TestCase): def test_create(self): class TestModelFactory(FakeModelFactory): class Meta: - target = TestModel + model = TestModel one = 'one' @@ -568,7 +568,7 @@ class UsingFactoryTestCase(unittest.TestCase): def test_create_batch(self): class TestModelFactory(FakeModelFactory): class Meta: - target = TestModel + model = TestModel one = 'one' @@ -585,7 +585,7 @@ class UsingFactoryTestCase(unittest.TestCase): def test_generate_build(self): class TestModelFactory(FakeModelFactory): class Meta: - target = TestModel + model = TestModel one = 'one' @@ -596,7 +596,7 @@ class UsingFactoryTestCase(unittest.TestCase): def test_generate_create(self): class TestModelFactory(FakeModelFactory): class Meta: - target = TestModel + model = TestModel one = 'one' @@ -607,7 +607,7 @@ class UsingFactoryTestCase(unittest.TestCase): def test_generate_stub(self): class TestModelFactory(FakeModelFactory): class Meta: - target = TestModel + model = TestModel one = 'one' @@ -618,7 +618,7 @@ class UsingFactoryTestCase(unittest.TestCase): def test_generate_batch_build(self): class TestModelFactory(FakeModelFactory): class Meta: - target = TestModel + model = TestModel one = 'one' @@ -635,7 +635,7 @@ class UsingFactoryTestCase(unittest.TestCase): def test_generate_batch_create(self): class TestModelFactory(FakeModelFactory): class Meta: - target = TestModel + model = TestModel one = 'one' @@ -652,7 +652,7 @@ class UsingFactoryTestCase(unittest.TestCase): def test_generate_batch_stub(self): class TestModelFactory(FakeModelFactory): class Meta: - target = TestModel + model = TestModel one = 'one' @@ -669,7 +669,7 @@ class UsingFactoryTestCase(unittest.TestCase): def test_simple_generate_build(self): class TestModelFactory(FakeModelFactory): class Meta: - target = TestModel + model = TestModel one = 'one' @@ -680,7 +680,7 @@ class UsingFactoryTestCase(unittest.TestCase): def test_simple_generate_create(self): class TestModelFactory(FakeModelFactory): class Meta: - target = TestModel + model = TestModel one = 'one' @@ -691,7 +691,7 @@ class UsingFactoryTestCase(unittest.TestCase): def test_simple_generate_batch_build(self): class TestModelFactory(FakeModelFactory): class Meta: - target = TestModel + model = TestModel one = 'one' @@ -708,7 +708,7 @@ class UsingFactoryTestCase(unittest.TestCase): def test_simple_generate_batch_create(self): class TestModelFactory(FakeModelFactory): class Meta: - target = TestModel + model = TestModel one = 'one' @@ -725,7 +725,7 @@ class UsingFactoryTestCase(unittest.TestCase): def test_stub_batch(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = 'one' two = factory.LazyAttribute(lambda a: a.one + ' two') @@ -745,14 +745,14 @@ class UsingFactoryTestCase(unittest.TestCase): def test_inheritance(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = 'one' two = factory.LazyAttribute(lambda a: a.one + ' two') class TestObjectFactory2(TestObjectFactory): class Meta: - target = TestObject + model = TestObject three = 'three' four = factory.LazyAttribute(lambda a: a.three + ' four') @@ -770,13 +770,13 @@ class UsingFactoryTestCase(unittest.TestCase): """Sequence counters should be kept within an inheritance chain.""" class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = factory.Sequence(lambda n: n) class TestObjectFactory2(TestObjectFactory): class Meta: - target = TestObject + model = TestObject to1a = TestObjectFactory() self.assertEqual(0, to1a.one) @@ -794,13 +794,13 @@ class UsingFactoryTestCase(unittest.TestCase): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = factory.Sequence(lambda n: n) class TestObjectFactory2(TestObjectFactory): class Meta: - target = TestObject2 + model = TestObject2 to1a = TestObjectFactory() self.assertEqual(0, to1a.one) @@ -826,13 +826,13 @@ class UsingFactoryTestCase(unittest.TestCase): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = factory.Sequence(lambda n: n) class TestObjectFactory2(TestObjectFactory): class Meta: - target = TestObject2 + model = TestObject2 to1a = TestObjectFactory() self.assertEqual(0, to1a.one) @@ -847,7 +847,7 @@ class UsingFactoryTestCase(unittest.TestCase): def test_inheritance_with_inherited_class(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = 'one' two = factory.LazyAttribute(lambda a: a.one + ' two') @@ -865,13 +865,13 @@ class UsingFactoryTestCase(unittest.TestCase): def test_dual_inheritance(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = 'one' class TestOtherFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject two = 'two' four = 'four' @@ -887,7 +887,7 @@ class UsingFactoryTestCase(unittest.TestCase): def test_class_method_accessible(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject @classmethod def alt_create(cls, **kwargs): @@ -898,7 +898,7 @@ class UsingFactoryTestCase(unittest.TestCase): def test_static_method_accessible(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject @staticmethod def alt_create(**kwargs): @@ -914,7 +914,7 @@ class UsingFactoryTestCase(unittest.TestCase): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject arg_parameters = ('x', 'y') x = 1 @@ -934,7 +934,7 @@ class UsingFactoryTestCase(unittest.TestCase): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject hidden_args = ('x', 'z') x = 1 @@ -954,7 +954,7 @@ class UsingFactoryTestCase(unittest.TestCase): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject hidden_args = ('x', 'z') arg_parameters = ('y',) @@ -978,7 +978,7 @@ class NonKwargParametersTestCase(unittest.TestCase): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject arg_parameters = ('one', 'two',) one = 1 @@ -1004,7 +1004,7 @@ class NonKwargParametersTestCase(unittest.TestCase): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject arg_parameters = ('one', 'two') one = 1 @@ -1012,8 +1012,8 @@ class NonKwargParametersTestCase(unittest.TestCase): three = 3 @classmethod - def _create(cls, target_class, *args, **kwargs): - return target_class.create(*args, **kwargs) + def _create(cls, model_class, *args, **kwargs): + return model_class.create(*args, **kwargs) obj = TestObjectFactory.create() self.assertEqual((1, 2), obj.args) @@ -1031,7 +1031,7 @@ class KwargAdjustTestCase(unittest.TestCase): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject @classmethod def _adjust_kwargs(cls, **kwargs): @@ -1050,12 +1050,12 @@ class SubFactoryTestCase(unittest.TestCase): class TestModelFactory(FakeModelFactory): class Meta: - target = TestModel + model = TestModel one = 3 class TestModel2Factory(FakeModelFactory): class Meta: - target = TestModel2 + model = TestModel2 two = factory.SubFactory(TestModelFactory, one=1) test_model = TestModel2Factory(two__one=4) @@ -1069,11 +1069,11 @@ class SubFactoryTestCase(unittest.TestCase): class TestModelFactory(FakeModelFactory): class Meta: - target = TestModel + model = TestModel class TestModel2Factory(FakeModelFactory): class Meta: - target = TestModel2 + model = TestModel2 two = factory.SubFactory(TestModelFactory, one=factory.Sequence(lambda n: 'x%dx' % n), two=factory.LazyAttribute(lambda o: '%s%s' % (o.one, o.one)), @@ -1091,13 +1091,13 @@ class SubFactoryTestCase(unittest.TestCase): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = factory.Sequence(lambda n: int(n)) class WrappingTestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject wrapped = factory.SubFactory(TestObjectFactory) @@ -1114,7 +1114,7 @@ class SubFactoryTestCase(unittest.TestCase): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject class OtherTestObject(object): @@ -1124,7 +1124,7 @@ class SubFactoryTestCase(unittest.TestCase): class WrappingTestObjectFactory(factory.Factory): class Meta: - target = OtherTestObject + model = OtherTestObject wrapped = factory.SubFactory(TestObjectFactory, two=2, four=4) wrapped__two = 4 @@ -1145,18 +1145,18 @@ class SubFactoryTestCase(unittest.TestCase): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject class WrappingTestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject wrapped = factory.SubFactory(TestObjectFactory) wrapped_bis = factory.SubFactory(TestObjectFactory, one=1) class OuterWrappingTestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject wrap = factory.SubFactory(WrappingTestObjectFactory, wrapped__two=2) @@ -1174,19 +1174,19 @@ class SubFactoryTestCase(unittest.TestCase): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject two = 'two' class WrappingTestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject wrapped = factory.SubFactory(TestObjectFactory) friend = factory.LazyAttribute(lambda o: o.wrapped.two.four + 1) class OuterWrappingTestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject wrap = factory.SubFactory(WrappingTestObjectFactory, wrapped__two=factory.SubFactory(TestObjectFactory, four=4)) @@ -1207,13 +1207,13 @@ class SubFactoryTestCase(unittest.TestCase): # Innermost factory class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject two = 'two' # Intermediary factory class WrappingTestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject wrapped = factory.SubFactory(TestObjectFactory) wrapped__two = 'three' @@ -1232,12 +1232,12 @@ class SubFactoryTestCase(unittest.TestCase): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject two = 'two' class WrappingTestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject wrapped = factory.SubFactory(TestObjectFactory) friend = factory.LazyAttribute(lambda o: o.wrapped.two + 1) @@ -1272,23 +1272,23 @@ class SubFactoryTestCase(unittest.TestCase): class InnerMostFactory(factory.Factory): class Meta: - target = InnerMost + model = InnerMost a = 15 b = 20 class SideAFactory(factory.Factory): class Meta: - target = SideA + model = SideA inner_from_a = factory.SubFactory(InnerMostFactory, a=20) class SideBFactory(factory.Factory): class Meta: - target = SideB + model = SideB inner_from_b = factory.SubFactory(InnerMostFactory, b=15) class OuterMostFactory(factory.Factory): class Meta: - target = OuterMost + model = OuterMost foo = 30 side_a = factory.SubFactory(SideAFactory, @@ -1314,13 +1314,13 @@ class SubFactoryTestCase(unittest.TestCase): class TestModelFactory(FakeModelFactory): class Meta: - target = TestModel + model = TestModel one = 3 two = factory.ContainerAttribute(lambda obj, containers: len(containers or []), strict=False) class TestModel2Factory(FakeModelFactory): class Meta: - target = TestModel2 + model = TestModel2 one = 1 two = factory.SubFactory(TestModelFactory, one=1) @@ -1339,13 +1339,13 @@ class SubFactoryTestCase(unittest.TestCase): class TestModelFactory(FakeModelFactory): class Meta: - target = TestModel + model = TestModel one = 3 two = factory.ContainerAttribute(lambda obj, containers: len(containers or []), strict=True) class TestModel2Factory(FakeModelFactory): class Meta: - target = TestModel2 + model = TestModel2 one = 1 two = factory.SubFactory(TestModelFactory, one=1) @@ -1362,7 +1362,7 @@ class SubFactoryTestCase(unittest.TestCase): class TestModelFactory(FakeModelFactory): class Meta: - target = TestModel + model = TestModel one = 3 @factory.container_attribute @@ -1373,7 +1373,7 @@ class SubFactoryTestCase(unittest.TestCase): class TestModel2Factory(FakeModelFactory): class Meta: - target = TestModel2 + model = TestModel2 one = 1 two = factory.SubFactory(TestModelFactory, one=1) @@ -1392,7 +1392,7 @@ class IteratorTestCase(unittest.TestCase): def test_iterator(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = factory.Iterator(range(10, 30)) @@ -1406,7 +1406,7 @@ class IteratorTestCase(unittest.TestCase): def test_iterator_list_comprehension_scope_bleeding(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = factory.Iterator([j * 3 for j in range(5)]) @@ -1418,7 +1418,7 @@ class IteratorTestCase(unittest.TestCase): def test_iterator_list_comprehension_protected(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = factory.Iterator([_j * 3 for _j in range(5)]) @@ -1432,7 +1432,7 @@ class IteratorTestCase(unittest.TestCase): def test_iterator_decorator(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject @factory.iterator def one(): @@ -1483,7 +1483,7 @@ class DjangoModelFactoryTestCase(unittest.TestCase): def test_simple(self): class FakeModelFactory(factory.django.DjangoModelFactory): class Meta: - target = FakeModel + model = FakeModel obj = FakeModelFactory(one=1) self.assertEqual(1, obj.one) @@ -1498,7 +1498,7 @@ class DjangoModelFactoryTestCase(unittest.TestCase): class MyFakeModelFactory(factory.django.DjangoModelFactory): class Meta: - target = MyFakeModel + model = MyFakeModel django_get_or_create = ('x',) x = 1 y = 4 @@ -1520,7 +1520,7 @@ class DjangoModelFactoryTestCase(unittest.TestCase): class MyFakeModelFactory(factory.django.DjangoModelFactory): class Meta: - target = MyFakeModel + model = MyFakeModel django_get_or_create = ('x', 'y', 'z') x = 1 y = 4 @@ -1542,7 +1542,7 @@ class DjangoModelFactoryTestCase(unittest.TestCase): class MyFakeModelFactory(factory.django.DjangoModelFactory): class Meta: - target = MyFakeModel + model = MyFakeModel django_get_or_create = ('x',) x = 1 y = 4 @@ -1564,7 +1564,7 @@ class DjangoModelFactoryTestCase(unittest.TestCase): class MyFakeModelFactory(factory.django.DjangoModelFactory): class Meta: - target = MyFakeModel + model = MyFakeModel django_get_or_create = ('x', 'y', 'z') x = 1 y = 4 @@ -1580,7 +1580,7 @@ class DjangoModelFactoryTestCase(unittest.TestCase): def test_sequence(self): class TestModelFactory(factory.django.DjangoModelFactory): class Meta: - target = TestModel + model = TestModel a = factory.Sequence(lambda n: 'foo_%s' % n) @@ -1599,7 +1599,7 @@ class DjangoModelFactoryTestCase(unittest.TestCase): def test_no_get_or_create(self): class TestModelFactory(factory.django.DjangoModelFactory): class Meta: - target = TestModel + model = TestModel a = factory.Sequence(lambda n: 'foo_%s' % n) @@ -1611,7 +1611,7 @@ class DjangoModelFactoryTestCase(unittest.TestCase): def test_get_or_create(self): class TestModelFactory(factory.django.DjangoModelFactory): class Meta: - target = TestModel + model = TestModel django_get_or_create = ('a', 'b') a = factory.Sequence(lambda n: 'foo_%s' % n) @@ -1631,7 +1631,7 @@ class DjangoModelFactoryTestCase(unittest.TestCase): """Test a DjangoModelFactory with all fields in get_or_create.""" class TestModelFactory(factory.django.DjangoModelFactory): class Meta: - target = TestModel + model = TestModel django_get_or_create = ('a', 'b', 'c', 'd') a = factory.Sequence(lambda n: 'foo_%s' % n) @@ -1652,7 +1652,7 @@ class PostGenerationTestCase(unittest.TestCase): def test_post_generation(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = 1 @@ -1671,7 +1671,7 @@ class PostGenerationTestCase(unittest.TestCase): def test_post_generation_hook(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = 1 @@ -1693,7 +1693,7 @@ class PostGenerationTestCase(unittest.TestCase): def test_post_generation_extraction(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = 1 @@ -1719,7 +1719,7 @@ class PostGenerationTestCase(unittest.TestCase): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject bar = factory.PostGeneration(my_lambda) @@ -1739,7 +1739,7 @@ class PostGenerationTestCase(unittest.TestCase): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = 3 two = 2 post_call = factory.PostGenerationMethodCall('call', one=1) @@ -1764,13 +1764,13 @@ class PostGenerationTestCase(unittest.TestCase): class TestRelatedObjectFactory(factory.Factory): class Meta: - target = TestRelatedObject + model = TestRelatedObject one = 1 two = factory.LazyAttribute(lambda o: o.one + 1) class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = 3 two = 2 three = factory.RelatedFactory(TestRelatedObjectFactory, name='obj') @@ -1811,13 +1811,13 @@ class PostGenerationTestCase(unittest.TestCase): class TestRelatedObjectFactory(factory.Factory): class Meta: - target = TestRelatedObject + model = TestRelatedObject one = 1 two = factory.LazyAttribute(lambda o: o.one + 1) class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = 3 two = 2 three = factory.RelatedFactory(TestRelatedObjectFactory) @@ -1859,11 +1859,11 @@ class RelatedFactoryExtractionTestCase(unittest.TestCase): class TestRelatedObjectFactory(factory.Factory): class Meta: - target = TestRelatedObject + model = TestRelatedObject class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = factory.RelatedFactory(TestRelatedObjectFactory, 'obj') self.TestRelatedObject = TestRelatedObject @@ -1911,7 +1911,7 @@ class DictTestCase(unittest.TestCase): def test_empty_dict(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = factory.Dict({}) o = TestObjectFactory() @@ -1920,7 +1920,7 @@ class DictTestCase(unittest.TestCase): def test_naive_dict(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = factory.Dict({'a': 1}) o = TestObjectFactory() @@ -1929,7 +1929,7 @@ class DictTestCase(unittest.TestCase): def test_sequence_dict(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = factory.Dict({'a': factory.Sequence(lambda n: n + 2)}) o1 = TestObjectFactory() @@ -1941,7 +1941,7 @@ class DictTestCase(unittest.TestCase): def test_dict_override(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = factory.Dict({'a': 1}) o = TestObjectFactory(one__a=2) @@ -1950,7 +1950,7 @@ class DictTestCase(unittest.TestCase): def test_dict_extra_key(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = factory.Dict({'a': 1}) o = TestObjectFactory(one__b=2) @@ -1959,7 +1959,7 @@ class DictTestCase(unittest.TestCase): def test_dict_merged_fields(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject two = 13 one = factory.Dict({ 'one': 1, @@ -1973,7 +1973,7 @@ class DictTestCase(unittest.TestCase): def test_nested_dicts(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = 1 two = factory.Dict({ 'one': 3, @@ -2002,7 +2002,7 @@ class ListTestCase(unittest.TestCase): def test_empty_list(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = factory.List([]) o = TestObjectFactory() @@ -2011,7 +2011,7 @@ class ListTestCase(unittest.TestCase): def test_naive_list(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = factory.List([1]) o = TestObjectFactory() @@ -2020,7 +2020,7 @@ class ListTestCase(unittest.TestCase): def test_sequence_list(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = factory.List([factory.Sequence(lambda n: n + 2)]) o1 = TestObjectFactory() @@ -2032,7 +2032,7 @@ class ListTestCase(unittest.TestCase): def test_list_override(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = factory.List([1]) o = TestObjectFactory(one__0=2) @@ -2041,7 +2041,7 @@ class ListTestCase(unittest.TestCase): def test_list_extra_key(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = factory.List([1]) o = TestObjectFactory(one__1=2) @@ -2050,7 +2050,7 @@ class ListTestCase(unittest.TestCase): def test_list_merged_fields(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject two = 13 one = factory.List([ 1, @@ -2064,7 +2064,7 @@ class ListTestCase(unittest.TestCase): def test_nested_lists(self): class TestObjectFactory(factory.Factory): class Meta: - target = TestObject + model = TestObject one = 1 two = factory.List([ -- cgit v1.2.3 From f2d04144167120dc8820401940172d10fdda007b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Sun, 18 May 2014 15:15:45 +0200 Subject: Rename hidden/arg_parameters to exclude/inline_args. --- docs/introduction.rst | 4 ++-- docs/reference.rst | 18 +++++++++--------- factory/base.py | 16 ++++++++-------- tests/test_base.py | 4 ++-- tests/test_using.py | 18 +++++++++--------- 5 files changed, 30 insertions(+), 30 deletions(-) diff --git a/docs/introduction.rst b/docs/introduction.rst index 5e3b4d8..d00154d 100644 --- a/docs/introduction.rst +++ b/docs/introduction.rst @@ -218,14 +218,14 @@ Non-kwarg arguments Some classes take a few, non-kwarg arguments first. -This is handled by the :data:`~factory.FactoryOptions.arg_parameters` attribute: +This is handled by the :data:`~factory.FactoryOptions.inline_args` attribute: .. code-block:: python class MyFactory(factory.Factory): class Meta: model = MyClass - arg_parameters = ('x', 'y') + inline_args = ('x', 'y') x = 1 y = 2 diff --git a/docs/reference.rst b/docs/reference.rst index d616d1c..25fef22 100644 --- a/docs/reference.rst +++ b/docs/reference.rst @@ -47,10 +47,10 @@ The :class:`Factory` class .. versionadded:: 2.4.0 - .. attribute:: arg_parameters + .. attribute:: inline_args Some factories require non-keyword arguments to their :meth:`~object.__init__`. - They should be listed, in order, in the :attr:`arg_parameters` + They should be listed, in order, in the :attr:`inline_args` attribute: .. code-block:: python @@ -58,7 +58,7 @@ The :class:`Factory` class class UserFactory(factory.Factory): class Meta: model = User - arg_parameters = ('login', 'email') + inline_args = ('login', 'email') login = 'john' email = factory.LazyAttribute(lambda o: '%s@example.com' % o.login) @@ -72,14 +72,14 @@ The :class:`Factory` class .. versionadded:: 2.4.0 - .. attribute:: hidden_args + .. attribute:: exclude While writing a :class:`Factory` for some object, it may be useful to have general fields helping defining others, but that should not be passed to the model class; for instance, a field named 'now' that would hold a reference time used by other objects. - Factory fields whose name are listed in :attr:`hidden_args` will + Factory fields whose name are listed in :attr:`exclude` will be removed from the set of args/kwargs passed to the underlying class; they can be any valid factory_boy declaration: @@ -88,7 +88,7 @@ The :class:`Factory` class class OrderFactory(factory.Factory): class Meta: model = Order - hidden_args = ('now',) + exclude = ('now',) now = factory.LazyAttribute(lambda o: datetime.datetime.utcnow()) started_at = factory.LazyAttribute(lambda o: o.now - datetime.timedelta(hours=1)) @@ -125,12 +125,12 @@ The :class:`Factory` class .. attribute:: FACTORY_ARG_PARAMETERS .. deprecated:: 2.4.0 - See :attr:`FactoryOptions.arg_parameters`. + See :attr:`FactoryOptions.inline_args`. .. attribute:: FACTORY_HIDDEN_ARGS .. deprecated:: 2.4.0 - See :attr:`FactoryOptions.hidden_args`. + See :attr:`FactoryOptions.exclude`. **Class-level attributes:** @@ -231,7 +231,7 @@ The :class:`Factory` class The :meth:`_adjust_kwargs` extension point allows for late fields tuning. It is called once keyword arguments have been resolved and post-generation - items removed, but before the :attr:`~FactoryOptions.arg_parameters` extraction + items removed, but before the :attr:`~FactoryOptions.inline_args` extraction phase. .. code-block:: python diff --git a/factory/base.py b/factory/base.py index e5c31f7..923c56b 100644 --- a/factory/base.py +++ b/factory/base.py @@ -192,8 +192,8 @@ class FactoryOptions(object): OptionDefault('model', None, inherit=True), OptionDefault('abstract', False, inherit=False), OptionDefault('strategy', CREATE_STRATEGY, inherit=True), - OptionDefault('arg_parameters', (), inherit=True), - OptionDefault('hidden_args', (), inherit=True), + OptionDefault('inline_args', (), inherit=True), + OptionDefault('exclude', (), inherit=True), ] def _fill_from_meta(self, meta, base_meta): @@ -326,8 +326,8 @@ class BaseFactory(object): 'FACTORY_FOR': 'model', 'ABSTRACT_FACTORY': 'abstract', 'FACTORY_STRATEGY': 'strategy', - 'FACTORY_ARG_PARAMETERS': 'arg_parameters', - 'FACTORY_HIDDEN_ARGS': 'hidden_args', + 'FACTORY_ARG_PARAMETERS': 'inline_args', + 'FACTORY_HIDDEN_ARGS': 'exclude', } # ID to use for the next 'declarations.Sequence' attribute. @@ -470,11 +470,11 @@ class BaseFactory(object): kwargs = cls._adjust_kwargs(**kwargs) # Remove 'hidden' arguments. - for arg in cls._meta.hidden_args: + for arg in cls._meta.exclude: del kwargs[arg] # Extract *args from **kwargs - args = tuple(kwargs.pop(key) for key in cls._meta.arg_parameters) + args = tuple(kwargs.pop(key) for key in cls._meta.inline_args) logger.debug('BaseFactory: Generating %s.%s(%s)', cls.__module__, @@ -725,7 +725,7 @@ class BaseDictFactory(Factory): def _build(cls, model_class, *args, **kwargs): if args: raise ValueError( - "DictFactory %r does not support Meta.arg_parameters.", cls) + "DictFactory %r does not support Meta.inline_args.", cls) return model_class(**kwargs) @classmethod @@ -747,7 +747,7 @@ class BaseListFactory(Factory): def _build(cls, model_class, *args, **kwargs): if args: raise ValueError( - "ListFactory %r does not support Meta.arg_parameters.", cls) + "ListFactory %r does not support Meta.inline_args.", cls) values = [v for k, v in sorted(kwargs.items())] return model_class(values) diff --git a/tests/test_base.py b/tests/test_base.py index d93bf29..d1df58e 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -122,8 +122,8 @@ class OptionsTests(unittest.TestCase): # Declarative attributes self.assertTrue(AbstractFactory._meta.abstract) self.assertIsNone(AbstractFactory._meta.model) - self.assertEqual((), AbstractFactory._meta.arg_parameters) - self.assertEqual((), AbstractFactory._meta.hidden_args) + self.assertEqual((), AbstractFactory._meta.inline_args) + self.assertEqual((), AbstractFactory._meta.exclude) self.assertEqual(base.CREATE_STRATEGY, AbstractFactory._meta.strategy) # Non-declarative attributes diff --git a/tests/test_using.py b/tests/test_using.py index 5486d33..e20f949 100644 --- a/tests/test_using.py +++ b/tests/test_using.py @@ -906,7 +906,7 @@ class UsingFactoryTestCase(unittest.TestCase): self.assertEqual(TestObjectFactory.alt_create(foo=1), {"foo": 1}) - def test_arg_parameters(self): + def test_inline_args(self): class TestObject(object): def __init__(self, *args, **kwargs): self.args = args @@ -915,7 +915,7 @@ class UsingFactoryTestCase(unittest.TestCase): class TestObjectFactory(factory.Factory): class Meta: model = TestObject - arg_parameters = ('x', 'y') + inline_args = ('x', 'y') x = 1 y = 2 @@ -926,7 +926,7 @@ class UsingFactoryTestCase(unittest.TestCase): self.assertEqual((42, 2), obj.args) self.assertEqual({'z': 5, 't': 4}, obj.kwargs) - def test_hidden_args(self): + def test_exclude(self): class TestObject(object): def __init__(self, *args, **kwargs): self.args = args @@ -935,7 +935,7 @@ class UsingFactoryTestCase(unittest.TestCase): class TestObjectFactory(factory.Factory): class Meta: model = TestObject - hidden_args = ('x', 'z') + exclude = ('x', 'z') x = 1 y = 2 @@ -946,7 +946,7 @@ class UsingFactoryTestCase(unittest.TestCase): self.assertEqual((), obj.args) self.assertEqual({'y': 2, 't': 4}, obj.kwargs) - def test_hidden_args_and_arg_parameters(self): + def test_exclude_and_inline_args(self): class TestObject(object): def __init__(self, *args, **kwargs): self.args = args @@ -955,8 +955,8 @@ class UsingFactoryTestCase(unittest.TestCase): class TestObjectFactory(factory.Factory): class Meta: model = TestObject - hidden_args = ('x', 'z') - arg_parameters = ('y',) + exclude = ('x', 'z') + inline_args = ('y',) x = 1 y = 2 @@ -979,7 +979,7 @@ class NonKwargParametersTestCase(unittest.TestCase): class TestObjectFactory(factory.Factory): class Meta: model = TestObject - arg_parameters = ('one', 'two',) + inline_args = ('one', 'two',) one = 1 two = 2 @@ -1005,7 +1005,7 @@ class NonKwargParametersTestCase(unittest.TestCase): class TestObjectFactory(factory.Factory): class Meta: model = TestObject - arg_parameters = ('one', 'two') + inline_args = ('one', 'two') one = 1 two = 2 -- cgit v1.2.3 From ecde9a5c2f5d7ea230e68e6d0b3586e5956e55c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Sun, 18 May 2014 15:17:52 +0200 Subject: Update ideas. --- docs/ideas.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/ideas.rst b/docs/ideas.rst index 914e640..f3c9e62 100644 --- a/docs/ideas.rst +++ b/docs/ideas.rst @@ -4,5 +4,6 @@ Ideas This is a list of future features that may be incorporated into factory_boy: -* **A 'options' attribute**: instead of adding more class-level constants, use a django-style ``class Meta`` Factory attribute with all options there +* When a :class:`Factory` is built or created, pass the calling context throughout the calling chain instead of custom solutions everywhere +* Define a proper set of rules for the support of third-party ORMs -- cgit v1.2.3 From 3d7a00d1c5cafe37e49a716c8ae075e984b3111a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Sun, 18 May 2014 15:23:54 +0200 Subject: Improve docs on create_batch (Closes #139). --- README.rst | 10 ++++++++++ docs/examples.rst | 12 ++++-------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/README.rst b/README.rst index b4ba689..0ba4a86 100644 --- a/README.rst +++ b/README.rst @@ -155,6 +155,16 @@ No matter which strategy is used, it's possible to override the defined attribut "Joe" +It is also possible to create a bunch of objects in a single call: + +.. code-block:: pycon + + >>> users = USerFactory.build(10, first_name="Joe") + >>> len(users) + 10 + >>> [user.first_name for user in users] + ["Joe", "Joe", "Joe", "Joe", "Joe", "Joe", "Joe", "Joe", "Joe", "Joe"] + Lazy Attributes """"""""""""""" diff --git a/docs/examples.rst b/docs/examples.rst index a57080e..ee521e3 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -114,12 +114,9 @@ We can now use our factories, for tests: def test_get_profile_stats(self): profiles = [] - for _ in xrange(4): - profiles.append(factories.ProfileFactory()) - for _ in xrange(2): - profiles.append(factories.FemaleProfileFactory()) - for _ in xrange(2): - profiles.append(factories.ProfileFactory(planet='Tatooine')) + profiles.extend(factories.ProfileFactory.batch_create(4)) + profiles.extend(factories.FemaleProfileFactory.batch_create(2)) + profiles.extend(factories.ProfileFactory.batch_create(2, planet="Tatooine")) stats = business_logic.profile_stats(profiles) self.assertEqual({'Earth': 6, 'Mars': 2}, stats.planets) @@ -133,8 +130,7 @@ Or for fixtures: from . import factories def make_objects(): - for _ in xrange(50): - factories.ProfileFactory() + factories.ProfileFactory.batch_create(size=50) # Let's create a few, known objects. factories.ProfileFactory( -- cgit v1.2.3 From 46ae739823bc9d9c3a176f20058d65097c22cb66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Sun, 18 May 2014 15:25:20 +0200 Subject: Fix test_deprecation test. --- tests/test_deprecation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_deprecation.py b/tests/test_deprecation.py index bad6104..a07cbf3 100644 --- a/tests/test_deprecation.py +++ b/tests/test_deprecation.py @@ -44,6 +44,6 @@ class DeprecationTests(unittest.TestCase): warning = w[0] # Message is indeed related to the current file # This is to ensure error messages are readable by end users. - self.assertEqual(__file__, warning.filename) + self.assertIn(warning.filename, __file__) self.assertIn('FACTORY_FOR', str(warning.message)) self.assertIn('model', str(warning.message)) -- cgit v1.2.3 From 790e8ea2db7a68d7074809124dfd82c3b05b925b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Wed, 21 May 2014 14:01:41 +0200 Subject: Introduce back missing doc about migrating FACTROY_DJANGO_GET_OR_CREATE. --- docs/orms.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/orms.rst b/docs/orms.rst index d3d98c9..6a942a6 100644 --- a/docs/orms.rst +++ b/docs/orms.rst @@ -40,6 +40,11 @@ All factories for a Django :class:`~django.db.models.Model` should use the attributes, the base object will be :meth:`saved ` once all post-generation hooks have run. + .. attribute:: FACTORY_DJANGO_GET_OR_CREATE + + .. deprecated:: 2.4.0 + See :attr:`DjangoOptions.django_get_or_create`. + .. class:: DjangoOptions(factory.base.FactoryOptions) @@ -47,6 +52,8 @@ All factories for a Django :class:`~django.db.models.Model` should use the .. attribute:: django_get_or_create + .. versionadded:: 2.4.0 + Fields whose name are passed in this list will be used to perform a :meth:`Model.objects.get_or_create() ` instead of the usual :meth:`Model.objects.create() `: -- cgit v1.2.3 From ad056787937844809b48dd36311dac0f8bd4c0ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Sat, 31 May 2014 14:06:45 +0200 Subject: doc: Document upgrade path for FACTORY_*. --- docs/changelog.rst | 19 +++++++++++++++++++ docs/orms.rst | 10 ++++++++-- docs/reference.rst | 12 ++++++++++++ 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index e5d76c7..b84ebc3 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -17,6 +17,25 @@ ChangeLog *Deprecation:* - Use of ``FACTORY_FOR`` and other ``FACTORY`` class-level attributes is deprecated and will be removed in 2.5. + Those attributes should now declared within the :class:`class Meta ` attribute: + + For :class:`factory.Factory`: + + * Rename :attr:`~factory.Factory.FACTORY_FOR` to :attr:`~factory.FactoryOptions.model` + + * Rename :attr:`~factory.Factory.FACTORY_FOR` to :attr:`~factory.FactoryOptions.model` + * Rename :attr:`~factory.Factory.ABSTRACT_FACTORY` to :attr:`~factory.FactoryOptions.abstract` + * Rename :attr:`~factory.Factory.FACTORY_STRATEGY` to :attr:`~factory.FactoryOptions.strategy` + * Rename :attr:`~factory.Factory.FACTORY_ARG_PARAMETERS` to :attr:`~factory.FactoryOptions.inline_args` + * Rename :attr:`~factory.Factory.FACTORY_HIDDEN_ARGS` to :attr:`~factory.FactoryOptions.exclude` + + For :class:`factory.django.DjangoModelFactory`: + + * Rename :attr:`~factory.django.DjangoModelFactory.FACTORY_DJANGO_GET_OR_CREATE` to :attr:`~factory.django.DjangoOptions.django_get_or_create` + + For :class:`factory.alchemy.SQLAlchemyModelFactory`: + + * Rename :attr:`~factory.alchemy.SQLAlchemyModelFactory.FACTORY_SESSION` to :attr:`~factory.alchemy.SQLAlchemyOptions.sqlalchemy_session` .. _v2.3.1: diff --git a/docs/orms.rst b/docs/orms.rst index 6a942a6..2aa27b2 100644 --- a/docs/orms.rst +++ b/docs/orms.rst @@ -273,7 +273,7 @@ SQLAlchemy Factoy_boy also supports `SQLAlchemy`_ models through the :class:`SQLAlchemyModelFactory` class. -To work, this class needs an `SQLAlchemy`_ session object affected to the ``Meta.sqlalchemy_session`` attribute. +To work, this class needs an `SQLAlchemy`_ session object affected to the :attr:`Meta.sqlalchemy_session ` attribute. .. _SQLAlchemy: http://www.sqlalchemy.org/ @@ -286,6 +286,11 @@ To work, this class needs an `SQLAlchemy`_ session object affected to the ``Meta * :func:`~factory.Factory.create()` uses :meth:`sqlalchemy.orm.session.Session.add` * :func:`~factory.Factory._setup_next_sequence()` selects the next unused primary key value + .. attribute:: FACTORY_SESSION + + .. deprecated:: 2.4.0 + See :attr:`~SQLAlchemyOptions.sqlalchemy_session`. + .. class:: SQLAlchemyOptions(factory.base.FactoryOptions) In addition to the usual parameters available in :class:`class Meta `, @@ -293,7 +298,8 @@ To work, this class needs an `SQLAlchemy`_ session object affected to the ``Meta .. attribute:: sqlalchemy_session - Fields whose SQLAlchemy session object are passed will be used to communicate with the database + SQLAlchemy session to use to communicate with the database when creating + an object through this :class:`SQLAlchemyModelFactory`. A (very) simple exemple: diff --git a/docs/reference.rst b/docs/reference.rst index 25fef22..b0dda50 100644 --- a/docs/reference.rst +++ b/docs/reference.rst @@ -106,6 +106,13 @@ The :class:`Factory` class .. versionadded:: 2.4.0 + .. attribute:: strategy + + Use this attribute to change the strategy used by a :class:`Factory`. + The default is :data:`BUILD_STRATEGY`. + + + .. class:: Factory .. note:: In previous versions, the fields of :class:`class Meta ` were @@ -132,6 +139,11 @@ The :class:`Factory` class .. deprecated:: 2.4.0 See :attr:`FactoryOptions.exclude`. + .. attribute:: FACTORY_STRATEGY + + .. deprecated:: 2.4.0 + See :attr:`FactoryOptions.strategy`. + **Class-level attributes:** -- cgit v1.2.3 From d9b49c72395a82d356fc2704c9a66047f20fe983 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Sat, 21 Jun 2014 13:32:04 +0200 Subject: Provide readable errors when Meta.model isn't set (Closes #137). --- factory/__init__.py | 2 ++ factory/django.py | 3 +++ tests/test_django.py | 9 +++++++++ 3 files changed, 14 insertions(+) diff --git a/factory/__init__.py b/factory/__init__.py index aa550e8..ca1571a 100644 --- a/factory/__init__.py +++ b/factory/__init__.py @@ -32,6 +32,8 @@ from .base import ( ListFactory, StubFactory, + FactoryError, + BUILD_STRATEGY, CREATE_STRATEGY, STUB_STRATEGY, diff --git a/factory/django.py b/factory/django.py index 6090145..2b6c463 100644 --- a/factory/django.py +++ b/factory/django.py @@ -101,6 +101,9 @@ class DjangoModelFactory(base.Factory): @classmethod def _get_manager(cls, model_class): + if model_class is None: + raise base.AssociatedClassError("No model set on %s.%s.Meta" + % (cls.__module__, cls.__name__)) try: return model_class._default_manager # pylint: disable=W0212 except AttributeError: diff --git a/tests/test_django.py b/tests/test_django.py index 84b0933..41a26cf 100644 --- a/tests/test_django.py +++ b/tests/test_django.py @@ -166,6 +166,15 @@ class WithSignalsFactory(factory.django.DjangoModelFactory): model = models.WithSignals +@unittest.skipIf(django is None, "Django not installed.") +class ModelTests(django_test.TestCase): + def test_unset_model(self): + class UnsetModelFactory(factory.django.DjangoModelFactory): + pass + + self.assertRaises(factory.FactoryError, UnsetModelFactory.create) + + @unittest.skipIf(django is None, "Django not installed.") class DjangoPkSequenceTestCase(django_test.TestCase): def setUp(self): -- cgit v1.2.3 From 52a66af1d9ca679c8c9653e254253b172d8ee1cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Sat, 21 Jun 2014 13:35:13 +0200 Subject: Release v2.4.0 --- docs/changelog.rst | 4 ++-- factory/__init__.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index b84ebc3..561ce18 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -4,8 +4,8 @@ ChangeLog .. _v2.4.0: -2.4.0 (master) --------------- +2.4.0 (2014-06-21) +------------------ *New:* diff --git a/factory/__init__.py b/factory/__init__.py index ca1571a..1f06fba 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__ = '2.3.1' +__version__ = '2.4.0' __author__ = 'Raphaël Barrois ' -- cgit v1.2.3 From 6269fef31787aba4956612febfa3f4944fda947b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Sat, 21 Jun 2014 13:36:52 +0200 Subject: Fix typo (Closes #144). Thanks to @clouserw for the report. --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 0ba4a86..32b93bd 100644 --- a/README.rst +++ b/README.rst @@ -159,7 +159,7 @@ It is also possible to create a bunch of objects in a single call: .. code-block:: pycon - >>> users = USerFactory.build(10, first_name="Joe") + >>> users = UserFactory.build(10, first_name="Joe") >>> len(users) 10 >>> [user.first_name for user in users] -- cgit v1.2.3 From e2ef7c96ed74b35b9dec75a7f222b6ffa9214c10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Mon, 23 Jun 2014 11:09:53 +0200 Subject: Fix declaration inheritance. --- factory/base.py | 2 +- tests/test_using.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/factory/base.py b/factory/base.py index 923c56b..9e07899 100644 --- a/factory/base.py +++ b/factory/base.py @@ -231,7 +231,7 @@ class FactoryOptions(object): self.counter_reference = self._get_counter_reference() - for parent in self.factory.__mro__[1:]: + for parent in reversed(self.factory.__mro__[1:]): if not hasattr(parent, '_meta'): continue self.declarations.update(parent._meta.declarations) diff --git a/tests/test_using.py b/tests/test_using.py index e20f949..f18df4d 100644 --- a/tests/test_using.py +++ b/tests/test_using.py @@ -766,6 +766,37 @@ class UsingFactoryTestCase(unittest.TestCase): test_object_alt = TestObjectFactory.build() self.assertEqual(None, test_object_alt.three) + def test_override_inherited(self): + """Overriding inherited declarations""" + class TestObjectFactory(factory.Factory): + class Meta: + model = TestObject + + one = 'one' + + class TestObjectFactory2(TestObjectFactory): + one = 'two' + + test_object = TestObjectFactory2.build() + self.assertEqual('two', test_object.one) + + def test_override_inherited_deep(self): + """Overriding inherited declarations""" + class TestObjectFactory(factory.Factory): + class Meta: + model = TestObject + + one = 'one' + + class TestObjectFactory2(TestObjectFactory): + one = 'two' + + class TestObjectFactory3(TestObjectFactory2): + pass + + test_object = TestObjectFactory3.build() + self.assertEqual('two', test_object.one) + def test_inheritance_and_sequences(self): """Sequence counters should be kept within an inheritance chain.""" class TestObjectFactory(factory.Factory): -- cgit v1.2.3 From 87f8cc0cc0d2f48f489c81b8c93e8ab6de6cff26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Mon, 23 Jun 2014 11:11:13 +0200 Subject: Release v2.4.1 --- docs/changelog.rst | 9 +++++++++ factory/__init__.py | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 561ce18..7d77f7f 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -2,6 +2,15 @@ ChangeLog ========= +.. _v2.4.1: + +2.4.1 (2014-06-23) +------------------ + +*Bugfix:* + + - Fix overriding deeply inherited attributes (set in one factory, overridden in a subclass, used in a sub-sub-class). + .. _v2.4.0: 2.4.0 (2014-06-21) diff --git a/factory/__init__.py b/factory/__init__.py index 1f06fba..8fc8ef8 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__ = '2.4.0' +__version__ = '2.4.1' __author__ = 'Raphaël Barrois ' -- cgit v1.2.3