Skip to content

Commit

Permalink
Change field_is_complex to be more similar to pydantic v1
Browse files Browse the repository at this point in the history
  • Loading branch information
dmontagu committed Apr 27, 2023
1 parent 6d9c1a2 commit 6275726
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 5 deletions.
36 changes: 31 additions & 5 deletions pydantic_settings/sources.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@
import os
import warnings
from abc import ABC, abstractmethod
from collections import deque
from dataclasses import is_dataclass
from pathlib import Path
from typing import TYPE_CHECKING, Any, Dict, List, Mapping, Optional, Tuple, Type, Union
from typing import TYPE_CHECKING, Any, Dict, List, Mapping, Optional, Sequence, Tuple, Type, Union

from pydantic import BaseModel
from pydantic._internal._typing_extra import origin_is_union
from pydantic._internal._utils import deep_update, lenient_issubclass
from pydantic.fields import FieldInfo
from typing_extensions import get_origin
from typing_extensions import get_args, get_origin

from pydantic_settings.utils import path_type_label

Expand Down Expand Up @@ -53,10 +54,16 @@ def get_field_value(self, field: FieldInfo, field_name: str) -> Tuple[Any, str,
pass

def field_is_complex(self, field: FieldInfo) -> bool:
def _annotation_is_complex(annotation: type[Any] | None) -> bool:
return lenient_issubclass(annotation, (BaseModel, list, set, frozenset, dict)) or is_dataclass(annotation)
"""
Checks whether a field is complex, in which case it will attempt to be parsed as JSON.
Args:
field (FieldInfo): The field.
return _annotation_is_complex(field.annotation) or _annotation_is_complex(get_origin(field.annotation))
Returns:
bool: Whether the field is complex.
"""
return _annotation_is_complex(field.annotation)

def prepare_field_value(self, field_name: str, field: FieldInfo, value: Any, value_is_complex: bool) -> Any:
"""
Expand Down Expand Up @@ -433,3 +440,22 @@ def find_case_path(dir_path: Path, file_name: str, case_sensitive: bool) -> Opti
elif not case_sensitive and f.name.lower() == file_name.lower():
return f
return None


def _annotation_is_complex(annotation: type[Any] | None) -> bool:
origin = get_origin(annotation)
return (
_annotation_is_complex_inner(annotation)
or _annotation_is_complex_inner(origin)
or hasattr(origin, '__pydantic_core_schema__')
or hasattr(origin, '__get_pydantic_core_schema__')
)


def _annotation_is_complex_inner(annotation: type[Any] | None) -> bool:
if lenient_issubclass(annotation, str):
return False

return lenient_issubclass(annotation, (BaseModel, Mapping, Sequence, tuple, set, frozenset, deque)) or is_dataclass(
annotation
)
4 changes: 4 additions & 0 deletions tests/test_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,10 @@ class B(BaseSettings):
class Settings(BaseSettings):
content: Union[A, B, datetime]

env.set('content', '{"a": "test"}')
s = Settings()
assert s.content == A(a='test')

env.set('content', '2020-07-05T00:00:00Z')
s = Settings()
assert s.content == datetime(2020, 7, 5, 0, 0, tzinfo=timezone.utc)
Expand Down

0 comments on commit 6275726

Please sign in to comment.