6. Приклади Distutils¶
Примітка
Цей документ зберігається лише до тих пір, поки документація setuptools
за адресою https://setuptools.readthedocs.io/en/latest/setuptools.html окремо не охопить всю відповідну інформацію, яка зараз включена тут.
У цьому розділі наведено низку основних прикладів, які допоможуть розпочати роботу з distutils. Додаткову інформацію про використання distutils можна знайти в кулінарній книзі Distutils.
Дивись також
- Кулінарна книга Distutils
Збірка рецептів, які показують, як досягти більшого контролю над distutils.
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
є списком, ви, звичайно, можете вказати декілька модулів, наприклад. якщо ви розповсюджуєте модулі 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. Чистий дистрибутив 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=[''],
)
Однак зазвичай ви захочете поширювати кілька модулів в одному пакеті (або в підпакетах). Наприклад, якщо модулі foo
і bar
належать до пакета 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 не сканує ваше дерево вихідних кодів, намагаючись з’ясувати, які каталоги відповідають пакетам 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
. Коли проект на основі Distutils інстальовано в Python, файл 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'