In this post I explain how to transform a working code into a python package
that can be installed from PyPi using
pip install yourmodule. I will
suppose you are modern and use Python 3. For those in a hurry, three steps:
clone a repository, update the setup.py
file, and follow the instructions in
the last part.
Quick reminder on Python modules and packages
Creating a Python module is easy:
Create a file with your code, call it
def hello(): print("I am a Python3 module!")
This a module: a file with things in it. You can import it or do whatever you want.
Make it a package:
And ta-daaa you have a Python package. If the directory containing the two
myhellomodule.py) is called
swaggymodule, then you
from swaggymodule.myhellomodule import hello (from the parent directory).
Nothing fancy for now. Let’s see how to publish such a wonderful package, so
that your grandmother can install it with a simple
pip install swaggymodule.
Packaging your project
First, clone the sample project and give it the name of your module:
git clone https://github.com/pypa/sampleproject swaggymodule
The important files:
- setup.py allows you to specify your project configuration, and to run
packaging commands: try
python setup.py --help-commands
- setup.cfg is an INI file containing option defaults for
- README.rst describes the goal of the project, using reStructuredText
Copy your module(s) inside this new folder and remove the existing “sample” module:
swaggymodule |- swaggymodule |- __init__.py |- myhellomodule.py |- setup.py |- setup.cfg |- README.rst
Configure the name, version, description…
First, open the
setup.py file, to enter a few details about the project. All the fields are self-explanatory but here are a few additional pieces of advice:
name: according to PEP0008:
Modules should have short, all-lowercase names. Underscores can be used in the module name if it improves readability. Python packages should also have short, all-lowercase names, although the use of underscores is discouraged.
Never use dashes (
-) in your package name because importing it would become a very hard task.
- license: in case of doubt (what should I use?), try http://choosealicense.com/: it’s super clear.
- classifiers: check https://pypi.python.org/pypi?%3Aaction=list_classifiers for a full list.
- entry_points: in case your application plugs in an existing system, you may specify an entry point. See this page for more details. But in most cases you should just set it to an empty dictionnary.
The actual packaging steps
So that you don’t run into the same issues as me:
pip install wheel twine setuptools --upgrade
First, create a Source Distribution. This kind of “distribution” (aka “Package”) requires a build step when installed by pip.
python setup.py sdist
But we want to install a “wheel” (a built package) which is faster to install than a source distribution:
python setup.py bdist_wheel
Uploading your package
The official documentation recommends to use
twine instead of the default
python setup.py upload because the latter uploads files and credentials over
plain HTTP whereas
twine uses TLS (so use
To save the configuration data, create a file in
[distutils] index-servers=pypi [pypi] repository = https://testpypi.python.org/pypi username = yourusername
You may also add a
password line if you don’t want to type your password
# Register your project twine register dist/*.whl # Upload the project twine upload dist/*
And this is what you should get when you head to testpypi.python.org:
If you need to make updates: change your code, bump the version to 1.0.1 in the
setup.py file, optionally commit your code to your repository, and do:
twine upload dist/swaggymodule-1.0.1*
This should have updated your project online and made the new version available. Now try it:
$ pip install -i https://testpypi.python.org/pypi swaggymodule Downloading/unpacking swaggymodule Downloading swaggymodule-1.0.1-py3-none-any.whl ...
It works! But before letting people know about your new package, we should upload it to the actual PyPi (not the test one). The process is summed up in the next section:
In a nutshell
pip install wheel twine setuptools --upgrade # Check and update the server to use (https://pypi.python.org/pypi) and your credentials nano ~/.pypirc # Build the distributions python setup.py sdist python setup.py bdist_wheel # Register and upload your package twine register dist/*.whl twine upload dist/*
To go further
- The official tutorial
- The naming convention
- A more complete article: Open Sourcing a Python Project the Right Way by Jeff Knup.
Following these steps, I was able to publish a small
application we were
using on a closed-source project, to share it but also to decrease the amount of
code inside the project itself that was not focused on the business logic.
This application is a Django application enabling users to generate a new
secret key when deploying their Django
project. In our
project, a simple
pip install django-generate-secret-key replaced a whole
folder and saved us space, complexity, and increased the readability of the