From 251c9ef081bdb9233b4885d23501afc3b26324c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Wed, 3 Sep 2014 22:54:26 +0200 Subject: Fix typo in docs (Closes #157). --- docs/examples.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'docs') diff --git a/docs/examples.rst b/docs/examples.rst index ee521e3..e7f6057 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -114,9 +114,9 @@ We can now use our factories, for tests: def test_get_profile_stats(self): profiles = [] - profiles.extend(factories.ProfileFactory.batch_create(4)) - profiles.extend(factories.FemaleProfileFactory.batch_create(2)) - profiles.extend(factories.ProfileFactory.batch_create(2, planet="Tatooine")) + profiles.extend(factories.ProfileFactory.create_batch(4)) + profiles.extend(factories.FemaleProfileFactory.create_batch(2)) + profiles.extend(factories.ProfileFactory.create_batch(2, planet="Tatooine")) stats = business_logic.profile_stats(profiles) self.assertEqual({'Earth': 6, 'Mars': 2}, stats.planets) @@ -130,7 +130,7 @@ Or for fixtures: from . import factories def make_objects(): - factories.ProfileFactory.batch_create(size=50) + factories.ProfileFactory.create_batch(size=50) # Let's create a few, known objects. factories.ProfileFactory( -- cgit v1.2.3 From 827af8f13a1b768a75264874c73cc0e620177262 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Sun, 16 Nov 2014 21:17:11 +0100 Subject: Add docs for manual sequence counter management --- docs/recipes.rst | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) (limited to 'docs') diff --git a/docs/recipes.rst b/docs/recipes.rst index 72dacef..70eca46 100644 --- a/docs/recipes.rst +++ b/docs/recipes.rst @@ -327,3 +327,97 @@ default :meth:`Model.objects.create() ` manager = cls._get_manager(model_class) # The default would use ``manager.create(*args, **kwargs)`` return manager.create_user(*args, **kwargs) + + +Forcing the sequence counter +---------------------------- + +A common pattern with factory_boy is to use a :class:`factory.Sequence` declaration +to provide varying values to attributes declared as unique. + +However, it is sometimes useful to force a given value to the counter, for instance +to ensure that tests are properly reproductible. + +factory_boy provides a few hooks for this: + + +Forcing the value on a per-call basis + In order to force the counter for a specific :class:`~factory.Factory` instantiation, + just pass the value in the ``__sequence=42`` parameter: + + .. code-block:: python + + class AccountFactory(factory.Factory): + class Meta: + model = Account + uid = factory.Sequence(lambda n: n) + name = "Test" + + .. code-block:: pycon + + >>> obj1 = AccountFactory(name="John Doe", __sequence=10) + >>> obj1.uid # Taken from the __sequence counter + 10 + >>> obj2 = AccountFactory(name="Jane Doe") + >>> obj2.uid # The base sequence counter hasn't changed + 1 + + +Resetting the counter globally + If all calls for a factory must start from a deterministic number, + use :meth:`factory.Factory.reset_sequence`; this will reset the counter + to its initial value (as defined by :meth:`factory.Factory._setup_next_sequence`). + + .. code-block:: pycon + + >>> AccountFactory().uid + 1 + >>> AccountFactory().uid + 2 + >>> AccountFactory.reset_sequence() + >>> AccountFactory().uid # Reset to the initial value + 1 + >>> AccountFactory().uid + 2 + + It is also possible to reset the counter to a specific value: + + .. code-block:: pycon + + >>> AccountFactory.reset_sequence(10) + >>> AccountFactory().uid + 10 + >>> AccountFactory().uid + 11 + + This recipe is most useful in a :class:`~unittest.TestCase`'s + :meth:`~unittest.TestCase.setUp` method. + + +Forcing the initial value for all projects + The sequence counter of a :class:`~factory.Factory` can also be set + automatically upon the first call through the + :meth:`~factory.Factory._setup_next_sequence` method; this helps when the + objects's attributes mustn't conflict with pre-existing data. + + A typical example is to ensure that running a Python script twice will create + non-conflicting objects, by setting up the counter to "max used value plus one": + + .. code-block:: python + + class AccountFactory(factory.django.DjangoModelFactory): + class Meta: + model = models.Account + + @classmethod + def _setup_next_sequence(cls): + try: + return models.Accounts.objects.latest('uid').uid + 1 + except models.Account.DoesNotExist: + return 1 + + .. code-block:: pycon + + >>> Account.objects.create(uid=42, name="Blah") + >>> AccountFactory.create() # Sets up the account number based on the latest uid + -- cgit v1.2.3 From 13d310fa14f4e4b9a559f8b7887f2a2492357013 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Sun, 16 Nov 2014 22:34:29 +0100 Subject: Remove automagic pk-based sequence setup Related to issues #78, #92, #103, #111, #153, #170 The default value of all sequences is now 0; the automagic ``_setup_next_sequence`` behavior of Django/SQLAlchemy has been removed. This feature's only goal was to allow the following scenario: 1. Run a Python script that uses MyFactory.create() a couple of times (with a unique field based on the sequence counter) 2. Run the same Python script a second time Without the magical ``_setup_next_sequence``, the Sequence counter would be set to 0 at the beginning of each script run, so both runs would generate objects with the same values for the unique field ; thus conflicting and crashing. The above behavior having only a very limited use and bringing various issues (hitting the database on ``build()``, problems with non-integer or composite primary key columns, ...), it has been removed. It could still be emulated through custom ``_setup_next_sequence`` methods, or by calling ``MyFactory.reset_sequence()``. --- docs/changelog.rst | 13 ++++++++++++- docs/orms.rst | 2 -- 2 files changed, 12 insertions(+), 3 deletions(-) (limited to 'docs') diff --git a/docs/changelog.rst b/docs/changelog.rst index 7d77f7f..018ec60 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -2,6 +2,17 @@ ChangeLog ========= +.. _v2.5.0: + +2.5.0 (master) +-------------- + +*Deprecation:* + + - Remove deprecated features from :ref:`v2.4.0` + - Remove the auto-magical sequence setup (based on the latest primary key value in the database) for Django and SQLAlchemy; + this relates to issues :issue:`170`, :issue:`153`, :issue:`111`, :issue:`103`, :issue:`92`, :issue:`78`. + .. _v2.4.1: 2.4.1 (2014-06-23) @@ -19,7 +30,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`) + - 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. diff --git a/docs/orms.rst b/docs/orms.rst index 2aa27b2..88d49e9 100644 --- a/docs/orms.rst +++ b/docs/orms.rst @@ -35,7 +35,6 @@ All factories for a Django :class:`~django.db.models.Model` should use the * 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 * When using :class:`~factory.RelatedFactory` or :class:`~factory.PostGeneration` attributes, the base object will be :meth:`saved ` once all post-generation hooks have run. @@ -284,7 +283,6 @@ To work, this class needs an `SQLAlchemy`_ session object affected to the :attr: This class provides the following features: * :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 -- cgit v1.2.3 From 336ea5ac8b2d922fb54f99edd55d4773dd126934 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Tue, 18 Nov 2014 00:35:19 +0100 Subject: Remove deprecated features. This disables the ``FACTORY_FOR`` syntax and related parameters, that should be declared through ``class Meta``. --- docs/orms.rst | 9 --------- docs/reference.rst | 29 ----------------------------- 2 files changed, 38 deletions(-) (limited to 'docs') diff --git a/docs/orms.rst b/docs/orms.rst index 88d49e9..e32eafa 100644 --- a/docs/orms.rst +++ b/docs/orms.rst @@ -39,11 +39,6 @@ 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) @@ -284,10 +279,6 @@ To work, this class needs an `SQLAlchemy`_ session object affected to the :attr: * :func:`~factory.Factory.create()` uses :meth:`sqlalchemy.orm.session.Session.add` - .. attribute:: FACTORY_SESSION - - .. deprecated:: 2.4.0 - See :attr:`~SQLAlchemyOptions.sqlalchemy_session`. .. class:: SQLAlchemyOptions(factory.base.FactoryOptions) diff --git a/docs/reference.rst b/docs/reference.rst index b0dda50..5eea62c 100644 --- a/docs/reference.rst +++ b/docs/reference.rst @@ -115,35 +115,6 @@ The :class:`Factory` class .. 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.model`. - - .. attribute:: ABSTRACT_FACTORY - - .. deprecated:: 2.4.0 - See :attr:`FactoryOptions.abstract`. - - .. attribute:: FACTORY_ARG_PARAMETERS - - .. deprecated:: 2.4.0 - See :attr:`FactoryOptions.inline_args`. - - .. attribute:: FACTORY_HIDDEN_ARGS - - .. 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 7b31d60af0ab0678d04d7f50abc28ba7c4ccfcbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Tue, 18 Nov 2014 00:45:07 +0100 Subject: Fix typo in docs --- docs/reference.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/reference.rst b/docs/reference.rst index 5eea62c..2516936 100644 --- a/docs/reference.rst +++ b/docs/reference.rst @@ -369,7 +369,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`` attribute *and* the :meth:`~Factory._create` classmethod of the :class:`Factory` wasn't overridden. -- cgit v1.2.3 From 392db861e585f12038f18f41e467ecfcab9d39b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Tue, 25 Nov 2014 23:46:28 +0100 Subject: Fix reference docs (Closes #166, #167). Use ``obj`` for ``@post_generation``-decorated methods, instead of ``self``: this makes it clearer that the ``obj`` is an instance of the model, and not of the ``Factory``. Thanks to @jamescooke & @NiklasMM for spotting the typo. --- docs/reference.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/reference.rst b/docs/reference.rst index 2516936..43433e0 100644 --- a/docs/reference.rst +++ b/docs/reference.rst @@ -1192,7 +1192,7 @@ For instance, a :class:`PostGeneration` hook is declared as ``post``: model = SomeObject @post_generation - def post(self, create, extracted, **kwargs): + def post(obj, create, extracted, **kwargs): obj.set_origin(create) .. OHAI_VIM** -- cgit v1.2.3 From f83c602874698427bdc141accd8fc14a9749d6c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Fri, 6 Feb 2015 23:19:06 +0100 Subject: docs: Add explanations about SQLAlchemy's scoped_session. --- docs/conf.py | 4 +-- docs/orms.rst | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 102 insertions(+), 4 deletions(-) (limited to 'docs') diff --git a/docs/conf.py b/docs/conf.py index 4f76d45..ce6730b 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -247,7 +247,7 @@ intersphinx_mapping = { 'http://docs.djangoproject.com/en/dev/_objects/', ), 'sqlalchemy': ( - 'http://docs.sqlalchemy.org/en/rel_0_8/', - 'http://docs.sqlalchemy.org/en/rel_0_8/objects.inv', + 'http://docs.sqlalchemy.org/en/rel_0_9/', + 'http://docs.sqlalchemy.org/en/rel_0_9/objects.inv', ), } diff --git a/docs/orms.rst b/docs/orms.rst index e32eafa..ab813a2 100644 --- a/docs/orms.rst +++ b/docs/orms.rst @@ -298,9 +298,8 @@ A (very) simple exemple: from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import scoped_session, sessionmaker - session = scoped_session(sessionmaker()) engine = create_engine('sqlite://') - session.configure(bind=engine) + session = scoped_session(sessionmaker(bind=engine)) Base = declarative_base() @@ -330,3 +329,102 @@ A (very) simple exemple: >>> session.query(User).all() [] + + +Managing sessions +""""""""""""""""" + +Since `SQLAlchemy`_ is a general purpose library, +there is no "global" session management system. + +The most common pattern when working with unit tests and ``factory_boy`` +is to use `SQLAlchemy`_'s :class:`sqlalchemy.orm.scoping.scoped_session`: + +* The test runner configures some project-wide :class:`~sqlalchemy.orm.scoping.scoped_session` +* Each :class:`~SQLAlchemyModelFactory` subclass uses this + :class:`~sqlalchemy.orm.scoping.scoped_session` as its :attr:`~SQLAlchemyOptions.sqlalchemy_session` +* The :meth:`~unittest.TestCase.tearDown` method of tests calls + :meth:`Session.remove ` + to reset the session. + + +Here is an example layout: + +- A global (test-only?) file holds the :class:`~sqlalchemy.orm.scoping.scoped_session`: + +.. code-block:: python + + # myprojet/test/common.py + + from sqlalchemy import orm + Session = orm.scoped_session(orm.sessionmaker()) + + +- All factory access it: + +.. code-block:: python + + # myproject/factories.py + + import factory + import factory.alchemy + + from . import models + from .test import common + + class UserFactory(factory.alchemy.SQLAlchemyModelFactory): + class Meta: + model = models.User + + # Use the not-so-global scoped_session + # Warning: DO NOT USE common.Session()! + sqlalchemy_session = common.Session + + name = factory.Sequence(lambda n: "User %d" % n) + + +- The test runner configures the :class:`~sqlalchemy.orm.scoping.scoped_session` when it starts: + +.. code-block:: python + + # myproject/test/runtests.py + + import sqlalchemy + + from . import common + + def runtests(): + engine = sqlalchemy.create_engine('sqlite://') + + # It's a scoped_session, we can configure it later + common.Session.configure(engine=engine) + + run_the_tests + + +- :class:`test cases ` use this ``scoped_session``, + and clear it after each test: + +.. code-block:: python + + # myproject/test/test_stuff.py + + import unittest + + from . import common + + class MyTest(unittest.TestCase): + + def setUp(self): + # Prepare a new, clean session + self.session = common.Session() + + def test_something(self): + u = factories.UserFactory() + self.assertEqual([u], self.session.query(User).all()) + + def tearDown(self): + # Rollback the session => no changes to the database + self.session.rollback() + # Remove it, so that the next test gets a new Session() + common.Session.remove() -- cgit v1.2.3 From d95bc982cd8480aa44e5282ab1284a9278049066 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Fri, 6 Feb 2015 23:29:52 +0100 Subject: docs: Improve explanation of SQLAlchemy's scoped_session. --- docs/orms.rst | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'docs') diff --git a/docs/orms.rst b/docs/orms.rst index ab813a2..9e4d106 100644 --- a/docs/orms.rst +++ b/docs/orms.rst @@ -347,6 +347,16 @@ is to use `SQLAlchemy`_'s :class:`sqlalchemy.orm.scoping.scoped_session`: :meth:`Session.remove ` to reset the session. +.. note:: See the excellent :ref:`SQLAlchemy guide on scoped_session ` + for details of :class:`~sqlalchemy.orm.scoping.scoped_session`'s usage. + + The basic idea is that declarative parts of the code (including factories) + need a simple way to access the "current session", + but that session will only be created and configured at a later point. + + The :class:`~sqlalchemy.orm.scoping.scoped_session` handles this, + by virtue of only creating the session when a query is sent to the database. + Here is an example layout: @@ -396,14 +406,14 @@ Here is an example layout: def runtests(): engine = sqlalchemy.create_engine('sqlite://') - # It's a scoped_session, we can configure it later - common.Session.configure(engine=engine) + # It's a scoped_session, and now is the time to configure it. + common.Session.configure(bind=engine) run_the_tests - :class:`test cases ` use this ``scoped_session``, - and clear it after each test: + and clear it after each test (for isolation): .. code-block:: python -- cgit v1.2.3 From 97a88905b7f0f513bd480fe630e43798aba22c74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Wed, 18 Feb 2015 22:00:01 +0100 Subject: Enable resetting factory.fuzzy's random generator (Closes #175, #185). Users may now call ``factory.fuzzy.get_random_state()`` to retrieve the current random generator's state (isolated from the one used in Python's ``random``). That state can then be reinjected with ``factory.fuzzy.set_random_state(state)``. --- docs/changelog.rst | 4 ++++ docs/fuzzy.rst | 30 ++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) (limited to 'docs') diff --git a/docs/changelog.rst b/docs/changelog.rst index 018ec60..ebe9930 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -7,6 +7,10 @@ ChangeLog 2.5.0 (master) -------------- +*New:* + + - Add support for getting/setting :mod:`factory.fuzzy`'s random state (see :issue:`175`, :issue:`185`). + *Deprecation:* - Remove deprecated features from :ref:`v2.4.0` diff --git a/docs/fuzzy.rst b/docs/fuzzy.rst index 1480419..0658652 100644 --- a/docs/fuzzy.rst +++ b/docs/fuzzy.rst @@ -338,3 +338,33 @@ They should inherit from the :class:`BaseFuzzyAttribute` class, and override its The method responsible for generating random values. *Must* be overridden in subclasses. + + +Managing randomness +------------------- + +Using :mod:`random` in factories allows to "fuzz" a program efficiently. +However, it's sometimes required to *reproduce* a failing test. + +:mod:`factory.fuzzy` uses a separate instance of :class:`random.Random`, +and provides a few helpers for this: + +.. method:: get_random_state() + + Call :meth:`get_random_state` to retrieve the random generator's current + state. + +.. method:: set_random_state(state) + + Use :meth:`set_random_state` to set a custom state into the random generator + (fetched from :meth:`get_random_state` in a previous run, for instance) + +.. method:: reseed_random(seed) + + The :meth:`reseed_random` function allows to load a chosen seed into the random generator. + + +Custom :class:`BaseFuzzyAttribute` subclasses **SHOULD** +use :obj:`factory.fuzzy._random` foras a randomness source; this ensures that +data they generate can be regenerated using the simple state from +:meth:`get_random_state`. -- cgit v1.2.3 From efa9d3c0d165a4c49def26b423711ed28eb2d264 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Tue, 3 Mar 2015 22:45:45 +0100 Subject: Fix typos in docs (Closes #159, closes #178, closes #188). --- docs/orms.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/orms.rst b/docs/orms.rst index 9e4d106..a0afc40 100644 --- a/docs/orms.rst +++ b/docs/orms.rst @@ -290,7 +290,7 @@ To work, this class needs an `SQLAlchemy`_ session object affected to the :attr: SQLAlchemy session to use to communicate with the database when creating an object through this :class:`SQLAlchemyModelFactory`. -A (very) simple exemple: +A (very) simple example: .. code-block:: python -- cgit v1.2.3 From c666411153ea9840b492f7abecf0cfa51e21dc27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Tue, 3 Mar 2015 22:48:43 +0100 Subject: Docs: fix default strategy (Closes #158). --- docs/reference.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/reference.rst b/docs/reference.rst index 43433e0..9fd2576 100644 --- a/docs/reference.rst +++ b/docs/reference.rst @@ -109,7 +109,7 @@ The :class:`Factory` class .. attribute:: strategy Use this attribute to change the strategy used by a :class:`Factory`. - The default is :data:`BUILD_STRATEGY`. + The default is :data:`CREATE_STRATEGY`. -- cgit v1.2.3 From 69befae5fde1897cf68c4d44a146db5ba642c814 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Thu, 26 Mar 2015 22:22:03 +0100 Subject: Allow lazy evaluation of FuzzyChoice's iterators (Closes #184). This allows the following idiom: ``user = factory.fuzzy.FuzzyChoice(User.objects.all())`` Previously, the ``User.objects.all()`` queryset would have been evaluated *at import time*; it is now evaluated with the first use of the ``FuzzyChoice``. --- docs/changelog.rst | 1 + docs/fuzzy.rst | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/docs/changelog.rst b/docs/changelog.rst index ebe9930..13fdd68 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -10,6 +10,7 @@ ChangeLog *New:* - Add support for getting/setting :mod:`factory.fuzzy`'s random state (see :issue:`175`, :issue:`185`). + - Support lazy evaluation of iterables in :class:`factory.fuzzy.FuzzyChoice` (see :issue:`184`). *Deprecation:* diff --git a/docs/fuzzy.rst b/docs/fuzzy.rst index 0658652..18978e4 100644 --- a/docs/fuzzy.rst +++ b/docs/fuzzy.rst @@ -62,8 +62,11 @@ FuzzyChoice The :class:`FuzzyChoice` fuzzer yields random choices from the given iterable. - .. note:: The passed in :attr:`choices` will be converted into a list at - declaration time. + .. note:: The passed in :attr:`choices` will be converted into a list upon + first use, not at declaration time. + + This allows passing in, for instance, a Django queryset that will + only hit the database during the database, not at import time. .. attribute:: choices -- cgit v1.2.3 From 72fd943513b0e516f06c53b13ff35ca814b0a4a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Thu, 26 Mar 2015 22:37:54 +0100 Subject: Fix issues between mute_signals() and factory inheritance (Closes #183). Previously, if a factory was decorated with ``@mute_signals`` and one of its descendant called another one of its descendant, signals weren't unmuted properly. --- docs/changelog.rst | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'docs') diff --git a/docs/changelog.rst b/docs/changelog.rst index 13fdd68..0cf8368 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -12,6 +12,10 @@ ChangeLog - Add support for getting/setting :mod:`factory.fuzzy`'s random state (see :issue:`175`, :issue:`185`). - Support lazy evaluation of iterables in :class:`factory.fuzzy.FuzzyChoice` (see :issue:`184`). +*Bugfix:* + + - Avoid issues when using :meth:`factory.django.mute_signals` on a base factory class (see :issue:`183`). + *Deprecation:* - Remove deprecated features from :ref:`v2.4.0` -- cgit v1.2.3 From 636ca46951d710a4b9d9fd61ec1da02294806d3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Thu, 26 Mar 2015 22:53:15 +0100 Subject: Add support for multidb with Django (Closes #171). The ``factory.django.DjangoModelFactory`` now takes an extra option: ``` class MyFactory(factory.django.DjangoModelFactory): class Meta: model = models.MyModel database = 'replica' ``` This will create all instances of ``models.Model`` in the ``'replica'`` database. --- docs/changelog.rst | 1 + docs/orms.rst | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/changelog.rst b/docs/changelog.rst index 0cf8368..c2da698 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -11,6 +11,7 @@ ChangeLog - Add support for getting/setting :mod:`factory.fuzzy`'s random state (see :issue:`175`, :issue:`185`). - Support lazy evaluation of iterables in :class:`factory.fuzzy.FuzzyChoice` (see :issue:`184`). + - Support non-default databases at the factory level (see :issue:`171`) *Bugfix:* diff --git a/docs/orms.rst b/docs/orms.rst index a0afc40..5105e66 100644 --- a/docs/orms.rst +++ b/docs/orms.rst @@ -42,7 +42,14 @@ All factories for a Django :class:`~django.db.models.Model` should use the .. class:: DjangoOptions(factory.base.FactoryOptions) - The ``class Meta`` on a :class:`~DjangoModelFactory` supports an extra parameter: + The ``class Meta`` on a :class:`~DjangoModelFactory` supports extra parameters: + + .. attribute:: database + + .. versionadded:: 2.5.0 + + All queries to the related model will be routed to the given database. + It defaults to ``'default'``. .. attribute:: django_get_or_create -- cgit v1.2.3 From a456a9e3f440e5f61497e97d75dd0a15efe71a8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Thu, 26 Mar 2015 23:04:41 +0100 Subject: Remove limitations of factory.StubFactory (Closes #131). ``StubFactory.build()`` is now supported, and maps to ``StubFactory.stub()``. --- docs/changelog.rst | 1 + 1 file changed, 1 insertion(+) (limited to 'docs') diff --git a/docs/changelog.rst b/docs/changelog.rst index c2da698..a6ca79e 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -16,6 +16,7 @@ ChangeLog *Bugfix:* - Avoid issues when using :meth:`factory.django.mute_signals` on a base factory class (see :issue:`183`). + - Fix limitations of :class:`factory.StubFactory`, that can now use :class:`factory.SubFactory` and co (see :issue:`131`). *Deprecation:* -- cgit v1.2.3 From 4e0e563c1c0d823d2869d340e2fa31ca8630d854 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Thu, 26 Mar 2015 23:31:56 +0100 Subject: Turn FileField/ImageField into normal fields (Closes #141). Previously, they ran as post_generation hooks, meaning that they couldn't be checked in a model's ``save()`` method, for instance. --- docs/changelog.rst | 1 + 1 file changed, 1 insertion(+) (limited to 'docs') diff --git a/docs/changelog.rst b/docs/changelog.rst index a6ca79e..c2731ef 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -12,6 +12,7 @@ ChangeLog - Add support for getting/setting :mod:`factory.fuzzy`'s random state (see :issue:`175`, :issue:`185`). - Support lazy evaluation of iterables in :class:`factory.fuzzy.FuzzyChoice` (see :issue:`184`). - Support non-default databases at the factory level (see :issue:`171`) + - Make :class:`factory.django.FileField` and :class:`factory.django.ImageField` non-post_generation, i.e normal fields also available in ``save()`` (see :issue:`141`). *Bugfix:* -- cgit v1.2.3 From 35f9ee112f5b3dfb799e24635d548fd228c98db1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Thu, 26 Mar 2015 23:40:07 +0100 Subject: Release v2.5.0 --- docs/changelog.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/docs/changelog.rst b/docs/changelog.rst index c2731ef..4018e32 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -4,8 +4,8 @@ ChangeLog .. _v2.5.0: -2.5.0 (master) --------------- +2.5.0 (2015-03-26) +------------------ *New:* -- cgit v1.2.3 From 8a3127f394283b367f15f43328a1c8751982898f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Thu, 26 Mar 2015 23:41:11 +0100 Subject: Get ready for next release. --- docs/changelog.rst | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'docs') diff --git a/docs/changelog.rst b/docs/changelog.rst index 4018e32..0554eb7 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -2,6 +2,12 @@ ChangeLog ========= +.. _v2.5.1: + +2.5.1 (master) +-------------- + + .. _v2.5.0: 2.5.0 (2015-03-26) -- cgit v1.2.3 From a1e5ff13c0573feb95c810e7e27cd30de97b8f21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Thu, 26 Mar 2015 23:45:29 +0100 Subject: Update header years. --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/conf.py b/docs/conf.py index ce6730b..c3512e0 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -51,7 +51,7 @@ master_doc = 'index' # General information about the project. project = u'Factory Boy' -copyright = u'2011-2013, Raphaël Barrois, Mark Sandstrom' +copyright = u'2011-2015, Raphaël Barrois, Mark Sandstrom' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the -- cgit v1.2.3 From 140956f854b34164cce90bbaaa49255383a440c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Thu, 26 Mar 2015 23:52:41 +0100 Subject: Clarify impacts of 2.5.0. --- docs/changelog.rst | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/changelog.rst b/docs/changelog.rst index 0554eb7..326e8f1 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -25,11 +25,16 @@ ChangeLog - Avoid issues when using :meth:`factory.django.mute_signals` on a base factory class (see :issue:`183`). - Fix limitations of :class:`factory.StubFactory`, that can now use :class:`factory.SubFactory` and co (see :issue:`131`). + *Deprecation:* - Remove deprecated features from :ref:`v2.4.0` - Remove the auto-magical sequence setup (based on the latest primary key value in the database) for Django and SQLAlchemy; - this relates to issues :issue:`170`, :issue:`153`, :issue:`111`, :issue:`103`, :issue:`92`, :issue:`78`. + this relates to issues :issue:`170`, :issue:`153`, :issue:`111`, :issue:`103`, :issue:`92`, :issue:`78`. See https://github.com/rbarrois/factory_boy/commit/13d310f for technical details. + +.. warning:: Version 2.5.0 removes the 'auto-magical sequence setup' bug-and-feature. + This could trigger some bugs when tests expected a non-zero sequence reference. + .. _v2.4.1: -- cgit v1.2.3 From d6f351c5af74ac659b4d3add916546d286ff4fcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Fri, 27 Mar 2015 13:44:15 +0100 Subject: Add upgrade instructions for 2.5.0 --- docs/changelog.rst | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'docs') diff --git a/docs/changelog.rst b/docs/changelog.rst index 326e8f1..a7ff050 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -35,6 +35,36 @@ ChangeLog .. warning:: Version 2.5.0 removes the 'auto-magical sequence setup' bug-and-feature. This could trigger some bugs when tests expected a non-zero sequence reference. +Upgrading +""""""""" + +.. warning:: Version 2.5.0 removes features that were marked as deprecated in :ref:`v2.4.0 `. + +All ``FACTORY_*``-style attributes are now declared in a ``class Meta:`` section: + +.. code-block:: python + + # Old-style, deprecated + class MyFactory(factory.Factory): + FACTORY_FOR = models.MyModel + FACTORY_HIDDEN_ARGS = ['a', 'b', 'c'] + + # New-style + class MyFactory(factory.Factory): + class Meta: + model = models.MyModel + exclude = ['a', 'b', 'c'] + +A simple shell command to upgrade the code would be: + +.. code-block:: sh + + # sed -i: inplace update + # grep -l: only file names, not matching lines + sed -i 's/FACTORY_FOR =/class Meta:\n model =/' $(grep -l FACTORY_FOR $(find . -name '*.py')) + +This takes care of all ``FACTORY_FOR`` occurences; the files containing other attributes to rename can be found with ``grep -R FACTORY .`` + .. _v2.4.1: -- cgit v1.2.3 From bdc1b815cfdf3028379c6c3f18c9c47ee8298a70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Fri, 27 Mar 2015 16:27:05 +0100 Subject: Respect default manager in DjangoModelFactory (Closes #192). The previous version tries to use ``cls._default_manager`` all the time, which breaks with ``manager.using(db_name)``. --- docs/changelog.rst | 3 +++ 1 file changed, 3 insertions(+) (limited to 'docs') diff --git a/docs/changelog.rst b/docs/changelog.rst index a7ff050..cc4a1dc 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -7,6 +7,9 @@ ChangeLog 2.5.1 (master) -------------- +*Bugfix:* + + - Respect custom managers in :class:`~factory.django.DjangoModelFactory` (see :issue:`192`) .. _v2.5.0: -- cgit v1.2.3 From 5363951bb62ca90d971bf036851dea564204ed2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Fri, 27 Mar 2015 17:00:32 +0100 Subject: Support declarations in FileField/ImageField. Previously, the declarations (``factory.Sequence`` & co) weren't properly computed. --- docs/changelog.rst | 2 ++ 1 file changed, 2 insertions(+) (limited to 'docs') diff --git a/docs/changelog.rst b/docs/changelog.rst index cc4a1dc..de9778b 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -10,6 +10,8 @@ ChangeLog *Bugfix:* - Respect custom managers in :class:`~factory.django.DjangoModelFactory` (see :issue:`192`) + - Allow passing declarations (e.g :class:`~factory.Sequence`) as parameters to :class:`~factory.django.FileField` + and :class:`~factory.django.ImageField`. .. _v2.5.0: -- cgit v1.2.3 From 48a1e4a65968a911d530c87cf0bcb9f312927641 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Fri, 27 Mar 2015 17:48:38 +0100 Subject: Release v2.5.1 --- docs/changelog.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/docs/changelog.rst b/docs/changelog.rst index de9778b..0d12cb3 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -4,8 +4,8 @@ ChangeLog .. _v2.5.1: -2.5.1 (master) --------------- +2.5.1 (2015-03-27) +------------------ *Bugfix:* -- cgit v1.2.3 From 52c984d3f1c6c440a832e53331d7f95f25c8b046 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Tue, 14 Apr 2015 00:22:08 +0200 Subject: Fix minor typo (Closes #194). Thanks to @DasAllFolks for spotting it! --- docs/reference.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/reference.rst b/docs/reference.rst index 9fd2576..44f78b6 100644 --- a/docs/reference.rst +++ b/docs/reference.rst @@ -42,7 +42,7 @@ The :class:`Factory` class It will be automatically set to ``True`` if neither the :class:`Factory` subclass nor its parents define the :attr:`~FactoryOptions.model` attribute. - .. warning:: This flag is reset to ``False`` When a :class:`Factory` subclasses + .. warning:: This flag is reset to ``False`` when a :class:`Factory` subclasses another one if a :attr:`~FactoryOptions.model` is set. .. versionadded:: 2.4.0 -- cgit v1.2.3 From 24269d9265ee2e3f53ca9f4bdbb01c79470988df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Tue, 21 Apr 2015 11:38:19 +0200 Subject: Release v2.5.2 --- docs/changelog.rst | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'docs') diff --git a/docs/changelog.rst b/docs/changelog.rst index 0d12cb3..8f63567 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,6 +1,15 @@ ChangeLog ========= +.. _v2.5.2: + +2.5.2 (2015-04-21) +------------------ + +*Bugfix:* + + - Add support for Django 1.7/1.8 + - Add support for mongoengine>=0.9.0 / pymongo>=2.1 .. _v2.5.1: -- cgit v1.2.3 From 0e3cdffac41250cddfe93388b1c9fc1547e77a67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Sat, 25 Apr 2015 17:50:50 +0200 Subject: Clarify .build() issue with Django>1.8 (Ref #198). From 1.8 onwards, this crashes: >>> a = MyModel() # Don't save >>> b = MyOtherModel(fkey_to_mymodel=a) In turn, it breaks: class MyModelFactory(factory.django.DjangoModelFactory): class Meta: model = MyModel class MyOtherModelFactory(factory.django.DjangoModelFactory): class Meta: model = MyOtherModel fkey_to_mymodel = factory.SubFactory(MyModelFactory) MyOtherModelFactory.build() # Breaks The error message is: Cannot assign "MyModel()": "MyModel" instance isn't saved in the database. See https://code.djangoproject.com/ticket/10811 for details. --- docs/orms.rst | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'docs') diff --git a/docs/orms.rst b/docs/orms.rst index 5105e66..bbe91e6 100644 --- a/docs/orms.rst +++ b/docs/orms.rst @@ -40,6 +40,14 @@ All factories for a Django :class:`~django.db.models.Model` should use the once all post-generation hooks have run. +.. note:: Starting with Django 1.8, it is no longer possible to call ``.build()`` + on a factory if this factory uses a :class:`~factory.SubFactory` pointing + to another model: Django refuses to set a :class:`~djang.db.models.ForeignKey` + to an unsaved :class:`~django.db.models.Model` instance. + + See https://code.djangoproject.com/ticket/10811 for details. + + .. class:: DjangoOptions(factory.base.FactoryOptions) The ``class Meta`` on a :class:`~DjangoModelFactory` supports extra parameters: -- cgit v1.2.3 From fa6d60d17ddb7b70c6bc2337d901ef8cc924e67b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Wed, 20 May 2015 23:24:45 +0200 Subject: Add Meta.rename to handle name conflicts (See #206). Define ``Meta.rename = {'attrs': 'attributes'}`` if your model expects a ``attributes`` kwarg but you can't define it since it's already reserved by the ``Factory`` class. --- docs/changelog.rst | 9 +++++++++ docs/reference.rst | 23 ++++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/changelog.rst b/docs/changelog.rst index 8f63567..cd5d281 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,6 +1,15 @@ ChangeLog ========= +.. _v2.6.0: + +2.6.0 (XXXX-XX-XX) +------------------ + +*New:* + + - Add :attr:`factory.FactoryOptions.rename` to help handle conflicting names (:issue:`206`) + .. _v2.5.2: 2.5.2 (2015-04-21) diff --git a/docs/reference.rst b/docs/reference.rst index 44f78b6..0705ca2 100644 --- a/docs/reference.rst +++ b/docs/reference.rst @@ -106,6 +106,28 @@ The :class:`Factory` class .. versionadded:: 2.4.0 + .. attribute:: rename + + Sometimes, a model expect a field with a name already used by one + of :class:`Factory`'s methods. + + In this case, the :attr:`rename` attributes allows to define renaming + rules: the keys of the :attr:`rename` dict are those used in the + :class:`Factory` declarations, and their values the new name: + + .. code-block:: python + + class ImageFactory(factory.Factory): + # The model expects "attributes" + form_attributes = ['thumbnail', 'black-and-white'] + + class Meta: + model = Image + rename = {'form_attributes': 'attributes'} + + .. versionadded: 2.6.0 + + .. attribute:: strategy Use this attribute to change the strategy used by a :class:`Factory`. @@ -229,7 +251,6 @@ The :class:`Factory` class .. OHAI_VIM** - .. classmethod:: _setup_next_sequence(cls) This method will compute the first value to use for the sequence counter -- cgit v1.2.3 From 939796a915d66722b0c3a286a12c88757d4eb137 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Wed, 20 May 2015 23:32:33 +0200 Subject: Fix typo in docs/fuzzy (Closes #207). Thanks to @nikolas for spotting it! --- docs/fuzzy.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/fuzzy.rst b/docs/fuzzy.rst index 18978e4..af5c490 100644 --- a/docs/fuzzy.rst +++ b/docs/fuzzy.rst @@ -368,6 +368,6 @@ and provides a few helpers for this: Custom :class:`BaseFuzzyAttribute` subclasses **SHOULD** -use :obj:`factory.fuzzy._random` foras a randomness source; this ensures that +use :obj:`factory.fuzzy._random` as a randomness source; this ensures that data they generate can be regenerated using the simple state from :meth:`get_random_state`. -- cgit v1.2.3 From 6f37f9be2d2e1bc75340068911db18b2bbcbe722 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Fri, 22 May 2015 20:24:13 +0200 Subject: Add factory.Faker() This relies on the ``fake-factory`` library, and provides realistic random values for most field types. --- docs/changelog.rst | 2 ++ docs/reference.rst | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) (limited to 'docs') diff --git a/docs/changelog.rst b/docs/changelog.rst index cd5d281..886db0b 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -9,6 +9,8 @@ ChangeLog *New:* - Add :attr:`factory.FactoryOptions.rename` to help handle conflicting names (:issue:`206`) + - Add support for random-yet-realistic values through `fake-factory `_, + through the :class:`factory.Faker` class. .. _v2.5.2: diff --git a/docs/reference.rst b/docs/reference.rst index 0705ca2..a168de5 100644 --- a/docs/reference.rst +++ b/docs/reference.rst @@ -474,6 +474,66 @@ factory_boy supports two main strategies for generating instances, plus stubs. Declarations ------------ + +Faker +""""" + +.. class:: Faker(provider, locale=None, **kwargs) + + .. OHAIVIM** + + In order to easily define realistic-looking factories, + use the :class:`Faker` attribute declaration. + + This is a wrapper around `fake-factory `_; + its argument is the name of a ``fake-factory`` provider: + + .. code-block:: python + + class UserFactory(factory.Factory): + class Meta: + model = User + + first_name = factory.Faker('name') + + .. code-block:: pycon + + >>> user = UserFactory() + >>> user.name + 'Lucy Cechtelar' + + + .. attribute:: locale + + If a custom locale is required for one specific field, + use the ``locale`` parameter: + + .. code-block:: python + + class UserFactory(factory.Factory): + class Meta: + model = User + + first_name = factory.Faker('name', locale='fr_FR') + + .. code-block:: pycon + + >>> user = UserFactory() + >>> user.name + 'Jean Valjean' + + + .. classmethod:: override_default_locale(cls, locale) + + If the locale needs to be overridden for a whole test, + use :meth:`~factory.Faker.override_default_locale`: + + .. code-block:: pycon + + >>> with factory.Faker.override_default_locale('de_DE'): + ... UserFactory() + + LazyAttribute """"""""""""" -- cgit v1.2.3 From ebc89520d3f7589da35d4e7b78637fbe7d4d664a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Sun, 24 May 2015 18:21:04 +0200 Subject: Add lazy loading to factory.Iterator. factory.Iterator no longers begins iteration of its argument on declaration, since this behavior may trigger database query when that argument is, for instance, a Django queryset. The ``factory.Iterator``'s argument will only be called when the containing ``Factory`` is first evaluated; this means that factories using ``factory.Iterator(models.MyThingy.objects.all())`` will no longer call the database at import time. --- docs/changelog.rst | 3 +++ docs/recipes.rst | 23 +++++++++++++++++++++++ 2 files changed, 26 insertions(+) (limited to 'docs') diff --git a/docs/changelog.rst b/docs/changelog.rst index 886db0b..0cbd4af 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -11,6 +11,9 @@ ChangeLog - Add :attr:`factory.FactoryOptions.rename` to help handle conflicting names (:issue:`206`) - Add support for random-yet-realistic values through `fake-factory `_, through the :class:`factory.Faker` class. + - :class:`factory.Iterator` no longer begins iteration of its argument at import time, + thus allowing to pass in a lazy iterator such as a Django queryset + (i.e ``factory.Iterator(models.MyThingy.objects.all())``). .. _v2.5.2: diff --git a/docs/recipes.rst b/docs/recipes.rst index 70eca46..3cbe6d2 100644 --- a/docs/recipes.rst +++ b/docs/recipes.rst @@ -33,6 +33,29 @@ use the :class:`~factory.SubFactory` declaration: group = factory.SubFactory(GroupFactory) +Choosing from a populated table +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If the target of the :class:`~django.db.models.ForeignKey` should be +chosen from a pre-populated table +(e.g :class:`django.contrib.contenttypes.models.ContentType`), +simply use a :class:`factory.Iterator` on the chosen queryset: + +.. code-block:: python + + import factory, factory.django + from . import models + + class UserFactory(factory.django.DjangoModelFactory): + class Meta: + model = models.User + + language = factory.Iterator(models.Language.objects.all()) + +Here, ``models.Language.objects.all()`` won't be evaluated until the +first call to ``UserFactory``; thus avoiding DB queries at import time. + + Reverse dependencies (reverse ForeignKey) ----------------------------------------- -- cgit v1.2.3 From e9851a7d51afffea2a5679934ad6284c0835cfa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Sun, 31 May 2015 10:15:27 +0100 Subject: Docs: fix minor typo. As spotted by @proofit404 --- docs/reference.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/docs/reference.rst b/docs/reference.rst index a168de5..4c7f8f7 100644 --- a/docs/reference.rst +++ b/docs/reference.rst @@ -494,7 +494,7 @@ Faker class Meta: model = User - first_name = factory.Faker('name') + name = factory.Faker('name') .. code-block:: pycon @@ -514,7 +514,7 @@ Faker class Meta: model = User - first_name = factory.Faker('name', locale='fr_FR') + name = factory.Faker('name', locale='fr_FR') .. code-block:: pycon -- cgit v1.2.3 From 0b5270eab393fad20faa7a6a9720af18c97b1773 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Sun, 31 May 2015 10:47:28 +0100 Subject: Properly handle custom Django managers (Closes #201). The actual behavior of Django with custom managers and inherited abstract models is rather complex, so this had to be adapted to the actual Django source code. --- docs/changelog.rst | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'docs') diff --git a/docs/changelog.rst b/docs/changelog.rst index 0cbd4af..c871ce8 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -15,6 +15,10 @@ ChangeLog thus allowing to pass in a lazy iterator such as a Django queryset (i.e ``factory.Iterator(models.MyThingy.objects.all())``). +*Bugfix:* + + - :issue:`201`: Properly handle custom Django managers when dealing with abstract Django models. + .. _v2.5.2: 2.5.2 (2015-04-21) -- cgit v1.2.3 From 9246fa6d26ca655c02ae37bbfc389d9f34dfba16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Sun, 31 May 2015 10:57:53 +0100 Subject: Improve ORM layer import paths (Closes #186). You may now use the following code: import factory factory.alchemy.SQLAlchemyModelFactory factory.django.DjangoModelFactory factory.mongoengine.MongoEngineFactory --- docs/changelog.rst | 2 ++ docs/orms.rst | 31 ++++++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/changelog.rst b/docs/changelog.rst index c871ce8..eea38c5 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -14,6 +14,8 @@ ChangeLog - :class:`factory.Iterator` no longer begins iteration of its argument at import time, thus allowing to pass in a lazy iterator such as a Django queryset (i.e ``factory.Iterator(models.MyThingy.objects.all())``). + - Simplify imports for ORM layers, now available through a simple ``factory`` import, + at ``factory.alchemy.SQLAlchemyModelFactory`` / ``factory.django.DjangoModelFactory`` / ``factory.mongoengine.MongoEngineFactory``. *Bugfix:* diff --git a/docs/orms.rst b/docs/orms.rst index bbe91e6..26390b5 100644 --- a/docs/orms.rst +++ b/docs/orms.rst @@ -273,6 +273,34 @@ factory_boy supports `MongoEngine`_-style models, through the :class:`MongoEngin This feature makes it possible to use :class:`~factory.SubFactory` to create embedded document. +A minimalist example: + +.. code-block:: python + + import mongoengine + + class Address(mongoengine.EmbeddedDocument): + street = mongoengine.StringField() + + class Person(mongoengine.Document): + name = mongoengine.StringField() + address = mongoengine.EmbeddedDocumentField(Address) + + import factory + + class AddressFactory(factory.mongoengine.MongoEngineFactory): + class Meta: + model = Address + + street = factory.Sequence(lambda n: 'street%d' % n) + + class PersonFactory(factory.mongoengine.MongoEngineFactory): + class Meta: + model = Person + + name = factory.Sequence(lambda n: 'name%d' % n) + address = factory.SubFactory(AddressFactory) + SQLAlchemy ---------- @@ -327,8 +355,9 @@ A (very) simple example: Base.metadata.create_all(engine) + import factory - class UserFactory(SQLAlchemyModelFactory): + class UserFactory(factory.alchemy.SQLAlchemyModelFactory): class Meta: model = User sqlalchemy_session = session # the SQLAlchemy session object -- cgit v1.2.3 From d471c1b4b0d4b06d557b5b6a9349a7dc55515d69 Mon Sep 17 00:00:00 2001 From: Ilya Baryshev Date: Thu, 2 Jul 2015 23:44:37 +0300 Subject: Fix mute_signals behavior for signals with caching Connecting signals (with use_caching=True) inside mute_signals was breaking unmute on exit. Paused receivers were not running. This was caused by signal cache not being restored after unpatching. Workaround is to clear signal cache on exit. Fixes #212 --- docs/changelog.rst | 1 + 1 file changed, 1 insertion(+) (limited to 'docs') diff --git a/docs/changelog.rst b/docs/changelog.rst index eea38c5..01d5775 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -20,6 +20,7 @@ ChangeLog *Bugfix:* - :issue:`201`: Properly handle custom Django managers when dealing with abstract Django models. + - :issue:`212`: Fix :meth:`factory.django.mute_signals` to handle Django's signal caching .. _v2.5.2: -- cgit v1.2.3 From 197555d3d0de4759ca9ad45d5986fdcc4aa4c15b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Sat, 25 Jul 2015 14:19:12 +0200 Subject: Docs: 'import factory.fuzzy' as required (See #138). --- docs/fuzzy.rst | 2 ++ 1 file changed, 2 insertions(+) (limited to 'docs') diff --git a/docs/fuzzy.rst b/docs/fuzzy.rst index af5c490..6b06608 100644 --- a/docs/fuzzy.rst +++ b/docs/fuzzy.rst @@ -8,6 +8,8 @@ Some tests may be interested in testing with fuzzy, random values. This is handled by the :mod:`factory.fuzzy` module, which provides a few random declarations. +.. note:: Use ``import factory.fuzzy`` to load this module. + FuzzyAttribute -------------- -- cgit v1.2.3 From 15f328350311ee46f84c628310e58e4ed8b49e13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Tue, 20 Oct 2015 23:08:29 +0200 Subject: Docs: Document Faker.add_provider (Closes #218) --- docs/reference.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'docs') diff --git a/docs/reference.rst b/docs/reference.rst index 4c7f8f7..3a57c66 100644 --- a/docs/reference.rst +++ b/docs/reference.rst @@ -534,6 +534,23 @@ Faker ... UserFactory() + .. classmethod:: add_provider(cls, locale=None) + + Some projects may need to fake fields beyond those provided by ``fake-factory``; + in such cases, use :meth:`factory.Faker.add_provider` to declare additional providers + for those fields: + + .. code-block:: python + + factory.Faker.add_provider(SmileyProvider) + + class FaceFactory(factory.Factory): + class Meta: + model = Face + + smiley = factory.Faker('smiley') + + LazyAttribute """"""""""""" -- cgit v1.2.3 From f30c7b243a112eb07af0bcddbd9a211596ed80d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Tue, 20 Oct 2015 23:18:22 +0200 Subject: Lazy load django's get_model (Closes #228). Loading this function will, on pre-1.8 versions, load Django settings. We'll lazy-load it to avoid crashes when Django hasn't been configured yet (e.g in auto-discovery test setups). --- docs/changelog.rst | 1 + 1 file changed, 1 insertion(+) (limited to 'docs') diff --git a/docs/changelog.rst b/docs/changelog.rst index 01d5775..24c01aa 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -21,6 +21,7 @@ ChangeLog - :issue:`201`: Properly handle custom Django managers when dealing with abstract Django models. - :issue:`212`: Fix :meth:`factory.django.mute_signals` to handle Django's signal caching + - :issue:`228`: Don't load :func:`django.apps.apps.get_model()` until required .. _v2.5.2: -- cgit v1.2.3 From 1e1adebe92397b405563dc141c853f62feca6c82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Tue, 20 Oct 2015 23:21:33 +0200 Subject: Docs: Fix typo in M2M recipes (Closes #226) As spotted by @stephane, thanks! --- docs/recipes.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'docs') diff --git a/docs/recipes.rst b/docs/recipes.rst index 3cbe6d2..df86bac 100644 --- a/docs/recipes.rst +++ b/docs/recipes.rst @@ -148,8 +148,8 @@ factory_boy related factories. method. -Simple ManyToMany ------------------ +Simple Many-to-many relationship +-------------------------------- Building the adequate link between two models depends heavily on the use case; factory_boy doesn't provide a "all in one tools" as for :class:`~factory.SubFactory` @@ -167,7 +167,7 @@ hook: class User(models.Model): name = models.CharField() - groups = models.ManyToMany(Group) + groups = models.ManyToManyField(Group) # factories.py @@ -204,8 +204,8 @@ the ``groups`` declaration will add passed in groups to the set of groups for th user. -ManyToMany with a 'through' ---------------------------- +Many-to-many relation with a 'through' +-------------------------------------- If only one link is required, this can be simply performed with a :class:`RelatedFactory`. @@ -219,7 +219,7 @@ If more links are needed, simply add more :class:`RelatedFactory` declarations: class Group(models.Model): name = models.CharField() - members = models.ManyToMany(User, through='GroupLevel') + members = models.ManyToManyField(User, through='GroupLevel') class GroupLevel(models.Model): user = models.ForeignKey(User) -- cgit v1.2.3 From dc7d02095fff8124aaeccf8f08958fa6797b6ce6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Tue, 20 Oct 2015 23:26:52 +0200 Subject: mogo: Stop using deprecated .new (Closes #219) This method has been deprecated in `mogo.model.Model` since 2012. Thanks to @federicobond for spotting this! --- docs/changelog.rst | 1 + 1 file changed, 1 insertion(+) (limited to 'docs') diff --git a/docs/changelog.rst b/docs/changelog.rst index 24c01aa..d38c06a 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -22,6 +22,7 @@ ChangeLog - :issue:`201`: Properly handle custom Django managers when dealing with abstract Django models. - :issue:`212`: Fix :meth:`factory.django.mute_signals` to handle Django's signal caching - :issue:`228`: Don't load :func:`django.apps.apps.get_model()` until required + - :issue:`219`: Stop using :meth:`mogo.model.Model.new()`, deprecated 4 years ago. .. _v2.5.2: -- cgit v1.2.3 From 41bbff4701ac857bf6c468a4dc53836ee85baa11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Tue, 20 Oct 2015 23:30:18 +0200 Subject: Update note on django's unsaved instance checks This note was added to document a regression in Django 1.8.0; the regression has been fixed in 1.8.4. Closes #232 --- docs/orms.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'docs') diff --git a/docs/orms.rst b/docs/orms.rst index 26390b5..9b209bc 100644 --- a/docs/orms.rst +++ b/docs/orms.rst @@ -40,12 +40,12 @@ All factories for a Django :class:`~django.db.models.Model` should use the once all post-generation hooks have run. -.. note:: Starting with Django 1.8, it is no longer possible to call ``.build()`` - on a factory if this factory uses a :class:`~factory.SubFactory` pointing - to another model: Django refuses to set a :class:`~djang.db.models.ForeignKey` +.. note:: With Django versions 1.8.0 to 1.8.3, it was no longer possible to call ``.build()`` + on a factory if this factory used a :class:`~factory.SubFactory` pointing + to another model: Django refused to set a :class:`~djang.db.models.ForeignKey` to an unsaved :class:`~django.db.models.Model` instance. - See https://code.djangoproject.com/ticket/10811 for details. + See https://code.djangoproject.com/ticket/10811 and https://code.djangoproject.com/ticket/25160 for details. .. class:: DjangoOptions(factory.base.FactoryOptions) -- cgit v1.2.3 From 72751aef7b4ba519575bbd8bd4b40864fdf5158e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Tue, 20 Oct 2015 23:41:02 +0200 Subject: Ideas: I want to be able to nest declarations Closes #140, as this won't be implemented in the next few weeks. --- docs/ideas.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/ideas.rst b/docs/ideas.rst index f3c9e62..6e3962d 100644 --- a/docs/ideas.rst +++ b/docs/ideas.rst @@ -6,4 +6,4 @@ This is a list of future features that may be incorporated into factory_boy: * 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 - +* Properly evaluate nested declarations (e.g ``factory.fuzzy.FuzzyDate(start_date=factory.SelfAttribute('since'))``) -- cgit v1.2.3 From 5ae2055fe474fbd2a5c5b5a92515bc0affcf9e9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Wed, 21 Oct 2015 00:12:26 +0200 Subject: docs: Note 2.6.0 release date. --- docs/changelog.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/changelog.rst b/docs/changelog.rst index d38c06a..32d8da6 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -3,7 +3,7 @@ ChangeLog .. _v2.6.0: -2.6.0 (XXXX-XX-XX) +2.6.0 (2015-10-20) ------------------ *New:* -- cgit v1.2.3 From be85908f5205810083c524a25c7da565788f2c03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Sat, 7 Nov 2015 10:08:47 +0100 Subject: Fix obsolete text in docs (Closes #245, #248, #249). Thanks a lot to Jeff Widman for spotting them! --- docs/changelog.rst | 2 -- docs/reference.rst | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'docs') diff --git a/docs/changelog.rst b/docs/changelog.rst index 32d8da6..fa542f4 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -131,8 +131,6 @@ This takes care of all ``FACTORY_FOR`` occurences; the files containing other at 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` diff --git a/docs/reference.rst b/docs/reference.rst index 3a57c66..6398d9a 100644 --- a/docs/reference.rst +++ b/docs/reference.rst @@ -634,7 +634,7 @@ This declaration takes a single argument, a function accepting a single paramete .. note:: An extra kwarg argument, ``type``, may be provided. - This feature is deprecated in 1.3.0 and will be removed in 2.0.0. + This feature was deprecated in 1.3.0 and will be removed in 2.0.0. .. code-block:: python -- cgit v1.2.3 From 05082c661655df319ce641dd7976c02d1799ab14 Mon Sep 17 00:00:00 2001 From: mluszczyk Date: Mon, 28 Dec 2015 13:06:13 +0100 Subject: Fixed spelling. --- docs/orms.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/orms.rst b/docs/orms.rst index 9b209bc..0afda69 100644 --- a/docs/orms.rst +++ b/docs/orms.rst @@ -15,7 +15,7 @@ Django The first versions of factory_boy were designed specifically for Django, -but the library has now evolved to be framework-independant. +but the library has now evolved to be framework-independent. Most features should thus feel quite familiar to Django users. -- cgit v1.2.3 From 4172dd686ce483191b33e3189d716f11b3da921e Mon Sep 17 00:00:00 2001 From: Alejandro Date: Wed, 6 Jan 2016 19:36:10 -0300 Subject: optional forced flush on SQLAlchemyModelFactory fixes rbarrois/factory_boy#81 --- docs/orms.rst | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'docs') diff --git a/docs/orms.rst b/docs/orms.rst index 9b209bc..bd481bd 100644 --- a/docs/orms.rst +++ b/docs/orms.rst @@ -333,6 +333,10 @@ To work, this class needs an `SQLAlchemy`_ session object affected to the :attr: SQLAlchemy session to use to communicate with the database when creating an object through this :class:`SQLAlchemyModelFactory`. + .. attribute:: force_flush + + Force a session flush() at the end of :func:`~factory.alchemy.SQLAlchemyModelFactory._create()`. + A (very) simple example: .. code-block:: python -- cgit v1.2.3 From 229d43874723f36b380eb49e53538bf21511fa5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Tue, 9 Feb 2016 23:57:31 +0100 Subject: Clarify the use of SelfAttribute in RelatedFactory (Closes #264) --- docs/reference.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'docs') diff --git a/docs/reference.rst b/docs/reference.rst index 6398d9a..b5ccd16 100644 --- a/docs/reference.rst +++ b/docs/reference.rst @@ -1412,6 +1412,23 @@ If a value if passed for the :class:`RelatedFactory` attribute, this disables 1 +.. note:: The target of the :class:`RelatedFactory` is evaluated *after* the initial factory has been instantiated. + This means that calls to :class:`factory.SelfAttribute` cannot go higher than this :class:`RelatedFactory`: + + .. code-block:: python + + class CountryFactory(factory.Factory): + class Meta: + model = Country + + lang = 'fr' + capital_city = factory.RelatedFactory(CityFactory, 'capital_of', + # factory.SelfAttribute('..lang') will crash, since the context of + # ``CountryFactory`` has already been evaluated. + main_lang=factory.SelfAttribute('capital_of.lang'), + ) + + PostGeneration """""""""""""" -- cgit v1.2.3 From 2eb8242a31f303d36c15b4644c54afb2cef8257e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Tue, 9 Feb 2016 23:58:01 +0100 Subject: doc: Use ReadTheDocs theme for local doc builds. --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/conf.py b/docs/conf.py index c3512e0..d5b86f4 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -114,7 +114,7 @@ pygments_style = 'sphinx' # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'default' +html_theme = 'sphinx_rtd_theme' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the -- cgit v1.2.3 From efd5c65b99a31992001a9581a41ec4627c4d94fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Barrois?= Date: Wed, 10 Feb 2016 00:15:52 +0100 Subject: Clarify precedence on factory.django.FileField (Closes #257). When both ``from_file`` and ``filename`` are provided, ``filename`` takes precedence. Thanks to @darkowic for spotting this :) --- docs/orms.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/orms.rst b/docs/orms.rst index bd481bd..d1b30fc 100644 --- a/docs/orms.rst +++ b/docs/orms.rst @@ -126,7 +126,7 @@ Extra fields :param str from_path: Use data from the file located at ``from_path``, and keep its filename :param file from_file: Use the contents of the provided file object; use its filename - if available + if available, unless ``filename`` is also provided. :param bytes data: Use the provided bytes as file contents :param str filename: The filename for the FileField -- cgit v1.2.3