diff --git a/pydantic_settings/sources/providers/cli.py b/pydantic_settings/sources/providers/cli.py index f0439785..a2d6f839 100644 --- a/pydantic_settings/sources/providers/cli.py +++ b/pydantic_settings/sources/providers/cli.py @@ -162,6 +162,9 @@ def __init__( self.cli_prog_name = ( cli_prog_name if cli_prog_name is not None else settings_cls.model_config.get('cli_prog_name', sys.argv[0]) ) + self.cli_parse_args = ( + cli_parse_args if cli_parse_args is not None else settings_cls.model_config.get('cli_parse_args', None) + ) self.cli_hide_none_type = ( cli_hide_none_type if cli_hide_none_type is not None @@ -247,15 +250,14 @@ def __init__( add_subparsers_method=add_subparsers_method, formatter_class=formatter_class, ) - - if cli_parse_args not in (None, False): - if cli_parse_args is True: - cli_parse_args = sys.argv[1:] - elif not isinstance(cli_parse_args, (list, tuple)): + if self.cli_parse_args not in (None, False): + if self.cli_parse_args is True: + self.cli_parse_args = sys.argv[1:] + elif not isinstance(self.cli_parse_args, (list, tuple)): raise SettingsError( - f'cli_parse_args must be a list or tuple of strings, received {type(cli_parse_args)}' + f'cli_parse_args must be a list or tuple of strings, received {type(self.cli_parse_args)}' ) - self._load_env_vars(parsed_args=self._parse_args(self.root_parser, cli_parse_args)) + self._load_env_vars(parsed_args=self._parse_args(self.root_parser, self.cli_parse_args)) @overload def __call__(self) -> dict[str, Any]: ... diff --git a/tests/test_source_cli.py b/tests/test_source_cli.py index 4f1b6ff3..98c4b0a6 100644 --- a/tests/test_source_cli.py +++ b/tests/test_source_cli.py @@ -2464,3 +2464,30 @@ class Options(BaseSettings): assert CliApp.run(Options, cli_args=['--nested']).model_dump() == {'nested': {'foo': 1, 'bar': 2}} assert CliApp.run(Options, cli_args=['--nested={}']).model_dump() == {'nested': {'foo': 1, 'bar': 2}} assert CliApp.run(Options, cli_args=['--nested.foo=5']).model_dump() == {'nested': {'foo': 5, 'bar': 2}} + + +def test_cli_parse_args_from_model_config_is_respected_with_settings_customise_sources( + monkeypatch: pytest.MonkeyPatch, +): + class MySettings(BaseSettings): + model_config = SettingsConfigDict(cli_parse_args=True) + + foo: str + + @classmethod + def settings_customise_sources( + cls, + settings_cls: type[BaseSettings], + init_settings: PydanticBaseSettingsSource, + env_settings: PydanticBaseSettingsSource, + dotenv_settings: PydanticBaseSettingsSource, + file_secret_settings: PydanticBaseSettingsSource, + ) -> tuple[PydanticBaseSettingsSource, ...]: + return (CliSettingsSource(settings_cls),) + + with monkeypatch.context() as m: + m.setattr(sys, 'argv', ['example.py', '--foo', 'bar']) + + cfg = CliApp.run(MySettings) + + assert cfg.model_dump() == {'foo': 'bar'}