-
Notifications
You must be signed in to change notification settings - Fork 2
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
1 parent
c0585a8
commit 16ad9fa
Showing
24 changed files
with
736 additions
and
13 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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,3 +15,6 @@ max_line_length = 79 | |
|
||
[*.md] | ||
trim_trailing_whitespace = false | ||
|
||
[*.{yaml,yml}] | ||
indent_size = 2 |
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,20 @@ | ||
import contextlib | ||
from collections.abc import Iterator | ||
|
||
import aioinject | ||
from aioinject import Scoped | ||
|
||
|
||
@contextlib.contextmanager | ||
def dependency() -> Iterator[int]: | ||
print("Startup") | ||
yield 42 | ||
print("Shutdown") | ||
|
||
|
||
container = aioinject.Container() | ||
container.register(Scoped(dependency)) | ||
|
||
with container.sync_context() as ctx: | ||
print(ctx.resolve(int)) # Startup, 42 | ||
# Shutdown |
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,22 @@ | ||
import contextlib | ||
from collections.abc import Iterator | ||
|
||
import aioinject | ||
from aioinject import Singleton | ||
|
||
|
||
@contextlib.contextmanager | ||
def dependency() -> Iterator[int]: | ||
print("Startup") | ||
yield 42 | ||
print("Shutdown") | ||
|
||
|
||
container = aioinject.Container() | ||
container.register(Singleton(dependency)) | ||
|
||
with container: | ||
with container.sync_context() as ctx: | ||
print(ctx.resolve(int)) # Startup, 42 | ||
print("Context is closed") | ||
# Shutdown |
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,26 @@ | ||
from types import TracebackType | ||
from typing import Self | ||
|
||
import aioinject | ||
from aioinject import Scoped | ||
|
||
|
||
class Class: | ||
def __enter__(self) -> Self: | ||
print("Startup") | ||
return self | ||
|
||
def __exit__( | ||
self, | ||
exc_type: type[BaseException] | None, | ||
exc_val: BaseException | None, | ||
exc_tb: TracebackType | None, | ||
) -> None: | ||
print("Shutdown") | ||
|
||
|
||
container = aioinject.Container() | ||
container.register(Scoped(Class)) | ||
|
||
with container.sync_context() as ctx: | ||
print(ctx.resolve(Class)) # <__main__.Class object at ...> |
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,35 @@ | ||
from collections.abc import Sequence | ||
|
||
from pydantic import PostgresDsn | ||
from pydantic_settings import BaseSettings, SettingsConfigDict | ||
|
||
import aioinject | ||
|
||
|
||
class AppSettings(BaseSettings): | ||
model_config = SettingsConfigDict(env_prefix="app_") | ||
|
||
version: str | ||
site_url: str | ||
|
||
|
||
class DatabaseSettings(BaseSettings): | ||
model_config = SettingsConfigDict(env_prefix="database_") | ||
|
||
url: PostgresDsn | ||
|
||
|
||
_settings_classes: Sequence[type[BaseSettings]] = [ | ||
AppSettings, | ||
DatabaseSettings, | ||
] | ||
|
||
|
||
def create_container() -> aioinject.Container: | ||
container = aioinject.Container() | ||
|
||
for settings_cls in _settings_classes: | ||
# Type is inferred from the instance passed into "Object" | ||
container.register(aioinject.Object(settings_cls())) | ||
|
||
return container |
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,34 @@ | ||
import aioinject | ||
|
||
|
||
class Database: | ||
def __init__(self) -> None: | ||
self._storage = {1: "Username"} | ||
|
||
def get(self, id: int) -> str | None: | ||
return self._storage.get(id) | ||
|
||
|
||
class UserService: | ||
def __init__( | ||
self, | ||
database: Database, # <- Aioinject would try to inject `Database` here | ||
) -> None: | ||
self._database = database | ||
|
||
def get(self, id: int) -> str: | ||
user = self._database.get(id) | ||
if user is None: | ||
raise ValueError | ||
return user | ||
|
||
|
||
container = aioinject.Container() | ||
container.register(aioinject.Singleton(Database)) | ||
container.register(aioinject.Singleton(UserService)) | ||
|
||
with container.sync_context() as ctx: | ||
service = ctx.resolve(UserService) | ||
user = service.get(1) | ||
assert user == "Username" | ||
print(user) |
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,36 @@ | ||
import contextlib | ||
from collections.abc import AsyncIterator | ||
from typing import Annotated | ||
|
||
import uvicorn | ||
from fastapi import FastAPI | ||
|
||
import aioinject | ||
from aioinject import Inject | ||
from aioinject.ext.fastapi import AioInjectMiddleware, inject | ||
|
||
|
||
container = aioinject.Container() | ||
container.register(aioinject.Object(42)) | ||
|
||
|
||
@contextlib.asynccontextmanager | ||
async def lifespan(_: FastAPI) -> AsyncIterator[None]: | ||
async with container: | ||
yield | ||
|
||
|
||
def create_app() -> FastAPI: | ||
app = FastAPI(lifespan=lifespan) | ||
app.add_middleware(AioInjectMiddleware, container=container) | ||
|
||
@app.get("/") | ||
@inject | ||
async def root(number: Annotated[int, Inject]) -> int: | ||
return number | ||
|
||
return app | ||
|
||
|
||
if __name__ == "__main__": | ||
uvicorn.run("main:create_app", factory=True, reload=True) |
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,31 @@ | ||
from typing import Annotated | ||
|
||
import uvicorn | ||
from litestar import Litestar, get | ||
|
||
import aioinject | ||
from aioinject import Inject | ||
from aioinject.ext.litestar import AioInjectPlugin, inject | ||
|
||
|
||
container = aioinject.Container() | ||
container.register(aioinject.Object(42)) | ||
|
||
|
||
@get("/") | ||
@inject | ||
async def function_route( | ||
number: Annotated[int, Inject], | ||
) -> int: | ||
return number | ||
|
||
|
||
def create_app() -> Litestar: | ||
return Litestar( | ||
[function_route], | ||
plugins=[AioInjectPlugin(container=container)], | ||
) | ||
|
||
|
||
if __name__ == "__main__": | ||
uvicorn.run("main:create_app", factory=True, reload=True) |
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,36 @@ | ||
from typing import Annotated, Any | ||
|
||
import strawberry | ||
import uvicorn | ||
from strawberry import Schema | ||
from strawberry.asgi import GraphQL | ||
|
||
import aioinject | ||
from aioinject import Inject | ||
from aioinject.ext.strawberry import AioInjectExtension, inject # (1)! | ||
|
||
|
||
container = aioinject.Container() | ||
container.register(aioinject.Object(42)) | ||
|
||
|
||
@strawberry.type | ||
class Query: | ||
@strawberry.field | ||
@inject | ||
async def number(self, number: Annotated[int, Inject]) -> int: | ||
return number | ||
|
||
|
||
def create_app() -> GraphQL[Any, Any]: | ||
schema = Schema( | ||
query=Query, | ||
extensions=[ | ||
AioInjectExtension(container=container), | ||
], | ||
) | ||
return GraphQL(schema=schema) | ||
|
||
|
||
if __name__ == "__main__": | ||
uvicorn.run("main:create_app", factory=True, reload=True) |
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,10 @@ | ||
import aioinject | ||
|
||
|
||
container = aioinject.Container() | ||
container.register(aioinject.Scoped(list)) | ||
|
||
with container.sync_context() as ctx: | ||
object_1 = ctx.resolve(list) | ||
object_2 = ctx.resolve(list) | ||
assert object_1 is object_2 |
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,13 @@ | ||
import aioinject | ||
|
||
|
||
container = aioinject.Container() | ||
container.register(aioinject.Singleton(list)) | ||
|
||
with container.sync_context() as ctx: | ||
object_1 = ctx.resolve(list) | ||
|
||
with container.sync_context() as ctx: | ||
object_2 = ctx.resolve(list) | ||
|
||
assert object_1 is object_2 |
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,10 @@ | ||
import aioinject | ||
|
||
|
||
container = aioinject.Container() | ||
container.register(aioinject.Transient(list)) | ||
|
||
with container.sync_context() as ctx: | ||
object_1 = ctx.resolve(list) | ||
object_2 = ctx.resolve(list) | ||
assert object_1 is not object_2 |
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,41 @@ | ||
Dependencies can use | ||
[`@contextlib.contextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager) | ||
and [`@contextlib.asynccontextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager) | ||
decorators to execute code during their init and shutdown. | ||
|
||
## Implementation | ||
Internally aioinject uses [contextlib.ExitStack](https://docs.python.org/3/library/contextlib.html#contextlib.ExitStack) | ||
and [contextlib.AsyncExitStack](https://docs.python.org/3/library/contextlib.html#contextlib.AsyncExitStack) | ||
|
||
## Providers | ||
### Scoped and Transient providers | ||
For `Scoped` and `Transient` providers dependencies will close when context is | ||
closed: | ||
|
||
```python | ||
--8<-- "docs/code/contextmanagers/01_context.py" | ||
``` | ||
|
||
### Singleton provider | ||
In case of a `Singleton` they're closed when you close container itself: | ||
|
||
```python | ||
--8<-- "docs/code/contextmanagers/02_container.py" | ||
``` | ||
|
||
## Using your own or 3rd party class as a context manager | ||
Even if your class has `__enter__` and `__exit__` methods it won't implicitly be | ||
used as a context manager: | ||
|
||
```python | ||
--8<-- "docs/code/contextmanagers/03_implicity.py" | ||
``` | ||
Nothing is printed! You have to explicitly create a function and decorate it with | ||
contextlib decorator: | ||
|
||
```python | ||
@contextlib.contextmanager | ||
def create_class() -> Class: | ||
with Class() as cls: | ||
yield cls | ||
``` |
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,7 @@ | ||
|
||
|
||
## Pydantic Settings | ||
Adding pydantic settings to a container: | ||
```python | ||
--8<-- "docs/code/cookbook/pydantic-settings.py" | ||
``` |
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,14 @@ | ||
Aioinject is a [dependency injection](https://en.wikipedia.org/wiki/Dependency_injection) | ||
and [service locator](https://en.wikipedia.org/wiki/Service_locator_pattern) | ||
library, made to easily work with dependency injection using python type annotations. | ||
|
||
## Installation | ||
Install with pip or your favorite package manager: | ||
``` | ||
pip install aioinject | ||
``` | ||
## Example | ||
|
||
```python | ||
--8<-- "docs/code/example.py" | ||
``` |
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,5 @@ | ||
To integrate with FastAPI you need to add a `AioinjectMiddleware` and | ||
optionally a lifespan if you use context manager dependencies: | ||
```python hl_lines="24-25" | ||
--8<-- "docs/code/integrations/fastapi_.py" | ||
``` |
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,4 @@ | ||
Litestar integration comes with a plugin, you just need to add it to litestar app: | ||
```python hl_lines="26" | ||
--8<-- "docs/code/integrations/litestar_.py" | ||
``` |
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,8 @@ | ||
Aioinject integrates with `strawberry-graphql` using a | ||
[custom extension](https://strawberry.rocks/docs/guides/custom-extensions): | ||
|
||
```python hl_lines="10 28" | ||
--8<-- "docs/code/integrations/strawberry-graphql.py" | ||
``` | ||
|
||
1. Note that `inject` is imported from `aioinject.ext.strawberry` |
Oops, something went wrong.