mirror of
https://github.com/github/awesome-copilot.git
synced 2026-04-12 03:05:55 +00:00
Add new skill: Python PyPI Package Builder (#1302)
* Add python-pypi-package-builder skill for Python packaging - Created `SKILL.md` defining decision-driven workflow for building, testing, versioning, and publishing Python packages. - Added reference modules covering PyPA packaging, architecture patterns, CI/CD, testing, versioning strategy, and release governance. - Implemented scaffold script to generate complete project structure with pyproject.toml, CI workflows, tests, and configuration. - Included support for multiple build backends (setuptools_scm, hatchling, flit, poetry) with clear decision rules. - Added secure release practices including tag-based versioning, branch protection, and OIDC Trusted Publishing. * fix: correct spelling issues detected by codespell
This commit is contained in:
411
skills/python-pypi-package-builder/references/community-docs.md
Normal file
411
skills/python-pypi-package-builder/references/community-docs.md
Normal file
@@ -0,0 +1,411 @@
|
||||
# Community Docs, PR Checklist, Anti-patterns, and Release Checklist
|
||||
|
||||
## Table of Contents
|
||||
1. [README.md required sections](#1-readmemd-required-sections)
|
||||
2. [Docstrings — Google style](#2-docstrings--google-style)
|
||||
3. [CONTRIBUTING.md template](#3-contributingmd)
|
||||
4. [SECURITY.md template](#4-securitymd)
|
||||
5. [GitHub Issue Templates](#5-github-issue-templates)
|
||||
6. [PR Checklist](#6-pr-checklist)
|
||||
7. [Anti-patterns to avoid](#7-anti-patterns-to-avoid)
|
||||
8. [Master Release Checklist](#8-master-release-checklist)
|
||||
|
||||
---
|
||||
|
||||
## 1. `README.md` Required Sections
|
||||
|
||||
A good README is the single most important file for adoption. Users decide in 30 seconds whether
|
||||
to use your library based on the README.
|
||||
|
||||
```markdown
|
||||
# your-package
|
||||
|
||||
> One-line description — what it does and why it's useful.
|
||||
|
||||
[](https://pypi.org/project/your-package/)
|
||||
[](https://pypi.org/project/your-package/)
|
||||
[](https://github.com/you/your-package/actions/workflows/ci.yml)
|
||||
[](https://codecov.io/gh/you/your-package)
|
||||
[](LICENSE)
|
||||
|
||||
## Installation
|
||||
|
||||
pip install your-package
|
||||
|
||||
# With Redis backend:
|
||||
pip install "your-package[redis]"
|
||||
|
||||
## Quick Start
|
||||
|
||||
(A copy-paste working example — no setup required to run it)
|
||||
|
||||
from your_package import YourClient
|
||||
|
||||
client = YourClient(api_key="sk-...")
|
||||
result = client.process({"input": "value"})
|
||||
print(result)
|
||||
|
||||
## Features
|
||||
|
||||
- Feature 1
|
||||
- Feature 2
|
||||
|
||||
## Configuration
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
|---|---|---|—--|
|
||||
| api_key | str | required | Authentication credential |
|
||||
| timeout | int | 30 | Request timeout in seconds |
|
||||
| retries | int | 3 | Number of retry attempts |
|
||||
|
||||
## Backends
|
||||
|
||||
Brief comparison — in-memory vs Redis — and when to use each.
|
||||
|
||||
## Contributing
|
||||
|
||||
See [CONTRIBUTING.md](./CONTRIBUTING.md)
|
||||
|
||||
## Changelog
|
||||
|
||||
See [CHANGELOG.md](./CHANGELOG.md)
|
||||
|
||||
## License
|
||||
|
||||
MIT — see [LICENSE](./LICENSE)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Docstrings — Google Style
|
||||
|
||||
Use Google-style docstrings for every public class, method, and function. IDEs display these
|
||||
as tooltips, mkdocs/sphinx can auto-generate documentation from them, and they convey intent
|
||||
clearly to contributors.
|
||||
|
||||
```python
|
||||
class YourClient:
|
||||
"""
|
||||
Main client for <purpose>.
|
||||
|
||||
Args:
|
||||
api_key: Authentication credential.
|
||||
timeout: Request timeout in seconds. Defaults to 30.
|
||||
retries: Number of retry attempts. Defaults to 3.
|
||||
|
||||
Raises:
|
||||
ValueError: If api_key is empty or timeout is non-positive.
|
||||
|
||||
Example:
|
||||
>>> from your_package import YourClient
|
||||
>>> client = YourClient(api_key="sk-...")
|
||||
>>> result = client.process({"input": "value"})
|
||||
"""
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. `CONTRIBUTING.md`
|
||||
|
||||
```markdown
|
||||
# Contributing to your-package
|
||||
|
||||
## Development Setup
|
||||
|
||||
git clone https://github.com/you/your-package
|
||||
cd your-package
|
||||
pip install -e ".[dev]"
|
||||
pre-commit install
|
||||
|
||||
## Running Tests
|
||||
|
||||
pytest
|
||||
|
||||
## Running Linting
|
||||
|
||||
ruff check .
|
||||
black . --check
|
||||
mypy your_package/
|
||||
|
||||
## Submitting a PR
|
||||
|
||||
1. Fork the repository
|
||||
2. Create a feature branch: `git checkout -b feat/your-feature`
|
||||
3. Make changes with tests
|
||||
4. Ensure CI passes: `pre-commit run --all-files && pytest`
|
||||
5. Update `CHANGELOG.md` under `[Unreleased]`
|
||||
6. Open a PR — use the PR template
|
||||
|
||||
## Commit Message Format (Conventional Commits)
|
||||
|
||||
- `feat: add Redis backend`
|
||||
- `fix: correct retry behavior on timeout`
|
||||
- `docs: update README quick start`
|
||||
- `chore: bump ruff to 0.5`
|
||||
- `test: add edge cases for memory backend`
|
||||
|
||||
## Reporting Bugs
|
||||
|
||||
Use the GitHub issue template. Include Python version, package version,
|
||||
and a minimal reproducible example.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. `SECURITY.md`
|
||||
|
||||
```markdown
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
| Version | Supported |
|
||||
|---|---|
|
||||
| 1.x.x | Yes |
|
||||
| < 1.0 | No |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Do NOT open a public GitHub issue for security vulnerabilities.
|
||||
|
||||
Report via: GitHub private security reporting (preferred)
|
||||
or email: security@yourdomain.com
|
||||
|
||||
Include:
|
||||
- Description of the vulnerability
|
||||
- Steps to reproduce
|
||||
- Potential impact
|
||||
- Suggested fix (if any)
|
||||
|
||||
We aim to acknowledge within 48 hours and resolve within 14 days.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. GitHub Issue Templates
|
||||
|
||||
### `.github/ISSUE_TEMPLATE/bug_report.md`
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: Bug Report
|
||||
about: Report a reproducible bug
|
||||
labels: bug
|
||||
---
|
||||
|
||||
**Python version:**
|
||||
**Package version:**
|
||||
|
||||
**Describe the bug:**
|
||||
|
||||
**Minimal reproducible example:**
|
||||
```python
|
||||
# paste code here
|
||||
```
|
||||
|
||||
**Expected behavior:**
|
||||
|
||||
**Actual behavior:**
|
||||
```
|
||||
|
||||
### `.github/ISSUE_TEMPLATE/feature_request.md`
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: Feature Request
|
||||
about: Suggest a new feature or enhancement
|
||||
labels: enhancement
|
||||
---
|
||||
|
||||
**Problem this would solve:**
|
||||
|
||||
**Proposed solution:**
|
||||
|
||||
**Alternatives considered:**
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. PR Checklist
|
||||
|
||||
All items must be checked before requesting review. CI must be fully green.
|
||||
|
||||
### Code Quality Gates
|
||||
```
|
||||
[ ] ruff check . — zero errors
|
||||
[ ] black . --check — zero formatting issues
|
||||
[ ] isort . --check-only — imports sorted correctly
|
||||
[ ] mypy your_package/ — zero type errors
|
||||
[ ] pytest — all tests pass
|
||||
[ ] Coverage >= 80% (enforced by fail_under in pyproject.toml)
|
||||
[ ] All GitHub Actions workflows green
|
||||
```
|
||||
|
||||
### Structure
|
||||
```
|
||||
[ ] pyproject.toml: name, dynamic/version, description, requires-python, license, authors,
|
||||
keywords (10+), classifiers, dependencies, all [project.urls] filled in
|
||||
[ ] dynamic = ["version"] if using setuptools_scm
|
||||
[ ] [tool.setuptools_scm] with local_scheme = "no-local-version"
|
||||
[ ] setup.py shim present (if using setuptools_scm)
|
||||
[ ] py.typed marker file exists in the package directory (empty file)
|
||||
[ ] py.typed listed in [tool.setuptools.package-data]
|
||||
[ ] "Typing :: Typed" classifier in pyproject.toml
|
||||
[ ] __init__.py has __all__ listing all public symbols
|
||||
[ ] __version__ via importlib.metadata (not hardcoded string)
|
||||
```
|
||||
|
||||
### Testing
|
||||
```
|
||||
[ ] conftest.py has shared fixtures for client and backend
|
||||
[ ] Core happy path tested
|
||||
[ ] Error conditions and edge cases tested
|
||||
[ ] Each backend tested independently in isolation
|
||||
[ ] Redis backend tested in separate CI job with redis service (if applicable)
|
||||
[ ] asyncio_mode = "auto" in pyproject.toml (for async tests)
|
||||
[ ] fetch-depth: 0 in all CI checkout steps
|
||||
```
|
||||
|
||||
### Optional Backend (if applicable)
|
||||
```
|
||||
[ ] BaseBackend abstract class defines the interface
|
||||
[ ] MemoryBackend works with zero extra deps
|
||||
[ ] RedisBackend raises ImportError with clear pip install hint if redis not installed
|
||||
[ ] Both backends unit-tested independently
|
||||
[ ] redis extra declared in [project.optional-dependencies]
|
||||
[ ] README shows both install paths (base and [redis])
|
||||
```
|
||||
|
||||
### Changelog & Docs
|
||||
```
|
||||
[ ] CHANGELOG.md updated under [Unreleased]
|
||||
[ ] README has: description, install, quick start, config table, badges, license
|
||||
[ ] All public symbols have Google-style docstrings
|
||||
[ ] CONTRIBUTING.md: dev setup, test/lint commands, PR instructions
|
||||
[ ] SECURITY.md: supported versions, reporting process
|
||||
[ ] .github/ISSUE_TEMPLATE/bug_report.md
|
||||
[ ] .github/ISSUE_TEMPLATE/feature_request.md
|
||||
```
|
||||
|
||||
### CI/CD
|
||||
```
|
||||
[ ] ci.yml: lint + mypy + test matrix (all supported Python versions)
|
||||
[ ] ci.yml: separate job for Redis backend with redis service
|
||||
[ ] publish.yml: triggered on v*.*.* tags, uses Trusted Publishing (OIDC)
|
||||
[ ] fetch-depth: 0 in all workflow checkout steps
|
||||
[ ] pypi environment created in GitHub repo Settings → Environments
|
||||
[ ] No API tokens in repository secrets
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Anti-patterns to Avoid
|
||||
|
||||
| Anti-pattern | Why it's bad | Correct approach |
|
||||
|---|---|---|
|
||||
| `__version__ = "1.0.0"` hardcoded with setuptools_scm | Goes stale after first git tag | Use `importlib.metadata.version()` |
|
||||
| Missing `fetch-depth: 0` in CI checkout | setuptools_scm can't find tags → version = `0.0.0+dev` | Add `fetch-depth: 0` to **every** checkout step |
|
||||
| `local_scheme` not set | `+g<hash>` suffix breaks PyPI uploads (local versions rejected) | `local_scheme = "no-local-version"` |
|
||||
| Missing `py.typed` file | IDEs and mypy don't see package as typed | Create empty `py.typed` in package root |
|
||||
| `py.typed` not in `package-data` | File missing from installed wheel — useless | Add to `[tool.setuptools.package-data]` |
|
||||
| Importing optional dep at module top | `ImportError` on `import your_package` for all users | Lazy import inside the function/class that needs it |
|
||||
| Duplicating metadata in `setup.py` | Conflicts with `pyproject.toml`; drifts | Keep `setup.py` as 3-line shim only |
|
||||
| No `fail_under` in coverage config | Coverage regressions go unnoticed | Set `fail_under = 80` |
|
||||
| No mypy in CI | Type errors silently accumulate | Add mypy step to `ci.yml` |
|
||||
| API tokens in GitHub Secrets for PyPI | Security risk, rotation burden | Use Trusted Publishing (OIDC) |
|
||||
| Committing directly to `main`/`master` | Bypasses CI checks | Enforce via `no-commit-to-branch` pre-commit hook |
|
||||
| Missing `[Unreleased]` section in CHANGELOG | Changes pile up and get forgotten at release time | Keep `[Unreleased]` updated every PR |
|
||||
| Pinning exact dep versions in a library | Breaks dependency resolution for users | Use `>=` lower bounds only; avoid `==` |
|
||||
| No `__all__` in `__init__.py` | Users can accidentally import internal helpers | Declare `__all__` with every public symbol |
|
||||
| `from your_package import *` in tests | Tests pass even when imports are broken | Always use explicit imports |
|
||||
| No `SECURITY.md` | No path for responsible vulnerability disclosure | Add file with response timeline |
|
||||
| `Any` everywhere in type hints | Defeats mypy entirely | Use `object` for truly arbitrary values |
|
||||
| `Union` return types | Forces every caller to write `isinstance()` checks | Return concrete types; use overloads |
|
||||
| `setup.cfg` + `pyproject.toml` both active | Conflicts and confusing for contributors | Migrate everything to `pyproject.toml` |
|
||||
| Releasing on untagged commits | Version number is meaningless | Always tag before release |
|
||||
| Not testing on all supported Python versions | Breakage discovered by users, not you | Matrix test in CI |
|
||||
| `license = {text = "MIT"}` (old form) | Deprecated; PEP 639 uses SPDX strings | `license = "MIT"` |
|
||||
| No issue templates | Bug reports are inconsistent | Add `bug_report.md` + `feature_request.md` |
|
||||
|
||||
---
|
||||
|
||||
## 8. Master Release Checklist
|
||||
|
||||
Run through every item before pushing a release tag. CI must be fully green.
|
||||
|
||||
### Code Quality
|
||||
```
|
||||
[ ] ruff check . — zero errors
|
||||
[ ] ruff format . --check — zero formatting issues
|
||||
[ ] mypy src/your_package/ — zero type errors
|
||||
[ ] pytest — all tests pass
|
||||
[ ] Coverage >= 80% (fail_under enforced in pyproject.toml)
|
||||
[ ] All GitHub Actions CI jobs green (lint + test matrix)
|
||||
```
|
||||
|
||||
### Project Structure
|
||||
```
|
||||
[ ] pyproject.toml — name, description, requires-python, license (SPDX string), authors,
|
||||
keywords (10+), classifiers (Python versions + Typing :: Typed), urls (all 5 fields)
|
||||
[ ] dynamic = ["version"] set (if using setuptools_scm or hatch-vcs)
|
||||
[ ] [tool.setuptools_scm] with local_scheme = "no-local-version"
|
||||
[ ] setup.py shim present (if using setuptools_scm)
|
||||
[ ] py.typed marker file exists (empty file in package root)
|
||||
[ ] py.typed listed in [tool.setuptools.package-data]
|
||||
[ ] "Typing :: Typed" classifier in pyproject.toml
|
||||
[ ] __init__.py has __all__ listing all public symbols
|
||||
[ ] __version__ reads from importlib.metadata (not hardcoded)
|
||||
```
|
||||
|
||||
### Testing
|
||||
```
|
||||
[ ] conftest.py has shared fixtures for client and backend
|
||||
[ ] Core happy path tested
|
||||
[ ] Error conditions and edge cases tested
|
||||
[ ] Each backend tested independently in isolation
|
||||
[ ] asyncio_mode = "auto" in pyproject.toml (for async tests)
|
||||
[ ] fetch-depth: 0 in all CI checkout steps
|
||||
```
|
||||
|
||||
### CHANGELOG and Docs
|
||||
```
|
||||
[ ] CHANGELOG.md: [Unreleased] entries moved to [x.y.z] - YYYY-MM-DD
|
||||
[ ] README has: description, install commands, quick start, config table, badges
|
||||
[ ] All public symbols have Google-style docstrings
|
||||
[ ] CONTRIBUTING.md: dev setup, test/lint commands, PR instructions
|
||||
[ ] SECURITY.md: supported versions, reporting process with timeline
|
||||
```
|
||||
|
||||
### Versioning
|
||||
```
|
||||
[ ] All CI checks pass on the commit you plan to tag
|
||||
[ ] CHANGELOG.md updated and committed
|
||||
[ ] Git tag follows format v1.2.3 (semver, v prefix)
|
||||
[ ] No stale local_scheme suffixes will appear in the built wheel name
|
||||
```
|
||||
|
||||
### CI/CD
|
||||
```
|
||||
[ ] ci.yml: lint + mypy + test matrix (all supported Python versions)
|
||||
[ ] publish.yml: triggered on v*.*.* tags, uses Trusted Publishing (OIDC)
|
||||
[ ] pypi environment created in GitHub repo Settings → Environments
|
||||
[ ] No API tokens stored in repository secrets
|
||||
```
|
||||
|
||||
### The Release Command Sequence
|
||||
```bash
|
||||
# 1. Run full local validation
|
||||
ruff check . ; ruff format . --check ; mypy src/your_package/ ; pytest
|
||||
|
||||
# 2. Update CHANGELOG.md — move [Unreleased] to [x.y.z]
|
||||
# 3. Commit the changelog
|
||||
git add CHANGELOG.md
|
||||
git commit -m "chore: prepare release vX.Y.Z"
|
||||
|
||||
# 4. Tag and push — this triggers publish.yml automatically
|
||||
git tag vX.Y.Z
|
||||
git push origin main --tags
|
||||
|
||||
# 5. Monitor: https://github.com/<you>/<pkg>/actions
|
||||
# 6. Verify: https://pypi.org/project/your-package/
|
||||
```
|
||||
Reference in New Issue
Block a user