How to Build a Wheel with Hatchling in Python
Build a Python wheel using the hatchling build backend and the build package, handling missing project metadata automatically.
pip install build
Python code
44 linesimport subprocess
import sys
import tempfile
from pathlib import Path
def build_wheel_with_hatchling(project_dir: str) -> str:
"""Build a wheel using hatchling and return the wheel file path."""
project_path = Path(project_dir)
# Simulate a minimal project structure if missing
if not (project_path / "pyproject.toml").exists():
pyproject = """[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "demo"
version = "0.1.0"
"""
(project_path / "pyproject.toml").write_text(pyproject)
(project_path / "src" / "demo").mkdir(parents=True, exist_ok=True)
(project_path / "src" / "demo" / "__init__.py").write_text('__version__ = "0.1.0"\n')
# Build the wheel
result = subprocess.run(
[sys.executable, "-m", "build", "--wheel", "--outdir", str(project_path / "dist")],
cwd=str(project_path),
capture_output=True,
text=True,
check=False,
)
if result.returncode != 0:
raise RuntimeError(f"Build failed: {result.stderr}")
wheel_files = list((project_path / "dist").glob("*.whl"))
return str(wheel_files[0]) if wheel_files else "No wheel file produced"
if __name__ == "__main__":
with tempfile.TemporaryDirectory() as tmpdir:
wheel_path = build_wheel_with_hatchling(tmpdir)
print(f"Built wheel: {wheel_path}")
Output
Built wheel: /tmp/tmpxyz123/dist/demo-0.1.0-py3-none-any.whl
How it works
The script creates a minimal pyproject.toml with hatchling as the build backend if one doesn't exist. It invokes the build module via subprocess, which handles the wheel creation following PEP 517. The --wheel flag restricts the build to just the wheel artifact, and --outdir controls where the output lands. The function returns the path to the first .whl file found in the dist directory, or a message if none was produced. Using subprocess.run with check=False lets the script capture and surface the real error message when the build fails.
Common mistakes
- Forgetting that `pip install build` is required because the `build` module is not in the standard library
- Not creating the src layout directory before building when using a pure src layout
- Ignoring the stderr output when the build fails, which hides useful diagnostics
- Assuming a wheel was produced without verifying the return code first
Variations
- Use `python -m build --sdist` to build a source distribution instead of a wheel
- Pass `--wheel` and `--sdist` together to build both artifacts in one command
Real-world use cases
- CI pipelines that build and publish Python packages to PyPI after every merge to main.
- Automated release scripts that generate wheels for internal package registries within an organization.
- Local development workflows that check whether a package builds cleanly before pushing code changes.
Sponsored
More from Modern tooling
- Build a Recipe Runner Mock in Python easy
- Build a Textual TUI App Skeleton in Python easy
- Configure ruff linter rules in pyproject.toml with Python easy
- Data Conversion Helper Functions in Python easy
- How to Bind and Mock structlog Context in Python medium
- How to Build a Chainable Filter Helper in Python easy
Keep learning
Related tutorials and quizzes for this topic.