Fix - Does not work with from __future__ import annotations
This commit is contained in:
parent
3648dde1ea
commit
69fb553635
@ -1,5 +1,5 @@
|
|||||||
from .view import PydanticView
|
from .view import PydanticView
|
||||||
|
|
||||||
__version__ = "1.12.0"
|
__version__ = "1.12.1"
|
||||||
|
|
||||||
__all__ = ("PydanticView", "__version__")
|
__all__ = ("PydanticView", "__version__")
|
||||||
|
@ -3,7 +3,7 @@ import typing
|
|||||||
from inspect import signature, getmro
|
from inspect import signature, getmro
|
||||||
from json.decoder import JSONDecodeError
|
from json.decoder import JSONDecodeError
|
||||||
from types import SimpleNamespace
|
from types import SimpleNamespace
|
||||||
from typing import Callable, Tuple, Literal, Type
|
from typing import Callable, Tuple, Literal, Type, get_type_hints
|
||||||
|
|
||||||
from aiohttp.web_exceptions import HTTPBadRequest
|
from aiohttp.web_exceptions import HTTPBadRequest
|
||||||
from aiohttp.web_request import BaseRequest
|
from aiohttp.web_request import BaseRequest
|
||||||
@ -201,13 +201,19 @@ def _get_group_signature(cls) -> Tuple[dict, dict]:
|
|||||||
mro = getmro(cls)
|
mro = getmro(cls)
|
||||||
for base in reversed(mro[: mro.index(Group)]):
|
for base in reversed(mro[: mro.index(Group)]):
|
||||||
attrs = vars(base)
|
attrs = vars(base)
|
||||||
|
|
||||||
|
# Use __annotations__ to know if an attribute is
|
||||||
|
# overwrite to remove the default value.
|
||||||
for attr_name, type_ in base.__annotations__.items():
|
for attr_name, type_ in base.__annotations__.items():
|
||||||
sig[attr_name] = type_
|
|
||||||
if (default := attrs.get(attr_name)) is None:
|
if (default := attrs.get(attr_name)) is None:
|
||||||
defaults.pop(attr_name, None)
|
defaults.pop(attr_name, None)
|
||||||
else:
|
else:
|
||||||
defaults[attr_name] = default
|
defaults[attr_name] = default
|
||||||
|
|
||||||
|
# Use get_type_hints to have postponed annotations.
|
||||||
|
for attr_name, type_ in get_type_hints(base).items():
|
||||||
|
sig[attr_name] = type_
|
||||||
|
|
||||||
return sig, defaults
|
return sig, defaults
|
||||||
|
|
||||||
|
|
||||||
@ -229,26 +235,29 @@ def _parse_func_signature(
|
|||||||
header_args = {}
|
header_args = {}
|
||||||
defaults = {}
|
defaults = {}
|
||||||
|
|
||||||
|
annotations = get_type_hints(func)
|
||||||
for param_name, param_spec in signature(func).parameters.items():
|
for param_name, param_spec in signature(func).parameters.items():
|
||||||
|
|
||||||
if param_name == "self":
|
if param_name == "self":
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if param_spec.annotation == param_spec.empty:
|
if param_spec.annotation == param_spec.empty:
|
||||||
raise RuntimeError(f"The parameter {param_name} must have an annotation")
|
raise RuntimeError(f"The parameter {param_name} must have an annotation")
|
||||||
|
|
||||||
|
annotation = annotations[param_name]
|
||||||
if param_spec.default is not param_spec.empty:
|
if param_spec.default is not param_spec.empty:
|
||||||
defaults[param_name] = param_spec.default
|
defaults[param_name] = param_spec.default
|
||||||
|
|
||||||
if param_spec.kind is param_spec.POSITIONAL_ONLY:
|
if param_spec.kind is param_spec.POSITIONAL_ONLY:
|
||||||
path_args[param_name] = param_spec.annotation
|
path_args[param_name] = annotation
|
||||||
|
|
||||||
elif param_spec.kind is param_spec.POSITIONAL_OR_KEYWORD:
|
elif param_spec.kind is param_spec.POSITIONAL_OR_KEYWORD:
|
||||||
if is_pydantic_base_model(param_spec.annotation):
|
if is_pydantic_base_model(annotation):
|
||||||
body_args[param_name] = param_spec.annotation
|
body_args[param_name] = annotation
|
||||||
else:
|
else:
|
||||||
qs_args[param_name] = param_spec.annotation
|
qs_args[param_name] = annotation
|
||||||
elif param_spec.kind is param_spec.KEYWORD_ONLY:
|
elif param_spec.kind is param_spec.KEYWORD_ONLY:
|
||||||
header_args[param_name] = param_spec.annotation
|
header_args[param_name] = annotation
|
||||||
else:
|
else:
|
||||||
raise RuntimeError(f"You cannot use {param_spec.VAR_POSITIONAL} parameters")
|
raise RuntimeError(f"You cannot use {param_spec.VAR_POSITIONAL} parameters")
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import typing
|
import typing
|
||||||
from inspect import getdoc
|
from inspect import getdoc
|
||||||
from itertools import count
|
from itertools import count
|
||||||
from typing import List, Type, Optional
|
from typing import List, Type, Optional, get_type_hints
|
||||||
|
|
||||||
from aiohttp.web import Response, json_response
|
from aiohttp.web import Response, json_response
|
||||||
from aiohttp.web_app import Application
|
from aiohttp.web_app import Application
|
||||||
@ -126,7 +126,7 @@ def _add_http_method_to_oas(
|
|||||||
ref_template="#/components/schemas/{model}"
|
ref_template="#/components/schemas/{model}"
|
||||||
)
|
)
|
||||||
|
|
||||||
return_type = handler.__annotations__.get("return")
|
return_type = get_type_hints(handler).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(
|
||||||
return_type
|
return_type
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from aiohttp_pydantic.injectors import (
|
from aiohttp_pydantic.injectors import (
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Iterator, List, Optional
|
from typing import Iterator, List, Optional
|
||||||
|
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from aiohttp_pydantic import PydanticView
|
from aiohttp_pydantic import PydanticView
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
|
|
||||||
from aiohttp_pydantic import PydanticView
|
from aiohttp_pydantic import PydanticView
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
|
|
||||||
from aiohttp_pydantic.oas.docstring_parser import (
|
from aiohttp_pydantic.oas.docstring_parser import (
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from aiohttp_pydantic.oas.struct import OpenApiSpec3
|
from aiohttp_pydantic.oas.struct import OpenApiSpec3
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from aiohttp_pydantic.oas.struct import OpenApiSpec3
|
from aiohttp_pydantic.oas.struct import OpenApiSpec3
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from aiohttp_pydantic.oas.struct import OpenApiSpec3
|
from aiohttp_pydantic.oas.struct import OpenApiSpec3
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
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
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
@ -385,15 +387,16 @@ async def test_generated_view_info_as_title():
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Pagination(Group):
|
||||||
|
page: int = 1
|
||||||
|
page_size: int = 20
|
||||||
|
|
||||||
|
|
||||||
async def test_use_parameters_group_should_not_impact_the_oas(aiohttp_client):
|
async def test_use_parameters_group_should_not_impact_the_oas(aiohttp_client):
|
||||||
class PetCollectionView1(PydanticView):
|
class PetCollectionView1(PydanticView):
|
||||||
async def get(self, page: int = 1, page_size: int = 20) -> r200[List[Pet]]:
|
async def get(self, page: int = 1, page_size: int = 20) -> r200[List[Pet]]:
|
||||||
return web.json_response()
|
return web.json_response()
|
||||||
|
|
||||||
class Pagination(Group):
|
|
||||||
page: int = 1
|
|
||||||
page_size: int = 20
|
|
||||||
|
|
||||||
class PetCollectionView2(PydanticView):
|
class PetCollectionView2(PydanticView):
|
||||||
async def get(self, pagination: Pagination) -> r200[List[Pet]]:
|
async def get(self, pagination: Pagination) -> r200[List[Pet]]:
|
||||||
return web.json_response()
|
return web.json_response()
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Iterator, List, Optional
|
from typing import Iterator, List, Optional
|
||||||
|
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
|
|
||||||
from aiohttp_pydantic import PydanticView
|
from aiohttp_pydantic import PydanticView
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Optional, List
|
from typing import Optional, List
|
||||||
from pydantic import Field
|
from pydantic import Field
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
|
Loading…
x
Reference in New Issue
Block a user