entry points console scripts

Одна из действительно полезных вещей в python — это система скриптов установки. Любой, серьезно увлекающийся python-программированием разработчик рано или поздно сталкивается с ней. Но из-за гибкости инструментария скриптов установки, их документация весьма раздута. На текущий момент имеется набор утилит (setuptools, distutils, distribute) выполняющих одинаковые задачи.

В данной статье я на конкретных примерах покажу как создать и настроить простой python-пакет.

Наш проект будет иметь следующую функциональность:

  • Метод возвращающий строку: «Hello World!»;
  • Команда helloworld печатающая эту строку в стандартный вывод.

Создаем структуру проекта

Для начала создадим директорию для пакета. Ее минимальный набор файлов состоит из: файла дистрибьюции ( setup.py ) описывающего метаданные и python кода проекта (в нашем случае модуля helloworld).

Также, xорошим тоном считается создание в корне директории файла с описанием проекта: README.txt .

Получаем следующую структуру:

Наша корневая директория helloworld-project будет содержать мета-данные пакета и вспомогательные файлы (тесты, лицензию, документацию и т.д.), а поддиректория helloworld непосредственно сам модуль helloworld .

Теперь отредактируем файл: helloworld/core.py и добавим логику нашего приложения (получение и вывод строки «Hello World!»):

Редактируем мета-информацию (setup.py)

Заполним файл описания README.rst :

Теперь отредактируем файл setup.py :

Убедитесь, что в вашей системе доступны setuptools, в противном случае установите python-пакет distribute

Этих операций достаточно, чтобы собрать пакет дистрибьюции. Выполните команду сборки:

В случае успеха вы получите файл: dist/helloworld-1.0.tar.gz . Это полноценный, архивированный python-пакет и вы можете распространять его среди прочих разработчиков.

Виртуальное окружение

Virtualenv — пакет применяемый для создания изолированного python-окружения. Используем его для тестирования нашего проекта.

Создадим окружение env:

Команда создаст директорию env внутри нашего проекта и установит туда python, pip и distribute. Произведем в него установку нашего проекта.

И протестируем его работоспособность:

Все работает. Осталось добавить поддержку команды helloworld в консоли.

Создание команд

Для создания команды helloworld изменим файл setup.py :

В параметре entry_points мы задаем словарь с «точками вызова» нашего приложения. Ключ console_scripts задает список создаваемых исполняемых скриптов (в Windows это будут exe-файлы). В данном случае мы указали создание исполняемого скрипта helloworld при вызове которого будет запускаться метод print_message из модуля helloworld.core.

Переустановим модуль в наше окружение и проверим работу созданного скрипта (для этого прийдется активировать наше окружение):

Похоже все работает.

Работа с версиями

Номер версии важная часть любого проекта. От него зависит обновление пакетов и разрешение зависимостей. В примере выше мы указали номер версии 1.0 в файле setup.py . Более правильное решение перенести его в файл helloworld/__init__.py чтобы сделать доступным в python-коде. По существующим соглашения для хранения номера версии в модуле, используется переменная __version__.

Изменим файл setup.py , чтобы нам не приходилось редактировать номер версии в двух местах:

Существует множество систем наименования версий в python обычно рекомендуется использовать PEP386. Можно представить, что обозначение версии состоит из номера мажорного, минорного релизов (номера багфикса при необходимости), разделенных точками. В последней части версии разрешается использовать буквы латинского алфавита. Примеры из официальной документации:

Управление зависимостями

Добавим функциональности нашему проекту. Создадим команду serve которая будет запускать вебсервер отдающий страницу со строкой «Hello world!» генерируемой нашим модулем. Для этого воспользуемся пакетом Flask.

Добавляем файл helloworld/web.py :

И файл helloworld/templates/index.html :

И опишем команду serve в файле setup.py :

Теперь в нашем проекте появилась зависимость от пакета Flask. Без его установки наше приложение не будет правильно работать. За описание зависимостей в файле setup.py отвечает параметр install_requires:

Проверим установку зависимостей обновив наш пакет и работу команды serve:

Открыв браузер по адресу http://127.0.0.1:5000 вы должны увидеть нашу страницу.

Управление файлами проекта (MANIFEST.in)

На текущий момент при сборке нашего пакета distutils включает в него только python-файлы. Необходимо включить в него файл helloworld/templates/index.html без которого проект работать не будет.

Чтобы сделать это мы должны сообщить distutils какие еще файлы надо включать в наш проект. Один из способов — это создание файла MANIFEST.in :

Данная команда указывает distutils на включение в проект всех html файлов в директории helloworld/templates .

Также придется обновить setup.py :

Теперь шаблоны будут включены в наш проект.

Создание и запуск тестов

Хорошей практикой считается создание тестов для вашего проекта. Добавим простейшую реализацию, файл tests.py :

И обновим setup.py :

Теперь мы можем произвести предварительное тестирование нашего проекта:

Обратите внимание, что для запуска тестов даже не нужно создание виртуального окружения. Необходимые зависимости будут скачаны в директорию проекта в виде egg пакетов.

Публикация пакета на pypi.python.org

Прежде чем вы сможете опубликовать свой проект вам необходимо зарегистрироваться на PyPi. Запишите ваши реквизиты в файле

Все ваш проект готов к публикации. Достаточно ввести соответствующую команду:

Вы не сможете опубликовать пакет helloworld , тк данное имя проекта уже занято.

There are basically two ways to install Python console scripts to my path by setup.py :

What are the differences? I see the first approach allows me to choose nice, specific name for my script, but are there any other differences? Different original purposes, compatibility (setuptools, distutils, . ), usage, . I am quite confused and a nice elaborated reply could help me (and probably also others) to properly understand all this.

Update: Since I asked the question PyPA published these cool docs on the topic.

4 Answers 4

The docs for the (awesome) Click package suggest a few reasons to use entry points instead of scripts, including

  1. cross-platform compatibility and
  2. avoiding having the interpreter assign __name__ to __main__ , which could cause code to be imported twice (if another module imports your script)

Click is a nice way to implement functions for use as entry_points , btw.

One key difference between these two ways of creating command line executables is that with the setuptools approach (your first example), you have to call a function inside of the script — in your case this is the func inside of your module . However, in the distutils approach (your second example) you call the script directly (which allows being listed with or without an extension).

The setup tools entry point approach (#1) also has the benefit that on windows an .exe will be created that can be double clicked and invoked like a regular windows program. This is in addition to having a script placed in the bin path on posix-like systems.

One more difference is that when using console_scripts, my module’s init file was run. When just using scripts, the module init was not run, only the script was run.

Not the answer you’re looking for? Browse other questions tagged python package setup.py or ask your own question.

Linked

Hot Network Questions

To subscribe to this RSS feed, copy and paste this URL into your RSS reader.

site design / logo © 2019 Stack Exchange Inc; user contributions licensed under cc by-sa 4.0 with attribution required. rev 2019.11.15.35459

Many Python packages include command line tools. This is useful for distributing support tools which are associated with a library, or just taking advantage of the setuptools / PyPI infrastructure to distribute a command line tool that happens to use Python.

For funniest, we’ll add a funniest-joke command line tool.

There are two mechanisms that setuptools.setup() prov > scripts keyword argument, and the console_scripts entry point.

The scripts Keyword Argument¶

The first approach is to write your script in a separate file, such as you might write a shell script.:

The funniest-joke script just looks like this:

Then we can declare the script in setup() like this:

When we install the package, setuptools will copy the script to our PATH and make it available for general use.:

This has advantage of being generalizeable to non-python scripts, as well: funniest-joke could be a shell script, or something completely different.

The console_scripts Entry Point¶

The second approach is called an ‘entry point’. Setuptools allows modules to register entrypoints which other packages can hook into to prov > console_scripts entry point.

This allows Python functions (not scripts!) to be directly registered as command-line accessible tools.

In this case, we’ll add a new file and function to support the command line tool:

The command_line.py submodule exists only to service the command line tool (which is a convenient organization method):

You can test the “script” by running it directly, e.g.:

The main() function can then be registered like so:

Again, once the package has been installed, we can use it in the same way. Setuptools will generate a standalone script ‘shim’ which imports your module and calls the registered function.

This method has the advantage that it’s very easily testable. Instead of having to shell out to spawn the script, we can have a test case that just does something like:

In order to make that more useful, we’ll probably want something like a context manager which temporarily captures sys.stdout , but that is outside the scope of this tutorial.

© Copyright 2012, Scott Torborg. Revision 35daf993 .

Оцените статью