Skip to content

Commit 867fa96

Browse files
committed
Changed EXCEPTION_HANDLERS from dict of exception type or status code to list of IExceptionHandler
1 parent b0882b1 commit 867fa96

File tree

2 files changed

+38
-43
lines changed

2 files changed

+38
-43
lines changed

ellar/core/conf/app_settings_models.py

Lines changed: 9 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,23 @@
11
import typing as t
22

3-
from pydantic import Field, root_validator, validator
3+
from pydantic import Field, validator
44
from pydantic.json import ENCODERS_BY_TYPE as encoders_by_type
5+
from starlette.exceptions import HTTPException as StarletteHTTPException
56
from starlette.websockets import WebSocketClose
67

78
from ellar.constants import DEFAULT_LOGGING as default_logging, LOG_LEVELS as log_levels
89
from ellar.core.response import JSONResponse, PlainTextResponse
910
from ellar.core.versioning import DefaultAPIVersioning
10-
from ellar.exceptions import (
11-
APIException,
12-
HTTPException as StarletteHTTPException,
13-
RequestValidationError,
14-
)
1511
from ellar.serializer import Serializer, SerializerFilter
1612
from ellar.types import ASGIApp, TReceive, TScope, TSend
1713

18-
from ..exception_handlers import (
19-
api_exception_handler,
20-
request_validation_exception_handler,
14+
from .mixins import (
15+
ConfigDefaultTypesMixin,
16+
TEventHandler,
17+
TExceptionHandler,
18+
TMiddleware,
19+
TVersioning,
2120
)
22-
from .mixins import ConfigDefaultTypesMixin, TEventHandler, TMiddleware, TVersioning
2321

2422
if t.TYPE_CHECKING: # pragma: no cover
2523
from ellar.core.main import App
@@ -95,14 +93,7 @@ class Config:
9593

9694
MIDDLEWARE: t.List[TMiddleware] = []
9795

98-
_APP_EXCEPTION_HANDLERS: t.Dict[t.Union[int, t.Type[Exception]], t.Callable] = {
99-
RequestValidationError: request_validation_exception_handler,
100-
APIException: api_exception_handler,
101-
}
102-
103-
USER_CUSTOM_EXCEPTION_HANDLERS: t.Dict[
104-
t.Union[int, t.Type[Exception]], t.Callable
105-
] = {}
96+
EXCEPTION_HANDLERS: t.List[TExceptionHandler] = [] # type:ignore
10697

10798
# Default not found handler
10899
DEFAULT_NOT_FOUND_HANDLER: ASGIApp = _not_found
@@ -122,8 +113,6 @@ class Config:
122113
# logging Level
123114
LOG_LEVEL: t.Optional[log_levels] = log_levels.info
124115

125-
MIDDLEWARE_DECORATOR: t.List[TMiddleware] = []
126-
127116
ON_REQUEST_STARTUP: t.List[TEventHandler] = []
128117
ON_REQUEST_SHUTDOWN: t.List[TEventHandler] = []
129118

@@ -132,23 +121,6 @@ class Config:
132121

133122
LOGGING: t.Optional[t.Dict[str, t.Any]] = None
134123

135-
@root_validator(pre=False)
136-
def pre_root_validate(cls, values: t.Any) -> t.Any:
137-
app_exception_handlers = dict(cls._APP_EXCEPTION_HANDLERS)
138-
user_custom_exception_handlers = values.get(
139-
"USER_CUSTOM_EXCEPTION_HANDLERS", {}
140-
)
141-
142-
app_exception_handlers.update(**user_custom_exception_handlers)
143-
144-
values["EXCEPTION_HANDLERS"] = app_exception_handlers
145-
middleware_decorator_handlers = list(values.get("MIDDLEWARE_DECORATOR", []))
146-
user_settings_middleware = list(values.get("MIDDLEWARE", []))
147-
middleware_decorator_handlers.extend(user_settings_middleware)
148-
values["MIDDLEWARE"] = middleware_decorator_handlers
149-
150-
return values
151-
152124
@validator("MIDDLEWARE", pre=True)
153125
def pre_middleware_validate(cls, value: t.Any) -> t.Any:
154126
if isinstance(value, tuple):

ellar/core/conf/mixins.py

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,43 @@
1+
import inspect
12
import typing as t
23

34
from starlette.responses import JSONResponse
45
from starlette.types import ASGIApp
56

67
from ellar.constants import LOG_LEVELS as log_levels
78
from ellar.core.events import EventHandler
9+
from ellar.core.exceptions.interfaces import IExceptionHandler
810
from ellar.core.middleware import Middleware
911
from ellar.core.versioning import BaseAPIVersioning
1012

1113
if t.TYPE_CHECKING: # pragma: no cover
1214
from ellar.core import App
1315

14-
__all__ = ["ConfigDefaultTypesMixin", "TVersioning", "TMiddleware", "TEventHandler"]
16+
__all__ = [
17+
"ConfigDefaultTypesMixin",
18+
"TVersioning",
19+
"TMiddleware",
20+
"TEventHandler",
21+
"TExceptionHandler",
22+
]
23+
24+
25+
class TExceptionHandler:
26+
@classmethod
27+
def __get_validators__(
28+
cls: t.Type["TExceptionHandler"],
29+
) -> t.Iterable[t.Callable[..., t.Any]]:
30+
yield cls.validate
31+
32+
@classmethod
33+
def validate(cls: t.Type["TExceptionHandler"], v: t.Any) -> t.Any:
34+
if isinstance(v, IExceptionHandler):
35+
return v
36+
37+
if inspect.isclass(v):
38+
raise ValueError(f"Expected TExceptionHandler, received: {v}")
39+
40+
raise ValueError(f"Expected TExceptionHandler, received: {type(v)}")
1541

1642

1743
class TVersioning(BaseAPIVersioning):
@@ -89,18 +115,15 @@ class ConfigDefaultTypesMixin:
89115
# A dictionary mapping either integer status codes,
90116
# or exception class types onto callables which handle the exceptions.
91117
# Exception handler callables should be of the form
92-
# `handler(request, exc) -> response` and may be be either standard functions, or async functions.
93-
EXCEPTION_HANDLERS: t.Dict[t.Union[int, t.Type[Exception]], t.Callable]
118+
# `handler(request, exc) -> response` and may be either standard functions, or async functions.
119+
EXCEPTION_HANDLERS: t.List[IExceptionHandler]
94120

95121
# static route
96122
STATIC_MOUNT_PATH: str
97123

98124
# defines other custom json encoders
99125
SERIALIZER_CUSTOM_ENCODER: t.Dict[t.Any, t.Callable[[t.Any], t.Any]]
100126

101-
# will be set automatically when @middleware is found in a Module class
102-
MIDDLEWARE_DECORATOR: t.List[TMiddleware]
103-
104127
# will be set automatically when @on_startup is found in a Module class
105128
ON_REQUEST_STARTUP: t.List[TEventHandler]
106129

0 commit comments

Comments
 (0)