Merge pull request #22 from ffkirill/support_OptionalUnionT

Fix bug optional parameter is reported as required.
This commit is contained in:
MAILLOL Vincent 2021-08-04 08:35:56 +02:00 committed by GitHub
commit a624aba613
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 20 additions and 21 deletions

View File

@ -16,21 +16,6 @@ from ..view import PydanticView, is_pydantic_view
from .typing import is_status_code_type from .typing import is_status_code_type
def _handle_optional(type_):
"""
Returns the type wrapped in Optional or None.
>>> from typing import Optional
>>> _handle_optional(int)
>>> _handle_optional(Optional[str])
<class 'str'>
"""
if typing.get_origin(type_) is typing.Union:
args = typing.get_args(type_)
if len(args) == 2 and type(None) in args:
return next(iter(set(args) - {type(None)}))
return None
class _OASResponseBuilder: class _OASResponseBuilder:
""" """
Parse the type annotated as returned by a function and Parse the type annotated as returned by a function and
@ -128,18 +113,18 @@ def _add_http_method_to_oas(
i = next(indexes) i = next(indexes)
oas_operation.parameters[i].in_ = args_location oas_operation.parameters[i].in_ = args_location
oas_operation.parameters[i].name = name oas_operation.parameters[i].name = name
optional_type = _handle_optional(type_)
attrs = {"__annotations__": {"__root__": type_}} attrs = {"__annotations__": {"__root__": type_}}
if name in defaults: if name in defaults:
attrs["__root__"] = defaults[name] attrs["__root__"] = defaults[name]
oas_operation.parameters[i].required = False
else:
oas_operation.parameters[i].required = True
oas_operation.parameters[i].schema = type(name, (BaseModel,), attrs).schema( oas_operation.parameters[i].schema = type(name, (BaseModel,), attrs).schema(
ref_template="#/components/schemas/{model}" ref_template="#/components/schemas/{model}"
) )
oas_operation.parameters[i].required = optional_type is None
return_type = handler.__annotations__.get("return") return_type = handler.__annotations__.get("return")
if return_type is not None: if return_type is not None:
_OASResponseBuilder(oas, oas_operation, status_code_descriptions).build( _OASResponseBuilder(oas, oas_operation, status_code_descriptions).build(

View File

@ -1,5 +1,5 @@
from enum import Enum from enum import Enum
from typing import List, Optional, Union from typing import List, Optional, Union, Literal
from uuid import UUID from uuid import UUID
import pytest import pytest
@ -46,7 +46,7 @@ class PetCollectionView(PydanticView):
class PetItemView(PydanticView): class PetItemView(PydanticView):
async def get(self, id: int, /) -> Union[r200[Pet], r404]: async def get(self, id: int, /, size: Union[int, Literal['x', 'l', 's']], day: Union[int, Literal["now"]] = "now") -> Union[r200[Pet], r404]:
return web.json_response() return web.json_response()
async def put(self, id: int, /, pet: Pet): async def put(self, id: int, /, pet: Pet):
@ -245,7 +245,21 @@ async def test_pets_id_route_should_have_get_method(generated_oas):
"name": "id", "name": "id",
"required": True, "required": True,
"schema": {"title": "id", "type": "integer"}, "schema": {"title": "id", "type": "integer"},
} },
{'in': 'query',
'name': 'size',
'required': True,
'schema': {'anyOf': [{'type': 'integer'},
{'enum': ['x', 'l', 's'],
'type': 'string'}],
'title': 'size'}},
{'in': 'query',
'name': 'day',
'required': False,
'schema': {'anyOf': [{'type': 'integer'},
{'enum': ['now'], 'type': 'string'}],
'default': 'now',
'title': 'day'}}
], ],
"responses": { "responses": {
"200": { "200": {