Skip to content

pydantic-settings new version can't handle scenario #422

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
hsuyuming opened this issue Sep 25, 2024 · 2 comments
Closed

pydantic-settings new version can't handle scenario #422

hsuyuming opened this issue Sep 25, 2024 · 2 comments
Assignees
Labels
bug Something isn't working duplicate This issue or pull request already exists

Comments

@hsuyuming
Copy link

hsuyuming commented Sep 25, 2024

Hi All:

Recently, we get an error when we define "discriminated union" for one field within BaseSettings, and use _env_file to construct the class which was working fine before.

Enviroment

(.venv_pydantic_settings_2_5_2) user@jupyter:/abehsu/pydantic_testing$ python --version
Python 3.10.12
(.venv_pydantic_settings_2_5_2) user@jupyter:
/abehsu/pydantic_testing$ pip list | grep pydantic
pydantic 2.9.2
pydantic_core 2.23.4
pydantic-settings 2.5.2

Error message

(.venv_pydantic_settings_2_5_2) user@abehsu-us-vscode:~/abehsu/pydantic_testing$ python test.py 
Traceback (most recent call last):
  File "/home/user/abehsu/pydantic_testing/test.py", line 40, in <module>
    result = Html(_env_file="/home/user/abehsu/pydantic_testing/test.env")
  File "/home/user/abehsu/pydantic_testing/.venv_pydantic_settings_2_5_2/lib/python3.10/site-packages/pydantic_settings/main.py", line 152, in __init__
    super().__init__(
  File "/home/user/abehsu/pydantic_testing/.venv_pydantic_settings_2_5_2/lib/python3.10/site-packages/pydantic/main.py", line 212, in __init__
    validated_self = self.__pydantic_validator__.validate_python(data, self_instance=self)
pydantic_core._pydantic_core.ValidationError: 2 validation errors for Html
contents__el_type
  Extra inputs are not permitted [type=extra_forbidden, input_value='input', input_type=str]
    For further information visit https://errors.pydantic.dev/2.9/v/extra_forbidden
contents__class_name
  Extra inputs are not permitted [type=extra_forbidden, input_value='123', input_type=str]
    For further information visit https://errors.pydantic.dev/2.9/v/extra_forbidden

Code

from typing import Any, Literal

from pydantic import BaseModel, Field
from pydantic_settings import BaseSettings, SettingsConfigDict

class DivModel(BaseModel):
    el_type: Literal['div'] = 'div'
    class_name: str | None = None
    children: list[Any] | None = None


class SpanModel(BaseModel):
    el_type: Literal['span'] = 'span'
    class_name: str | None = None
    contents: str | None = None


class ButtonModel(BaseModel):
    el_type: Literal['button'] = 'button'
    class_name: str | None = None
    contents: str | None = None


class InputModel(BaseModel):
    el_type: Literal['input'] = 'input'
    class_name: str | None = None
    value: str | None = None


class Html(BaseSettings):
    contents: DivModel | SpanModel | ButtonModel | InputModel = Field(
        discriminator='el_type'
    )

    model_config = SettingsConfigDict(
        env_nested_delimiter="__",
    )


result = Html(_env_file="/home/user/abehsu/pydantic_testing/test.env")
print(result)
contents__el_type=input
contents__class_name=123

==================================================

The same code can successfully if i use pydantic-settings 2.4.0 version.

(.venv_pydantic_settings_2_4_0) user@abehsu-us-vscode:~/abehsu/pydantic_testing$ python --version
Python 3.10.12
(.venv_pydantic_settings_2_4_0) user@abehsu-us-vscode:~/abehsu/pydantic_testing$ pip list | grep pydantic
pydantic             2.8.2
pydantic_core        2.20.1
pydantic-extra-types 2.9.0
pydantic-settings    2.4.0
(.venv_pydantic_settings_2_4_0) user@abehsu-us-vscode:~/abehsu/pydantic_testing$ python test.py 
contents=InputModel(el_type='input', class_name='123', value=None)

After comparison, i find out it is because this line be added from last week's release (https://github.com/pydantic/pydantic-settings/blob/main/pydantic_settings/sources.py#L989) by this PR (287cb22), are there any suggestion?

https://github.com/pydantic/pydantic/blob/c9190eedd8c536cd1445876c4a078c29b04d3aa1/pydantic/_internal/_utils.py#L76-L82

def lenient_issubclass(cls: Any, class_or_tuple: Any) -> bool:  # pragma: no cover
    try:
        return isinstance(cls, type) and issubclass(cls, class_or_tuple)
    except TypeError:
        if isinstance(cls, _typing_extra.WithArgsTypes):
            return False
        raise  # pragma: no cover
(Pdb) l
 75  
 76     def lenient_issubclass(cls: Any, class_or_tuple: Any) -> bool:  # pragma: no cover
 77         try:
 78             if cls != {}:
 79                 breakpoint()
 80  ->         return isinstance(cls, type) and issubclass(cls, class_or_tuple)
 81         except TypeError:
 82             if isinstance(cls, _typing_extra.WithArgsTypes):
 83                 return False
 84             raise  # pragma: no cover
 85  
(Pdb) cls
__main__.DivModel | __main__.SpanModel | __main__.ButtonModel | __main__.InputModel
(Pdb) isinstance(cls, type)
False
(Pdb) type(cls)
<class 'types.UnionType'>

(Pdb) issubclass(cls, class_or_tuple)
*** TypeError: issubclass() arg 1 must be a class
@hramezani
Copy link
Member

Thanks @hsuyuming for reporting this bug.

I think it is a duplicate of #420

I created #423 as a fix. Could you please confirm the fix?

@hramezani hramezani added bug Something isn't working duplicate This issue or pull request already exists and removed unconfirmed labels Sep 26, 2024
@hramezani
Copy link
Member

Fixed in f3a25f2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working duplicate This issue or pull request already exists
Projects
None yet
Development

No branches or pull requests

2 participants