jeni注入标注依赖项
项目描述
jeni 允许开发者构建应用程序,例如不是Web应用程序。
概述
配置项目中每个依赖项(requirements.txt、config等)。
使用自然调用签名编写代码,并将这些依赖项作为输入。
为每个依赖项实现一个 Provider,并将其注册到 Injector 中。
jeni在Python 2.7、Python 3.2至3.4以及pypy上运行。
动机
编写代码就像它应该被编写的那样,而无需将函数调用签名固定到只适用于特定运行时的某个单一对象。这不仅仅是关于测试。这是关于组合。
jeni的设计原则是使所有标注的可调用项在不知道jeni的上下文中也可用。任何可调用项对新的Python REPL的相关性就像对注入器一样。
标注
标注在Python 2中作为装饰器实现。在Python 3中,可以使用装饰器或函数标注进行注入。
核心API
annotate
使用装饰器标注可调用项以提供数据供注入器使用。
预期用途
from jeni import annotate @annotate('foo', 'bar') def function(foo, bar): return
然后注入器需要注册“foo”和“bar”的提供者,以便应用此函数;具有此类提供者的注入器可以在没有更多信息的情况下应用标注的函数
injector.apply(function)
以获取部分应用函数,稍后调用
fn = injector.partial(function) fn()
标注不会改变可调用项的默认行为。正常调用它
foo, bar = 'foo', 'bar' function(foo, bar)
在Python 2中,使用装饰器进行标注。在Python 3中,可以使用装饰器或函数标注
from jeni import annotate @annotate def function(foo: 'foo', bar: 'bar'): return
注意,在Python函数注解中使用时,所有注入的值都作为关键字参数提供。
由于不同的包可能会以不同的方式解释函数注解,注入器不会直接使用function.__annotations__。函数通过简单的@annotate装饰来选择加入。没有装饰注解的Python注解函数假定未进行装饰以进行注入。
(因此,不支持在单个注解中标记一个可调用的对象,其中注解本身是可调用的。)
提供给annotate(在‘foo’和‘bar’上方)的注解可以是任何可哈希的对象(即可以作为字典键的对象),而不限于字符串。如果使用元组作为注解,则长度必须为2,并且(‘maybe’,…)和(‘partial’,…)是保留的。
提供者
提供单个准备好的依赖项。
提供者.get(self, name=None)
在子类中实现。
形式为'object:name'的注解将通过name值传递给已注册的Provider的get方法(在这种情况下,注册给Injector以提供object的提供者)。这种按名称获取模式对于具有支持通过键查找的依赖项的提供者很有用(例如HTTP头或键值存储中的记录)。
提供者.close(self)
默认情况下,不执行任何操作。在子类中按需关闭对象。
提供者关闭方法不应故意引发错误。具体来说,如果依赖项具有事务,则在调用close之前应提交或回滚事务,而不是将其留为在关闭阶段调用的操作。
提供者关闭方法不得接受任何参数;注入器无法在关闭方法上应用提供的值,因为某些提供者可能已经关闭。如果关闭方法需要注入值,请注解__init__并通过self访问该值。
注入器
收集依赖项并读取注解以进行注入。
注入器.__init__(self, provide_self=False)
子类可以接受参数,但应将关键字传递给super。
注入器子类继承其基类的提供者注册表,但可以通过重新注册注解覆盖任何提供者。在组织项目时,创建一个注入器子类作为注册所有提供者的对象。这允许项目拥有自己的注册依赖项命名空间。此注册表可以通过进一步的自定义子类进行自定义,例如在测试中注入模拟或在不同的运行时提供替代依赖项。
from jeni import Injector as BaseInjector class Injector(BaseInjector): "Subclass provides namespace when registering providers."
默认情况下,注入器不提供自身,但在请求时将提供。
injector = Injector(provide_self=True) injector.get('injector')
这在上下文管理器中很有用。
with Injector(provide_self=True) as injector: injector.get('injector')
使用注解‘injector’注解以注入注入器。
注入器.sub(cls, *mixins_and_dicts, **values)
创建并实例化一个子注入器。
可以作为参数传递混入和本地值字典。局部值也可以作为关键字参数传递。
注入器.provider(cls, note, provider=None, name=False)
注册一个提供者,可以是提供者类或生成器。
提供者类
from jeni import Injector as BaseInjector from jeni import Provider class Injector(BaseInjector): pass @Injector.provider('hello') class HelloProvider(Provider): def get(self, name=None): if name is None: name = 'world' return 'Hello, {}!'.format(name)
简单的生成器
@Injector.provider('answer') def answer(): yield 42
如果生成器支持带有名称参数的get
@Injector.provider('spam', name=True) def spam(): count_str = yield 'spam' while True: count_str = yield 'spam' * int(count_str)
注册可以是装饰器或直接方法调用
Injector.provider('hello', HelloProvider)
注入器.factory(cls, note, fn=None)
将函数注册为提供者。
函数(可选支持名称)
from jeni import Injector as BaseInjector from jeni import Provider class Injector(BaseInjector): pass @Injector.factory('echo') def echo(name=None): return name
注册可以是装饰器或直接方法调用
Injector.factory('echo', echo)
注入器.value(cls, note, scalar)
注册要提供的单个值。
支持基本注解,不支持按名称获取注解。
注入器.apply(self, fn, *a, **kw)
完全应用注解的可调用对象,返回可调用对象的结果。
注入器.partial(self, fn, *user_args, **user_kwargs)
返回带有闭包的函数,以延迟注入注解的可调用对象。
对结果函数的重复调用将重用第一次调用的注入。
位置参数按照此顺序提供
注入器提供的位置参数
在 partial_fn = partial(fn, *args) 中提供的位置参数
在 partial_fn(*args) 中提供的位置参数
关键字参数按照此顺序解析(后一个覆盖前一个)
注入器提供的关键字参数
在 partial_fn = partial(fn, **kwargs) 中提供的关键字参数
在 partial_fn(**kwargs) 中提供的关键字参数
请注意,Python 函数注释(在 Python 3 中)作为关键字参数注入,如 annotate 中所述,这会影响此处参数的顺序。
annotate.partial 接受的参数与这个 partial 相同。
Injector.eager_partial(self, fn, *a, **kw)
部分应用注释可调用,返回一个部分函数。
默认情况下,partial 是懒加载的,因此注入仅在需要时发生。当在创建部分应用函数时需要注入的保证时,请使用 eager_partial 代替 partial。
eager_partial 解析参数的方式类似于 partial,但在调用最终部分函数时依赖于 functools.partial 进行参数解析。
Injector.apply_regardless(self, fn, *a, **kw)
与 apply 类似,但如果可调用未注释,则应用。
Injector.partial_regardless(self, fn, *a, **kw)
与 partial 类似,但如果可调用未注释,则应用。
Injector.eager_partial_regardless(self, fn, *a, **kw)
与 eager_partial 类似,但如果可调用未注释,则应用。
Injector.get(self, note)
将单个注释解析为对象。
Injector.close(self)
关闭注入器及注入的 Provider 实例,包括生成器。
Provider 按照它们打开的相反顺序关闭,并且每个 Provider 只关闭一次。如果 Provider 被注入器访问,即使依赖项未成功提供,也会关闭 Provider。因此,Provider 应该确定是否需要在关闭方法中执行任何操作。
Injector.enter(self)
在不使用 with 块的情况下进入上下文管理器。另请参阅:exit。
对于无法使用 with 块的 before-and-after 钩子很有用。
Injector.exit(self)
在不使用 with 块的情况下退出上下文管理器。另请参阅:enter。
其他 API
annotate.wraps
类似于 functools.wraps,支持注释。
annotate.maybe
包装一个关键字注释以记录其解析是可选的。
通常所有注释都需要满足依赖项,但如果关键字参数被注释为 maybe,则在应用时,注入器不会尝试传递未设置或未提供的依赖项
from jeni import annotate @annotate('foo', bar=annotate.maybe('bar')) def foobar(foo, bar=None): return
annotate.partial
包装一个用于注入部分应用函数的注释。
这允许对注释函数进行注入以进行组合
from jeni import annotate @annotate('foo', bar=annotate.maybe('bar')) def foobar(foo, bar=None): return @annotate('foo', annotate.partial(foobar)) def bazquux(foo, fn): # fn: injector.partial(foobar) return
当使用部分应用时,关键字参数被视为 maybe,以便只允许提供注释的局部应用,调用者可以应用注入器中已知不可用的参数。请注意,与 Python 3 函数注释一样,所有注释都作为关键字参数注入。
对部分函数的注入是懒加载的,直到注入的部分函数被调用才应用。有关 eager 注入,请参阅 eager_partial。
annotate.eager_partial
包装一个用于注入急切部分应用函数的注释。
当需要急切注入而不是懒加载注入时,请使用此代替 partial。
InjectorProxy
将 getattr & getitem 转发到封装的注入器。
如果注入器已注册 'hello'
from jeni import InjectorProxy deps = InjectorProxy(injector) deps.hello
可以通过字典样式访问获取
deps['hello:name']
许可
版权所有 2013-2015 Ron DuPlain <ron.duplain@gmail.com>(见 AUTHORS 文件)。
在BSD许可证下发布(见LICENSE文件)。
项目详情
下载文件
下载适用于您平台的文件。如果您不确定选择哪个,请了解有关安装包的更多信息。
源分发
jeni-0.4.1.zip的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | c9bca43db82a9642233d72c69c77ba96b4f0f7f56e5c95bed45f047bad357504 |
|
MD5 | 26792a1e059bb0f4cb885076e5b8412b |
|
BLAKE2b-256 | 7a41c8355db682c0a2bb107ec45fee84acd65b2a08f5ad1ac8700cceb2c12871 |
jeni-0.4.1.tar.bz2的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | f9e4fe4fba0c660c46ee6b4e471d5c07f8a91e207f9ce21b869a97b96dc7c6bd |
|
MD5 | 6d05da5eb687fbb7a310249a4167cc4a |
|
BLAKE2b-256 | 1f359c16cc93a946e8cd4a4dcd661e92f70eb6bbf71cb6b4faecff00aa0818ab |