-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
130 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
## wireup_init_fastapi_integration | ||
::: wireup.integration.fastapi_integration.wireup_init_fastapi_integration | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
Dependency injection for FastAPI (all versions) is available via the first-party integration wireup provides, available in | ||
`wireup.integration.fastapi_integration`. | ||
|
||
|
||
**Features:** | ||
|
||
* Automatically decorate Flask views and blueprints where the container is being used. | ||
* Eliminates the need for `@container.autowire` in views. | ||
* Views without container references will not be decorated. | ||
* Services **must** be annotated with `Wire()`. | ||
* Can: Mix FastAPI dependencies and Wireup in views | ||
* Can: Autowire any FastAPI target with `@container.autowire`. | ||
* Cannot: Use FastAPI dependencies in Wireup service objects. | ||
|
||
!!! tip | ||
As FastAPI does not have a fixed configuration mechanism, you need to expose | ||
any configuration objects to the container using one of the two options: | ||
|
||
* By dumping all values in the parameter bag. | ||
* Registering the configuration object as a service using a factory function. | ||
|
||
## Examples | ||
|
||
```python | ||
|
||
app = FastAPI() | ||
|
||
@app.get("/random") | ||
async def target( | ||
# Wire annotation tells wireup that this argument should be injected. | ||
random_service: Annotated[RandomService, Wire()], | ||
is_debug: Annotated[bool, Wire(param="env.debug")], | ||
|
||
# This is a regular FastAPI dependency. | ||
lucky_number: Annotated[int, Depends(get_lucky_number)] | ||
): | ||
return { | ||
"number": random_service.get_random(), | ||
"lucky_number": lucky_number, | ||
"is_debug": is_debug, | ||
} | ||
|
||
# Initialize the integration. | ||
# Must be called after all views have been registered. | ||
# Pass to service_modules a list of top-level modules where your services reside. | ||
wireup_init_fastapi_integration(app, service_modules=[services]) | ||
``` | ||
|
||
## Api Reference | ||
|
||
* [fastapi_integration](../class/fastapi_integration.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
from __future__ import annotations | ||
|
||
from typing import TYPE_CHECKING | ||
|
||
from fastapi.routing import APIRoute | ||
|
||
from wireup import DependencyContainer, container, warmup_container | ||
from wireup.integration.util import is_view_using_container | ||
|
||
if TYPE_CHECKING: | ||
from types import ModuleType | ||
|
||
from fastapi import FastAPI | ||
|
||
|
||
def wireup_init_fastapi_integration( | ||
app: FastAPI, | ||
service_modules: list[ModuleType], | ||
dependency_container: DependencyContainer = container, | ||
) -> None: | ||
"""Integrate wireup with a fastapi application. | ||
This must be called once all views have been registered. | ||
Decorates all views where container objects are being used making | ||
the `@container.autowire` decorator no longer needed. | ||
:param app: The application instance | ||
:param service_modules: A list of python modules where application services reside. These will be loaded to trigger | ||
container registrations. | ||
:param dependency_container: The instance of the dependency container. | ||
The default wireup singleton will be used when this is unset. | ||
This will be a noop and have no performance penalty for views which do not use the container. | ||
""" | ||
warmup_container(dependency_container, service_modules or []) | ||
|
||
for route in app.routes: | ||
if ( | ||
isinstance(route, APIRoute) | ||
and route.dependant.call | ||
and is_view_using_container(dependency_container, route.dependant.call) | ||
): | ||
route.dependant.call = dependency_container.autowire(route.dependant.call) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import inspect | ||
from typing import Any, Callable | ||
|
||
from wireup import DependencyContainer | ||
from wireup.ioc.types import InjectableType | ||
from wireup.ioc.util import parameter_get_type_and_annotation | ||
|
||
|
||
def is_view_using_container(dependency_container: DependencyContainer, view: Callable[..., Any]) -> bool: | ||
"""Determine whether the view is using the given dependency container.""" | ||
for dep in inspect.signature(view).parameters.values(): | ||
param = parameter_get_type_and_annotation(dep) | ||
|
||
is_requesting_injection = isinstance(param.annotation, InjectableType) | ||
if is_requesting_injection or (param.klass and dependency_container.is_type_known(param.klass)): | ||
return True | ||
|
||
return False |