Description
pydantic version: 2.8.0
OS: confirmed broken on Windows and Linux, haven't tested others
pydantic-settings version: 2.3.2
Hello, I noticed that there is a breaking change in pydantic-settings==2.3.2
, which I think was introduced by PR: #309. Here is a minimal working example:
from pydantic import BaseModel, field_validator
import os
from pydantic_settings import BaseSettings, SettingsConfigDict
class Child(BaseModel):
ATTRIBUTE: list[str]
@field_validator("ATTRIBUTE", mode="before")
def convert_fields(cls, input: str) -> list[str]:
return input.split("|")
class Parent(BaseSettings):
model_config = SettingsConfigDict(
env_prefix="PREFIX_",
env_nested_delimiter="__",
case_sensitive=False,
env_file_encoding="utf-8",
)
child: Child
os.environ["PREFIX_CHILD__ATTRIBUTE"] = "a|b|c"
settings = Parent()
assert settings.child.ATTRIBUTE == ["a", "b", "c"]
This test passes for pydantic-settings
up to and including 2.3.1, but has been broken since 2.3.2. The test doesn't simply fail: the instantiation of Parent
raises with the following traceback:
Traceback (most recent call last):
File "C:\proj\pypoetry\virtualenvs\pydantic-test-fL1284vF-py3.11\Lib\site-packages\pydantic_settings\sources.py", line 375, in __call__
field_value = self.prepare_field_value(field_name, field, field_value, value_is_complex)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\proj\pypoetry\virtualenvs\pydantic-test-fL1284vF-py3.11\Lib\site-packages\pydantic_settings\sources.py", line 568, in prepare_field_value
env_val_built = self.explode_env_vars(field_name, field, self.env_vars)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\proj\pypoetry\virtualenvs\pydantic-test-fL1284vF-py3.11\Lib\site-packages\pydantic_settings\sources.py", line 703, in explode_env_vars
raise e
File "C:\proj\pypoetry\virtualenvs\pydantic-test-fL1284vF-py3.11\Lib\site-packages\pydantic_settings\sources.py", line 700, in explode_env_vars
env_val = self.decode_complex_value(last_key, target_field, env_val) # type: ignore
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\proj\pypoetry\virtualenvs\pydantic-test-fL1284vF-py3.11\Lib\site-packages\pydantic_settings\sources.py", line 187, in decode_complex_value
return json.loads(value)
^^^^^^^^^^^^^^^^^
File "C:\Python\Python311\Lib\json\__init__.py", line 346, in loads
return _default_decoder.decode(s)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Python\Python311\Lib\json\decoder.py", line 337, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Python\Python311\Lib\json\decoder.py", line 355, in raw_decode
raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "C:\software\pydantic-test\test.py", line 26, in <module>
settings = Parent()
^^^^^^^^
File "C:\proj\pypoetry\virtualenvs\pydantic-test-fL1284vF-py3.11\Lib\site-packages\pydantic_settings\main.py", line 141, in __init__
**__pydantic_self__._settings_build_values(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\proj\pypoetry\virtualenvs\pydantic-test-fL1284vF-py3.11\Lib\site-packages\pydantic_settings\main.py", line 311, in _settings_build_values
return deep_update(*reversed([source() for source in sources]))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\proj\pypoetry\virtualenvs\pydantic-test-fL1284vF-py3.11\Lib\site-packages\pydantic_settings\main.py", line 311, in <listcomp>
return deep_update(*reversed([source() for source in sources]))
^^^^^^^^
File "C:\proj\pypoetry\virtualenvs\pydantic-test-fL1284vF-py3.11\Lib\site-packages\pydantic_settings\sources.py", line 377, in __call__
raise SettingsError(
pydantic_settings.sources.SettingsError: error parsing value for field "child" from source "EnvSettingsSource"
So it's trying to JSON-decode the string "a|b|c"
and failing. But my field_validator
is running in "before"
mode
so this shouldn't happen. Indeed, if I simply comment-out the field_validator
I see exactly the same error. So I believe that decorator is either being ignored altogether, or "before"
mode has been broken.