Skip to content

Commit 2022260

Browse files
authored
Merge pull request #231 from python-ellar/documentation_update
Documentation Updates Aug2024
2 parents 6852ed4 + ddb2043 commit 2022260

Some content is hidden

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

55 files changed

+697
-228
lines changed

docs/basics/application-context.md

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
1-
# **Application Context**
1+
# **Injector Context**
22

33
In the complex web of dependencies within Ellar,
44
accessing the application instance without triggering circular import errors can be a daunting task.
55

6-
To address this challenge, Ellar introduces the concept of an application context,
6+
To address this challenge, Ellar introduces the concept of an injector context,
77
a powerful mechanism that facilitates smooth access to the application instance throughout various parts of the codebase.
88

9-
## **Understanding the Application Context**
9+
## **Understanding the Injector Context**
1010

11-
The application context serves as a bridge between different components of the application, making the application object
11+
The Injector context serves as a bridge between different components of the application, making the application object
1212
readily available through the application Dependency Injection (DI) container. This ensures that you can access the
1313
application instance without encountering import issues, whether it's during request handling, execution of CLI commands,
1414
or manual invocation of the context.
1515

1616
Two key elements of the application context are:
1717

1818
- **current_injector**: This proxy variable refers to the current application **injector**, providing access to any service or the application instance itself.
19-
- **config**: A lazy loader for application configuration, which is based on the `ELLAR_CONFIG_MODULE` reference or accessed through `application.config` when the application context is active.
19+
- **current_config**: A lazy loader for application configuration, which is based on the `ELLAR_CONFIG_MODULE` reference or accessed through `application.config` when the application context is active.
2020

2121
## **Integration with Click Commands**
2222

@@ -27,7 +27,7 @@ For instance, consider the following example:
2727

2828
```python
2929
import ellar_cli.click as click
30-
from ellar.app import current_injector
30+
from ellar.core import current_injector
3131
from ellar.di import injectable
3232

3333
@injectable
@@ -37,7 +37,7 @@ class MyService:
3737

3838
@click.command()
3939
@click.argument('name')
40-
@click.with_app_context
40+
@click.with_injector_context
4141
def my_command(name: str):
4242
my_service = current_injector.get(MyService)
4343
my_service.do_something()
@@ -63,8 +63,9 @@ For example, consider the following event handling setup:
6363

6464
```python
6565
from ellar.events import app_context_teardown, app_context_started
66-
from ellar.app import App, AppFactory, current_injector
67-
from ellar.threading import run_as_async
66+
from ellar.app import App, AppFactory
67+
from ellar.core import current_injector, injector_context
68+
from ellar.threading import run_as_sync
6869

6970
@app_context_started.connect
7071
async def on_context_started():
@@ -76,9 +77,9 @@ def on_context_ended():
7677

7778
app = AppFactory.create_app()
7879

79-
@run_as_async
80+
@run_as_sync
8081
async def run_app_context():
81-
async with app.application_context() as ctx:
82+
async with injector_context(app.injector) as ctx:
8283
print("-----> Context is now available <------")
8384

8485
app_instance = ctx.injector.get(App)

docs/cli/custom-commands.md

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -38,44 +38,42 @@ ARGUMENTS:
3838
--help Show this message and exit.
3939
```
4040

41-
## **With App Context Decorator**
42-
The `ellar_cli.click` module includes a command decorator function called `with_app_context`.
41+
## **With Injector Context Decorator**
42+
The `ellar_cli.click` module includes a command decorator function called `with_injector_context`.
4343
This decorator ensures that a click command is executed within the application context,
44-
allowing `current_injector`, and `config` to have values.
44+
allowing `current_injector`, and `current_config` to have values.
4545

4646
For instance:
4747

4848
```python
4949
import ellar_cli.click as click
50-
from ellar.core import Config
51-
from ellar.app import current_injector
50+
from ellar.core import Config, current_injector
5251

5352
@click.command()
5453
@click.argument("arg1", required=True, help="Arg1 description")
55-
@click.with_app_context
54+
@click.with_injector_context
5655
def command_context(arg1):
5756
config = current_injector.get(Config)
5857
print("ALLOWED_HOSTS:", config.ALLOWED_HOSTS, ";ELLAR_CONFIG_MODULE:", config.config_module)
5958

6059
@click.command()
6160
@click.argument("arg1", required=True, help="Arg1 description")
62-
def command_wc(arg1):
61+
def command_woc(arg1):
6362
config = current_injector.get(Config)
6463
print("ALLOWED_HOSTS:", config.ALLOWED_HOSTS, ";ELLAR_CONFIG_MODULE:", config.config_module)
6564
```
6665

67-
In this example, `command_context` is wrapped with `with_app_context`, while `command_wc` is not.
66+
In this example, `command_context` is wrapped with `with_injector_context`, while `command_woc` is not.
6867
When executing both commands, `command_context` will run successfully, and `command_wc` will raise a RuntimeError
6968
because it attempts to access a value outside the context.
7069

7170
## **AppContextGroup**
72-
`AppContextGroup` extended from `click.Group` to wrap all its commands with `with_app_context` decorator.
71+
`AppContextGroup` extended from `click.Group` to wrap all its commands with `with_injector_context` decorator.
7372

7473

7574
```python
7675
import ellar_cli.click as click
77-
from ellar.core import Config
78-
from ellar.app import current_injector
76+
from ellar.core import Config, current_injector
7977

8078
cm = click.AppContextGroup(name='cm')
8179

@@ -94,37 +92,36 @@ def command_wc(arg1):
9492
```
9593
All commands registered under `cm` will be executed under within the context of the application.
9694

97-
### **Disabling `with_app_context` in AppContextGroup**
95+
### **Disabling `with_injector_context` in AppContextGroup**
9896
There are some cases where you may want to execute a command under `AppContextGroup` outside application context.
99-
This can be done by setting `with_app_context=False` as command parameter.
97+
This can be done by setting `with_injector_context=False` as command parameter.
10098

10199
```python
102100
import ellar_cli.click as click
103101

104102
cm = click.AppContextGroup(name='cm')
105103

106-
@cm.command(with_app_context=False)
104+
@cm.command(with_injector_context=False)
107105
@click.argument("arg1", required=True, help="Arg1 description")
108106
def command_wc(arg1):
109107
# config = current_injector.get(Config)
110108
print("ALLOWED_HOSTS:Unavailable;ELLAR_CONFIG_MODULE:Unavailable")
111109
```
112110

113111
## Async Command
114-
The `ellar_cli.click` package provides a utility decorator function, `run_as_async`,
112+
The `ellar_cli.click` package provides a utility decorator function, `run_as_sync`,
115113
specifically designed to execute coroutine commands.
116114
This is useful when you want to define asynchronous commands using the `click` package.
117115
Here's an example:
118116

119117
```python
120118
import ellar_cli.click as click
121-
from ellar.core import Config
122-
from ellar.app import current_injector
119+
from ellar.core import Config,current_injector
123120

124121
@click.command()
125122
@click.argument("arg1", required=True, help="Arg1 description")
126-
@click.with_app_context
127-
@click.run_as_async
123+
@click.with_injector_context
124+
@click.run_as_sync
128125
async def command_context(arg1):
129126
config = current_injector.get(Config)
130127
print("ALLOWED_HOSTS:", config.ALLOWED_HOSTS, ";ELLAR_CONFIG_MODULE:", config.config_module)
@@ -148,7 +145,7 @@ def makemigrations():
148145
"""Create DB Migration """
149146

150147
@db.command()
151-
def migrate():
148+
async def migrate():
152149
"""Applies Migrations"""
153150
```
154151

@@ -184,7 +181,7 @@ Commands:
184181

185182
```
186183

187-
Having explored various methods for crafting commands and understanding the roles of `wrap_app_context` and `run_as_async` decorators,
184+
Having explored various methods for crafting commands and understanding the roles of `with_injector_context` and `run_as_sync` decorators,
188185
you now possess the knowledge to create diverse commands for your Ellar application.
189186

190187
It's crucial to keep in mind that any custom command you develop needs to be registered within a `@Module` class, which,

docs/overview/custom_decorators.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,9 @@ The **Inject[Type]** annotation is used to inject a service registered in Ellar
4545

4646
For example:
4747
```python
48+
from ellar.app import App
4849
from ellar.common import ModuleRouter, Inject
49-
from ellar.core import App, Config
50+
from ellar.core import Config
5051
from sqlalchemy.ext.asyncio import AsyncSession
5152

5253

@@ -172,7 +173,7 @@ def get_requests_case_2(
172173
## **Custom Parameter Decorators**
173174
You can create your own route parameter decorators whenever necessary. You simply need to follow a contract, `NonParameterResolver`, and override the resolve function.
174175

175-
The `NonParameterResolver` has two attribute, `type_annotation` and `parameter_name`, that are provided automatically when computing route function parameter dependencies.
176+
The `NonParameterResolver` has two attributes, `type_annotation` and `parameter_name`, that are provided automatically when computing route function parameter dependencies.
176177
The `type_annotation` and `parameter_name` are determined from the parameter declaration like so - `def route_function(parameter_name:type_annotation = NonParameterResolver())`.
177178

178179
All `NonParameterResolver` receives current `IExecutionContext` during route function execution, and it must return a tuple of dict object of the resulting resolve data with `parameter_name` and list of errors if any.
@@ -445,11 +446,13 @@ See [Ellar-CLI Custom Commands](../cli/introduction.md){target="_blank"}
445446

446447
- `@exception_handler`: This decorator is used to register a function as an exception handler. This function will be called when an unhandled exception occurs during a request. It should take the exception instance as its only argument and return a response object.
447448

448-
- `@middleware`: This decorator is used to register a function as a middleware. Middlewares are called for each incoming request and can be used to modify the request or response, or perform any other actions before or after the request is handled.
449+
- `@middleware`: This decorator is used to register a function as middleware. Middlewares are called for each incoming request and can be used to modify the request or response, or perform any other actions before or after the request is handled.
449450

450-
- `@template_filter`: This decorator is used to register a function as a Jinja2 template filter. The function should take one or more arguments and return a modified value.
451+
- `@template_filter`: This decorator is used to register a function as a Jinja2 template filter.
451452

452-
- `@template_global`: This decorator is used to register a function as a global variable available in all Jinja2 templates. The function can be called without any arguments and should return a value.
453+
- `@template_global`: This decorator is used to register a function as a global variable available in all Jinja2 templates.
453454

455+
- `@template_context`: This decorator is used to register a function as a global template context for dynamic template context processing.
456+
454457
These decorators can be used to define functions that will be executed at specific points in the application's lifecycle.
455458
They provide a way to separate and organize the different parts of an application. See [Module Additional Configuration](modules.md#additional-module-configurations){target="_blank"} for examples on how these decorator functions are used.

docs/overview/exception_handling.md

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ it is intercepted by this middleware, which then automatically sends an appropri
1010
}
1111
```
1212
Depending on the application's configuration and the value of `DEBUG`, the exception handling behavior differs.
13-
When `config.DEBUG` is True, the exception that is raised is shown to the client for easy error debugging.
14-
However, when `config.DEBUG` is False, a 500 error is returned to the client, as illustrated below:
13+
When `current_config.DEBUG` is True, the exception that is raised is shown to the client for easy error debugging.
14+
However, when `current_config.DEBUG` is False, a 500 error is returned to the client, as illustrated below:
1515

1616
```json
1717
{
@@ -91,7 +91,8 @@ Service Unavailable
9191

9292

9393
## **Exception Handlers**
94-
Exception Handlers are classes or functions that handles what response that is returned to the client for specific exception types.
94+
Exception Handlers are classes or functions
95+
that handle what response that is returned to the client for specific exception types.
9596

9697
Here is an example of an ExceptionHandler that handles `HTTPException` in the application:
9798

@@ -298,38 +299,31 @@ To make the `exception_handler_fun` work as an ExceptionHandler, you will need t
298299
```python
299300
from starlette.responses import PlainTextResponse
300301
from ellar.common import IExecutionContext
301-
from ellar.common.exceptions import CallableExceptionHandler
302+
from ellar.core.exceptions import CallableExceptionHandler, as_exception_handler
302303

303304

304-
def exception_handler_fun(ctx: IExecutionContext, exc: Exception):
305+
@as_exception_handler
306+
def exception_400_handler(ctx: IExecutionContext, exc: Exception):
305307
return PlainTextResponse('Bad Request', status_code=400)
306-
307-
308-
exception_400_handler = CallableExceptionHandler(
309-
exc_class_or_status_code=400, callable_exception_handler=exception_handler_fun
310-
)
311308
```
312309
In the example above, you have created an `exception_400_handler` Exception Handler to handle HTTP exceptions with a status code of 400.
313310
You can then register it as an exception handler in your configuration, as we did in the previous section:
314311

315-
Additionally, `exception_handler_fun` can be configured to handle a custom exception type, as shown below:
312+
Additionally, We can create a handler to handle custom exception types, as shown below:
316313

317314
```python
318315
from starlette.responses import PlainTextResponse
319316
from ellar.common import IExecutionContext
320-
from ellar.common.exceptions import CallableExceptionHandler
317+
from ellar.core.exceptions import as_exception_handler
321318

322319

323320
class CustomException(Exception):
324321
pass
325322

326323

327-
def exception_handler_fun(ctx: IExecutionContext, exc: Exception):
324+
@as_exception_handler(CustomException)
325+
def exception_custom_handler(ctx: IExecutionContext, exc: Exception):
328326
return PlainTextResponse('Bad Request', status_code=400)
329327

330-
331-
exception_custom_handler = CallableExceptionHandler(
332-
exc_class_or_status_code=CustomException, callable_exception_handler=exception_handler_fun
333-
)
334328
```
335329
In this example, `exception_custom_handler` is configured to handle a custom exception type, CustomException.

docs/overview/guards.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# **Guards**
22

33
A **Guard** in Ellar is a way to add **authentication** and **authorization** checks to your application.
4-
It acts as a middleware and runs before executing the route handler. If the guard returns **false**, the request is rejected and the execution is stopped.
4+
It acts as middleware and runs before executing the route handler.
5+
If the guard returns **false**, the request is rejected and the execution is stopped.
56

67
**Guards** can be used to check for specific roles, permissions, or any other arbitrary condition.
78
They can be easily applied to individual routes or groups of routes using `@guard` decorator.

docs/overview/interceptors.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,4 +145,6 @@ class InterceptCustomException(EllarInterceptor):
145145
return {"message": str(cex)}
146146
```
147147

148-
In the above code, the `InterceptCustomException` interceptor catches any `CustomException` raised during the execution of the request/response cycle. It then modifies the response object to set the status code to 400 and returns a JSON response containing the exception message. This allows for custom handling of exceptions within the interceptor before they are propagated to the system's exception handlers.
148+
In the above code, the `InterceptCustomException` interceptor catches any `CustomException` raised during the execution of the request/response cycle.
149+
It then modifies the response object to set the status code to 400 and returns a JSON response containing the exception message.
150+
This allows for custom handling of exceptions within the interceptor before they are propagated to the system's exception handlers.

0 commit comments

Comments
 (0)