How to Package and Publish a Python Project to PyPI
This tutorial explains why Python projects need packaging, introduces essential tools like setuptools, wheel, and twine, shows the recommended project layout, walks through creating a setup.py file, building distribution files, testing locally, uploading to PyPI, and handling version updates and common questions.
In Python development, writing code is only the first step; packaging and publishing the project to PyPI (or other repositories) enables easy installation for other developers. This guide covers the entire workflow.
1. Why package a Python project?
Convenient installation via pip install your-package
Automatic dependency management
Version control for users
Sharing code through PyPI or private repositories
2. Python packaging tools
The official toolchain uses setuptools for packaging, combined with wheel to generate binary distribution files. The table below summarizes the main tools:
Tool
Purpose
setuptoolsDefine project metadata, dependencies, entry points, etc.
wheelGenerate
.whlbinary distribution (faster install than
.tar.gz)
twineSecurely upload packages to PyPI
pipInstall and manage Python packages
3. Recommended project structure
my_package/
│
├── my_package/ # main package directory
│ ├── __init__.py # makes it a package
│ ├── module1.py # module 1
│ └── module2.py # module 2
│
├── tests/ # test code
│ └── test_module1.py
│
├── README.md # project description
├── setup.py # packaging configuration
└── requirements.txt # optional dependencies4. Writing setup.py (core configuration)
The setup.py file defines the package name, version, author, dependencies, and other metadata. Example:
from setuptools import setup, find_packages
setup(
name="my_package", # package name on PyPI
version="0.1.0", # semantic version
author="Your Name",
author_email="[email protected]",
description="A short description of your package",
long_description=open("README.md").read(),
long_description_content_type="text/markdown",
url="https://github.com/yourusername/my_package",
packages=find_packages(),
install_requires=[
"requests>=2.25.0",
"numpy>=1.20.0",
],
classifiers=[
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
],
python_requires=">=3.6",
)5. Generating distribution packages ( .whl and .tar.gz )
Run the following commands in the project root:
# Install packaging tools
pip install setuptools wheel
# Build source and wheel distributions (output in
dist/
)
python setup.py sdist bdist_wheelAfter execution, the dist/ directory contains:
my_package-0.1.0.tar.gz (source archive)
my_package-0.1.0-py3-none-any.whl (wheel archive)
6. Local test installation
Install the built wheel locally to verify it works:
pip install dist/my_package-0.1.0-py3-none-any.whlThen import the package and check the version:
import my_package
print(my_package.__version__) # should output 0.1.07. Publishing to PyPI
(1) Register a PyPI account and obtain an API token for twine .
(2) Install twine :
pip install twine(3) Upload the distribution files:
twine upload dist/*Provide your PyPI username/password or API token when prompted; after a successful upload, users can install the package with pip install my_package .
8. Advanced: version management and updates
Follow semantic versioning MAJOR.MINOR.PATCH : MAJOR : incompatible API changes MINOR : backward‑compatible feature additions PATCH : backward‑compatible bug fixes
To release a new version: Update the version field in setup.py . Re‑build the packages with python setup.py sdist bdist_wheel . Upload again using twine upload dist/* .
9. Frequently Asked Questions
Q1: How to make a command‑line tool installable via pip install ?
Add an entry_points section to setup.py :
entry_points={
"console_scripts": [
"my_command=my_package.cli:main",
],
}Q2: How to include non‑Python files (e.g., data, config) in the package?
Use a MANIFEST.in file or the package_data argument:
setup(
...,
package_data={"my_package": ["data/*.json"]},
include_package_data=True,
)Summary
Toolchain: setuptools + wheel + twine
Core steps: write setup.py → build dist/ → test locally → upload to PyPI
Best practices: proper versioning, dependency control, and thorough testing before release
php中文网 Courses
php中文网's platform for the latest courses and technical articles, helping PHP learners advance quickly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.