Publishing a Python Package to PyPI
The Python Package Index (PyPI) has become the go-to place for searching and downloading python packages. This guide will take you through all of the steps to take a python project and upload it so that others may use it.
Preparing Project
Folder Structure
To help us illustrate how the folder structure is handled, let us use an example. Say we want to deploy the package with the name <package-name>
to PyPI. The root folder of our repo is called base
and inside, we should have the following structure:
.
├── LICENSE
├── README.md
├── demo/
│ ├── __init__.py
│ ├── demo.py
│ └── ...
├── <package-name>/
│ ├── __init__.py
│ ├── package_file.py
│ └── ...
├── requirements.txt
├── setup.py
└── tests/
├── __init__.py
├── test_file.py
└── ...
The core files of the library should all be within the <package-name>/
folder. The demo
and tests
folders are places where you can add example scripts and tests if desired. The contents of the setup.py
script is covered in the next section.
The __init__.py
files allow external scripts to 'see' the <package-name>/
folder. Examples of the contents of these files are shown below:
By setting the __init__.py
files this way you can just call the package classes in a similar way to other packages:
Creating Setup Script
The setup script is what will be used to create the distribution that will be uploaded to PyPI. It should be located in the root directory of you repository. Below you can find a template of the setup.py
script.
from setuptools import setup, find_packages
VERSION = '1.1.0'
DESCRIPTION = 'Transforming and handling poses.'
# read the contents of your README file
from pathlib import Path
this_directory = Path(__file__).parent
long_description = (this_directory / "README.md").read_text()
# Add resource links
project_urls = {
'Documentation': 'https://demo.org',
'Repository': 'https://gitlab.com/'
}
# Setting up
setup(
name="<package-name>",
version=VERSION,
author="Firstname Lastname",
author_email="<email@address.com>",
description=DESCRIPTION,
long_description=long_description,
long_description_content_type='text/markdown',
packages=find_packages(),
install_requires=open("requirements.txt", "r").read().split("\n"),
keywords=['python'],
project_urls = project_urls,
classifiers=[
"Intended Audience :: Developers",
"Programming Language :: Python :: 3",
"Operating System :: Unix",
"Operating System :: MacOS :: MacOS X",
"Operating System :: Microsoft :: Windows",
]
)
This setup script defines a few key parameters of the package to be published:
- Version number
- Which operating systems are allowed to install the package
- Dependencies of the package (defined the
requirements.txt
file) - Adds links to documentation and repository (found in
project_urls
)
This setup file is also configured to show the README.md
file of the repository as the long description of the package of PyPI.
Info
Future improvements should be made to:
- Automatically increment the version number on a new build (using
bumpver
)
Publishing
Create Account on PyPi
If you don't already have an account on PyPi, you will need to create one (you can do so here). Make sure to save your username and password as you will need it for the following steps.
Publish Package
Now that you project is ready, and you have an account on PyPI, we can now move onto publishing the package.
Building Project
Let us start by building the project, so that it is saved as an executable. Go to the root folder of your project (base
in the example), and run the commands below:
Info
Make sure to change the version number of your package in the setup.py
file before building, otherwise PyPI will reject the new upload.
The command with create three new folders:
build
dist
<package-name>.egg-info
The contents of the dist
folder is what we will upload to PyPI.
Publishing the Build using Twine
To publish this new build, we will use the twine
python package (pip3 install twine
).
To upload, simply type in the following command:
twine
will then ask for your PyPI username and password, and then upload the new build!
Adding to .gitignore
The command python3 setup.py sdist bdist_wheel
creates three folders containing a lot of content. It is therefore best to add the following lines to your .gitignore
file to avoid syncing these folders: