Документация Python неофициальный перевод
Содержание страницы

7. ПримерыExamples

Эта глава содержит несколько базовых примеров, которые помогут начать работу с distutils. Дополнительную информацию об использовании distutils можно найти в Distutils Cookbook.

См. также

Кулинарная книга Distutils
Сборник рецептов, показывающих, как получить больше контроля над distutils.

7.1. Дистрибутив чистого Python (по модулям)Pure Python distribution (by module)

При распространении всего нескольких модулей, особенно если они не находятся в определённом пакете, их можно указать по отдельности с помощью параметра py_modules в скрипте setup.

В простейшем случае понадобятся два файла: скрипт setup и единственный распространяемый модуль foo.py в этом примере:

<root>/
        setup.py
        foo.py

(На всех схемах в этом разделе <root> обозначает корневой каталог дистрибутива.) Минимальный скрипт setup для описания этой ситуации будет выглядеть так:

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

Обратите внимание, что имя дистрибутива указывается независимо с помощью параметра name, и нет правила, что оно должно совпадать с именем единственного модуля в дистрибутиве (хотя это, вероятно, хорошее соглашение). Однако имя дистрибутива используется для генерации имён файлов, поэтому следует использовать только буквы, цифры, символы подчёркивания и дефисы.

Так как py_modules – это список, можно, конечно, указать несколько модулей, например, если распространяются модули foo и bar, то скрипт setup может выглядеть так:

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

а скрипт setup может быть таким:

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

Вы можете поместить исходные файлы модулей в другой каталог, но если у вас достаточно модулей для этого, вероятно, проще указывать модули по пакетам, а не перечислять их по отдельности.

7.2. Дистрибутив чистого Python (по пакетам)Pure Python distribution (by package)

Если нужно распространять более нескольких модулей, особенно если они находятся в нескольких пакетах, вероятно, проще указать целые пакеты, а не отдельные модули. Это работает даже если модули не находятся в пакете; можно просто указать Distutils обрабатывать модули из корневого пакета, и это работает так же, как с любым другим пакетом (за исключением того, что не нужно иметь файл __init__.py).

Скрипт setup из предыдущего примера можно также записать как

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=[''],
      )

Однако чаще требуется распространять несколько модулей в одном пакете (или в подпакетах). Например, если модули foo и bar принадлежат пакету foobar, один из способов организовать дерево исходных кодов – это

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

Фактически это стандартная структура, ожидаемая Distutils, и та, что требует наименьших усилий для описания в вашем скрипте setup:

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

соответствующий скрипт setup будет таким:

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

в этом случае скрипт setup будет таким:

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

(Пустая строка также обозначает текущий каталог.)

Если имеются подпакеты, они должны быть явно перечислены в packages, но любые записи в package_dir автоматически распространяются на подпакеты. (Другими словами, Distutils не сканирует дерево исходных кодов, пытаясь определить, какие каталоги соответствуют пакетам Python, по наличию файлов __init__.py.) Таким образом, если в стандартной структуре появляется подпакет:

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

тогда соответствующий скрипт setup будет таким:

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

7.3. Одиночный модуль расширенияSingle extension module

Модули расширения указываются с помощью параметра ext_modules. package_dir не влияет на то, где находятся исходные файлы расширений; он влияет только на исходники чистых модулей Python. Простейший случай – один модуль расширения в одном файле исходного кода на C:

<root>/
        setup.py
        foo.c

Если расширение foo принадлежит корневому пакету, скрипт setup для этого может быть таким:

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

7.4. Проверка пакетаChecking a package

Команда 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

Если используется синтаксис reStructuredText в поле 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.

7.5. Чтение метаданныхReading the metadata

Функция distutils.core.setup() предоставляет интерфейс командной строки, позволяющий запрашивать поля мета-информации проекта через скрипт setup.py заданного проекта:

$ python setup.py --name
distribute

Этот вызов считывает мета-информацию name, запуская функцию distutils.core.setup(). Однако, когда исходный или двоичный дистрибутив создаётся с помощью Distutils, поля мета-информации записываются в статический файл с именем PKG-INFO. Когда проект на основе Distutils устанавливается в Python, файл PKG-INFO копируется вместе с модулями и пакетами дистрибутива в каталог NAME-VERSION-pyX.X.egg-info, где NAME – имя проекта, VERSION – его версия, определённая в мета-информации, а pyX.X – major и minor версия Python, например, 2.7 или 3.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'