1010import typing_extensions
1111from pydantic import (
1212 AliasChoices ,
13+ AliasGenerator ,
1314 AliasPath ,
1415 BaseModel ,
1516 ConfigDict ,
@@ -107,7 +108,7 @@ def parse_args(self, *args: Any, **kwargs: Any) -> argparse.Namespace:
107108 return self .parser .parse_args (* args , ** kwargs )
108109
109110
110- def test_validation_alias_with_cli_prefix ():
111+ def test_cli_validation_alias_with_cli_prefix ():
111112 class Settings (BaseSettings , cli_exit_on_error = False ):
112113 foobar : str = Field (validation_alias = 'foo' )
113114
@@ -119,6 +120,36 @@ class Settings(BaseSettings, cli_exit_on_error=False):
119120 assert CliApp .run (Settings , cli_args = ['--p.foo' , 'bar' ]).foobar == 'bar'
120121
121122
123+ @pytest .mark .parametrize (
124+ 'alias_generator' ,
125+ [
126+ AliasGenerator (validation_alias = lambda s : AliasChoices (s , s .replace ('_' , '-' ))),
127+ AliasGenerator (validation_alias = lambda s : AliasChoices (s .replace ('_' , '-' ), s )),
128+ ],
129+ )
130+ def test_cli_alias_resolution_consistency_with_env (env , alias_generator ):
131+ class SubModel (BaseModel ):
132+ v1 : str = 'model default'
133+
134+ class Settings (BaseSettings ):
135+ model_config = SettingsConfigDict (
136+ env_nested_delimiter = '__' ,
137+ nested_model_default_partial_update = True ,
138+ alias_generator = alias_generator ,
139+ )
140+
141+ sub_model : SubModel = SubModel (v1 = 'top default' )
142+
143+ assert CliApp .run (Settings , cli_args = []).model_dump () == {'sub_model' : {'v1' : 'top default' }}
144+
145+ env .set ('SUB_MODEL__V1' , 'env default' )
146+ assert CliApp .run (Settings , cli_args = []).model_dump () == {'sub_model' : {'v1' : 'env default' }}
147+
148+ assert CliApp .run (Settings , cli_args = ['--sub-model.v1=cli default' ]).model_dump () == {
149+ 'sub_model' : {'v1' : 'cli default' }
150+ }
151+
152+
122153def test_cli_nested_arg ():
123154 class SubSubValue (BaseModel ):
124155 v6 : str
0 commit comments