All Projects → illuin-tech → opyoid

illuin-tech / opyoid

Licence: MIT License
Dependency injection library for Python

Programming Languages

python
139335 projects - #7 most used programming language

Projects that are alternatives of or similar to opyoid

React Ioc
Hierarchical Dependency Injection with new React 16 Context API
Stars: ✭ 133 (+291.18%)
Mutual labels:  dependency-injection, injection
Reflex
Minimal dependency injection framework for Unity
Stars: ✭ 263 (+673.53%)
Mutual labels:  dependency-injection, injection
Tsyringe
Lightweight dependency injection container for JavaScript/TypeScript
Stars: ✭ 2,761 (+8020.59%)
Mutual labels:  dependency-injection, injection
Dikit
Dependency Injection Framework for Swift, inspired by KOIN.
Stars: ✭ 77 (+126.47%)
Mutual labels:  dependency-injection, injection
inject
A simple Kotlin multi-platform abstraction around the javax.inject annotations.
Stars: ✭ 42 (+23.53%)
Mutual labels:  dependency-injection, injection
Container Ioc
Inversion of Control container & Dependency Injection for Javascript and Node.js apps powered by Typescript.
Stars: ✭ 89 (+161.76%)
Mutual labels:  dependency-injection, injection
AnnotationInject
Compile-time Swift dependency injection annotations
Stars: ✭ 40 (+17.65%)
Mutual labels:  dependency-injection, injection
vesselize
⛵ A JavaScript IoC container that works seamlessly with Vue.js and React.
Stars: ✭ 22 (-35.29%)
Mutual labels:  dependency-injection, injection
DependencyInjector
Lightweight dependency injector
Stars: ✭ 30 (-11.76%)
Mutual labels:  dependency-injection, injection
tsdi
Dependency Injection container (IoC) for TypeScript
Stars: ✭ 50 (+47.06%)
Mutual labels:  dependency-injection, injection
Poodinis
A dependency injection framework for D with support for autowiring.
Stars: ✭ 57 (+67.65%)
Mutual labels:  dependency-injection, injection
refuel
Lightweight dependency injection engine and DI-driven tools.
Stars: ✭ 21 (-38.24%)
Mutual labels:  dependency-injection, injection
Koin
Koin - a pragmatic lightweight dependency injection framework for Kotlin
Stars: ✭ 7,142 (+20905.88%)
Mutual labels:  dependency-injection, injection
Swiftdi
SwiftDI the new way to use your dependency in Swift 5.1
Stars: ✭ 107 (+214.71%)
Mutual labels:  dependency-injection, injection
Kangaru
🦘 A dependency injection container for C++11, C++14 and later
Stars: ✭ 297 (+773.53%)
Mutual labels:  dependency-injection, injection
PopKorn
DI can be simple. Forget about modules and components. Just use it!
Stars: ✭ 139 (+308.82%)
Mutual labels:  dependency-injection, injection
Zenject-2019
Dependency Injection Framework for Unity3D
Stars: ✭ 2,567 (+7450%)
Mutual labels:  dependency-injection, injection
fusion
A simple automated dependency injection library for TypeScript, supporting React class and functional components.
Stars: ✭ 18 (-47.06%)
Mutual labels:  dependency-injection, injection
lifeline-rs
A dependency injection library for message-based applications
Stars: ✭ 32 (-5.88%)
Mutual labels:  dependency-injection
SQL Injection Payload
SQL Injection Payload List
Stars: ✭ 62 (+82.35%)
Mutual labels:  injection

Opyoid

CI codecov

Dependency injection library using typings, to easily manage large applications.

This project is inspired from Guice.

Installation

Run pip install opyoid to install from PyPI.

Run pip install . to install from sources.

This project follows the Semantic Versioning Specification. All breaking changes are described in the Changelog.

Usage

Simple Injection

from opyoid import Module, Injector


class MyClass:
    pass


class MyParentClass:
    def __init__(self, my_param: MyClass):
        self.my_param = my_param


class MyModule(Module):
    def configure(self) -> None:
        self.bind(MyClass)
        self.bind(MyParentClass)


injector = Injector([MyModule()])
my_instance = injector.inject(MyParentClass)
assert isinstance(my_instance, MyParentClass)
assert isinstance(my_instance.my_param, MyClass)

If they are multiple bindings for the same class, the latest will be used.

Module

The module is used to group bindings related to a feature. You can include a module in another with install:

from opyoid import Module, Injector


class MyClass:
    pass


class MyModule(Module):
    def configure(self) -> None:
        self.bind(MyClass)


class MyParentClass:
    def __init__(self, my_param: MyClass):
        self.my_param = my_param


class MyParentModule(Module):
    def configure(self) -> None:
        self.install(MyModule())
        self.bind(MyParentClass)


injector = Injector([MyParentModule()])
my_instance = injector.inject(MyParentClass)
assert isinstance(my_instance, MyParentClass)
assert isinstance(my_instance.my_param, MyClass)

Binding Subclasses

from opyoid import Module, Injector


class MyClass:
    pass


class MySubClass(MyClass):
    pass


class MyModule(Module):
    def configure(self) -> None:
        self.bind(MyClass, to_class=MySubClass)

injector = Injector([MyModule()])
my_instance = injector.inject(MyClass)
assert isinstance(my_instance, MySubClass)

Binding Instances

from opyoid import Module, Injector


class MyClass:
    def __init__(self, my_param: str):
        self.my_param = my_param

my_instance = MyClass("hello")


class MyModule(Module):
    def configure(self) -> None:
        self.bind(MyClass, to_instance=my_instance)


injector = Injector([MyModule()])
injected_instance = injector.inject(MyClass)
assert my_instance is injected_instance

Binding scopes

When binding a class, you can choose the scope in which it will be instantiated. This will only have an effect when binding classes, not instances.

Singleton Scope

By default, all classes are instantiated in a Singleton scope. This means that only one instance of each class will be created, and it will be shared between all classes requiring it.

from opyoid import Module, Injector, SingletonScope


class MyClass:
    pass


class MyParentClass:
    def __init__(self, my_param: MyClass):
        self.my_param = my_param


class MyModule(Module):
    def configure(self) -> None:
        self.bind(MyClass, scope=SingletonScope)
        self.bind(MyParentClass, scope=SingletonScope)

injector = Injector([MyModule()])
instance_1 = injector.inject(MyClass)
instance_2 = injector.inject(MyClass)
parent_instance = injector.inject(MyParentClass)
assert instance_1 is instance_2
assert instance_1 is parent_instance.my_param

PerLookup Scope

If you use the per lookup scope, a new instance will be created every time each class is injected.

from opyoid import Module, Injector, PerLookupScope


class MyClass:
    pass


class MyParentClass:
    def __init__(self, my_param: MyClass):
        self.my_param = my_param


class MyModule(Module):
    def configure(self) -> None:
        self.bind(MyClass, scope=PerLookupScope)
        self.bind(MyParentClass)

injector = Injector([MyModule()])
instance_1 = injector.inject(MyClass)
instance_2 = injector.inject(MyClass)
parent_instance = injector.inject(MyParentClass)
assert instance_1 is not instance_2
assert instance_1 is not parent_instance.my_param

Thread Scope

This scope only creates a new instance the first time that the class is injected in the current thread. There will only be one instance of each class in each thread, and two instances injected from different threads will be different objects.

from threading import Thread

from opyoid import Module, Injector, ThreadScope


class MyClass:
    pass


class MyModule(Module):
    def configure(self) -> None:
        self.bind(MyClass, scope=ThreadScope)

injector = Injector([MyModule()])
instance_1 = injector.inject(MyClass)
instance_2 = injector.inject(MyClass)

def thread_target():
    instance_3 = injector.inject(MyClass)
    assert instance_1 is not instance_3

Thread(target=thread_target).start()

assert instance_1 is instance_2

Bindings without Module

If you prefer, you can add bindings to your injector without creating a Module class (or using both).

from opyoid import Module, Injector, SelfBinding


class MyClass:
    pass


class MyParentClass:
    def __init__(self, my_param: MyClass):
        self.my_param = my_param


class MyModule(Module):
    def configure(self) -> None:
        self.bind(MyClass)


injector = Injector([MyModule()], [SelfBinding(MyParentClass)])
my_instance = injector.inject(MyParentClass)
assert isinstance(my_instance, MyParentClass)
assert isinstance(my_instance.my_param, MyClass)

The same options of Module.bind are available when using bindings:

from opyoid import ClassBinding, InstanceBinding, PerLookupScope, SelfBinding


class MyClass:
    pass


class MySubClass(MyClass):
    pass

my_instance = MyClass()

SelfBinding(MyClass)  # binding a class to itself
ClassBinding(MyClass, MySubClass)  # binding a class to a subclass
SelfBinding(MyClass, scope=PerLookupScope)  # specifying scope
InstanceBinding(MyClass, my_instance)  # binding an instance
SelfBinding(MyClass, named="my_name")  # binding a class to itself with a specific name
InstanceBinding(MyClass, my_instance, named="my_name")  # binding an instance with a specific name

Injecting Type

If no explicit binding is defined, the last class binding will be used to inject a type:

from typing import Type

from opyoid import Module, Injector

class MyClass:
    pass

class SubClass(MyClass):
    pass

class MyParentClass:
    def __init__(self, my_param: Type[MyClass]):
        self.my_param = my_param

my_instance = MyClass()

class MyModule(Module):
    def configure(self) -> None:
        self.bind(MyClass)
        self.bind(MyClass, to_instance=my_instance)
        self.bind(MyClass, to_class=SubClass)
        self.bind(MyParentClass)


injector = Injector([MyModule()])
parent_instance = injector.inject(MyParentClass)
assert isinstance(parent_instance, MyParentClass)
assert parent_instance.my_param is SubClass

Dataclasses

opyoid can inject classes and parameters defined with the attrs library and python data classes.

Notes about Generics

  • The supported generic types are List, Set, Tuple, Optional, Union and Type (and any combination of them). Other generics must be bound explicitly (e.g. you must bind a dict to Dict[str, MyClass] if you want to inject it).
  • Be careful when using generics, the bindings will only be used if the type matches exactly. For example, you cannot implicitly bind MyClass[T] to inject MyClass, or MyClass[str] to inject MyClass[T]. You need to bind something to MyClass[str] to be able to inject it.

Advanced usage

More advanced features and examples are available in the ./docs folder.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].