.. _distribute-deployment:

Deploying with Setuptools
=========================

`Setuptools`_, is an extension library that is commonly used to
distribute Python libraries and extensions. It extends distutils, a basic
module installation system shipped with Python to also support various more
complex constructs that make larger applications easier to distribute:

- **support for dependencies**: a library or application can declare a
  list of other libraries it depends on which will be installed
  automatically for you.
- **package registry**: setuptools registers your package with your
  Python installation.  This makes it possible to query information
  provided by one package from another package.  The best known feature of
  this system is the entry point support which allows one package to
  declare an "entry point" that another package can hook into to extend the
  other package.
- **installation manager**: :command:`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, you
will need to install them yourself.

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

In this case we assume your application is called
:file:`yourapplication.py` and you are not using a module, but a :ref:`package
<larger-applications>`. If you have not yet converted your application into
a package, head over to the :ref:`larger-applications` pattern to see
how this can be done.

A working deployment with setuptools is the first step into more complex
and more automated deployment scenarios.  If you want to fully automate
the process, also read the :ref:`fabric-deployment` chapter.

Basic Setup Script
------------------

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

Standard disclaimer applies: :ref:`you better use a virtualenv
<virtualenv>`.

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

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

    from setuptools import setup

    setup(
        name='Your Application',
        version='1.0',
        long_description=__doc__,
        packages=['yourapplication'],
        include_package_data=True,
        zip_safe=False,
        install_requires=['Flask']
    )

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

    from setuptools import setup, find_packages

    setup(
        ...
        packages=find_packages()
    )

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 :file:`MANIFEST.in` file
and install all the entries that match as package data.  We will use this
to distribute the static files and templates along with the Python module
(see :ref:`distributing-resources`).  The ``zip_safe`` flag can be used to
force or prevent zip Archive creation.  In general you probably don't want
your packages to be installed as zip files because some tools do not
support them and they make debugging a lot harder.


Tagging Builds
--------------

It is useful to distinguish between release and development builds.  Add a
:file:`setup.cfg` file to configure these options.

    [egg_info]
    tag_build = .dev
    tag_date = 1

    [aliases]
    release = egg_info -RDb ''

Running ``python setup.py sdist`` will create a development package
with ".dev" and the current date appended: ``flaskr-1.0.dev20160314.tar.gz``.
Running ``python setup.py release sdist`` will create a release package
with only the version: ``flaskr-1.0.tar.gz``.


.. _distributing-resources:

Distributing Resources
----------------------

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

    recursive-include yourapplication/templates *
    recursive-include yourapplication/static *

Don't forget that even if you enlist them in your :file:`MANIFEST.in` file, they
won'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 from
PyPI on installation.  By default it will always use the most recent
version, but you can also provide minimum and maximum version
requirements.  Here some examples::

    install_requires=[
        'Flask>=0.2',
        'SQLAlchemy>=0.6',
        'BrokenPackage>=0.7,<=1.0'
    ]

As mentioned earlier, dependencies are pulled from PyPI.  What if you
want to depend on a package that cannot be found on PyPI and won't be
because 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 of
alternative locations where setuptools should look for tarballs::

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

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


Installing / Developing
-----------------------

To install your application (ideally into a virtualenv) just run the
:file:`setup.py` script with the ``install`` parameter.  It will install your
application into the virtualenv's site-packages folder and also download
and install all dependencies::

    $ python setup.py install

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

    $ python setup.py develop

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


.. _pip: https://pypi.python.org/pypi/pip
.. _Setuptools: https://pythonhosted.org/setuptools
