Skip to content

fix: parse enum names through nested annotations - #910

Merged
hramezani merged 4 commits into
pydantic:mainfrom
Sanjays2402:fix/nested-annotated-enum-parsing
Jul 14, 2026
Merged

fix: parse enum names through nested annotations#910
hramezani merged 4 commits into
pydantic:mainfrom
Sanjays2402:fix/nested-annotated-enum-parsing

Conversation

@Sanjays2402

Copy link
Copy Markdown
Contributor

With env_parse_enums=True, enum names inside nested wrappers such as Optional[Annotated[MyEnum, ...]] were left as strings and failed validation. Resolve enum members recursively through annotation arguments, while preserving existing direct and union handling; the regression test fails before the source change and passes with it.

Sanjays2402 and others added 3 commits July 12, 2026 14:23
Walk nested annotation arguments when resolving enum member names.
Add a regression test for an optional Annotated enum.
Cast the leniently validated enum candidate before member lookup so the strict mypy gate accepts the recursive annotation fix.
_annotation_enum_val_to_name had the same one-level limitation that was
just fixed in _annotation_enum_name_to_val: it only inspected the
annotation, its origin, and its direct args, so an enum wrapped as
Optional[Annotated[MyEnum, ...]] was not resolved. This affected CLI
help rendering of enum defaults, which fell back to the raw value
(e.g. "(default: 1)") instead of the member name ("(default: kiwi)").

Resolve enum members recursively through annotation arguments, mirroring
the name_to_val fix. Regression test fails before the source change and
passes with it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@hramezani

hramezani commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Thanks @Sanjays2402 for the fix! I pushed one follow-up commit (761bfb9) to the branch.

_annotation_enum_val_to_name — the twin of the function you fixed — had the exact same one-level lookup limitation. It only inspected the annotation, its origin, and its direct args, so an enum wrapped as Optional[Annotated[MyEnum, ...]] was not resolved. This shows up in CLI help rendering of enum defaults, which fell back to the raw value (e.g. (default: 1)) instead of the member name ((default: kiwi)).

The commit applies the same recursive-descent pattern you used for _annotation_enum_name_to_val, plus a regression test (test_cli_enum_default_through_nested_annotation) that fails before the change and passes with it. This keeps the two helpers symmetric so both the env-parsing and CLI-help paths handle nested annotations consistently.
@

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes enum parsing when env_parse_enums=True (and CLI default rendering) for enums wrapped inside nested typing constructs (e.g. Optional[Annotated[MyEnum, ...]]), by recursively inspecting annotation arguments to resolve enum names/values correctly.

Changes:

  • Update enum (name ↔ value) resolution helpers to traverse nested annotation arguments recursively.
  • Add a regression test ensuring CLI --help shows enum defaults correctly through nested Annotated + optional wrappers.
  • Add a regression test ensuring env enum parsing works through nested Annotated + optional wrappers.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
tests/test_source_cli.py Adds CLI help-output regression test for enum defaults in nested annotations.
tests/test_settings.py Adds env parsing regression test for enums in nested Annotated + optional annotations.
pydantic_settings/sources/utils.py Makes enum name/value resolution recursive across annotation arguments to support nested wrappers.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@hramezani
hramezani merged commit 37816f1 into pydantic:main Jul 14, 2026
19 checks passed
@hramezani

Copy link
Copy Markdown
Contributor

Thanks @Sanjays2402

@hramezani hramezani mentioned this pull request Aug 7, 2026
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.

3 participants