Skip to content

Commit 672e10e

Browse files
committed
Added more tests
1 parent b4f71cf commit 672e10e

File tree

14 files changed

+150
-29
lines changed

14 files changed

+150
-29
lines changed

ellar/common/params/resolvers/parameter.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ async def get_request_body(self, ctx: IExecutionContext) -> t.Any:
155155
except json.JSONDecodeError as e:
156156
request_logger.error("JSONDecodeError: ", exc_info=True)
157157
raise RequestValidationError([ErrorWrapper(e, ("body", e.pos))]) from e
158-
except Exception as e: # pragma: no cover
158+
except Exception as e:
159159
request_logger.error("Unable to parse the body: ", exc_info=e)
160160
raise HTTPException(
161161
status_code=400, detail="There was an error parsing the body"

ellar/common/responses/models/base.py

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,17 @@ def serialize_if_pydantic_object(obj: t.Any) -> t.Any:
2626

2727

2828
class ResponseModelField(ModelField):
29+
"""
30+
A representation of response schema defined in route function
31+
32+
@get('/', response={200: ASchema, 404: ErrorSchema})
33+
def example():
34+
pass
35+
36+
During module building, `ASchema` and `ErrorSchema` will be converted to ResponseModelField
37+
types for the of validation and OPENAPI documentation
38+
"""
39+
2940
def validate_object(self, obj: t.Any) -> t.Any:
3041
request_logger.debug(
3142
f"Validating Response Object - '{self.__class__.__name__}'"
@@ -52,6 +63,21 @@ def serialize(
5263

5364

5465
class BaseResponseModel(IResponseModel, ABC):
66+
"""
67+
A base model representation of endpoint response. It provides essential information about a response type, just as
68+
it is defined on the endpoint, the status code and schema plus description for OPENAPI documentation.
69+
70+
For example:
71+
72+
@get('/', response={200: ASchema, 404: ErrorSchema})
73+
def example():
74+
pass
75+
76+
From the Above example, two response models will be generated.
77+
- response model for 200 status and ASchema and
78+
- response model for 400 status and ErrorSchema
79+
"""
80+
5581
__slots__ = (
5682
"_response_type",
5783
"_media_type",
@@ -126,10 +152,10 @@ def serialize(
126152
def create_response(
127153
self, context: IExecutionContext, response_obj: t.Any, status_code: int
128154
) -> Response:
155+
"""Please override this function to create a custom response"""
129156
request_logger.debug(
130157
f"Creating Response from returned Handler value - '{self.__class__.__name__}'"
131158
)
132-
"""Cant create custom responses, Please override this function to create a custom response"""
133159
response_args, headers = self.get_context_response(
134160
context=context, status_code=status_code
135161
)
@@ -162,6 +188,16 @@ def get_context_response(
162188

163189

164190
class ResponseModel(BaseResponseModel):
191+
"""
192+
Handles endpoint models with Response Type as schema
193+
194+
from starlette.responses import PlainTextResponse
195+
196+
@get('/', response={200: PlainTextResponse})
197+
def example():
198+
pass
199+
"""
200+
165201
def serialize(
166202
self,
167203
response_obj: t.Any,

ellar/common/responses/models/route.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
import logging
21
import typing as t
32

43
from ellar.common.constants import SCOPE_RESPONSE_STARTED
54
from ellar.common.interfaces import IExecutionContext, IResponseModel
6-
from ellar.common.logger import request_logger
5+
from ellar.common.logger import logger, request_logger
76
from pydantic import BaseModel
87

98
from ..response_types import Response
@@ -12,8 +11,6 @@
1211
from .helper import create_response_model
1312
from .json import EmptyAPIResponseModel, JSONResponseModel
1413

15-
logger = logging.getLogger("ellar")
16-
1714

1815
class RouteResponseModel:
1916
__slots__ = ("models",)
@@ -104,7 +101,8 @@ def process_response(
104101
return response_obj
105102
scope, _, _ = ctx.get_args()
106103

107-
if scope.get(SCOPE_RESPONSE_STARTED) is True:
104+
if scope.get(SCOPE_RESPONSE_STARTED) is True: # pragma: no cover
105+
# Similar condition exists in EllarConsumer Manager
108106
request_logger.debug(
109107
f"Stopped Processing Since `response.send` has been called - '{self.__class__.__name__}'"
110108
)

ellar/common/routing/base.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,11 @@ def __init__(self, endpoint: t.Callable) -> None:
4141
t.Union[t.Type, t.Type["ControllerBase"]], _controller_type
4242
)
4343

44-
@t.no_type_check
45-
def __call__(
46-
self, context: IExecutionContext, *args: t.Any, **kwargs: t.Any
47-
) -> t.Any:
48-
return self.endpoint(*args, **kwargs)
44+
# @t.no_type_check
45+
# def __call__(
46+
# self, context: IExecutionContext, *args: t.Any, **kwargs: t.Any
47+
# ) -> t.Any:
48+
# return self.endpoint(*args, **kwargs)
4949

5050
@abstractmethod
5151
def _load_model(self) -> None:

ellar/common/routing/controller/base.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ def _get_controller_instance(self, ctx: IExecutionContext) -> ControllerBase:
1919
controller_instance.context = ctx
2020
return controller_instance
2121

22-
@t.no_type_check
23-
def __call__(
24-
self, context: IExecutionContext, *args: t.Any, **kwargs: t.Any
25-
) -> t.Any:
26-
request_logger.debug("Calling Controller Endpoint manually")
27-
controller_instance = self._get_controller_instance(ctx=context)
28-
return self.endpoint(controller_instance, *args, **kwargs)
22+
# @t.no_type_check
23+
# def __call__(
24+
# self, context: IExecutionContext, *args: t.Any, **kwargs: t.Any
25+
# ) -> t.Any:
26+
# request_logger.debug("Calling Controller Endpoint manually")
27+
# controller_instance = self._get_controller_instance(ctx=context)
28+
# return self.endpoint(controller_instance, *args, **kwargs)

ellar/core/interceptors/consumer.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
from ellar.common import EllarInterceptor, IExecutionContext, IInterceptorsConsumer
55
from ellar.common.constants import ROUTE_INTERCEPTORS, SCOPE_RESPONSE_STARTED
6+
from ellar.common.logger import request_logger
67
from ellar.di import injectable
78

89
if t.TYPE_CHECKING: # pragma: no cover
@@ -51,6 +52,8 @@ async def handler(idx: int) -> t.Any:
5152
res = await route_operation.handle_request(context=context)
5253

5354
if context.get_args()[0][SCOPE_RESPONSE_STARTED]:
54-
print("\nResponse Started")
55+
request_logger.debug(
56+
f"Stopped Processing Since `response.send` has been called - '{self.__class__.__name__}'"
57+
)
5558
return
5659
await route_operation.handle_response(context, res)

ellar/core/lifespan.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import typing as t
22

33
from anyio import create_task_group
4-
from ellar.common import IApplicationShutdown, IApplicationStartup
4+
from ellar.common import IApplicationShutdown, IApplicationStartup, logger
55
from ellar.reflect import asynccontextmanager
66

77
if t.TYPE_CHECKING: # pragma: no cover
@@ -51,12 +51,16 @@ async def run_all_shutdown_actions(self, app: "App") -> None:
5151

5252
@asynccontextmanager
5353
async def lifespan(self, app: "App") -> t.AsyncIterator[t.Any]:
54+
logger.logger.debug("Executing Modules Startup Handlers")
55+
5456
async with create_task_group() as tg:
5557
tg.start_soon(self.run_all_startup_actions, app)
5658

5759
try:
5860
async with self._lifespan_context(app) as ctx: # type:ignore[attr-defined]
5961
yield ctx
6062
finally:
63+
64+
logger.logger.debug("Executing Modules Shutdown Handlers")
6165
async with create_task_group() as tg:
6266
tg.start_soon(self.run_all_shutdown_actions, app)

ellar/core/main.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from ellar.auth import IIdentitySchemes
66
from ellar.auth.handlers import AuthenticationHandlerType
77
from ellar.common.compatible import cached_property
8-
from ellar.common.constants import LOG_LEVELS
8+
from ellar.common.constants import ELLAR_LOG_FMT_STRING, LOG_LEVELS
99
from ellar.common.datastructures import State, URLPath
1010
from ellar.common.interfaces import IExceptionHandler, IExceptionMiddlewareService
1111
from ellar.common.logger import logger
@@ -92,7 +92,7 @@ def _config_logging(self) -> None:
9292
)
9393
logger_ = logging.getLogger("ellar")
9494
if not logger_.handlers:
95-
formatter = logging.Formatter("%(levelname)s: [%(name)s] %(message)s")
95+
formatter = logging.Formatter(ELLAR_LOG_FMT_STRING)
9696
stream_handler = logging.StreamHandler()
9797
# file_handler = logging.FileHandler("my_app.log")
9898
# file_handler.setFormatter(formatter)

ellar/reflect/_reflect.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from .constants import REFLECT_TYPE
88
from .contextmanager_fix import asynccontextmanager
99

10-
logger = logging.getLogger(__name__)
10+
logger = logging.getLogger("ellar")
1111

1212

1313
def _get_actual_target(

tests/test_controller/test_controller_type.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33

44

55
@Controller()
6-
class CarsController(ControllerBase, controller_name="CarSample"):
6+
class CarController(ControllerBase, controller_name="CarSample"):
77
pass
88

99

1010
def test_car_controller_name_changed():
11-
controller_name = reflect.get_metadata("name", CarsController)
11+
controller_name = reflect.get_metadata("name", CarController)
1212
assert controller_name == "carsample"

0 commit comments

Comments
 (0)