-
-
Notifications
You must be signed in to change notification settings - Fork 61
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
BaseSettings validates default field value #166
Comments
Thanks @stinovlas for reporting this 🙏 You are right. pydantic-settings validates default value and we need to document it. Would you like to open a PR? |
Before I do open anything, I'd like to know a bit more about reasoning. Why does |
It is the same behavior in settings management in
Yes
Why did you annotate |
I load most of my settings either from env variables or static config files (usually YAML, but format does not matter). You can't represent ZONE=Europe/Prague python example.py Maybe this is not the recommended way to load strings into more complex types? If you know about a better pattern, I'll be happy to learn about it. Anyway, I think that I know enough to create PR for documentation update. I'll put it together and submit a PR. Pydantic is fantastic library and I'm happy I'll be able to contribute my tiny bit to it 🙂. |
You can use the following code: from zoneinfo import ZoneInfo
from pydantic import BeforeValidator
from pydantic.functional_validators import BeforeValidator
from pydantic_settings import BaseSettings
from typing_extensions import Annotated
class Settings(BaseSettings):
zone: Annotated[ZoneInfo, BeforeValidator(lambda x: ZoneInfo(x) if isinstance(x, str) else x)] = ZoneInfo("UTC")
print(repr(Settings().zone)) |
Well of course I can :-). In fact, if I were doing something like this, I'd probably enclose it to a separate function. Or used the I opened #168 with the docs amend ;-). |
what do you mean by
Thanks! I will take a look! |
This is highly opinionated and I certainly don't want to force my opinions on anyone. So, just for the illustration of what I consider clean (this is a bit off-topic, but I intend to not to dive further): Clean code is easy to readAfter all, code is usually written once, read many times. For this reason, I like the Writing Clean code does not repeat itselfBut, if I need to create helper function for each data type, it can get a bit messy. Of course, I could (and would) enclose those helper functions to separate module, but maybe I could even build a decorator that takes a type and returns a function that applies the type on its argument unless it already is an instance of that type. That would simplify things down. But... Simple is better than complexSuch decorator can be a bit hard to understand, especially for less experienced developers who may need to work on the code base. I have to give you one thing. Explicit conversion function is probably better than just using the type as a conversion tool. This validator has the undeniable advantage of being source-agnostic. I can imagine pydantic doing this conversion auto-magically, but I can also see valid arguments against such behaviour (mostly explicit is better than implicit). |
Thanks for explaning.
The lambda was an example to make it short. for sure you can define your own conversion function and use it.
You are using a custom data type which Pydantic does not support it internally. If you have different approach of conversion you need to write different conversion functions and you are not repeating yourself. In general I would say IMHO, there shouldn't be a big difference between |
Co-authored-by: Hasan Ramezani <[email protected]>
Summary
BaseSettings
, unlikeBaseModel
validates field default value. This contradicts the documentation. pydantic docs state:Documentation of
pydantic-settings
doesn't mention exception from this behavior.I don't know whether this behavior is intended or not (I'd guess not, because workarounds are quite ugly, see below). But even if it is, it should probably be documented in
pydantic-settings
docs.Minimal working example
python -V
pip --list
Workarounds
validate_default=False
explicitely. This works, but is unnecessarily verbose:The text was updated successfully, but these errors were encountered: