Skip to content
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

Add RootSettings #200

Open
rijenkii opened this issue Dec 6, 2023 · 9 comments
Open

Add RootSettings #200

rijenkii opened this issue Dec 6, 2023 · 9 comments
Assignees

Comments

@rijenkii
Copy link

rijenkii commented Dec 6, 2023

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]
@hramezani
Copy link
Member

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?

@rijenkii
Copy link
Author

rijenkii commented Dec 6, 2023

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.

@pavelrib
Copy link

@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?

@hramezani
Copy link
Member

@pavelrib
Have you tried TypeAdapter

@pavelrib
Copy link

@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.

@pavelrib
Copy link

@hramezani Is there anything that I'm missing here?

@hramezani
Copy link
Member

No, I think TypeAdapter is not good for this usecase

@pavelrib
Copy link

@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.

@hramezani
Copy link
Member

@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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants