Packaging Python Projects
It is a short note to show how to package a simple Python project, build it and how to upload it to the Python Package Index, which is a repository of software for the Python programming language. PyPI helps you find and install software developed and shared by the Python community.
There is also Test Python Package Index, which is similar to PyPI but is a stage zone, where people can test their packages before uploading them to the official PyPI.
Project structure
The Python project should include necessary files and be structured to allow build
creating a package out of it.
Let’s begin to structure our project like this. Reference to samplepackage
── foo
│ ├── __init__.py
│ └── bar
│ ├── __init__.py
│ └── main.py
├── requirements.txt
├── samples
└── setup.py
setup.py
This is a heart of packaging our Python project as it contains metadata and drives the build
import setuptools
from os import path
from foo import __version__
# Read the contents of README.md
this_directory = path.abspath(path.dirname(__file__))
with open(path.join(this_directory, 'README.md'), encoding='utf-8') as f:
long_description = f.read()
setuptools.setup(
name='samplepackage',
version=__version__,
description="This is a sample package",
long_description=long_description,
long_description_content_type='text/markdown',
url='https://github.com/Thanh-Truong/samplepackage',
author='Thanh Truong',
author_email='tcthanh@gmail.com',
license='MIT',
packages=setuptools.find_packages(),
install_requires = ['requests'],
classifiers=[
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
],
entry_points={
'console_scripts': [
'samplepackage = foo.bar.main:main'
],
}
)
The above was an example from one of mine packages and it is quite self-explanatory. There are some notes here:
-
install_requires
contains all required packages or dependencies. It is important to lock in specific versions so your code will not break. -
entry_points
orconsole_scripts
. While you can do much more withconsole_scripts
, this allows specifying the entry point to your “executable” program. In this example, user can invokesamplepackage
which is equivalent tofoo.bar.main:main
. To further explain, we havefoo
as a packagebar
as another package- finally
main:main
is the main entry
.pypirc
This file resides at ~/.pypirc
containing all authentication needed to identify with pypi.org or test.pypi.org. One needs to create accounts on the two sites and fills in the .pyirc
with account details. There are also ways to authenticate using token, but I don’t find it particularly useful if you build code from your local machine.
[distutils]
index-servers =
pypi
pypitest
[pypi]
repository=https://pypi.python.org/pypi
username=
password=
[pypitest]
repository=https://testpypi.python.org/pypi
username=
password=
Building package
List of commands
python -m pip install --upgrade pip
python3 -m pip install --upgrade build
python3 -m build
Uploading to PyPI or Test PyPI
Install twine, which is a utility for publishing Python packages on PyPI. It provides build system independent uploads of source and binary distribution artifacts.
python3 -m pip install --upgrade twine
Upload
python3 -m twine upload --repository testpypi dist/*
After that, you should be able to view your newly uploaded package at https://pypi.org/ or https://test.pypi.org/
Install our package
pip install -i https://test.pypi.org/simple/ sample