跳转到主要内容

为基本组件(适配器、工具、订阅者)提供类似Grok的配置

项目描述

此包提供了Zope组件架构的基本组件类型的基类,以及直接在Python中(不使用ZCML)配置和注册它们的手段。

如何设置grokcore.component

以下我们假设你正在编写或扩展一个使用ZCML进行引导配置的应用程序。应用程序启动时,总是有一个ZCML文件被执行,然后包含所有其他内容。让我们假设这个文件叫做site.zcml(这就是Zope中的叫法),因此我们将编辑这个文件。

为了注册使用grokcore.component中可用的基类和指令编写的组件,我们将使用<grok:grok /> ZCML指令。但在我们能够使用它之前,我们需要确保它对ZCML机制是可用的。我们通过包含grokcore.component的元配置来完成此操作。

<include package="grokcore.component" file="meta.zcml" />

将此行放置在site.zcml文件顶部,靠近其他元配置包含项。现在,在下一行,我们可以告诉grokcore.component中的机制注册你的包中的所有组件(假设它叫做helloworld

<grok:grok package="helloworld" />

总结一下,你的site.zcml文件应该看起来像这样

<configure
    xmlns="http://namespaces.zope.org/zope"
    xmlns:grok="http://namespaces.zope.org/grok">

  <!-- do the meta configuration to make the ZCML directives available -->
  <include package="zope.foobar" file="meta.zcml" />
  <include package="zope.frobnaz" file="meta.zcml" />
  <include package="grokcore.component" file="meta.zcml" />

  <!-- now load the configuration of packages that we depend on -->
  <include package="zope.barfoo" />
  <include package="zope.somethingorother" />

  <!-- finally load my components which are based on grokcore.component -->
  <grok:grok package="helloworld" />

</configure>

grok指令中有一个可选的exclude。它允许指定在遇到时不会被解析的包或模块的名称。这些名称可能包含Unix shell风格的通配符。

implementer()implements()

注意Python 3兼容性如何改变了grokcore.component.implements() 指令的工作方式。当你使用此指令时,你现在必须确保组件被解析,以便底层机制生效。

或者你可以开始使用grokcore.component.implementer() 类装饰器。这将做同样的事情,但不需要你的组件被解析,并且仍然允许你的组件声明它实现了给定的接口。

示例

适配器

这是一个简单的适配器,在Zope中可能很有用。它从请求中提取用户首选的语言

import grokcore.component
from zope.publisher.interfaces.browser import IBrowserRequest
from zope.i18n.interfaces import IUserPreferredLanguages

class CookieLanguage(grokcore.component.Adapter):
    """Extract the preferred language from a cookie"""
    grokcore.component.context(IBrowserRequest)
    grokcore.component.implements(IUserPreferredLanguages)

    # No need to implement __init__, it's already provided by the base class.

    def getPreferredLanguages(self):
        # This an adapter for the request, so self.context is the request.
        request = self.context

        # Extract the preferred language from a cookie:
        lang = request.cookies.get('language', 'en')

        # According to IUserPreferredLanguages, we must return a list.
        return [lang]

多适配器

这是一个多适配器,作为zope.contentprovider库中已知的内容提供者。内容提供者是返回HTML片段的组件。它们是多适配器,用于内容对象(模型)、请求以及它们应该成为其一部分的视图

import grokcore.component
from zope.publisher.interfaces.browser import IBrowserRequest
from zope.publisher.interfaces.browser import IBrowserPage
from zope.contentprovider.interfaces import IContentProvider

class HelloWorldProvider(grokcore.component.MultiAdapter):
    """Display Hello World!"""
    grokcore.component.adapts(Interface, IBrowserRequest, IBrowserPage)
    grokcore.component.implements(IContentProvider)

    def __init__(self, context, request, view):
        pass

    def update(self):
        pass

    def render(self):
        return u'<p>Hello World!</p>'

全局工具

这是一个简单的命名工具,再次来自Zope世界。它是一个翻译域。换句话说,它包含用户消息的翻译,并在i18n机制需要翻译某些内容时被调用

import grokcore.component
from zope.i18n.interfaces import ITranslationDomain

class HelloWorldTranslationDomain(grokcore.component.GlobalUtility):
    grokcore.component.implements(ITranslationDomain)
    grokcore.component.name('helloworld')

    domain = u'helloworld'

    def translate(self, msgid, mapping=None, context=None,
                  target_language=None, default=None):
        if target_language is None:
            preferred = IUserPreferredLanguages(context)
            target_language = preferred.getPreferredLanguages()[0]

        translations = {'de': u'Hallo Welt',
                        'nl': u'Hallo Wereld'}
        return translations.get(target_language, u'Hello World')

当然,如果你已经有了在zope.i18n(从GNU gettext消息目录中读取翻译的实例以及用于测试的简单实现)中可用的实现,自己实现自己的翻译域工具是愚蠢的。让我们尝试重用该实现并注册一个实例

import grokcore.component
from zope.i18n.interfaces import ITranslationDomain
from zope.i18n.simpletranslationdomain import SimpleTranslationDomain

messages = {('de', u'Hello World'): u'Hallo Welt',
            ('nl', u'Hello World'): u'Hallo Wereld'}
helloworld_domain = SimpleTranslationDomain(u'helloworld', messages)

grokcore.component.global_utility(helloworld_domain,
                                  provides=ITranslationDomain,
                                  name='helloworld',
                                  direct=True)

全局适配器

有时,你可能有一个对象,它应该注册为适配器工厂。它可能来自某个其他框架,该框架已经为你配置了适配器,比如说,或者你可能有一个类,你实例化多次以获取特定适配器工厂的不同变体。在这些情况下,无法通过继承 grokcore.component.Adapter 或 MultiAdapter 来实现。相反,你可以使用 global_adapter() 指令。以下是一个示例,该示例借鉴了 z3c.form 库,该库为命名小部件属性提供了适配器工厂工厂。

import zope.interface
import zope.schema
import grokcore.component
import z3c.form.widget import ComputedWidgetAttribute

class ISchema(Interface):
    """This schema will be used to power a z3c.form form"""

    field = zope.schema.TextLine(title=u"Sample field")

...

label_override = z3c.form.widget.StaticWidgetAttribute(
                      u"Override label", field=ISchema['field'])

grokcore.component.global_adapter(label_override, name=u"label")

在上面的示例中,提供的和适配的接口是从 StaticWidgetAttribute 工厂返回的对象中推断出来的。global_adapter 的完整语法如下:

global_adapter(factory, (IAdapted1, IAdapted2,), IProvided, name=u"name")

工厂必须是一个可调用对象(适配器工厂)。适配接口作为元组给出。你可以使用单个接口而不是一个元素元组来表示单个适配器。提供的接口按照所示给出。名称默认为 u””(一个无名的适配器)。

处理事件

这里我们看到一个事件处理程序,它类似于它在 Zope 内部发生时的样子。它订阅了所有可注解对象(换句话说,可以与元数据相关联的对象)的修改事件。当被调用时,它将 Dublin Core 的“修改”属性相应地更新。

import datetime
import grokcore.component
from zope.annotation.interfaces import IAnnotatable
from zope.lifecycleevent.interfaces import IObjectModifiedEvent
from zope.dublincore.interfaces import IZopeDublinCore

@grokcore.component.subscribe(IAnnotatable, IObjectModifiedEvent)
def updateDublinCoreAfterModification(obj, event):
    """Updated the Dublin Core 'Modified' property when a modified
    event is sent for an object."""
    IZopeDublinCore(obj).modified = datetime.datetime.utcnow()

订阅

订阅看起来类似于适配器,然而,与常规适配器不同,订阅适配器在我们想要所有将对象适配到特定适配器的适配器时使用。

类似于 MultiAdapter,还有一个 MultiSubscription 组件,它“适配”多个对象。

更改

4.1 (2023-03-21)

  • 通过不再导入已删除的函数来升级以支持 zope.interface >= 6.0

    • classProvides

    • implementsOnly

4.0 (2023-02-17)

  • 添加对 Python 3.10、3.11 的支持。

  • 取消对 Python 2.7、3.5、3.6 的支持。

3.2.0 (2021-03-22)

  • 添加对 Python 3.7 至 3.9 的支持。

  • 更新到 zope.component >= 5

  • 取消对 Python 3.4 的支持。

3.1 (2018-05-09)

  • 通过我们的 API 公开 martian.ignore

3.0.2 (2018-01-17)

  • 在整个文档中用 @grok.implementer() 指令替换 grok.implements() 的使用。

3.0.1 (2018-01-12)

  • 重新排列测试,以便 Travis CI 可以拾取所有功能测试。

3.0 (2017-10-19)

  • 添加对 Python 3.5、3.6、PyPy2 和 PyPy3 的支持。

  • 取消对 Python 2.6 和 3.3 的支持。

2.7 (2016-02-16)

  • 使用 <grok:grok exclude="<names>" /> 添加排除多个模块或包的能力,并允许在内部使用 Unix shell 风格的通配符。

2.6.1 (2016-01-29)

  • 使 grokcore.component.implementer 与 zope.interface.implementer 兼容,允许在函数上使用时执行适配器魔术。

2.6 (2015-05-12)

  • Python 3l 兼容性

  • Python 3 不再支持 zope.interface.implements 指令,需要使用 @implementer 类装饰器代替。grokcore.components 的这个版本为 Python 2 和 3 都提供了自己的 grokcore.component.implements 指令。因此,在 grokker 的帮助下,此指令仍然可以使用。如果你使用 grokcore.components >= 2.6,将使用新实现,而早期版本使用 zope.interface.implements。

2.5 (2012-05-01)

  • 在 grokcore.component 中引入 provideUtility、providerAdapter、provideSubscriptionAdapter、provideHandler 和 provideInterface。默认情况下,它们将组件注册委托给全局站点管理器,就像之前所做的那样,但为 grokked 组件提供了自定义注册的能力。

  • 修复 global_adapter,使其能够正确使用由 grok.adapter 注释的信息,并在未指定时使用 IContext 对象。(修复 Launchpad 问题 #960097)。

  • sort_components 添加一个 key 选项,其行为类似于标准 Python 排序方法上的 key 选项。

2.4 (2011-04-27)

  • 修复了 global_adapter 指令实现,使其能够接受一个显式的“空”名称用于无名称适配器注册(因为之前提供空名称在注册时实际上会在工厂具有 grok.name 的情况下注册一个命名的适配器)。

2.3 (2011-02-14)

  • 实现了通用(多)订阅组件。

2.2 (2010-11-03)

  • 现在在指令本身中定义了上下文指令和提供指令的默认值计算。这意味着在检索这些指令的值时,不再需要传递“default_context”函数以进行通用情况。

    类似地,在获取提供指令的值时,在通用情况下也不再需要传递“default_provides”函数。

2.1 (2010-11-01)

  • 使包符合 zope.org 存储库策略。

  • 将 grokcore.viewlet 中的指令“order”和 grokcore.view 中的“path”移动到本包中。

  • 微调依赖关系:将 zope.event 移动到测试依赖中。

  • 将 1.x 分支的排除参数从 Grok ZCML 指令中移植过来。

  • 从 1.x 分支移植对 testing.py 模块的忽略。

2.0 (2009-09-16)

  • 使用具有更好的继承支持的 Martian 新版本。这可以在 tests/inherit 中看到。

  • 由于新的 Martian,ContextGrokkerscan.py 模块已经不再需要。

  • 指令实现(在其工厂方法中)不应绑定指令。指令绑定不能在导入时间进行,只能在 grok 时间进行。在导入时间(指令执行时)绑定指令可能导致更改问题。(我们在使用新的 Martian 的重构过程中发现了这一点)。

  • 在 Grok 的发布信息中使用 1.0b1 版本的 versions.cfg,而不是本地副本;维护所有 grokcore 包的本地副本过于困难。

1.7 (2009-06-01)

  • 将缺失的提供者、全局适配器、implementsOnly、classProvides() 添加到模块接口中,以便它们包含在 __all__ 中

1.6 (2009-04-10)

  • 为 zope.interface 中的 classProvides() 类声明添加方便的导入。

  • 添加在模块级别注册全局适配器的支持

    grok.global_adapter(factory, (IAdapted1, IAdapted2,), IProvided, name=u"name")

    只需要“factory”。如果只适配一个接口,第二个参数可以是一个接口,而不是一个元组。如果组件已声明适配/提供接口,则可以省略第二个和第三个参数。

  • 添加支持使用 @provider 装饰器直接提供接口

    @grok.provider(IFoo, IBar)
    def some_function():
        ...

    这相当于 alsoProvides(some_function, IFoo, IBar)。

  • 添加支持使用 @adapter 装饰器注册具有名称的适配器

    @grok.adapter(IAdaptedOne, IAdaptedTwo, name=u"foo")
    def some_function(one, two):
        ...

1.5.1 (2008-07-28)

  • IGrokcoreComponentAPI 接口缺少对 titledescription 指令的声明。

1.5 (2008-07-22)

  • 修复 https://bugs.launchpad.net/grok/+bug/242353:grokcore.component 包含旧式测试设置。在 grokcore.component.testing 中不再有 register_all_tests 方法。使用 z3c.testsetup。

  • 允许带有 @grok.subscribe 标记的函数也被手动注册为 zope.component.provideHandler()。这对于单元测试很有用,在单元测试中可能不想 grok 整个模块。

  • 在接口中记录 grokcore.component 的公共 API,IGrokcoreComponentAPI。当您现在这样做时

    from grokcore.component import *

    只有在该接口中记录的项目将被导入到您的本地命名空间中。

1.4 (2008-06-11)

  • 将类 grokkers 端口移植以利用 Martian 的进一步改进。这需要 Martian 0.10。

1.3 (2008-05-14)

  • 将类 grokkers 端口移植以利用从类中检索指令信息的新的声明性方法。这需要 Martian 0.9.6。

1.2.1 (2008-05-04)

  • 升级到 Martian 0.9.5,其中 scan_for_classes 的签名略有变化。

  • 从 grokcore.component.scan 中删除不必要的导入 methods_from_class

1.2 (2008-05-04)

  • 将指令导入到火星新的指令实现中。结果,几乎所有来自 grokcore.component.util 的辅助函数都已删除。现在,功能大多可以从指令本身获得。

  • baseclass 指令移动到火星。

  • order 指令及其辅助函数移回 Grok,因为它对通用没有帮助,但非常具体于视图。

1.1 (2008-05-03)

  • determine_module_component 现在查找实现特定接口的类(如 IContext),而不是接受类列表。如果查找 IContext,它仍然会找到 Context 子类,因为这些也被用来实现 IContext

  • public_methods_from_class 辅助函数移回 Grok,因为在 grokcore.component 中完全没有使用。

1.0.1 (2008-05-02)

  • 适配器和全局实用程序解析器在配置操作判别器中没有使用正确的 provided 接口值。因此,会出现没有信息且可能错误的冲突错误,以及应该在冲突发生的地方没有冲突。

  • global_utility() 指令解析器立即进行了注册,而不是生成配置操作。因此,它不会引发冲突注册的 ConflictErrors

  • 改进了文档

1.0 (2008-05-01)

  • 于2008年3月创建了 grokcore.component,通过将基本组件基类及其指令和解析器从 Grok 中提取出来。

项目详细信息


下载文件

下载适合您平台的应用程序。如果您不确定要选择哪个,请了解更多关于 安装包 的信息。

源分布

grokcore.component-4.1.tar.gz (49.9 kB 查看散列)

上传时间

构建分布

grokcore.component-4.1-py3-none-any.whl (77.6 kB 查看散列)

上传时间 Python 3

由以下支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误日志 StatusPage StatusPage 状态页面