pydantic / pydantic-settings

Settings management using pydantic

Home Page:https://docs.pydantic.dev/latest/usage/pydantic_settings/

Repository from Github https://github.compydantic/pydantic-settingsRepository from Github https://github.compydantic/pydantic-settings

Top-level CLI alias for nested model

maxnoe opened this issue · comments

We are looking to replace traitlets.config with pydantic_settings and one feature we are missing that is important to us is the ability to define short, top-level command line options for things that are defined deeper in the hierarchy.

E.g. consider:

from pydantic_settings import BaseSettings, CliApp


class SubSettings(BaseSettings):
    option: str = "foo"


class Settings(BaseSettings):
    sub: SubSettings

    def cli_cmd(self) -> None:
        print(self.model_dump())


CliApp.run(Settings)

In this example, I'd like to expose --sub.option just as --option, e.g. by defining an alias mapping.

Thanks @maxnoe for this issue.

@kschwab Do you have time to check this issue?

Looking at the code, maybe adding a field cli_aliases to the SettingsConfigDict would be a way here?

So that the code would look like this:

from pydantic_settings import BaseSettings, CliApp, SettingsConfigDict


class SubSettings(BaseSettings):
    option: str = "foo"

class Settings(BaseSettings):
    sub: SubSettings = SubSettings()

    model_config = SettingsConfigDict(
        cli_aliases={
            "alias": "sub.option",
        },
    )

    def cli_cmd(self) -> None:
        print(self.model_dump())


CliApp.run(Settings)

And then python example.py --alias="bar" would set sub.option="bar"

It should rather be:

model_config = SettingsConfigDict(
    cli_aliases={
        "sub.option": "alias",
    },
)

What is the expected behavior in the following case?

from pydantic_settings import BaseSettings, CliApp, SettingsConfigDict
from pydantic import Field

class SubSettings(BaseSettings):
    option: str = "foo"

class Settings(BaseSettings):
    sub: SubSettings = SubSettings()
    option: str = "bar"
    option2: str = Field("foobar", alias="option")

    model_config = SettingsConfigDict(
        cli_aliases={
            "sub.option": "option",
        },
    )

Making the mapping from the alias to the options trivially prevents duplicated alias definitions, so I found that the more natural mapping.

Concerning your example, I'd say raise an error like "Settings.option conflicts with cli_alias definition option: sub.optoin".