6. Distutils示例

注解

本文件仅保留至 setuptools https://setuptools.readthedocs.io/en/latest/setuptools.html上的文档独立地涵盖了此处当前包含的所有相关信息。

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

参见

Distutils Cookbook

显示如何对distuils实现更多控制的秘诀集合。

6.1. 纯Python分发(按模块)

如果您只是分发几个模块,特别是如果它们不存在于特定的包中,那么可以使用 py_modules 设置脚本中的选项。

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

<root>/
        setup.py
        foo.py

(在本节的所有图表中, <root> 将引用分发根目录。)描述此情况的最小安装脚本为:

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

请注意,分发的名称是用 name 选项,并且没有规则规定它必须与发行版中唯一模块的名称相同(尽管这可能是一个很好的约定)。但是,分发名称用于生成文件名,因此应使用字母、数字、下划线和连字符。

自从 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'],
      )

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

6.2. 纯Python分发(按包)

如果要分发多个模块,尤其是在多个包中,那么指定整个包而不是单个模块可能更容易。即使您的模块不在包中,也可以这样做;您只需告诉distuils从根包中处理模块,它的工作方式与任何其他包相同(除了您不需要 __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

这实际上是distuils所期望的默认布局,并且是安装脚本中描述的工作最少的布局:

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 not 扫描源代码树,通过查找 __init__.py 因此,如果默认布局增加子包:

<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

如果 foo 扩展名属于根包,其安装脚本可以是:

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

如果扩展名实际上属于一个包,那么说 foopkg 然后

使用完全相同的源码树布局,可以将此扩展放到 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) should be supplied

如果在 long_description 字段和 docutils 已安装。您可以检查语法是否符合 check 命令,使用 restructuredtext 选择权。

例如,如果 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='tarek@ziade.org',
    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() 函数提供了一个命令行接口,允许您通过 setup.py 给定项目的脚本:

$ python setup.py --name
distribute

此调用显示 name 通过运行 distutils.core.setup() 功能。但是,当使用distuils创建源或二进制分发时,元数据字段将写入名为 PKG-INFO . 当在python中安装基于distutils的项目时, PKG-INFO 文件与下面分发的模块和包一起复制 NAME-VERSION-pyX.X.egg-info 在哪里 NAME 是项目的名称, VERSION 元数据中定义的版本,以及 pyX.X 类似于python的主要和次要版本 2.73.2 .

通过使用 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'