-
Notifications
You must be signed in to change notification settings - Fork 408
Description
Description
When using factory.SelfAttribute
to set the value of a field to the value of a nested attribute from a factory.SubFactory
field that is a factory.DictFactory
, the evaluation of SelfAttribute
fails with a AttributeError
:
AttributeError: 'dict' object has no attribute 'last_name'
To Reproduce
Run the code below
Model / Factory code
import factory
class ChildFactory(factory.DictFactory):
first_name = factory.Faker("first_name")
last_name = factory.Faker("last_name")
class ParentFactory(factory.DictFactory):
child = factory.SubFactory(ChildFactory)
last_name = factory.SelfAttribute("child.last_name")
parent = ParentFactory()
The issue
This code sets up the ParentFactory.last_name
to be a factory.SelfAttribute
of ParentFactory.child.last_name
. This succeeds if a regular python class is used as the model instead of a dict.
Python 3.13.3 (main, May 21 2025, 10:47:46) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import factory
...
... class ChildFactory(factory.DictFactory):
...
... first_name = factory.Faker("first_name")
... last_name = factory.Faker("last_name")
...
...
... class ParentFactory(factory.DictFactory):
...
... child = factory.SubFactory(ChildFactory)
... last_name = factory.SelfAttribute("child.last_name")
...
... parent = ParentFactory()
...
Traceback (most recent call last):
File "<python-input-0>", line 14, in <module>
parent = ParentFactory()
File "/home/rccausey/.cache/pypoetry/virtualenvs/billing-api--M5yUIBR-py3.13/lib/python3.13/site-packages/factory/base.py", line 43, in __call__
return cls.create(**kwargs)
~~~~~~~~~~^^^^^^^^^^
File "/home/rccausey/.cache/pypoetry/virtualenvs/billing-api--M5yUIBR-py3.13/lib/python3.13/site-packages/factory/base.py", line 539, in create
return cls._generate(enums.CREATE_STRATEGY, kwargs)
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/rccausey/.cache/pypoetry/virtualenvs/billing-api--M5yUIBR-py3.13/lib/python3.13/site-packages/factory/base.py", line 468, in _generate
return step.build()
~~~~~~~~~~^^
File "/home/rccausey/.cache/pypoetry/virtualenvs/billing-api--M5yUIBR-py3.13/lib/python3.13/site-packages/factory/builder.py", line 270, in build
step.resolve(pre)
~~~~~~~~~~~~^^^^^
File "/home/rccausey/.cache/pypoetry/virtualenvs/billing-api--M5yUIBR-py3.13/lib/python3.13/site-packages/factory/builder.py", line 211, in resolve
self.attributes[field_name] = getattr(self.stub, field_name)
~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^
File "/home/rccausey/.cache/pypoetry/virtualenvs/billing-api--M5yUIBR-py3.13/lib/python3.13/site-packages/factory/builder.py", line 356, in __getattr__
value = value.evaluate_pre(
instance=self,
step=self.__step,
overrides=declaration.context,
)
File "/home/rccausey/.cache/pypoetry/virtualenvs/billing-api--M5yUIBR-py3.13/lib/python3.13/site-packages/factory/declarations.py", line 67, in evaluate_pre
return self.evaluate(instance, step, context)
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/rccausey/.cache/pypoetry/virtualenvs/billing-api--M5yUIBR-py3.13/lib/python3.13/site-packages/factory/declarations.py", line 228, in evaluate
return deepgetattr(target, self.attribute_name, self.default)
File "/home/rccausey/.cache/pypoetry/virtualenvs/billing-api--M5yUIBR-py3.13/lib/python3.13/site-packages/factory/declarations.py", line 188, in deepgetattr
return deepgetattr(getattr(obj, attr), subname, default)
File "/home/rccausey/.cache/pypoetry/virtualenvs/billing-api--M5yUIBR-py3.13/lib/python3.13/site-packages/factory/declarations.py", line 190, in deepgetattr
return getattr(obj, name)
AttributeError: 'dict' object has no attribute 'last_name'
Notes
Direct self attribute access on the model being created works fine. For example:
>>> class ExampleFactory(factory.DictFactory):
...
... foo = "foo"
... bar = factory.SelfAttribute("foo")
...
>>> ExampleFactory()
{'foo': 'foo', 'bar': 'foo'}
The error only appears when attempting to get a nested attribute from an attribute that is a factory.SubFactory
of a factory.DictFactory
. My suspicion is that the deepgetattr
code is not set up to handle the case where a nested object field is a dictionary.
Seen in FactoryBoy version 3.3.3