Opened 4 weeks ago

Closed 3 weeks ago

#36695 closed Bug (fixed)

Model field validator with a generic parameter causes infinite recursion when making migrations

Reported by: Michal Dabski Owned by: Augusto Pontes
Component: Migrations Version: 4.2
Severity: Normal Keywords:
Cc: Michal Dabski Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Michal Dabski)

Minimal code to reproduce (in models.py) in Django==4.2.25

from django.utils.deconstruct import deconstructible
from django.db import models

@deconstructible
class SchemaValidator:
    def __init__(self, expected_type: type):
        pass

    def __call__(self, *args, **kwargs):
        pass

class TestModel(models.Model):
    config: dict[str, float] = models.JSONField(validators=[SchemaValidator(dict[str, float])])

This triggers an error when running makemigrations:

$ ./manage.py makemigrations
Migrations for 'audit_builder':
  meg_forms\audit_builder\migrations\0083_alter_testmodel_config.py
    - Alter field config on testmodel
Traceback (most recent call last):
  File "C:\Users\Michal\src\mat-cms\.venv\Lib\site-packages\django\db\migrations\serializer.py", line 214, in serialize
    item_string, item_imports = serializer_factory(item).serialize()
                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Michal\src\mat-cms\.venv\Lib\site-packages\django\db\migrations\serializer.py", line 214, in serialize
    item_string, item_imports = serializer_factory(item).serialize()
                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Michal\src\mat-cms\.venv\Lib\site-packages\django\db\migrations\serializer.py", line 214, in serialize
    item_string, item_imports = serializer_factory(item).serialize()
                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  [Previous line repeated 996 more times]
  File "C:\Users\Michal\src\mat-cms\.venv\Lib\site-packages\django\db\migrations\serializer.py", line 389, in serializer_factory
    if isinstance(value, type_):
       ^^^^^^^^^^^^^^^^^^^^^^^^
RecursionError: maximum recursion depth exceeded

Debugging locally shows that:

  • removing generic parameters from the dict type passed to SchemaValidator does not trigger the error
  • The loop happens in django.db.migrations.serializer.IterableSerializer.serialize, it keeps recursively invoking serializer_factory(item).serialize() with item='*dict[str, float]' (GenericAlias)
  • the same behaviour is with similar generic types - list[str]
  • without the migration being created/applied, validation works as expected

Change History (10)

comment:1 by Michal Dabski, 4 weeks ago

Description: modified (diff)

comment:2 by Michal Dabski, 4 weeks ago

Description: modified (diff)

comment:3 by Augusto Pontes, 4 weeks ago

Hi michael, i will try to reproduce it, and see if i can give to you a suggestion of how to solve it, i will test if this is still happening on newer versions, in this case i will use the 5.2

comment:4 by Augusto Pontes, 4 weeks ago

Needs documentation: set
Needs tests: set
Owner: set to Augusto Pontes
Patch needs improvement: set
Status: newassigned

comment:5 by Augusto Pontes, 4 weeks ago

Triage Stage: UnreviewedAccepted

comment:7 by Jacob Walls, 4 weeks ago

Needs documentation: unset

comment:8 by Jacob Walls, 3 weeks ago

Needs tests: unset
Patch needs improvement: unset
Triage Stage: AcceptedReady for checkin

comment:9 by Jacob Walls, 3 weeks ago

Has patch: set

comment:10 by Jacob Walls <jacobtylerwalls@…>, 3 weeks ago

Resolution: fixed
Status: assignedclosed

In 8af79e2:

Fixed #36695 -- Fixed handling of parameterized generics in migration serialization.

Co-authored-by: Jacob Walls <jacobtylerwalls@…>

Note: See TracTickets for help on using tickets.
Back to Top