diff options
-rw-r--r-- | docs/changelog.rst | 1 | ||||
-rw-r--r-- | docs/reference.rst | 31 | ||||
-rw-r--r-- | factory/base.py | 8 | ||||
-rw-r--r-- | factory/containers.py | 13 | ||||
-rw-r--r-- | tests/test_using.py | 16 |
5 files changed, 64 insertions, 5 deletions
diff --git a/docs/changelog.rst b/docs/changelog.rst index 100952c..80074ae 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -14,6 +14,7 @@ ChangeLog - Add support for ``get_or_create`` in :class:`~factory.DjangoModelFactory`, through :attr:`~factory.DjangoModelFactory.FACTORY_DJANGO_GET_OR_CREATE`. - Add support for :mod:`~factory.fuzzy` attribute definitions. + - The :class:`Sequence` counter can be overridden when calling a generating function *Removed:* diff --git a/docs/reference.rst b/docs/reference.rst index a2af327..13220b0 100644 --- a/docs/reference.rst +++ b/docs/reference.rst @@ -502,6 +502,37 @@ sequence counter is shared: '123-555-0003' +Forcing a sequence counter +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If a specific value of the sequence counter is required for one instance, the +``__sequence`` keyword argument should be passed to the factory method. + +This will force the sequence counter during the call, without altering the +class-level value. + +.. code-block:: python + + class UserFactory(factory.Factory): + FACTORY_FOR = User + + uid = factory.Sequence(int) + +.. code-block:: pycon + + >>> UserFactory() + <User: 0> + >>> UserFactory() + <User: 1> + >>> UserFactory(__sequence=42) + <User: 42> + + +.. warning:: The impact of setting ``__sequence=n`` on a ``_batch`` call is + undefined. Each generated instance may share a same counter, or + use incremental values starting from the forced value. + + LazyAttributeSequence """"""""""""""""""""" diff --git a/factory/base.py b/factory/base.py index 13a0623..25f4714 100644 --- a/factory/base.py +++ b/factory/base.py @@ -282,7 +282,13 @@ class BaseFactory(object): applicable; the current list of computed attributes is available to the currently processed object. """ - return containers.AttributeBuilder(cls, extra).build(create) + force_sequence = None + if extra: + force_sequence = extra.pop('__sequence', None) + return containers.AttributeBuilder(cls, extra).build( + create=create, + force_sequence=force_sequence, + ) @classmethod def declarations(cls, extra_defs=None): diff --git a/factory/containers.py b/factory/containers.py index e02f9f9..ee2ad82 100644 --- a/factory/containers.py +++ b/factory/containers.py @@ -236,16 +236,21 @@ class AttributeBuilder(object): attrs_with_subfields, self._attrs) def has_subfields(self, value): - return isinstance(value, declarations.SubFactory) + return isinstance(value, declarations.ParameteredAttribute) - def build(self, create): + def build(self, create, force_sequence=None): """Build a dictionary of attributes. Args: create (bool): whether to 'build' or 'create' the subfactories. + force_sequence (int or None): if set to an int, use this value for + the sequence counter; don't advance the related counter. """ # Setup factory sequence. - self.factory.sequence = self.factory._generate_next_sequence() + if force_sequence is None: + sequence = self.factory._generate_next_sequence() + else: + sequence = force_sequence # Parse attribute declarations, wrapping SubFactory and # OrderedDeclaration. @@ -253,7 +258,7 @@ class AttributeBuilder(object): for k, v in self._attrs.items(): if isinstance(v, declarations.OrderedDeclaration): v = OrderedDeclarationWrapper(v, - sequence=self.factory.sequence, + sequence=sequence, create=create, extra=self._subfields.get(k, {}), ) diff --git a/tests/test_using.py b/tests/test_using.py index dde0ba7..def49e4 100644 --- a/tests/test_using.py +++ b/tests/test_using.py @@ -346,6 +346,22 @@ class UsingFactoryTestCase(unittest.TestCase): self.assertEqual('one43', test_object1.one) self.assertEqual('two43', test_object1.two) + def test_sequence_override(self): + class TestObjectFactory(factory.Factory): + FACTORY_FOR = TestObject + + one = factory.Sequence(lambda n: 'one%d' % n) + + o1 = TestObjectFactory() + o2 = TestObjectFactory() + o3 = TestObjectFactory(__sequence=42) + o4 = TestObjectFactory() + + self.assertEqual('one0', o1.one) + self.assertEqual('one1', o2.one) + self.assertEqual('one42', o3.one) + self.assertEqual('one2', o4.one) + def test_custom_create(self): class TestModelFactory(factory.Factory): FACTORY_FOR = TestModel |