fix: handle discriminated model with root definition

This commit is contained in:
Georg K 2023-02-09 12:25:28 +03:00
parent be944ac98e
commit 26fd6fa19f
2 changed files with 39 additions and 2 deletions

View File

@ -68,7 +68,10 @@ class BodyGetter(AbstractInjector):
def __init__(self, args_spec: dict, default_values: dict): def __init__(self, args_spec: dict, default_values: dict):
self.arg_name, self.model = next(iter(args_spec.items())) 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): async def inject(self, request: BaseRequest, args_view: list, kwargs_view: dict):
try: try:

View File

@ -1,7 +1,7 @@
from __future__ import annotations from __future__ import annotations
from enum import Enum from enum import Enum
from typing import List, Optional, Union, Literal from typing import List, Optional, Union, Literal, Annotated
from uuid import UUID from uuid import UUID
import pytest import pytest
@ -42,6 +42,20 @@ class Error(BaseModel):
text: str 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): class PetCollectionView(PydanticView):
async def get( async def get(
self, format: str, lang: Lang = Lang.EN, name: Optional[str] = None, *, promo: Optional[UUID] = None 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() 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): async def ensure_content_durability(client):
""" """
Reload the page 2 times to ensure that content is always the same 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", PetCollectionView)
app.router.add_view("/pets/{id}", PetItemView) app.router.add_view("/pets/{id}", PetItemView)
app.router.add_view("/simple-type", ViewResponseReturnASimpleType) app.router.add_view("/simple-type", ViewResponseReturnASimpleType)
app.router.add_view("/animals", DiscriminatedView)
oas.setup(app) oas.setup(app)
return await ensure_content_durability(await aiohttp_client(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): async def test_generated_oas_should_have_components_schemas(generated_oas):
assert generated_oas["components"]["schemas"] == { 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": { "Color": {
"description": "An enumeration.", "description": "An enumeration.",
"enum": ["red", "green", "pink"], "enum": ["red", "green", "pink"],
"title": "Color", "title": "Color",
"type": "string", "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': { 'Error': {
'properties': { 'properties': {
'code': {'title': 'Code', 'type': 'integer'}, 'code': {'title': 'Code', 'type': 'integer'},