Skip to content

Commit b046323

Browse files
committed
Ignore propagation of model default if not of same type.
1 parent 1c3ffe9 commit b046323

File tree

2 files changed

+48
-3
lines changed

2 files changed

+48
-3
lines changed

pydantic_settings/sources.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1615,6 +1615,17 @@ def _add_parser_args(
16151615
model_default=PydanticUndefined,
16161616
)
16171617
else:
1618+
# For union of models, ignore model default if not of same type as current model.
1619+
model_default = (
1620+
None
1621+
if (
1622+
model_default is not PydanticUndefined
1623+
and (is_model_class(type(model_default)) or is_pydantic_dataclass(type(model_default)))
1624+
and type(model_default) is not model
1625+
)
1626+
else model_default
1627+
)
1628+
16181629
flag_prefix: str = self._cli_flag_prefix
16191630
is_append_action = _annotation_contains_types(
16201631
field_info.annotation, (list, set, dict, Sequence, Mapping), is_strip_annotated=True
@@ -1866,9 +1877,7 @@ def _help_format(self, field_name: str, field_info: FieldInfo, model_default: An
18661877
_help += f' ({ifdef}required)' if _help else f'({ifdef}required)'
18671878
else:
18681879
default = f'(default: {self.cli_parse_none_str})'
1869-
if (is_model_class(type(model_default)) or is_pydantic_dataclass(type(model_default))) and hasattr(
1870-
model_default, field_name
1871-
):
1880+
if is_model_class(type(model_default)) or is_pydantic_dataclass(type(model_default)):
18721881
default = f'(default: {getattr(model_default, field_name)})'
18731882
elif model_default not in (PydanticUndefined, None) and _is_function(model_default):
18741883
default = f'(default factory: {self._metavar_format(model_default)})'

tests/test_source_cli.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,42 @@ class MultilineDoc(BaseSettings, cli_parse_args=True):
447447
)
448448

449449

450+
def test_cli_help_union_of_models(capsys, monkeypatch):
451+
class Cat(BaseModel):
452+
meow: str = 'meow'
453+
454+
class Dog(BaseModel):
455+
bark: str = 'bark'
456+
457+
class Bird(BaseModel):
458+
caww: str = 'caww'
459+
tweet: str
460+
461+
class Car(BaseSettings, cli_parse_args=True):
462+
driver: Cat | Dog | Bird = Cat(meow='purr')
463+
464+
with monkeypatch.context() as m:
465+
m.setattr(sys, 'argv', ['example.py', '--help'])
466+
467+
with pytest.raises(SystemExit):
468+
Car()
469+
assert (
470+
capsys.readouterr().out
471+
== f"""usage: example.py [-h] [--driver JSON] [--driver.meow str] [--driver.bark str]
472+
473+
{ARGPARSE_OPTIONS_TEXT}:
474+
-h, --help show this help message and exit
475+
476+
driver options:
477+
--driver JSON set driver from JSON string
478+
--driver.meow str (default: purr)
479+
--driver.bark str (default: bark)
480+
--driver.caww str (default: caww)
481+
--driver.tweet str (ifdef: required)
482+
"""
483+
)
484+
485+
450486
def test_cli_help_default_or_none_model(capsys, monkeypatch):
451487
class DeeperSubModel(BaseModel):
452488
flag: bool

0 commit comments

Comments
 (0)