
Python Pypi Package Builder
Scaffold a publishable Python library with plugin backends, settings dataclass, HTTP transport abstraction, and optional CLI entrypoints for PyPI.
Install
npx skills add https://github.com/github/awesome-copilot --skill python-pypi-package-builderWhat is this skill?
- Plugin/strategy backends package: ABC or Protocol base, memory default, optional redis-style heavy extras
- Settings dataclass config layer with explicit decision rules for when to split modules
- HTTP client transport abstraction decoupled from core client logic
- CLI support patterns aligned with backend injection in the core client
- Decision rules section for choosing layout when scope grows beyond a single module
Adoption & trust: 684 installs on skills.sh; 34.6k GitHub stars; 2/3 security scanners passed (skills.sh audits).
Recommended Skills
Python Performance Optimizationwshobson/agents
Python Testing Patternswshobson/agents
Python Design Patternswshobson/agents
Python Executorqu-skills/skills
Async Python Patternswshobson/agents
Uv Package Managerwshobson/agents
Journey fit
Primary fit
Build/backend is the canonical home because the skill defines package architecture before ship-ready testing and release automation. Backend captures the plugin/strategy backends, core client injection, and transport layers that anchor most PyPI-bound libraries.
Common Questions / FAQ
Is Python Pypi Package Builder safe to install?
skills.sh reports 2 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.
SKILL.md
READMESKILL.md - Python Pypi Package Builder
# Architecture Patterns — Backend System, Config, Transport, CLI ## Table of Contents 1. [Backend System (Plugin/Strategy Pattern)](#1-backend-system-pluginstrategy-pattern) 2. [Config Layer (Settings Dataclass)](#2-config-layer-settings-dataclass) 3. [Transport Layer (HTTP Client Abstraction)](#3-transport-layer-http-client-abstraction) 4. [CLI Support](#4-cli-support) 5. [Backend Injection in Core Client](#5-backend-injection-in-core-client) 6. [Decision Rules](#6-decision-rules) --- ## 1. Backend System (Plugin/Strategy Pattern) Structure your `backends/` sub-package with a clear base protocol, a zero-dependency default implementation, and optional heavy implementations behind extras. ### Directory Layout ``` your_package/ backends/ __init__.py # Exports BaseBackend + factory; holds the Protocol/ABC base.py # Abstract base class (ABC) or Protocol definition memory.py # Default, zero-dependency in-memory implementation redis.py # Optional, heavier implementation (guarded by extras) ``` ### `backends/base.py` — Abstract Interface ```python # your_package/backends/base.py from __future__ import annotations from abc import ABC, abstractmethod class BaseBackend(ABC): """Abstract storage/processing backend. All concrete backends must implement these methods. Never import heavy dependencies at module level — guard them inside the class. """ @abstractmethod def get(self, key: str) -> str | None: """Retrieve a value by key. Return None when the key does not exist.""" ... @abstractmethod def set(self, key: str, value: str, ttl: int | None = None) -> None: """Store a value with an optional TTL (seconds).""" ... @abstractmethod def delete(self, key: str) -> None: """Remove a key. No-op when the key does not exist.""" ... def close(self) -> None: # noqa: B027 (intentionally non-abstract) """Optional cleanup hook. Override in backends that hold connections.""" ``` ### `backends/memory.py` — Default Zero-Dep Implementation ```python # your_package/backends/memory.py from __future__ import annotations import time from collections.abc import Iterator from contextlib import contextmanager from threading import Lock from .base import BaseBackend class MemoryBackend(BaseBackend): """Thread-safe in-memory backend. No external dependencies required.""" def __init__(self) -> None: self._store: dict[str, tuple[str, float | None]] = {} self._lock = Lock() def get(self, key: str) -> str | None: with self._lock: entry = self._store.get(key) if entry is None: return None value, expires_at = entry if expires_at is not None and time.monotonic() > expires_at: del self._store[key] return None return value def set(self, key: str, value: str, ttl: int | None = None) -> None: expires_at = time.monotonic() + ttl if ttl is not None else None with self._lock: self._store[key] = (value, expires_at) def delete(self, key: str) -> None: with self._lock: self._store.pop(key, None) ``` ### `backends/redis.py` — Optional Heavy Implementation ```python # your_package/backends/redis.py from __future__ import annotations from .base import BaseBackend class RedisBackend(BaseBackend): """Redis-backed implementation. Requires: pip install your-package[redis]""" def __init__(self, url: str = "redis://localhost:6379/0") -> None: try: import redis as _redis except ImportError as exc: raise ImportError( "RedisBackend requires redis. " "Install it with: pip install your-package[redis]" ) from exc self._client = _redis.from_url(url, decode_responses=True) def get(self, key: str) -> str | None: return se