-
-
Notifications
You must be signed in to change notification settings - Fork 92
Inspect type aliases to determine if an annotation is complex #644
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
Conversation
6a5e7ad
to
5f9a0bf
Compare
Thanks @tselepakis, I would suggest using the following patch instead: diff --git a/pydantic_settings/sources/base.py b/pydantic_settings/sources/base.py
index b2c4d16..881546b 100644
--- a/pydantic_settings/sources/base.py
+++ b/pydantic_settings/sources/base.py
@@ -16,6 +16,7 @@ from pydantic._internal._typing_extra import ( # type: ignore[attr-defined]
from pydantic._internal._utils import is_model_class
from pydantic.fields import FieldInfo
from typing_extensions import get_args
+from typing_inspection import typing_objects
from typing_inspection.introspection import is_union_origin
from ..exceptions import SettingsError
@@ -353,6 +354,12 @@ class PydanticBaseEnvSettingsSource(PydanticBaseSettingsSource):
field_info.append((v_alias, self._apply_case_sensitive(v_alias), False))
if not v_alias or self.config.get('populate_by_name', False):
+ if typing_objects.is_typealiastype(field.annotation) or typing_objects.is_typealiastype(get_origin(field.annotation)):
+ annotation = field.annotation.__value__
+ else:
+ annotation = field.annotation
+ if typing_objects.is_annotated(get_origin(annotation)):
+ annotation = annotation.__origin__
if is_union_origin(get_origin(field.annotation)) and _union_is_complex(field.annotation, field.metadata):
field_info.append((field_name, self._apply_case_sensitive(self.env_prefix + field_name), True))
else:
diff --git a/pydantic_settings/sources/utils.py b/pydantic_settings/sources/utils.py
index 270a8c1..498a8dc 100644
--- a/pydantic_settings/sources/utils.py
+++ b/pydantic_settings/sources/utils.py
@@ -43,6 +43,9 @@ def parse_env_vars(
def _annotation_is_complex(annotation: type[Any] | None, metadata: list[Any]) -> bool:
# If the model is a root model, the root annotation should be used to
# evaluate the complexity.
+ if typing_objects.is_typealiastype(annotation) or typing_objects.is_typealiastype(get_origin(annotation)):
+ annotation = annotation.__value__
+
if annotation is not None and _lenient_issubclass(annotation, RootModel) and annotation is not RootModel:
annotation = cast('type[RootModel[Any]]', annotation)
root_annotation = annotation.model_fields['root'].annotation That's really hacky and looking at the code related to this I'm pretty sure it contains many other bugs, but we can't do better considering the current state of |
Thanks for the review and the detailed patch, @Viicos. I appreciate you taking the time to provide a solution. I have a question regarding the first change in base.py. You've introduced a new annotation variable that strips away TypeAlias and Annotated wrappers. However, the is_union_origin check immediately after that, still uses get_origin(field.annotation) instead of get_origin(annotation). Was this intentional, or should the Additionally, could you please explain the specific bug or use case that this logic is intended to cover (if I remove this part my test still passes, perhaps we need another test to cover this case)? I'm trying to understand which scenario requires us to check for is_typealiastype and is_annotated here. As you mentioned that the solution is "hacky", understanding the exact case would be very helpful for me. |
That's an oversight sorry, it should check
I believe both options would have worked but yours was more likely to cause unexpected issues as you implemented the type alias "unpacking" in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @tselepakis!
This PR ensures that type aliases declared using type (PEP 695) are correctly resolved and handled during environment value parsing and model field introspection.
I aimed to keep the changes minimal, but addressing compatibility issues required introducing a couple of new patterns, specifically to work around syntax errors triggered by pytest when using Python versions <3.12, as well as ruff linter errors. If there are better or more idiomatic approaches, I'm happy to discuss them. I'm not certain the current solutions are the best long-term fit for the project.
Fixes #536