Skip to content

Commit 41cb12a

Browse files
authored
Merge pull request #59 from eadwinCode/guard_refactor
Guards Refactor
2 parents 45da751 + fc22b5d commit 41cb12a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+1394
-501
lines changed

ellar/common/__init__.py

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,27 @@
1+
import typing as t
2+
13
from ellar.core.params.params import Param, ParamTypes
24
from ellar.core.routing import ModuleRouter
35

4-
from .decorators.base import set_metadata
5-
from .decorators.command import command
6-
from .decorators.controller import Controller
7-
from .decorators.exception import exception_handler
8-
from .decorators.file import file
9-
from .decorators.guards import guards
10-
from .decorators.html import render, template_filter, template_global
11-
from .decorators.middleware import middleware
12-
from .decorators.modules import Module
13-
from .decorators.openapi import openapi_info
14-
from .decorators.request import on_shutdown, on_startup
15-
from .decorators.serializer import serializer_filter
16-
from .decorators.versioning import version
6+
from .decorators import (
7+
Controller,
8+
Module,
9+
command,
10+
exception_handler,
11+
extra_args,
12+
file,
13+
guards,
14+
middleware,
15+
on_shutdown,
16+
on_startup,
17+
openapi_info,
18+
render,
19+
serializer_filter,
20+
set_metadata,
21+
template_filter,
22+
template_global,
23+
version,
24+
)
1725
from .routing import (
1826
Body,
1927
Context,
@@ -91,4 +99,9 @@
9199
"Http",
92100
"UploadFile",
93101
"file",
102+
"extra_args",
94103
]
104+
105+
106+
def __dir__() -> t.List[str]:
107+
return sorted(__all__) # pragma: no cover

ellar/common/decorators/__init__.py

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,40 @@
1-
from .base import set_metadata # noqa
2-
from .command import command # noqa
3-
from .controller import Controller # noqa
4-
from .exception import exception_handler # noqa
5-
from .file import file # noqa
6-
from .guards import guards # noqa
7-
from .html import render, template_filter, template_global # noqa
8-
from .middleware import middleware # noqa
9-
from .modules import Module # noqa
10-
from .openapi import openapi_info # noqa
11-
from .request import on_shutdown, on_startup # noqa
12-
from .serializer import serializer_filter # noqa
13-
from .versioning import version # noqa
1+
import typing as t
2+
3+
from .base import set_metadata
4+
from .command import command
5+
from .controller import Controller
6+
from .exception import exception_handler
7+
from .extra_args import extra_args
8+
from .file import file
9+
from .guards import guards
10+
from .html import render, template_filter, template_global
11+
from .middleware import middleware
12+
from .modules import Module
13+
from .openapi import openapi_info
14+
from .request import on_shutdown, on_startup
15+
from .serializer import serializer_filter
16+
from .versioning import version
17+
18+
__all__ = [
19+
"serializer_filter",
20+
"Controller",
21+
"version",
22+
"guards",
23+
"template_filter",
24+
"template_global",
25+
"file",
26+
"render",
27+
"on_startup",
28+
"exception_handler",
29+
"on_shutdown",
30+
"command",
31+
"set_metadata",
32+
"middleware",
33+
"openapi_info",
34+
"Module",
35+
"extra_args",
36+
]
37+
38+
39+
def __dir__() -> t.List[str]:
40+
return sorted(__all__) # pragma: no cover

ellar/common/decorators/base.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,12 @@
88
def set_metadata(
99
meta_key: t.Any,
1010
meta_value: t.Optional[t.Any] = NOT_SET,
11-
default_value: t.Any = None,
1211
) -> t.Callable:
1312
if meta_value is NOT_SET:
1413
return partial(set_metadata, meta_key)
1514

1615
def _decorator(target: t.Union[t.Callable, t.Any]) -> t.Union[t.Callable, t.Any]:
17-
reflect.define_metadata(meta_key, meta_value, target, default_value)
16+
reflect.define_metadata(meta_key, meta_value, target)
1817
return target
1918

2019
return _decorator

ellar/common/decorators/controller.py

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@
99
CONTROLLER_METADATA,
1010
CONTROLLER_OPERATION_HANDLER_KEY,
1111
CONTROLLER_WATERMARK,
12+
GUARDS_KEY,
1213
NOT_SET,
1314
OPERATION_ENDPOINT_KEY,
1415
REFLECT_TYPE,
16+
VERSIONING_KEY,
1517
)
1618
from ellar.core import ControllerBase
1719
from ellar.core.controller import ControllerType
@@ -45,12 +47,19 @@ def reflect_all_controller_type_routes(cls: t.Type[ControllerBase]) -> None:
4547
operation = reflect.get_metadata( # type: ignore
4648
CONTROLLER_OPERATION_HANDLER_KEY, item
4749
)
48-
reflect.define_metadata(CONTROLLER_CLASS_KEY, cls, operation.endpoint) # type: ignore
50+
endpoint_func = operation.endpoint # type:ignore
51+
if reflect.has_metadata(CONTROLLER_CLASS_KEY, endpoint_func):
52+
raise Exception(
53+
f"{cls.__name__} Controller route tried to be processed more than once."
54+
f"\n-RouteFunction - {endpoint_func}."
55+
f"\n-Controller route function can not be reused once its under a `@Controller` decorator."
56+
)
57+
58+
reflect.define_metadata(CONTROLLER_CLASS_KEY, cls, endpoint_func)
4959
reflect.define_metadata(
5060
CONTROLLER_OPERATION_HANDLER_KEY,
51-
operation,
61+
[operation],
5262
cls,
53-
default_value=[],
5463
)
5564

5665

@@ -144,14 +153,17 @@ def _decorator(cls: t.Type) -> t.Type[ControllerBase]:
144153
if not isinstance(cls, type):
145154
raise ImproperConfiguration(f"Controller is a class decorator - {cls}")
146155

156+
_controller_type = t.cast(t.Type[ControllerBase], cls)
157+
new_cls = None
158+
147159
if type(cls) is not ControllerType:
148160
# We force the cls to inherit from `ControllerBase` by creating another type.
149161
attrs = {}
150162
if hasattr(cls, REFLECT_TYPE):
151163
attrs.update({REFLECT_TYPE: cls.__dict__[REFLECT_TYPE]})
152-
cls = type(cls.__name__, (cls, ControllerBase), attrs)
164+
new_cls = type(cls.__name__, (cls, ControllerBase), attrs)
153165

154-
_controller_type = t.cast(t.Type[ControllerBase], cls)
166+
_controller_type = t.cast(t.Type[ControllerBase], new_cls)
155167

156168
_tag = _controller_type.controller_class_name()
157169

@@ -168,14 +180,23 @@ def _decorator(cls: t.Type) -> t.Type[ControllerBase]:
168180
.replace("controller", "")
169181
)
170182

171-
if not reflect.get_metadata(CONTROLLER_WATERMARK, _controller_type):
183+
if not reflect.has_metadata(
184+
CONTROLLER_WATERMARK, _controller_type
185+
) and not hasattr(cls, "__CONTROLLER_WATERMARK__"):
172186
reflect.define_metadata(CONTROLLER_WATERMARK, True, _controller_type)
173187
reflect_all_controller_type_routes(_controller_type)
174188
injectable(RequestScope)(cls)
175189

176190
for key in CONTROLLER_METADATA.keys:
177191
reflect.define_metadata(key, kwargs[key], _controller_type)
178192

193+
reflect.define_metadata(VERSIONING_KEY, kwargs.version, _controller_type)
194+
reflect.define_metadata(GUARDS_KEY, kwargs.guards, _controller_type)
195+
196+
if new_cls:
197+
# if we forced cls to inherit from ControllerBase, we need to block it from been processed
198+
setattr(cls, "__CONTROLLER_WATERMARK__", True)
199+
179200
return _controller_type
180201

181202
if callable(prefix):

ellar/common/decorators/extra_args.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import typing as t
2+
3+
from ellar.constants import EXTRA_ROUTE_ARGS_KEY
4+
from ellar.core.params import ExtraEndpointArg
5+
6+
from .base import set_metadata as set_meta
7+
8+
9+
def extra_args(*args: ExtraEndpointArg) -> t.Callable:
10+
"""
11+
=========FUNCTION DECORATOR ==============
12+
13+
Programmatically adds extra route function parameter.
14+
see https://github.com/eadwinCode/ellar/blob/main/tests/test_routing/test_extra_args.py for usages
15+
:param args: Collection ExtraEndpointArg
16+
:return:
17+
"""
18+
return set_meta(EXTRA_ROUTE_ARGS_KEY, list(args))

ellar/common/decorators/guards.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@ def guards(
1818
:param _guards: Guard Type or Instance
1919
:return:
2020
"""
21-
return set_meta(GUARDS_KEY, _guards, default_value=[])
21+
return set_meta(GUARDS_KEY, list(_guards))

ellar/common/decorators/modules.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,14 +90,14 @@ def Module(
9090
"""
9191
kwargs = AttributeDict(
9292
name=name,
93-
controllers=controllers,
93+
controllers=list(controllers),
9494
base_directory=base_directory,
9595
static_folder=static_folder,
96-
routers=routers,
97-
providers=providers,
96+
routers=list(routers),
97+
providers=list(providers),
9898
template_folder=template_folder,
99-
modules=modules,
100-
commands=commands,
99+
modules=list(modules),
100+
commands=list(commands),
101101
)
102102

103103
return partial(

ellar/common/decorators/openapi.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,4 @@ def openapi_info(
3333
deprecated=deprecated,
3434
tags=tags,
3535
),
36-
default_value=AttributeDict(),
3736
)

ellar/common/decorators/versioning.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,4 @@ def version(*_version: str) -> t.Callable:
1313
:param _version: allowed versions
1414
:return:
1515
"""
16-
return set_meta(
17-
VERSIONING_KEY, set([str(i) for i in _version]), default_value=set()
18-
)
16+
return set_meta(VERSIONING_KEY, set([str(i) for i in _version]))

ellar/common/routing/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import typing as t
2+
13
from ellar.core.datastructures import UploadFile
24
from ellar.core.params import Param, ParamTypes
35
from ellar.core.routing import OperationDefinitions
@@ -69,3 +71,7 @@
6971
"Host",
7072
"Http",
7173
]
74+
75+
76+
def __dir__() -> t.List[str]:
77+
return sorted(__all__) # pragma: no cover

0 commit comments

Comments
 (0)