Opened 4 hours ago
Last modified 4 hours ago
#37431 new Uncategorized
MigrationWriter silently serializes Python 3.15 frozendict values as tuples of keys — at Initial Version
| Reported by: | amanjain | Owned by: | |
|---|---|---|---|
| Component: | Migrations | Version: | dev |
| Severity: | Normal | Keywords: | |
| Cc: | Triage Stage: | Unreviewed | |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
Ticket title:
`
MigrationWriter silently serializes Python 3.15 frozendict values as tuples of keys
`
Ticket description:
On Python 3.15.0, Django's migration serializer treats built-in frozendict instances as generic iterables, preserving only their keys and silently discarding their values.
Reproduced against Django main at d430084791.
Minimal reproducer:
`python
from django.db.migrations.writer import MigrationWriter
MigrationWriter.serialize(frozendict(answer=42))
`
Actual result:
`python
("('answer',)", set())
`
Expected behavior: preserve the mapping's keys and values, rather than serialize it as a tuple of keys.
This affects field defaults. For example:
`python
models.JSONField(default=frozendict(answer=42))
`
is written into a migration as:
`python
models.JSONField(default=('answer',))
`
I reproduced the database consequence on SQLite: after executing a generated AddField migration against a table containing an existing row, the new JSON field contains answer instead of {"answer": 42}.
The serializer registry handles dict explicitly, but frozendict is not a dict subclass and falls through to IterableSerializer.
A proposed patch adds a dedicated frozendict serializer, regression tests in the existing migration writer and operation suites, and documentation noting that generated migrations containing frozendict require Python 3.15+.
Validation:
- Python 3.15: all 75 writer/regression tests passed.
- Python 3.15: 181 migration operation tests ran successfully, with 2 skipped.
- Python 3.14: 75 writer/regression tests ran successfully, with 3 skipped.
- Formatting and whitespace checks passed.
- The full Django test suite has not been run.
AI disclosure: OpenAI Codex (GPT-6) assisted with investigation, implementation, regression tests, documentation, and commit preparation.