Getting Started With setuptools and setup.py ¶
setuptools is a rich and complex program. This tutorial will focus on the bare minimum basics you need to get setuptools running so you can:
- Register your package on pypi.
- Build egg, source, and window installer ‘distributables’.
- Upload these ‘distributables’ to pypi.
Installing setuptools and easy install¶
To install setuptools visit http://pypi.python.org/pypi/setuptools and follow the instructions for your operating system. Also, check out http://peak.telecommunity.com/DevCenter/EasyInstall for more instructions on how to install setup tools.
Currently (as of November, 2009), setuptools is pretty easy to install for Python version 2.3 through 2.6.
Bootstrapping setuptools¶
If you are having trouble setting up setuptools for your platform, you may want to check out the ‘bootstrap’ setuptools script at http://peak.telecommunity.com/dist/ez_setup.py.
You can run this like this:
and it will install setuptools for whichever version of Python python refers to. For example on windows:
will install a setuptools for your python24 distribution.
Setting up setup.py ¶
All the features of what can go into a setup.py file is beyond the scope of this simple tutorial. I’ll just focus on a very basic and common format needed to get this project onto pypi.
The contents of setup.py is just pure python:
Directory Structure¶
The directory structure, so far, should look like this:
README¶
A nice idea stolen from http://pypi.python.org/pypi/Sphinx-PyPI-upload is to include a README text file which your code. This would be visible when someone, say, cloned your repo.
Using the simple read function, it is easy to include this in the long_description keyword arg for the setuptools.setup() function.
Classifiers¶
A really nice website is http://pypi.python.org/pypi?%3Aaction=list_classifiers which lists all the classifiers you can use in the setup call.
A sample of this website is:
Using setup.py ¶
The basic usage of setup.py is:
To see all commands type:
And you will get:
Intermezzo: .pypirc file and gpg¶
In order to interact with pypi, you first need to setup an account. Go to http://pypi.python.org/pypi and click on Register .
Now, once registered, when you run setup.py commands that interact with pypi you’ll have to enter your username and password each time.
To get around this, place a .pypirc file in your $HOME directory on linux. On windows, an you’ll need to set a HOME environ var to point to the directory where this file lives.
The structure of a .pypirc file is pretty simple:
There’s probably away around having your plain text password in this file, but I don’t know of the solution and haven’t looked into it.
Also, you often want to sign the files using gpg encryption. Visit http://www.gnupg.org/ on linux or http://www.gpg4win.org/ on windows to install this software.
Registering Your Project¶
With your setup.py and .pypirc in place, registering your project is pretty simple. Just type:
I would say more, but it is just that simple.
Uploading Your Project¶
There are three major setup.py commands we will use:
- bdist_egg : This creates an egg file. This is what is necessary so someone can use easy_install your_project .
- bdist_wininst : This will create an .exe that will install your project on a windows machine.
- sdist : This create a raw source distribution which someone can download and run python setup.py directly.
A key point here is you need to run these commands with the version of python you want to support. We’ll cover this in the Putting It All Together With The Full Windows Script below.
You can run these commands by themselves and simply create the files but not upload them. However, for this project, we always marry these commands with the upload directive which will both build and upload the necessary files.
Putting It All Together With The Full Windows Script¶
This project was build on a windows machine. To best understand how it all works and the other options used when using setup.py let’s just look at the .bat file I use to build the package and upload it to pypi:
For linux, it would be pretty much the same commands, just changing around the directories to point to the correct python versions.
I use the set HOME=C:\Users\Owner\ instead of setting an environ variable on windows
Пакетирование и дистрибуция приложений Python
Все библиотеки Python (т.е. пакеты прикладных программ), которые вы загружаете при помощи менеджера пакетов (например, PIP), распределяются с помощью специальной утилиты. Такие утилиты создают дистрибутивы Python; по сути, это сжатые версированные архивы, содержащие все связанные элементы, например, исходные и ресурсные файлы.
Данное руководство рассказывает о важных инструментах для дистрибуции приложений и ключевых этапах пакетирования библиотек, модулей и приложений. Это поможет развернуть собственный проект.
Дистрибутивы и пакеты Python
Даже пользователи с небольшим опытом работы с Python должны уметь использовать менеджер пакетов (например, pip, easy_install) для загрузки модулей и библиотек, которые в дальнейшем можно импортировать и использовать для создания нового приложения.
Эти инструменты управления пакетами при локальном использовании подключаются к исходникам и выполняют необходимое действие (установку, поиск и т.д.).
Для дистрибуции приложения нужно:
- Упаковать каталог приложения, добавив в него необходимые и рекомендуемые файлы;
- Указать элементы, связанные с приложением (зависимости, ресурсы и т.п.)
- Выпустить релиз приложения.
Примечание: В работе настоятельно рекомендуется использовать виртуальное окружение (virtualenv), позволяющее изолировать загрузки, модули и остальные компоненты определённого приложения Python.
Пакет Python технически являются импортируемым каталогом (с __init__.py), содержащим исходные файлы (модули). Не нужно путать их с пакетами операционной системы, которые технически являются приложениями.
Пример структуры пакета:
Приложения Python
В целом, приложение Python может состоять как из одного файла, так и из сотни. Но, как правило, оно содержит несколько модулей и определённое количество внешних файлов (из библиотек).
Пример структуры приложения:
Инструменты и библиотеки Python
Сегодня Python пользуется широкой популярностью, а потому для него разработано много сторонних библиотек и приложений, которые способны сделать процесс дистрибуции более простым и удобным.
Для управления дистрибуцией Python предлагает утилиту distutils.
Каталог пакетов Python
Python Package Index, чаще PyPI – это централизованный онлайн-репозиторий, предназначенный для проектов-дистрибутивов Python. Пакетные менеджеры (например, pip) используют этот репозиторий для хранения, поиска и установки необходимых дистрибутивов.
Для начала попробуем создать простое Python-приложение, которое потом можно пакетировать.
Структура приложения
Данное тестовое приложение будет иметь наиболее общую и распространённую структуру, дополненную несколькими модулями.
/MyApplication
|— run.py
|— config.py
|__ /app
|— __init__.py
|— /module_one
|— __init__.py
|— controllers.py
|— models.py
|__ /templates
|— module_one
|— hello.html
|__ /static
|__ ..
|__ .
Создайте необходимые папки:
/MyApplication
touch run.py
touch config.py
mkdir app
cd app
touch __init__.py
mkdir templates
mkdir static
mkdir module_one
cd module_one
touch __init__.py
touch controllers.py
touch models.py
cd ../templates
mkdir module_one
cd module_one
touch hello.html
Поместите в него следующий код:
# Run a test server.
from app import app
app.run(debug=True)
Сохраните и закройте файл (CTRL+X, Y).
Затем откройте в текстовом редакторе config.py:
Вставьте в него следующий код:
DEBUG = True
THREADS_PER_PAGE = 4
CSRF_ENABLED = True
CSRF_SESSION_KEY = «secret»
Сохраните и закройте файл (CTRL+X, Y).
Откройте файл app/init.py в текстовом редакторе:
Добавьте в него код:
from flask import Flask, render_template
app = Flask(__name__)
app.config.from_object(«config»)
from app.module_one.controllers import module_one
app.register_blueprint(module_one)
Сохраните и закройте файл.
Откройте app/module_one/controllers.py в текстовом редакторе:
Добавьте в файл следующий контент:
from flask import Blueprint, request, render_template
module_one = Blueprint(«auth», __name__, url_prefix=»/auth»)
@module_one.route(«/hello»)
def hello():
return render_template(«module_one/hello.html»)
Сохраните и закройте файл.
Откройте в редакторе файл app/templates/module_one/hello.html:
Поместите в него:
Сохраните и закройте файл (CTRL+X, Y).
Тестовое приложение готово.
Дистрибуция и пакетирование приложения
Теперь на сервере есть простое приложение, основанное на flask, которое можно подготовить к дистрибуции.
Редактирование структуры папок
Чтобы пакетирование приложения прошло успешно, нужно внести некоторые поправки в структуру папок.
/MyApplication
|— run.py
|__ /app
|— __init__.py
|— /module_one
|— __init__.py
|— controllers.py
|— models.py
|__ /templates
|— module_one
|— hello.html
|__ /static
|__ ..
|__ .
|— setup.py # Distribution setup file
|— README.txt # Read-me file
|— MANIFEST.in # Distribution manifest file
|— CHANGES.txt # Changes log
После этого нужно создать дополнительные файлы:
Создайте файл setup.py:
Добавьте в него такой код:
from distutils.core import setup
setup(
# Application name:
name=»MyApplication»,
# Version number (initial):
version=»0.1.0″,
# Application author details:
author=»name surname»,
author_email=»name@addr.ess»,
# Packages
packages=[«app»],
# Include additional files into the package
include_package_data=True,
# Details
url=»http://pypi.python.org/pypi/MyApplication_v010/»,
#
# license=»LICENSE.txt»,
description=»Useful towel-related stuff.»,
# long_description=open(«README.txt»).read(),
# Dependent packages (distributions)
install_requires=[
«flask»,
],
)
Сохраните и закройте файл.
Создание MANIFEST.in
При необходимости внести в пакет приложения дополнительные каталоги (статические файлы или шаблоны) укажите их в MANIFEST.in, после чего они будут упакованы.
Добавьте в файл строки:
recursive-include app/templates *
recursive-include app/static *
Сохраните и закройте файл.
Теперь пакет дистрибутива Python готов к установке и отправке.
Дополнительные файлы
Помните, что для создания полного дистрибутива нужно добавить в файл/каталог и настроить поддержку следующих файлов:
- README.txt
- MANIFEST.in
- LICENSE.txt
Работа с приложением, готовым к дистрибуции
На данном этапе приложение полностью готово к операции пакетирования.
Создание файла дистрибутива
Чтобы создать копию файла дистрибутива, запустите:
/MyApplication
python setup.py sdist
Эта команда просмотрит настройку, выведет выполняемые операции и создаст архива внутри только что созданного каталога diet, что выглядит примерно так:
/MyApplication# ls dist
# MyApplication-0.1.0.tar.gz
Примечание: Поскольку не все подкаталоги и дополнительные файлы были ранее заполнены, на данном этапе может система может вернуть предупреждение.
Установка приложения
Теперь другие пользователи могут установить приложение при помощи файла setup.py.
Чтобы установить приложение, запустите:
python setup.py install
Если эта установка предназначена для разработки и не все зависимости установлены, введите:
python setup.py develop
Распространение приложения
Чтобы поделиться своим кодом в Python Packaging Index, используйте команду register:
python setup.py register
После запуска команды следуйте инструкциям на экране.
Если у вас уже есть учётная запись, используйте следующую команду, чтобы просто выгрузить код:
A Practical Guide to Using Setup.py
Note: nowadays the use of setup.py is discouraged in favour of pyproject.toml together with setup.cfg . Find out how to use those here.
When you are using python professionally it pays to set up your projects
in a consistent manner. This helps your collaborators quickly understand the
structure of a project, and makes it easier for them to set up the project
on their machine. The key to setting up your project is the setup.py file.
In this blog I’ll go into the details of this file.
Where we start
Here I assume that you already have a package that you want to set up.
This does not need to be a finished package – ideally you should create the
setup.py long before your project is finished. It could even be an empty package;
just make sure the package folder exists
and contains a file named __init__.py (which may be empty).
If you follow my colleague Henk’s structure
for your project, your starting situation should look something like this:
You may have other files or folders in your structure, for example
folders named notebooks/ , tests/ or data/ , but these aren’t required.
The case for a setup.py
Once you have created a package like this, then you are likely
to use some of the code in other places. For example, you might want
to do this in a notebook:
This would work if your current working directory is example_project/ , but in
all other cases python will give you output like:
You could tell python where to look for the package by setting the PYTHONPATH
environment variable or adding the path to sys.path ,
but that is far from ideal: it would require different actions on different
platforms, and the path you need to set depends on the location of your code.
A much better way is to install your package using a setup.py and pip ,
since pip is the standard way to install all other packages, and it is bound
it work the same on all platforms.
A minimal example
So what does a setup.py file look like? Here is a minimal example 0 :
Here we specify three things:
- The name of the package, which is the name that pip will use for your package.
This does not have to be the same as the folder name the package lives
in, although it may be confusing if it is not. An example of where the package
name and the directory do not match is Scikit-Learn: you install it
using pip install scikit-learn , while you use it by importing from sklearn . - The version of your package. This is the version pip will report, and is used
for example when you publish your package on PyPI 1 . - What packages to include; in our case this is just exampleproject/ .
Here we let setuptools figure this out
automatically 2 . While you could in principle use find_packages()
without any arguments, this can potentially result in unwanted packages to
be included. This can happen, for example,
if you included an __init__.py in your tests/
directory. Alternatively, you can also use the exclude argument to explicitly
prevent the inclusion of tests in the package, but this is slightly
less robust.
Now all that you need to do in order to install your package is to run the following
from inside the example_project/ directory 3 :
The . here refers to the current working directory, which I assume to be the directory
where the setup.py can be found. The -e flag specifies that we want to install
in editable mode, which means
that when we edit the files in our package we do not need to re-install the
package before the changes come into effect. You will need to either restart
python or reload the package though!
When you edit information in the setup.py itself you will need to re-install
the package in most cases, and also if you add new (sub)packages.
When in doubt, it can never hurt to re-install. Just run pip install -e . again.
Requirements
Most projects have some dependencies. You have most likely used
a requirements.txt
file before, or an environment.yml
if you are using conda . Now that you are creating a setup.py , you can specify your
dependencies in the install_requires argument.
For example, for a typical data science project you may have:
You may specify requirements without a version ( PyYAML ), pin a version ( pandas==0.23.3 ), specify a minimum
version ( ‘numpy>=1.14.5 ) or set a range of versions ( matplotlib>=2.2.0,<3.0.0 ). These
requirements will automatically be installed by pip when you install your package.
Extras-require
Sometimes you may have dependencies that are only required in certain situations. As a data scientist
I often make packages which I use to train a model. When I work on such a model interactively
I may need to have matplotlib and jupyter installed in order to interactively work with the
data and to create visualizations
of the performance of the model. On the other hand, if the model runs in production I do not
want to install matplotlib nor jupyter on the machine (or container) where I train
or do inference. Luckily setuptools allows to specify optional dependencies in extras_require :
Now if we install the package normally ( pip install example from PyPI or pip install -e . locally)
it will only install the dependencies PyYAML , pandas and numpy . However, when we specify
that we want the optional interactive dependencies ( pip install «example[interactive]»
or pip install -e «.[interactive]» ),
then matplotlib and jupyter will also be installed.
Scripts and entry points
The main use case of most python packages that you install from PyPI is to provide functionality
that can be used in other python code. In other words, you can import from those packages.
As a data scientist I often make packages that aren’t meant to be used by other python code but
are meant to do something, for example to train a model. As such, I often have a python script that
I want to execute from the command line.
The best way 4 to expose functionality of your package to the command line is to define
an entry_point as such:
Now you can use the command my-command from the command line, which will in turn execute the main
function inside exampleproject/example.py . Do not forget to re-install – otherwise the command
will not be registered.
Tests
Whenever you write any code, I strongly encourage you to also write tests for this code. For testing
with python I suggest you use pytest . Of course you do not want to add pytest to your dependencies
in install_requires : it isn’t required by the users of your package. In order to have it installed
automatically when you run tests you can add the following to your setup.py :
Additionally you will have to create a file named setup.cfg with the following contents:
Now you can simply run python setup.py test and setuptools will ensure the necessary dependencies
are installed and run pytest for you! Have a look here if
you want to provide arguments or set configuration options for pytest .
If you have any additional requirements for testing (e.g. pytest-flask ) you can add them to tests_require .
Flake8
Personally I think it is a good idea to run Flake8 to
check the formatting of your code. Just like with pytest , you do not want to add flake8 to the
install_requires dependencies: it does not need to be installed in order to use your
package. Instead, you can add it to setup_requires :
Now you can simply run python setup.py flake8 . Of course you can also pin the version
of flake8 (or any other package) in setup_requires .
If you want to change some of the configuration parameters of Flake8 you can add a [flake8] section to
your setup.cfg . For example:
Package data
Sometimes you may want to include some non-python files in your package. These
may for example be schema files or a small lookup table. Be aware that such files
will be packaged together with your code, so it is in general a bad idea to include
any large files.
Suppose we have a schema.json in our project, which we place in exampleproject/data/schema.json .
If we want to include this in our package, we must use the package_data argument of setup :
This will make sure the file is included in the package. We can also choose to include
all files based on a pattern, for example:
This will add all *.json files in any package it encounters.
Now don’t try to figure out the installed files’ location yourself, as
pkg_resources has some very handy convenience functions:
- pkg_resources.resource_stream will give you a stream of the file, much like the
object you get when you call open( ) , - pkg_resources.resource_string will give you the contents of the file as a string,
- pkg_resources.resource_filename will give you the filename of the file (and extract
it into a temporary if it is included in a zipped package) for if the two options
above do not suit your needs.
For example, we could read in our schema using:
Metadata
If you are going to publish your package, then you probably want to give your
potential users some more information about your package, including a description,
the name of the author or maintainer, and the url to the package’s home page.
You can find a complete list of all allowed metadata in the setuptools
docs.
Additionally, if you are going to publish to PyPI, then you may want to
automatically load the contents of your README.md
into the long_description ,
and provide classifiers to tell pip even
more about your package.
Wrap-up
This blog should be a good starting point to set up most of your python projects.
If you want to read more about python packaging have a look
at the docs. Here is an example setup.py
which combines all parts shown in this blog:
and the accompanying setup.cfg :
Improve your Python skills, learn from the experts!
At GoDataDriven we offer a host of Python courses from beginner to expert, taught by the very best professionals in the field. Join us and level up your Python game:
-
– Great if you are just starting with Python. – Want to make the step up from data analysis and visualization to true data science? This is the right course. – Learn to productionize your models like a pro and use Python for machine learning.
Footnotes
0: In this blog I have used setuptools
to set up my example project. Alternatively
you could also use distutils,
which is the standard tool for packaging in python, but it lacks features
such as the find_packages() function and entry_points .
Since the use of setuptools is very common nowadays and many of its features
can be particularly useful, I suggest that you should use setuptools.
1: If you want the version of your package to also be available inside python,
have a look here.
2: You could also list your packages manually, but this is particularly error-prone.
3: Alternatively you could run python setup.py install , but using pip has
many benefits, among which are automatic installation of dependencies and the
ability to uninstall or update your package.
4: You could also use the scripts argument (see for
example here)
but as this requires you to create a python shell script it may not work
as well (or at all) on Windows.
Subscribe to our newsletter
Stay up to date on the latest insights and best-practices by registering for the GoDataDriven newsletter.