pydantic-settings
pydantic-settings copied to clipboard
Add `RootSettings`
After making a discussion, question, and not getting any answers, I assume the functionality I'm looking for is not implemented, so I am making a feature request.
I want to use a following model for my settings:
import pydantic
class Clustered(pydantic.BaseModel):
is_clustered: typing.Literal[True]
server_name: str
class NonClustered(pydantic.BaseModel):
is_clustered: typing.Literal[False] = False
Settings = pydantic.RootModel[Clustered | NonClustered]
~~In pydantic v1 it was possible to do such a thing (I think)~~
EDIT: Nope it wasn't
root@b8ce1c649a1f:/# cat main.py
import typing
import pydantic
class Clustered(pydantic.BaseModel):
is_clustered: typing.Literal[True]
server_name: str
class NonClustered(pydantic.BaseModel):
is_clustered: typing.Literal[False] = False
class Settings(pydantic.BaseSettings):
__root__: Clustered | NonClustered
print(Settings().dict())
root@b8ce1c649a1f:/# python main.py
Traceback (most recent call last):
File "//main.py", line 15, in <module>
print(Settings().dict())
^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/pydantic/env_settings.py", line 40, in __init__
super().__init__(
File "/usr/local/lib/python3.12/site-packages/pydantic/main.py", line 341, in __init__
raise validation_error
pydantic.error_wrappers.ValidationError: 1 validation error for Settings
__root__
field required (type=value_error.missing
But in v2 __root__
was removed, and multiple inheritance does not work:
>>> class Settings(pydantic_settings.BaseSettings, pydantic.RootModel[NonClustered | Clustered]): pass
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.12/site-packages/pydantic/_internal/_model_construction.py", line 117, in __new__
cls: type[BaseModel] = super().__new__(mcs, cls_name, bases, namespace, **kwargs) # type: ignore
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "<frozen abc>", line 106, in __new__
File "/usr/local/lib/python3.12/site-packages/pydantic/root_model.py", line 50, in __init_subclass__
raise PydanticUserError(
pydantic.errors.PydanticUserError: `RootModel` does not support setting `model_config['extra']`
What I assume needs to happen is RootSettings
has to be added, so the following code can be written:
Settings = pydantic_settings.RootSettings[Clustered | NonClustered]
Thanks @rijenkii for reporting this.
Yeah, it is not possible in pydantic-settings
but I think it is not possible to fetch data from env variables with your provided example in v1:
class Settings(pydantic.BaseSettings):
__root__: Clustered | NonClustered
Have you tried it in v1?
You are right, it is not possible. I thought I've tried that, but it seems I've messed up somewhere. I've edited the OP (and the stackoverflow question) and redacted the part about v1.
@hramezani Actually, what was possible in pydantic v1 (given the example above):
Settings = typing.Union[Clustered, NonClustered]
pydantic.parse_obj_as(Settings)
Now fails when is_clustered=False
in env var (I assume that it disregards the union).
Any way around this, if we want to upgrade to pydantic v2?
@pavelrib Have you tried TypeAdapter
@hramezani Thanks for the heads up, but can you please give an example of the usage in that case? I've figured you meant probably:
Settings: TypeAdapter[typing.Union[Clustered, NonClustered]] = TypeAdapter(typing.Union[Clustered, NonClustered])
But what's the next step to evaluate Settings? All examples show validation with an actual object, but here the values should be implicitly read from env.
@hramezani Is there anything that I'm missing here?
No, I think TypeAdapter
is not good for this usecase
@hramezani Is there any plan to add it in the near future? I've tried playing with different definitions and parsing methods to no avail.
@pavelrib I don't think that I can add it shortly. I hope some contributors work on this but this can be a complex feature