autocontainer 1.1.0

Creator: railscoder56

Last updated:

Add to Cart

Description:

autocontainer 1.1.0

AutoContainer
Python really needed a modern reflection based dependency injection container
that "just works". Alas, welcome to AutoContainer for python. The dependency injection service contaienr that just works.
Features

Direct class as service
Separate provider functions
Service Behaviors:

Singleton
Factory
Assembler
Instance


Naming Services
Container Bound Functions
Dependency Graph
Automatic Injection
Service registration checking
Inject typehint by name
Primitive types by name

Installation
pip3 install autocontainer

Requirements:

Python >= 3.5

Usage
It's all about types and hints, but first create the container
from autocontianer import Container

container = Container()

# Party Time

Classes & Injection
We'll use singleton as an example.
class A:
pass

class B:
def __init__(self, obj_a: A):
assert isinstance(obj_a, A)

# Order does not matter.
container.singleton(B)
container.singleton(A)

obj_b = container.get(B)
assert isinstance(obj_b, B)

Naming Services
class A:
pass

container.singleton(A, 'ayy')

obj_a = container.get(A)
obj_b = container.get('ayy')


assert obj_a is obj_b

Other ways to get
obj_a = container.get(A) # <--- Best IDE Support due to type hints.
obj_b = container.get('ayy')
obj_c = container.ayy # <--- the most concise way.
obj_d = container('ayy')

Builder Functions
You won't always put raw classes into the service container
sometimes, it's necessary to write a function that custom
initializes a class or object.
class A:
pass

class B:
def __init__(self):
self.fruit = 'tomato'

def makeB(obj_a: A) -> B: # Return type MUST be annotated
b = B()
b.fruit = 'mango'

return b

container.singleton(makeB)

obj_b = container(B)

assert obj_b.fruit == 'mango'

Factory
Factories can also take builder function as well as classes.
The container returns a new instance every time.
class A:
pass

container.factory(A)

aa = container.get(A)
ab = container.get(A)

assert aa is not ab
assert isinstance(aa, A)
assert isinstance(ab, A)

Binding
This is the coolest feature, trust me. Imagine you have a function
that needs both classes out of a container and vanilla arguments
like int and str, this would be a pain to do manually. Unless...
class A:
pass

class B:
pass

container.singleton(A)
container.singleton(B)

def crazy_function(a: A, repeating: str, b: B, times: int):
assert isinstance(a, A)
assert isinstance(b, B)

return repeating * time

less_crazy_function = container.bind(crazy_function)

result = less_crazy_function("pew", 3)
assert result == 'pewpewpew'

Injecting
Same as binding but for simpler times.
class A:
pass

class B:
pass

container.singleton(A)
container.singleton(B)

def crazy_function(a: A, b: B):
assert isinstance(a, A)
assert isinstance(b, B)

return 'potato'

assert contianer.inject(crazy_function) == 'potato'

Specificity Injector
The container maintains an internal graph of dependencies that allows
it to efficiently push instances of ancestor classes.
class A:
pass

class B:
pass

class C(A):
pass

class D(C, B):
pass

container.factory(A)
container.singleton(B)
container.factory(C)
container.singleton(D)

obj = container.get(A)
assert isinstance(obj, D)
assert isinstance(obj, A)

Hinting by Name
This is completely valid with the container
class A:
pass

container.singleton(A, 'apple')

def magic(ap: 'apple'):
assert isinstance(ap, A)

container.inject(magic)

Available Methods


get(service: Union[Type, str])
Retreives a service


has(service: Union[Type, str])
Returns if a service exists


singleton(service: Union[Type, Callable[..., Instance]], name?: str)
Adds a service as a singleton into container.
(Returns the same object on every get)


factory(service: Union[Type, Callable[..., Instance]], name?: str)
Adds a service as a factory into container.
(Returns a fresh object on every get)


instance(service: object, name?: str)
Adds a service as an instance into container.
(Returns the same object on every get, but does not try to instantiate)


assembler(service: Union[Type, Callable[..., Instance]], name?: str)
Adds a service such that on every get, the container returns a bound callable
that produces a fresh object everytime.


bind(func: Callable)
Returns a new callable but in which the arguments recognized by the container
are automatically pushed when calling. (see examples below)


inject(func: Callable)
Takes a callable and calls it by injecting all the services it requires
and then returns the return value.


Running Tests
python -m unittest discover -s ./

License
MIT. Go crazy.

License

For personal and professional use. You cannot resell or redistribute these repositories in their original state.

Customer Reviews

There are no reviews.