factory_boy
factory_boy copied to clipboard
Regression on 3.2.1 causes RecursionError with django-dirtyfields
Description
A regression done in https://github.com/FactoryBoy/factory_boy/pull/799 causes a RecursionError. After upgrading from 3.2.0 to 3.2.1 the error happened.
To verify that this was really the cause of the issue, I installed 3.2.1 in current dir using pip install factory-boy -t .
, modified these lines back to what it is originally in 3.2.0 and it is working again.
- signal.receivers += receivers
+ signal.receivers = receivers
To Reproduce
Model / Factory code
Here is the model. To add, there are also signal receivers but will not include the full details.
class Company(DirtyFieldsMixin, models.Model):
...
@receiver(post_save, sender=Company)
def my_receiver(instance, raw, **kwargs):
...
class CompanyFactory(DjangoModelFactory): # standard
class Meta:
model = Company
The issue
You can find the error here that happens on instance.save()
.venv/lib/python3.9/site-packages/factory/django.py:173: in _after_postgeneration
instance.save()
src/company/models/company.py:607: in save
return super().save(*args, **kwargs)
.venv/lib/python3.9/site-packages/safedelete/models.py:96: in save
super(SafeDeleteModel, self).save(**kwargs)
.venv/lib/python3.9/site-packages/django/db/models/base.py:726: in save
self.save_base(using=using, force_insert=force_insert,
.venv/lib/python3.9/site-packages/django/db/models/base.py:774: in save_base
post_save.send(
.venv/lib/python3.9/site-packages/django/dispatch/dispatcher.py:180: in send
return [
.venv/lib/python3.9/site-packages/django/dispatch/dispatcher.py:181: in <listcomp>
(receiver, receiver(signal=self, sender=sender, **named))
.venv/lib/python3.9/site-packages/dirtyfields/dirtyfields.py:155: in reset_state
new_state = instance._as_dict(check_relationship=True)
.venv/lib/python3.9/site-packages/dirtyfields/dirtyfields.py:94: in _as_dict
all_field[field.name] = deepcopy(field_value)
/usr/local/lib/python3.9/copy.py:172: in deepcopy
y = _reconstruct(x, memo, *rv)
/usr/local/lib/python3.9/copy.py:270: in _reconstruct
state = deepcopy(state, memo)
/usr/local/lib/python3.9/copy.py:146: in deepcopy
y = copier(x, memo)
/usr/local/lib/python3.9/copy.py:230: in _deepcopy_dict
y[deepcopy(key, memo)] = deepcopy(value, memo)
/usr/local/lib/python3.9/copy.py:172: in deepcopy
y = _reconstruct(x, memo, *rv)
/usr/local/lib/python3.9/copy.py:270: in _reconstruct
state = deepcopy(state, memo)
/usr/local/lib/python3.9/copy.py:146: in deepcopy
y = copier(x, memo)
/usr/local/lib/python3.9/copy.py:230: in _deepcopy_dict
y[deepcopy(key, memo)] = deepcopy(value, memo)
/usr/local/lib/python3.9/copy.py:146: in deepcopy
y = copier(x, memo)
/usr/local/lib/python3.9/copy.py:230: in _deepcopy_dict
y[deepcopy(key, memo)] = deepcopy(value, memo)
/usr/local/lib/python3.9/copy.py:172: in deepcopy
y = _reconstruct(x, memo, *rv)
/usr/local/lib/python3.9/copy.py:270: in _reconstruct
state = deepcopy(state, memo)
/usr/local/lib/python3.9/copy.py:146: in deepcopy
y = copier(x, memo)
/usr/local/lib/python3.9/copy.py:230: in _deepcopy_dict
y[deepcopy(key, memo)] = deepcopy(value, memo)
E RecursionError: maximum recursion depth exceeded while calling a Python object
!!! Recursion detected (same locals & position)
Notes
Add any notes you feel relevant here :)
@roniemartinez Can you provide the entire block of code around instance.save()
that causes the stacktrace and the details of the Model fields?
@LincolnPuzey
The errors aren't that helpful for me and I currently cannot replicate/isolate the source of the issue (it's a huge project). Here's the complete info.
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
.venv/lib/python3.10/site-packages/factory/base.py:40: in __call__
return cls.create(**kwargs)
.venv/lib/python3.10/site-packages/factory/base.py:528: in create
return cls._generate(enums.CREATE_STRATEGY, kwargs)
.venv/lib/python3.10/site-packages/factory/django.py:117: in _generate
return super()._generate(strategy, params)
.venv/lib/python3.10/site-packages/factory/base.py:465: in _generate
return step.build()
.venv/lib/python3.10/site-packages/factory/builder.py:258: in build
step.resolve(pre)
.venv/lib/python3.10/site-packages/factory/builder.py:199: in resolve
self.attributes[field_name] = getattr(self.stub, field_name)
.venv/lib/python3.10/site-packages/factory/builder.py:344: in __getattr__
value = value.evaluate_pre(
.venv/lib/python3.10/site-packages/factory/declarations.py:48: in evaluate_pre
return self.evaluate(instance, step, context)
.venv/lib/python3.10/site-packages/factory/declarations.py:395: in evaluate
return step.recurse(subfactory, extra, force_sequence=force_sequence)
.venv/lib/python3.10/site-packages/factory/builder.py:216: in recurse
return builder.build(parent_step=self, force_sequence=force_sequence)
.venv/lib/python3.10/site-packages/factory/builder.py:271: in build
postgen_results[declaration_name] = declaration.declaration.evaluate_post(
.venv/lib/python3.10/site-packages/factory/declarations.py:592: in evaluate_post
return self.call(instance, step, postgen_context)
.venv/lib/python3.10/site-packages/factory/declarations.py:673: in call
return step.recurse(factory, passed_kwargs)
.venv/lib/python3.10/site-packages/factory/builder.py:216: in recurse
return builder.build(parent_step=self, force_sequence=force_sequence)
.venv/lib/python3.10/site-packages/factory/builder.py:258: in build
step.resolve(pre)
.venv/lib/python3.10/site-packages/factory/builder.py:199: in resolve
self.attributes[field_name] = getattr(self.stub, field_name)
.venv/lib/python3.10/site-packages/factory/builder.py:344: in __getattr__
value = value.evaluate_pre(
.venv/lib/python3.10/site-packages/factory/declarations.py:48: in evaluate_pre
return self.evaluate(instance, step, context)
.venv/lib/python3.10/site-packages/factory/declarations.py:395: in evaluate
return step.recurse(subfactory, extra, force_sequence=force_sequence)
.venv/lib/python3.10/site-packages/factory/builder.py:216: in recurse
return builder.build(parent_step=self, force_sequence=force_sequence)
.venv/lib/python3.10/site-packages/factory/builder.py:276: in build
self.factory_meta.use_postgeneration_results(
.venv/lib/python3.10/site-packages/factory/base.py: in use_postgeneration_results
self.factory._after_postgeneration(
.venv/lib/python3.10/site-packages/factory/django.py:173: in _after_postgeneration
instance.save()
src/company/models/company.py:634: in save
super(Company, self).save(*args, **kwargs)
.venv/lib/python3.10/site-packages/safedelete/models.py:107: in save
super(SafeDeleteModel, self).save(**kwargs)
.venv/lib/python3.10/site-packages/django/db/models/base.py:739: in save
self.save_base(using=using, force_insert=force_insert,
.venv/lib/python3.10/site-packages/django/db/models/base.py:787: in save_base
post_save.send(
.venv/lib/python3.10/site-packages/django/dispatch/dispatcher.py:180: in send
return [
.venv/lib/python3.10/site-packages/django/dispatch/dispatcher.py:181: in <listcomp>
(receiver, receiver(signal=self, sender=sender, **named))
.venv/lib/python3.10/site-packages/dirtyfields/dirtyfields.py:163: in reset_state
new_state = instance._as_dict(check_relationship=True)
.venv/lib/python3.10/site-packages/dirtyfields/dirtyfields.py:99: in _as_dict
all_field[field.name] = deepcopy(field_value)
/usr/local/lib/python3.10/copy.py:172: in deepcopy
y = _reconstruct(x, memo, *rv)
/usr/local/lib/python3.10/copy.py:271: in _reconstruct
state = deepcopy(state, memo)
/usr/local/lib/python3.10/copy.py:146: in deepcopy
y = copier(x, memo)
/usr/local/lib/python3.10/copy.py:231: in _deepcopy_dict
y[deepcopy(key, memo)] = deepcopy(value, memo)
/usr/local/lib/python3.10/copy.py:172: in deepcopy
y = _reconstruct(x, memo, *rv)
/usr/local/lib/python3.10/copy.py:271: in _reconstruct
state = deepcopy(state, memo)
/usr/local/lib/python3.10/copy.py:146: in deepcopy
y = copier(x, memo)
/usr/local/lib/python3.10/copy.py:231: in _deepcopy_dict
y[deepcopy(key, memo)] = deepcopy(value, memo)
/usr/local/lib/python3.10/copy.py:146: in deepcopy
y = copier(x, memo)
/usr/local/lib/python3.10/copy.py:231: in _deepcopy_dict
y[deepcopy(key, memo)] = deepcopy(value, memo)
/usr/local/lib/python3.10/copy.py:172: in deepcopy
y = _reconstruct(x, memo, *rv)
/usr/local/lib/python3.10/copy.py:271: in _reconstruct
state = deepcopy(state, memo)
/usr/local/lib/python3.10/copy.py:146: in deepcopy
y = copier(x, memo)
/usr/local/lib/python3.10/copy.py:231: in _deepcopy_dict
y[deepcopy(key, memo)] = deepcopy(value, memo)
E RecursionError: maximum recursion depth exceeded while calling a Python object
!!! Recursion detected (same locals & position)