443 lines
9.3 KiB
Markdown
443 lines
9.3 KiB
Markdown
---
|
|
name: python-pypi-setup
|
|
description: Set up Python project for PyPI publishing with pyproject.toml, src layout, and build scripts
|
|
---
|
|
|
|
# Python PyPI Project Setup Pattern
|
|
|
|
This skill helps you set up a Python project for PyPI publishing following modern best practices with pyproject.toml, src layout, and standardized build/publish scripts.
|
|
|
|
## When to Use This Skill
|
|
|
|
Use this skill when:
|
|
- Starting a new Python package for PyPI distribution
|
|
- You want to use modern pyproject.toml-based configuration
|
|
- You need a standardized src/ layout with explicit package discovery
|
|
- You want automated build and publish scripts
|
|
|
|
## What This Skill Creates
|
|
|
|
1. **`pyproject.toml`** - Modern Python project configuration
|
|
2. **`src/{package_name}/`** - Source layout with package structure
|
|
3. **`.gitignore`** - Comprehensive Python gitignore
|
|
4. **`dev-requirements.txt`** - Development dependencies (build, twine, testing tools)
|
|
5. **`build-publish.sh`** - Automated build and publish script
|
|
6. **`README.md`** - Basic project documentation
|
|
|
|
## Step 1: Gather Project Information
|
|
|
|
**IMPORTANT**: Before creating files, ask the user these questions:
|
|
|
|
1. **"What is your project name?"** (e.g., "pg-podcast-toolkit", "mypackage")
|
|
- Use this to derive:
|
|
- PyPI package name: `{project-name}` (with hyphens, e.g., `pg-podcast-toolkit`)
|
|
- Python package name: `{package_name}` (with underscores, e.g., `pg_podcast_toolkit`)
|
|
- Module directory: `src/{package_name}/`
|
|
|
|
2. **"What is the project description?"** (brief one-line description for PyPI)
|
|
|
|
3. **"What is your name?"** (for author field)
|
|
|
|
4. **"What is your email?"** (for author field)
|
|
|
|
5. **"What is your GitHub username?"** (for project URLs)
|
|
|
|
6. **"What license do you want to use?"** (options: MIT, Apache-2.0, GPL-3.0, BSD-3-Clause)
|
|
|
|
7. **"What Python version should be the minimum requirement?"** (default: 3.8)
|
|
|
|
8. **"What are your initial dependencies?"** (optional - comma-separated list, can be empty)
|
|
|
|
9. **"What keywords describe your project?"** (optional - for PyPI searchability)
|
|
|
|
## Step 2: Create Directory Structure
|
|
|
|
Create these directories if they don't exist:
|
|
```
|
|
{project_root}/
|
|
├── src/
|
|
│ └── {package_name}/
|
|
└── (other files at root)
|
|
```
|
|
|
|
## Step 3: Create pyproject.toml
|
|
|
|
Create `pyproject.toml` with the following structure, **substituting project-specific values**:
|
|
|
|
```toml
|
|
[project]
|
|
name = "{project-name}"
|
|
version = "0.0.1"
|
|
authors = [
|
|
{ name="{author_name}", email="{author_email}" },
|
|
]
|
|
description = "{project_description}"
|
|
keywords = [{keywords_list}]
|
|
readme = "README.md"
|
|
requires-python = ">={python_version}"
|
|
license = {text = "{license_name} License"}
|
|
classifiers = [
|
|
"Programming Language :: Python :: 3",
|
|
"License :: OSI Approved :: {license_classifier}",
|
|
"Operating System :: OS Independent",
|
|
]
|
|
dependencies = [
|
|
{dependencies_list}
|
|
]
|
|
|
|
[build-system]
|
|
requires = ["hatchling"]
|
|
build-backend = "hatchling.build"
|
|
|
|
[tool.hatch.build.targets.wheel]
|
|
packages = ["src/{package_name}"]
|
|
|
|
[project.urls]
|
|
Homepage = "https://github.com/{github_username}/{project-name}"
|
|
Issues = "https://github.com/{github_username}/{project-name}/issues"
|
|
```
|
|
|
|
**CRITICAL Substitutions**:
|
|
- `{project-name}` → project name with hyphens (e.g., `pg-podcast-toolkit`)
|
|
- `{package_name}` → package name with underscores (e.g., `pg_podcast_toolkit`)
|
|
- `{author_name}` → author's name
|
|
- `{author_email}` → author's email
|
|
- `{project_description}` → one-line description
|
|
- `{keywords_list}` → comma-separated quoted keywords (e.g., `"podcasting", "rss", "parser"`) or empty
|
|
- `{python_version}` → minimum Python version (e.g., `3.8`)
|
|
- `{license_name}` → license name (e.g., `MIT`, `Apache-2.0`)
|
|
- `{license_classifier}` → OSI classifier (e.g., `MIT License`, `Apache Software License`)
|
|
- `{dependencies_list}` → comma-separated quoted dependencies (e.g., `'requests', 'beautifulsoup4'`) or empty
|
|
- `{github_username}` → GitHub username
|
|
|
|
**License Classifiers Mapping**:
|
|
- MIT → `MIT License`
|
|
- Apache-2.0 → `Apache Software License`
|
|
- GPL-3.0 → `GNU General Public License v3 (GPLv3)`
|
|
- BSD-3-Clause → `BSD License`
|
|
|
|
## Step 4: Create Comprehensive .gitignore
|
|
|
|
Create `.gitignore` with comprehensive Python patterns:
|
|
|
|
```gitignore
|
|
# Byte-compiled / optimized / DLL files
|
|
__pycache__/
|
|
*.py[cod]
|
|
*$py.class
|
|
|
|
# C extensions
|
|
*.so
|
|
|
|
# Distribution / packaging
|
|
.Python
|
|
build/
|
|
develop-eggs/
|
|
dist/
|
|
downloads/
|
|
eggs/
|
|
.eggs/
|
|
lib/
|
|
lib64/
|
|
parts/
|
|
sdist/
|
|
var/
|
|
wheels/
|
|
pip-wheel-metadata/
|
|
share/python-wheels/
|
|
*.egg-info/
|
|
.installed.cfg
|
|
*.egg
|
|
MANIFEST
|
|
|
|
# PyInstaller
|
|
*.manifest
|
|
*.spec
|
|
|
|
# Unit test / coverage reports
|
|
htmlcov/
|
|
.tox/
|
|
.nox/
|
|
.coverage
|
|
.coverage.*
|
|
.cache
|
|
nosetests.xml
|
|
coverage.xml
|
|
*.cover
|
|
*.py,cover
|
|
.hypothesis/
|
|
.pytest_cache/
|
|
|
|
# Translations
|
|
*.mo
|
|
*.pot
|
|
|
|
# Django stuff:
|
|
*.log
|
|
local_settings.py
|
|
db.sqlite3
|
|
db.sqlite3-journal
|
|
|
|
# Flask stuff:
|
|
instance/
|
|
.webassets-cache
|
|
|
|
# Scrapy stuff:
|
|
.scrapy
|
|
|
|
# Sphinx documentation
|
|
docs/_build/
|
|
|
|
# PyBuilder
|
|
target/
|
|
|
|
# Jupyter Notebook
|
|
.ipynb_checkpoints
|
|
|
|
# IPython
|
|
profile_default/
|
|
ipython_config.py
|
|
|
|
# pyenv
|
|
.python-version
|
|
|
|
# pipenv
|
|
Pipfile.lock
|
|
|
|
# PEP 582
|
|
__pypackages__/
|
|
|
|
# Celery stuff
|
|
celerybeat-schedule
|
|
celerybeat.pid
|
|
|
|
# SageMath parsed files
|
|
*.sage.py
|
|
|
|
# Environments
|
|
.env
|
|
.venv
|
|
env/
|
|
venv/
|
|
ENV/
|
|
env.bak/
|
|
venv.bak/
|
|
bin/
|
|
include/
|
|
pyvenv.cfg
|
|
|
|
# Spyder project settings
|
|
.spyderproject
|
|
.spyproject
|
|
|
|
# Rope project settings
|
|
.ropeproject
|
|
|
|
# mkdocs documentation
|
|
/site
|
|
|
|
# mypy
|
|
.mypy_cache/
|
|
.dmypy.json
|
|
dmypy.json
|
|
|
|
# Pyre type checker
|
|
.pyre/
|
|
|
|
# IDEs
|
|
.vscode/
|
|
.idea/
|
|
*.swp
|
|
*.swo
|
|
*~
|
|
.DS_Store
|
|
```
|
|
|
|
## Step 5: Create dev-requirements.txt
|
|
|
|
Create `dev-requirements.txt` with development dependencies:
|
|
|
|
```
|
|
build
|
|
twine
|
|
pytest
|
|
black
|
|
mypy
|
|
```
|
|
|
|
These are the tools needed to build, publish, and develop the package. Add other dev tools as needed (isort, pytest-cov, etc.).
|
|
|
|
## Step 6: Create build-publish.sh
|
|
|
|
Create `build-publish.sh` with venv activation and build/publish commands:
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
# Build and publish package to PyPI
|
|
# Activates virtual environment before running
|
|
|
|
# Activate virtual environment
|
|
source bin/activate
|
|
|
|
# Clean previous builds
|
|
rm -rf dist/*
|
|
|
|
# Build package
|
|
python -m build
|
|
|
|
# Upload to PyPI
|
|
python -m twine upload dist/*
|
|
```
|
|
|
|
**Note**: This script follows the convention that the virtual environment is in `bin/` at the project root.
|
|
|
|
## Step 7: Create Package Structure
|
|
|
|
Create the basic package structure:
|
|
|
|
1. **`src/{package_name}/__init__.py`** - Package initialization file:
|
|
```python
|
|
"""
|
|
{project_description}
|
|
"""
|
|
|
|
__version__ = "0.0.1"
|
|
```
|
|
|
|
2. **If this is a library package**, you can add:
|
|
```python
|
|
# Export main classes/functions here for easier imports
|
|
# from .module import ClassName, function_name
|
|
# __all__ = ['ClassName', 'function_name']
|
|
```
|
|
|
|
## Step 8: Create README.md
|
|
|
|
Create `README.md` with basic project documentation:
|
|
|
|
```markdown
|
|
# {project-name}
|
|
|
|
{project_description}
|
|
|
|
## Installation
|
|
|
|
```bash
|
|
pip install {project-name}
|
|
```
|
|
|
|
## Usage
|
|
|
|
```python
|
|
import {package_name}
|
|
|
|
# Add usage examples here
|
|
```
|
|
|
|
## Development
|
|
|
|
### Setup
|
|
|
|
```bash
|
|
# Create virtual environment
|
|
python -m venv .
|
|
|
|
# Activate virtual environment
|
|
source bin/activate # On Windows: bin\Scripts\activate
|
|
|
|
# Install dependencies
|
|
pip install -r dev-requirements.txt
|
|
pip install -e .
|
|
```
|
|
|
|
### Building and Publishing
|
|
|
|
```bash
|
|
# Make sure you have PyPI credentials configured
|
|
# Build and publish to PyPI
|
|
./build-publish.sh
|
|
```
|
|
|
|
## License
|
|
|
|
{license_name}
|
|
|
|
## Author
|
|
|
|
{author_name} ({author_email})
|
|
```
|
|
|
|
## Step 9: Make Script Executable
|
|
|
|
Run:
|
|
```bash
|
|
chmod +x build-publish.sh
|
|
```
|
|
|
|
## Step 10: Create Initial Git Repository (if needed)
|
|
|
|
If not already a git repository:
|
|
```bash
|
|
git init
|
|
git add .
|
|
git commit -m "Initial project structure for PyPI package"
|
|
```
|
|
|
|
## Step 11: Document Next Steps
|
|
|
|
Inform the user of the next steps:
|
|
|
|
1. **Install development dependencies**:
|
|
```bash
|
|
source bin/activate
|
|
pip install -r dev-requirements.txt
|
|
```
|
|
|
|
2. **Install package in development mode**:
|
|
```bash
|
|
pip install -e .
|
|
```
|
|
|
|
3. **Write your code** in `src/{package_name}/`
|
|
|
|
4. **Update version** in `pyproject.toml` before publishing
|
|
|
|
5. **Configure PyPI credentials** (one-time setup):
|
|
```bash
|
|
# Create ~/.pypirc with your PyPI token
|
|
```
|
|
|
|
6. **Build and publish**:
|
|
```bash
|
|
./build-publish.sh
|
|
```
|
|
|
|
## Design Principles
|
|
|
|
This pattern follows these principles:
|
|
|
|
1. **Modern pyproject.toml** - No setup.py needed, all config in pyproject.toml
|
|
2. **Src Layout** - Source code in `src/` directory for better separation
|
|
3. **Explicit Package Discovery** - Using hatchling with explicit package paths
|
|
4. **Comprehensive .gitignore** - Covers all common Python artifacts
|
|
5. **Virtual Environment Convention** - Uses `bin/` at project root
|
|
6. **Automated Publishing** - Simple script for build and publish
|
|
7. **Best Practices** - Follows PEP 517/518 and modern Python packaging standards
|
|
|
|
## Example Usage in Claude Code
|
|
|
|
User: "Set up a Python package for PyPI"
|
|
Claude: "What is your project name?"
|
|
User: "awesome-lib"
|
|
Claude: [Asks remaining questions]
|
|
Claude:
|
|
1. Creates src/awesome_lib/ directory structure
|
|
2. Creates pyproject.toml with project metadata
|
|
3. Creates comprehensive .gitignore
|
|
4. Creates dev-requirements.txt with build tools and dev dependencies
|
|
5. Creates build-publish.sh script
|
|
6. Creates src/awesome_lib/__init__.py
|
|
7. Creates README.md with instructions
|
|
8. Makes script executable
|
|
9. Documents next steps for the user
|