Skip to content

CLI use of IntEnum not working with nested models #583

@lsg551

Description

@lsg551

Description

The pydantic docs about the usage of enums in CLIs state that enum.IntEnum can perfectly be used with CLIs, where the enum's field names are eventually accepted as flag values.

[excerpt] from the docs:

CLI argument parsing of literals and enums are converted into CLI choices.

import sys
from enum import IntEnum
from pydantic_settings import BaseSettings

class Fruit(IntEnum):
    pear = 0
    kiwi = 1
    lime = 2

class Settings(BaseSettings, cli_parse_args=True):
    fruit: Fruit

sys.argv = ['example.py', '--fruit', 'lime']
print(Settings().model_dump())
#> {'fruit': <Fruit.lime: 2>}

And this works totally fine. But as soon as a model is nested, it raises a validation error. For example, consider this scenario:

from enum import IntEnum

class LogLevel(IntEnum):
    CRITICAL = 50
    ERROR = 40
    WARNING = 30
    INFO = 20
    DEBUG = 10

@pydantic.dataclasses.dataclass
class LoggingOptions:
    level: LogLevel = LogLevel.INFO

class Settings(BaseSettings):

    model_config = SettingsConfigDict(
        cli_parse_args=True,
        cli_kebab_case=True,
        cli_use_class_docs_for_groups=True,
        cli_avoid_json=True,
        frozen=True,
    )

    level: LogLevel = LogLevel.INFO # this works

    logging: LoggingOptions # this DOES NOT work

When tested, the root level flags work as intended with integer enums:

 sys.argv = ['example.py', '--level', 'DEBUG']
 settings = Settings()

However, nested ones do not:

 sys.argv = ['example.py', '--logging.level', 'DEBUG']
 settings = Settings()

and this will raise:

Traceback (most recent call last):
  File "/project/sandbox/main.py", line 55, in <module>
    settings = Settings()
               ^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/pydantic_settings/main.py", line 176, in __init__
    super().__init__(
  File "/usr/local/lib/python3.12/site-packages/pydantic/main.py", line 253, in __init__
    validated_self = self.__pydantic_validator__.validate_python(data, self_instance=self)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
pydantic_core._pydantic_core.ValidationError: 1 validation error for Settings
logging.level
  Input should be 50, 50, 40, 30, 30, 20, 10 or 0 [type=enum, input_value='DEBUG', input_type=str]
    For further information visit https://errors.pydantic.dev/2.11/v/enum

Expected Behaviour

I expected this to work properly with nested models too, just like root level objects. However, I am not familiar enough with pydantic or pydantic-settings to tell whether this is intended / expected behaviour.

I searched the docs and issues, but couldn't find related information. Sorry, if this was already brought up.

How to replicate

Note that the code of the above examples is simplified, but I created a codesandbox to replicate this: https://codesandbox.io/p/devbox/59rv9y?embed=1&file=%2Fmain.py

Affected Versions

I tested with the latest versions of pydantic and pydantic-settings:

  • pydantic == 2.11.3
  • pydantic-settings == 2.8.1

and used Python 3.12 as well as 3.13.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions