Skip to main content

No project description provided

Project description

Ninject

PyPI - Version PyPI - Python Version License: MIT

Ninject uses modern Python features to provide a simple and performant dependency injection framework.

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 TypedDictand 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ninject-0.0.1.tar.gz (13.2 kB view details)

Uploaded Source

Built Distribution

ninject-0.0.1-py3-none-any.whl (9.7 kB view details)

Uploaded Python 3

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

Hashes for ninject-0.0.1.tar.gz
Algorithm Hash digest
SHA256 b2a44abc6a52b04b0a317b709a18a5baa217643ead8394eaa05a1bb7d5d585ef
MD5 acc3fccdf47eaed130a0b9a00f418cf7
BLAKE2b-256 5f5fec1072a825b4451b5de65f10ff0f4e495fda4266f06571629ec757cfe95c

See more details on using hashes here.

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

Hashes for ninject-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 4ed7acd1b9d1b7f9e573d4942da401f7f59b6a9e36428a2216d4ec9ebb847921
MD5 d92535809e754bc7656e4f35aef6ab6f
BLAKE2b-256 894b878205478b6a5392216f6ab09e5ebfb7501d15f2cbb66a3237657b99dc6a

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page