Python Package Build Workflow
Build Python package distributions (wheel and source distribution).
Overviewโ
This workflow builds Python package artifacts using modern Python packaging tools, creating both wheel (.whl) and source distribution (.tar.gz) files ready for publishing to PyPI or other package indexes.
When to Useโ
- โ You need to build Python package distributions
- โ You're preparing for PyPI publication
- โ You want to create distributable package artifacts
- โ You need to validate package build process
Workflow Architectureโ
Inputsโ
Required Inputsโ
None - uses repository defaults
Optional Inputsโ
| Input | Type | Default | Description |
|---|---|---|---|
python_version | string | '3.11' | Python version for building |
build_tool | string | 'build' | Build tool (build, setuptools, poetry) |
build_args | string | '' | Additional build arguments |
validate_package | boolean | true | Run package validation checks |
Outputsโ
| Output | Description |
|---|---|
wheel_path | Path to built wheel file |
sdist_path | Path to built source distribution |
package_version | Extracted package version |
artifact_name | Name of uploaded artifact |
Usage Examplesโ
Basic Usageโ
name: Build
on: [push, pull_request]
jobs:
build:
uses: Chisanan232/GitHub-Action_Reusable_Workflows-Python/.github/workflows/rw_python_package.yaml@master
With Custom Python Versionโ
jobs:
build:
uses: Chisanan232/GitHub-Action_Reusable_Workflows-Python/.github/workflows/rw_python_package.yaml@master
with:
python_version: '3.12'
Using Poetryโ
jobs:
build:
uses: Chisanan232/GitHub-Action_Reusable_Workflows-Python/.github/workflows/rw_python_package.yaml@master
with:
build_tool: poetry
python_version: '3.11'
Complete Build and Publish Pipelineโ
name: Build and Publish
on:
push:
tags:
- 'v*'
jobs:
build:
uses: Chisanan232/GitHub-Action_Reusable_Workflows-Python/.github/workflows/rw_python_package.yaml@master
with:
python_version: '3.11'
validate_package: true
publish:
needs: build
uses: Chisanan232/GitHub-Action_Reusable_Workflows-Python/.github/workflows/rw_push_pypi.yaml@master
secrets:
pypi_token: ${{ secrets.PYPI_API_TOKEN }}
How It Worksโ
Step 1: Environment Setupโ
Sets up Python and installs build tools:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ inputs.python_version }}
- name: Install build tools
run: |
python -m pip install --upgrade pip
pip install build twine check-manifest
Step 2: Build Source Distributionโ
Creates source distribution (.tar.gz):
python -m build --sdist
Step 3: Build Wheelโ
Creates wheel distribution (.whl):
python -m build --wheel
Step 4: Package Validationโ
Validates built packages:
twine check dist/*
check-manifest
Step 5: Upload Artifactsโ
Uploads built packages as artifacts:
- uses: actions/upload-artifact@v4
with:
name: python-package-distributions
path: dist/
Build Toolsโ
Python Build (Default)โ
Modern PEP 517 compliant build tool:
build_tool: build
Advantages:
- Standard Python packaging
- PEP 517/518 compliant
- Works with any build backend
Requirements:
[build-system]
requires = ["setuptools>=45", "wheel", "setuptools_scm[toml]>=6.2"]
build-backend = "setuptools.build_meta"
Poetryโ
Poetry-based package building:
build_tool: poetry
Advantages:
- Integrated dependency management
- Lock file support
- Modern packaging
Requirements:
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
Setuptoolsโ
Traditional setuptools building:
build_tool: setuptools
Advantages:
- Wide compatibility
- Well-established
- Flexible configuration
Package Configurationโ
pyproject.toml (Recommended)โ
Modern Python packaging configuration:
[build-system]
requires = ["setuptools>=45", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "my-package"
version = "1.0.0"
description = "My Python package"
authors = [
{name = "Your Name", email = "you@example.com"}
]
dependencies = [
"requests>=2.28.0",
]
requires-python = ">=3.9"
[project.optional-dependencies]
dev = [
"pytest>=7.0.0",
"pytest-cov>=4.0.0",
]
setup.py (Legacy)โ
Traditional setup.py configuration:
from setuptools import setup, find_packages
setup(
name="my-package",
version="1.0.0",
packages=find_packages(where="src"),
package_dir={"": "src"},
install_requires=[
"requests>=2.28.0",
],
python_requires=">=3.9",
)
Package Validationโ
Twine Checkโ
Validates package metadata and structure:
twine check dist/*
Checks:
- README rendering
- Metadata completeness
- Package structure
- File integrity
Check-Manifestโ
Verifies MANIFEST.in completeness:
check-manifest
Ensures all necessary files are included in source distribution.
Package Structure Validationโ
Validates package can be installed:
pip install dist/*.whl
python -c "import my_package; print(my_package.__version__)"
Best Practicesโ
1. Version Managementโ
Use dynamic versioning:
[project]
dynamic = ["version"]
[tool.setuptools.dynamic]
version = {attr = "my_package.__version__"}
Or use setuptools_scm:
[build-system]
requires = ["setuptools>=45", "setuptools_scm[toml]>=6.2"]
[tool.setuptools_scm]
write_to = "src/my_package/_version.py"
2. Include Necessary Filesโ
Create MANIFEST.in:
include README.md
include LICENSE
include pyproject.toml
recursive-include src *.py
recursive-include tests *.py
3. Package Metadataโ
Provide complete metadata:
[project]
name = "my-package"
version = "1.0.0"
description = "A short description"
readme = "README.md"
license = {text = "MIT"}
authors = [{name = "Your Name", email = "you@example.com"}]
keywords = ["keyword1", "keyword2"]
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
]
4. Clean Build Environmentโ
Ensure clean builds:
# Remove old builds
rm -rf dist/ build/ *.egg-info/
# Build fresh
python -m build
Troubleshootingโ
Build Failsโ
Symptoms:
- Build command fails
- Missing dependencies
Solutions:
-
Check
pyproject.tomlsyntax:python -m build --sdist --wheel -
Verify build dependencies:
[build-system]
requires = ["setuptools>=45", "wheel"] -
Review build logs for errors
Package Validation Failsโ
Symptoms:
- Twine check fails
- Invalid metadata
Solutions:
-
Fix README rendering:
[project]
readme = {file = "README.md", content-type = "text/markdown"} -
Complete required metadata:
[project]
name = "my-package"
version = "1.0.0"
description = "Required description" -
Check file includes in MANIFEST.in
Missing Files in Distributionโ
Symptoms:
- Files missing from built package
- Import errors after installation
Solutions:
-
Update MANIFEST.in:
recursive-include src *.py
include README.md LICENSE -
Use check-manifest:
check-manifest -
Verify package_data in pyproject.toml:
[tool.setuptools.package-data]
my_package = ["data/*.json", "templates/*.html"]
Package Distribution Typesโ
Wheel Distribution (.whl)โ
Binary distribution format:
Advantages:
- Faster installation
- No build step required
- Platform-specific optimizations
File naming:
my_package-1.0.0-py3-none-any.whl
Source Distribution (.tar.gz)โ
Source code distribution:
Advantages:
- Platform independent
- Includes all source files
- Can be built on any platform
File naming:
my-package-1.0.0.tar.gz
Related Workflowsโ
- rw_push_pypi - Publish to PyPI
- rw_pre-building_test - Test package installation
- rw_checking_deployment_state - Check deployment readiness