Содержание страницы
6. Примеры использования Distutils¶Distutils Examples
Примечание
Этот документ сохраняется только до тех пор, пока setuptools документация
по адресу https://setuptools.readthedocs.io/en/latest/setuptools.html
не станет самостоятельно охватывать всю актуальную информацию, приведённую здесь.
Эта глава содержит несколько базовых примеров, которые помогут начать работу с distutils. Дополнительную информацию об использовании distutils можно найти в Distutils Cookbook.
См. также
- Кулинарная книга Distutils
Сборник рецептов, показывающих, как получить больше контроля над distutils.
6.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'],
)
Вы можете поместить исходные файлы модулей в другой каталог, но если у вас достаточно модулей для этого, вероятно, проще указывать модули по пакетам, а не перечислять их по отдельности.
6.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'],
)
6.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'])],
)
6.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
Если в поле long_description используется синтаксис reStructuredText и установлены 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. Чтение метаданных¶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'