diff --git a/aiohttp_pydantic/injectors.py b/aiohttp_pydantic/injectors.py index 335adae..d9378a6 100644 --- a/aiohttp_pydantic/injectors.py +++ b/aiohttp_pydantic/injectors.py @@ -68,7 +68,10 @@ class BodyGetter(AbstractInjector): def __init__(self, args_spec: dict, default_values: dict): self.arg_name, self.model = next(iter(args_spec.items())) - self._expect_object = self.model.schema()["type"] == "object" + schema = self.model.schema() + if "type" not in schema: + schema["type"] = "object" + self._expect_object = schema["type"] == "object" async def inject(self, request: BaseRequest, args_view: list, kwargs_view: dict): try: diff --git a/tests/test_oas/test_view.py b/tests/test_oas/test_view.py index e8d6506..f3283a2 100644 --- a/tests/test_oas/test_view.py +++ b/tests/test_oas/test_view.py @@ -1,7 +1,7 @@ from __future__ import annotations from enum import Enum -from typing import List, Optional, Union, Literal +from typing import List, Optional, Union, Literal, Annotated from uuid import UUID import pytest @@ -42,6 +42,20 @@ class Error(BaseModel): text: str +class Cat(BaseModel): + pet_type: Literal['cat'] + meows: int + + +class Dog(BaseModel): + pet_type: Literal['dog'] + barks: float + + +class Animal(BaseModel): + __root__: Annotated[Union[Cat, Dog], Field(discriminator='pet_type')] + + class PetCollectionView(PydanticView): async def get( self, format: str, lang: Lang = Lang.EN, name: Optional[str] = None, *, promo: Optional[UUID] = None @@ -91,6 +105,11 @@ class ViewResponseReturnASimpleType(PydanticView): return web.json_response() +class DiscriminatedView(PydanticView): + async def post(self, /, request: Animal) -> r200[int]: + return web.json_response() + + async def ensure_content_durability(client): """ Reload the page 2 times to ensure that content is always the same @@ -115,6 +134,7 @@ async def generated_oas(aiohttp_client, event_loop) -> web.Application: app.router.add_view("/pets", PetCollectionView) app.router.add_view("/pets/{id}", PetItemView) app.router.add_view("/simple-type", ViewResponseReturnASimpleType) + app.router.add_view("/animals", DiscriminatedView) oas.setup(app) return await ensure_content_durability(await aiohttp_client(app)) @@ -122,12 +142,26 @@ async def generated_oas(aiohttp_client, event_loop) -> web.Application: async def test_generated_oas_should_have_components_schemas(generated_oas): assert generated_oas["components"]["schemas"] == { + 'Cat': {'properties': {'meows': {'title': 'Meows', 'type': 'integer'}, + 'pet_type': {'enum': ['cat'], + 'title': 'Pet Type', + 'type': 'string'}}, + 'required': ['pet_type', 'meows'], + 'title': 'Cat', + 'type': 'object'}, "Color": { "description": "An enumeration.", "enum": ["red", "green", "pink"], "title": "Color", "type": "string", }, + 'Dog': {'properties': {'barks': {'title': 'Barks', 'type': 'number'}, + 'pet_type': {'enum': ['dog'], + 'title': 'Pet Type', + 'type': 'string'}}, + 'required': ['pet_type', 'barks'], + 'title': 'Dog', + 'type': 'object'}, 'Error': { 'properties': { 'code': {'title': 'Code', 'type': 'integer'},