最小和惯用依赖注入库
siringa的Python项目详细描述
关于
siringa(意为意大利语中的syringe)是一个极简的、惯用的dependency injection和inversion of control库。 对于Python,用Hy实现,这是python的一种同形lisp方言。
要开始,请查看documentation、API、tutorial和examples。
功能
设计理念
- 代码插装应该是非侵入性的和惯用的。
- 隐式之上的显式性:依赖和注入都是显式定义的。
- python习惯用法:包含decorators和类型注释。
- 极简主义:少使多。
- 一致性:只有一种方法可以声明和使用依赖项。
- 可预测性:开发人员的意图必须基于明确定义的意图而持久。
- 域不可知:不要强制任何特定于域的模式。
安装
使用pippackage manager:
pip install --upgrade siringa
或者从github安装最新的源代码:
pip install -e git+git://github.com/h2non/siringa.git#egg=siringa
教程
导入siringa
importsiringa
检测依赖项
siringa包含类型提示/参数注释python语法 依赖推理和模式匹配。
@siringa.injectdeftask(x,y,logger:'!Logger'):logger.info('task called with arguments: {}, {}'.format(x,y))returnx*y
您可以选择通过siringa类型注释来注释依赖项:
fromsiringaimportA@siringa.injectdeftask(x,y,logger:A('Logger')):logger.info('task called with arguments: {}, {}'.format(x,y))returnx*y
最后,对于dryer方法,您可以使用!annotation标志简单地注释依赖项。
在这种情况下,参数名表达式将用于依赖关系推理。
fromsiringaimportA@siringa.injectdeftask(x,y,Logger:'!'):Logger.info('task called with arguments: {}, {}'.format(x,y))returnx*y
注册依赖项
siringa允许您依赖decorators进行惯用依赖项注册。
依赖项名称在注册时根据class或function名称动态推断。
@siringa.registerclassLogger(object):logger=logging.getLogger('siringa')@staticmethoddefinfo(msg,*args,**kw):logger.info(msg,*args,**kw)
但是,您可以通过简单地将string作为第一个参数来定义自定义依赖项名称:
@siringa.register('MyCustomLogger')classLogger(object):...
最后,您可以使用传统函数调用注册依赖项,例如:
classLogger(object):passsiringa.register('MyCustomLogger',Logger)classcompute(x,y):returnx*ysiringa.register('multiply',compute)
调用
siringa以透明和无摩擦的方式包装可调用对象,为开发人员抽象对象。
您可以调用或实例化任何依赖注入检测对象 正如您在原始python代码中所做的那样,siringa将为您进行推理和模式匹配 相应地需要依赖项。
下面是一个简单的例子:
# 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
让我们用一个特别的例子来演示这个:
importsiringa@siringa.registerdefmul(x,y):returnx*y@siringa.registerdefmul2(x,mul:'!mul'):returnmul(x,2)@siringa.registerdefpow2(x):returnx**2@siringa.injectdefcompute(x,pow:'!pow2',mul:'!mul2'):returnpow(mul(x))compute(2)# => 16
如果目标对象 未正确检测为依赖项:
@siringa.registerdefmul2(x):returnx*2# Note that the function was not instrumented yet!defcompute(x,mul:'!mul2'):returnmul(x)siringa.invoke(compute,2)
创建新的依赖项容器
siringa为可用性提供了内置的全局依赖项容器, 但是你可以创建任意多的容器。
在siringa习惯用法中,这意味着创建一个新的依赖层,它提供 拥有容器和依赖注入api,几乎和全局包api一样。
您可以创建新的依赖项layer,例如:
layer=siringa.Layer('app')# Then you can use the standard APIlayer.register('print',print)# Then you can use the standard API@layer.injectdefmul2(x,print:'!'):print('Argument:',x)returnx*2mul2(x)
依赖层可以从父依赖层继承。
这在o中特别有用创建依赖层的层次结构 从父容器中使用和注入依赖项的位置。
parent=siringa.Layer('parent')child=siringa.Layer('child',parent)# Register a sample dependency within parent@parent.registerdefmul2(x):returnx*2# Verify that the dependency is injectable from child layerparent.is_injectable('mul2')# Truechild.is_injectable('mul2')# True@child.injectdefcompute(x,mul:'!mul2'):returnmul(x)compute(2)# => 2
模拟依赖项
siringa允许您为依赖项定义mock,这在测试期间特别有用:
@siringa.registerclassDB(object):defquery(self,sql):return['john','mike']@siringa.mock('DB')classDBMock(object):defquery(self,sql):return['foo','bar']@siringa.injectdefrun(sql,db:'!DB'):returndb().query(sql)# Test mock callassertrun('SELECT name FROM foo')==['foo','bar']# Once done, clear all the mockssiringa.unregister_mock('DB')# Or alternatively clear all the registed mocks within the containersiringa.clear_mocks()# Test read callassertrun('SELECT name FROM foo')==['john','mike']
历史记录
V0.1.3/2017-04-25
- fix(invoke): missing export symbol at public level
- refactor(docs): update disclaimer note
- fix(docs): remove unused tutorial.rst file
- refactor(Makefile): use –commit when bumping version
V0.1.2/2017-04-25
- feat(examples): add inject flag example
- fix(injector): process inject flag “!” based annotations accordingly
- fix(register): return decorated injectable callable object, if needed
- fix(register): return decorated injectable callable object, if needed
- refactor(analyzer): use method access notation
- refactor(docs): typo in design philosophy section
- fix(docs): typo in rst syntax
- fix(examples): type on mocking example comment
V0.1.1/2017-04-24
- fix(core): handle not present __init__ member in classes. feat(examples): add mocking example
- fix(docs): type in about section
- fix(setup.py): package description
V0.1.0(2017-04-23)
- 第一个版本(测试版)。