This is a quick guide for create and generate distribution package of your python project so that others can install, import and use in their projects.
Prerequisites:
You will need the following tools installed in your computer:
- Python (2.x/3.x)
- Pip
- API key for uploading your package to distribution platform, such as test.pypi.org.
After install python, you can install pip by using:
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
python get-pip.py
Note: get-pip.py
also installs setuptools 2 and wheel if they are not already ! We will later use these tools to install our package. You can update these tools to the latest version using:
python3 -m pip install --user --upgrade setuptools wheel
Create folder structure
Suppose that you want to create a package under the name example_pkg
, then you can create the following folder structure:
packaging_tutorial/
example_pkg/
__init__.py
where packaging_tutorial
is the project root directory. All your code will be place in example_pkg
, and __init__.py
can simply be an empty file or can be used to import the directory as a package.
The setup.py
is the important file that contains the configuration of the package, e.g. package name, version etc. If you want to add README.md
and LICENSE file, then also place them in the root folder.
packaging_tutorial/
example_pkg/
__init__.py
your_other_files.py
setup.py
LICENSE
README.md
Creating setup.py
Next, you will edit setup.py
by your favorite editor. The file contain 3 mains parts:
- import tools
- Display License or ReadMe
- Configuration
import setuptools
with open("README.md", "r") as fh:
long_description = fh.read()
setuptools.setup(
name="example-pkg-YOUR-USERNAME-HERE", # Replace with your own username
version="0.0.1",
author="Example Author",
author_email="author@example.com",
description="A small example package",
long_description=long_description,
long_description_content_type="text/markdown",
url="https://github.com/pypa/sampleproject",
packages=setuptools.find_packages(),
classifiers=[
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
],
python_requires='>=3.6',
)
This example package uses a relatively minimal set:
name
is the distribution name of your package. This can be any name as long as only contains letters, numbers,_
, and-
. It also must not already be taken on pypi.org. Be sure to update this with your username, as this ensures you won’t try to upload a package with the same name as one which already exists when you upload the package.version
is the package version see PEP 440 for more details on versions.author
andauthor_email
are used to identify the author of the package.description
is a short, one-sentence summary of the package.long_description
is a detailed description of the package. This is shown on the package detail package on the Python Package Index. In this case, the long description is loaded fromREADME.md
which is a common pattern.long_description_content_type
tells the index what type of markup is used for the long description. In this case, it’s Markdown.url
is the URL for the homepage of the project. For many projects, this will just be a link to GitHub, GitLab, Bitbucket, or similar code hosting service.packages
is a list of all Python import packages that should be included in the distribution package. Instead of listing each package manually, we can usefind_packages()
to automatically discover all packages and subpackages. In this case, the list of packages will be example_pkg as that’s the only package present.classifiers
gives the index and pip some additional metadata about your package. In this case, the package is only compatible with Python 3, is licensed under the MIT license, and is OS-independent. You should always include at least which version(s) of Python your package works on, which license your package is available under, and which operating systems your package will work on. For a complete list of classifiers, see https://pypi.org/classifiers/.
Generating distribution archives
When everything is ready, it is time for generating distribution packages by runing this command from the same directory where setup.py
is located:
python3 setup.py sdist bdist_wheel
This command should output a lot of text and once completed should generate two files in the dist
directory:
dist/ example_pkg_YOUR_USERNAME_HERE-0.0.1-py3-none-any.whl example_pkg_YOUR_USERNAME_HERE-0.0.1.tar.gz
Uploading the distribution archives
Ignore this if you don’t want to distribute your package online. Otherwise, if you use pypi.org, you can follow their tutorial to create one.
- Register an API token
- Upload the archives
Go to https://test.pypi.org/manage/account/#api-tokens and create a new API token; don’t limit its scope to a particular project, since you are creating a new project. API tokens provide an alternative way (instead of username and password) to authenticate when uploading packages to PyPI.
Don’t close the page until you have copied and saved the token — you won’t see that token again.
You can create a token for an entire PyPI account, in which case, the token will work for all projects associated with that account. Alternatively, you can limit a token’s scope to a specific project.
We strongly recommend you authenticate with an API token where possible.
To make an API token:
- Verify your email address (check your account settings)
- In your account settings, go to the API tokens section and select “Add API token”
To use an API token:
- Set your username to
__token__
- Set your password to the token value, including the
pypi-
prefix
Where you edit or add these values will depend on your individual use case. For example, some users may need to edit their .pypirc
file, while others may need to update their CI configuration file (e.g. .travis.yml
if you are using Travis).
Advanced users may wish to inspect their token by decoding it with base64, and checking the output against the unique identifier displayed on PyPI.
Now that you are registered, you can use twine to upload the distribution packages. You’ll need to install Twine:
python3 -m pip install --user --upgrade twine
Once installed, run Twine to upload all of the archives under dist
:
python3 -m twine upload --repository-url https://test.pypi.org/legacy/ dist/*
You will be prompted for a username and password. For the username, use __token__
. For the password, use the token value, including the pypi-
prefix. After the command completes, you should see output similar to this:
Uploading distributions to https://test.pypi.org/legacy/ Enter your username: [your username] Enter your password: Uploading example_pkg_YOUR_USERNAME_HERE-0.0.1-py3-none-any.whl 100%|█████████████████████| 4.65k/4.65k [00:01<00:00, 3.88kB/s] Uploading example_pkg_YOUR_USERNAME_HERE-0.0.1.tar.gz 100%|█████████████████████| 4.25k/4.25k [00:01<00:00, 4.05kB/s]
Once uploaded your package should be viewable on TestPyPI, for example, https://test.pypi.org/project/example-pkg-YOUR-USERNAME-HERE
Wrapping up
Congratulations, you’ve packaged and distributed a Python project!
Keep in mind that this tutorial showed you how to upload your package to Test PyPI, which isn’t a permanent storage. The Test system occasionally deletes packages and accounts. It is best to use Test PyPI for testing and experiments like this tutorial.