6. Distutils Examples

Note

该文档将一直保留,直到https://setuptools.readthedocs.io/en/latest/setuptools.htmlsetuptools文档独立涵盖了此处当前包括的所有相关信息。

本章提供了一些基本示例,以帮助您开始使用 distutils。有关使用 distutils 的其他信息,请参见 Distutils Cookbook。

See also

6.1. 纯 Python 发行版(按模块)

如果您只是分发几个模块,特别是如果它们不位于特定软件包中,则可以使用安装脚本中的py_modules选项分别指定它们。

在最简单的情况下,您需要担心两个文件:安装脚本和要分发的单个模块,在此示例中为foo.py

<root>/
        setup.py
        foo.py

(在本节中的所有图中,* *表示分发根目录.)描述这种情况的最小安装脚本为:

from distutils.core import setup
setup(name='foo',
      version='1.0',
      py_modules=['foo'],
      )

请注意,发行版的名称是passname选项独立指定的,没有规则说该名称必须与发行版中唯一模块的名称相同(尽管遵循的惯例可能不错)。但是,分发名称用于生成文件名,因此您应坚持字母,数字,下划线和连字符。

由于py_modules是列表,因此您当然可以指定多个模块,例如。如果您要分配模块foobar,则设置可能如下所示:

<root>/
        setup.py
        foo.py
        bar.py

并且安装脚本可能是

from distutils.core import setup
setup(name='foobar',
      version='1.0',
      py_modules=['foo', 'bar'],
      )

您可以将模块源文件放在另一个目录中,但是如果您有足够的模块来执行此操作,则pass包指定模块而不是单独列出它们可能会更容易。

6.2. 纯 Python 发行版(按软件包)

如果要分发多个模块,尤其是当它们位于多个软件包中时,则指定整个软件包而不是单个模块可能会更容易。即使您的模块不在包装中,此方法仍然有效。您只需告诉 Distutils 处理根软件包中的模块即可,它的工作原理与任何其他软件包相同(除了不必具有__init__.py文件)。

最后一个示例中的安装脚本也可以写成

from distutils.core import setup
setup(name='foobar',
      version='1.0',
      packages=[''],
      )

(空字符串代表根包.)

如果将这两个文件移到一个子目录中,但仍保留在根包中,例如:

<root>/
        setup.py
        src/      foo.py
                  bar.py

那么您仍将指定根软件包,但是必须告诉 Distutils 根软件包中的源文件在何处:

from distutils.core import setup
setup(name='foobar',
      version='1.0',
      package_dir={'': 'src'},
      packages=[''],
      )

但是,更典型的情况是,您将希望在同一程序包(或子程序包)中分发多个模块。例如,如果foobar模块属于软件包foobar,则布局源树的一种方法是

<root>/
        setup.py
        foobar/
                 __init__.py
                 foo.py
                 bar.py

实际上,这是 Distutils 期望的默认布局,并且它需要最少的工作来在安装脚本中进行描述:

from distutils.core import setup
setup(name='foobar',
      version='1.0',
      packages=['foobar'],
      )

如果要将模块放在未为其包命名的目录中,则需要再次使用package_dir选项。例如,如果src目录在foobar程序包中包含模块:

<root>/
        setup.py
        src/
                 __init__.py
                 foo.py
                 bar.py

一个合适的安装脚本是

from distutils.core import setup
setup(name='foobar',
      version='1.0',
      package_dir={'foobar': 'src'},
      packages=['foobar'],
      )

或者,您可以将主包中的模块放在分发根目录中:

<root>/
        setup.py
        __init__.py
        foo.py
        bar.py

在这种情况下,您的安装脚本将是

from distutils.core import setup
setup(name='foobar',
      version='1.0',
      package_dir={'foobar': ''},
      packages=['foobar'],
      )

(空字符串也代表当前目录.)

如果您有子软件包,则必须在packages中明确列出它们,但是package_dir中的所有条目都会自动扩展到子软件包。 (换句话说,Distutils 不会*扫描您的源代码树,而是pass查找__init__.py文件来找出与 Python 包相对应的目录.)因此,如果默认布局增加了一个子包:

<root>/
        setup.py
        foobar/
                 __init__.py
                 foo.py
                 bar.py
                 subfoo/
                           __init__.py
                           blah.py

那么相应的设置脚本将是

from distutils.core import setup
setup(name='foobar',
      version='1.0',
      packages=['foobar', 'foobar.subfoo'],
      )

6.3. 单扩展模块

扩展模块使用ext_modules选项指定。 package_dir对在哪里找到扩展源文件没有影响;它只会影响纯 Python 模块的源代码。最简单的情况是单个 C 源文件中的单个扩展模块是:

<root>/
        setup.py
        foo.c

如果fooextensions 属于根软件包,则此安装脚本可能是

from distutils.core import setup
from distutils.extension import Extension
setup(name='foobar',
      version='1.0',
      ext_modules=[Extension('foo', ['foo.c'])],
      )

如果 extensions 实际上属于某个包,请说foopkg,然后

使用完全相同的源树布局,只需更改 extensions 即可将该扩展放入foopkg包中:

from distutils.core import setup
from distutils.extension import Extension
setup(name='foobar',
      version='1.0',
      ext_modules=[Extension('foopkg.foo', ['foo.c'])],
      )

6.4. 检查包裹

check命令允许您验证软件包元数据是否满足构建发行版的最低要求。

要运行它,只需使用您的setup.py脚本进行调用。如果缺少某些内容,check将显示警告。

让我们以一个简单的脚本为例:

from distutils.core import setup

setup(name='foobar')

运行check命令将显示一些警告:

$ python setup.py check
running check
warning: check: missing required meta-data: version, url
warning: check: missing meta-data: either (author and author_email) or
         (maintainer and maintainer_email) must be supplied

如果在long_description字段中使用 reStructuredText 语法并且已安装docutils,则可以使用restructuredtext选项使用check命令检查语法是否正确。

例如,如果像这样更改setup.py脚本:

from distutils.core import setup

desc = """\
My description
==============

This is the description of the ``foobar`` package.
"""

setup(name='foobar', version='1', author='tarek',
    author_email='[email protected]',
    url='http://example.com', long_description=desc)

如果长说明不完整,则check将能够使用docutils解析器对其进行检测:

$ python setup.py check --restructuredtext
running check
warning: check: Title underline too short. (line 2)
warning: check: Could not finish the parsing.

6.5. 读取元数据

distutils.core.setup()函数提供了一个命令行界面,使您可以pass给定项目的setup.py脚本查询项目的元数据字段:

$ python setup.py --name
distribute

该调用pass运行distutils.core.setup()函数读取name元数据。虽然,当使用 Distutils 创建源或二进制发行版时,元数据字段被写入称为PKG-INFO的静态文件中。当在 Python 中安装基于 Distutils 的项目时,PKG-INFO文件将与分发的模块和软件包一起在NAME-VERSION-pyX.X.egg-info下复制,其中NAME是项目的名称,VERSION是其在元数据中定义的版本,而pyX.X是主要和诸如2.73.2的 Python 的次要版本。

您可以使用distutils.dist.DistributionMetadata类及其read_pkg_file()方法来读回此静态文件:

>>> from distutils.dist import DistributionMetadata
>>> metadata = DistributionMetadata()
>>> metadata.read_pkg_file(open('distribute-0.6.8-py2.7.egg-info'))
>>> metadata.name
'distribute'
>>> metadata.version
'0.6.8'
>>> metadata.description
'Easily download, build, install, upgrade, and uninstall Python packages'

注意,也可以使用元数据文件路径实例化该类以加载其值:

>>> pkg_info_path = 'distribute-0.6.8-py2.7.egg-info'
>>> DistributionMetadata(pkg_info_path).name
'distribute'