Though I may still be in the early stages of my programming journey, I had not learned the most modern way of packaging a Python project six months ago when I started doing it. Initially, I used setuptools
and a setup.py
file.
However, the pyproject.toml
file has emerged as a modern way to specify build dependencies and configurations for Python projects. Below is a practical workflow for creating, building, and distributing a Python package using solely pyproject.toml
.
Creating a Package
Setup Your Project Directory
/path/to/your/project/ ├── new_project/ # Python package directory. │ ├── __init__.py # Makes the directory a package. │ └── cli.py # An example module for CLI. ├── tests/ # Directory for tests. │ └── cli_test.py # Test module for CLI. ├── pyproject.toml # Definition of build process of the package. └── README.md # README with info about the project.
Define Your Package Configuration
Building and Distributing Your Package
Build Your Package
This command creates a
dist/
folder in your project directory, containing the built package files.Install Your Package Locally (For Testing)
Upload Your Package to PyPi
Managing Dependencies
Configuring Entry Points
If you’re creating a CLI tool, specify the entry point in the pyproject.toml
like so:
Tool Configuration
Configure tools such as black
for code formatting and ruff
for linting in the pyproject.toml
:
Starter pyproject.toml
Example
Below is a starter pyproject.toml
file for quick project setup:
[project]
name = "new_project"
version = "0.0.0"
authors = [{name = "Sébastien De Revière"},]
description = ""
readme = "README.md"
requires-python = ">=3.12"
classifiers = [
"Programming Language :: Python :: 3",
"License :: OSI Approved :: Apache Software License",
"Operating System :: OS Independent",
]
dependencies = [
"",
]
[project.optional-dependencies]
test = ["pytest"]
lint = [
"black",
"ruff",
]
pypi = [
"twine",
"wheel",
]
ci = [
"pytest",
"black",
"ruff",
]
[projects.urls]
Homepage = "https://github.com/sderev/new_project"
Documentation = "https://github.com/sderev/new_project"
Repository = "https://github.com/sderev/new_project"
Changelog = "https://github.com/sderev/new_project/releases"
Issues = "https://github.com/sderev/new_project/issues"
[project.scripts]
new_project = "new_project.cli:cli"
[tool.ruff]
line-length = 100
[tool.black]
line-length = 100
[tool.pytest.ini_options]
testpaths = ["tests"]
References
- Python Enhancement Proposal (PEP) 518: Specifying Minimum Build System Requirements for Python Projects.
- Python Enhancement Proposal (PEP) 517: A build-system independent format for source trees.
- Declaring Project Metadata in
pyproject.toml
(Python Packaging User Guide). - Classifiers · PyPI.
- Entry Points Configuration for CLI (Click Documentation).
- Packaging Python Projects Tutorial.