#36695: Model field validator with a generic parameter causes infinite recursion
when making migrations
-------------------------------+--------------------------------------
Reporter: Michal Dabski | Owner: (none)
Type: Bug | Status: new
Component: Migrations | Version: 4.2
Severity: Normal | Resolution:
Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------+--------------------------------------
Description changed by Michal Dabski:
Old description:
> 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
> C:\Users\Michal\src\mat-cms\.venv\Lib\site-
> packages\django_downloadview\__init__.py:4: UserWarning: pkg_resources is
> deprecated as an API. See
> https://setuptools.pypa.io/en/latest/pkg_resources.html. The
> pkg_resources package is slated for removal as early as 2025-11-30.
> Refrain from using this package or pin to Setuptools<81.
> import pkg_resources
> 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`)
New description:
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`)
--
--
Ticket URL: <https://code.djangoproject.com/ticket/36695#comment:1>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion visit
https://groups.google.com/d/msgid/django-updates/0107019a3005207a-5180aeaa-5e3c-40a9-981b-573bea559c20-000000%40eu-central-1.amazonses.com.