最小和惯用依赖注入库

siringa的Python项目详细描述


siringa logo

Build StatusPyPICoverage StatusDocumentation StatusStabilityPython VersionsSay Thanks

关于

siringa(意为意大利语中的syringe)是一个极简的、惯用的dependency injectioninversion of control库。 对于Python,用Hy实现,这是python的一种同形lisp方言。

要开始,请查看documentationAPItutorialexamples

功能

  • 简单,惯用,多才多艺。
  • 基于注释的依赖注入,对PEP 3017PEP 0484友好。
  • 第一类decorator驱动的依赖注入和注册。
  • 能够创建多个依赖关系容器。
  • 基于继承的层次依赖关系容器。
  • 基于模式匹配技术的依赖推理。
  • 一级支持依赖性模拟以实现更好的测试。
  • 检测循环依赖项(正在工作)。
  • 小型(几乎)无依赖关系库。
  • 与cpython 3+一起使用。

设计理念

  • 代码插装应该是非侵入性的和惯用的。
  • 隐式之上的显式性:依赖和注入都是显式定义的。
  • 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进行惯用依赖项注册。

依赖项名称在注册时根据classfunction名称动态推断。

@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)

  • 第一个版本(测试版)。

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
带有嵌套JAR的java RCP ClassNotFoundException   java在输入框中设置默认值,crud应用程序使用spring   java如何在Heroku中使用fs创建新文件   java将JPanel放在JFrame中   java这个正则表达式会匹配“i.imgur.com/xxx”吗?   java在片段内创建RecylerView,而无需在Android中设置片段   Android上Groovy导致java错误的双精度浮点精度损失   swing Java查找JFrame属于JPanel的内容   java Spring junit自连线自定义类本身必须有构造函数吗?   java textswitcher支持前面的文本   从Android客户端到JAXRS的java Post自定义对象   java如何检索JSON数据并使用MPAndroidChart绘制折线图,以及在安卓上的改进   拒绝用户“root”@“localhost”的java c3p0访问(使用密码“是”)   使用Selenium Webdriver自动化ExtJS应用程序时java面临的问题