All skills
github avatar

/python-pypi-package-builder

@49fd3f3 official
by githubgithub/awesome-copilot40k stars
5,040

End-to-end skill for building, testing, linting, versioning, and publishing a production-grade Python library to PyPI. Covers all four build backends (setuptools+setuptools_scm, hatchling, flit, poetry), PEP 440 versioning, semantic versioning, dynamic git-tag versioning, OOP/SOLID design, type hints (PEP 484/526/544/561), Trusted Publishing (OIDC), and the full PyPA packaging flow. Use for: creating Python packages, pip-installable SDKs, CLI tools, framework plugins, pyproject.toml setup, py.typed, setuptools_scm, semver, mypy, pre-commit, GitHub Actions CI/CD, or PyPI publishing.

Use this Skill: https://skilld.dev/gh/github/awesome-copilot/python-pypi-package-builder

This session only. Nothing lands on disk.

referencescommunity-docs.md

≈3.3k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Community Docs, PR Checklist, Anti-patterns, and Release Checklist

Table of Contents

  1. README.md required sections
  2. Docstrings — Google style
  3. CONTRIBUTING.md template
  4. SECURITY.md template
  5. GitHub Issue Templates
  6. PR Checklist
  7. Anti-patterns to avoid
  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.

# your-package

> One-line description — what it does and why it's useful.

[![PyPI version](https://badge.fury.io/py/your-package.svg)](https://pypi.org/project/your-package/)
[![Python Versions](https://img.shields.io/pypi/pyversions/your-package)](https://pypi.org/project/your-package/)
[![CI](https://github.com/you/your-package/actions/workflows/ci.yml/badge.svg)](https://github.com/you/your-package/actions/workflows/ci.yml)
[![Coverage](https://codecov.io/gh/you/your-package/branch/master/graph/badge.svg)](https://codecov.io/gh/you/your-package)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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.

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

# 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

# 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

---
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

# 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/

Source: SKILL.md on GitHub

No alerts10d4 checks · Risk SAFE
  • Gen Agent Trust Hub10d

    This skill provides a comprehensive and secure framework for building, testing, and publishing Python packages following industry best practices. It incorporates secure publishing via OpenID Connect (OIDC), uses modern and efficient tooling like Ruff, and provides a local scaffolding script that follows standard templating procedures. All external references and dependencies target well-known and trusted organizations within the Python and GitHub ecosystems.

  • Socket10d

    No alerts

  • Snyk10d

    Risk: LOW · No issues

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 49fd3f3. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub yesterday.

Activeupdated 6 months ago
  • Python
  • pypi
  • packaging
  • setuptools
  • hatchling
  • flit
  • poetry
  • versioning
  • ci-cd
  • github-actions

README badge

README badge for github/awesome-copilot/python-pypi-package-builder

Covers the full PyPI publishing pipeline for Python packages: build backend selection (setuptools+setuptools_scm, hatchling, flit, poetry), project structure (src/ vs flat), type hints, testing, versioning (PEP 440 / semver / git-tag), and GitHub Actions CI/CD with Trusted Publishing. Targets teams building pip-installable libraries, SDKs, CLI tools, or framework plugins.

Generated from the current SKILL.md.

Which build backend should I use?
Use setuptools + setuptools_scm if you want version derived from git tags. Use hatchling or flit for pure-Python projects without git-tag versioning. Use poetry v2+ if you want an all-in-one tool. Use setuptools only if you have C/Cython extensions.
Does this skill support publishing with Trusted Publishing (OIDC)?
Yes. The skill covers Trusted Publishing setup in the CI/publishing workflow references and includes GitHub Actions templates for OIDC-based PyPI publishing.
What folder structure should I use for a new package?
Use src/ layout as the default for new projects — it prevents accidental imports of uninstalled code and is PyPA-recommended. Use flat layout only for single-purpose packages with 1–4 modules.
Does this cover type hints and mypy configuration?
Yes. The skill includes PEP 484/526/544/561 type hint patterns, py.typed marker file setup, and complete mypy configuration in the testing and quality reference.
Can I use this skill for CLI tools, SDKs, and plugins?
Yes. The skill covers all package types including utility libraries, API clients/SDKs, CLI tools, framework plugins, and data processing libraries, with patterns and entry-point configuration for each.

Generated from the current SKILL.md. These answers refresh after source changes.