Open LachlanMarnham opened 3 days ago
Thanks @LachlanMarnham for reporting this.
Actually, the example code shouldn't have worked before because ATTRIBUTE
field's type is list[str]
, and pydantic-settings
considers it as a complex field. pydantic-settings
parses the values of the complex field and this is the reason that you get the error.
By fixing the bug that we had before, you don't need a field_validator
anymore. you can pass a list as value and pydantic-settings
parses it.
from pydantic import BaseModel
import os
from pydantic_settings import BaseSettings, SettingsConfigDict
class Child(BaseModel):
ATTRIBUTE: list[str]
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"]
Ok thanks @hramezani. I think this is maybe a problem of documentation, with a conflict between pydantic
and pydantic-settings
. To your point, the pydantic-settings
documentation does say:
Complex types like list, set, dict, and sub-models are populated from the environment by treating the environment variable's value as a JSON-encoded string.
Which is fair enough. However, pydantic
guarantees that I can avoid this behaviour if I want to:
Before validators run before Pydantic's internal parsing and validation (e.g. coercion of a str to an int). These are more flexible than After validators since they can modify the raw input, but they also have to deal with the raw input, which in theory could be any arbitrary object.
It does feel a bit as if pydantic-settings
is breaking a contract with pydantic
here, given that internal parsing and validation is in fact taking place before the before
validator.
Good point @LachlanMarnham.
The json parsing behavior was in pydanatic-settings v1(actually pydantic. because pydantic-settings was in pydantic in V1)
. That's why we keep the behavior in V2. I think we can have a config flag to disable parsing and let the people parse the value by before field_validator
I think we can have a config flag...
Do you mean a flag in the SettingsConfigDict
? I guess such a flag can't really be added to the field_validator
itself since that's owned by pydantic
. Personally I don't rely on any settings being JSON, but I can imagine that some people might think it is a bit too much for the two options to be "all fields must be JSON"
and "JSON de-serlialisation will be switched off anywhere"
(unless I am mis-understanding you).
Maybe the way I'm using pydantic-settings
is a bit of an edge case, seeing as 2.3.2 was released a few weeks ago and nobody else has raised a ticket yet. If you think the current behaviour is correct, just a bit out of sync with the documentation, I can open a PR to update the docs.
Thanks
Yes, I meant a flag in pydantic-settings SettingsConfigDict
like enable_json_parsing
which has two values:
True
- keeps the current behavior of pydantic-setting and is the default to prevent breaking changeFalse
- disables the json parsing of values and pass the value to pydantic. we can have field_validator
in this case to parse the values if we want.Maybe the way I'm using pydantic-settings is a bit of an edge case, seeing as 2.3.2 was released a few weeks ago and nobody else has raised a ticket yet. If you think the current behaviour is correct, just a bit out of sync with the documentation, I can open a PR to update the docs.
Yes, I think the current behaviour is correct. what do you think? which part is wrong?
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: https://github.com/pydantic/pydantic-settings/pull/309. Here is a minimal working example: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 ofParent
raises with the following traceback:So it's trying to JSON-decode the string
"a|b|c"
and failing. But myfield_validator
is running in"before"
mode so this shouldn't happen. Indeed, if I simply comment-out thefield_validator
I see exactly the same error. So I believe that decorator is either being ignored altogether, or"before"
mode has been broken.