Skip to content

Commit

Permalink
Support TypedDict
Browse files Browse the repository at this point in the history
  • Loading branch information
Viicos committed Sep 20, 2023
1 parent 0016cf0 commit 09919ae
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 12 deletions.
12 changes: 12 additions & 0 deletions pydantic/_internal/_generate_schema.py
Expand Up @@ -71,6 +71,7 @@
inspect_model_serializer,
inspect_validator,
)
from ._docs_extraction import extract_docstrings_from_cls
from ._fields import collect_dataclass_fields, get_type_hints_infer_globalns
from ._forward_ref import PydanticRecursiveRef
from ._generics import get_standard_typevars_map, has_instance_in_type, recursively_defined_type_refs, replace_types
Expand Down Expand Up @@ -1057,6 +1058,11 @@ def _typed_dict_schema(self, typed_dict_cls: Any, origin: Any) -> core_schema.Co

decorators = DecoratorInfos.build(typed_dict_cls)

if self._config_wrapper.use_attributes_docstring:
field_docstrings = extract_docstrings_from_cls(typed_dict_cls)
else:
field_docstrings = None

for field_name, annotation in get_type_hints_infer_globalns(
typed_dict_cls, localns=self._types_namespace, include_extras=True
).items():
Expand All @@ -1077,6 +1083,12 @@ def _typed_dict_schema(self, typed_dict_cls: Any, origin: Any) -> core_schema.Co
)[0]

field_info = FieldInfo.from_annotation(annotation)
if (
field_docstrings is not None
and field_info.description is None
and field_name in field_docstrings
):
field_info.description = field_docstrings[field_name]
fields[field_name] = self._generate_td_field_schema(
field_name, field_info, decorators, required=required
)
Expand Down
39 changes: 27 additions & 12 deletions tests/test_docs_extraction.py
Expand Up @@ -70,7 +70,7 @@ class ModelDCNoDocs:


def test_dataclass_docs_extraction():
@pydantic_dataclass(config=ConfigDict(use_attributes_docstring=True), kw_only=True)
@pydantic_dataclass(config=ConfigDict(use_attributes_docstring=True))
class ModelDCDocs:
a: int
"""A docs"""
Expand All @@ -80,26 +80,26 @@ class ModelDCDocs:
c: int = 1
# This isn't used as a description.

d: int
d: int = 1

def dummy_method(self) -> None:
"""Docs for dummy_method that won't be used for d"""

e: int = Field(1, description='Real description')
"""Won't be used"""

f: int
f: int = 1
"""F docs"""

"""Useless docs"""

g: int
g: int = 1
"""G docs"""

h = 1
"""H docs"""

i: Annotated[int, Field(description='Real description')]
i: Annotated[int, Field(description='Real description')] = 1
"""Won't be used"""

assert ModelDCDocs.__pydantic_fields__['a'].description == 'A docs'
Expand All @@ -108,32 +108,47 @@ def dummy_method(self) -> None:
assert ModelDCDocs.__pydantic_fields__['d'].description is None
assert ModelDCDocs.__pydantic_fields__['e'].description == 'Real description'
assert ModelDCDocs.__pydantic_fields__['g'].description == 'G docs'
assert ModelDCDocs.__pydantic_fields__['i'].description == 'Real description' # TODO What is happening here?
# Annotated[..., Field(...)] doesn't seem to work for dataclasses
assert ModelDCDocs.__pydantic_fields__['i'].description == 'Real description'


def test_typeddict():
class ModelTD(TypedDict):
class ModelTDNoDocs(TypedDict):
a: int
"""A docs"""

ta = TypeAdapter(ModelTD)
ta = TypeAdapter(ModelTDNoDocs)
assert ta.json_schema() == {
'properties': {'a': {'title': 'A', 'type': 'integer'}},
'required': ['a'],
'title': 'Model',
'title': 'ModelTDNoDocs',
'type': 'object',
}

class Model(TypedDict):
class ModelTDDocs(TypedDict):
a: int
"""A docs"""

__pydantic_config__ = ConfigDict(use_attributes_docstring=True)

ta = TypeAdapter(ModelTDDocs)

assert ta.json_schema() == {
'properties': {'a': {'title': 'A', 'type': 'integer', 'description': 'A docs'}},
'required': ['a'],
'title': 'Model',
'title': 'ModelTDDocs',
'type': 'object',
}


def test_typeddict_as_field():
class ModelTDAsField(TypedDict):
a: int
"""A docs"""

__pydantic_config__ = ConfigDict(use_attributes_docstring=True)

class ModelWithTDField(BaseModel):
td: ModelTDAsField

a_property = ModelWithTDField.model_json_schema()['$defs']['ModelTDAsField']['properties']['a']
assert a_property['description'] == 'A docs'

0 comments on commit 09919ae

Please sign in to comment.