Factory and mutable values - changing the object changes values inside Factory
Hello, I couldn't find any topic about behavior like this so I create a new one. I found this because I started to write some tests for a django project which uses postgresql Jsonb fields.
Every time I change the instance of an object created with Traits, the Factory parameters are change too and all newly created instances have this changed values
Here is a simplified example
import factory
class A:
def __init__(self, json_field):
self.json_field = json_field
class AFactory(factory.Factory):
class Meta:
model = A
json_field = {'text': 'hello'}
class Params:
prefilled = factory.Trait(
json_field={
'props': [100, 101, 102, 103, 104],
'str_property': 'hello',
}
)
if __name__ == '__main__':
item_one = AFactory(prefilled=True)
print('Item one json_field [created]: {}'.format(item_one.json_field))
item_one.json_field['props'][0] = 999
item_one.json_field['str_property'] = 'Goodbye!'
print('Item one json_field [changed]: {}'.format(item_one.json_field))
item_two = AFactory(prefilled=True)
# new instance will have the same json_field as item_one
print('Item two json_field [created]: {}'.format(item_two.json_field))
assert item_one.json_field == item_two.json_field
#without traits
item_three = AFactory()
print('Item three json_field [created]: {}'.format(item_three.json_field))
item_three.json_field['text'] = 'different text'
print('Item three json_field [changed]: {}'.format(item_three.json_field))
item_four = AFactory()
print('Item four json_field [created]: {}'.format(item_four.json_field))
assert item_three.json_field == item_four.json_field
Item one json_field [created]: {'props': [100, 101, 102, 103, 104], 'str_property': 'hello'}
Item one json_field [changed]: {'props': [999, 101, 102, 103, 104], 'str_property': 'Goodbye!'}
Item two json_field [created]: {'props': [999, 101, 102, 103, 104], 'str_property': 'Goodbye!'}
Item three json_field [created]: {'text': 'hello'}
Item three json_field [changed]: {'text': 'different text'}
Item four json_field [created]: {'text': 'different text'}
P.S. at first I wrote about Traits but then I realised that any mutable values assigned inside Factory class are shared between factory and its instances.
I'm not sure is it bug or nor, using mutable objects as default values for a class variables is a very bad idea, and I will change my tests to not to do that.
Hi @wwarne,
Thanks for the report! I don’t think this is a bug, it looks like standard Python behavior. However, it is likely to trip others. Perhaps a note about this gotcha in the Factory class would be useful?
AFAICT, the project does not attempt to copy mutable properties in declarations. Using LazyFunction is encouraged to copy mutable objects.
Perhaps a note about this gotcha in the Factory class would be useful?
I think it would be great!
Using
LazyFunctionis encouraged to copy mutable objects.
Thanks again. I have used LazyFunction and everything is perfectly isolated now.