Skip to content

Commit f8fa4d5

Browse files
committed
some minor updates and bug fixes on package
1 parent 1b700a5 commit f8fa4d5

File tree

19 files changed

+214
-203
lines changed

19 files changed

+214
-203
lines changed

ellar/common/compatible/dict.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
class AttributeDictAccessMixin:
77
def __getattribute__(self, name: t.Any) -> t.Optional[t.Any]:
88
if name in self:
9-
return self[name]
9+
return self.__attribute_dict__(self[name])
1010
try:
1111
return super(AttributeDictAccessMixin, self).__getattribute__(name)
1212
except Exception:
@@ -17,6 +17,9 @@ def __missing__(self, name) -> VT:
1717
f"'{self.__class__.__name__}' object has no attribute '{name}'"
1818
)
1919

20+
def __attribute_dict__(self, value: t.Any) -> t.Any:
21+
return value
22+
2023

2124
class AttributeDict(AttributeDictAccessMixin, t.Dict[KT, VT]):
2225
def __setattr__(self, name: KT, value: VT) -> None: # type: ignore
@@ -28,3 +31,8 @@ def set_defaults(self, **kwargs: t.Any) -> None:
2831

2932
def __missing__(self, name) -> VT:
3033
return None
34+
35+
def __attribute_dict__(self, value: t.Any) -> t.Any:
36+
if isinstance(value, dict):
37+
return self.__class__(value)
38+
return value

ellar/common/constants.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,17 @@
3030
EXTRA_ROUTE_ARGS_KEY = "EXTRA_ROUTE_ARGS"
3131
RESPONSE_OVERRIDE_KEY = "RESPONSE_OVERRIDE"
3232
EXCEPTION_HANDLERS_KEY = "EXCEPTION_HANDLERS"
33+
APP_EXCEPTION_HANDLERS_KEY = "APP_EXCEPTION_HANDLERS"
3334
MODULE_DECORATOR_ITEM = "MODULE_DECORATOR_ITEM"
3435
TEMPLATE_GLOBAL_KEY = "TEMPLATE_GLOBAL_FILTERS"
36+
TEMPLATE_CONTEXT_PROCESSOR_KEY = "TEMPLATE_CONTEXT_PROCESSOR_KEY"
3537
TEMPLATE_FILTER_KEY = "TEMPLATE_FILTERS"
3638
NESTED_ROUTERS_KEY = "NESTED_ROUTERS_KEY"
3739

3840
MIDDLEWARE_HANDLERS_KEY = "MIDDLEWARE"
41+
APP_MIDDLEWARE_HANDLERS_KEY = "APP_MIDDLEWARE"
3942

4043
MODULE_WATERMARK = "MODULE_WATERMARK"
41-
MODULE_FIELDS = "__MODULE_FIELDS__"
4244
CONTROLLER_WATERMARK = "CONTROLLER_WATERMARK"
4345

4446
MULTI_RESOLVER_KEY = "MULTI_RESOLVER_KEY"
@@ -54,6 +56,7 @@
5456

5557
GROUP_METADATA = "GROUP_METADATA"
5658
SKIP_AUTH = "SKIP_AUTH"
59+
MODULE_COMPONENT = "MODULE_COMPONENT"
5760

5861

5962
class MODULE_METADATA(metaclass=AnnotationToValue):

ellar/common/decorators/base.py

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

44
from ellar.common.constants import NOT_SET
55
from ellar.common.operations.router import ModuleRouter
6-
from ellar.reflect import reflect
6+
from ellar.reflect import ensure_target, reflect
77

88

99
def set_metadata(
@@ -14,8 +14,9 @@ def set_metadata(
1414
return partial(set_metadata, meta_key)
1515

1616
def _decorator(target: t.Union[t.Callable, t.Any]) -> t.Callable:
17+
target = ensure_target(target)
1718
if isinstance(target, ModuleRouter):
18-
target = target.control_type
19+
target = target.get_controller_type()
1920

2021
reflect.define_metadata(meta_key, meta_value, target)
2122
return target

ellar/common/decorators/controller.py

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from ellar.common.exceptions import ImproperConfiguration
1010
from ellar.common.models import ControllerBase, ControllerType
1111
from ellar.di import RequestORTransientScope, injectable
12-
from ellar.reflect import REFLECT_TYPE, reflect
12+
from ellar.reflect import reflect, transfer_metadata
1313
from injector import Scope
1414
from starlette.middleware import Middleware
1515

@@ -64,10 +64,9 @@ def _decorator(cls: t.Type) -> t.Type[ControllerBase]:
6464
if type(cls) is not ControllerType:
6565
# We force the cls to inherit from `ControllerBase` by creating another type.
6666
attrs = {}
67-
if hasattr(cls, REFLECT_TYPE):
68-
attrs.update({REFLECT_TYPE: cls.__dict__[REFLECT_TYPE]})
6967
new_cls = type(cls.__name__, (cls, ControllerBase), attrs)
7068

69+
transfer_metadata(cls, new_cls)
7170
_controller_type = t.cast(t.Type[ControllerBase], new_cls)
7271

7372
_tag = _controller_type.controller_class_name()
@@ -82,19 +81,6 @@ def _decorator(cls: t.Type) -> t.Type[ControllerBase]:
8281
.replace("controller", "")
8382
)
8483

85-
# for base in get_type_of_base(ControllerBase, _controller_type):
86-
# if reflect.has_metadata(CONTROLLER_WATERMARK, base) and hasattr(
87-
# cls, "__CONTROLLER_WATERMARK__"
88-
# ):
89-
# raise ImproperConfiguration(
90-
# f"`@Controller` decorated classes does not support inheritance. \n"
91-
# f"{_controller_type}"
92-
# )
93-
94-
# if not reflect.has_metadata(
95-
# CONTROLLER_WATERMARK, _controller_type
96-
# ) and not hasattr(cls, "__CONTROLLER_WATERMARK__"):
97-
9884
reflect.define_metadata(CONTROLLER_WATERMARK, True, _controller_type)
9985
# reflect_all_controller_type_routes(_controller_type)
10086

ellar/common/decorators/exception.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,28 @@ class ValidateExceptionHandler(BaseModel):
1212
def _add_exception_handler(
1313
exc_class_or_status_code: t.Union[int, t.Type[Exception]],
1414
handler: t.Union[t.Callable, t.Type],
15+
app: bool = False,
1516
) -> None:
1617
validator = ValidateExceptionHandler(key=exc_class_or_status_code, value=handler)
17-
exception_handlers = {validator.key: validator.value}
18+
exception_handlers = {validator.key: (validator.value, app)}
1819
setattr(handler, EXCEPTION_HANDLERS_KEY, exception_handlers)
1920
setattr(handler, MODULE_DECORATOR_ITEM, EXCEPTION_HANDLERS_KEY)
2021

2122

2223
def exception_handler(
23-
exc_class_or_status_code: t.Union[int, t.Type[Exception]],
24+
exc_or_status_code: t.Union[int, t.Type[Exception]], app: bool = False
2425
) -> t.Callable:
2526
"""
2627
========= MODULE DECORATOR ==============
2728
2829
Defines Exception Handler at Module Level
29-
:param exc_class_or_status_code:
30+
:param exc_or_status_code: Exception Class or Status Code
31+
:param app: Indicates Exception Handler will be global to the application
3032
:return: Function
3133
"""
3234

3335
def decorator(func: t.Union[t.Callable, t.Type]) -> t.Callable:
34-
_add_exception_handler(exc_class_or_status_code, func)
36+
_add_exception_handler(exc_or_status_code, func, app)
3537
return func
3638

3739
return decorator

ellar/common/decorators/middleware.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,16 @@
44
from ellar.common.constants import MIDDLEWARE_HANDLERS_KEY, MODULE_DECORATOR_ITEM
55

66

7-
def _add_middleware(dispatch: t.Callable, **options: t.Any) -> None:
7+
def _add_middleware(dispatch: t.Callable, app: bool = False, **options: t.Any) -> None:
88
setattr(
99
dispatch,
1010
MIDDLEWARE_HANDLERS_KEY,
11-
AttributeDict(dispatch=dispatch, options=options),
11+
AttributeDict(dispatch=dispatch, options=options, is_global=app),
1212
)
1313
setattr(dispatch, MODULE_DECORATOR_ITEM, MIDDLEWARE_HANDLERS_KEY)
1414

1515

16-
def middleware() -> t.Callable:
16+
def middleware(app: bool = False) -> t.Callable:
1717
"""
1818
========= MODULE DECORATOR ==============
1919
@@ -32,7 +32,7 @@ async def my_middleware(cls, context: IExecutionContext, call_next):
3232
"""
3333

3434
def decorator(func: t.Callable) -> t.Callable:
35-
_add_middleware(dispatch=func)
35+
_add_middleware(dispatch=func, app=app)
3636
return func
3737

3838
return decorator

ellar/common/decorators/modules.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,20 @@ def _wrapper(
3131
if not isinstance(target, type):
3232
raise ImproperConfiguration(f"{name} is a class decorator - {target}")
3333

34-
if not kwargs.base_directory:
34+
if not kwargs.base_directory and not reflect.get_metadata(
35+
MODULE_METADATA.BASE_DIRECTORY, target
36+
):
3537
kwargs.update(base_directory=Path(inspect.getfile(target)).resolve().parent)
3638

37-
if not kwargs.name:
39+
if not kwargs.name and not reflect.get_metadata(MODULE_METADATA.NAME, target):
3840
kwargs.name = f"{get_name(target)}{uuid.uuid4().hex[:10]}"
3941

4042
reflect.define_metadata(watermark_key, True, target)
43+
4144
for key in metadata_keys:
42-
reflect.define_metadata(key, kwargs[key], target)
45+
if not reflect.get_metadata(key, target) or kwargs[key] is not None:
46+
reflect.define_metadata(key, kwargs[key], target)
47+
4348
injectable(SingletonScope)(target)
4449
return target
4550

ellar/common/exceptions/callable_exceptions.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,25 +40,25 @@ def exception_handler_fun(ctx: IExecutionContext, exc: Exception):
4040
def __init__(
4141
self,
4242
*func_args: t.Any,
43-
exc_class_or_status_code: t.Union[t.Type[Exception], int],
44-
callable_exception_handler: t.Union[
43+
exc_or_status_code: t.Union[t.Type[Exception], int],
44+
handler: t.Union[
4545
t.Callable[
4646
[IHostContext, Exception],
4747
t.Union[t.Awaitable[Response], Response, t.Any],
4848
],
4949
t.Any,
5050
],
5151
) -> None:
52-
self.callable_exception_handler = callable_exception_handler
52+
self.callable_exception_handler = handler
5353
self.is_async = False
5454
self.func_args = func_args
5555

56-
if not isinstance(exc_class_or_status_code, int):
57-
assert issubclass(exc_class_or_status_code, Exception)
56+
if not isinstance(exc_or_status_code, int):
57+
assert issubclass(exc_or_status_code, Exception)
5858

59-
self.exception_type_or_code = exc_class_or_status_code
59+
self.exception_type_or_code = exc_or_status_code
6060

61-
if is_async_callable(callable_exception_handler):
61+
if is_async_callable(handler):
6262
self.is_async = True
6363

6464
async def catch(

ellar/common/interfaces/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from .middleware import IEllarMiddleware
1717
from .module import IModuleSetup
1818
from .response_model import IResponseModel
19-
from .templating import IModuleTemplateLoader
19+
from .templating import IModuleTemplateLoader, ITemplateRenderingService
2020
from .versioning import IAPIVersioning, IAPIVersioningResolver
2121

2222
__all__ = [
@@ -42,4 +42,5 @@
4242
"IEllarMiddleware",
4343
"IIdentitySchemes",
4444
"IApplicationReady",
45+
"ITemplateRenderingService",
4546
]

ellar/common/interfaces/exceptions.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,12 @@
11
import typing as t
22
from abc import ABC, abstractmethod
33

4-
from ellar.pydantic import as_pydantic_validator
54
from starlette.responses import Response
65

76
from .context import IHostContext
87

98

10-
@as_pydantic_validator("__validate_input__", schema={"type": "object"})
119
class IExceptionHandler(ABC, t.Iterable):
12-
@classmethod
13-
def __validate_input__(cls, v: t.Any, _: t.Any) -> t.Any:
14-
if not isinstance(v, cls):
15-
raise ValueError(f"Expected IExceptionHandler object, received: {type(v)}")
16-
return v
17-
1810
def __eq__(self, other: t.Any) -> bool:
1911
if isinstance(other, IExceptionHandler):
2012
return other.exception_type_or_code == self.exception_type_or_code
@@ -42,7 +34,9 @@ def __init_subclass__(cls, **kwargs: t.Any) -> None:
4234

4335
class IExceptionMiddlewareService:
4436
@abstractmethod
45-
def build_exception_handlers(self, *exception_handlers: IExceptionHandler) -> None:
37+
def build_exception_handlers(
38+
self, *exception_handlers: IExceptionHandler
39+
) -> "IExceptionMiddlewareService":
4640
"""Build Exception Handlers"""
4741

4842
@abstractmethod

0 commit comments

Comments
 (0)