mirror of
https://github.com/github/awesome-copilot.git
synced 2026-04-11 10:45:56 +00:00
* 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
9.2 KiB
9.2 KiB
Tooling — Ruff-Only Setup and Code Quality
Table of Contents
- Use Only Ruff (Replaces black, isort, flake8)
- Ruff Configuration in pyproject.toml
- mypy Configuration
- pre-commit Configuration
- pytest and Coverage Configuration
- Dev Dependencies in pyproject.toml
- CI Lint Job — Ruff Only
- Migration Guide — Removing black and isort
1. Use Only Ruff (Replaces black, isort, flake8)
Decision: Use ruff as the single linting and formatting tool. Remove black and isort.
| Old (avoid) | New (use) | What it does |
|---|---|---|
black |
ruff format |
Code formatting |
isort |
ruff check --select I |
Import sorting |
flake8 |
ruff check |
Style and error linting |
pyupgrade |
ruff check --select UP |
Upgrade syntax to modern Python |
bandit |
ruff check --select S |
Security linting |
| All of the above | ruff |
One tool, one config section |
Why ruff?
- 10–100× faster than the tools it replaces (written in Rust).
- Single config section in
pyproject.toml— no.flake8,.isort.cfg,pyproject.toml[tool.black]sprawl. - Actively maintained by Astral; follows the same rules as the tools it replaces.
ruff formatis black-compatible — existing black-formatted code passes without changes.
2. Ruff Configuration in pyproject.toml
[tool.ruff]
target-version = "py310" # Minimum supported Python version
line-length = 88 # black-compatible default
src = ["src", "tests"]
[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
"I", # isort
"B", # flake8-bugbear (opinionated but very useful)
"C4", # flake8-comprehensions
"UP", # pyupgrade (modernise syntax)
"SIM", # flake8-simplify
"TCH", # flake8-type-checking (move imports to TYPE_CHECKING block)
"ANN", # flake8-annotations (enforce type hints — remove if too strict)
"S", # flake8-bandit (security)
"N", # pep8-naming
]
ignore = [
"ANN101", # Missing type annotation for `self`
"ANN102", # Missing type annotation for `cls`
"S101", # Use of `assert` — necessary in tests
"S603", # subprocess without shell=True — often intentional
"B008", # Do not perform function calls in default arguments (false positives in FastAPI/Typer)
]
[tool.ruff.lint.isort]
known-first-party = ["your_package"]
[tool.ruff.lint.per-file-ignores]
"tests/**" = ["S101", "ANN", "D"] # Allow assert and skip annotations/docstrings in tests
[tool.ruff.format]
quote-style = "double" # black-compatible
indent-style = "space"
skip-magic-trailing-comma = false
line-ending = "auto"
Useful ruff commands
# Check for lint issues (no changes)
ruff check .
# Auto-fix fixable issues
ruff check --fix .
# Format code (replaces black)
ruff format .
# Check formatting without changing files (CI mode)
ruff format --check .
# Run both lint and format check in one command (for CI)
ruff check . && ruff format --check .
3. mypy Configuration
[tool.mypy]
python_version = "3.10"
strict = true
warn_return_any = true
warn_unused_ignores = true
warn_redundant_casts = true
disallow_untyped_defs = true
disallow_incomplete_defs = true
check_untyped_defs = true
no_implicit_optional = true
show_error_codes = true
# Ignore missing stubs for third-party packages that don't ship types
[[tool.mypy.overrides]]
module = ["redis.*", "pydantic_settings.*"]
ignore_missing_imports = true
Running mypy — handle both src and flat layouts
# src layout:
mypy src/your_package/
# flat layout:
mypy your_package/
In CI, detect layout dynamically:
- name: Run mypy
run: |
if [ -d "src" ]; then
mypy src/
else
mypy your_package/
fi
4. pre-commit Configuration
# .pre-commit-config.yaml
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.4.4 # Pin to a specific release; update periodically with `pre-commit autoupdate`
hooks:
- id: ruff
args: [--fix] # Auto-fix what can be fixed
- id: ruff-format # Format (replaces black hook)
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.10.0
hooks:
- id: mypy
additional_dependencies:
- types-requests
- types-redis
# Add stubs for any typed dependency used in your package
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-toml
- id: check-yaml
- id: check-merge-conflict
- id: check-added-large-files
args: ["--maxkb=500"]
❌ Remove these hooks (replaced by ruff)
# DELETE or never add:
- repo: https://github.com/psf/black # replaced by ruff-format
- repo: https://github.com/PyCQA/isort # replaced by ruff lint I rules
- repo: https://github.com/PyCQA/flake8 # replaced by ruff check
- repo: https://github.com/PyCQA/autoflake # replaced by ruff check F401
Setup
pip install pre-commit
pre-commit install # Installs git hook — runs on every commit
pre-commit run --all-files # Run manually on all files
pre-commit autoupdate # Update all hooks to latest pinned versions
5. pytest and Coverage Configuration
[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = "-ra -q --strict-markers --cov=your_package --cov-report=term-missing"
asyncio_mode = "auto" # Enables async tests without @pytest.mark.asyncio decorator
[tool.coverage.run]
source = ["your_package"]
branch = true
omit = ["**/__main__.py", "**/cli.py"] # omit entry points from coverage
[tool.coverage.report]
show_missing = true
skip_covered = false
fail_under = 85 # Fail CI if coverage drops below 85%
exclude_lines = [
"pragma: no cover",
"if TYPE_CHECKING:",
"raise NotImplementedError",
"@abstractmethod",
]
asyncio_mode = "auto" — remove @pytest.mark.asyncio
With asyncio_mode = "auto" set in pyproject.toml, do not add @pytest.mark.asyncio
to test functions. The decorator is redundant and will raise a warning in modern pytest-asyncio.
# WRONG — the decorator is deprecated when asyncio_mode = "auto":
@pytest.mark.asyncio
async def test_async_operation():
result = await my_async_func()
assert result == expected
# CORRECT — just use async def:
async def test_async_operation():
result = await my_async_func()
assert result == expected
6. Dev Dependencies in pyproject.toml
Declare all dev/test tools in an [extras] group named dev.
[project.optional-dependencies]
dev = [
"pytest>=8",
"pytest-asyncio>=0.23",
"pytest-cov>=5",
"ruff>=0.4",
"mypy>=1.10",
"pre-commit>=3.7",
"httpx>=0.27", # If testing HTTP transport
"respx>=0.21", # If mocking httpx in tests
]
redis = [
"redis>=5",
]
docs = [
"mkdocs-material>=9",
"mkdocstrings[python]>=0.25",
]
Install dev dependencies:
pip install -e ".[dev]"
pip install -e ".[dev,redis]" # Include optional extras
7. CI Lint Job — Ruff Only
Replace the separate black, isort, and flake8 steps with a single ruff step.
# .github/workflows/ci.yml — lint job
lint:
name: Lint & Type Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install dev dependencies
run: pip install -e ".[dev]"
# Single step: ruff replaces black + isort + flake8
- name: ruff lint
run: ruff check .
- name: ruff format check
run: ruff format --check .
- name: mypy
run: |
if [ -d "src" ]; then
mypy src/
else
mypy $(basename $(ls -d */))/ 2>/dev/null || mypy .
fi
8. Migration Guide — Removing black and isort
If you are converting an existing project that used black and isort:
# 1. Remove black and isort from dev dependencies
pip uninstall black isort
# 2. Remove black and isort config sections from pyproject.toml
# [tool.black] ← delete this section
# [tool.isort] ← delete this section
# 3. Add ruff to dev dependencies (see Section 2 for config)
# 4. Run ruff format to confirm existing code is already compatible
ruff format --check .
# ruff format is black-compatible; output should be identical
# 5. Update .pre-commit-config.yaml (see Section 4)
# Remove black and isort hooks; add ruff and ruff-format hooks
# 6. Update CI (see Section 7)
# Remove black, isort, flake8 steps; add ruff check + ruff format --check
# 7. Reinstall pre-commit hooks
pre-commit uninstall
pre-commit install
pre-commit run --all-files # Verify clean