Agent skill
python-project-development
Creates production-ready Python projects including CLI tools, packages, and distributable libraries. Use when building CLI tools with argparse/click, packaging for PyPI, setting up pyproject.toml, or creating entry points. Triggers include "CLI tool", "Python package", "pyproject.toml", "publish to PyPI", "entry points", or "build wheel".
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/python-project-development
SKILL.md
Python Project Development
Comprehensive guide for building production-ready Python CLI tools and distributable packages.
When to Use This Skill
- Building command-line tools with argparse or click
- Creating Python libraries for distribution
- Publishing packages to PyPI
- Setting up modern pyproject.toml configuration
- Creating installable packages with dependencies
- Building wheels and source distributions
Quick Start: CLI Tool
#!/usr/bin/env python3
"""Brief description of what this script does."""
import sys
from pathlib import Path
from dataclasses import dataclass
from typing import Final
@dataclass(frozen=True, slots=True)
class Config:
"""Immutable configuration."""
input_dir: Path
max_size: int = 1000
verbose: bool = False
def main() -> int:
"""Entry point. Returns exit code."""
try:
# Parse args, validate input, process
return 0
except ValueError as e:
print(f"Error: {e}", file=sys.stderr)
return 1
if __name__ == "__main__":
sys.exit(main())
Quick Start: Package Structure
my-package/
├── pyproject.toml
├── README.md
├── LICENSE
├── src/
│ └── my_package/
│ ├── __init__.py
│ ├── cli.py
│ └── core.py
└── tests/
└── test_core.py
Minimal pyproject.toml
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"
[project]
name = "my-package"
version = "0.1.0"
description = "A short description"
authors = [{name = "Your Name", email = "[email protected]"}]
readme = "README.md"
requires-python = ">=3.8"
dependencies = ["click>=8.0"]
[project.optional-dependencies]
dev = ["pytest>=7.0", "ruff>=0.1"]
[project.scripts]
my-cli = "my_package.cli:main"
[tool.setuptools.packages.find]
where = ["src"]
CLI Standards
- Types: All functions typed (
-> ReturnType),dataclass(slots=True)for data - Performance: O(n) algorithms, frozenset for lookups, generators for large data
- Stdlib-first: Zero external deps unless justified
- Exit codes: 0=success, 1=error, 2+=specific failures
- Error handling: Catch specific exceptions, fail fast, clear messages
CLI with Click
# src/my_package/cli.py
import click
@click.group()
@click.version_option()
def cli():
"""My awesome CLI tool."""
pass
@cli.command()
@click.argument("name")
@click.option("--greeting", default="Hello", help="Greeting to use")
def greet(name: str, greeting: str):
"""Greet someone."""
click.echo(f"{greeting}, {name}!")
def main():
cli()
if __name__ == "__main__":
main()
CLI with argparse
import argparse
import sys
def main():
parser = argparse.ArgumentParser(description="My tool", prog="my-tool")
parser.add_argument("--version", action="version", version="%(prog)s 1.0.0")
subparsers = parser.add_subparsers(dest="command", help="Commands")
process_parser = subparsers.add_parser("process", help="Process data")
process_parser.add_argument("input_file", help="Input file")
process_parser.add_argument("-o", "--output", default="output.txt")
args = parser.parse_args()
if args.command == "process":
return process_data(args.input_file, args.output)
parser.print_help()
return 1
if __name__ == "__main__":
sys.exit(main())
Full pyproject.toml Template
[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "my-package"
version = "1.0.0"
description = "Package description"
readme = "README.md"
requires-python = ">=3.8"
license = {text = "MIT"}
authors = [{name = "Name", email = "[email protected]"}]
keywords = ["example", "package"]
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
]
dependencies = [
"click>=8.0.0",
"pydantic>=2.0.0",
]
[project.optional-dependencies]
dev = ["pytest>=7.0", "ruff>=0.1", "mypy>=1.0"]
[project.urls]
Homepage = "https://github.com/user/my-package"
Documentation = "https://my-package.readthedocs.io"
Repository = "https://github.com/user/my-package"
[project.scripts]
my-cli = "my_package.cli:main"
[tool.setuptools]
package-dir = {"" = "src"}
[tool.setuptools.packages.find]
where = ["src"]
[tool.setuptools.package-data]
my_package = ["py.typed", "data/*.json"]
[tool.ruff]
line-length = 100
target-version = "py38"
[tool.ruff.lint]
select = ["E", "F", "I", "N", "W", "UP"]
[tool.mypy]
python_version = "3.8"
warn_return_any = true
disallow_untyped_defs = true
[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = "-v --cov=my_package"
Building and Publishing
# Install build tools
uv pip install build twine
# Build distribution
python -m build
# Check distribution
twine check dist/*
# Test on TestPyPI first
twine upload --repository testpypi dist/*
# Publish to PyPI
twine upload dist/*
Editable Install for Development
# Install in development mode
uv pip install -e .
# With optional dependencies
uv pip install -e ".[dev]"
Dynamic Versioning
[build-system]
requires = ["setuptools>=61.0", "setuptools-scm>=8.0"]
build-backend = "setuptools.build_meta"
[project]
name = "my-package"
dynamic = ["version"]
[tool.setuptools_scm]
write_to = "src/my_package/_version.py"
Including Data Files
[tool.setuptools.package-data]
my_package = ["data/*.json", "templates/*.html", "py.typed"]
# Accessing data files
from importlib.resources import files
data = files("my_package").joinpath("data/config.json").read_text()
Security Checklist
- No hardcoded secrets/paths
- Validate all user input (paths, patterns)
- Use
Path.resolve()to prevent traversal - Catch
PermissionError,FileNotFoundError - Timeout on subprocess calls
- No
eval(),exec(),__import__()
Publishing Checklist
- Code is tested (pytest passing)
- Documentation complete (README, docstrings)
- Version number updated
- CHANGELOG.md updated
- License file included
- pyproject.toml complete
- Package builds without errors
- Installation tested in clean environment
- Tested on TestPyPI first
- Git tag created for release
Reusable Components
Use battle-tested components from scripts/:
cli_template.py- Production CLI scaffold with argparselog_component.py- ANSI colored loggingsubprocess_helpers.py- Safe subprocess wrappers with retry/timeoutcommon_utils.py- has(), find_files(), safe file ops
See references/patterns.md for common CLI patterns and references/stdlib_perf.md for performance tips.
Resources
- Python Packaging Guide: https://packaging.python.org/
- PyPI: https://pypi.org/
- setuptools: https://setuptools.pypa.io/
- Click: https://click.palletsprojects.com/
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?