跳转到主要内容

用于隔离Python发行版(包和脚本)的配方。

项目描述

此构建配方仅用于隔离分发包及其依赖项。此配方最初是为在Debian操作系统中对Zope2进行打包而开发的。此配方还可以用于填充Python环境(或虚拟环境)。在需要buildout构建应用程序,但开发人员/系统管理员希望在典型的Python环境中使用应用程序的情况下,这可能很有用。

分发隔离

可以使用 buildout.recipe.isolation 配方在单个目录中隔离分发和其依赖项。该配方包含一些选项

dists

要隔离的分布列表,作为一个或多个setuptools需求字符串给出。每个需求字符串应单独一行给出。默认使用部分名称作为分发。

exclude-dists(可选)

要排除隔离的分布列表。

dists-location(可选)

将隔离的分布放置的目录位置。此选项默认为在配方使用的部分名称下的buildout部分目录中的位置。

scripts-location(可选)

一个目录位置,用于隔离分发脚本。此选项默认为构建部分目录下部分(或章节)名称后跟“-scripts”的位置(例如,对于名为 isolated 的部分,默认脚本目录名称将是 isolated-scripts)。

pth-location(可选)

创建此隔离的 .pth 文件的目录位置。此选项默认为构建部分目录下部分(或章节)名称后跟“-pth”的位置(例如,对于名为 isolated 的部分,默认 pth 目录名称将是 isolated-pth)。

pth 文件的最终名称将是部分名称,后跟 .pth 扩展名。要引用生成的 .pth 文件,请使用 pth-file-location 选项。

pth-file-location(仅参考)

.pth 文件所在的路径。生成的 .pth 文件在脚本生成过程中使用,以提供位于文件系统另一处的隔离分布的列表。

extra-pth(可选)

要作为脚本初始化部分包括的 .pth 文件列表。

此选项解决了由依赖隔离引起的依赖性问题。例如,如果您正在使用 exclude-dists,并且要排除的分布需要运行脚本,您可能希望包括包含这些依赖项位置的 .pth 文件。

exclude-own-pth(可选)

一个布尔选项,当设置时,将排除上下文部分生成的 .pth 文件在脚本中的包含。此选项与 pth-file-location 和 extra-pth 密切相关。此选项默认为 false。

此选项被包含的原因是 .pth 文件中的位置已经通过 site-packages 中 .pth 文件的位置包含在 Python 路径中。

executable(可选)

Python 可执行文件的位置。默认情况下这是 sys.executable

指定的可执行文件在食谱中未执行。位置在脚本生成期间用作 shebang 行。

stage-locally(可选)

一个布尔选项,用于指定我们是否应将资源存档或将其放置在最终目标位置。如果此选项为 true,则使用 dist-locationscript-locationpth-location 指定的值生成资源,但资源放置在默认部分位置。此选项对存档安装很有用。

食谱交付成果

  • 包含指定分布(s)包及其依赖包(s)的目录。

  • 包含 .pth 文件的目录,其中列出隔离上下文中每个包的绝对路径。

  • 包含从分布(s)包及其依赖包生成的脚本。

工作原理

我们有一个示例 buildout。让我们更新其配置文件以安装演示包。

>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... parts = demo
...
... [demo]
... recipe = buildout.recipe.isolation
... dists = demo<0.3
... find-links = %(server)s
... index = %(server)s/index
... """ % dict(server=link_server))

在此示例中,我们将范围限制在 0.3 之前的修订版。我们还指定了使用 find-links 选项查找分布的位置。

为了控制分布测试数据,我们决定使用 buildout 的测试索引,如下所示

>>> print get(link_server),
<html><body>
<a href="bigdemo-0.1-py2.3.egg">bigdemo-0.1-pyN.N.egg</a><br>
<a href="demo-0.1-py2.3.egg">demo-0.1-py2.3.egg</a><br>
<a href="demo-0.2-py2.3.egg">demo-0.2-py2.3.egg</a><br>
<a href="demo-0.3-py2.3.egg">demo-0.3-py2.3.egg</a><br>
<a href="demo-0.4c1-py2.3.egg">demo-0.4c1-py2.3.egg</a><br>
<a href="demoneeded-1.0.zip">demoneeded-1.0.zip</a><br>
<a href="demoneeded-1.1.zip">demoneeded-1.1.zip</a><br>
<a href="demoneeded-1.2c1.zip">demoneeded-1.2c1.zip</a><br>
<a href="extdemo-1.4.zip">extdemo-1.4.zip</a><br>
<a href="index/">index/</a><br>
<a href="other-1.0-py2.3.egg">other-1.0-py2.3.egg</a><br>
</body></html>

我们将通过测试结构使用此索引,并进一步解释在各个分布之前的这些关系。

让我们运行 buildout

>>> import os
>>> print system(buildout), #doctest: +ELLIPSIS
Installing demo.
Getting distribution for 'demo<0.3'.
Got demo 0.2.
Getting distribution for 'demoneeded'.
install_dir ...
Got demoneeded 1.2c1.
demo: Copying demo to the destination directory.
demo: Copying demoneeded to the destination directory.
demo: Generated script '/sample-buildout/parts/demo-scripts/demo'.

现在,如果我们查看隔离的 buildout 部分目录

>>> ls(sample_buildout, 'parts/demo')
-  demo-0.2-py2.3.egg
d  demoneeded-1.2c1-py2.3.egg

这些分布已进入 .pth 文件。此文件对 buildout 没有直接用途,但在 Python 环境中有其位置。.pth 文件的内容将是已安装到隔离中的每个分布的绝对路径。让我们看一下

>>> cat(sample_buildout, 'parts/demo-pth', 'demo.pth')
/sample-buildout/parts/demo/demo-0.2-py2.6.egg
/sample-buildout/parts/demo/demoneeded-1.2c1-py2.6.egg

默认情况下,.pth 文件的名称将与构建部分名称相同,在本例中为 demo。您可以使用 pth-file-location 选项更改 .pth 文件的位置。

依赖排除

现在让我们尝试一个稍大一些的示例构建,我们可以用它来展示从特定隔离中排除依赖项。

让我们根据上一个构建配置创建一个新的构建配置。此配置已设置为隔离 bigdemo 分发及其依赖项,但排除 demoneeded 依赖项。

>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... parts =
...     demoneeded
...     demo
... find-links = %(server)s
... index = %(server)s/index
...
... [demoneeded]
... recipe = buildout.recipe.isolation
... dists = demoneeded
...
... [demo]
... recipe = buildout.recipe.isolation
... dists = bigdemo
... exclude-dists = ${demoneeded:dists}
... """ % dict(server=link_server))
>>> print system(buildout), #doctest: +ELLIPSIS
Uninstalling demo.
Installing demoneeded.
demoneeded: Copying demoneeded to the destination directory.
Installing demo.
Getting distribution for 'bigdemo'.
Got bigdemo 0.1.
Getting distribution for 'demo'.
Got demo 0.4c1.
demo: Copying demo to the destination directory.
demo: Copying bigdemo to the destination directory.
demo: Generated script '/sample-buildout/parts/demo-scripts/demo'.

检查隔离结果

>>> ls(sample_buildout, 'parts/demo')
-  bigdemo-0.1-py2.6.egg
-  demo-0.4c1-py2.6.egg
>>> ls(sample_buildout, 'parts/demoneeded')
d  demoneeded-1.2c1-py2.6.egg

脚本生成

某些分发在其软件包中提供命令行脚本。Buildout 通常为我们生成这些脚本,因为它需要向脚本提供构建的软件包。它通过将分发位置注入 Python 系统路径来完成此操作。在某些情况下,我们不希望将任何内容注入 Python 系统路径,因为我们可能已经将生成的 .pth 文件放置在虚拟环境的 site-packages 目录中。而在其他情况下,我们可能希望将 .pth 文件作为导入解析的手段提供。让我们更仔细地看看这两种情况。

对于一般情况,我们可能希望将我们的 .pth 文件提供给脚本。此外,我们可能还希望提供任何依赖隔离可能生成的 .pth 文件。以下是一个示例。

>>> import sys
>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... parts =
...     demoneeded
...     demo
... find-links = %(server)s
... index = %(server)s/index
...
... [demoneeded]
... recipe = buildout.recipe.isolation
... dists = demoneeded
...
... [demo]
... recipe = buildout.recipe.isolation
... dists = bigdemo
... exclude-dists = ${demoneeded:dists}
... extra-pth = ${demoneeded:pth-file-location}
... executable = %(python)s
... """ % dict(server=link_server, python=sys.executable))
>>> print system(buildout), #doctest: +ELLIPSIS
Uninstalling demo.
Uninstalling demoneeded.
Installing demoneeded.
demoneeded: Copying demoneeded to the destination directory.
Installing demo.
demo: Copying demo to the destination directory.
demo: Copying bigdemo to the destination directory.
demo: Generated script '/sample-buildout/parts/demo-scripts/demo'.

生成的脚本应包含两个 .pth 文件。demo.pth 文件已定义并从上下文中的配方生成。demoneeded.pth 文件是由 demoneeded 部分生成的,并使用 extra-pth 配方选项引入。

>>> if sys.platform == 'win32':
...    script_name = 'demo-script.py'
... else:
...    script_name = 'demo'
>>> script_dir = 'parts/demo-scripts'
>>> f = open(os.path.join(sample_buildout, script_dir, script_name))
>>> shebang = f.readline().strip()
>>> if shebang[:3] == '#!"' and shebang[-1] == '"':
...     shebang = '#!'+shebang[3:-1]
>>> shebang == '#!' + os.path.realpath(sys.executable)
True
>>> print f.read(), # doctest: +NORMALIZE_WHITESPACE
<BLANKLINE>
import sys
def pth_injector(pth_file):
    path_file = open(pth_file, 'r')
    sys.path[0:0] = [line
        for line in path_file.read().split('\n')
        if line is not None]
<BLANKLINE>
pth_files = ['/sample-buildout/parts/demo-pth/demo.pth', '/sample-buildout/parts/demoneeded-pth/demoneeded.pth']
for pth in pth_files:
    pth_injector(pth)
<BLANKLINE>
import eggrecipedemo
<BLANKLINE>
if __name__ == '__main__':
    eggrecipedemo.main()
>>> f.close()

第二种情况是将 .pth 文件存放到虚拟环境中。让我们为了演示的目的,在构建结构内部设置一个 伪造 的虚拟环境结构。

>>> virtenv = os.path.join(sample_buildout, 'virtenv')
>>> mkdir(virtenv)
>>> mkdir(virtenv, 'bin')
>>> mkdir(virtenv, 'lib')
>>> mkdir(virtenv, 'lib', 'python2.6')
>>> mkdir(virtenv, 'lib', 'python2.6', 'site-packages')
>>> site_pkgs = os.path.join(virtenv, 'lib', 'python2.6', 'site-packages')

对于这个演示,我们实际上只需要 site-packages 目录。

>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... parts =
...     demoneeded
...     demo
... find-links = %(server)s
... index = %(server)s/index
...
... [demoneeded]
... recipe = buildout.recipe.isolation
... dists = demoneeded
... pth-file-location = %(site_pkgs)s
...
... [demo]
... recipe = buildout.recipe.isolation
... dists = bigdemo
... exclude-dists = ${demoneeded:dists}
... pth-file-location = %(site_pkgs)s
... exclude-own-pth = trUE
... python = %(python)s
... """ % dict(server=link_server, python=sys.executable,
...     site_pkgs=site_pkgs))
>>> print system(buildout), #doctest: +ELLIPSIS
Uninstalling demo.
Uninstalling demoneeded.
Installing demoneeded.
demoneeded: Copying demoneeded to the destination directory.
Installing demo.
demo: Copying demo to the destination directory.
demo: Copying bigdemo to the destination directory.
demo: Generated script '/sample-buildout/parts/demo-scripts/demo'.

现在,如果我们打印出 demo 脚本,我们会发现没有提到 .pth 文件。

>>> f = open(os.path.join(sample_buildout, script_dir, script_name))
>>> shebang = f.readline().strip()
>>> if shebang[:3] == '#!"' and shebang[-1] == '"':
...     shebang = '#!'+shebang[3:-1]
>>> shebang == '#!' + os.path.realpath(sys.executable)
True
>>> print f.read(), # doctest: +NORMALIZE_WHITESPACE
<BLANKLINE>
import eggrecipedemo
<BLANKLINE>
if __name__ == '__main__':
    eggrecipedemo.main()
>>> f.close()

为什么这会起作用?如果我们使用虚拟环境的 Python 可执行文件,它会加载 site-packages 目录以及其中的任何 .pth 文件。这将反过来加载我们使用构建生成的模块。

隔离的预演

在某些情况下,在将资源传输到最终目的地之前在本地构建软件包很有用。为此,我们可以使用 stage-locally 选项对隔离过程进行预演。

此选项将允许您设置 dists-locationscripts-locationpth-file-location 作为最终目的地,但将结果放置在其默认构建位置。如果您还记得,默认构建位置在构建的 parts 目录中。

让我们通过创建一个类似的构建配置来了解这是如何工作的,但现在我们将 stage-locally 选项设置为 true

>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... parts =
...     demo
... find-links = %(server)s
... index = %(server)s/index
...
... [demo]
... recipe = buildout.recipe.isolation
... dists = bigdemo
... dists-location = %(site_pkgs)s
... scripts-location = %(bin_dir)s
... pth-location = %(site_pkgs)s
... executable = %(python)s
... stage-locally = true
... """ % dict(server=link_server,
...            bin_dir=os.path.join(virtenv, 'bin'),
...            python=os.path.join(virtenv, 'bin', 'python'),
...            site_pkgs=site_pkgs))
>>> print system(buildout), #doctest: +ELLIPSIS
Uninstalling demo.
Uninstalling demoneeded.
Installing demo.
demo: Copying demo to the staging directory.
demo: Copying demoneeded to the staging directory.
demo: Copying bigdemo to the staging directory.
demo: Can't find the executable on the filesystem. Perhaps this setup is not destine to be used on this machine. So we are using the given executable value /sample-buildout/virtenv/bin/python as is.
demo: Generated script '/sample-buildout/parts/demo-scripts/demo'.

为了验证事物已被部署,让我们仔细查看演示脚本以确认一切是否按计划进行。首先,我们期望脚本位于parts目录中

>>> parts_dir = os.path.join(sample_buildout, 'parts')
>>> demo_script = os.path.join(parts_dir, 'demo-scripts', 'demo')
>>> os.path.exists(demo_script)
True
>>> cat(demo_script)
#!/sample-buildout/virtenv/bin/python
<BLANKLINE>
import sys
def pth_injector(pth_file):
    path_file = open(pth_file, 'r')
    sys.path[0:0] = [line
        for line in path_file.read().split('\n')
        if line is not None]
<BLANKLINE>
pth_files = ['/sample-buildout/virtenv/lib/python2.6/site-packages/demo.pth']
for pth in pth_files:
    pth_injector(pth)
<BLANKLINE>
import eggrecipedemo
<BLANKLINE>
if __name__ == '__main__':
    eggrecipedemo.main()

此外,我们还想检查pth位置是否正确,并且pth本身是否与parts一起位于部署区域

>>> demo_pth = os.path.join(parts_dir, 'demo-pth', 'demo.pth')
>>> cat(demo_pth)
/sample-buildout/virtenv/lib/python2.6/site-packages/demo-0.4c1-py2.1.egg
/sample-buildout/virtenv/lib/python2.6/site-packages/demoneeded-1.2c1-py2.1.egg
/sample-buildout/virtenv/lib/python2.6/site-packages/bigdemo-0.1-py2.1.egg

问题和帮助

如果您有问题或需要帮助,请向WebLion的项目网站提交错误报告,或通过IRC或电子邮件联系我们。

项目详情


下载文件

下载适用于您的平台文件。如果您不确定选择哪个,请了解有关安装包的更多信息。

源分发

buildout.recipe.isolation-0.2.0.tar.gz (17.0 kB 查看哈希值)

上传时间:

由以下支持