No project description provided
Project description
Ninject
Ninject uses modern Python features to provide a simple and performant dependency injection framework.
- Installation
- Basic Usage
- Types of Providers
- Providers with Dependencies
- Providing Multiple Dependencies
- Providing Dependencies Concurrently
- Mixing Async and Sync Providers
Installation
pip install ninject
Basic Usage
First declare a Dependency
and inject
it into a dependent function.
from ninject import Dependency, inject
Message = Dependency("Message", str)
@inject
def print_message(*, message: Message = inject.ed):
print(message)
Next, define a Context
with a function that provides
the Dependency
.
from ninject import Context
context = Context()
@context.provides
def provide_message() -> Message:
return Message("Hello, World!")
Finally, establish the context
and call the function with the inject.ed
dependency:
with context:
print_message()
The output will be:
Hello, World!
Types of Providers
A provider is one of the following
- A function that returns a value
- A generator that yields a single value
- A context manager class that yields a value
- An async function that returns a value
- An async generator that yields a single value
- An async context manager class that yields a value
from contextlib import ContextManager, AsyncContextManager
from ninject import Dependency, Context
Message = Dependency("Message", str)
context = Context()
# --- Sync Providers -------------------------------------
@context.provides
def sync_function() -> Message:
return Message("Hello, World!")
@context.provides
def sync_generator() -> Message:
try:
yield Message("Hello, World!")
finally:
pass
@context.provides
class SyncContextManager(ContextManager):
def __enter__(self) -> Message:
return Message("Hello, World!")
def __exit__(self, *args) -> None:
pass
# --- Async Providers ------------------------------------
@context.provides
async def async_function() -> Message:
return Message("Hello, World!")
@context.provides
async def async_generator() -> Message:
try:
yield Message("Hello, World!")
finally:
pass
@context.provides
class AsyncContextManager(AsyncContextManager):
async def __aenter__(self) -> Message:
return Message("Hello, World!")
async def __aexit__(self, *args) -> None:
pass
Providers with Dependencies
Providers can have their own dependencies:
from ninject import Context, Dependency, inject
Greeting = Dependency("Greeting", str)
Recipient = Dependency("Recipient", str)
Message = Dependency("Message", str)
@inject
def print_message(*, message: Message = inject.ed):
print(message)
context = Context()
@context.provides
def provide_greeting() -> Greeting:
return Greeting("Hello")
@context.provides
def provide_recipient() -> Greeting:
return Greeting("World")
@context.provides
def provide_message(
*, greeting: Greeting = inject.ed, recipient: Recipient = inject.ed
) -> Message:
return Message(f"{greeting}, {recipient}!")
if __name__ == "__main__":
with context:
print_message()
The output will be:
Hello, World!
Providing Multiple Dependencies
A single provider can supply multiple dependencies:
from ninject import Context, Dependency, inject
Greeting = Dependency("Greeting", str)
Recipient = Dependency("Recipient", str)
MessageContent = tuple[Greeting, Recipient]
@inject
def print_message(*, greeting: Greeting = inject.ed, recipient: Recipient = inject.ed):
print(f"{greeting}, {recipient}!")
context = Context()
@context.provides
def provide_message_content() -> MessageContent:
return "Hello", "World"
if __name__ == "__main__":
with context:
print_message()
You may also depend on MessageContent
directly:
from ninject import Context, Dependency, inject
Greeting = Dependency("Greeting", str)
Recipient = Dependency("Recipient", str)
MessageContent = tuple[Greeting, Recipient]
@inject
def print_message(*, message_content: MessageContent = inject.ed): # TypeError!
greeting = message_content["greeting"]
recipient = message_content["recipient"]
print(f"{greeting}, {recipient}!")
context = Context()
@context.provides(MessageContent)
def provide_message_content() -> dict:
return {"greeting": "Hello", "recipient": "World"}
if __name__ == "__main__":
with context:
print_message()
Note that the dependencies
decorator returns an Annotated
type so you won't be able
to call it directly as you normally would. If you want to do this you'll need to have
two separate types defined - one for the TypedDict
and one for theDependency
:
from ninject import Dependency
Greeting = Dependency("Greeting", str)
Recipient = Dependency("Recipient", str)
class MessageContent(TypedDict):
greeting: Greeting
recipient: Recipient
MessageContentDependency = Dependency[MessageContent, "MessageContent"]
Providing Dependencies Concurrently
Ninject does not execute async providers concurrently. If you want to do so, you can leverage the ability to provide multiple dependencies at once.
import asyncio
from ninject import Context, Dependency, inject
Greeting = Dependency("Greeting", str)
Recipient = Dependency("Recipient", str)
@dependencies
class MessageContent(TypedDict):
greeting: Greeting
recipient: Recipient
@inject
async def print_message(
*, greeting: Greeting = inject.ed, recipient: Recipient = inject.ed
):
print(f"{greeting}, {recipient}!")
context = Context()
async def get_message() -> str:
return "Hello"
async def get_recipient() -> str:
return "World"
@context.provides(MessageContent)
async def provide_message_content() -> dict:
greeting, recipient = await asyncio.gather(get_message(), get_recipient())
return {"greeting": greeting, "recipient": recipient}
if __name__ == "__main__":
with context:
asyncio.run(print_message())
Mixing Async and Sync Providers
To mix async and sync providers, the highest order dependent function must be async. So,
in the example below, the fact that the sync provide_message
function depends on the
async provide_recipient
function works because print_message
(the highest order
dependent function) is async:
import asyncio
from ninject import Context, Dependency, inject
Greeting = Dependency("Greeting", str)
Recipient = Dependency("Recipient", str)
context = Context()
@context.provides(Recipient)
async def provide_recipient() -> str:
return "World"
@context.provides(Message)
def provide_message(*, recipient: Recipient = inject.ed) -> str:
return f"Hello, {recipient}!"
@inject
async def print_message(*, message: Message = inject.ed):
print(message)
if __name__ == "__main__":
with context:
asyncio.run(print_message())
If print_message
were sync, then the following error would be raised:
RuntimeError: Cannot use an async context manager in a sync context
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file ninject-0.0.1.tar.gz
.
File metadata
- Download URL: ninject-0.0.1.tar.gz
- Upload date:
- Size: 13.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: python-httpx/0.27.0
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | b2a44abc6a52b04b0a317b709a18a5baa217643ead8394eaa05a1bb7d5d585ef |
|
MD5 | acc3fccdf47eaed130a0b9a00f418cf7 |
|
BLAKE2b-256 | 5f5fec1072a825b4451b5de65f10ff0f4e495fda4266f06571629ec757cfe95c |
File details
Details for the file ninject-0.0.1-py3-none-any.whl
.
File metadata
- Download URL: ninject-0.0.1-py3-none-any.whl
- Upload date:
- Size: 9.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: python-httpx/0.27.0
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 4ed7acd1b9d1b7f9e573d4942da401f7f59b6a9e36428a2216d4ec9ebb847921 |
|
MD5 | d92535809e754bc7656e4f35aef6ab6f |
|
BLAKE2b-256 | 894b878205478b6a5392216f6ab09e5ebfb7501d15f2cbb66a3237657b99dc6a |