diff --git a/pydantic_settings/sources.py b/pydantic_settings/sources.py index 1bfceb62..cb43f591 100644 --- a/pydantic_settings/sources.py +++ b/pydantic_settings/sources.py @@ -1407,7 +1407,7 @@ def _help_format(self, field_info: FieldInfo) -> str: elif field_info.default_factory is not None: default = f'(default: {field_info.default_factory})' _help += f' {default}' if _help else default - return _help + return _help.replace('%', '%%') if issubclass(type(self._root_parser), ArgumentParser) else _help class ConfigFileSourceMixin(ABC): diff --git a/tests/test_settings.py b/tests/test_settings.py index 5b6f2ceb..37d89f3e 100644 --- a/tests/test_settings.py +++ b/tests/test_settings.py @@ -2261,6 +2261,29 @@ class Cfg(BaseSettings): ) +def test_cli_help_string_format(capsys, monkeypatch): + class Cfg(BaseSettings): + date_str: str = '%Y-%m-%d' + + argparse_options_text = 'options' if sys.version_info >= (3, 10) else 'optional arguments' + + with monkeypatch.context() as m: + m.setattr(sys, 'argv', ['example.py', '--help']) + + with pytest.raises(SystemExit): + Cfg(_cli_parse_args=True) + + assert ( + re.sub(r'0x\w+', '0xffffffff', capsys.readouterr().out, re.MULTILINE) + == f"""usage: example.py [-h] [--date_str str] + +{argparse_options_text}: + -h, --help show this help message and exit + --date_str str (default: %Y-%m-%d) +""" + ) + + def test_cli_nested_dataclass_arg(): @pydantic_dataclasses.dataclass class MyDataclass: