将Python软件包发行版作为egg安装的配方
项目描述
egg-installation配方将egg安装到buildout eggs目录中。它还在包含egg路径的buildout bin目录中生成脚本。
变更历史
2.0.7 (2018-07-02)
对于2.0.6的更改,我们要求zc.buildout 2.12.0。现在在setup.py中的install_requires也说明了这一点。
2.0.6 (2018-07-02)
添加了额外的关键字参数allow_unknown_extras,以支持zc.buildout 2.12.0。
2.0.5 (2017-12-04)
修复了#429:添加了对不同类型路径(develop-eggs-directory、eggs-directory、其他路径)优先级排序的工作集。
2.0.4 (2017-08-17)
修复 #153:buildout 应该缓存工作集环境 [rafaelbco]
2.0.3 (2015-10-02)
除了 sdist 之外,还将 zc.recipe.egg 作为 wheel 发布。没有功能上的变更。 [reinout]
2.0.2 (2015-07-01)
修复:在 zc.recipe.egg#custom 菜单的 rpath 支持,不要假设路径元素是 buildout 相关的,如果它们以“特殊”令牌之一(例如,$ORIGIN)开头。参见:https://github.com/buildout/buildout/issues/225。[tseaver]
2.0.1 (2013-09-05)
适应 zc.buildout 切换到 post-merge setuptools。
2.0.0 (2013-04-02)
默认启用“prefer-final”选项。
2.0.0a3 (2012-11-19)
添加了对 Python 3.2/3.3 的支持。
添加了“MANIFEST.in”。
支持非入口点脚本。
尊重脚本的退出代码(https://bugs.launchpad.net/bugs/697913)。
2.0.0a2 (2012-05-03)
始终解压已安装的 eggs。
从使用“setuptools”切换到“distribute”。
删除了多 Python 支持。
1.3.2 (2010-08-23)
修复了 1.3.1 中引入的变化的 bug。
1.3.1 (2010-08-23)
通过传递字典而不是预期的/测试过的 zc.buildout.buildout.Options 对象来支持使用 zc.recipe.egg 的配方。
1.3.0 (2010-08-23)
在 1.2.3b1 之后进行了小的重构,以兼容 zc.buildout 1.5.0。
1.2.3b1 (2010-04-29)
重构以与 z3c.recipe.scripts 和 zc.buildout 1.5.0 一起使用。没有新增用户可见的功能。
1.2.2 (2009-03-18)
修复了依赖信息。需要 zc.buildout >1.2.0。
1.2.1 (2009-03-18)
重构相对 egg 路径的生成以生成更简单的代码。
1.2.0 (2009-03-17)
添加了 dependent-scripts 选项。当设置为 true 时,除了特定命名的 eggs 之外,还将为所有必需的 eggs 生成脚本。这个想法来自这个配方两个分支,repoze.recipe.egg 和 pylons_sandbox,但选项名称以破折号而不是下划线书写,默认为 false。
添加了相对路径选项。当为 true 时,脚本中的 egg 路径相对于脚本名称生成。
1.1.0 (2008-07-19)
重构以尊重新的 buildout 级解压缩选项。
1.1.0b1 (2008-06-27)
将 environment 选项添加到自定义扩展构建选项中。
1.0.0 (2007-11-03)
与上一个 beta 版本相比没有代码更改,只是对一些小型的包元数据进行了改进。
1.0.0b5 (2007-02-08)
功能更改
添加了对 buildout 最新选项的支持。
1.0.0b4 (2007-01-17)
功能更改
将初始化和参数选项添加到脚本配方中。
添加了一个仅安装 eggs 的 eggs 配方。
宣传脚本配方用于创建脚本。
1.0.0b3 (2006-12-04)
功能更改
添加了用于创建开发 eggs 的开发配方。
这很有用
指定自定义扩展构建选项
指定要使用的 Python 版本,以及
在创建开发 eggs 后创建其他部分。
现在,开发配方和构建配方现在返回创建的路径,因此当部分被删除(或更改)时,创建的 eggs 或 egg 链接将被删除。
1.0.0b2 (2006-10-16)
更新以与 zc.buildout 1.0.0b10 一起工作(不发出警告)。
1.0.0b1
更新以与 zc.buildout 1.0.0b3 一起工作。
1.0.0a3
现在可以通过 extra-paths 选项设置要包含在生成的脚本中的额外路径元素。
不再隐式为每个 egg 生成“py_”脚本。现在有一个解释器选项可以生成一个脚本,当没有参数运行时,它将使用基于部分 eggs 和额外路径的路径启动 Python 交互式解释器。如果以 Python 脚本名称和参数运行此脚本,则将使用设置的路径运行该脚本。
现在可以指定显式的入口点。这对于使用没有声明自己的入口点的包很有用。
添加了对 Windows 的支持。
不再隐式为每个 egg 生成“py_”脚本。现在可以根据为 egg 部分定义的 eggs 生成用于启动 Python 解释器或运行脚本的脚本。
现在可以为没有声明入口点的包指定自定义入口点。
现在您可以为生成的脚本指定额外的路径。
1.0.0a2
添加了一个用于使用自定义distutils build_ext参数构建自定义egg的自定义配方。
1.0.0a1
初始公开版本
详细文档
作为egg安装发行版的安装
zc.recipe.egg:eggs配方可用于安装各种类型的distutils分发作为egg。它接受多个选项
- eggs
要安装的egg列表,以一个或多个setuptools需求字符串的形式给出。每个字符串必须单独一行给出。
- find-links
用于搜索分发的URL、文件或目录列表。
- index
索引服务器的URL,或几乎任何有效的URL。:)
如果没有指定,则使用Python包索引,http://cheeseshop.python.org/pypi。您可以使用此选项指定备用索引。如果您使用links选项,并且链接指向所需分发,则索引可以是任何内容,将被很大程度上忽略。在下面的示例中,我们将仅指向我们的链接服务器上的一个空目录。这将使我们的示例运行得稍微快一些。
我们有一个包含许多分发的链接服务器
>>> print_(get(link_server), end='') <html><body> <a href="bigdemo-0.1-py2.3.egg">bigdemo-0.1-py2.3.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.4rc1-py2.3.egg">demo-0.4rc1-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.2rc1.zip">demoneeded-1.2rc1.zip</a><br> <a href="du_zipped-1.0-pyN.N.egg">du_zipped-1.0-pyN.N.egg</a><br> <a href="extdemo-1.4.zip">extdemo-1.4.zip</a><br> <a href="index/">index/</a><br> <a href="mixedcase-0.5.zip">mixedcase-0.5.zip</a><br> <a href="other-1.0-py2.3.egg">other-1.0-py2.3.egg</a><br> </body></html>
我们有一个示例buildout。让我们更新它的配置文件以安装demo包。
>>> write(sample_buildout, 'buildout.cfg', ... """ ... [buildout] ... parts = demo ... ... [demo] ... recipe = zc.recipe.egg:eggs ... eggs = demo<0.3 ... find-links = %(server)s ... index = %(server)s/index ... """ % dict(server=link_server))
在此示例中,我们将范围限制在0.3之前的修订版。我们还使用find-links选项指定了查找分发的地方。
让我们运行buildout
>>> import os >>> print_(system(buildout), end='') Installing demo. Getting distribution for 'demo<0.3'. Got demo 0.2. Getting distribution for 'demoneeded'. Got demoneeded 1.1.
现在,如果我们查看buildout eggs目录
>>> ls(sample_buildout, 'eggs') d demo-0.2-py2.3.egg d demoneeded-1.1-py2.3.egg - setuptools-0.7-py2.3.egg d zc.buildout-1.0-py2.3.egg
我们看到我们得到了满足要求的demo egg,以及demo所需的demoneeded egg。(我们还在develop-eggs目录中看到了一个recipe的egg链接。实际上,这个egg链接是作为示例buildout设置的一部分创建的。通常,在使用配方时,您将获得常规的egg安装。)
脚本生成
demo egg定义了一个脚本,但我们没有安装它
>>> ls(sample_buildout, 'bin') - buildout
如果我们想安装egg提供的脚本,我们应该使用scripts配方
>>> write(sample_buildout, 'buildout.cfg', ... """ ... [buildout] ... parts = demo ... ... [demo] ... recipe = zc.recipe.egg:scripts ... eggs = demo<0.3 ... find-links = %(server)s ... index = %(server)s/index ... """ % dict(server=link_server))>>> print_(system(buildout), end='') Uninstalling demo. Installing demo. Generated script '/sample-buildout/bin/demo'.
现在我们也看到了由demo script定义的脚本
>>> ls(sample_buildout, 'bin') - buildout - demo
scripts配方定义了一些附加选项
- entry-points
形式为的entry-point标识符列表
name=module:attrs
其中name是脚本名称,module是解析到模块名称的点分名称,attrs是解析到模块内的可调用对象的点分名称。
此选项在处理未声明entry points的分发时很有用,例如没有为使用setuptools编写的分发。
下面的“指定entry points”部分中有示例。
- scripts
控制要生成的脚本。值应该是零个或多个令牌的列表。每个令牌要么是名称,要么是名称后跟一个'='和一个新名称。仅生成命名的脚本。如果没有给出任何令牌,则禁用脚本生成。如果没有提供此选项,则生成由命名的eggs定义的所有脚本。
- dependent-scripts
如果设置为字符串“true”,则除了特定命名的egg外,还会为所有所需egg生成脚本。
- interpreter
要生成的脚本的名称,允许访问具有基于已安装egg设置的路径的Python解释器。
- extra-paths
要包含在生成的脚本中的额外路径。
- initialization
指定一些Python初始化代码。这非常有限。特别是,请注意,从提供的代码中删除了前导空格。
- arguments
指定作为Python源传递给entry points的一些参数。
- relative-paths
如果设置为true,则egg路径将相对于脚本路径生成。这允许在移动构建时不会破坏egg路径。此选项可以在脚本部分或构建部分中设置。
让我们添加一个解释器选项
>>> write(sample_buildout, 'buildout.cfg', ... """ ... [buildout] ... parts = demo ... ... [demo] ... recipe = zc.recipe.egg ... eggs = demo<0.3 ... find-links = %(server)s ... index = %(server)s/index ... interpreter = py-demo ... """ % dict(server=link_server))
请注意,我们从配方规范中省略了入口点名称。我们能这样做是因为脚本配方是zc.recipe.egg egg的默认入口点。
>>> print_(system(buildout), end='') Uninstalling demo. Installing demo. Generated script '/sample-buildout/bin/demo'. Generated interpreter '/sample-buildout/bin/py-demo'.
现在我们还得到了一个py-demo脚本,它提供了一个Python提示,其中包含用于演示的路径以及它依赖的任何egg,它们包含在sys.path中。这对于调试和测试非常有用。
>>> ls(sample_buildout, 'bin') - buildout - demo - py-demo
如果我们运行演示脚本,它会打印出一些最小数据
>>> print_(system(join(sample_buildout, 'bin', 'demo')), end='') 2 1
打印的值恰好是安装的模块中定义的一些值。
我们还可以运行py-demo脚本。这里我们只打印出反映egg路径的位
>>> print_(system(join(sample_buildout, 'bin', 'py-demo'), ... """import os, sys ... for p in sys.path: ... if 'demo' in p: ... _ = sys.stdout.write(os.path.basename(p)+'\\n') ... ... """).replace('>>> ', '').replace('... ', ''), end='') ... # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE demo-0.2-py2.4.egg demoneeded-1.1-py2.4.egg...
更新egg
配方通常获取满足规范的最新分发。如果构建处于非最新模式或离线模式,则不会这样做。为了了解它是如何工作的,我们将移除对演示的限制
>>> write(sample_buildout, 'buildout.cfg', ... """ ... [buildout] ... parts = demo ... ... [demo] ... recipe = zc.recipe.egg ... find-links = %(server)s ... index = %(server)s/index ... """ % dict(server=link_server))
并在非最新模式下运行构建
>>> print_(system(buildout+' -N'), end='') Uninstalling demo. Installing demo. Generated script '/sample-buildout/bin/demo'.
请注意,我们已经移除了egg选项,并且egg默认为部分名称。因为我们移除了egg选项,所以演示被重新安装。
我们还将以离线模式运行构建
>>> print_(system(buildout+' -o'), end='') Updating demo.
我们没有为演示获取更新
>>> ls(sample_buildout, 'eggs') d demo-0.2-py2.3.egg d demoneeded-1.1-py2.3.egg - setuptools-0.7-py2.3.egg d zc.buildout-1.0-py2.3.egg
如果我们以默认的在线和最新模式运行构建,我们将为演示获取更新
>>> print_(system(buildout), end='') Updating demo. Getting distribution for 'demo'. Got demo 0.3. Generated script '/sample-buildout/bin/demo'.
然后我们将得到一个新的演示egg
>>> ls(sample_buildout, 'eggs') d demo-0.2-py2.3.egg d demo-0.3-py2.3.egg d demoneeded-1.1-py2.3.egg - setuptools-0.7-py2.4.egg d zc.buildout-1.0-py2.4.egg
脚本也更新了
>>> print_(system(join(sample_buildout, 'bin', 'demo')), end='') 3 1
控制脚本生成
您可以使用脚本选项来控制要生成的脚本。例如,为了抑制脚本,请使用不带任何参数的脚本选项
>>> write(sample_buildout, 'buildout.cfg', ... """ ... [buildout] ... parts = demo ... ... [demo] ... recipe = zc.recipe.egg ... find-links = %(server)s ... index = %(server)s/index ... scripts = ... """ % dict(server=link_server))>>> print_(system(buildout), end='') Uninstalling demo. Installing demo.>>> ls(sample_buildout, 'bin') - buildout
您还可以控制脚本使用的名称
>>> write(sample_buildout, 'buildout.cfg', ... """ ... [buildout] ... parts = demo ... ... [demo] ... recipe = zc.recipe.egg ... find-links = %(server)s ... index = %(server)s/index ... scripts = demo=foo ... """ % dict(server=link_server))>>> print_(system(buildout), end='') Uninstalling demo. Installing demo. Generated script '/sample-buildout/bin/foo'.>>> ls(sample_buildout, 'bin') - buildout - foo
指定额外的脚本路径
如果我们需要在脚本中包含额外的路径,我们可以使用extra-paths选项
>>> write(sample_buildout, 'buildout.cfg', ... """ ... [buildout] ... parts = demo ... ... [demo] ... recipe = zc.recipe.egg ... find-links = %(server)s ... index = %(server)s/index ... scripts = demo=foo ... extra-paths = ... /foo/bar ... ${buildout:directory}/spam ... """ % dict(server=link_server))>>> print_(system(buildout), end='') Uninstalling demo. Installing demo. Generated script '/sample-buildout/bin/foo'.
让我们看看生成的脚本
>>> cat(sample_buildout, 'bin', 'foo') # doctest: +NORMALIZE_WHITESPACE #!/usr/local/bin/python2.7 <BLANKLINE> import sys sys.path[0:0] = [ '/sample-buildout/eggs/demo-0.3-py2.4.egg', '/sample-buildout/eggs/demoneeded-1.1-py2.4.egg', '/foo/bar', '/sample-buildout/spam', ] <BLANKLINE> import eggrecipedemo <BLANKLINE> if __name__ == '__main__': sys.exit(eggrecipedemo.main())
相对egg路径
如果指定了相对路径选项并设置为true值,则路径将相对于脚本生成。当您想能够移动构建目录而不会破坏脚本时,这非常有用。
>>> write(sample_buildout, 'buildout.cfg', ... """ ... [buildout] ... parts = demo ... ... [demo] ... recipe = zc.recipe.egg ... find-links = %(server)s ... index = %(server)s/index ... scripts = demo=foo ... relative-paths = true ... extra-paths = ... /foo/bar ... ${buildout:directory}/spam ... """ % dict(server=link_server))>>> print_(system(buildout), end='') Uninstalling demo. Installing demo. Generated script '/sample-buildout/bin/foo'.
让我们看看生成的脚本
>>> cat(sample_buildout, 'bin', 'foo') # doctest: +NORMALIZE_WHITESPACE #!/usr/local/bin/python2.7 <BLANKLINE> import os <BLANKLINE> join = os.path.join base = os.path.dirname(os.path.abspath(os.path.realpath(__file__))) base = os.path.dirname(base) <BLANKLINE> import sys sys.path[0:0] = [ join(base, 'eggs/demo-0.3-pyN.N.egg'), join(base, 'eggs/demoneeded-1.1-pyN.N.egg'), '/foo/bar', join(base, 'spam'), ] <BLANKLINE> import eggrecipedemo <BLANKLINE> if __name__ == '__main__': sys.exit(eggrecipedemo.main())
您可以在构建部分中指定相对路径,而不是在各个脚本部分中指定
>>> write(sample_buildout, 'buildout.cfg', ... """ ... [buildout] ... parts = demo ... relative-paths = true ... ... [demo] ... recipe = zc.recipe.egg ... find-links = %(server)s ... index = %(server)s/index ... scripts = demo=foo ... extra-paths = ... /foo/bar ... ${buildout:directory}/spam ... """ % dict(server=link_server))>>> print_(system(buildout), end='') Uninstalling demo. Installing demo. Generated script '/sample-buildout/bin/foo'.>>> cat(sample_buildout, 'bin', 'foo') # doctest: +NORMALIZE_WHITESPACE #!/usr/local/bin/python2.7 <BLANKLINE> import os <BLANKLINE> join = os.path.join base = os.path.dirname(os.path.abspath(os.path.realpath(__file__))) base = os.path.dirname(base) <BLANKLINE> import sys sys.path[0:0] = [ join(base, 'eggs/demo-0.3-pyN.N.egg'), join(base, 'eggs/demoneeded-1.1-pyN.N.egg'), '/foo/bar', join(base, 'spam'), ] <BLANKLINE> import eggrecipedemo <BLANKLINE> if __name__ == '__main__': sys.exit(eggrecipedemo.main())
指定初始化代码和参数
有时,我们需要做的不仅仅是调用入口点。我们可以使用初始化和参数选项来指定要包含在生成的脚本中的额外代码
>>> write(sample_buildout, 'buildout.cfg', ... """ ... [buildout] ... parts = demo ... ... [demo] ... recipe = zc.recipe.egg ... find-links = %(server)s ... index = %(server)s/index ... scripts = demo=foo ... extra-paths = ... /foo/bar ... ${buildout:directory}/spam ... initialization = a = (1, 2 ... 3, 4) ... interpreter = py ... arguments = a, 2 ... """ % dict(server=link_server))>>> print_(system(buildout), end='') Uninstalling demo. Installing demo. Generated script '/sample-buildout/bin/foo'. Generated interpreter '/sample-buildout/bin/py'.>>> cat(sample_buildout, 'bin', 'foo') # doctest: +NORMALIZE_WHITESPACE #!/usr/local/bin/python2.7 <BLANKLINE> import sys sys.path[0:0] = [ '/sample-buildout/eggs/demo-0.3-py2.4.egg', '/sample-buildout/eggs/demoneeded-1.1-py2.4.egg', '/foo/bar', '/sample-buildout/spam', ] <BLANKLINE> a = (1, 2 3, 4) <BLANKLINE> import eggrecipedemo <BLANKLINE> if __name__ == '__main__': sys.exit(eggrecipedemo.main(a, 2))
在这里,我们看到我们指定的初始化代码在设置路径之后添加。注意,如上所述,前面空白已被删除。同样,我们指定的参数代码在入口点调用(到main)中添加。
我们的解释器也有初始化代码
>>> cat(sample_buildout, 'bin', 'py') ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS #!/usr/local/bin/python2.7 <BLANKLINE> import sys <BLANKLINE> sys.path[0:0] = [ '/sample-buildout/eggs/demo-0.3-py3.3.egg', '/sample-buildout/eggs/demoneeded-1.1-py3.3.egg', '/foo/bar', '/sample-buildout/spam', ] <BLANKLINE> a = (1, 2 3, 4) <BLANKLINE> <BLANKLINE> _interactive = True ...
指定入口点
可以为显式声明的入口点生成脚本。我们可以使用entry-points选项声明入口点
>>> write(sample_buildout, 'buildout.cfg', ... """ ... [buildout] ... parts = demo ... ... [demo] ... recipe = zc.recipe.egg ... find-links = %(server)s ... index = %(server)s/index ... extra-paths = ... /foo/bar ... ${buildout:directory}/spam ... entry-points = alt=eggrecipedemo:alt other=foo.bar:a.b.c ... """ % dict(server=link_server))>>> print_(system(buildout), end='') Uninstalling demo. Installing demo. Generated script '/sample-buildout/bin/demo'. Generated script '/sample-buildout/bin/alt'. Generated script '/sample-buildout/bin/other'.>>> ls(sample_buildout, 'bin') - alt - buildout - demo - other>>> cat(sample_buildout, 'bin', 'other') #!/usr/local/bin/python2.7 <BLANKLINE> import sys sys.path[0:0] = [ '/sample-buildout/eggs/demo-0.3-py2.4.egg', '/sample-buildout/eggs/demoneeded-1.1-py2.4.egg', '/foo/bar', '/sample-buildout/spam', ] <BLANKLINE> import foo.bar <BLANKLINE> if __name__ == '__main__': sys.exit(foo.bar.a.b.c())
生成所有脚本
bigdemo包没有脚本,但它需要具有脚本的demo包。指定dependent-scripts = true以生成所需包中的所有脚本
>>> write(sample_buildout, 'buildout.cfg', ... """ ... [buildout] ... parts = bigdemo ... ... [bigdemo] ... recipe = zc.recipe.egg ... find-links = %(server)s ... index = %(server)s/index ... dependent-scripts = true ... """ % dict(server=link_server)) >>> print_(system(buildout+' -N'), end='') Uninstalling demo. Installing bigdemo. Getting distribution for 'bigdemo'. Got bigdemo 0.1. Generated script '/sample-buildout/bin/demo'.
离线模式
如果构建离线选项设置为“true”,则不会尝试联系索引服务器
>>> write(sample_buildout, 'buildout.cfg', ... """ ... [buildout] ... parts = demo ... offline = true ... ... [demo] ... recipe = zc.recipe.egg ... index = eek! ... scripts = demo=foo ... """ % dict(server=link_server))>>> print_(system(buildout), end='') Uninstalling bigdemo. Installing demo. Generated script '/sample-buildout/bin/foo'.
创建需要自定义构建设置的扩展egg
有时,有必要提供对创建egg的额外控制。对于需要访问库或包含文件的扩展模块的egg,这通常是正确的。
可以使用zc.recipe.egg:custom配方来定义具有自定义构建参数的egg。当前定义的参数包括
- include-dirs
用于搜索包含文件的新行分隔的目录列表。
- library-dirs
用于搜索链接库的新行分隔的目录列表。
- rpath
运行时搜索动态库的新行分隔的目录列表。
- define
要定义的C预处理器变量名称的逗号分隔列表。
- undef
要取消定义的C预处理器变量名称的逗号分隔列表。
- libraries
要链接的额外库的名称。由于distutils的限制,尽管选项名称允许,但只能指定一个库。
- 链接对象
要链接的链接对象的名称。由于distutils的限制,尽管选项名称允许,但只能指定一个链接对象。
- 调试
编译/链接时包含调试信息
- 强制
强制构建所有内容(忽略文件时间戳)
- 编译器
指定编译器类型
- swig
swig可执行文件的路径
- swig-cpp
让SWIG创建C++文件(默认为C)
- swig-opts
SWIG命令行选项列表
此外,可以使用以下选项来指定egg
- egg
创建egg的规范,以setuptools需求字符串的形式安装。默认为部分名称。
- find-links
用于搜索分发的URL、文件或目录列表。
- index
索引服务器的URL,或几乎任何有效的URL。:)
如果没有指定,则使用Python包索引,http://cheeseshop.python.org/pypi。您可以使用此选项指定备用索引。如果您使用links选项,并且链接指向所需分发,则索引可以是任何内容,将被很大程度上忽略。在下面的示例中,我们将仅指向我们的链接服务器上的一个空目录。这将使我们的示例运行得稍微快一些。
- 环境
包含附加环境变量的节名称。在构建egg之前设置环境变量。
为了说明这一点,我们将定义一个buildout,用于构建一个包含简单扩展模块的egg
#include <Python.h> #include <extdemo.h> static PyMethodDef methods[] = {}; PyMODINIT_FUNC initextdemo(void) { PyObject *m; m = Py_InitModule3("extdemo", methods, ""); #ifdef TWO PyModule_AddObject(m, "val", PyInt_FromLong(2)); #else PyModule_AddObject(m, "val", PyInt_FromLong(EXTDEMO)); #endif }
扩展依赖于系统相关的包含文件extdemo.h,它定义了一个常量EXTDEMO,该常量由扩展公开。
扩展模块作为一个源分发布布在分发服务器上,文件名为extdemo-1.4.tar.gz。
我们有一个示例buildout,我们将添加一个包含必要包含文件的包含目录
>>> mkdir('include') >>> write('include', 'extdemo.h', ... """ ... #define EXTDEMO 42 ... """)
我们还将更新buildout配置文件以定义一个egg的部分
>>> write(sample_buildout, 'buildout.cfg', ... """ ... [buildout] ... parts = extdemo ... ... [extdemo] ... recipe = zc.recipe.egg:custom ... find-links = %(server)s ... index = %(server)s/index ... include-dirs = include ... ... """ % dict(server=link_server))>>> print_(system(buildout), end='') # doctest: +ELLIPSIS Installing extdemo...
我们收到了zip_safe警告,因为我们使用的源分发布布不是基于setuptools的,因此没有设置此选项。
由于它依赖于buildout特定的参数,并且egg目录可以在多个buildout之间共享,因此egg在develop-eggs目录中创建而不是 eggs目录。
>>> ls(sample_buildout, 'develop-eggs') d extdemo-1.4-py2.4-unix-i686.egg - zc.recipe.egg.egg-link
请注意,没有安装脚本或依赖项。要安装依赖项或脚本的自定义egg,请定义另一个部分并使用zc.recipe.egg配方,将自定义egg列为要安装的egg之一。zc.recipe.egg配方将使用已安装的egg。
让我们定义一个使用我们的扩展示例的脚本
>>> mkdir('demo') >>> write('demo', 'demo.py', ... """ ... import extdemo, sys ... def print_(*args): ... sys.stdout.write(' '.join(map(str, args)) + '\\n') ... def main(): ... print_(extdemo.val) ... """)>>> write('demo', 'setup.py', ... """ ... from setuptools import setup ... setup(name='demo') ... """)>>> write('buildout.cfg', ... """ ... [buildout] ... develop = demo ... parts = extdemo demo ... ... [extdemo] ... recipe = zc.recipe.egg:custom ... find-links = %(server)s ... index = %(server)s/index ... include-dirs = include ... ... [demo] ... recipe = zc.recipe.egg ... eggs = demo ... extdemo ... entry-points = demo=demo:main ... """ % dict(server=link_server))>>> print_(system(buildout), end='') Develop: '/sample-buildout/demo' Updating extdemo. Installing demo. Generated script '/sample-buildout/bin/demo'...
当我们运行脚本时,我们将打印42
>>> print_(system(join('bin', 'demo')), end='') 42
更新
自定义配方通常会检查满足给定规范的新源分发布布。可以使用buildout non-newest和offline模式来抑制此操作。我们将为extdemo生成一个新的源分发布布。
>>> update_extdemo()
如果我们以非最新或离线模式运行buildout
>>> print_(system(buildout+' -N'), end='') Develop: '/sample-buildout/demo' Updating extdemo. Updating demo.>>> print_(system(buildout+' -o'), end='') Develop: '/sample-buildout/demo' Updating extdemo. Updating demo.
我们不会收到更新。
>>> ls(sample_buildout, 'develop-eggs') - demo.egg-link d extdemo-1.4-py2.4-unix-i686.egg - zc.recipe.egg.egg-link
但是,如果我们以默认的在线和最新模式运行buildout,我们会。这一次,我们再次收到test-variable消息,因为新版本被导入
>>> print_(system(buildout), end='') # doctest: +ELLIPSIS Develop: '/sample-buildout/demo' Updating extdemo. zip_safe flag not set; analyzing archive contents... Updating demo. ...>>> ls(sample_buildout, 'develop-eggs') - demo.egg-link d extdemo-1.4-py2.4-linux-i686.egg d extdemo-1.5-py2.4-linux-i686.egg - zc.recipe.egg.egg-link
控制使用的版本
我们可以使用egg选项指定特定版本
>>> write('buildout.cfg', ... """ ... [buildout] ... develop = demo ... parts = extdemo demo ... ... [extdemo] ... recipe = zc.recipe.egg:custom ... egg = extdemo ==1.4 ... find-links = %(server)s ... index = %(server)s/index ... include-dirs = include ... ... [demo] ... recipe = zc.recipe.egg ... eggs = demo ... extdemo ==1.4 ... entry-points = demo=demo:main ... """ % dict(server=link_server))>>> print_(system(buildout+' -D'), end='') # doctest: +ELLIPSIS Develop: '/sample-buildout/demo' ...>>> ls(sample_buildout, 'develop-eggs') - demo.egg-link d extdemo-1.4-py2.4-linux-i686.egg - zc.recipe.egg.egg-link
控制环境变量
要设置附加环境变量,请使用环境选项。
让我们创建一个打印环境变量的配方。我们需要这样做以确保在egg:custom配方运行后删除设置的变量。
>>> mkdir(sample_buildout, 'recipes') >>> write(sample_buildout, 'recipes', 'environ.py', ... """ ... import logging, os, zc.buildout ... ... class Environ: ... ... def __init__(self, buildout, name, options): ... self.name = name ... ... def install(self): ... logging.getLogger(self.name).info( ... 'test-variable left over: %s' % ( ... 'test-variable' in os.environ)) ... return [] ... ... def update(self): ... self.install() ... """) >>> write(sample_buildout, 'recipes', 'setup.py', ... """ ... from setuptools import setup ... ... setup( ... name = "recipes", ... entry_points = {'zc.buildout': ['environ = environ:Environ']}, ... ) ... """)
创建我们的buildout
>>> write(sample_buildout, 'buildout.cfg', ... """ ... [buildout] ... develop = recipes ... parts = extdemo checkenv ... ... [extdemo-env] ... test-variable = foo ... ... [extdemo] ... recipe = zc.recipe.egg:custom ... find-links = %(server)s ... index = %(server)s/index ... include-dirs = include ... environment = extdemo-env ... ... [checkenv] ... recipe = recipes:environ ... ... """ % dict(server=link_server)) >>> print_(system(buildout), end='') # doctest: +ELLIPSIS Develop: '/sample-buildout/recipes' Uninstalling demo. Uninstalling extdemo. Installing extdemo. Have environment test-variable: foo zip_safe flag not set; analyzing archive contents... Installing checkenv. ...
setup.py还打印出我们已将环境变量test-variable设置为foo。在buildout之后,变量将重置为其原始值(即删除)。
在运行zc.recipe.egg:custom之前,如果环境变量具有值,则将恢复原始值。
>>> import os >>> os.environ['test-variable'] = 'bar' >>> print_(system(buildout), end='') Develop: '/sample-buildout/recipes' Updating extdemo. Updating checkenv. checkenv: test-variable left over: True>>> os.environ['test-variable'] 'bar'
有时需要向现有环境变量前缀或后缀,例如向PATH添加内容。因此,在设置之前,所有变量都通过os.environ进行插值。
>>> write(sample_buildout, 'buildout.cfg', ... """ ... [buildout] ... develop = recipes ... parts = extdemo checkenv ... ... [extdemo-env] ... test-variable = foo:%%(test-variable)s ... ... [extdemo] ... recipe = zc.recipe.egg:custom ... find-links = %(server)s ... index = %(server)s/index ... include-dirs = include ... environment = extdemo-env ... ... [checkenv] ... recipe = recipes:environ ... ... """ % dict(server=link_server)) >>> print_(system(buildout), end='') # doctest: +ELLIPSIS Develop: '/sample-buildout/recipes' Uninstalling extdemo. Installing extdemo. Have environment test-variable: foo:bar zip_safe flag not set; analyzing archive contents... Updating checkenv. ...>>> os.environ['test-variable'] 'bar' >>> del os.environ['test-variable']
创建一个没有checkenv配方的干净buildout.cfg,并删除配方
>>> write(sample_buildout, 'buildout.cfg', ... """ ... [buildout] ... develop = recipes ... parts = extdemo ... ... [extdemo] ... recipe = zc.recipe.egg:custom ... find-links = %(server)s ... index = %(server)s/index ... include-dirs = include ... ... """ % dict(server=link_server)) >>> print_(system(buildout), end='') # doctest: +ELLIPSIS Develop: '/sample-buildout/recipes' Uninstalling checkenv. Uninstalling extdemo. Installing extdemo...>>> rmdir(sample_buildout, 'recipes')
控制develop-egg生成
如果您想要为开发egg提供自定义构建选项,可以使用develop配方。该配方具有以下选项
- 设置
设置脚本或包含启动脚本的目录的路径。这是必需的。
- include-dirs
用于搜索包含文件的新行分隔的目录列表。
- library-dirs
用于搜索链接库的新行分隔的目录列表。
- rpath
运行时搜索动态库的新行分隔的目录列表。
- define
要定义的C预处理器变量名称的逗号分隔列表。
- undef
要取消定义的C预处理器变量名称的逗号分隔列表。
- libraries
要链接的额外库的名称。由于distutils的限制,尽管选项名称允许,但只能指定一个库。
- 链接对象
要链接的链接对象的名称。由于distutils的限制,尽管选项名称允许,但只能指定一个链接对象。
- 调试
编译/链接时包含调试信息
- 强制
强制构建所有内容(忽略文件时间戳)
- 编译器
指定编译器类型
- swig
swig可执行文件的路径
- swig-cpp
让SWIG创建C++文件(默认为C)
- swig-opts
SWIG命令行选项列表
为了说明这一点,我们将使用包含早期部分中extdemo示例的目录
>>> ls(extdemo) - MANIFEST - MANIFEST.in - README - extdemo.c - setup.py>>> write('buildout.cfg', ... """ ... [buildout] ... develop = demo ... parts = extdemo demo ... ... [extdemo] ... setup = %(extdemo)s ... recipe = zc.recipe.egg:develop ... include-dirs = include ... define = TWO ... ... [demo] ... recipe = zc.recipe.egg ... eggs = demo ... extdemo ... entry-points = demo=demo:main ... """ % dict(extdemo=extdemo))
请注意,我们添加了一个定义选项,以使预处理器变量TWO被定义。这将导致模块变量'val'被设置为2。
>>> print_(system(buildout), end='') # doctest: +ELLIPSIS Develop: '/sample-buildout/demo' Uninstalling extdemo. Installing extdemo. Installing demo. ...
我们的develop-eggs现在包括了extdemo的链接
>>> ls('develop-eggs') - demo.egg-link - extdemo.egg-link - zc.recipe.egg.egg-link
并且extdemo现在有一个构建的扩展
>>> contents = os.listdir(extdemo) >>> bool([f for f in contents if f.endswith('.so') or f.endswith('.pyd')]) True
由于develop eggs比非develop eggs具有优先权,因此demo脚本将使用新的develop egg
>>> print_(system(join('bin', 'demo')), end='') 2
其他配方的Egg Recipe API
对于配方来说,接受一组egg规范并基于结果的工作集生成脚本是很常见的。egg配方提供了一个API,其他配方可以使用。
一个配方可以通过在配方构造函数中创建一个egg配方实例来重用egg配方,支持eggs、find-links、index和extra-paths选项。这是通过在配方构造函数中创建一个egg配方实例来完成的。在配方的安装脚本中,使用egg-recipe实例的working_set方法来收集所需蛋和工作集。
为了说明,我们创建了一个围绕egg配方的非常薄的示例配方
>>> mkdir(sample_buildout, 'sample') >>> write(sample_buildout, 'sample', 'sample.py', ... """ ... import logging, os, sys ... import zc.recipe.egg ... ... def print_(*args): ... sys.stdout.write(' '.join(map(str, args)) + '\\n') ... ... class Sample: ... ... def __init__(self, buildout, name, options): ... self.egg = zc.recipe.egg.Scripts(buildout, name, options) ... self.name = name ... self.options = options ... ... def install(self): ... extras = self.options['extras'].split() ... requirements, ws = self.egg.working_set(extras) ... print_('Part:', self.name) ... print_('Egg requirements:') ... for r in requirements: ... print_(r) ... print_('Working set:') ... for d in ws: ... print_(d) ... print_('extra paths:', self.egg.extra_paths) ... return () ... ... update = install ... """)
在这里,我们在构造函数中实例化了egg配方,并将其保存到一个属性中。这也初始化了选项字典。
在我们的安装方法中,我们在保存的实例上调用working_set方法。working_set方法接受一个可选的额外要求序列,要包含在工作集中。
>>> write(sample_buildout, 'sample', 'setup.py', ... """ ... from setuptools import setup ... ... setup( ... name = "sample", ... entry_points = {'zc.buildout': ['default = sample:Sample']}, ... install_requires = 'zc.recipe.egg', ... ) ... """)>>> write(sample_buildout, 'sample', 'README.txt', " ")>>> write(sample_buildout, 'buildout.cfg', ... """ ... [buildout] ... develop = sample ... parts = sample-part ... ... [sample-part] ... recipe = sample ... eggs = demo<0.3 ... find-links = %(server)s ... index = %(server)sindex ... extras = other ... """ % dict(server=link_server))>>> import os >>> os.chdir(sample_buildout) >>> buildout = os.path.join(sample_buildout, 'bin', 'buildout') >>> print_(system(buildout + ' -q'), end='') Part: sample-part Egg requirements: demo<0.3 Working set: demoneeded 1.1 other 1.0 demo 0.2 extra paths: []
通过查看.installed.cfg,我们可以看到选项被egg配方计算出的额外数据所增强
>>> cat(sample_buildout, '.installed.cfg') [buildout] installed_develop_eggs = /sample-buildout/develop-eggs/sample.egg-link parts = sample-part <BLANKLINE> [sample-part] __buildout_installed__ = __buildout_signature__ = ... _b = /sample-buildout/bin _d = /sample-buildout/develop-eggs _e = /sample-buildout/eggs bin-directory = /sample-buildout/bin develop-eggs-directory = /sample-buildout/develop-eggs eggs = demo<0.3 eggs-directory = /sample-buildout/eggs extras = other find-links = https://127.0.0.1:27071/ index = https://127.0.0.1:27071/index recipe = sample
如果我们使用extra-paths选项
>>> write(sample_buildout, 'buildout.cfg', ... """ ... [buildout] ... develop = sample ... parts = sample-part ... ... [sample-part] ... recipe = sample ... eggs = demo<0.3 ... find-links = %(server)s ... index = %(server)sindex ... extras = other ... extra-paths = /foo/bar ... /spam/eggs ... """ % dict(server=link_server))
那么我们将在egg配方实例的extra_paths属性中看到这一点
>>> print_(system(buildout + ' -q'), end='') Part: sample-part Egg requirements: demo<0.3 Working set: demo 0.2 other 1.0 demoneeded 1.1 extra paths: ['/foo/bar', '/spam/eggs']
工作集缓存
工作集被缓存,以提高基于zc.recipe.egg的多个类似部分的构建的速度。
egg-recipe实例的_working_set辅助方法用于简化缓存。它与working_set()做同样的工作,但有一些不同
签名不同:构建工作集所需的所有信息都作为参数传递。
返回值更简单:仅返回pkg_resources.WorkingSet的实例。
这里是一个例子
>>> from zc.buildout import testing >>> from zc.recipe.egg.egg import Eggs >>> import os >>> import pkg_resources >>> recipe = Eggs(buildout=testing.Buildout(), name='fake-part', options={}) >>> eggs_dir = os.path.join(sample_buildout, 'eggs') >>> develop_eggs_dir = os.path.join(sample_buildout, 'develop-eggs') >>> testing.install_develop('zc.recipe.egg', develop_eggs_dir) >>> ws = recipe._working_set( ... distributions=['zc.recipe.egg', 'demo<0.3'], ... eggs_dir=eggs_dir, ... develop_eggs_dir=develop_eggs_dir, ... index=link_server, ... ) Getting... >>> isinstance(ws, pkg_resources.WorkingSet) True >>> sorted(dist.project_name for dist in ws) ['demo', 'demoneeded', 'setuptools', 'zc.buildout', 'zc.recipe.egg']
我们将修改easy_install模块中的一个方法,以验证缓存是否工作
>>> import zc.buildout.easy_install >>> old_install = zc.buildout.easy_install.Installer.install >>> def new_install(*args, **kwargs): ... print('Building working set.') ... return old_install(*args, **kwargs) >>> zc.buildout.easy_install.Installer.install = new_install
现在我们通过验证是否仅构建一次相同的工作集来检查缓存是否工作。
>>> ws_args_1 = dict( ... distributions=['demo>=0.1'], ... eggs_dir=eggs_dir, ... develop_eggs_dir=develop_eggs_dir, ... offline=True, ... ) >>> ws_args_2 = dict(ws_args_1) >>> ws_args_2['distributions'] = ['demoneeded'] >>> recipe._working_set(**ws_args_1) Building working set. <pkg_resources.WorkingSet object at ...> >>> recipe._working_set(**ws_args_1) <pkg_resources.WorkingSet object at ...> >>> recipe._working_set(**ws_args_2) Building working set. <pkg_resources.WorkingSet object at ...> >>> recipe._working_set(**ws_args_1) <pkg_resources.WorkingSet object at ...> >>> recipe._working_set(**ws_args_2) <pkg_resources.WorkingSet object at ...>
撤销monkey patch
>>> zc.buildout.easy_install.Installer.install = old_install
由于pkg_resources.WorkingSet实例是可变的,我们必须确保working_set()始终返回一个干净的副本。否则,调用者将能够修改缓存中的实例。
让我们创建一个工作集
>>> ws = recipe._working_set(**ws_args_1) >>> sorted(dist.project_name for dist in ws) ['demo', 'demoneeded']
现在我们向其中添加一个分布
>>> dist = pkg_resources.get_distribution('zc.recipe.egg') >>> ws.add(dist) >>> sorted(dist.project_name for dist in ws) ['demo', 'demoneeded', 'zc.recipe.egg']
让我们再次调用working_set函数,看看结果是否仍然有效
>>> ws = recipe._working_set(**ws_args_1) >>> sorted(dist.project_name for dist in ws) ['demo', 'demoneeded']
下载
项目详情
zc.recipe.egg-2.0.7.tar.gz的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | b89eb00979614e3584bb4e8431172b2345d00b983a04ebf00a401fb695f4e6d3 |
|
MD5 | b0d432087849dbe24a94edebbba29fe6 |
|
BLAKE2b-256 | 7a6fc6871e8490a153c3b44ac43e4a6552d802561a12b4780c7ea088a7ec5ff0 |