Skip to content

feat: add choices to strings to enable literal types#1580

Open
MaximSrour wants to merge 2 commits intoormar-orm:masterfrom
MaximSrour:add-choices-to-strings-to-enable-literal-types
Open

feat: add choices to strings to enable literal types#1580
MaximSrour wants to merge 2 commits intoormar-orm:masterfrom
MaximSrour:add-choices-to-strings-to-enable-literal-types

Conversation

@MaximSrour
Copy link
Contributor

Summary

Enables ormar.String to preserve string literal typing when choices are provided, while keeping the underlying database column as sqlalchemy.String.

Closes #1579.

Changes

  • update ormar.String to project a typing.Literal[...] pydantic type when string choices are provided
  • preserve nullable behavior for String(..., choices=..., nullable=True) by wrapping the projected type in Optional[...]
  • keep normal String behavior unchanged when choices are not provided
  • add/adjust tests for:
    • runtime validation of String(..., choices=...)
    • nullable string choices
    • generated JSON schema for string choices fields
  • update field documentation to describe String and String(..., choices=...) in a single section

Testing

Built and ran targetted tests for the new changes, and ran tests against the entire suite. All passing.

Installed a local version of ORMAR into a personal repository that uses it, and tested against existing type errors.

Screenshots

Error before:
image

Using the new literal inference:
image

@codspeed-hq
Copy link

codspeed-hq bot commented Mar 10, 2026

Merging this PR will degrade performance by 23.72%

⚡ 1 improved benchmark
❌ 2 regressed benchmarks
✅ 81 untouched benchmarks

⚠️ Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
WallTime test_making_and_inserting_models_in_bulk[10] 8.5 ms 9.9 ms -14.04%
WallTime test_making_and_inserting_models_in_bulk[20] 12.6 ms 10.8 ms +16.78%
WallTime test_creating_individually_with_related_models[10] 56.4 ms 73.9 ms -23.72%

Comparing MaximSrour:add-choices-to-strings-to-enable-literal-types (61242d6) with master (8e144d0)1

Open in CodSpeed

Footnotes

  1. No successful run was found on master (7f22aa2) during the generation of this report, so 8e144d0 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@MaximSrour MaximSrour marked this pull request as ready for review March 11, 2026 09:41
@collerek
Copy link
Collaborator

Any particural reason why you dont want to use EnumField here?

@MaximSrour
Copy link
Contributor Author

Any particural reason why you dont want to use EnumField here?

I wrote about it a bit in the linked issue, but it mostly comes down to flexibility - with an enum, I'd need to push a migration to update the column type (which can take a while when there are a lot of records), after which I'll be able to use the new value. With a string column instead, the code can immediately start using the new values.

@collerek
Copy link
Collaborator

We used to have choices for all field types that was removed in https://github.com/ormar-orm/ormar/releases/tag/0.20.0

If we would like to restore it as Literal type I guess that should support all field types again and not only string one. After all Literal[1,2,3] is also a valid literal and could be used to limit Integer field.

Note also that you now overwrite the overwrite_pydantic_type that the user might have provided, along with choices - which at least require a warning displayed.

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.

Updating type annotations to support string literals

2 participants