Skip to content

Pin pydantic-settings upper bound due to parser bug#255

Merged
gpauloski merged 1 commit intomainfrom
pydantic-settings-bug
Feb 16, 2026
Merged

Pin pydantic-settings upper bound due to parser bug#255
gpauloski merged 1 commit intomainfrom
pydantic-settings-bug

Conversation

@gpauloski
Copy link
Contributor

Description

Pydantic-settings 2.13.0 causes the following error in parsing:

=================================== FAILURES ===================================
___________________________ test_parse_cli_args_only ___________________________

    def test_parse_cli_args_only() -> None:
        argv = [
            '--app',
            'mock-app',
            '--engine.executor',
            'thread-pool',
        ]
>       config = parse_args_to_config(argv)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/run/parse_test.py:49: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
taps/run/parse.py:192: in parse_args_to_config
    cli_settings: CliSettingsSource[Config] = CliSettingsSource(
.tox/py311/lib/python3.11/site-packages/pydantic_settings/sources/providers/cli.py:415: in __init__
    self._connect_root_parser(
.tox/py311/lib/python3.11/site-packages/pydantic_settings/sources/providers/cli.py:906: in _connect_root_parser
    self._add_parser_args(
.tox/py311/lib/python3.11/site-packages/pydantic_settings/sources/providers/cli.py:1049: in _add_parser_args
    self._add_parser_submodels(
.tox/py311/lib/python3.11/site-packages/pydantic_settings/sources/providers/cli.py:1237: in _add_parser_submodels
    self._add_argument(model_group, *(f'{flag_prefix}{name}' for name in arg_names), **kwargs)
taps/run/parse.py:51: in _add_argument
    parser.add_argument(*names, **kwargs)
/opt/hostedtoolcache/Python/3.11.14/x64/lib/python3.11/argparse.py:1473: in add_argument
    return self._add_action(action)
           ^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.11.14/x64/lib/python3.11/argparse.py:1675: in _add_action
    action = super(_ArgumentGroup, self)._add_action(action)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.11.14/x64/lib/python3.11/argparse.py:1487: in _add_action
    self._check_conflict(action)
/opt/hostedtoolcache/Python/3.11.14/x64/lib/python3.11/argparse.py:1624: in _check_conflict
    conflict_handler(action, confl_optionals)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <argparse._ArgumentGroup object at 0x7f9930c27bd0>
action = _StoreAction(option_strings=['--app'], dest='app', nargs='?', const='{}', default='==SUPPRESS==', type=None, choices=None, required=False, help='==SUPPRESS==', metavar='JSON')
conflicting_actions = [('--app', _StoreAction(option_strings=['--app'], dest='app.name', nargs=None, const=None, default='==SUPPRESS==', typ...ge', 'physics', 'synthetic', 'mock-app'], required=False, help='App choice {%(choices)s}. (required)', metavar='APP'))]

    def _handle_conflict_error(self, action, conflicting_actions):
        message = ngettext('conflicting option string: %s',
                           'conflicting option strings: %s',
                           len(conflicting_actions))
        conflict_string = ', '.join([option_string
                                     for option_string, action
                                     in conflicting_actions])
>       raise ArgumentError(action, message % conflict_string)
E       argparse.ArgumentError: argument --app: conflicting option string: --app

/opt/hostedtoolcache/Python/3.11.14/x64/lib/python3.11/argparse.py:1633: ArgumentError
_________________________ test_parse_config_file_only __________________________

tmp_path = PosixPath('/tmp/pytest-of-runner/pytest-0/test_parse_config_file_only0')

    def test_parse_config_file_only(tmp_path: pathlib.Path) -> None:
        config_text = """\
    [app]
    name = "mock-app"
    tasks = 0
    """
    
        config_file = tmp_path / 'config.toml'
        with open(config_file, 'w') as f:
            f.write(config_text)
    
>       config = parse_args_to_config(['--config', str(config_file)])
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/run/parse_test.py:87: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
taps/run/parse.py:192: in parse_args_to_config
    cli_settings: CliSettingsSource[Config] = CliSettingsSource(
.tox/py311/lib/python3.11/site-packages/pydantic_settings/sources/providers/cli.py:415: in __init__
    self._connect_root_parser(
.tox/py311/lib/python3.11/site-packages/pydantic_settings/sources/providers/cli.py:906: in _connect_root_parser
    self._add_parser_args(
.tox/py311/lib/python3.11/site-packages/pydantic_settings/sources/providers/cli.py:1049: in _add_parser_args
    self._add_parser_submodels(
.tox/py311/lib/python3.11/site-packages/pydantic_settings/sources/providers/cli.py:1237: in _add_parser_submodels
    self._add_argument(model_group, *(f'{flag_prefix}{name}' for name in arg_names), **kwargs)
taps/run/parse.py:51: in _add_argument
    parser.add_argument(*names, **kwargs)
/opt/hostedtoolcache/Python/3.11.14/x64/lib/python3.11/argparse.py:1473: in add_argument
    return self._add_action(action)
           ^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.11.14/x64/lib/python3.11/argparse.py:1675: in _add_action
    action = super(_ArgumentGroup, self)._add_action(action)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.11.14/x64/lib/python3.11/argparse.py:1487: in _add_action
    self._check_conflict(action)
/opt/hostedtoolcache/Python/3.11.14/x64/lib/python3.11/argparse.py:1624: in _check_conflict
    conflict_handler(action, confl_optionals)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <argparse._ArgumentGroup object at 0x7f9930dd1250>
action = _StoreAction(option_strings=['--app'], dest='app', nargs='?', const='{}', default='==SUPPRESS==', type=None, choices=None, required=False, help='==SUPPRESS==', metavar='JSON')
conflicting_actions = [('--app', _StoreAction(option_strings=['--app'], dest='app.name', nargs=None, const=None, default='==SUPPRESS==', typ...ge', 'physics', 'synthetic', 'mock-app'], required=False, help='App choice {%(choices)s}. (required)', metavar='APP'))]

    def _handle_conflict_error(self, action, conflicting_actions):
        message = ngettext('conflicting option string: %s',
                           'conflicting option strings: %s',
                           len(conflicting_actions))
        conflict_string = ', '.join([option_string
                                     for option_string, action
                                     in conflicting_actions])
>       raise ArgumentError(action, message % conflict_string)
E       argparse.ArgumentError: argument --app: conflicting option string: --app

/opt/hostedtoolcache/Python/3.11.14/x64/lib/python3.11/argparse.py:1633: ArgumentError
_______________________ test_parse_multiple_config_file ________________________

tmp_path = PosixPath('/tmp/pytest-of-runner/pytest-0/test_parse_multiple_config_fil0')

    def test_parse_multiple_config_file(tmp_path: pathlib.Path) -> None:
        config_text_1 = """\
    [app]
    name = "mock-app"
    tasks = 0
    """
        config_text_2 = """\
    [app]
    tasks = 1
    """
    
        config_file_1 = tmp_path / 'config-1.toml'
        with open(config_file_1, 'w') as f:
            f.write(config_text_1)
    
        config_file_2 = tmp_path / 'config-2.toml'
        with open(config_file_2, 'w') as f:
            f.write(config_text_2)
    
>       config = parse_args_to_config(
            ['--config', str(config_file_1), str(config_file_2)],
        )

tests/run/parse_test.py:112: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
taps/run/parse.py:192: in parse_args_to_config
    cli_settings: CliSettingsSource[Config] = CliSettingsSource(
.tox/py311/lib/python3.11/site-packages/pydantic_settings/sources/providers/cli.py:415: in __init__
    self._connect_root_parser(
.tox/py311/lib/python3.11/site-packages/pydantic_settings/sources/providers/cli.py:906: in _connect_root_parser
    self._add_parser_args(
.tox/py311/lib/python3.11/site-packages/pydantic_settings/sources/providers/cli.py:1049: in _add_parser_args
    self._add_parser_submodels(
.tox/py311/lib/python3.11/site-packages/pydantic_settings/sources/providers/cli.py:1237: in _add_parser_submodels
    self._add_argument(model_group, *(f'{flag_prefix}{name}' for name in arg_names), **kwargs)
taps/run/parse.py:51: in _add_argument
    parser.add_argument(*names, **kwargs)
/opt/hostedtoolcache/Python/3.11.14/x64/lib/python3.11/argparse.py:1473: in add_argument
    return self._add_action(action)
           ^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.11.14/x64/lib/python3.11/argparse.py:1675: in _add_action
    action = super(_ArgumentGroup, self)._add_action(action)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.11.14/x64/lib/python3.11/argparse.py:1487: in _add_action
    self._check_conflict(action)
/opt/hostedtoolcache/Python/3.11.14/x64/lib/python3.11/argparse.py:1624: in _check_conflict
    conflict_handler(action, confl_optionals)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <argparse._ArgumentGroup object at 0x7f9939893750>
action = _StoreAction(option_strings=['--app'], dest='app', nargs='?', const='{}', default='==SUPPRESS==', type=None, choices=None, required=False, help='==SUPPRESS==', metavar='JSON')
conflicting_actions = [('--app', _StoreAction(option_strings=['--app'], dest='app.name', nargs=None, const=None, default='==SUPPRESS==', typ...ge', 'physics', 'synthetic', 'mock-app'], required=False, help='App choice {%(choices)s}. (required)', metavar='APP'))]

    def _handle_conflict_error(self, action, conflicting_actions):
        message = ngettext('conflicting option string: %s',
                           'conflicting option strings: %s',
                           len(conflicting_actions))
        conflict_string = ', '.join([option_string
                                     for option_string, action
                                     in conflicting_actions])
>       raise ArgumentError(action, message % conflict_string)
E       argparse.ArgumentError: argument --app: conflicting option string: --app

/opt/hostedtoolcache/Python/3.11.14/x64/lib/python3.11/argparse.py:1633: ArgumentError
_____________________ test_parse_cli_args_and_config_file ______________________

tmp_path = PosixPath('/tmp/pytest-of-runner/pytest-0/test_parse_cli_args_and_config0')

    def test_parse_cli_args_and_config_file(tmp_path: pathlib.Path) -> None:
        config_text = """\
    [app]
    name = "mock-app"
    tasks = 0
    """
    
        config_file = tmp_path / 'config.toml'
        with open(config_file, 'w') as f:
            f.write(config_text)
    
        args = ['--config', str(config_file), '--app.tasks', '1']
>       config = parse_args_to_config(args)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/run/parse_test.py:133: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
taps/run/parse.py:192: in parse_args_to_config
    cli_settings: CliSettingsSource[Config] = CliSettingsSource(
.tox/py311/lib/python3.11/site-packages/pydantic_settings/sources/providers/cli.py:415: in __init__
    self._connect_root_parser(
.tox/py311/lib/python3.11/site-packages/pydantic_settings/sources/providers/cli.py:906: in _connect_root_parser
    self._add_parser_args(
.tox/py311/lib/python3.11/site-packages/pydantic_settings/sources/providers/cli.py:1049: in _add_parser_args
    self._add_parser_submodels(
.tox/py311/lib/python3.11/site-packages/pydantic_settings/sources/providers/cli.py:1237: in _add_parser_submodels
    self._add_argument(model_group, *(f'{flag_prefix}{name}' for name in arg_names), **kwargs)
taps/run/parse.py:51: in _add_argument
    parser.add_argument(*names, **kwargs)
/opt/hostedtoolcache/Python/3.11.14/x64/lib/python3.11/argparse.py:1473: in add_argument
    return self._add_action(action)
           ^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.11.14/x64/lib/python3.11/argparse.py:1675: in _add_action
    action = super(_ArgumentGroup, self)._add_action(action)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.11.14/x64/lib/python3.11/argparse.py:1487: in _add_action
    self._check_conflict(action)
/opt/hostedtoolcache/Python/3.11.14/x64/lib/python3.11/argparse.py:1624: in _check_conflict
    conflict_handler(action, confl_optionals)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <argparse._ArgumentGroup object at 0x7f99397f8ad0>
action = _StoreAction(option_strings=['--app'], dest='app', nargs='?', const='{}', default='==SUPPRESS==', type=None, choices=None, required=False, help='==SUPPRESS==', metavar='JSON')
conflicting_actions = [('--app', _StoreAction(option_strings=['--app'], dest='app.name', nargs=None, const=None, default='==SUPPRESS==', typ...ge', 'physics', 'synthetic', 'mock-app'], required=False, help='App choice {%(choices)s}. (required)', metavar='APP'))]

    def _handle_conflict_error(self, action, conflicting_actions):
        message = ngettext('conflicting option string: %s',
                           'conflicting option strings: %s',
                           len(conflicting_actions))
        conflict_string = ', '.join([option_string
                                     for option_string, action
                                     in conflicting_actions])
>       raise ArgumentError(action, message % conflict_string)
E       argparse.ArgumentError: argument --app: conflicting option string: --app

/opt/hostedtoolcache/Python/3.11.14/x64/lib/python3.11/argparse.py:1633: ArgumentError

Fixes

N/A

Type of Change

  • Bug (non-breaking change which fixes an issue)
  • Enhancement (non-breaking change which adds or improves functionality)
  • Internal (refactoring, performance, and testing)
  • Breaking (fix or feature that would cause existing functionality to not work as expected)
  • Documentation (no changes to the code)
  • Development (CI workflows, packages, templates, etc.)
  • Package (package dependencies and versions)

Testing

Tests pass on older version.

Pull Request Checklist

Please confirm the PR meets the following requirements.

  • Relevant tags are added (breaking, bug, documentation, enhancement, package, etc.).
  • Code changes pass pre-commit (e.g., ruff, mypy, etc.).
  • Tests have been added to show the fix is effective or that the new feature works.
  • New and existing unit tests pass locally with the changes.
  • Docs have been updated and reviewed if relevant.

@gpauloski gpauloski added bug Something isn't working package Dependencies, version changes, or package metadata labels Feb 16, 2026
@gpauloski gpauloski merged commit 09a7a06 into main Feb 16, 2026
6 checks passed
@gpauloski gpauloski deleted the pydantic-settings-bug branch February 16, 2026 20:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working package Dependencies, version changes, or package metadata

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant