mirror of
https://github.com/flakestorm/flakestorm.git
synced 2026-04-25 16:56:25 +02:00
562 lines
12 KiB
Markdown
562 lines
12 KiB
Markdown
# Publishing flakestorm to PyPI
|
|
|
|
This guide explains how to publish flakestorm so users can install it with `pip install flakestorm`.
|
|
|
|
---
|
|
|
|
## Table of Contents
|
|
|
|
1. [Understanding PyPI](#understanding-pypi)
|
|
2. [Prerequisites](#prerequisites)
|
|
3. [Project Structure for Publishing](#project-structure-for-publishing)
|
|
4. [Step-by-Step Publishing Guide](#step-by-step-publishing-guide)
|
|
5. [Automated Publishing with GitHub Actions](#automated-publishing-with-github-actions)
|
|
6. [Publishing the Rust Extension](#publishing-the-rust-extension)
|
|
7. [Version Management](#version-management)
|
|
8. [Testing Before Publishing](#testing-before-publishing)
|
|
9. [Common Issues](#common-issues)
|
|
|
|
---
|
|
|
|
## Understanding PyPI
|
|
|
|
### What is PyPI?
|
|
|
|
**PyPI** (Python Package Index) is the official repository for Python packages. When users run:
|
|
|
|
```bash
|
|
pip install flakestorm
|
|
```
|
|
|
|
pip downloads the package from PyPI (https://pypi.org).
|
|
|
|
### What Gets Published?
|
|
|
|
A Python package is distributed as either:
|
|
- **Source Distribution (sdist)**: `.tar.gz` file with source code
|
|
- **Wheel (bdist_wheel)**: `.whl` file, pre-built for specific platforms
|
|
|
|
For flakestorm:
|
|
- **Pure Python code**: Published as universal wheel (works everywhere)
|
|
- **Rust extension**: Published as platform-specific wheels (separate process)
|
|
|
|
---
|
|
|
|
## Prerequisites
|
|
|
|
### 1. PyPI Account
|
|
|
|
Create accounts on:
|
|
- **Test PyPI**: https://test.pypi.org/account/register/ (for testing)
|
|
- **PyPI**: https://pypi.org/account/register/ (for production)
|
|
|
|
### 2. API Tokens
|
|
|
|
Generate API tokens (more secure than username/password):
|
|
|
|
1. Go to https://pypi.org/manage/account/token/
|
|
2. Create a token with scope "Entire account" or project-specific
|
|
3. Save the token securely (you'll only see it once!)
|
|
|
|
### 3. Install Build Tools
|
|
|
|
```bash
|
|
pip install build twine hatch
|
|
```
|
|
|
|
---
|
|
|
|
## Project Structure for Publishing
|
|
|
|
flakestorm is already set up correctly. Here's what makes it publishable:
|
|
|
|
### pyproject.toml (Key Sections)
|
|
|
|
```toml
|
|
[build-system]
|
|
requires = ["hatchling", "hatch-fancy-pypi-readme"]
|
|
build-backend = "hatchling.build"
|
|
|
|
[project]
|
|
name = "flakestorm" # Package name on PyPI
|
|
version = "0.1.0" # Version number
|
|
description = "The Agent Reliability Engine"
|
|
readme = "README.md" # Shown on PyPI page
|
|
license = "Apache-2.0"
|
|
requires-python = ">=3.10"
|
|
dependencies = [ # Auto-installed with package
|
|
"typer>=0.9.0",
|
|
"rich>=13.0.0",
|
|
# ...
|
|
]
|
|
|
|
[project.scripts]
|
|
flakestorm = "flakestorm.cli.main:app" # Creates `flakestorm` command
|
|
|
|
[tool.hatch.build.targets.wheel]
|
|
packages = ["src/flakestorm"] # What to include in wheel
|
|
```
|
|
|
|
### Directory Structure
|
|
|
|
```
|
|
flakestorm/
|
|
├── pyproject.toml # Package metadata (required)
|
|
├── README.md # PyPI description
|
|
├── LICENSE # License file
|
|
├── src/
|
|
│ └── flakestorm/ # Your package code
|
|
│ ├── __init__.py # Must exist for package
|
|
│ ├── core/
|
|
│ ├── mutations/
|
|
│ └── ...
|
|
└── tests/ # Not included in package
|
|
```
|
|
|
|
### `src/flakestorm/__init__.py` (Package Entry Point)
|
|
|
|
```python
|
|
"""flakestorm - The Agent Reliability Engine"""
|
|
|
|
__version__ = "0.1.0"
|
|
|
|
from flakestorm.core.config import load_config, FlakeStormConfig
|
|
from flakestorm.core.runner import FlakeStormRunner
|
|
|
|
__all__ = ["load_config", "FlakeStormConfig", "FlakeStormRunner", "__version__"]
|
|
```
|
|
|
|
---
|
|
|
|
## Step-by-Step Publishing Guide
|
|
|
|
### Step 1: Verify Package Metadata
|
|
|
|
```bash
|
|
# Check pyproject.toml is valid
|
|
# NOTE: Use editable mode for development, regular install for testing wheel builds
|
|
pip install -e . # Editable mode (recommended for development)
|
|
|
|
# OR test the wheel build process:
|
|
python -m pip install build
|
|
python -m build --wheel
|
|
python -m pip install dist/*.whl
|
|
|
|
# Verify the package works
|
|
flakestorm --version
|
|
```
|
|
|
|
**Important:** If you get `ModuleNotFoundError: No module named 'flakestorm.reports'` when using `pip install .` (non-editable), it means the wheel build didn't include all subpackages. Use `pip install -e .` for development, or ensure `pyproject.toml` has the correct `packages` configuration.
|
|
|
|
### Step 2: Build the Package
|
|
|
|
```bash
|
|
# Install build tools (if not already installed)
|
|
pip install build
|
|
|
|
# Clean previous builds
|
|
rm -rf dist/ build/ *.egg-info src/*.egg-info
|
|
|
|
# Build source distribution and wheel
|
|
python -m build
|
|
|
|
# You should see:
|
|
# dist/
|
|
# flakestorm-0.1.0.tar.gz (source)
|
|
# flakestorm-0.1.0-py3-none-any.whl (wheel)
|
|
|
|
# Verify all subpackages are included (especially reports)
|
|
unzip -l dist/*.whl | grep "flakestorm/reports"
|
|
```
|
|
|
|
### Step 3: Check the Build
|
|
|
|
```bash
|
|
# Install twine for checking (if not already installed)
|
|
pip install twine
|
|
|
|
# Verify the package contents
|
|
twine check dist/*
|
|
|
|
# List files in the wheel
|
|
unzip -l dist/*.whl
|
|
|
|
# Ensure it contains all subpackages:
|
|
# - flakestorm/__init__.py
|
|
# - flakestorm/core/*.py
|
|
# - flakestorm/mutations/*.py
|
|
# - flakestorm/reports/*.py (important: check this exists!)
|
|
# - flakestorm/assertions/*.py
|
|
# - etc.
|
|
|
|
# Quick check for reports module:
|
|
unzip -l dist/*.whl | grep "flakestorm/reports"
|
|
```
|
|
|
|
### Step 4: Test on Test PyPI (Recommended)
|
|
|
|
```bash
|
|
# Upload to Test PyPI first
|
|
twine upload --repository testpypi dist/*
|
|
|
|
# You'll be prompted for:
|
|
# Username: __token__
|
|
# Password: pypi-your-test-token-here
|
|
|
|
# Install from Test PyPI to verify
|
|
pip install --index-url https://test.pypi.org/simple/ flakestorm
|
|
```
|
|
|
|
### Step 5: Publish to Production PyPI
|
|
|
|
```bash
|
|
# Upload to real PyPI
|
|
twine upload dist/*
|
|
|
|
# Username: __token__
|
|
# Password: pypi-your-real-token-here
|
|
```
|
|
|
|
### Step 6: Verify Installation
|
|
|
|
```bash
|
|
# In a fresh virtual environment
|
|
python -m venv test_env
|
|
source test_env/bin/activate
|
|
|
|
pip install flakestorm
|
|
flakestorm --version
|
|
```
|
|
|
|
🎉 **Congratulations!** Users can now `pip install flakestorm`!
|
|
|
|
---
|
|
|
|
## Automated Publishing with GitHub Actions
|
|
|
|
Set up automatic publishing when you create a release:
|
|
|
|
### `.github/workflows/publish.yml`
|
|
|
|
```yaml
|
|
name: Publish to PyPI
|
|
|
|
on:
|
|
release:
|
|
types: [published]
|
|
|
|
jobs:
|
|
build:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version: '3.11'
|
|
|
|
- name: Install build tools
|
|
run: pip install build twine
|
|
|
|
- name: Build package
|
|
run: python -m build
|
|
|
|
- name: Check package
|
|
run: twine check dist/*
|
|
|
|
- name: Publish to PyPI
|
|
env:
|
|
TWINE_USERNAME: __token__
|
|
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
|
|
run: twine upload dist/*
|
|
```
|
|
|
|
### Setting Up the Secret
|
|
|
|
1. Go to your GitHub repo → Settings → Secrets → Actions
|
|
2. Add a new secret named `PYPI_TOKEN`
|
|
3. Paste your PyPI API token as the value
|
|
|
|
### Creating a Release
|
|
|
|
1. Go to GitHub → Releases → Create new release
|
|
2. Create a new tag (e.g., `v0.1.0`)
|
|
3. Add release notes
|
|
4. Publish release
|
|
5. GitHub Actions will automatically publish to PyPI
|
|
|
|
---
|
|
|
|
## Publishing the Rust Extension
|
|
|
|
The Rust extension (if implemented) would be published separately because it requires platform-specific binaries.
|
|
|
|
### Using `maturin`
|
|
|
|
```bash
|
|
cd rust/
|
|
|
|
# Build wheels for your current platform
|
|
maturin build --release
|
|
|
|
# The wheel would be in: ../target/wheels/flakestorm_rust-0.1.0-cp311-*.whl
|
|
# (or cp310, cp312 depending on Python version used)
|
|
```
|
|
|
|
### Multi-Platform Publishing with GitHub Actions
|
|
|
|
```yaml
|
|
# .github/workflows/rust-publish.yml
|
|
name: Publish Rust Extension
|
|
|
|
on:
|
|
release:
|
|
types: [published]
|
|
|
|
jobs:
|
|
linux:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: PyO3/maturin-action@v1
|
|
with:
|
|
manylinux: auto
|
|
command: build
|
|
args: --release --manifest-path rust/Cargo.toml -o dist
|
|
- name: Upload wheels
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: wheels-linux
|
|
path: dist
|
|
|
|
macos:
|
|
runs-on: macos-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: PyO3/maturin-action@v1
|
|
with:
|
|
command: build
|
|
args: --release --manifest-path rust/Cargo.toml -o dist
|
|
- name: Upload wheels
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: wheels-macos
|
|
path: dist
|
|
|
|
windows:
|
|
runs-on: windows-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: PyO3/maturin-action@v1
|
|
with:
|
|
command: build
|
|
args: --release --manifest-path rust/Cargo.toml -o dist
|
|
- name: Upload wheels
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: wheels-windows
|
|
path: dist
|
|
|
|
publish:
|
|
needs: [linux, macos, windows]
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/download-artifact@v4
|
|
with:
|
|
path: dist
|
|
merge-multiple: true
|
|
- name: Publish to PyPI
|
|
uses: PyO3/maturin-action@v1
|
|
with:
|
|
command: upload
|
|
args: --skip-existing dist/*
|
|
env:
|
|
MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }}
|
|
```
|
|
|
|
---
|
|
|
|
## Version Management
|
|
|
|
### Semantic Versioning
|
|
|
|
Follow [Semantic Versioning](https://semver.org/):
|
|
|
|
```
|
|
MAJOR.MINOR.PATCH
|
|
|
|
0.1.0 - Initial release
|
|
0.1.1 - Bug fixes
|
|
0.2.0 - New features (backward compatible)
|
|
1.0.0 - Stable release / Breaking changes
|
|
```
|
|
|
|
### Where Version is Defined
|
|
|
|
Update version in TWO places:
|
|
|
|
1. **`pyproject.toml`**:
|
|
```toml
|
|
[project]
|
|
version = "0.2.0"
|
|
```
|
|
|
|
2. **`src/flakestorm/__init__.py`**:
|
|
```python
|
|
__version__ = "0.2.0"
|
|
```
|
|
|
|
### Automating Version Sync (Optional)
|
|
|
|
Use `hatch-vcs` to automatically get version from git tags:
|
|
|
|
```toml
|
|
# pyproject.toml
|
|
[build-system]
|
|
requires = ["hatchling", "hatch-vcs"]
|
|
|
|
[tool.hatch.version]
|
|
source = "vcs"
|
|
```
|
|
|
|
Then just create a git tag and the version is set automatically:
|
|
|
|
```bash
|
|
git tag v0.2.0
|
|
git push --tags
|
|
```
|
|
|
|
---
|
|
|
|
## Testing Before Publishing
|
|
|
|
### Local Testing
|
|
|
|
```bash
|
|
# Create a fresh virtual environment
|
|
python -m venv test_install
|
|
source test_install/bin/activate
|
|
|
|
# Install from local build
|
|
pip install dist/flakestorm-0.1.0-py3-none-any.whl
|
|
|
|
# Test it works
|
|
flakestorm --help
|
|
flakestorm init
|
|
python -c "from flakestorm import load_config; print('OK')"
|
|
```
|
|
|
|
### Test PyPI
|
|
|
|
Always test on Test PyPI first:
|
|
|
|
```bash
|
|
# Upload to Test PyPI
|
|
twine upload --repository testpypi dist/*
|
|
|
|
# Install from Test PyPI
|
|
pip install --index-url https://test.pypi.org/simple/ \
|
|
--extra-index-url https://pypi.org/simple/ \
|
|
flakestorm
|
|
```
|
|
|
|
The `--extra-index-url` is needed because Test PyPI may not have all dependencies.
|
|
|
|
---
|
|
|
|
## Common Issues
|
|
|
|
### "Package name already taken"
|
|
|
|
Package names on PyPI are unique. If `flakestorm` is taken:
|
|
- Check https://pypi.org/project/flakestorm/
|
|
- Choose a different name: `flakestorm-cli`, `py-flakestorm`, etc.
|
|
|
|
### "Invalid distribution file"
|
|
|
|
```bash
|
|
# Check what's wrong
|
|
twine check dist/*
|
|
|
|
# Common fixes:
|
|
# - Ensure README.md is valid markdown
|
|
# - Ensure LICENSE file exists
|
|
# - Ensure version is valid format
|
|
```
|
|
|
|
### "Missing files in wheel"
|
|
|
|
```bash
|
|
# List wheel contents
|
|
unzip -l dist/*.whl
|
|
|
|
# If files are missing, check pyproject.toml:
|
|
[tool.hatch.build.targets.wheel]
|
|
packages = ["src/flakestorm"] # Make sure path is correct
|
|
```
|
|
|
|
### "Command not found after install"
|
|
|
|
Ensure `project.scripts` is set in pyproject.toml:
|
|
|
|
```toml
|
|
[project.scripts]
|
|
flakestorm = "flakestorm.cli.main:app"
|
|
```
|
|
|
|
---
|
|
|
|
## Quick Reference
|
|
|
|
### One-Time Setup
|
|
|
|
```bash
|
|
# Install tools
|
|
pip install build twine
|
|
|
|
# Create PyPI account and token
|
|
# Store token securely
|
|
```
|
|
|
|
### Each Release
|
|
|
|
```bash
|
|
# 1. Update version in pyproject.toml and __init__.py
|
|
# 2. Commit and push
|
|
git add -A && git commit -m "Release 0.2.0" && git push
|
|
|
|
# 3. Build
|
|
python -m build
|
|
|
|
# 4. Check
|
|
twine check dist/*
|
|
|
|
# 5. Test (optional but recommended)
|
|
twine upload --repository testpypi dist/*
|
|
pip install --index-url https://test.pypi.org/simple/ flakestorm
|
|
|
|
# 6. Publish
|
|
twine upload dist/*
|
|
|
|
# 7. Tag release
|
|
git tag v0.2.0
|
|
git push --tags
|
|
```
|
|
|
|
### With GitHub Actions
|
|
|
|
Just create a release on GitHub and everything happens automatically!
|
|
|
|
---
|
|
|
|
## Next Steps After Publishing
|
|
|
|
1. **Announce**: Post on social media, Reddit, Hacker News
|
|
2. **Documentation**: Update docs with install instructions
|
|
3. **Monitor**: Watch for issues and PyPI download stats
|
|
4. **Iterate**: Fix bugs, add features, release new versions
|
|
|
|
---
|
|
|
|
*Happy publishing! 🚀*
|