How to package and deploy your Python app to the PyPi package index

This is a TLDR summary on how to quickly package and deploy your Python application to the PyPi package index. See the full article over at python.org.

Image from pypi.org

Project structure

text
packaging_tutorial/
├── LICENSE
├── pyproject.toml
├── README.md
├── setup.cfg
├── setup.py  # optional, needed to make editable pip installs work
├── src/
│   └── pkg_name-/
│       └── __init__.py
└── tests/

Notes

Setup your project. The file structure should look something like the above. A quick rundown of the files:

  • setup.cfg - Static metadata

  • setup.py - dynamic metadata

  • pyproject.toml - tells build tools like pip, poetry what system you are using and what is required for a build.

Generate distribution archives

text
# install latest versions of PyPA’s    
$ python3 -m pip install --upgrade build  

# then run this in the same folder where pyproject.toml is located.    
$ python3 -m build   

The command should generate the following files in the dist directory:

text
dist/
  pkg_name_here-0.0.1-py3-none-any.whl
  pkg_name_here-0.0.1.tar.gz

Upload to the Python package index

Install twine and create an account at Test PyPI and create an API token.

TestPyPI is a separate instance of the package index for testing and experimentation.

text
# upgrade twine
$ python3 -m pip install --upgrade twine 

# upload to the index. 
$ python3 -m twine upload --repository testpypi dist/*

# You will be prompted for your username and password.
Uploading distributions to https://test.pypi.org/legacy/
Enter your username: [your username]
Enter your password:
Uploading pkg_name_here-0.0.1-py3-none-any.whl
100%|█████████████████████| 10.87k/10.87k [00:01<00:00, 5.88kB/s]
Uploading pkg_name_here-0.0.1.tar.gz
100%|█████████████████████| 5.22k/5.22k [00:01<00:00, 4.05kB/s]
       

Check that your package has been uploaded at for example at https://test.pypi.org/project/pkg_name_here.

Testing

Download and install your package.

text

$ python3 -m pip install --index-url https://test.pypi.org/simple/ --no-deps pkg-name-here==0.0.1

Looking in indexes: https://test.pypi.org/simple/
Collecting pkg-name-here==0.0.1
  Downloading https://test-files.pythonhosted.org/packages/50/51/f38453224c89bc94dd9d975cd76be1a157e3a51981213ab11bb1026d4d63/vanty_installer-0.0.1-py3-none-any.whl (2.3 kB)
Installing collected packages: pkg-name-here
Successfully installed pkg-name-here-0.0.1

Notes

You will notice a couple of unusual flags in the shell command above.

  1. --index-url - indicates which package index to use.

  2. --no-deps - tells pip to ignore any dependencies.

Congratulations you have deployed your package. To upload to the live package index, sign up for an account at PyPI and repeat Step 4 above. Don't forget to remove the --index-url flag from your command.

Using Alternative Build Tools - (Poetry)

If you are using poetry as your build tool, you can use it to both package indexes and publish your project. Assuming you have already installed poetry, you can go back to Step 2 above and build your project.

text
# Build the project
$ poetry build

# Add pypitest as a repository and publish
$ poetry config repositories.testpypi https://test.pypi.org/legacy/
$ poetry publish --repository testpypi    

Username: [username_but_not_in_brackets]
Password: 
Publishing pkg-name-here (0.0.5) to testpypi
 - Uploading pkg-name-here-0.0.5.tar.gz 100%
 - Uploading pkg-name-here-0.0.5-py3-none-any.whl 100%

Using tokens for PyPy authentication:

text
### Publishing to PYPI Test

$ poetry config repositories.testpypi https://test.pypi.org/legacy/

$ export POETRY_PYPI_TOKEN_TESTPYPI=my-token  
or
$ poetry config pypi-token.testpypi my-token

$ poetry publish -r testpypi

And that's it. For a more detailed article on how to use poetry check this article out .

Glossary Terms

  • Package index - A repository of distributions with a web interface to automate package discovery and consumption.

  • PyPI - the default Package Index for the Python community. It is open to all Python developers to consume and distribute their distributions.