Skip to content

Commit

Permalink
Ignore propagation of model default if not of same type.
Browse files Browse the repository at this point in the history
  • Loading branch information
kschwab committed Nov 7, 2024
1 parent 1c3ffe9 commit b046323
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 3 deletions.
15 changes: 12 additions & 3 deletions pydantic_settings/sources.py
Original file line number Diff line number Diff line change
Expand Up @@ -1615,6 +1615,17 @@ def _add_parser_args(
model_default=PydanticUndefined,
)
else:
# For union of models, ignore model default if not of same type as current model.
model_default = (
None
if (
model_default is not PydanticUndefined
and (is_model_class(type(model_default)) or is_pydantic_dataclass(type(model_default)))
and type(model_default) is not model
)
else model_default
)

flag_prefix: str = self._cli_flag_prefix
is_append_action = _annotation_contains_types(
field_info.annotation, (list, set, dict, Sequence, Mapping), is_strip_annotated=True
Expand Down Expand Up @@ -1866,9 +1877,7 @@ def _help_format(self, field_name: str, field_info: FieldInfo, model_default: An
_help += f' ({ifdef}required)' if _help else f'({ifdef}required)'
else:
default = f'(default: {self.cli_parse_none_str})'
if (is_model_class(type(model_default)) or is_pydantic_dataclass(type(model_default))) and hasattr(
model_default, field_name
):
if is_model_class(type(model_default)) or is_pydantic_dataclass(type(model_default)):
default = f'(default: {getattr(model_default, field_name)})'
elif model_default not in (PydanticUndefined, None) and _is_function(model_default):
default = f'(default factory: {self._metavar_format(model_default)})'
Expand Down
36 changes: 36 additions & 0 deletions tests/test_source_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,42 @@ class MultilineDoc(BaseSettings, cli_parse_args=True):
)


def test_cli_help_union_of_models(capsys, monkeypatch):
class Cat(BaseModel):
meow: str = 'meow'

class Dog(BaseModel):
bark: str = 'bark'

class Bird(BaseModel):
caww: str = 'caww'
tweet: str

class Car(BaseSettings, cli_parse_args=True):
driver: Cat | Dog | Bird = Cat(meow='purr')

with monkeypatch.context() as m:
m.setattr(sys, 'argv', ['example.py', '--help'])

with pytest.raises(SystemExit):
Car()
assert (
capsys.readouterr().out
== f"""usage: example.py [-h] [--driver JSON] [--driver.meow str] [--driver.bark str]
{ARGPARSE_OPTIONS_TEXT}:
-h, --help show this help message and exit
driver options:
--driver JSON set driver from JSON string
--driver.meow str (default: purr)
--driver.bark str (default: bark)
--driver.caww str (default: caww)
--driver.tweet str (ifdef: required)
"""
)


def test_cli_help_default_or_none_model(capsys, monkeypatch):
class DeeperSubModel(BaseModel):
flag: bool
Expand Down

0 comments on commit b046323

Please sign in to comment.