Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Update the return type hint for IntEnumField/CharEnumField from EnumType to tortoise.fields.Field[EnumType] (fixes #2155) - #2243

Merged
waketzheng merged 6 commits into
tortoise:developfrom
apoorvdarshan:fix-2155-enum-field-migration-mypy
Sep 12, 2026
Merged

Update the return type hint for IntEnumField/CharEnumField from EnumType to tortoise.fields.Field[EnumType] (fixes #2155)#2243
waketzheng merged 6 commits into
tortoise:developfrom
apoorvdarshan:fix-2155-enum-field-migration-mypy

Conversation

@apoorvdarshan

Copy link
Copy Markdown
Contributor

Summary

makemigrations generated migration files that fail mypy when a model uses CharEnumField / IntEnumField (issue #2155):

error: List item 1 has incompatible type "tuple[str, ExampleEnum]";
  expected "tuple[str, Field[Any] | ManyToManyRelation[Any] | None]"   # CreateModel
error: Argument "field" to "AddField" has incompatible type "ExampleEnum";
  expected "Field[Any] | ManyToManyRelation[Any] | None"               # AddField

The root cause is that the public IntEnumField / CharEnumField names are factory functions typed to return the enum type (a TypeVar bound to Enum) rather than a Field. That return type is intentional — it lets models write field: MyEnum = CharEnumField(MyEnum) and have the attribute resolve to the enum. But the migration writer rendered field expressions using those same factory names, so the generated fields.CharEnumField(...) call was inferred by mypy as the enum type, not a Field, and the surrounding migration operation rejected it.

Fix

Render enum fields as their concrete IntEnumFieldInstance / CharEnumFieldInstance classes instead of the factory names. These are the real Field subclasses (CharField / SmallIntField descendants), so the generated code type-checks cleanly while constructing an identical field at runtime.

  • tortoise/migrations/writer.py: exclude the two enum *FieldInstance classes from the FieldInstanceField name remapping, so they render as their concrete class.
  • tortoise/fields/__init__.py: export CharEnumFieldInstance and IntEnumFieldInstance so the generated from tortoise import fields alias resolves fields.CharEnumFieldInstance(...).

Model-side typing is untouched: the factory functions still return the enum type, so field: MyEnum = CharEnumField(MyEnum) continues to type-check.

Tests / Verification

  • Reproduced the issue end-to-end with the model/config from the report: tortoise --config-file config.json makemigrations then mypy migrations. Before the fix mypy emitted both reported errors; after the fix mypy migrations reports Success: no issues found for both the CreateModel (initial) and AddField cases.
  • Confirmed the generated migrations still apply at runtime (tortoise ... migrate → OK).
  • Updated test_writer_handles_enum_fields and added test_writer_enum_field_render_is_field_instance (a Invalid type hint for CharEnumField in generated migration script #2155 regression test covering the AddField path). Both fail on the pristine tree and pass with the fix.
  • pytest tests/migrations/ (300 passed) and pytest tests/fields/ (enum + field tests, all pass).
  • ruff format --check, ruff check, and mypy are clean on the changed files (no new errors vs. the pristine tree).
  • Added a CHANGELOG.rst entry under 1.1.8 → Fixed.

Disclosure: prepared with AI assistance; reviewed and verified locally.

The migration writer rendered IntEnumField/CharEnumField using their public
factory-function names. Those factories are typed to return the enum type
(so model attributes resolve to the enum), not a Field, so the generated
migration failed mypy with 'incompatible type "tuple[str, ...]"' in
CreateModel and 'incompatible type' in AddField.

Emit the concrete IntEnumFieldInstance/CharEnumFieldInstance classes instead;
these are real Field subclasses, so the generated code type-checks while
producing an identical field at runtime. Export the instance classes from
tortoise.fields so the 'from tortoise import fields' alias resolves them.

Fixes tortoise#2155.
@codspeed-hq

codspeed-hq Bot commented Jul 11, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 24 untouched benchmarks


Comparing apoorvdarshan:fix-2155-enum-field-migration-mypy (557595b) with develop (d1338bc)

Open in CodSpeed

@waketzheng

Copy link
Copy Markdown
Contributor

@apoorvdarshan Thanks for your work. It would be better to correct the return type of IntEnumField/CharEnumField rather than change the migration behavior. I've updated this PR to fix the issue.

@waketzheng waketzheng changed the title Render enum fields as concrete Field instances in migrations (fixes #2155) Update the return type hint for IntEnumField/CharEnumField from EnumType to tortoise.fields.Field[EnumType] (fixes #2155) Sep 12, 2026
@waketzheng
waketzheng merged commit 4d55222 into tortoise:develop Sep 12, 2026
25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants