We've already seen some of what it takes to package an application. Packaging means combining the source code and other files for one or more Python modules into a single file that can be distributed to other Python developers. This could be a ZIP file or a Python egg.
We've already seen some of what setuptools
can do. The distutils
module is included with Python and is the official packaging tool that setuptools
is built on. Set
uptools
is an extension to distutils
, not an official part of Python.
One of the biggest differences between distutils
and setuptools
is that setuptools
generates eggs, while distutils
does not. Using distutils
, developers create distributions as opposed to eggs. These distributions can take a couple of forms, namely source and built. Source distributions are generally just archived and compressed copies of a module's directories and source code. This is useful for distributing your modules to other developers.
Built distributions (or binary distributions) compile your modules into an executable format specific to a destination-build platform. This could be Window (.exe
), Red Hat Linux (.rpm
), or a variety of other formats.
Another noteworthy difference between distutils
distributions and those created by setuptools
is that distutils
is unaware of dependencies and is unable to download them anyway, even if it knew about them. This feature is likely responsible for setuptools
and easy_install
's popularity, despite not being an official part of Python.
To make use of distutils
to distribute our modules, we need to write a setup script called setup.py
, just as we did using setuptools
. A lot the setup.py
code is compatible with distutils
and setuptools
. Here is the simple example setup script from the distutils
documentation:
from distutils.core import setup setup(name='foo', version='1.0', py_modules=['foo'],)
This simple setup script includes two keyword arguments of metadata about our distribution, name and version, and a simple list of individual modules we want to include in our distribution. In this case, the foo
module will be included and will correspond to a file called foo.py
at the same level in the filesystem as our setup script.
This works for a single file or a short list of Python modules. But what about the case of packaging several packages, each with many modules? Distutils
handles this as well:
setup(name='foo', version='1.0', packages=['foo', 'bar'], package_dir={'': 'src},)
Will look for modules in src/foo/
and src/bar/
relative to the setup script location and include them in the distribution output.
With this setup script in place and pointing to the appropriate modules or packages, we can run:
$ python setup.py sdist
The sdist
command will generate a source distribution for our modules in a .tar.gz
format. To create a built distribution we would use the following syntax for a Red Hat Linux .RPM file:
$ python setup.py bdist_rpm
Or, to create a Windows-compatible .EXE
installation file we would use the following:
$ python setup.py bdist_windows
In addition to providing distributions for developers to easily exchange modules between themselves, the distutils
setup script allows users to install modules as well. This is done by passing the install
command to the setup script:
$ python setup.py install
Usually, the process of installing a package like this involves downloading the .tar.gz
source distribution, un-archiving the contents to the filesystem, and running the setup.py
script as above.
Installing a package in this way places the Python modules included in our distribution into the user's site-packages
. If they are running their default system Python, the package will be installed system-wide. If they are using virtualenv, for example, and have an active environment, the distribution will be installed to that environment.
Even though distutils
does not provide a mechanism for installing packages by directly downloading from PyPI, you can still define meta-data inside your setup.py
script and use it to register and upload your distribution with the Python Package Index.
Uploading the distribution to PyPI also acts as a form of publishing your project. By providing version, author, and dependency metadata in setup.py
, these requirements will be included on your distributions web page at the package index.
Registering and uploading your distribution with PyPI is done using the register setup.py
command:
$ python setup.py register
Registering your distribution will transmit any metadata defined in setup.py
, such as version and author's e-mail address, and create a project page for it in the index. This page will list all metadata you supplied in your setup.py
. You can update a distribution's metadata by registering it again, with corrected metadata keyword arguments in your setup script.
You will be required to have a PyPI account before you can register your distributions. You can do this directly in the setup.py
register command by choosing the second menu option when prompted.
Once your package is registered, you can upload it using the upload
command:
$ python setup.py sdist bdist_wininst upload
This upload command will package and upload a source distribution as well as a built Windows install distribution. Both will be listed under the appropriate metadata in the PyPI.
Python packages deployed to PyPI using setuptools
have an additional advantage: super-simple installation using the easy_install
tool. This is a utility that with a single command, will find, download, and install a Python package from the package index. To install Django, for example, one can attempt it from the command line like so:
$ easy_install Django
This will download the latest released version of Django from PyPI and install it into the current Python environment, whether it is the system environment or a virtual environment. In this way it works very much like setup.py
, with the enhanced function of automatically locating and downloading the appropriate package.