6. Примеры дистрибутивов¶
Примечание
Этот документ будет храниться только до тех пор, пока в документации setuptools
по адресу https://setuptools.readthedocs.io/en/latest/setuptools.html самостоятельно не будет представлена вся соответствующая информация, которая в настоящее время включена в этот документ.
В этой главе приведен ряд основных примеров, которые помогут начать работу с distutils. Дополнительную информацию об использовании distutils можно найти в книге Distutils Cookbook.
См.также
- Distutils Cookbook
Коллекция рецептов, показывающих, как добиться большего контроля над дистрибутивами.
6.1. Дистрибутив Pure 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
- это список, вы, конечно, можете указать несколько модулей, например, если вы распространяете модули foo
и bar
, ваша настройка может выглядеть следующим образом:
<root>/
setup.py
foo.py
bar.py
и сценарий установки может быть следующим
from distutils.core import setup
setup(name='foobar',
version='1.0',
py_modules=['foo', 'bar'],
)
Вы можете поместить исходные файлы модулей в другой каталог, но если у вас достаточно модулей для этого, вероятно, проще указать модули по пакетам, а не перечислять их по отдельности.
6.2. Дистрибутив Pure Python (по пакетам)¶
Если у вас есть несколько модулей для распространения, особенно если они находятся в нескольких пакетах, вероятно, проще указать целые пакеты, а не отдельные модули. Это работает, даже если ваши модули не находятся в пакете; вы можете просто указать Distutils обрабатывать модули из корневого пакета, и это работает так же, как и любой другой пакет (за исключением того, что вам не обязательно иметь файл __init__.py
).
Сценарий установки из последнего примера также можно было бы записать следующим образом
from distutils.core import setup
setup(name='foobar',
version='1.0',
packages=[''],
)
(Пустая строка обозначает корневой пакет.)
Если эти два файла перемещены в подкаталог, но остаются в корневом пакете, например:
<root>/
setup.py
src/ foo.py
bar.py
тогда вы все равно указали бы корневой пакет, но вы должны указать дистрибутивам, где находятся исходные файлы в корневом пакете:
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
На самом деле это макет по умолчанию, ожидаемый дистрибутивами, и тот, который требует наименьших усилий для описания в вашем сценарии установки:
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 не сканирует ваше дерево исходных текстов, пытаясь выяснить, какие каталоги соответствуют пакетам Python, путем поиска файлов __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
Если вы используете синтаксис 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.
6.5. Чтение метаданных¶
Функция distutils.core.setup()
предоставляет интерфейс командной строки, который позволяет запрашивать поля метаданных проекта с помощью setup.py
скрипта данного проекта:
$ python setup.py --name
distribute
Этот вызов считывает метаданные name
, запуская функцию distutils.core.setup()
. Хотя, когда исходный код или двоичный дистрибутив создается с помощью Distutils, поля метаданных записываются в статический файл с именем PKG-INFO
. Когда на Python устанавливается проект, основанный на Distutils, файл PKG-INFO
копируется вместе с модулями и пакетами дистрибутива в раздел NAME-VERSION-pyX.X.egg-info
, где NAME
- это название проекта, VERSION
его версия, определенная в метаданных, и pyX.X
основная и второстепенные версии 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'