This guide walks through extracting audio-hotplug into its own repository and publishing to PyPI.
- Go to https://github.com/LedFx (or your org)
- Click "New repository"
- Name:
audio-hotplug - Description: "Cross-platform audio device hotplug detection library"
- Public repository
- Don't initialize with README (we have one)
- Create repository
Run these commands in a temporary directory:
# Create temporary working directory
cd C:\mine\development\ledfx
New-Item -ItemType Directory -Path "audio-hotplug-extraction" -Force
cd audio-hotplug-extraction
# Clone the repository locally
git clone --no-hardlinks C:\mine\development\ledfx\LedFx temp-repo
cd temp-repo
# Checkout the branch with audio-hotplug
git checkout audio-device-hotswap
# Extract only audio-hotplug subdirectory with history
git filter-repo --path audio-hotplug/ --path-rename audio-hotplug/:
# This creates a repo with ONLY audio-hotplug files and their history
# Verify it worked
git log --oneline | Select-Object -First 10
ls
# Add new remote
git remote add origin git@github.com:LedFx/audio-hotplug.git
# Push to new repository
git push -u origin mainNote: If git filter-repo is not installed:
pip install git-filter-repo# Using git subtree split
cd C:\mine\development\ledfx\LedFx
git checkout audio-device-hotswap
# Create new branch with only audio-hotplug
git subtree split --prefix=audio-hotplug -b audio-hotplug-only
# Create new repo
cd C:\mine\development\ledfx\audio-hotplug-extraction
git init
git remote add origin git@github.com:LedFx/audio-hotplug.git
# Pull the subtree branch
git pull C:\mine\development\ledfx\LedFx audio-hotplug-only
# Push to GitHub
git branch -M main
git push -u origin mainAfter pushing, verify the repository has:
src/audio_hotplug/- Source codetests/- Test filesexamples/- Example scriptspyproject.toml- Build configurationREADME.md- DocumentationLICENSE- GPL-3.0 licenseTESTING.md- Testing guide
The workflows are already prepared in .github/workflows/ (see files created below)
-
Create PyPI account (if you don't have one):
- Go to https://pypi.org/account/register/
- Verify email
-
Create API token:
- Go to https://pypi.org/manage/account/token/
- Create token named "audio-hotplug-ci"
- Scope: "Entire account" or specific to audio-hotplug project
- Copy the token (starts with
pypi-...)
-
Add token to GitHub Secrets:
- Go to repository Settings → Secrets and variables → Actions
- Click "New repository secret"
- Name:
PYPI_API_TOKEN - Value: Paste the token
- Click "Add secret"
-
Optional: TestPyPI token (for testing):
- Go to https://test.pypi.org/manage/account/token/
- Create token named "audio-hotplug-test"
- Add as
TEST_PYPI_API_TOKENin GitHub Secrets
cd C:\mine\development\ledfx\audio-hotplug-extraction\temp-repo
# Install build tools
pip install build twine
# Build the package
python -m build
# This creates:
# - dist/audio_hotplug-0.1.0-py3-none-any.whl
# - dist/audio_hotplug-0.1.0.tar.gz
# Verify the package
python -m twine check dist/*# Upload to TestPyPI
python -m twine upload --repository testpypi dist/*
# Test install from TestPyPI
pip install --index-url https://test.pypi.org/simple/ --no-deps audio-hotplug
# Test the installation
python -c "from audio_hotplug import create_monitor; print('Success!')"Once TestPyPI works:
# Upload to production PyPI
python -m twine upload dist/*
# Or use GitHub Actions - just create a release tag:
git tag v0.1.0
git push origin v0.1.0cd C:\mine\development\ledfx\LedFx
# Make sure main is up to date
git checkout main
git pull upstream main
# Create new clean branch
git checkout -b feat/audio-hotplug-pypi-integrationReplace workspace dependency with PyPI package:
# Remove workspace configuration
# [tool.uv.workspace]
# members = [
# "audio-hotplug",
# ]
# [tool.uv.sources]
# audio-hotplug = { workspace = true }
# In dependencies, change:
dependencies = [
# ... other deps ...
"audio-hotplug>=0.1.0", # From PyPI
]# Remove the workspace copy
Remove-Item -Recurse -Force audio-hotplugThe integration code in ledfx/core.py is already correct:
from audio_hotplug import create_monitor
# In LedFx class __init__:
self._audio_monitor = create_monitor(
on_devices_changed=self._on_audio_devices_changed
)Update docs/apis/websocket.md (already done in previous PR)
# Regenerate lock file with PyPI dependency
uv lock --upgrade-package audio-hotplug# Install from PyPI
uv sync
# Run LedFx
uv run python -m ledfx --offline -vv
# Test audio device changes workgit add .
git commit -m "feat: Integrate audio-hotplug from PyPI
- Replace workspace dependency with PyPI package (audio-hotplug>=0.1.0)
- Remove audio-hotplug workspace directory
- Update uv.lock with PyPI dependency
- Audio device change monitoring now uses published package"
git push origin feat/audio-hotplug-pypi-integration
# Create PR on GitHubThis new PR should have ~10 files changed instead of 203!
- Day 1: Extract repository, set up CI/CD, test builds
- Day 2: Publish to TestPyPI, verify installation
- Day 3: Publish to PyPI, create clean LedFx PR
- Week 1: PR review and merge
pip install git-filter-repoUse API token instead:
python -m twine upload --username __token__ --password pypi-... dist/*Check the GitHub Actions logs for platform-specific issues. Windows/macOS/Linux may behave differently.
Verify package name is audio-hotplug on PyPI but imports as audio_hotplug (underscore):
import audio_hotplug # Correct
# NOT: import audio-hotplug- Add badges to README (build status, PyPI version, coverage)
- Set up documentation on ReadTheDocs
- Add changelog automation (release-drafter)
- Consider adding dependabot for dependency updates
- Set up semantic versioning for releases