Skip to content

Commit e674371

Browse files
authored
Merge pull request #130 from python-ellar/route_function_parameter_annotation
Route handlers dependencies type annotation support
2 parents 63b515c + 063fe57 commit e674371

File tree

81 files changed

+886
-562
lines changed

Some content is hidden

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

81 files changed

+886
-562
lines changed

.pre-commit-config.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@ repos:
1414
name: Code Formatting
1515
entry: "make fmt"
1616
types: [python]
17-
language_version: python3.8
17+
language_version: python3.10
1818
language: python
1919
- id: code_linting
2020
args: [ ]
2121
name: Code Linting
2222
entry: "make lint"
2323
types: [ python ]
24-
language_version: python3.8
24+
language_version: python3.10
2525
language: python
2626
- repo: https://github.com/pre-commit/pre-commit-hooks
2727
rev: v2.3.0

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ fmt format:clean ## Run code formatters
2626
black ellar tests examples
2727
ruff check --fix ellar tests examples
2828

29-
test: ## Run tests
29+
test:clean ## Run tests
3030
pytest
3131

3232
test-cov: ## Run tests with coverage

docs/basics/dynamic-modules.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,4 +141,4 @@ When `AppFactory` starts module bootstrapping, `my_module_configuration_factory`
141141
all the required **parameters** and returned a `DynamicModule` of `MyModule`.
142142

143143
For more example, checkout [Ellar Throttle Module](https://github.com/eadwinCode/ellar-throttler/blob/master/ellar_throttler/module.py){target="_blank"}
144-
or [Ellar Cache Module](../../techniques/caching){target="_blank"}
144+
or [Ellar Cache Module](../techniques/caching.md){target="_blank"}

docs/basics/execution-context.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -164,18 +164,18 @@ class ExecutionContext(HostContext):
164164
These extra information are necessary for reading `metadata` properties set on controllers or the route handler function.
165165

166166
### **How to access the current execution context**
167-
You can access the current execution context using the `Context()` function.
167+
You can access the current execution context using the `Inject[ExecutionContext]` annotation.
168168
This decorator can be applied to a parameter of a controller or service method,
169169
and it will inject the current `ExecutionContext` object into the method.
170170

171171
For example, consider the following controller method:
172172
```python
173-
from ellar.common import Context, get, Controller
173+
from ellar.common import get, Controller, IExecutionContext, Inject
174174

175175
@Controller('/users')
176176
class UserController:
177177
@get('/{user_id}')
178-
async def get_user(self, user_id: str, ctx=Context()):
178+
async def get_user(self, user_id: str, ctx:Inject[IExecutionContext]):
179179
# Use the ctx object to access the current execution context
180180
res = ctx.switch_to_http_connection().get_response()
181181
res.status_code = 200
@@ -185,7 +185,8 @@ class UserController:
185185

186186
```
187187

188-
In this example, the `get_user` method is decorated with the `@get` decorator to handle a GET request to the /users/:id route. The `Context()` function is applied to the second parameter of the method, which will inject the current `ExecutionContext` object into the method.
188+
In this example, the `get_user` method is decorated with the `@get` decorator to handle a GET request to the /users/:id route.
189+
The `Inject[ExecutionContext]` annotation is applied to the second parameter of the method, which will inject the current `ExecutionContext` object into the method.
189190

190191
Once you have access to the `ExecutionContext` object, you can use its methods and properties to access information about the current request.
191192

docs/index.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ $(venv) pip install ellar
5656
## **Try This**
5757
```python
5858
import uvicorn
59-
from ellar.common import Body, Controller, ControllerBase, delete, get, post, put, Serializer, Provide
59+
from ellar.common import Body, Controller, ControllerBase, delete, get, post, put, Serializer, Inject
6060
from ellar.core import AppFactory
6161
from ellar.di import injectable, request_scope
6262
from ellar.openapi import OpenAPIDocumentModule, OpenAPIDocumentBuilder, SwaggerDocumentGenerator
@@ -95,7 +95,7 @@ class MotoController(ControllerBase):
9595
return result
9696

9797
@get('/{car_id:str}')
98-
async def get_one(self, car_id: str, service: CarService = Provide()):
98+
async def get_one(self, car_id: str, service: Inject[CarService]):
9999
assert self._service == service
100100
return f"This action returns a #{car_id} car"
101101

docs/overview/controllers.md

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -91,19 +91,19 @@ class CarController(ControllerBase):
9191
...
9292
```
9393

94-
### **injection (`parameter_name=Req()`)**
94+
### **injection (`parameter_name=Inject[Request]`)**
9595

96-
We can also inject request object to any handler by using `@Req` decorator in handler signature.
96+
We can also inject request object to any handler by using `Inject[Request]` decorator in handler signature.
9797
```python
9898
# project_name/apps/car/controllers.py
9999

100-
from ellar.common import Controller, ControllerBase, get, Req
100+
from ellar.common import Controller, ControllerBase, get, Inject
101101
from ellar.core import Request
102102

103103
@Controller('/car')
104104
class CarController(ControllerBase):
105105
@get()
106-
def get_all(self, req_data: Request, req_data_2=Req()):
106+
def get_all(self, req_data: Request, req_data_2: Inject[Request]):
107107
assert isinstance(req_data, Request) # True
108108
assert isinstance(req_data_2, Request)
109109
assert req_data == req_data_2
@@ -131,21 +131,21 @@ class CarController(ControllerBase):
131131

132132
Other request `handler` signature injectors
133133

134-
| | |
135-
|-------------|--------------------------------------------------------------------------------------------------------|
136-
| `Req()` | for `Request` object |
137-
| `Res()` | for `Response` object |
138-
| `Path()` | pydantic field - resolves path parameters |
139-
| `Body()` | pydantic field - resolves required Request `body` parameters |
140-
| `Form()` | pydantic field - resolves required Request `body` parameters with content-type=`x-www-form-urlencoded` |
141-
| `Header()` | pydantic field - resolves required Request `header` parameters |
142-
| `Query()` | pydantic field - resolves required Request `query` parameters |
143-
| `File()` | pydantic field - resolves required Request `body` parameters with content-type=`x-www-form-urlencoded` |
144-
| `Ctx()` | Injects `ExecutionContext`. |
145-
| `Cookie()` | pydantic field - resolves required Request `cookie` parameters |
146-
| `Session()` | injects Request session data |
147-
| `Host()` | injects Request clients host |
148-
| `Provide()` | injects services |
134+
| | |
135+
|---------------------------------------|--------------------------------------------------------------------------------------------------------|
136+
| `Inject[Request]` | for `Request` object |
137+
| `Inject[Response]` | for `Response` object |
138+
| `Path()` | pydantic field - resolves path parameters |
139+
| `Body()` | pydantic field - resolves required Request `body` parameters |
140+
| `Form()` | pydantic field - resolves required Request `body` parameters with content-type=`x-www-form-urlencoded` |
141+
| `Header()` | pydantic field - resolves required Request `header` parameters |
142+
| `Query()` | pydantic field - resolves required Request `query` parameters |
143+
| `File()` | pydantic field - resolves required Request `body` parameters with content-type=`x-www-form-urlencoded` |
144+
| `Inject[ExecutionContext]` | Injects `ExecutionContext`. |
145+
| `Cookie()` | pydantic field - resolves required Request `cookie` parameters |
146+
| `Inject[dict, Inject.Key('Session')]` | injects Request session data |
147+
| `Inject[str, Inject.Key('Host')]` | injects Request clients host |
148+
| `Inject[Type]` | injects services |
149149

150150
## **Resource**
151151

@@ -244,7 +244,7 @@ from .schemas import CreateCarSerializer
244244

245245

246246
@post()
247-
async def create(self, payload: CreateCarSerializer = Body()):
247+
async def create(self, payload: Body[CreateCarSerializer]):
248248
return 'This action adds a new car'
249249
```
250250

@@ -271,13 +271,13 @@ from .schemas import CreateCarSerializer, CarListFilter
271271
@Controller('/car')
272272
class CarController(ControllerBase):
273273
@post()
274-
async def create(self, payload: CreateCarSerializer = Body()):
274+
async def create(self, payload:Body[CreateCarSerializer]):
275275
result = payload.dict()
276276
result.update(message='This action adds a new car')
277277
return result
278278

279279
@put('/{car_id:str}')
280-
async def update(self, car_id: str, payload: CreateCarSerializer = Body()):
280+
async def update(self, car_id: str, payload:Body[CreateCarSerializer]):
281281
result = payload.dict()
282282
result.update(message=f'This action updated #{car_id} car resource')
283283
return result
@@ -291,7 +291,7 @@ class CarController(ControllerBase):
291291
return f"This action removes a #{car_id} car"
292292

293293
@get()
294-
async def get_all(self, query: CarListFilter = Query()):
294+
async def get_all(self, query:Query[CarListFilter]):
295295
assert isinstance(self.context.switch_to_http_connection().get_request(), Request) # True
296296
return f'This action returns all cars at limit={query.limit}, offset={query.offset}'
297297

0 commit comments

Comments
 (0)