-
-
Notifications
You must be signed in to change notification settings - Fork 105
Make InitSettingsSource
resolution deterministic
#681
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
Make InitSettingsSource
resolution deterministic
#681
Conversation
36bb51b
to
021cbaa
Compare
Thanks @enrico-stauss for the PR. @kschwab Could you review the PR? |
This is a great catch, thanks @enrico-stauss. Looks good to me. Could simplify to a single line if desired: init_kwarg_name = sorted(init_kwarg_names & set(alias_names)) |
Not sure that I understand correctly @kschwab , you want to sort the set and then always take the last element by Thanks for the approval, I'm glad I could contribute :) May I ask for the reason why nesting BaseSettings is disencouraged? Could it be that this PR voids that? |
You're right. I think currently precedence is implicit, but I agree. Stick with what you have, it's more correct.
Your fix is independent of nested BaseSettings. It's a good fix. Nesting BaseSettings can have unintended consequences since all the source modules will be re-ran at different levels. i.e., YMMV. @hramezani can likely provide more insight here. Otherwise, everything else looks good. Thanks again for the fix! |
Thanks @kschwab for the review.
This is exactly the reason and we mentioned it in the docs as well. |
Thanks both ❤️ |
My thoughts were going in the direction of "it maybe not having unintended consequences anymore" 😄 I had obviously read the dochmentation, but wanted to understand a bit better of what nature these unintended consequences are. Is there an assessment or something available? |
if the nested model inherits from Example from #426 from pydantic_settings import BaseSettings, SettingsConfigDict
class InnerSettings(BaseSettings):
port: int = 5432
class Settings(BaseSettings):
model_config = SettingsConfigDict(env_prefix="SETTINGS__", env_nested_delimiter="__")
inner_settings: InnerSettings = InnerSettings()
port: int = 5433
settings = Settings()
print(settings.model_dump()) if we run the above code with |
Thanks for the concrete example! I personally would probably consider this a feature, not a bug, since the resolution order makes sense to me. In the example I would encourage users to do: from pydantic_settings import BaseSettings, SettingsConfigDict
class InnerSettings(BaseSettings):
port: int = 5432
class Settings(BaseSettings):
model_config = SettingsConfigDict(env_prefix="SETTINGS__", env_nested_delimiter="__")
inner_settings: InnerSettings = InnerSettings(port=5432) # Explicitly pass the default to the initializer
port: int = 5433 if the default to the inner BaseSettings object should take precedence over environment variables. But I agree that this could be a bit unintuitive, given that there is no way to completely deactivate parsing of non-prefixed environment variables for inner BaseSettings objects. Maybe for Pydantic V3 you could consider having a mechanism that (by default) surpresses parsing of non-prefixed environment variables for inner BaseSettings and allows users to opt-in via the SettingsConfigDict of the outer class? This was my last thoughts on the topic, I promise I'll leave you in peace now :D |
This PR fixes the issue described in #679, by making the alias resolution in
InitSettingsSource
deterministically follow the configured precedence.