Skip to content

Commit 120a84c

Browse files
authored
Merge pull request #230 from python-ellar/module_concept
Ft: Module Routes Execution Context
2 parents dd27863 + d1fd7ef commit 120a84c

File tree

187 files changed

+2834
-1939
lines changed

Some content is hidden

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

187 files changed

+2834
-1939
lines changed

.github/workflows/test_full.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ jobs:
3232
- name: Set up Python
3333
uses: actions/setup-python@v5
3434
with:
35-
python-version: 3.8
35+
python-version: 3.9
3636
- name: Install Flit
3737
run: pip install flit
3838
- name: Install Dependencies

docs/overview/exception_handling.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ class ExceptionHandlerAction405(IExceptionHandler):
200200
self, ctx: IHostContext, exc: HTTPException
201201
) -> t.Union[Response, t.Any]:
202202
context_kwargs = {}
203-
return render_template('405.html', request=ctx.switch_to_http_connection().get_request(), **context_kwargs)
203+
return render_template('405.html', **context_kwargs)
204204
```
205205
In this code snippet, we've registered a handler for any `HTTP` exception with a `405` status code, and we return a template, `405.html`, as a response.
206206
Similarly, you can create an exception handler for the `500` status code that returns an HTML template.

docs/security/rate-limit.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ from ellar.common import Controller, get
103103

104104

105105
@Controller("/limit")
106-
@Throttle(apply_interceptor=True)
106+
@Throttle(intercept=True)
107107
class LimitController:
108108
def __init__(self, app_service: AppService):
109109
self.app_service = app_service
@@ -113,15 +113,15 @@ class LimitController:
113113
return self.app_service.success(use_auth)
114114
```
115115

116-
In the above example, by setting `apply_interceptor=True` within **@Throttle**,
116+
In the above example, by setting `intercept=True` within **@Throttle**,
117117
the `ThrottlerInterceptor` is applied to all routes within the `LimitController`.
118118
This feature is particularly useful when `ThrottlerInterceptor` is not globally applied.
119119

120120
Additionally, the **@Throttle** decorator can be used on a route level:
121121

122122
```python
123123
@get()
124-
@Throttle(apply_interceptor=True)
124+
@Throttle(intercept=True)
125125
def get_throttled(self, use_auth: bool):
126126
return self.app_service.success(use_auth)
127127
```
@@ -130,7 +130,7 @@ Another application of the **@Throttle** decorator is to override `ttl` and `lim
130130

131131
```python
132132
@Controller("/limit")
133-
@Throttle(apply_interceptor=True, anon={'ttl': 100, 'limit': 30})
133+
@Throttle(intercept=True, anon={'ttl': 100, 'limit': 30})
134134
class LimitController:
135135
def __init__(self, app_service: AppService):
136136
self.app_service = app_service

ellar/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
"""Ellar - Python ASGI web framework for building fast, efficient, and scalable RESTful APIs and server-side applications."""
22

3-
__version__ = "0.8.0"
3+
__version__ = "0.8b"

ellar/app/__init__.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
1-
from ellar.core.context import config, current_injector
2-
31
from .factory import AppFactory
42
from .main import App
53

64
__all__ = [
75
"App",
86
"AppFactory",
9-
"config",
10-
"current_injector",
117
]

ellar/app/factory.py

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
from pathlib import Path
33

44
import click
5-
from ellar.app.core_module import get_core_module
65
from ellar.common import IApplicationReady, Module
76
from ellar.common.constants import MODULE_METADATA
87
from ellar.common.exceptions import ImproperConfiguration
@@ -15,19 +14,22 @@
1514
ModuleBase,
1615
ModuleSetup,
1716
)
17+
from ellar.core.execution_context import injector_context
18+
from ellar.core.module import get_core_module
1819
from ellar.core.modules import ModuleRefBase, ModuleTemplateRef
1920
from ellar.di import EllarInjector, ProviderConfig
2021
from ellar.di.injector.tree_manager import ModuleTreeManager
2122
from ellar.reflect import reflect
22-
from ellar.threading.sync_worker import execute_async_context_manager
23+
from ellar.threading.sync_worker import execute_async_context_manager, execute_coroutine
2324
from ellar.utils import get_name, get_unique_type
2425
from starlette.routing import Host, Mount
2526

27+
from ..events.build import build_with_context_event
2628
from .main import App
2729

2830
if t.TYPE_CHECKING: # pragma: no cover
2931
from ellar.common import ModuleRouter
30-
from ellar.core.routing import EllarMount
32+
from ellar.core.routing import EllarControllerMount
3133

3234

3335
class AppFactory:
@@ -115,17 +117,23 @@ def _get_config_kwargs() -> t.Dict:
115117
parent_container=injector.container if injector else None,
116118
config=config,
117119
)
118-
core_module_ref.initiate_module_build()
120+
with execute_async_context_manager(
121+
injector_context(core_module_ref.container.injector)
122+
) as context:
123+
core_module_ref.initiate_module_build()
119124

120-
# service = EllarAppService(injector, config)
121-
# service.register_core_services()
122-
123-
with execute_async_context_manager(core_module_ref.context()) as context:
124125
tree_manager: ModuleTreeManager = core_module_ref.get(ModuleTreeManager)
125126
cls.read_all_module(core_module_ref, tree_manager)
127+
128+
# service = EllarAppService(injector, config)
129+
# service.register_core_services()
130+
126131
# Build application first level. This will trigger ApplicationModule to be built
127132
core_module_ref.build_dependencies(step=1)
128-
app_module_ref = tree_manager.get_root_module()
133+
app_module_ref = tree_manager.get_app_module()
134+
135+
execute_coroutine(build_with_context_event.run())
136+
build_with_context_event.disconnect_all()
129137

130138
app = App(
131139
routes=[],
@@ -155,19 +163,21 @@ def _get_config_kwargs() -> t.Dict:
155163
# app.setup_jinja_environment
156164
app.setup_jinja_environment()
157165

158-
for module, data in context.injector.tree_manager.modules.items():
166+
for module, data in context.tree_manager.modules.items():
159167
data.value.run_module_register_services()
160168

161169
if issubclass(module, IApplicationReady):
162-
context.injector.get(module).on_ready(app)
170+
context.get(module).on_ready(app)
163171

164172
return app
165173

166174
@classmethod
167175
def create_app(
168176
cls,
169177
controllers: t.Sequence[t.Union[t.Type]] = (),
170-
routers: t.Sequence[t.Union["ModuleRouter", "EllarMount", Mount, Host]] = (),
178+
routers: t.Sequence[
179+
t.Union["ModuleRouter", "EllarControllerMount", Mount, Host, t.Callable]
180+
] = (),
171181
providers: t.Sequence[t.Union[t.Type, "ProviderConfig"]] = (),
172182
modules: t.Sequence[t.Type[t.Union[ModuleBase, t.Any]]] = (),
173183
template_folder: t.Optional[str] = None,

0 commit comments

Comments
 (0)