Skip to main content

Dep man is a dependency manager library with dependency injection implementation and future annotations support for avoiding circular imports.

Project description

Web SDK

Dep man is a dependency manager library with dependency injection implementation and future annotations support for avoiding circular imports.

CI Coverage pypi downloads versions Web SDK alfa

Installation

Install using pip install dep-man-pydi or uv add dep-man-pydi

Features

  • ContextVar based injection
  • Annotation like providers injection
    • String annotations support
    • ForwardRef annotations support
    • Future annotations support
    • Runtime annotations support
  • Scopes support
    • Custom providers scopes
    • Interface based injection from different scopes
    • Multiple scopes context
    • Including other scopes external providers
  • Context manager injection
    • Sync manager support
    • Async manager support
    • Nested context managers usage
    • Global context with optional immediate injection
  • Classes support
    • Class instances injection
    • Class providers inheritance
    • Nested providers in classes attrs
    • Interface based class instance injection
    • Injection via context manager
    • Injection via global context
    • Mark as injectable via decorating
    • Sync function result attrs injection
    • Async function result attrs injection
  • Functions support
    • Sync function result injection
    • Async function result injection
    • Nested providers in function args
    • Protocol based function result injection
    • Injection via context manager
    • Injection via global context
    • Injection via decorating
  • Singleton support
    • App level singletons (including any functions results)
    • Global context singleton support
    • Current context singleton support
  • Dependency manager
    • Multi DI managers support
    • Custom DI managers support
    • DI manager custom Scope type
    • DI manager custom Injector type
  • Integrations
    • Django middleware
    • Starlet middleware (can use with FastAPI)

Examples

# docs/examples/home/minimal/usage.py

from collections.abc import Awaitable

from dep_man import BIND, Depend, FDepend, dm


# declare sync function
def foo() -> str:
    return "foo_value"


# declare async function
async def async_foo() -> str:
    return "async_foo_value"


# declare function with dependence on foo
def bar(foo_value: FDepend[str, foo] = BIND) -> tuple[str, str]:
    # also you can use Depend and FDepend with function or classes
    # which also hame save annotations their values will be created
    # from context or scope providers
    return "bar_value", foo_value


# declare interface
class IFoo:
    foo: bool
    var: int


# declare class with dependence on foo and bar
class Foo(IFoo):
    # in this case all fields with "Depend" of "FDepend" annotations
    # will be replaced with descriptor for getting value from context
    foo: FDepend[bool, foo]
    bar: FDepend[int, bar]
    # also you can use Depend and FDepend with function or classes
    # which also hame save annotations their values will be created
    # from context or scope providers

    # inheritance providers is also supported


# declare function for providing singleton result
def singleton(arg: Depend[Foo] = BIND) -> Foo:
    return arg


# I recommend creating a new scopes and call provide methods
# in the "dependencies.py" file in the roots of your modules or applications

# as scope name you can use Enum or str
scope = dm.add_scope("scope")
# provide functions and classes
scope.provide(foo)
scope.provide(async_foo)
scope.provide(bar)
# provide Foo with interface, you can use Depend[Foo] or Depend[IFoo] for getting Foo instance
scope.provide(Foo, interface=IFoo)
# singleton result function

# you can also provide object in certain scope using dm method
dm.provide(singleton, scope="scope", singleton=True)


# declare class with interface for other scope
class OtherFoo(IFoo):
    foo = False
    bar = -1


# create other scope
other_scope = dm.add_scope("other_scope")
# provide class in other scope with same interface
other_scope.provide(OtherFoo, interface=IFoo)

# next you need specify modules for loading
# if you have next structure
"""
...
├── app
└   ├── bar
    │   ├── ...
    │   ├── dependencies.py
    │   ├── __init__.py
    └── foo
        ├── ...
        ├── dependencies.py
        ├── __init__.py
"""

# you need make next load call
dm.load("app.bar", "app.foo")

# you can also specify file_name via load arg file_name
dm.load("app.bar", "app.foo", file_name="your_file")

# for django you need call this in ready method of you AppConfig
dm.load()

# at the beginning of the request you need call dm.init()
# if you use starlette, fastapy or django you can use middleware
from dep_man import get_django_middleware, get_starlette_middleware

# this method you need call for every request in middleware
dm.init()
# you can use globalize=True for add providers from all scopes globally to dm context
dm.init(globalize=True)
# or add to global context only certain scopes
dm.init(globalize=("notifications", "settings"))


# if you use context of run dm.init(globalize=True)
# you can create instance or call functions for any provider
# without context manager usage
foo_instance = Foo()  # <__main__.Foo object at ...>
foo_instance.foo  # 'foo_value'
foo_instance.bar  # ('bar_value', 'foo_value')

# singleton function result
singleton() is singleton()  # True


# If you want to inject dependencies into a class that was not provided,
# use need decorate this class with dm.inject as decorator
@dm.inject
class Injectable:
    # in this case all fields with "Depend" of "FDepend" annotations
    # will be replaced with descriptor for getting value from context
    foo: Depend[Foo]
    foo_from_interface: Depend[IFoo]


# usage example via context manager
with dm.inject("scope"):
    # create instance of inject decorated class
    instance = Injectable()

    # Foo instance was created ones and set to instance.__dict__
    instance.foo  # <__main__.Foo object at ...>

    instance.foo_from_interface  # <__main__.Foo object at ...>

    # foo call ones for getting result and set to instance.__dict__
    instance.foo.foo  # foo_value

    # bar call ones for getting result and set to instance.__dict__
    # inside the bar call foo was called once.
    instance.foo.bar  # ('bar_value', 'foo_value')


# you can also use nested context managers
with dm.inject("scope"):
    instance = Injectable()
    # In this context we will get the provider instance with interface=IFoo from the scope
    isinstance(instance.foo_from_interface, Foo)  # True

    with dm.inject("other_scope"):
        instance = Injectable()
        # In this context we will get the provider instance with interface=IFoo from the other_scope
        isinstance(instance.foo_from_interface, OtherFoo)  # True


# usage example via function decoration
# here you can specify scopes or inject all if not specify
@dm.inject("scope")
def injectable(common: bool, arg: Depend[Foo] = BIND):
    # in this case injectable __code__ will be replaced passing
    # providers via signature.parameters defaults values from context
    return common, arg.foo, arg.bar


# function call will be run with dm.inject("scope") context
injectable(True)  # (True, 'foo_value', ('bar_value', 'foo_value'))


# async support logic of the injector's operation is similar
@dm.inject
class Foo:
    # you can add async function result to you instances attrs
    async_attr: FDepend[Awaitable[bool], async_foo]


# you can use async variant of context manager
async with dm.inject("scope"):
    async with dm.inject("other_scope"):
        # you can get async function result from provider
        await Foo().async_attr  # async_foo_value


# you can use inject decorator on async function
@dm.inject("scope")
async def async_injectable(common: bool, arg: FDepend[Awaitable[bool], async_foo] = BIND):
    return common, await arg


await async_injectable(common=True)  # (True, 'async_foo_value')

Changelog

v0.2.0

  • Add permanent singletons supporting

v0.1.3

  • Fix root all

v0.1.2

  • Add core logic
  • Add tests
  • Add minimal docs

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

dep_man_pydi-0.2.0.tar.gz (34.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dep_man_pydi-0.2.0-py3-none-any.whl (30.7 kB view details)

Uploaded Python 3

File details

Details for the file dep_man_pydi-0.2.0.tar.gz.

File metadata

  • Download URL: dep_man_pydi-0.2.0.tar.gz
  • Upload date:
  • Size: 34.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for dep_man_pydi-0.2.0.tar.gz
Algorithm Hash digest
SHA256 23d8a8cb9fad9e6e2fd06680953c93989bbc1151560927b39f836db09acf4fae
MD5 9bc4598420d63e1924364099f817b159
BLAKE2b-256 355bed9da0450b0063f9981c6fc9d58da11453a9369021cdab13c2c02c49c3a4

See more details on using hashes here.

Provenance

The following attestation bundles were made for dep_man_pydi-0.2.0.tar.gz:

Publisher: ci.yml on extralait-web/dep-man

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file dep_man_pydi-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: dep_man_pydi-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 30.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for dep_man_pydi-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 17f1ac3d7f9db283bcbfb1bf6e6508ca474227e2fefb9fd7514f687ca9d1ae49
MD5 af18e7eead30ebaaefe754e001bc55bf
BLAKE2b-256 d4cfdc78a94bc0247544ce2f96ff911a5cf8c45f56d5f55ef3cbfdf741f48d80

See more details on using hashes here.

Provenance

The following attestation bundles were made for dep_man_pydi-0.2.0-py3-none-any.whl:

Publisher: ci.yml on extralait-web/dep-man

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

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