Introduction π
Packaging your Python project allows others to install it using pip. Two major packaging formats exist in modern Python:
- setup.py β Traditional packaging (setuptools)
- pyproject.toml β Modern packaging (PEP 517 / PEP 518)
Note
π‘ Packaging is essential for libraries, CLI apps, and internal tools.
1. Project Structure for Packaging π
project_structure.txt
my_package/
βββ my_package/
β βββ __init__.py
β βββ core.py
β
βββ tests/
βββ README.md
βββ LICENSE
βββ setup.py # OR pyproject.toml
βββ requirements.txtβ Your code must be inside a folder named exactly like the package.
2. Packaging with setup.py (Traditional Method)
Example setup.py
setup.py
from setuptools import setup, find_packages
setup(
name="my_package",
version="1.0.0",
packages=find_packages(),
description="A demo Python package",
author="Sathish",
author_email="you@example.com",
install_requires=["requests"],
license="MIT",
)Build the package
build.sh
pip install setuptools wheel
python setup.py sdist bdist_wheelβ Creates .tar.gz & .whl files in dist/
Install your package locally
local_install.sh
pip install dist/my_package-1.0.0-py3-none-any.whl3. Packaging with pyproject.toml (Modern Standard) π
Introduced by PEP 517/518, pyproject.toml is now the official method for packaging.
Minimal pyproject.toml (Setuptools)
pyproject.toml
[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "my_package"
version = "1.0.0"
description = "A demo Python package"
authors = [
{ name="Sathish", email="you@example.com" }
]
requires-python = ">=3.8"
dependencies = ["requests"]
[tool.setuptools.packages.find]
where = ["my_package"]Build the project
build_pyporject.sh
pip install build
python -m buildβ Generates wheel and source files in dist/
4. Adding Entry Points (CLI Commands) π₯οΈ
pyproject.toml (CLI)
[project.scripts]
mytool = "my_package.core:main"β Running mytool in terminal now runs core.main()
core.py
def main():
print("Hello from CLI!")5. Writing an __init__.py File π§
__init__.py
__version__ = "1.0.0"
from .core import *β Makes your package importable via import my_package
6. Uploading Package to PyPI π
Install tools
pypi_tools.sh
pip install twineUpload
upload.sh
twine upload dist/*Note
7. Versioning Best Practices π§Ύ
- 1.0.0 β Major release
- 1.1.0 β New features
- 1.1.1 β Bug fixes
8. Setup.cfg (Optional Middle Approach)
Not required today but still used. Structure β minimal setup.py + metadata in setup.cfg.
9. pyproject.toml vs setup.py Comparison βοΈ
| Feature | setup.py | pyproject.toml |
|---|---|---|
| Modern Standard | β | β |
| Build Backends | Limited | Flexible (Poetry, Flit, Setuptools) |
| Better Dependency Handling | β | β |
| Recommended for New Projects | β | β |
10. Creating a Package with Poetry πͺ (Advanced)
Poetry is a modern package/dependency manager.
poetry_install.sh
pip install poetryCreate project
poetry_new.sh
poetry new my_packageβ Automatically creates structure + pyproject.toml
11. Best Practices π‘
- β Prefer pyproject.toml for new projects
- β Keep package code inside a folder matching project name
- β Maintain a clean README.md
- β Use semantic versioning (MAJOR.MINOR.PATCH)
- β Test package locally before uploading to PyPI
Conclusion π
You now understand how to package Python projects using setup.py and pyproject.toml! Want the next tutorial? Try Publishing to PyPI, Dependency Management, Poetry, or Creating CLI Tools. Just tell me! π