动态配置
项目描述
此软件包提供了一种配置器,它设计用于在创建Zope3组件之后对其进行扩展。
配置器
配置器设计用于在创建组件之后对其进行扩展。传统上,这是通过监听ObjectCreatedEvent事件来完成的。然而,这种方法不足以满足需求,因为配置通常依赖于其他配置步骤,并且通常需要额外的数据来完成配置。这就是配置器的用武之地。它使用一个独立的插件机制来实现所提到的功能。
在我们可以演示配置机制之前,我们必须创建一个接口和一个组件,配置可以在其上操作
>>> import zope.interface>>> class ISomething(zope.interface.Interface): ... """Some interesting interface.""">>> @zope.interface.implementer(ISomething) ... class Something(object): ... """Implementation of something.""">>> something = Something()
现在我们可以让配置对组件进行操作
>>> from z3c import configurator >>> configurator.configure(something, {})
第二个参数是数据字典,可以用来传递在配置过程中可能需要的附加信息。每个插件都负责解析这些数据。
当然,由于没有注册任何配置插件,所以没有任何操作。现在我们创建一个新的配置插件,为组件设置一个新的属性
>>> import zope.component >>> from z3c.configurator import interfaces>>> class AddFooAttribute(configurator.ConfigurationPluginBase): ... zope.component.adapts(ISomething) ... ... def __call__(self, data): ... setattr(self.context, 'foo', data.get('foo'))>>> zope.component.provideAdapter(AddFooAttribute, name='add foo')
如果我们再次执行配置,将添加该属性
>>> configurator.configure(something, {'foo': u'my value'}) >>> something.foo u'my value'
依赖关系
现在我们已经有了简单的配置插件,我们也可以开发依赖于其他插件的插件。让我们创建一个配置插件,为foo属性添加一些附加数据。显然,在执行此步骤之前,foo属性必须存在。可以使用dependencies属性通过名称指定所有插件依赖项
>>> class ExtendFooAttribute(configurator.ConfigurationPluginBase): ... zope.component.adapts(ISomething) ... dependencies = ('add foo',) ... ... def __call__(self, data): ... self.context.foo = u'Text: ' + self.context.foo>>> zope.component.provideAdapter(ExtendFooAttribute, name='extend foo')
如果我们现在再次执行配置,应该可以看到扩展的结果
>>> something = Something() >>> configurator.configure(something, {'foo': u'my value'}) >>> something.foo u'Text: my value'
数据模式
出于纯粹的信息目的,插件上使用了一个schema属性来描述插件期望从数据字典中获取的字段。为了添加另一个简单属性,这可能如下所示
>>> import zope.schema >>> class IAddBar(zope.interface.Interface): ... bar = zope.schema.Text(title=u'Bar')>>> class AddBarAttribute(configurator.SchemaConfigurationPluginBase): ... zope.component.adapts(ISomething) ... schema = IAddBar ... ... def __call__(self, data): ... self.verify(data) ... setattr(self.context, 'bar', data.get('bar'))>>> zope.component.provideAdapter(AddBarAttribute, name='add bar')
使用基类的好处是它提供了一个verify()方法,允许您验证数据是否与模式匹配。我们现在可以再次运行配置
>>> something = Something() >>> configurator.configure(something, {'foo': u'my value', 'bar': u'value'}) >>> something.bar u'value'
值必须存在且有效
>>> something = Something() >>> configurator.configure(something, {'foo': u'my value'}) Traceback (most recent call last): ... RequiredMissing: bar>>> something = Something() >>> configurator.configure(something, {'foo': u'my value', 'bar': 1}) Traceback (most recent call last): ... WrongType: (1, <type 'unicode'>, 'bar')
数据命名空间
为了避免两个共享相同名称的插件混淆属性名称,可以将数据作为字典的字典传递。字典的键是插件注册的名称
>>> something = Something() >>> data = {u'add foo': {'foo': u'foo value'}, ... u'add bar': {'bar': u'bar value'}} >>> configurator.configure(something, data, useNameSpaces=True) >>> something.foo, something.bar (u'Text: foo value', u'bar value')
命名配置
有时我们不想执行所有已注册的配置插件。可以通过向configure函数提供names参数来实现这一点
让我们创建一个新的东西
>>> something = Something()
如果我们现在不指定名称来配置它,我们将设置两个属性
>>> configurator.configure(something, {'foo': u'my value', 'bar': u'asdf'}) >>> sorted(something.__dict__.items()) [('bar', 'asdf'), ('foo', 'Text: my value')]
现在让我们只配置插件‘add bar’。
>>> something = Something() >>> configurator.configure(something, {'foo': u'my value', 'bar': u'asdf'}, ... names=['add bar']) >>> something.__dict__ {'bar': u'asdf'}
插件依赖项总是执行,不需要添加到`names`参数中。
>>> something = Something() >>> configurator.configure(something, {'foo': u'my value'}, ... names=['extend foo']) >>> something.foo u'Text: my value'
命名配置在手动通过网页调用时很有用(参见browser/README.txt)。当调用两次时,配置器包不会检查配置是否已经应用。这是插件的责任,要意识到它不会重复执行或删除操作。
错误的实现
配置器必须提供一个__call__方法。
>>> class CallNotImplemented(configurator.ConfigurationPluginBase): ... zope.component.adapts(ISomething) >>> zope.component.provideAdapter(CallNotImplemented, name='no call')>>> configurator.configure(something, None, names=['no call']) Traceback (most recent call last): ... NotImplementedError
对于基于模式的配置器也必须如此。
>>> class SchemaCallNotImplemented(configurator.SchemaConfigurationPluginBase): ... zope.component.adapts(ISomething) >>> zope.component.provideAdapter(SchemaCallNotImplemented, name='schema no call')>>> configurator.configure(something, None, names=['schema no call']) Traceback (most recent call last): ... NotImplementedError
无递归
可以定义递归依赖项而不会遇到递归错误。让我们定义一个新的插件free对象
>>> class IFoo(zope.interface.Interface): ... """Just a foo interface.""">>> @zope.interface.implementer(IFoo) ... class Foo(object): ... """Implementation of foo."""
让我们定义另一个名为的插件,它依赖于名为的插件。
>>> log = [] >>> class FirstPlugin(configurator.ConfigurationPluginBase): ... zope.component.adapts(IFoo) ... dependencies = ('second',) ... ... def __call__(self, data): ... log.append('FirstPlugin called')>>> zope.component.provideAdapter(FirstPlugin, name='first')
然后定义一个名为的插件,它依赖于
>>> class SecondPlugin(configurator.ConfigurationPluginBase): ... zope.component.adapts(IFoo) ... dependencies = ('first',) ... ... def __call__(self, data): ... log.append('SecondPlugin called')>>> zope.component.provideAdapter(SecondPlugin, name='second')>>> foo = Foo() >>> configurator.configure(foo, {}) >>> for msg in sorted(log): print(msg) FirstPlugin called SecondPlugin called
在TTW中调用配置器
注册了一个配置视图,以在任意对象上应用命名配置。我们定义了两个示例配置器,现在我们将它们应用到site对象上。
>>> from zope.testbrowser.wsgi import Browser >>> browser = Browser(wsgi_app=layer.make_wsgi_app()) >>> browser.addHeader('Authorization','Basic mgr:mgrpw') >>> browser.handleErrors = False>>> browser.open('https://127.0.0.1/manage') >>> browser.url 'https://127.0.0.1/@@contents.html'
视图注册在zmi_views菜单中
>>> browser.getLink(u'Configurators').click() >>> viewURL = browser.url >>> viewURL 'https://127.0.0.1/@@configurators.html'>>> sel = browser.getControl(name="form.pluginNames.to")
首先,我们可以从注册的命名插件中选择。
>>> plugs = browser.getControl(name="form.pluginNames.from").options >>> sorted(plugs) ['z3c.configurator.testing.setdescription', 'z3c.configurator.testing.settitle'] >>> browser.open(viewURL + '?form.pluginNames=z3c.configurator.testing.settitle')
我们选择了一个插件,所以现在我们有一个表单来填写所需的参数。
>>> browser.getControl('Some Argument').value '' >>> browser.getControl('Some Argument').value = "New Title" >>> browser.getControl('Apply').click()
XXX form.pluginNames必须设置,但我们不能,因为小部件使用了javascript。
变更记录
3.0 (2023-02-17)
停止支持Python 2.6、2.7、3.3。
添加对Python 3.7、3.8、3.9、3.10、3.11的支持。
停止使用python setup.py test运行测试。
2.0.0 (2015-11-09)
标准化namespace __init__
2.0.0a1 (2013-03-04)
添加了对Python 3.3的支持,删除了对Python 2.4和2.5的支持。
1.3.0 (2010-12-12)
更新测试设置以使用ZTK 1.0。
版本 1.2.1 (2009-12-27)
将浏览器依赖项移动到‘zmi’额外插件
版本 1.2.0 (2009-12-19)
使浏览器视图的注册有条件
将测试所需的包移动到‘test’额外插件
删除旧的zpkg-related SETUP.cfg文件。
版权“Zope Foundation and Contributors”
版本 1.1.2 (2009-01-04)
在configure中添加了仅应用特定命名插件的可能性。
配置的新选项允许使用命名空间数据来解决命名冲突。
添加了一个页面以调用TTW配置器。这是将z3c.configurator和z3c.sampledata合并为一个包的第一步。
在Pypi主页上添加了文档。
错误修复:在IConfigurationPlugin依赖项中定义递归依赖名称,会导致递归插件查找。
错误修复:SchemaConfigurationPluginBase现在实现了ISchemaConfigurationPluginBase。
版本 1.1.1 (未知)
初始版本
项目详情
下载文件
下载适用于您的平台的文件。如果您不确定选择哪个,请了解更多关于安装包的信息。
源分布
构建分布
z3c.configurator-3.0.tar.gz的哈希
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 39034e92b6af6d21df14ffc3a520f19428d339b6517e8f0daf23d6291040c697 |
|
MD5 | e18794788518b68f041ebf0fb2e2e3a0 |
|
BLAKE2b-256 | 1a365410cd614ef04b5c4e63d1cdbe068c9d7ebd8d11d20bcd05e91493c22690 |
z3c.configurator-3.0-py3-none-any.whl的哈希
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 51863ec634e5d2a70afb132eb685fd60d8df5b314bb31089735ea32eb9fa64c4 |
|
MD5 | 02f16ef21b3d4cd340948dd56fa23456 |
|
BLAKE2b-256 | 2c2fd94205c25053a30687880efcb0375b06cf73255b1970d100dd49f6e5a203 |