Skip to content

Commit cf68986

Browse files
committed
Refactored and added a factor for creating ResponseModels
1 parent 40a5877 commit cf68986

File tree

6 files changed

+81
-83
lines changed

6 files changed

+81
-83
lines changed

ellar/core/response/model/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
ResponseTypeDefinitionConverter,
66
RouteResponseExecution,
77
)
8+
from .factory import create_response_model
89
from .html import HTMLResponseModel
910
from .interface import IResponseModel
1011
from .json import EmptyAPIResponseModel, JSONResponseModel
@@ -21,4 +22,5 @@
2122
"ResponseTypeDefinitionConverter",
2223
"IResponseModel",
2324
"HTMLResponseModel",
25+
"create_response_model",
2426
]

ellar/core/response/model/base.py

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import typing as t
2-
from abc import ABC
2+
from abc import ABC, abstractmethod
33
from dataclasses import is_dataclass
44

55
from pydantic import BaseModel
@@ -9,6 +9,7 @@
99
from ellar.core.context import IExecutionContext
1010
from ellar.core.converters import TypeDefinitionConverter
1111
from ellar.exceptions import RequestValidationError
12+
from ellar.helper.modelfield import create_model_field
1213
from ellar.reflect import reflect
1314
from ellar.serializer import (
1415
BaseSerializer,
@@ -64,7 +65,9 @@ def serialize(
6465

6566
class BaseResponseModel(IResponseModel, ABC):
6667
__slots__ = ("_response_type", "media_type", "description", "meta", "schema")
68+
6769
response_type: t.Type[Response] = Response
70+
model_schema: t.Union[ResponseModelField, t.Any] = None
6871

6972
def __init__(
7073
self,
@@ -80,17 +83,38 @@ def __init__(
8083
)
8184
self.description = description
8285
self.meta = kwargs
83-
self.schema = schema
8486

87+
_schema: t.Optional[ResponseModelField] = None
88+
if (
89+
schema
90+
or self.model_schema
91+
and not isinstance(schema or self.model_schema, ResponseModelField)
92+
):
93+
new_response_schema = ResponseTypeDefinitionConverter(
94+
schema or self.model_schema
95+
).re_group_outer_type()
96+
97+
_schema = t.cast(
98+
ResponseModelField,
99+
create_model_field(
100+
name="response_model",
101+
type_=new_response_schema,
102+
model_field_class=ResponseModelField,
103+
),
104+
)
105+
self.schema: t.Optional[ResponseModelField] = _schema
106+
107+
@abstractmethod
85108
def get_model_field(self) -> t.Optional[t.Union[ResponseModelField, t.Any]]:
86-
return self.schema
109+
pass
87110

111+
@abstractmethod
88112
def serialize(
89113
self,
90114
response_obj: t.Any,
91115
serializer_filter: t.Optional[SerializerFilter] = None,
92116
) -> t.Union[t.List[t.Dict], t.Dict, t.Any]:
93-
return response_obj
117+
pass
94118

95119
def create_response(
96120
self, context: IExecutionContext, response_obj: t.Any, status_code: int
@@ -131,22 +155,15 @@ def __copy__(self, memodict: t.Dict = {}) -> "BaseResponseModel":
131155

132156

133157
class ResponseModel(BaseResponseModel):
134-
@classmethod
135-
def create_model(
136-
cls,
137-
*args: t.Any,
138-
response_type: t.Type[Response] = None,
139-
description: str = "Successful Response",
140-
schema: t.Union[t.Type[ResponseModelField], t.Any] = None,
141-
**kwargs: t.Any,
142-
) -> "ResponseModel":
158+
def get_model_field(self) -> t.Optional[t.Union[ResponseModelField, t.Any]]:
159+
return self.schema
143160

144-
return cls(
145-
response_type=response_type,
146-
description=description,
147-
schema=schema,
148-
**kwargs,
149-
)
161+
def serialize(
162+
self,
163+
response_obj: t.Any,
164+
serializer_filter: t.Optional[SerializerFilter] = None,
165+
) -> t.Union[t.List[t.Dict], t.Dict, t.Any]:
166+
return response_obj
150167

151168

152169
class RouteResponseExecution(Exception):
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import typing as t
2+
3+
from starlette.responses import Response
4+
5+
if t.TYPE_CHECKING:
6+
from .base import ResponseModel, ResponseModelField
7+
8+
T = t.TypeVar("T")
9+
10+
11+
def create_response_model(
12+
response_model: t.Union[t.Type["ResponseModel"], t.Type[T]],
13+
/,
14+
response_type: t.Type[Response] = None,
15+
description: str = "Successful Response",
16+
schema: t.Union[t.Type["ResponseModelField"], t.Any] = None,
17+
**kwargs: t.Any,
18+
) -> t.Union["ResponseModel", T]:
19+
_init_kwargs: t.Dict[str, t.Any] = dict(
20+
response_type=response_type, description=description, schema=schema
21+
)
22+
_init_kwargs.update(kwargs)
23+
return response_model(**_init_kwargs)

ellar/core/response/model/interface.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,6 @@ class IResponseModel(ABC):
1414
media_type: str
1515
description: str
1616

17-
@classmethod
18-
@abstractmethod
19-
def create_model(
20-
cls,
21-
*args: t.Any,
22-
**kwargs: t.Any,
23-
) -> "IResponseModel":
24-
"""Creates ResponseModel Object"""
25-
2617
@abstractmethod
2718
def get_model_field(self) -> t.Optional[t.Union[ModelField, t.Any]]:
2819
"""Gets Model Fields"""

ellar/core/response/model/json.py

Lines changed: 13 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,26 @@
11
import typing as t
22

3-
from pydantic import BaseModel
4-
53
from ellar.constants import SERIALIZER_FILTER_KEY
64
from ellar.core.context import IExecutionContext
75
from ellar.helper.modelfield import create_model_field
86
from ellar.reflect import reflect
97
from ellar.serializer import SerializerFilter, serialize_object
108

119
from ..responses import JSONResponse, Response
12-
from .base import BaseResponseModel, ResponseModelField, ResponseTypeDefinitionConverter
13-
10+
from .base import ResponseModel, ResponseModelField
1411

15-
class JSONResponseModel(BaseResponseModel):
16-
response_type: t.Type[Response] = JSONResponse
17-
schema: ResponseModelField
12+
DictSchema: ResponseModelField = t.cast(
13+
ResponseModelField,
14+
create_model_field(
15+
name="response_model",
16+
type_=dict,
17+
model_field_class=ResponseModelField,
18+
),
19+
)
1820

19-
@classmethod
20-
def create_model( # type: ignore
21-
cls,
22-
schema: t.Union[t.Type[BaseModel], t.Any],
23-
description: str = "Successful Response",
24-
**kwargs: t.Any,
25-
) -> "JSONResponseModel":
26-
new_response_schema = ResponseTypeDefinitionConverter(
27-
schema
28-
).re_group_outer_type()
2921

30-
_schema = t.cast(
31-
ResponseModelField,
32-
create_model_field(
33-
name="response_model",
34-
type_=new_response_schema,
35-
model_field_class=ResponseModelField,
36-
),
37-
)
38-
return cls(
39-
description=description,
40-
schema=_schema,
41-
**kwargs,
42-
)
22+
class JSONResponseModel(ResponseModel):
23+
response_type: t.Type[Response] = JSONResponse
4324

4425
def create_response(
4526
self, context: IExecutionContext, response_obj: t.Any, status_code: int
@@ -64,32 +45,12 @@ def serialize(
6445
response_obj: t.Any,
6546
serializer_filter: t.Optional[SerializerFilter] = None,
6647
) -> t.Union[t.List[t.Dict], t.Dict, t.Any]:
48+
assert self.schema, "schema must exist for JSONResponseModel"
6749
return self.schema.serialize(response_obj, serializer_filter=serializer_filter)
6850

6951

7052
class EmptyAPIResponseModel(JSONResponseModel):
71-
@classmethod
72-
def create_model( # type: ignore
73-
cls,
74-
description: str = "Successful Response",
75-
**kwargs: t.Any,
76-
) -> "EmptyAPIResponseModel":
77-
new_response_schema = dict
78-
79-
_schema = t.cast(
80-
ResponseModelField,
81-
create_model_field(
82-
name="response_model",
83-
type_=new_response_schema,
84-
model_field_class=ResponseModelField,
85-
),
86-
)
87-
return cls(
88-
response_type=JSONResponse,
89-
description=description,
90-
schema=_schema,
91-
**kwargs,
92-
)
53+
model_schema = DictSchema
9354

9455
def serialize(
9556
self,

ellar/core/response/model/route.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
from ..responses import Response
88
from .base import ResponseModel, ResponseResolver, RouteResponseExecution
9+
from .factory import create_response_model
910
from .interface import IResponseModel
1011
from .json import JSONResponseModel
1112

@@ -36,16 +37,19 @@ def convert_route_responses_to_response_models(
3637
if isinstance(response_schema, type) and issubclass(
3738
response_schema, Response
3839
):
39-
self.models[status_code] = ResponseModel.create_model(
40-
response_type=response_schema, description=description
40+
self.models[status_code] = create_response_model(
41+
ResponseModel,
42+
response_type=response_schema,
43+
description=description,
4144
)
4245
continue
4346

4447
if isinstance(response_schema, IResponseModel):
4548
self.models[status_code] = response_schema
4649
continue
4750

48-
self.models[status_code] = JSONResponseModel.create_model(
51+
self.models[status_code] = create_response_model(
52+
JSONResponseModel,
4953
schema=t.cast(t.Type[BaseModel], response_schema),
5054
description=description,
5155
)

0 commit comments

Comments
 (0)