All Projects → h2non → siringa

h2non / siringa

Licence: MIT License
Minimalist dependency injection library for Python that embraces type annotations syntax

Programming Languages

Hy
24 projects
python
139335 projects - #7 most used programming language
Makefile
30231 projects

Projects that are alternatives of or similar to siringa

nodejs-boilerplate
Clean Architecture for node.js projects (Typescript + Express + TypeORM + Typedi)
Stars: ✭ 199 (+290.2%)
Mutual labels:  dependency-injection, inversion-of-control, injection-container, dependency-injection-container
Container Ioc
Inversion of Control container & Dependency Injection for Javascript and Node.js apps powered by Typescript.
Stars: ✭ 89 (+74.51%)
Mutual labels:  dependency-injection, inversion-of-control, dependency
Zenject-2019
Dependency Injection Framework for Unity3D
Stars: ✭ 2,567 (+4933.33%)
Mutual labels:  dependency-injection, dependency, injection-container
stashbox
A lightweight, fast, and portable dependency injection framework for .NET-based solutions.
Stars: ✭ 120 (+135.29%)
Mutual labels:  dependency-injection, inversion-of-control, dependency-injection-container
di
Simple and yet powerful Dependency Injection for Go
Stars: ✭ 188 (+268.63%)
Mutual labels:  dependency-injection, inversion-of-control
DependencyInjector
Lightweight dependency injector
Stars: ✭ 30 (-41.18%)
Mutual labels:  dependency-injection, dependency
potto
A minimum cross-platform implementation of COM (Component Object Model), DI/IOC framework
Stars: ✭ 13 (-74.51%)
Mutual labels:  inversion-of-control, dependency-injection-container
Griffin.Container
Inversion of control container with (almost) zero configuration
Stars: ✭ 13 (-74.51%)
Mutual labels:  dependency-injection, inversion-of-control
mindjs
Minimalistic, pure Node.js framework superpowered with Dependency Injection 💡 💻 🚀
Stars: ✭ 17 (-66.67%)
Mutual labels:  dependency-injection, inversion-of-control
vue-ioc
IoC and DI for Vue powered by InversifyJS and inspired by Angular Module syntactic sugar.
Stars: ✭ 39 (-23.53%)
Mutual labels:  dependency-injection, inversion-of-control
di.libx.js
💉 di.libx.js - Lightweight & non intrusive Dependency Injection module that supports async/deferred resolution and uglified support
Stars: ✭ 32 (-37.25%)
Mutual labels:  dependency-injection, inversion-of-control
Mimick.Fody
An integrated framework for dependency injection and aspect-oriented processing.
Stars: ✭ 15 (-70.59%)
Mutual labels:  dependency-injection, dependency
CNeptune
CNeptune improve productivity & efficiency by urbanize .net module with meta-code to lay foundation for frameworks
Stars: ✭ 30 (-41.18%)
Mutual labels:  inversion-of-control, dependency
inversify-koa-utils
inversify-koa-utils is a module based on inversify-express-utils. This module has utilities for koa 2 applications development using decorators and IoC Dependency Injection (with inversify)
Stars: ✭ 27 (-47.06%)
Mutual labels:  dependency-injection, inversion-of-control
noicejs
extremely thin async dependency injection
Stars: ✭ 16 (-68.63%)
Mutual labels:  dependency-injection, dependency-injection-container
ThunderboltIoc
One of the very first IoC frameworks for .Net that has no reflection. An IoC that casts its services before thunder casts its bolts.
Stars: ✭ 40 (-21.57%)
Mutual labels:  dependency-injection, inversion-of-control
telephone-ts
Telephone-ts: The "Event Emitter-less" TypeScript Event Architecture.
Stars: ✭ 22 (-56.86%)
Mutual labels:  dependency-injection, inversion-of-control
wp-app-container
DI Container and related tools to be used at website level.
Stars: ✭ 27 (-47.06%)
Mutual labels:  dependency-injection, dependency-injection-container
avaje-inject
Dependency injection via APT (source code generation) ala "Server side Dagger DI"
Stars: ✭ 114 (+123.53%)
Mutual labels:  dependency-injection, inversion-of-control
ufw
A minimalist framework for rapid server side applications prototyping in C++ with dependency injection support.
Stars: ✭ 19 (-62.75%)
Mutual labels:  dependency-injection, inversion-of-control

siringa logo

Build Status PyPI Coverage Status Documentation Status Stability Python Versions Say Thanks

About

siringa (meaning syringe in Italian) is a minimalist, idiomatic dependency injection/inversion of control library for Python, implemented in Hy, a Lisp dialect for Python.

To get started, take a look to the documentation, API, tutorial and examples.

Features

  • Simple, idiomatic and versatile programmatic API.
  • Annotation based dependency injection that is PEP 3017 and PEP 0484 friendly.
  • First-class decorator driven dependency injection and registering.
  • Ability to create multiple dependency containers.
  • Hierarchical dependency containers based on inheritance.
  • Dependency inference based on pattern-matching techniques.
  • First-class support for dependency mocking for better testing.
  • Highly tolerant: any type of object can be injected, including str, generators, coroutines ...
  • Detects cyclic dependencies (work in progress).
  • Small and (almost) dependency-free library.
  • Works with CPython 3+ (because of Hy <> CPython AST compatibility)

Design philosophy

  • Code instrumentation should be non-intrusive and idiomatic.
  • Explicitness over implicitness: dependencies and injections much be explicitly defined.
  • Python idiomatic: embrace decorators and type annotations.
  • Minimalism: less enables more.
  • Uniformity: there is only one way to declare and consume dependencies.
  • Predictability: developer intentions must persist based on explicitly defined intention.
  • Domain agnostic: do not enforce any domain-specific pattern.

Installation

Using pip package manager:

pip install --upgrade siringa

Or install the latest sources from Github:

pip install -e git+git://github.com/h2non/siringa.git#egg=siringa

Tutorial

Importing siringa

import siringa

Instrumenting dependencies

siringa embraces type hints/arguments annotation Python syntax for dependency inference and pattern matching.

@siringa.inject
def task(x, y, logger: '!Logger'):
    logger.info('task called with arguments: {}, {}'.format(x, y))
    return x * y

You can optionally annotate dependencies via siringa type annotations:

from siringa import A

@siringa.inject
def task(x, y, logger: A('Logger')):
    logger.info('task called with arguments: {}, {}'.format(x, y))
    return x * y

Finally, for a DRYer approach you can simply annotate dependencies with ! annotation flag.

In this case, the argument name expression will be used for dependency inference.

from siringa import A

@siringa.inject
def task(x, y, Logger: '!'):
    Logger.info('task called with arguments: {}, {}'.format(x, y))
    return x * y

Registering dependencies

siringa allows you to rely on decorators for idiomatic dependencies registering.

Dependency name is dynamically inferred at registration time based on class or function name.

@siringa.register
class Logger(object):
    logger = logging.getLogger('siringa')

    @staticmethod
    def info(msg, *args, **kw):
        logger.info(msg, *args, **kw)

However, you can define a custom dependency name by simply passing a string as first argument:

@siringa.register('MyCustomLogger')
class Logger(object):
    ...

Finally, you can register dependencies with a traditional function call, such as:

class Logger(object):
    pass

siringa.register('MyCustomLogger', Logger)

class compute(x, y):
    return x * y

siringa.register('multiply', compute)

Invocation

siringa wraps callable object in the transparent and frictionless way abstracting things for developers.

You can invoke or instantiate any dependency injection instrumented object as you do traditionally in raw Python code and siringa will do the rest inferring and pattern-matching required dependencies accordingly for you.

Below is an example of how simple it is:

# Call our previously declared function in this tutorial.
# Here, siringa will transparently inject required dependencies accordingly,
# respecting the invokation arguments and order.
task(2, 2) # => 4

Let's demostrate this with a featured example:

import siringa

@siringa.register
def mul(x, y):
    return x * y

@siringa.register
def mul2(x, mul: '!mul'):
    return mul(x, 2)

@siringa.register
def pow2(x):
    return x ** 2

@siringa.inject
def compute(x, pow: '!pow2', mul: '!mul2'):
    return pow(mul(x))

compute(2) # => 16

You can also use the invocation API in case that the target object was not properly instrumented as dependency:

@siringa.register
def mul2(x):
    return x * 2

# Note that the function was not instrumented yet!
def compute(x, mul: '!mul2'):
    return mul(x)

siringa.invoke(compute, 2)

Create a new dependency container

siringa provides a built-in global dependency container for usability purposes, but you can create as much containers as you want.

In the siringa idioms, this means creating a new dependency layer which provides its own container and dependency injection API, pretty much as the global package API.

You can create a new dependencies layer such as:

layer = siringa.Layer('app')

# Then you can use the standard API
layer.register('print', print)

# Then you can use the standard API
@layer.inject
def mul2(x, print: '!'):
    print('Argument:', x)
    return x * 2

mul2(x)

A dependency layer can inherit from a parent dependency layer.

This is particularly useful in order to create a hierarchy of dependency layers where you can consume and inject dependencies from a parent container.

parent = siringa.Layer('parent')
child = siringa.Layer('child', parent)

# Register a sample dependency within parent
@parent.register
def mul2(x):
    return x * 2

# Verify that the dependency is injectable from child layer
parent.is_injectable('mul2') # True
child.is_injectable('mul2') # True

@child.inject
def compute(x, mul: '!mul2'):
    return mul(x)

compute(2) # => 2

Mocking dependencies

siringa allows you to define mocks for dependencies, which is particularly useful during testing:

@siringa.register
class DB(object):
    def query(self, sql):
        return ['john', 'mike']

@siringa.mock('DB')
class DBMock(object):
    def query(self, sql):
        return ['foo', 'bar']

@siringa.inject
def run(sql, db: '!DB'):
    return db().query(sql)

# Test mock call
assert run('SELECT name FROM foo') == ['foo', 'bar']

# Once done, clear all the mocks
siringa.unregister_mock('DB')

# Or alternatively clear all the registed mocks within the container
siringa.clear_mocks()

# Test read call
assert run('SELECT name FROM foo') == ['john', 'mike']
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].