Skip to content

Conversation

@kzrnm
Copy link
Contributor

@kzrnm kzrnm commented Jan 1, 2026

Fix #742

import sys
from argparse import ArgumentParser
from typing import Literal

from pydantic_settings import BaseSettings, CliApp, CliSettingsSource, CliIgnoreArg

parser = ArgumentParser()
parser.add_argument('--food', choices=['pear', 'kiwi', 'lime'], help='fruite')


class Settings(BaseSettings):
    name: str = 'Bob'
    food: CliIgnoreArg[Literal['pear', 'kiwi', 'lime']]


cli_settings = CliSettingsSource(Settings, root_parser=parser)
cli_settings.root_parser.print_help()
# usage: app.py [-h] [--food {pear,kiwi,lime}] [--name str]

# options:
#   -h, --help            show this help message and exit
#   --food {pear,kiwi,lime}
#                         fruite

sys.argv = ['example.py', '--food', 'kiwi', '--name', 'waldo']
s = CliApp.run(Settings, cli_settings_source=cli_settings)
print(s.model_dump())
# {'name': 'waldo', 'food': 'kiwi'}


# Load CLI settings from pre-parsed arguments. i.e., the parsing occurs elsewhere and we
# just need to load the pre-parsed args into the settings source.
parsed_args = parser.parse_args(['--food', 'lime', '--name', 'ralph'])
s = CliApp.run(Settings, cli_args=parsed_args, cli_settings_source=cli_settings)
print(s.model_dump())
# {'name': 'waldo', 'food': 'lime'}

Selected Reviewer: @dmontagu

@hramezani
Copy link
Member

Thanks @kzrnm for the PR.

@kschwab Please review the PR when you have time.

@kschwab
Copy link
Contributor

kschwab commented Jan 12, 2026

Thanks for the PR @kzrnm. Can you change the name from CliIgnoreArg to something like CliExternalArg? CliIgnoreArg is somewhat confusing since the arg is not ignored, it's just mapped from an external parser.

Additionally, since this is externally mapped, we will have to ensure that the parsed arg is str or list[str]. Internally, CliSettingsSource is just an overlay on top of EnvSettingsSource, so all CLI arguments are expected to be parsed as type str.

You will need to modify _resolve_parsed_args such that for each field name, you get the mapped cli_arg, and then modify val to str or list[str]. Then everything else should work as expected.

Lastly, please amend the docs for Integrating with Existing Parsers with the new annotation.

@kzrnm
Copy link
Contributor Author

kzrnm commented Jan 15, 2026

we will have to ensure that the parsed arg is str or list[str].

Adding a requirement that type=str must be specified would break compatibility with argparse, which is unfortunate. I’d like to explore other options.

@hramezani
Copy link
Member

@kschwab Could you check again?

@kschwab
Copy link
Contributor

kschwab commented Jan 30, 2026

@kzrnm, it is separate from argparse. The key statement was below:

You will need to modify _resolve_parsed_args such that for each field name, you get the mapped cli_arg, and then modify val to str or list[str]. Then everything else should work as expected.

It means, the parsed values from the external parser (argparse, pytest, etc.) that are handed to CliSettingsSource need to be internally converted to str. So if argparse uses type=int, CliSettingsSource needs to convert the int to str before handing it over to the EnvSettingsSource to unpack. EnvSettingsSource expects dict[str, str].

The alternative is, for non-str values, create the relevant nested dictionary entry and then update self.env_vars after parse_env_vars in _load_env_vars. You might also have to make sure to differentiate between values that are CliExternalArg and values that are not.

Of the two approaches, the conversion to str type is simpler.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

There is no way to use arguments integrated with an existing parser

4 participants