Repository: FactoryBoy/factory_boy
Pull request #588 (2019-04-08 16:16:42)

Fix a bug when overriding Params in a Trait
When a factory defines a Params attribute and a Trait in which this attribute is overriden, the override of the trait is ignored.


```
class TruckFactory(factory.Factory):
    weight = factory.LazyAttribute()

```

The `Trait` is created when the Factory class is built and the `SimpleParameter` are built later at `contribute_to_class`, and they get a higher creation counter 
To fix, I update the creation counter so that the `Trait` gets ordered after the `SimpleParameter`


Patch:
diff --git a/docs/changelog.rst b/docs/changelog.rst
index d3cce2f..8e02f33 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -1,7 +1,13 @@
 ChangeLog
 =========
 
-2.11.2 (unreleased)
+2.12.1 (unreleased)
+-------------------
+
+- Nothing changed yet.
+
+
+2.12.0 (2019-05-11)
 -------------------
 
 *New:*
@@ -12,6 +18,7 @@ ChangeLog
       the behavior of ``getter`` in :class:`~factory.Iterator`
     - Make the ``extra_kwargs`` parameter of :meth:`~factory.faker.Faker.generate` optional
     - Add :class:`~factory.RelatedFactoryList` class for one-to-many support, thanks `Sean Harrington <https://github.com/seanharr11>`_.
+    - Make the `locale` argument for :class:`~factory.faker.Faker` keyword-only
 
 *Bugfix:*
 
diff --git a/docs/examples.rst b/docs/examples.rst
index 6f26b7e..c8c5cb4 100644
--- a/docs/examples.rst
+++ b/docs/examples.rst
@@ -13,9 +13,10 @@ First, let's define a couple of objects:
 .. code-block:: python
 
     class Account(object):
-        def __init__(self, username, email):
+        def __init__(self, username, email, date_joined):
             self.username = username
             self.email = email
+            self.date_joined = date_joined
 
         def __str__(self):
             return '%s (%s)' % (self.username, self.email)
@@ -38,7 +39,7 @@ First, let's define a couple of objects:
             return u'%s %s (%s)' % (
                 unicode(self.firstname),
                 unicode(self.lastname),
-                unicode(self.account.accountname),
+                unicode(self.account.username),
             )
 
 Factories
diff --git a/docs/reference.rst b/docs/reference.rst
index 3026503..0c97a80 100644
--- a/docs/reference.rst
+++ b/docs/reference.rst
@@ -1752,9 +1752,14 @@ RelatedFactoryList
 
     .. attribute:: size
 
-        Either an ``int``, or a ``lambda`` that returns an ``int``, which will define the number 
+        Either an ``int``, or a ``lambda`` that returns an ``int``, which will define the number
         of related Factories to be generated for each parent object.
 
+   .. versionadded:: 2.12
+
+        Note that the API for :class:`RelatedFactoryList` is considered experimental, and might change
+        in a future version for increased consistency with other declarations.
+
 .. note::
           Note that using a ``lambda`` for :attr:`size` allows the number of related objects per
           parents object to vary. This is useful for testing, when you likely don't want your mock
diff --git a/examples/django_demo/generic_foreignkey/models.py b/examples/django_demo/generic_foreignkey/models.py
index efaa23d..78fd427 100644
--- a/examples/django_demo/generic_foreignkey/models.py
+++ b/examples/django_demo/generic_foreignkey/models.py
@@ -6,7 +6,7 @@ from django.contrib.contenttypes.fields import GenericForeignKey
 
 
 class TaggedItem(models.Model):
-    """Example GenericForeinKey model from django docs"""
+    """Example GenericForeignKey model from django docs"""
     tag = models.SlugField()
     content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
     object_id = models.PositiveIntegerField()
diff --git a/factory/__init__.py b/factory/__init__.py
index 1d3c87b..b4ea92b 100644
--- a/factory/__init__.py
+++ b/factory/__init__.py
@@ -75,7 +75,7 @@ from . import mogo
 from . import mongoengine
 
 
-__version__ = '2.11.2.dev0'
+__version__ = '2.12.1.dev0'
 __author__ = 'Raphaël Barrois <raphael.barrois+fboy@polytechnique.org>'
 
 
diff --git a/factory/declarations.py b/factory/declarations.py
index 1100233..18c5452 100644
--- a/factory/declarations.py
+++ b/factory/declarations.py
@@ -545,6 +545,7 @@ class SimpleParameter(Parameter):
     def wrap(cls, value):
         if not isinstance(value, Parameter):
             return cls(value)
+        value.touch_creation_counter()
         return value
 
 
diff --git a/factory/faker.py b/factory/faker.py
index f1847cf..7bb2752 100644
--- a/factory/faker.py
+++ b/factory/faker.py
@@ -39,11 +39,11 @@ class Faker(declarations.BaseDeclaration):
     Usage:
         >>> foo = factory.Faker('name')
     """
-    def __init__(self, provider, locale=None, **kwargs):
+    def __init__(self, provider, **kwargs):
         super(Faker, self).__init__()
         self.provider = provider
         self.provider_kwargs = kwargs
-        self.locale = locale
+        self.locale = kwargs.pop('locale', None)
 
     def generate(self, extra_kwargs=None):
         kwargs = {}
diff --git a/factory/utils.py b/factory/utils.py
index a3ad2a2..f2b7aa5 100644
--- a/factory/utils.py
+++ b/factory/utils.py
@@ -98,13 +98,16 @@ class OrderedBase(object):
     def __init__(self, **kwargs):
         super(OrderedBase, self).__init__(**kwargs)
         if type(self) is not OrderedBase:
-            bases = type(self).__mro__
-            root = bases[bases.index(OrderedBase) - 1]
-            if not hasattr(root, self.CREATION_COUNTER_FIELD):
-                setattr(root, self.CREATION_COUNTER_FIELD, 0)
-            next_counter = getattr(self, self.CREATION_COUNTER_FIELD)
-            setattr(self, self.CREATION_COUNTER_FIELD, next_counter)
-            setattr(root, self.CREATION_COUNTER_FIELD, next_counter + 1)
+            self.touch_creation_counter()
+
+    def touch_creation_counter(self):
+        bases = type(self).__mro__
+        root = bases[bases.index(OrderedBase) - 1]
+        if not hasattr(root, self.CREATION_COUNTER_FIELD):
+            setattr(root, self.CREATION_COUNTER_FIELD, 0)
+        next_counter = getattr(root, self.CREATION_COUNTER_FIELD)
+        setattr(self, self.CREATION_COUNTER_FIELD, next_counter)
+        setattr(root, self.CREATION_COUNTER_FIELD, next_counter + 1)
 
 
 def sort_ordered_objects(items, getter=lambda x: x):


Test patch:
diff --git a/tests/test_using.py b/tests/test_using.py
index 448f443..cee2b4c 100644
--- a/tests/test_using.py
+++ b/tests/test_using.py
@@ -1331,6 +1331,21 @@ class TraitTestCase(unittest.TestCase):
             dict(one=None, two=None, three=None, four=None, five=None),
         )
 
+    def test_traits_override_params(self):
+        """Override a Params value in a trait"""
+        class TestObjectFactory(factory.Factory):
+            class Meta:
+                model = TestObject
+
+            one = factory.LazyAttribute(lambda o: o.zero + 1)
+
+            class Params:
+                zero = 0
+                plus_one = factory.Trait(zero=1)
+
+        obj = TestObjectFactory(plus_one=True)
+        self.assertEqual(obj.one, 2)
+
     def test_traits_override(self):
         """Override a trait in a subclass."""
         class TestObjectFactory(factory.Factory):