Практическое руководство по использованию setup.py

Оригинал статьи Rogier van der Geer: A Practical Guide to Using Setup.pyarrow-up-right от 25-03-2019.

Когда вы используете Python профессионально, выгодно настраивать свои проекты последовательно. Это поможет вашим соавторам быстро понять структуру проекта и упростит им настройку проекта на своей машине. Ключом к настройке вашего проекта является файл setup.py. В этом блоге я подробно расскажу об этом файле.

Где мы начинаем

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

Если вы следуете структуреarrow-up-right моего коллеги Хенка для вашего проекта, ваша начальная ситуация должна выглядеть примерно так:

example_project/
├── exampleproject/      Пакет Python с исходным кодом.
   ├── __init__.py      Сделайте папку пакетом.
   └── example.py       Пример модуля.
└── README.md            README с информацией о проекте.

В вашей структуре могут быть другие файлы или папки, например папки с именами notebooks/, tests/ или data/, но это не обязательно.

Случай для setup.py

После того, как вы создали такой пакет, вы, вероятно, использовать часть кода в других местах. Например, вы можете захотеть сделать это в блокноте:

from exampleproject.example import example_function

Это будет работать, если ваш текущий рабочий каталог - exampleproject/, но в во всех остальных случаях python выдаст такой вывод:

ModuleNotFoundError: No module named 'exampleproject'

Вы можете указать python, где искать пакет, установив переменную окружения PYTHONPATH или добавив пути к sys.path, но это далеко от идеала: потребуются разные действия на разных платформах, и путь, который вам нужно установить, зависит от местоположения вашего кода. Гораздо лучший способ - установить ваш пакет с помощью setup.py и pip, поскольку pip - это стандартный способ установки всех других пакетов, и он связан он работает одинаково на всех платформах.

Минимальный пример

Так как же выглядит файл setup.py? Вот минимальный пример [0]:

Здесь мы указываем три вещи:

  • Имя пакета name, которое будет использовать pip для вашего пакета. Это не обязательно должно совпадать с именем папки, в которой находится пакет, хотя, если это не так, это может сбить с толку. Пример того, где находится пакет имя и каталог не совпадают - Scikit-Learn: вы устанавливаете его используя pip install scikit-learn, но вы используете его путем импорта из sklearn.

  • Версия вашего пакета version. Это версия, которую сообщит pip, и она используется например, когда вы публикуете свой пакет на PyPIarrow-up-right [1].

  • Какие пакеты включать packages; в нашем случае это просто exampleproject/. Здесь мы позволяем setuptools понять это автоматически [2]. Хотя вы в принципе можете использовать find_packages () без каких-либо аргументов это может потенциально привести к тому, что нежелательные пакеты могут быть включены. Это может случиться, например, если вы включили __init__.py в свой каталог tests/. В качестве альтернативы вы также можете использовать аргумент exclude, чтобы явно предотвратить включение тестов в пакет, но это немного менее прочный.

Теперь все, что вам нужно сделать, чтобы установить ваш пакет, - это запустить следующий внутри каталога exampleproject/ [3]:

Здесь . относится к текущему рабочему каталогу, который, как я полагаю, является каталогом, в котором можно найти setup.py. Флаг -e указывает, что мы хотим установить в редактируемом режиме, что означает, что при редактировании файлов в нашем пакете нам не нужно переустанавливать пакет до того, как изменения вступят в силу. Вам нужно будет либо перезапустить python, либо перезагрузить пакет!

Когда вы редактируете информацию в самом файле setup.py, вам в большинстве случаев потребуется переустановить пакет, а также при добавлении новых (под)пакетов. Если есть сомнения, переустановка никогда не повредит. Просто запустите pip install -e . в очередной раз.

Requirements

У большинства проектов есть зависимости. Скорее всего, вы раньше использовали файл requirements.txtarrow-up-right или environment.ymlarrow-up-right, если используете conda. Теперь, когда вы создаете setup.py, вы можете указать свои зависимости в аргументе install_requires. Например, для типичного проекта по науке о данных у вас может быть:

Вы можете указать требования без версии (PyYAML), закрепить версию (pandas==0.23.3), указать минимальную версию (numpy>=1.14.5) или установить диапазон версий (matplotlib>=2.2.0, <3.0.0). Эти требования будут автоматически установлены pip при установке пакета.

Extras-require

Иногда у вас могут быть зависимости, которые требуются только в определенных ситуациях. Как специалист по данным, я часто создаю пакеты, которые использую для обучения модели. Когда я работаю над такой моделью в интерактивном режиме, мне может потребоваться установить matplotlib и jupyter для интерактивной работы с данными и создания визуализаций производительности модели. С другой стороны, если модель запускается в производственной среде, я не хочу устанавливать matplotlib или jupyter на машине (или контейнере), где я тренируюсь или делаю вывод. К счастью, setuptools позволяет указывать необязательные зависимости в extras_require:

Теперь, если мы установим пакет обычным образом (pip install example из PyPI или pip install -e . локально), он установит только зависимости PyYAML, pandas и numpy. Однако, когда мы укажем, что нам нужны дополнительные зависимости interactive (pip install example [interactive] или pip install -e . [interactive]), тогда также будут установлены matplotlib и jupyter.

Скрипты и точки входа

Основной вариант использования большинства пакетов Python, которые вы устанавливаете из PyPI, заключается в предоставлении функциональности, которая может использоваться в другом коде Python. Другими словами, вы можете импортировать из этих пакетов. Как специалист по данным, я часто делаю пакеты, которые не предназначены для использования другим кодом Python, но предназначены для чего-то, например, для обучения модели. Таким образом, у меня часто есть скрипт python, который я хочу выполнить из командной строки.

Лучший способ [4] раскрыть функциональность вашего пакета в командной строке - это определить точка входа как таковые:

Теперь вы можете использовать команду my-command из командной строки, которая, в свою очередь, выполнит функцию main внутри exampleproject/example.py. Не забудьте переустановить - иначе команда не будет зарегистрирована.

Тесты

Всякий раз, когда вы пишете какой-либо код, я настоятельно рекомендую вам также писать тесты для этого кода. Для тестирования с помощью python я предлагаю вам использовать pytest. Конечно, вы не хотите добавлять pytest к своим зависимостям в install_requires: это не требуется пользователям вашего пакета. Чтобы он устанавливался автоматически при запуске тестов, вы можете добавить в файл setup.py следующее:

Кроме того, вам необходимо создать файл с именем setup.cfg со следующим содержимым:

Теперь вы можете просто запустить python setup.py test, и setuptools обеспечит установку необходимых зависимостей и запустит pytest за вас! Посмотрите здесьarrow-up-right, если вы хотите предоставить аргументы или установить параметры конфигурации для pytest.

Если у вас есть дополнительные требования для тестирования (например, pytest-flask), вы можете добавить их в tests_require.

Flake8

Лично я считаю, что запустить Flake8arrow-up-right для проверки форматирования вашего кода - хорошая идея. Как и в случае с pytest, вы не хотите добавлять flake8 в зависимости install_requires: его не нужно устанавливать, чтобы использовать ваш пакет. Вместо этого вы можете добавить его в setup_requires:

Теперь вы можете просто запустить python setup.py flake8. Конечно, вы также можете закрепить версию flake8 (или любого другого пакета) в setup_requires.

Если вы хотите изменить некоторые параметры конфигурации Flake8, вы можете добавить раздел [flake8] в свой setup.cfg. Например:

Данные пакета

Иногда вы можете захотеть включить в свой пакет некоторые файлы, отличные от Python. Это могут быть, например, файлы схемы или небольшая таблица поиска. Имейте в виду, что такие файлы будут упакованы вместе с вашим кодом, поэтому, как правило, включать любые большие файлы - плохая идея.

Предположим, у нас есть schema.json в нашем проекте, который мы помещаем в exampleproject/data/schema.json. Если мы хотим включить это в наш пакет, мы должны использовать аргумент package_data в настройке:

Это гарантирует, что файл включен в пакет. Мы также можем включить все файлы на основе шаблона, например:

Это добавит все файлы *.json в любой встреченный пакет.

Теперь не пытайтесь самостоятельно определить расположение установленных файлов, поскольку pkg_resources имеет несколько очень удобных функций:

  • pkg_resources.resource_stream предоставит вам поток файла, очень похожий на объект, который вы получаете при вызове open (),

  • pkg_resources.resource_string предоставит вам содержимое файла в виде строки,

  • pkg_resources.resource_filename предоставит вам имя файла (и извлечет его во временное хранилище, если он включен в заархивированный пакет) на случай, если два указанных выше варианта не соответствуют вашим потребностям.

Например, мы можем читать в нашей схеме, используя:

Метаданные

Если вы собираетесь опубликовать свой пакет, вы, вероятно, захотите предоставить своим потенциальным пользователям дополнительную информацию о вашем пакете, включая описание, имя автора или сопровождающего и URL-адрес домашней страницы пакета. Вы можете найти полный список всех разрешенных метаданных в документацииarrow-up-right setuptools.

Кроме того, если вы собираетесь публиковать в PyPI, вы можете автоматически загрузить содержимое вашегоarrow-up-right README.md в long_description и предоставить классификаторыarrow-up-right classifiers, чтобы сообщить pip еще больше о вашем пакете.

Подведение итогов

Этот блог должен стать хорошей отправной точкой для настройки большинства ваших проектов на Python. Если вы хотите узнать больше о упаковке Python, загляните в документациюarrow-up-right. Вот пример setup.py, который объединяет все части, показанные в этом блоге:

и сопутствующий setup.cfg:

Совершенствуйте свои навыки Python, учитесь у экспертов!

В GoDataDriven мы предлагаем множество курсов Python от новичка до эксперта, которые проводят лучшие профессионалы в этой области. Присоединяйтесь к нам и повышайте уровень своей игры на Python:

Сноски

  • [0] - В этом блоге я использовал setuptoolsarrow-up-right для создания моего примера проекта. В качестве альтернативы вы также можете использовать distutilsarrow-up-right, который является стандартным инструментом для упаковки в python, но в нем отсутствуют такие функции, как функция find_packages () и entry_points. Поскольку использование setuptools в настоящее время очень распространено, и многие из его функций могут быть особенно полезными, я предлагаю вам использовать setuptools.

  • [1] - Если вы хотите, чтобы версия вашего пакета также была доступна внутри python, загляните сюдаarrow-up-right.

  • [2] - Вы также можете перечислить свои пакеты вручную, но это особенно подвержено ошибкам.

  • [3] - В качестве альтернативы вы можете запустить python setup.py install, но при использовании pip множество преимуществ, среди которых автоматическая установка зависимостей и возможность удалить или обновить ваш пакет.

  • [4] - Вы также можете использовать аргумент scripts (см., например, здесьarrow-up-right), но поскольку для этого требуется создать сценарий оболочки Python, он может не работать (или вообще) в Windows.

Last updated