|
11 | 11 |
|
12 | 12 | from litestar import Controller, Litestar, delete, get, patch, post |
13 | 13 | from litestar._openapi.plugin import OpenAPIPlugin |
| 14 | +from litestar.dto import DataclassDTO, DTOConfig |
14 | 15 | from litestar.enums import MediaType, OpenAPIMediaType, ParamType |
15 | 16 | from litestar.openapi import OpenAPIConfig |
16 | 17 | from litestar.openapi.plugins import YamlRenderPlugin |
17 | 18 | from litestar.openapi.spec import Parameter as OpenAPIParameter |
| 19 | +from litestar.openapi.spec import Schema |
18 | 20 | from litestar.params import Parameter |
19 | 21 | from litestar.serialization.msgspec_hooks import decode_json, encode_json, get_serializer |
20 | 22 | from litestar.status_codes import HTTP_200_OK, HTTP_404_NOT_FOUND |
@@ -360,6 +362,52 @@ def handler_b() -> module_b.Model: # type: ignore[name-defined] |
360 | 362 | # TODO: expand this test to cover more cases |
361 | 363 |
|
362 | 364 |
|
| 365 | +@dataclass |
| 366 | +class _SchemaNameChild: |
| 367 | + name: str |
| 368 | + |
| 369 | + |
| 370 | +@dataclass |
| 371 | +class _SchemaNamePerson: |
| 372 | + name: str |
| 373 | + age: int |
| 374 | + child: _SchemaNameChild |
| 375 | + |
| 376 | + |
| 377 | +def test_dto_schema_name_with_nested_model() -> None: |
| 378 | + """__schema_name__ should only apply to the root DTO, not nested child models.""" |
| 379 | + |
| 380 | + class PersonDTO(DataclassDTO[_SchemaNamePerson]): |
| 381 | + __schema_name__ = "PersonPublic" |
| 382 | + config = DTOConfig(exclude={"age"}) |
| 383 | + |
| 384 | + @get("/person", return_dto=PersonDTO, sync_to_thread=False) |
| 385 | + def get_person() -> _SchemaNamePerson: |
| 386 | + return _SchemaNamePerson(name="test", age=30, child=_SchemaNameChild(name="kid")) |
| 387 | + |
| 388 | + app = Litestar(route_handlers=[get_person]) |
| 389 | + openapi_plugin = app.plugins.get(OpenAPIPlugin) |
| 390 | + schemas = openapi_plugin.provide_openapi().components.schemas |
| 391 | + |
| 392 | + # parent should use the custom name |
| 393 | + assert schemas is not None |
| 394 | + assert "PersonPublic" in schemas |
| 395 | + |
| 396 | + # child should NOT use the parent's custom name |
| 397 | + # it should have its own schema |
| 398 | + person_schema = schemas["PersonPublic"] |
| 399 | + assert isinstance(person_schema, Schema) |
| 400 | + assert person_schema.properties is not None |
| 401 | + child_ref = person_schema.properties["child"].ref # type: ignore[union-attr] |
| 402 | + assert child_ref != "#/components/schemas/PersonPublic", ( |
| 403 | + "child $ref should not point to the parent's __schema_name__" |
| 404 | + ) |
| 405 | + |
| 406 | + # a separate child schema should exist |
| 407 | + child_schema_name = child_ref.split("/")[-1] |
| 408 | + assert child_schema_name in schemas |
| 409 | + |
| 410 | + |
363 | 411 | def test_multiple_handlers_for_same_route() -> None: |
364 | 412 | @post("/", sync_to_thread=False) |
365 | 413 | def post_handler() -> None: ... |
|
0 commit comments