Skip to main content

Highly extensible Dependency injection framework for humans

Project description

hexdi

Highly extensible Dependency Injection framework for humans

Project location: https://github.com/zibertscrem/hexdi

Installation

pip install hexdi

You should have python 3.5.* or higher

Usage

All of that usages you can find in examples directory

Quick usage reference

import hexdi


class SomeA:
    def foo(self): pass


# mark that class as injectable with permanent lifetime for class SomeA
@hexdi.permanent(SomeA)
class SomeAimplementation(SomeA):
    def foo(self):
        return 42


# inject instance of SomeA as a first argument
@hexdi.inject(SomeA)
def test_injection(a: SomeA):
    print('test_injection:', a.foo())


class ClassWithDependency:
    # constructor injection
    @hexdi.inject(SomeA)
    def __init__(self, a: SomeA):
        print('ClassWithDependency.__init__:', a.foo())

    # after that we can use property like an instance of SomeA class
    @property
    @hexdi.dependency(SomeA)
    def some_a(self) -> SomeA: pass

    def foo(self):
        print('ClassWithDependency.foo:', self.some_a.foo())

    # method injection also works fine.
    # Because injection members are passing after all transmitted positional arguments
    @hexdi.inject(SomeA)
    def foo_with_injection(self, a: SomeA):
        print('ClassWithDependency.foo_with_injection:', a.foo())


if __name__ == '__main__':
    # You don't need to provide any argument. DI container does it self
    # There also should not be cycle dependencies due to lazy loading of any injections
    test_injection()  # prints: test_injection: 42
    cwd = ClassWithDependency()  # prints: ClassWithDependency.__init__: 42
    cwd.foo()  # prints: ClassWithDependency.foo: 42
    cwd.foo_with_injection()  # prints: ClassWithDependency.foo_with_injection: 42

Self-binding

import hexdi


@hexdi.permanent()
class SomeA:
    def foo(self):
        return 42


@hexdi.inject(SomeA)
def test(a):
    print(a.foo())


if __name__ == '__main__':
    test()  # prints: 42

Multiple injection arguments

import hexdi


@hexdi.permanent()
class SomeA:
    def foo(self):
        return 42


@hexdi.permanent()
class SomeB:
    def foo(self):
        return 69


@hexdi.inject(SomeA, SomeB)
def test(a, b):
    print(a.foo() + b.foo())


if __name__ == '__main__':
    test()  # prints: 111

Permanent lifetime and transient lifetime

import hexdi


@hexdi.permanent()
class SomeA:
    NUMBER = 0

    def __init__(self):
        self.num = SomeA.NUMBER
        SomeA.NUMBER += 1

    def foo(self):
        print(self.__class__.__name__, self.num)


@hexdi.transient()
class SomeB:
    NUMBER = 0

    def __init__(self):
        self.num = SomeB.NUMBER
        SomeB.NUMBER += 1

    def foo(self):
        print(self.__class__.__name__, self.num)


@hexdi.inject(SomeA)
def test_a(a):
    a.foo()


@hexdi.inject(SomeB)
def test_b(b):
    b.foo()


if __name__ == '__main__':
    test_a()  # prints: SomeA 0
    test_a()  # prints: SomeA 0
    test_a()  # prints: SomeA 0
    test_b()  # prints: SomeB 0
    test_b()  # prints: SomeB 1
    test_b()  # prints: SomeB 2

Usage of container. Demonstration of lazy injection

import hexdi


class SomeA:
    def foo(self): pass


class SomeAImplementation(SomeA):
    def foo(self):
        return 42


@hexdi.permanent()
class SomeB:
    def foo(self):
        return 69


class SomeC:
    def foo(self):
        return 100500


@hexdi.inject(SomeC)
def test(c):
    print(c.foo())


if __name__ == '__main__':
    # getting of container
    container = hexdi.get_root_container()
    # binding SomeAImplementation on SomeA type with permanent lifetime
    container.bind_type(SomeAImplementation, SomeA, hexdi.lifetime.PermanentLifeTimeManager)
    instance = container.resolve(SomeA)
    print(instance.foo())  # prints: 42
    # resolve decorator-binded SomeB
    instance = container.resolve(SomeB)
    print(instance.foo())  # prints: 69
    # bind SomeC on itself with permanent lifetime
    container.bind_type(SomeC, SomeC, hexdi.lifetime.PermanentLifeTimeManager)
    # we mark SomeC for injection above in test func,
    # but all works fine, because it is lazy injection
    test()  # prints: 100500

Multifile project

If you have a project with separated base objects(to registration) and implementations(to injecting) there will be problematically to identify these implementations if you import it nowhere. For that situation, there is a class loading abstraction with a basic implementation that gets a list of specification objects with implementation modules. These specification object can be: - dot-separated module path as string: ‘pack1.pack2.module1’ - a function/lambda without params that returns a specification - a tuple that contains a function as a first argument and tuple of values as a second argument. Function should return a specification

import hexdi
from examples.multifile.interfaces import SomeA

loader = hexdi.get_loader([
    'examples.multifile.implementations'
])


@hexdi.inject(SomeA)
def test(a: SomeA):
    print(a.foo())


if __name__ == '__main__':
    loader.load()
    test()  # prints: 42

You also able to use recursive module finder to find all local packages, site-packages, dist-packages modules that contains type registering. Use same rules as module loader has

import hexdi
from examples.multifile.interfaces import SomeA

# That finder will find that
finder = hexdi.get_finder(['examples.multifile-finder'])
loader = hexdi.get_loader(finder.find())


@hexdi.inject(SomeA)
def test(a: SomeA):
    print(a.foo())


if __name__ == '__main__':
    loader.load()
    test()  # prints: 69

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

hexdi-0.1.4.tar.gz (7.6 kB view details)

Uploaded Source

Built Distribution

hexdi-0.1.4-py3-none-any.whl (16.9 kB view details)

Uploaded Python 3

File details

Details for the file hexdi-0.1.4.tar.gz.

File metadata

  • Download URL: hexdi-0.1.4.tar.gz
  • Upload date:
  • Size: 7.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No

File hashes

Hashes for hexdi-0.1.4.tar.gz
Algorithm Hash digest
SHA256 a4b9fa7c2f781139b6b5306e27babaa892248d1c4556405dfd3ddba4a9f6b3c3
MD5 471dfc329c79585f77703560e1b85a8a
BLAKE2b-256 21060f87112130c94f74cadc844e6e6ae64b96c18edf6c1c9218a848c20ee397

See more details on using hashes here.

File details

Details for the file hexdi-0.1.4-py3-none-any.whl.

File metadata

File hashes

Hashes for hexdi-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 f000ae8ae20232be0f0888f543fedbef2a8419113d964b118f15263d1b183700
MD5 f5c735a38a7d7aa5d9abf701f68a66a0
BLAKE2b-256 f255ca7c1250f6d9943d42d661437e8c50fc8e673ae3b6738164608e04514d53

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