Skip to content

Commit

Permalink
fix: DTO transfer pydantic field descriptions.
Browse files Browse the repository at this point in the history
Closes #3232
  • Loading branch information
peterschutt committed Mar 22, 2024
1 parent e763cea commit 9756003
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 7 deletions.
11 changes: 7 additions & 4 deletions litestar/dto/_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -750,14 +750,17 @@ def _create_struct_field_meta_for_field_definition(field_definition: TransferDTO
return None

return msgspec.Meta(
gt=kwarg_definition.gt,
description=kwarg_definition.description,
examples=[e.value for e in kwarg_definition.examples or []],
ge=kwarg_definition.ge,
lt=kwarg_definition.lt,
gt=kwarg_definition.gt,
le=kwarg_definition.le,
multiple_of=kwarg_definition.multiple_of,
min_length=kwarg_definition.min_length if not field_definition.is_partial else None,
lt=kwarg_definition.lt,
max_length=kwarg_definition.max_length if not field_definition.is_partial else None,
min_length=kwarg_definition.min_length if not field_definition.is_partial else None,
multiple_of=kwarg_definition.multiple_of,
pattern=kwarg_definition.pattern,
title=kwarg_definition.title,
)


Expand Down
40 changes: 39 additions & 1 deletion tests/unit/test_contrib/test_pydantic/test_dto.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from __future__ import annotations

from typing import TYPE_CHECKING, Optional
from typing import TYPE_CHECKING, Optional, cast

import pytest
from pydantic import v1 as pydantic_v1
Expand All @@ -13,8 +13,13 @@
from litestar.typing import FieldDefinition

if TYPE_CHECKING:
from collections.abc import Callable
from types import ModuleType

from pydantic import BaseModel

from litestar import Litestar


def test_schema_required_fields_with_pydantic_dto(
use_experimental_dto_backend: bool, base_model: type[BaseModel]
Expand Down Expand Up @@ -62,3 +67,36 @@ class Model(pydantic_v1.BaseModel):
dto_type = PydanticDTO[Model]
assert dto_type.detect_nested_field(FieldDefinition.from_annotation(Model)) is True
assert dto_type.detect_nested_field(FieldDefinition.from_annotation(int)) is False


def test_pydantic_field_descriptions(create_module: Callable[[str], ModuleType]) -> None:
module = create_module(
"""
from litestar import Litestar, get
from litestar.contrib.pydantic import PydanticDTO
from litestar.dto import DTOConfig
from pydantic import BaseModel, Field
from typing_extensions import Annotated
class User(BaseModel):
id: Annotated[
int,
Field(description="This is a test (id description)."),
]
class DataCollectionDTO(PydanticDTO[User]):
config = DTOConfig(rename_strategy="camel")
@get("/user", return_dto=DataCollectionDTO, sync_to_thread=False)
def get_user() -> User:
return User(id=user_id)
app = Litestar(route_handlers=[get_user])
"""
)
app = cast("Litestar", module.app)
schema = app.openapi_schema
assert schema.components.schemas is not None
component_schema = schema.components.schemas["GetUserUserResponseBody"]
assert component_schema.properties is not None
assert component_schema.properties["id"].description == "This is a test (id description)."
32 changes: 30 additions & 2 deletions tests/unit/test_dto/test_factory/test_backends/test_backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,20 @@
from unittest.mock import MagicMock

import pytest
from msgspec import Struct, to_builtins
from msgspec import Meta, Struct, to_builtins

from litestar import Litestar, Request, get, post
from litestar._openapi.schema_generation import SchemaCreator
from litestar.dto import DataclassDTO, DTOConfig, DTOField
from litestar.dto._backend import DTOBackend
from litestar.dto._backend import DTOBackend, _create_struct_field_meta_for_field_definition
from litestar.dto._types import CollectionType, SimpleType, TransferDTOFieldDefinition
from litestar.dto.data_structures import DTOFieldDefinition
from litestar.enums import MediaType
from litestar.exceptions import SerializationException
from litestar.openapi.spec.example import Example
from litestar.openapi.spec.reference import Reference
from litestar.openapi.spec.schema import Schema
from litestar.params import KwargDefinition
from litestar.serialization import encode_json
from litestar.testing import RequestFactory
from litestar.typing import FieldDefinition
Expand Down Expand Up @@ -448,3 +450,29 @@ class Factory(DataclassDTO):
assert b_d_nested_info is not None
assert not next(f for f in b_d_nested_info.field_definitions if f.name == "e").is_excluded
assert b_d_nested_info.field_definitions[1].name == "f"


@pytest.mark.parametrize(
("constraint_kwargs",),
(
({},),
({"gt": 0, "lt": 2},),
({"ge": 0, "le": 2},),
({"min_length": 1, "max_length": 2},),
({"pattern": "test"},),
),
)
def test_create_struct_field_meta_for_field_definition(constraint_kwargs: Any) -> None:
mock_field = MagicMock(spec=TransferDTOFieldDefinition, is_partial=False)
mock_field.kwarg_definition = KwargDefinition(
description="test",
examples=[Example(value=1)],
title="test",
**constraint_kwargs,
)
assert _create_struct_field_meta_for_field_definition(mock_field) == Meta(
description="test",
examples=[1],
title="test",
**constraint_kwargs,
)

0 comments on commit 9756003

Please sign in to comment.