Skip to content

Commit 1d09894

Browse files
authored
feat: ⚡️ Shorter syntax for FastAPI dependencies
1 parent bba3be8 commit 1d09894

File tree

4 files changed

+56
-57
lines changed

4 files changed

+56
-57
lines changed

documentation/integrations.md

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,29 +8,11 @@
88

99
Here's how to inject an instance into a FastAPI endpoint.
1010

11-
> Import:
12-
1311
```python
1412
from injection.ext.fastapi import Inject
15-
```
16-
17-
> With **Annotated**:
18-
19-
```python
20-
@app.get("/")
21-
async def my_endpoint(
22-
service: Annotated[MyService, Inject(MyService)],
23-
) -> None:
24-
...
25-
```
2613

27-
> Without **Annotated**:
28-
29-
```python
3014
@app.get("/")
31-
async def my_endpoint(
32-
service: MyService = Inject(MyService),
33-
) -> None:
15+
async def my_endpoint(service: Inject[MyService]) -> None:
3416
...
3517
```
3618

injection/ext/fastapi.py

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from types import GenericAlias
2-
from typing import Any, TypeAliasType
2+
from typing import TYPE_CHECKING, Annotated, Any, TypeAliasType
33

44
from fastapi import Depends
55

@@ -8,20 +8,37 @@
88
__all__ = ("Inject",)
99

1010

11-
def Inject[T]( # noqa: N802
12-
cls: type[T] | TypeAliasType | GenericAlias,
13-
/,
14-
default: T = NotImplemented,
15-
module: Module | None = None,
16-
) -> Any:
17-
"""
18-
Declare a FastAPI dependency with `python-injection`.
19-
"""
11+
class FastAPIInject:
12+
__slots__ = ()
2013

21-
module = module or mod()
22-
lazy_instance = module.aget_lazy_instance(cls, default)
14+
def __call__[T](
15+
self,
16+
cls: type[T] | TypeAliasType | GenericAlias,
17+
/,
18+
default: T = NotImplemented,
19+
module: Module | None = None,
20+
) -> Any:
21+
module = module or mod()
22+
lazy_instance = module.aget_lazy_instance(cls, default)
2323

24-
async def getter() -> T:
25-
return await lazy_instance
24+
async def getter() -> T:
25+
return await lazy_instance
2626

27-
return Depends(getter, use_cache=False)
27+
return Depends(getter, use_cache=False)
28+
29+
def __getitem__(self, params: Any, /) -> Any:
30+
if not isinstance(params, tuple):
31+
params = (params,)
32+
33+
iter_params = iter(params)
34+
cls = next(iter_params)
35+
return Annotated[cls, self(cls), *iter_params]
36+
37+
38+
if TYPE_CHECKING:
39+
type Inject[T, *Args] = Annotated[T, Depends(), *Args]
40+
41+
else:
42+
Inject = FastAPIInject()
43+
44+
del FastAPIInject

tests/ext/test_fastapi.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@ class Dependency: ...
1313

1414

1515
@application.post("/integration", status_code=204)
16-
async def integration_endpoint(dependency: Dependency = Inject(Dependency)):
16+
async def integration_endpoint(dependency: Inject[Dependency]):
1717
assert isinstance(dependency, Dependency)
1818

1919

2020
@application.post("/integration-unknown-dependency", status_code=204)
21-
async def integration_unknown_dependency_endpoint(dependency: object = Inject(object)):
21+
async def integration_unknown_dependency_endpoint(dependency: Inject[object]):
2222
assert dependency is NotImplemented
2323

2424

uv.lock

Lines changed: 21 additions & 21 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)