Pyramid

在引擎盖下, Pyramid 使用A Zope Component Architecture 组件注册表 application registry . Zope组件架构通俗地称为“ZCA”。

这个 zope.component 用于访问传统Zope应用程序中数据的API可能是不透明的。例如,这里是一个典型的“未命名实用程序”查找,使用 zope.component.getUtility() 传统Zope应用程序中可能出现的全局API:

1
2
3
from pyramid.interfaces import ISettings
from zope.component import getUtility
settings = getUtility(ISettings)

运行此代码后, settings 将是一本 Python 字典。但是,任何“平民”都不可能仅仅通过随便阅读代码就能解决这个问题。当 zope.component.getUtility 开发人员使用API,临时代码阅读器的概念负载很高。

而ZCA是构建 框架Pyramid 它并不总是构建 应用 由于 zope.component API。因此, Pyramid 倾向于对应用程序开发人员隐藏ZCA的存在。你不需要理解ZCA来创建一个 Pyramid 应用程序;它的使用实际上只是一个框架实现细节。

然而,已经习惯于写作的开发人员 Zope 应用程序在构建 Pyramid 应用。 Pyramid 使这成为可能。

Pyramid 应用

Zope 对在同一个python进程中运行的所有zope应用程序使用单个zca注册表“全局”zca注册表,有效地使单个进程中无法运行多个zope应用程序。

但是,为了便于部署,能够在每个流程中运行多个应用程序通常很有用。例如,使用 PasteDeploy “composite”允许您在同一个进程中运行单独的wsgi应用程序,每个应用程序都响应一些URL前缀的请求。这使得它可以运行,例如,涡轮齿轮应用程序 /turbogears 和A Pyramid 应用于 /pyramid 都用同样的 WSGI 单个python进程中的服务器。

大多数生产Zope应用程序都比较大,因此由于内存限制,每个Python进程运行多个Zope应用程序是不现实的。然而,A Pyramid 应用程序可能非常小,占用的内存非常少,因此能够运行多个应用程序是一个合理的目标。 Pyramid 每个流程的应用程序。

为了使运行多个 Pyramid 在一个过程中应用, Pyramid 默认使用单独的ZCA注册表 每次应用 .

虽然这是一个合理的目标,但在尝试使用模式构建典型的 Zope 要生成的应用程序 Pyramid 应用。在没有特别帮助的情况下,zca“全局”API如 zope.component.getUtility()zope.component.getSiteManager() 将使用ZCA“全局”注册表。因此,这些API在 Pyramid 应用程序,因为他们将咨询ZCA全局注册表,而不是与您的 Pyramid 应用。

有三种方法可以解决这个问题:通过使用 pyramid.config.Configurator.hook_zca() 或者通过将zca全局注册表传递给 Configurator 启动时的构造函数。我们将在本节中描述这三种方法。

停止使用全球ZCA API

zca“全局”API函数,例如 zope.component.getSiteManagerzope.component.getUtilityzope.component.getAdapter()zope.component.getMultiAdapter() 不是绝对必要的。每个组件注册表都有一个提供相同功能的方法API;可以改用它。例如,假设 registry 下面的值是一个Zope组件体系结构组件注册表,下面的代码位相当于 zope.component.getUtility(IFoo)

registry.getUtility(IFoo)

完整的方法API记录在 zope.component 但它基本上完全反映了“全局”API。

如果您愿意放弃“全局”ZCA API,而是使用注册表的方法接口,那么您只需要知道如何获取 Pyramid 组件注册表。

有两种方法可以做到:

  • 使用 pyramid.threadlocal.get_current_registry() 函数在 Pyramid 视图或资源代码。这将始终返回“当前” Pyramid 应用程序注册表。
  • 使用的属性 request 对象命名 registry 在你 Pyramid 查看代码,例如, request.registry . 这是与正在运行的 Pyramid 应用。

线程局部 有关的详细信息 pyramid.threadlocal.get_current_registry() .

通过使用 hook_zca

考虑下面的一些惯用语 Pyramid 启动代码:

1
2
3
4
5
6
from pyramid.config import Configurator

def app(global_settings, **settings):
    config = Configurator(settings=settings)
    config.include('some.other.package')
    return config.make_wsgi_app()

app 上面的函数是run,a Configurator 是构造的。当创建配置程序时,它会创建一个 new application registry (ZCA组件注册表)。每当 registryConfigurator 调用构造函数,或者当 registry 值为的参数 None 传递给 Configurator 建造师。

在请求期间,由配置程序创建的应用程序注册表是“当前的”。这意味着呼叫 get_current_registry() 在处理请求的线程中,将返回与应用程序关联的组件注册表。

因此,应用程序开发人员可以使用 get_current_registry 获取注册表,从而访问实用程序等,根据 停止使用全球ZCA API . 但是他们仍然不能使用全局ZCA API。在没有特殊处理的情况下,zca全局API将始终返回全局zca注册表(在 zope.component.globalregistry.base

要“修复”此问题并使ZCA全局API使用“当前” Pyramid 注册处,你需要打电话 hook_zca() 在设置代码中。例如:

1
2
3
4
5
6
7
from pyramid.config import Configurator

def app(global_settings, **settings):
    config = Configurator(settings=settings)
    config.hook_zca()
    config.include('some.other.application')
    return config.make_wsgi_app()

我们在原始启动代码第5行中添加了一行,它调用 config.hook_zca() . 发动机罩下面这条线的作用是执行以下代码的模拟:

1
2
3
from zope.component import getSiteManager
from pyramid.threadlocal import get_current_registry
getSiteManager.sethook(get_current_registry)

这将导致ZCA全局API开始使用 Pyramid 正在运行的线程中的应用程序注册表 Pyramid 请求。

调用 hook_zca 通常足以“修复”在 Pyramid 应用。但是,这也意味着在同一进程中运行的Zope应用程序可能会开始使用 Pyramid 全局注册表而不是Zope全局注册表,有效地反转了原始问题。在这种情况下,请遵循下一节中的步骤, 使用zca全局注册表启用zca全局API .

使用zca全局注册表启用zca全局API

你可以告诉你 Pyramid 应用程序在启动时使用ZCA全局注册表,而不是构造新注册表:

1
2
3
4
5
6
7
8
9
from zope.component import getGlobalSiteManager
from pyramid.config import Configurator

def app(global_settings, **settings):
    globalreg = getGlobalSiteManager()
    config = Configurator(registry=globalreg)
    config.setup_registry(settings=settings)
    config.include('some.other.application')
    return config.make_wsgi_app()

上面的第5、6和7行是有趣的。第5行检索全局ZCA组件注册表。第6行创建 Configurator ,将全局ZCA注册表作为 registry 争论。第7行“设置”具有金字塔特定注册的全局注册表;这是通常在构建注册表而不是创建注册表时执行的代码,但当我们传递显式注册表时,必须手动调用它。

在这一点上, Pyramid 将使用ZCA全局注册表,而不是创建新的特定于应用程序的注册表。因为在默认情况下,ZCA全局API将使用这个注册表,所以当您使用全局ZCA API时,在Zope应用程序中,事情将按预期工作。