Настройка setup.py для Python-пакетов: основы и продвинутые техники
Для кого эта статья:
- Python-разработчики, желающие углубить знания в упаковке и распространении библиотек.
- Новички в Python, стремящиеся понять основы создания собственных пакетов.
Программисты, ищущие практические советы по управлению зависимостями и проектами в Python.
За кулисами каждого качественного Python-пакета скрывается неприметный, но исключительно мощный инструмент — файл
setup.py. Этот файл, словно дирижёр оркестра, управляет всем процессом распространения и установки вашего кода. Если вы задумывались, почему некоторые проекты устанавливаются гладко одной командойpip, а другие требуют сложных манипуляций, ответ кроется именно в правильной настройкеsetup.py. Давайте раскроем секреты этого файла и научимся использовать его возможности на полную мощность. 🐍
Хотите не просто понимать, но и мастерски использовать инструменты профессиональной Python-разработки? Курс Обучение Python-разработке от Skypro погружает вас в экосистему Python от базовых концепций до создания собственных пакетов с правильной структурой и
setup.py. Вы не только изучите теорию, но и создадите несколько реальных проектов под руководством действующих разработчиков, готовых поделиться инсайдерскими хитростями.
Назначение setup.py в экосистеме Python
Файл setup.py — это сердце дистрибуции Python-пакетов, выполняющее несколько критических функций в экосистеме Python. Прежде всего, он служит интерфейсом между вашим кодом и инструментами установки, такими как pip, предоставляя необходимые метаданные и инструкции для корректной интеграции вашего пакета в Python-окружение. 📦
Ключевые функции setup.py:
- Определение метаданных пакета (имя, версия, автор, лицензия)
- Указание зависимостей, необходимых для работы пакета
- Настройка процесса установки и сборки пакета
- Определение точек входа (entry points) для консольных утилит
- Управление включаемыми файлами и ресурсами
setup.py взаимодействует с несколькими важными компонентами экосистемы Python:
| Компонент | Взаимодействие с setup.py | Значение |
|---|---|---|
| pip | Читает setup.py для установки пакета | Основной способ распространения пакетов |
| PyPI | Использует метаданные из setup.py | Хранилище и каталог пакетов |
| setuptools | Обрабатывает команды setup.py | Библиотека для создания и распространения |
| wheel | Создает бинарные дистрибутивы | Ускоряет установку пакетов |
| virtualenv | Изолирует установку пакетов | Предотвращает конфликты зависимостей |
Исторически setup.py появился как часть дистрибутива Python для стандартизации процесса распространения кода. До его появления установка пакетов представляла собой не более чем копирование файлов в директорию сайт-пакетов Python — подход, порождавший хаос и конфликты зависимостей. 🕰️
Михаил Гордеев, Python-разработчик с 12-летним стажем
Помню свой первый коммерческий проект на Python в 2011 году. Я поставил перед собой амбициозную задачу — создать библиотеку для обработки финансовых данных, которой могли бы пользоваться мои коллеги. Код работал отлично на моей машине, но когда я поделился им с командой, начался кошмар. Один разработчик не мог импортировать модули, у другого падали тесты, третий жаловался на недостающие зависимости.
Я потратил почти неделю, пытаясь разобраться в причинах, пока не осознал, что проблема в отсутствии правильно настроенного
setup.py. После того, как я добавил этот файл, описав все зависимости и структуру пакета, установка стала выполняться одной командойpip, а библиотека заработала идентично на всех машинах. Именно тогда я понял, насколько важен этот маленький файл для профессиональной разработки на Python.
Сегодня setup.py — стандарт de facto для дистрибуции Python-пакетов, хотя в последние годы появились альтернативы вроде pyproject.toml (PEP 517/518). Однако понимание setup.py остаётся фундаментальным навыком для любого серьёзного Python-разработчика.

Структура и ключевые параметры файла setup.py
Структура файла setup.py чрезвычайно гибкая, но в своей основе следует определённому шаблону. Центральным элементом является вызов функции setup() из пакета setuptools (исторически из distutils, но сегодня рекомендуется использовать именно setuptools). Эта функция принимает множество именованных параметров, определяющих все аспекты вашего пакета. 🧩
Базовый шаблон setup.py выглядит следующим образом:
from setuptools import setup, find_packages
setup(
name="my_package",
version="0.1.0",
author="Имя Автора",
author_email="author@example.com",
description="Краткое описание пакета",
long_description=open("README.md").read(),
long_description_content_type="text/markdown",
url="https://github.com/username/my_package",
packages=find_packages(),
classifiers=[
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
],
python_requires=">=3.6",
)
Ключевые параметры функции setup() можно разделить на несколько категорий:
| Категория | Параметры | Назначение |
|---|---|---|
| Основные метаданные | name | Имя пакета, используемое при установке через pip |
version | Версия пакета (рекомендуется semantic versioning) | |
description, long_description | Краткое и полное описание пакета | |
url | Ссылка на репозиторий или документацию | |
| Автор и лицензия | author, author_email | Контактная информация создателя |
license | Лицензия распространения кода | |
classifiers | Стандартизированные метки для каталогизации пакета | |
| Структура пакета | packages | Список модулей для включения в пакет |
package_data | Не-Python файлы, включаемые в пакет | |
exclude_package_data | Файлы, исключаемые из пакета | |
| Зависимости | install_requires | Список зависимостей для работы пакета |
extras_require | Опциональные зависимости для дополнительных функций | |
python_requires | Минимальная версия Python | |
| Дополнительно | entry_points | Определение команд консоли и интеграций |
zip_safe | Можно ли устанавливать пакет как zip-архив |
Особое внимание стоит уделить параметру packages. В простейшем случае можно указать список модулей вручную, но для больших проектов удобнее использовать функцию find_packages(), которая автоматически находит все пакеты в проекте:
packages=find_packages(include=['mypackage', 'mypackage.*'])
Параметр classifiers заслуживает отдельного упоминания. Классификаторы — стандартизированные метки, используемые PyPI для каталогизации пакетов. Они помогают пользователям находить ваш пакет и понимать его совместимость. Полный список допустимых классификаторов доступен на сайте PyPI. 🏷️
Создание и настройка Python-пакета через setup.py
Создание Python-пакета с использованием setup.py требует не только написания самого конфигурационного файла, но и соблюдения определённой структуры проекта. Правильно организованный пакет позволяет пользователям легко устанавливать, обновлять и использовать ваш код. 📚
Типичная структура проекта с использованием setup.py выглядит так:
my_package/
├── README.md
├── LICENSE
├── setup.py
├── my_package/
│ ├── __init__.py
│ ├── module1.py
│ ├── module2.py
│ └── subpackage/
│ ├── __init__.py
│ └── module3.py
└── tests/
├── __init__.py
├── test_module1.py
└── test_module2.py
Обратите внимание на несколько ключевых особенностей:
- Внешняя директория (
my_package) — корневая директория проекта, где размещаетсяsetup.py - Вложенная директория с тем же именем (
my_package/) — это собственно пакет, который будет установлен - Файл
__init__.pyвнутри пакета делает директорию пакетом Python - Тесты обычно выносятся в отдельную директорию
Рассмотрим шаги создания нового пакета с использованием setup.py:
- Создайте структуру директорий как указано выше.
- Напишите код вашего пакета внутри директории
my_package/. - Создайте файл
__init__.pyвнутри пакета. Этот файл может быть пустым, но обычно содержит импорты основных классов и функций для удобства использования. - Напишите
README.mdс описанием пакета, инструкциями по установке и базовыми примерами использования. - Создайте файл
setup.pyв корне проекта, включив все необходимые метаданные. - Протестируйте установку локально с помощью команды
pip install -e .в директории сsetup.py. - При необходимости создайте дистрибутив командой
python setup.py sdist bdist_wheel. - Опубликуйте пакет на PyPI с помощью
twine:twine upload dist/*.
Ключевым моментом при создании пакета является правильное определение его границ. Что должно входить в пакет, а что стоит оставить вне его? Вот несколько принципов:
- Включайте в пакет только модули, необходимые для его работы
- Тесты, примеры и документацию не включайте в пакет (но держите в репозитории)
- Внимательно продумывайте публичный API вашего пакета — какие модули, классы и функции доступны пользователям
- Следуйте принципу "бритвы Оккама": пакет должен делать одну вещь, но делать её хорошо
Алексей Чернов, DevOps-инженер
В нашей компании мы столкнулись с проблемой: команды писали повторяющийся код для работы с внутренними API. Каждая группа разработчиков копировала и модифицировала один и тот же код, что приводило к несогласованности и сложностям в поддержке.
Я предложил создать внутренний Python-пакет. Сначала разработчики сопротивлялись — казалось, что это лишняя работа. Но когда мы построили первую версию пакета с правильным
setup.py, настроили внутренний PyPI-сервер и показали, как легко установить пакет черезpip, отношение изменилось.Ключевым фактором успеха стала именно структура пакета и хорошо написанный
setup.py. Мы организовали код в логические модули, добавили автоматическую версионность, настроили зависимости, и обеспечили обратную совместимость. Через три месяца все команды перешли на использование пакета, а количество дублирующего кода сократилось на 78%. Когда нам нужно было обновить логику работы с API, достаточно было выпустить новую версию пакета — и все команды получали обновление одной командойpip.
Для динамической настройки пакетов setup.py позволяет использовать полную мощь Python. Например, можно определять версию пакета автоматически из файла или тега git, динамически генерировать список файлов или настраивать процесс сборки в зависимости от платформы. 🔄
Управление зависимостями проекта в setup.py
Управление зависимостями — одна из ключевых функций setup.py. Правильная конфигурация зависимостей обеспечивает корректную работу вашего пакета в различных окружениях и предотвращает конфликты версий библиотек. 🔗
В setup.py существует несколько механизмов для указания зависимостей:
install_requires— основные зависимости, необходимые для работы пакетаextras_require— опциональные зависимости для дополнительного функционалаsetup_requires— зависимости, необходимые для процесса установки (устаревший)tests_require— зависимости для запуска тестов (устаревший)
Рассмотрим, как правильно использовать эти механизмы. Начнем с install_requires — основного списка зависимостей:
setup(
# ... другие параметры
install_requires=[
'requests>=2.25.0,<3.0.0',
'numpy>=1.19.0',
'pandas~=1.2.0',
],
)
Обратите внимание на различные способы указания версий:
requests>=2.25.0,<3.0.0— требуется версия не ниже 2.25.0, но меньше 3.0.0numpy>=1.19.0— требуется версия не ниже 1.19.0 (любая более новая подойдет)pandas~=1.2.0— совместимая версия (не ниже 1.2.0, но меньше 1.3.0)
Для опциональных зависимостей используйте extras_require. Этот механизм позволяет пользователям устанавливать только те дополнительные библиотеки, которые им нужны:
setup(
# ... другие параметры
extras_require={
'dev': [
'pytest>=6.0.0',
'flake8>=3.8.0',
'mypy>=0.800',
],
'docs': [
'sphinx>=3.4.0',
'sphinx-rtd-theme>=0.5.0',
],
'performance': [
'numba>=0.52.0',
'cython>=0.29.21',
],
},
)
Теперь пользователи могут устанавливать пакет с дополнительными зависимостями:
pip install mypackage[dev] # Установка с инструментами разработки
pip install mypackage[docs,performance] # Установка с зависимостями для документации и производительности
При указании зависимостей следует соблюдать баланс между точностью требований к версиям и гибкостью. Слишком строгие требования могут вызвать конфликты с другими пакетами, а слишком свободные — привести к несовместимости.
| Спецификатор | Пример | Значение | Рекомендуемое использование |
|---|---|---|---|
| == | requests==2.25.1 | Точная версия | Только при критической зависимости от конкретной версии |
| >= | requests>=2.25.0 | Минимальная версия | Когда нужна определённая функциональность, появившаяся в указанной версии |
| <= | requests<=2.30.0 | Максимальная версия | При известной несовместимости с более новыми версиями |
| ~= | requests~=2.25.0 | Совместимая версия (>= 2.25.0, < 2.26.0) | Рекомендуется для большинства зависимостей |
| Комбинация | requests>=2.25.0,<3.0.0 | Диапазон версий | Для точного контроля допустимого диапазона |
Важно также различать зависимости разработки и производственные зависимости. Инструменты для тестирования, анализа кода и документирования не должны попадать в install_requires — их место в extras_require. 🧰
При обновлении вашего пакета следует внимательно относиться к изменению требований к зависимостям. Если вы повышаете минимальную требуемую версию библиотеки, это может быть воспринято как breaking change, особенно если новая версия несовместима со старыми системами или окружениями.
Практическое применение setup.py в разработке
Файл setup.py — не просто инструмент для публикации пакетов на PyPI. Он обладает широким спектром практических применений в повседневной разработке, упрощая множество задач и автоматизируя рутинные процессы. 🛠️
Рассмотрим несколько практических сценариев использования setup.py:
- Локальная разработка в редактируемом режиме
При разработке пакета чрезвычайно удобно устанавливать его в "редактируемом режиме". Это позволяет вносить изменения в код и немедленно видеть результат без переустановки:
pip install -e .
Эта команда создаёт символическую ссылку на вашу директорию разработки, вместо копирования файлов. Любые изменения в коде сразу становятся доступны при импорте пакета.
- Создание консольных скриптов (CLI)
setup.py позволяет определять точки входа (entry points) для создания консольных утилит, которые будут установлены вместе с вашим пакетом:
setup(
# ... другие параметры
entry_points={
'console_scripts': [
'my-cool-tool=mypackage.cli:main',
],
},
)
После установки такого пакета пользователь получает команду my-cool-tool в своём окружении, которая вызывает функцию main() из модуля mypackage.cli.
- Создание и публикация дистрибутивов
setup.py используется для создания дистрибутивов пакета в форматах source distribution (.tar.gz) и wheel (.whl):
python setup.py sdist bdist_wheel
Созданные дистрибутивы можно опубликовать на PyPI с помощью twine:
twine upload dist/*
- Определение пользовательских команд
Вы можете расширить setuptools, добавив собственные команды для выполнения специфических задач разработки:
from setuptools import setup, Command
class CleanCommand(Command):
"""Пользовательская команда для очистки директории от сгенерированных файлов."""
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
import os
import shutil
# Удаляем директории сборки
for dir_to_remove in ['build', 'dist', '*.egg-info']:
try:
shutil.rmtree(dir_to_remove)
except FileNotFoundError:
pass
# Удаляем Python кеш-файлы
for root, dirs, files in os.walk('.'):
for file in files:
if file.endswith('.pyc'):
os.remove(os.path.join(root, file))
for dir_ in dirs:
if dir_ == '__pycache__':
shutil.rmtree(os.path.join(root, dir_))
setup(
# ... другие параметры
cmdclass={
'clean': CleanCommand,
},
)
Теперь пользователи могут выполнить команду python setup.py clean для очистки проекта от временных файлов.
- Интеграция C/C++ расширений
Для высокопроизводительных вычислений часто требуется интегрировать код на C/C++. setup.py предоставляет механизм для компиляции и связывания таких расширений:
from setuptools import setup, Extension
# Определение модуля C-расширения
module = Extension('mypackage.fast_algorithms',
sources=['src/fast_algorithms.c'],
include_dirs=['include'],
libraries=['some_lib'])
setup(
# ... другие параметры
ext_modules=[module],
)
При установке такого пакета setuptools автоматически скомпилирует C-код и создаст бинарный модуль, который можно импортировать из Python.
Практические рекомендации по использованию setup.py:
- Всегда используйте
setuptoolsвместо устаревшегоdistutils - Выносите длинное описание в
README.mdи читайте его изsetup.py - Храните версию пакета в одном месте (например, в
__version__внутри пакета) - Используйте семантическое версионирование (MAJOR.MINOR.PATCH)
- Проверяйте ваш
setup.py, создавая тестовую установку в чистом виртуальном окружении - Не забывайте обновлять список зависимостей при добавлении новых импортов
- Документируйте требования к установке и опциональные возможности
Современные тренды в экосистеме Python склоняются к использованию pyproject.toml вместо setup.py (согласно PEP 517/518), но setup.py остаётся широко распространённым и полностью поддерживаемым решением. Многие проекты используют гибридный подход, комбинируя оба файла для максимальной совместимости. 🔄
Освоив
setup.py, вы получаете не просто техническое знание, а ключ к профессиональному управлению Python-проектами. Этот файл — граница между любительским кодом и профессиональными пакетами, которые можно распространять, поддерживать и развивать. Помните, что хорошо структурированный пакет с правильно настроеннымsetup.py— это проявление уважения к пользователям вашего кода и инвестиция в его долгосрочную жизнеспособность.