Skip to content

Regression for bool fields since 2.13 #782

@Geo5

Description

@Geo5

Hi,
since version 2.13 (i think concretely since #717) it is very easy to break bool arguments. The reason for this is non-type things inside the field metadata, e.g. by using CliSuppress or StrictBool. The following script breaks:

import pydantic_settings
from pydantic_settings import BaseSettings, CliApp, CliSuppress


class Settings(BaseSettings):
    field: CliSuppress[bool]


def parse_args():
    print(f'{pydantic_settings.VERSION=}')
    settings = CliApp.run(Settings)
    print(f'{settings=}')
    return settings


def main() -> None:
    parse_args()


if __name__ == '__main__':
    main()
$ python test_suppress.py
pydantic_settings.VERSION='2.13.0'
Traceback (most recent call last):
  File "/home/georg/Documents/denkweit/git/pydantic-settings/test_suppress.py", line 21, in <module>
    main()
  File "/home/georg/Documents/denkweit/git/pydantic-settings/test_suppress.py", line 17, in main
    parse_args()
  File "/home/georg/Documents/denkweit/git/pydantic-settings/test_suppress.py", line 11, in parse_args
    settings = CliApp.run(Settings)
               ^^^^^^^^^^^^^^^^^^^^
  File "/home/georg/Documents/denkweit/git/pydantic-settings/pydantic_settings/main.py", line 733, in run
    sources, init_kwargs = model_cls._settings_init_sources(**model_init_data)
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/georg/Documents/denkweit/git/pydantic-settings/pydantic_settings/main.py", line 424, in _settings_init_sources
    cli_settings = CliSettingsSource[Any](
                   ^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/georg/.local/share/uv/python/cpython-3.11.10-linux-x86_64-gnu/lib/python3.11/typing.py", line 1289, in __call__
    result = self.__origin__(*args, **kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/georg/Documents/denkweit/git/pydantic-settings/pydantic_settings/sources/providers/cli.py", line 415, in __init__
    self._connect_root_parser(
  File "/home/georg/Documents/denkweit/git/pydantic-settings/pydantic_settings/sources/providers/cli.py", line 906, in _connect_root_parser
    self._add_parser_args(
  File "/home/georg/Documents/denkweit/git/pydantic-settings/pydantic_settings/sources/providers/cli.py", line 1046, in _add_parser_args
    self._convert_bool_flag(arg.kwargs, field_info, model_default)
  File "/home/georg/Documents/denkweit/git/pydantic-settings/pydantic_settings/sources/providers/cli.py", line 1088, in _convert_bool_flag
    meta_bool_flags = [
                      ^
  File "/home/georg/Documents/denkweit/git/pydantic-settings/pydantic_settings/sources/providers/cli.py", line 1089, in <listcomp>
    meta for meta in field_info.metadata if issubclass(meta, _CliImplicitFlag | _CliExplicitFlag)
                                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: issubclass() arg 1 must be a class

Here is the link to the erroring line:

meta for meta in field_info.metadata if issubclass(meta, _CliImplicitFlag | _CliExplicitFlag)

Which raises the above exception, because CliSuppress, which is a literal string ("==SUPPRESS==") is inside field_info.metadata and which cannot be passed as 1st argument to issubclass

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions