Deploying with Setuptools

Setuptools, is an extension library that is commonly used todistribute Python libraries and extensions. It extends distutils, a basicmodule installation system shipped with Python to also support various morecomplex constructs that make larger applications easier to distribute:

  • support for dependencies: a library or application can declare alist of other libraries it depends on which will be installedautomatically for you.

  • package registry: setuptools registers your package with yourPython installation. This makes it possible to query informationprovided by one package from another package. The best known feature ofthis system is the entry point support which allows one package todeclare an “entry point” that another package can hook into to extend theother package.

  • installation manager: pip can install other libraries for you.

If you have Python 2 (>=2.7.9) or Python 3 (>=3.4) installed from python.org,you will already have pip and setuptools on your system. Otherwise, youwill need to install them yourself.

Flask itself, and all the libraries you can find on PyPI are distributed witheither setuptools or distutils.

In this case we assume your application is calledyourapplication.py and you are not using a module, but a package. If you have not yet converted your application intoa package, head over to the Larger Applications pattern to seehow this can be done.

A working deployment with setuptools is the first step into more complexand more automated deployment scenarios. If you want to fully automatethe process, also read the Deploying with Fabric chapter.

Basic Setup Script

Because you have Flask installed, you have setuptools available on your system.Flask already depends upon setuptools.

Standard disclaimer applies: you better use a virtualenv.

Your setup code always goes into a file named setup.py next to yourapplication. The name of the file is only convention, but becauseeverybody will look for a file with that name, you better not change it.

A basic setup.py file for a Flask application looks like this:

  1. from setuptools import setup
  2.  
  3. setup(
  4. name='Your Application',
  5. version='1.0',
  6. long_description=__doc__,
  7. packages=['yourapplication'],
  8. include_package_data=True,
  9. zip_safe=False,
  10. install_requires=['Flask']
  11. )

Please keep in mind that you have to list subpackages explicitly. If youwant setuptools to lookup the packages for you automatically, you can usethe find_packages function:

  1. from setuptools import setup, find_packages
  2.  
  3. setup(
  4. ...
  5. packages=find_packages()
  6. )

Most parameters to the setup function should be self explanatory,include_package_data and zip_safe might not be.include_package_data tells setuptools to look for a MANIFEST.in fileand install all the entries that match as package data. We will use thisto distribute the static files and templates along with the Python module(see Distributing Resources). The zip_safe flag can be used toforce or prevent zip Archive creation. In general you probably don’t wantyour packages to be installed as zip files because some tools do notsupport them and they make debugging a lot harder.

Tagging Builds

It is useful to distinguish between release and development builds. Add asetup.cfg file to configure these options.

  1. [egg_info]
  2. tag_build = .dev
  3. tag_date = 1
  4.  
  5. [aliases]
  6. release = egg_info -Db ''

Running python setup.py sdist will create a development packagewith “.dev” and the current date appended: flaskr-1.0.dev20160314.tar.gz.Running python setup.py release sdist will create a release packagewith only the version: flaskr-1.0.tar.gz.

Distributing Resources

If you try to install the package you just created, you will notice thatfolders like static or templates are not installed for you. Thereason for this is that setuptools does not know which files to add foryou. What you should do, is to create a MANIFEST.in file next to yoursetup.py file. This file lists all the files that should be added toyour tarball:

  1. recursive-include yourapplication/templates *
  2. recursive-include yourapplication/static *

Don’t forget that even if you enlist them in your MANIFEST.in file, theywon’t be installed for you unless you set the _include_package_data_parameter of the setup function to True!

Declaring Dependencies

Dependencies are declared in the install_requires parameter as a list.Each item in that list is the name of a package that should be pulled fromPyPI on installation. By default it will always use the most recentversion, but you can also provide minimum and maximum versionrequirements. Here some examples:

  1. install_requires=[
  2. 'Flask>=0.2',
  3. 'SQLAlchemy>=0.6',
  4. 'BrokenPackage>=0.7,<=1.0'
  5. ]

As mentioned earlier, dependencies are pulled from PyPI. What if youwant to depend on a package that cannot be found on PyPI and won’t bebecause it is an internal package you don’t want to share with anyone?Just do it as if there was a PyPI entry and provide a list ofalternative locations where setuptools should look for tarballs:

  1. dependency_links=['http://example.com/yourfiles']

Make sure that page has a directory listing and the links on the page arepointing to the actual tarballs with their correct filenames as this ishow setuptools will find the files. If you have an internal companyserver that contains the packages, provide the URL to that server.

Installing / Developing

To install your application (ideally into a virtualenv) just run thesetup.py script with the install parameter. It will install yourapplication into the virtualenv’s site-packages folder and also downloadand install all dependencies:

  1. $ python setup.py install

If you are developing on the package and also want the requirements to beinstalled, you can use the develop command instead:

  1. $ python setup.py develop

This has the advantage of just installing a link to the site-packagesfolder instead of copying the data over. You can then continue to work onthe code without having to run install again after each change.