Modern Python Guide for modern Python tooling and best practices, based on trailofbits/cookiecutter-python. When to Use This Skill - Creating a new Python project or package - Setting up configuration - Configuring development tools (linting, formatting, testing) - Writing Python scripts with external dependencies - Migrating from legacy tools (when user requests it) When NOT to Use This Skill - User wants to keep legacy tooling : Respect existing workflows if explicitly requested - Python < 3.11 required : These tools target modern Python - Non-Python projects : Mixed codebases where Python…

| while read -r pkg; do\n uv add \"$pkg\" || echo \"Failed to add: $pkg\"\ndone\n\nuv sync\n```\n\nThen:\n1. Delete `requirements.txt`, `requirements-dev.txt`\n2. Delete virtual environment (`venv/`, `.venv/`)\n3. Add `uv.lock` to version control\n\n### From setup.py / setup.cfg\n\n1. Run `uv init --bare` to create pyproject.toml\n2. Use `uv add` to add each dependency from `install_requires`\n3. Use `uv add --group dev` for dev dependencies\n4. Copy non-dependency metadata (name, version, description, etc.) to `[project]`\n5. Delete `setup.py`, `setup.cfg`, `MANIFEST.in`\n\n### From flake8 + black + isort\n\n1. Remove flake8, black, isort via `uv remove`\n2. Delete `.flake8`, `pyproject.toml [tool.black]`, `[tool.isort]` configs\n3. Add ruff: `uv add --group dev ruff`\n4. Add ruff configuration (see [ruff-config.md](./references/ruff-config.md))\n5. Run `uv run ruff check --fix .` to apply fixes\n6. Run `uv run ruff format .` to format\n\n### From mypy / pyright\n\n1. Remove mypy/pyright via `uv remove`\n2. Delete `mypy.ini`, `pyrightconfig.json`, or `[tool.mypy]`/`[tool.pyright]` sections\n3. Add ty: `uv add --group dev ty`\n4. Run `uv run ty check src/`\n\n## Quick Reference: uv Commands\n\n| Command | Description |\n|---------|-------------|\n| `uv init` | Create new project |\n| `uv init --package` | Create distributable package |\n| `uv add \u003cpkg>` | Add dependency |\n| `uv add --group dev \u003cpkg>` | Add to dependency group |\n| `uv remove \u003cpkg>` | Remove dependency |\n| `uv sync` | Install dependencies |\n| `uv sync --all-groups` | Install all dependency groups |\n| `uv run \u003ccmd>` | Run command in venv |\n| `uv run --with \u003cpkg> \u003ccmd>` | Run with temporary dependency |\n| `uv build` | Build package |\n| `uv publish` | Publish to PyPI |\n\n### Ad-hoc Dependencies with `--with`\n\nUse `uv run --with` for one-off commands that need packages not in your project:\n\n```bash\n# Run Python with a temporary package\nuv run --with requests python -c \"import requests; print(requests.get('https://httpbin.org/ip').json())\"\n\n# Run a module with temporary deps\nuv run --with rich python -m rich.progress\n\n# Multiple packages\nuv run --with requests --with rich python script.py\n\n# Combine with project deps (adds to existing venv)\nuv run --with httpx pytest # project deps + httpx\n```\n\n**When to use `--with` vs `uv add`:**\n- `uv add`: Package is a project dependency (goes in pyproject.toml/uv.lock)\n- `--with`: One-off usage, testing, or scripts outside a project context\n\nSee [uv-commands.md](./references/uv-commands.md) for complete reference.\n\n## Quick Reference: Dependency Groups\n\n```toml\n[dependency-groups]\ndev = [\"ruff\", \"ty\"]\ntest = [\"pytest\", \"pytest-cov\", \"hypothesis\"]\ndocs = [\"sphinx\", \"myst-parser\"]\n```\n\nInstall with: `uv sync --group dev --group test`\n\n## Best Practices Checklist\n\n- [ ] Use `src/` layout for packages\n- [ ] Set `requires-python = \">=3.11\"`\n- [ ] Configure ruff with `select = [\"ALL\"]` and explicit ignores\n- [ ] Use ty for type checking\n- [ ] Enforce test coverage minimum (80%+)\n- [ ] Use dependency groups instead of extras for dev tools\n- [ ] Add `uv.lock` to version control\n- [ ] Use PEP 723 for standalone scripts\n\n## Read Next\n\n- [migration-checklist.md](./references/migration-checklist.md) - Step-by-step migration cleanup\n- [pyproject.md](./references/pyproject.md) - Complete pyproject.toml reference\n- [uv-commands.md](./references/uv-commands.md) - uv command reference\n- [ruff-config.md](./references/ruff-config.md) - Ruff linting/formatting configuration\n- [testing.md](./references/testing.md) - pytest and coverage setup\n- [pep723-scripts.md](./references/pep723-scripts.md) - PEP 723 inline script metadata\n- [prek.md](./references/prek.md) - Fast pre-commit hooks with prek\n- [security-setup.md](./references/security-setup.md) - Security hooks and dependency scanning\n- [dependabot.md](./references/dependabot.md) - Automated dependency updates","attachment_filenames":["agents/openai.yaml","references/dependabot.md","references/migration-checklist.md","references/pep723-scripts.md","references/prek.md","references/pyproject.md","references/ruff-config.md","references/security-setup.md","references/testing.md","references/uv-commands.md","templates/dependabot.yml","templates/pre-commit-config.yaml"],"attachments":[{"filename":"agents/openai.yaml","content":"interface:\n display_name: \"Modern Python\"\n short_description: \"Set up Python projects with modern tooling\"\n icon_small: \"assets/trail-of-bits-mark.svg\"\n icon_large: \"assets/trail-of-bits-mark.svg\"\n brand_color: \"#D83A34\"\n","content_type":"application/yaml; charset=utf-8","language":"yaml","size":226,"content_sha256":"f56c544187af5bd3c76f1cd082619644090ab7b6d8abe77d4d3115d39dced5c1"},{"filename":"references/dependabot.md","content":"# Dependabot: Automated Dependency Updates\n\n[Dependabot](https://docs.github.com/en/code-security/dependabot) automatically creates pull requests to keep your dependencies up to date. GitHub hosts it natively—no external service required.\n\n## Why Use Dependabot?\n\n- **Security**: Automatically patches known vulnerabilities\n- **Freshness**: Keeps dependencies current without manual tracking\n- **Visibility**: PRs show changelogs and compatibility notes\n\n## Configuration\n\nCopy [templates/dependabot.yml](../templates/dependabot.yml) to `.github/dependabot.yml`.\n\nThe template includes:\n- Weekly update schedule for pip and GitHub Actions\n- 7-day cooldown for supply chain protection\n- Grouping to reduce PR noise\n\n## Supply Chain Protection\n\nThe `cooldown.default-days: 7` setting delays updates for newly published versions. This provides time for the community to detect compromised packages before they reach your project.\n\n**Why this matters:**\n- Attackers sometimes publish malicious versions of legitimate packages\n- A 7-day delay allows time for detection and removal\n- Combined with weekly schedules, this balances security with freshness\n\n## Common Options\n\n| Option | Description |\n|--------|-------------|\n| `interval` | `daily`, `weekly`, or `monthly` |\n| `cooldown.default-days` | Days to wait before updating new releases |\n| `ignore` | Skip specific dependencies or versions |\n| `groups` | Group related updates into single PRs |\n| `reviewers` | Auto-assign reviewers to PRs |\n\n## See Also\n\n- [GitHub Dependabot docs](https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file)\n- [security-setup.md](./security-setup.md) - Security tooling overview\n- [prek.md](./prek.md) - Pre-commit hooks (complementary tool)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":1800,"content_sha256":"d3678e32472305c0ef136bca99b26c3f75554d63675930e396f26a91a97451ad"},{"filename":"references/migration-checklist.md","content":"# Migration Checklist\n\nComprehensive checklist for migrating Python projects to modern tooling.\n\n## Before Migration\n\n- [ ] **Determine layout**: `src/` or flat? Configure `[tool.uv.build-backend]` if flat\n- [ ] **Decide uv.lock strategy**: app (commit) vs library (.gitignore)\n- [ ] **Backup current state**: Create a branch or tag before starting\n\n## Cleanup Old Artifacts\n\nFind and remove legacy linter comments:\n\n```bash\n# Find files with old linter pragmas\nrg \"# pylint:|# noqa:|# type: ignore\" --files-with-matches\n\n# Find missing __init__.py files\nuv run ruff check --select=INP001 .\n```\n\nRemove these files after migration:\n- [ ] `requirements.txt`, `requirements-dev.txt`\n- [ ] `setup.py`, `setup.cfg`, `MANIFEST.in`\n- [ ] `.flake8`, `mypy.ini`, `pyrightconfig.json`\n- [ ] `tox.ini` (if not needed)\n- [ ] `Pipfile`, `Pipfile.lock`\n- [ ] Old virtual environments (`venv/`, `.venv/`)\n\n## .gitignore Updates\n\nAdd these entries:\n\n```gitignore\n# Python\n__pycache__/\n*.py[cod]\n.venv/\n\n# Tools\n.ruff_cache/\n.ty/\n\n# uv (for libraries only - apps should commit uv.lock)\n# uv.lock\n```\n\n## pyproject.toml Sections to Remove\n\n- [ ] `[tool.black]`\n- [ ] `[tool.isort]`\n- [ ] `[tool.mypy]`\n- [ ] `[tool.pyright]`\n- [ ] `[tool.pylint]`\n- [ ] `[tool.flake8]` (if present)\n\n## Post-Migration Easy Wins\n\nRun these to modernize code automatically:\n\n```bash\n# Pyupgrade modernization (typing, syntax)\nuv run ruff check --select=UP --fix .\n\n# Unnecessary variable assignments before return\nuv run ruff check --select=RET504 --fix .\n\n# Simplifications (conditionals, comprehensions)\nuv run ruff check --select=SIM --fix .\n\n# Remove commented-out code\nuv run ruff check --select=ERA --fix .\n```\n\n## CI Cleanup\n\n- [ ] Remove scheduled CI triggers (activity without progress is theater)\n- [ ] Update CI to use `uv sync` and `uv run`\n- [ ] Pin GitHub Actions to SHA hashes\n- [ ] Set up security tooling (see [security-setup.md](./security-setup.md))\n\n## Gradual ty Adoption\n\nFor legacy codebases with many type errors, start lenient:\n\n```toml\n[tool.ty.terminal]\nerror-on-warning = true\n\n[tool.ty.environment]\npython-version = \"3.11\"\n\n[tool.ty.rules]\n# Start with these ignored for legacy codebases\npossibly-missing-attribute = \"ignore\"\nunresolved-import = \"ignore\"\ninvalid-argument-type = \"ignore\"\nnot-subscriptable = \"ignore\"\nunresolved-attribute = \"ignore\"\n```\n\nRemove rules as you fix errors. Track progress:\n\n```bash\n# Count remaining issues\nuv run ty check src/ 2>&1 | grep -c \"error\"\n```\n\n## Supply Chain Security\n\n- [ ] Add pip-audit to dependency groups\n- [ ] Configure Dependabot with 7-day cooldown\n- [ ] Pin exact versions in production (`==` not `>=`)\n\nSee [security-setup.md](./security-setup.md) for pip-audit and Dependabot configuration.\n\n## Verification\n\nAfter migration, verify everything works:\n\n```bash\n# Install all dependencies\nuv sync --all-groups\n\n# Run linting\nuv run ruff check .\nuv run ruff format --check .\n\n# Run type checking\nuv run ty check src/\n\n# Run tests\nuv run pytest\n\n# Security audit\nuv run pip-audit\n\n# Build package (if distributable)\nuv build\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":3071,"content_sha256":"58c947e6200a91f350c9adc898af7fc6263fda41d36ae81ffd4dd923b3a1015e"},{"filename":"references/pep723-scripts.md","content":"# PEP 723: Inline Script Metadata\n\nPEP 723 allows embedding dependency metadata directly in Python scripts, eliminating the need for separate `requirements.txt` or `pyproject.toml` files for simple scripts.\n\n## When to Use PEP 723\n\n**Use for:**\n- Single-file scripts with external dependencies\n- Quick automation scripts\n- Utility scripts shared between projects\n- Scripts that need to be self-contained\n\n**Don't use for:**\n- Multi-file projects (use `pyproject.toml`)\n- Reusable packages/libraries\n- Projects requiring complex configuration\n\n## Basic Syntax\n\nThe metadata block uses TOML format embedded in a special comment:\n\n```python\n#!/usr/bin/env -S uv run --script\n# /// script\n# requires-python = \">=3.11\"\n# dependencies = [\n# \"requests\",\n# \"rich\",\n# ]\n# ///\n\nimport requests\nfrom rich import print\n\nresponse = requests.get(\"https://api.example.com/data\")\nprint(response.json())\n```\n\n## Running Scripts\n\n```bash\n# With uv (recommended)\nuv run script.py\n\n# Script handles its own dependencies automatically\n./script.py # If shebang is set\n```\n\n## Metadata Fields\n\n### Required Python Version\n\n```python\n# /// script\n# requires-python = \">=3.11\"\n# ///\n```\n\n### Dependencies\n\n```python\n# /// script\n# dependencies = [\n# \"requests\",\n# \"click\",\n# \"rich\",\n# ]\n# ///\n```\n\n### Private Package Index\n\n```python\n# /// script\n# dependencies = [\"httpx\"]\n#\n# [tool.uv]\n# extra-index-url = [\"https://pypi.company.com/simple/\"]\n# ///\n```\n\n## Complete Example\n\n```python\n#!/usr/bin/env -S uv run --script\n# /// script\n# requires-python = \">=3.11\"\n# dependencies = [\n# \"httpx\",\n# \"rich\",\n# \"typer\",\n# ]\n# ///\n\n\"\"\"Fetch and display API data with nice formatting.\"\"\"\n\nimport httpx\nimport typer\nfrom rich.console import Console\nfrom rich.table import Table\n\nconsole = Console()\napp = typer.Typer()\n\n\[email protected]()\ndef fetch(url: str, format: str = \"table\"):\n \"\"\"Fetch data from URL and display it.\"\"\"\n with httpx.Client() as client:\n response = client.get(url)\n response.raise_for_status()\n data = response.json()\n\n if format == \"table\" and isinstance(data, list):\n table = Table()\n if data:\n for key in data[0].keys():\n table.add_column(key)\n for item in data:\n table.add_row(*[str(v) for v in item.values()])\n console.print(table)\n else:\n console.print_json(data=data)\n\n\nif __name__ == \"__main__\":\n app()\n```\n\n## Creating Scripts with uv\n\n```bash\n# Create new script with metadata\nuv init --script myscript.py\n\n# Add dependency to existing script\nuv add --script myscript.py requests\n\n# Remove dependency from script\nuv remove --script myscript.py requests\n```\n\n## Shebang Options\n\n### Basic (requires uv in PATH)\n\n```python\n#!/usr/bin/env -S uv run --script\n```\n\n### With specific Python version\n\n```python\n#!/usr/bin/env -S uv run --python 3.12 --script\n```\n\n### Quiet mode (suppress uv output)\n\n```python\n#!/usr/bin/env -S uv run --quiet --script\n```\n\n## Examples by Use Case\n\n### Data Processing Script\n\n```python\n#!/usr/bin/env -S uv run --script\n# /// script\n# requires-python = \">=3.11\"\n# dependencies = [\"pandas\", \"openpyxl\"]\n# ///\n\nimport pandas as pd\nimport sys\n\ndf = pd.read_excel(sys.argv[1])\nprint(df.describe())\n```\n\n### Web Scraping Script\n\n```python\n#!/usr/bin/env -S uv run --script\n# /// script\n# requires-python = \">=3.11\"\n# dependencies = [\"httpx\", \"beautifulsoup4\", \"lxml\"]\n# ///\n\nimport httpx\nfrom bs4 import BeautifulSoup\n\nresponse = httpx.get(\"https://example.com\")\nsoup = BeautifulSoup(response.text, \"lxml\")\nprint(soup.title.string)\n```\n\n### CLI Tool Script\n\n```python\n#!/usr/bin/env -S uv run --script\n# /// script\n# requires-python = \">=3.11\"\n# dependencies = [\"typer\", \"rich\"]\n# ///\n\nimport typer\nfrom rich import print\n\napp = typer.Typer()\n\[email protected]()\ndef greet(name: str):\n print(f\"[green]Hello, {name}![/green]\")\n\nif __name__ == \"__main__\":\n app()\n```\n\n### Async Script\n\n```python\n#!/usr/bin/env -S uv run --script\n# /// script\n# requires-python = \">=3.11\"\n# dependencies = [\"httpx\"]\n# ///\n\nimport asyncio\nimport httpx\n\nasync def main():\n async with httpx.AsyncClient() as client:\n urls = [\"https://api1.example.com\", \"https://api2.example.com\"]\n tasks = [client.get(url) for url in urls]\n responses = await asyncio.gather(*tasks)\n for r in responses:\n print(r.status_code)\n\nasyncio.run(main())\n```\n\n## Best Practices\n\n1. **Always specify `requires-python`** - Ensures compatibility\n2. **Pin major versions for Python** - Use `>=3.11` not `==3.11`\n3. **Omit version constraints for dependencies** - Use `uv add --script` to add dependencies; let uv select versions\n4. **Keep scripts focused** - One script, one purpose\n5. **Add docstring** - Document what the script does\n6. **Use type hints** - Improves readability and catches errors\n\n## Limitations\n\n- No support for dependency groups\n- No support for editable installs\n- No support for local dependencies (use relative imports)\n- No lockfile (versions may vary between runs)\n\nFor projects needing these features, use a full `pyproject.toml` setup instead.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":5134,"content_sha256":"c348b136613a4fed8f623d6013c0c6413d2c24f2973b2e5f85b80ecc68646045"},{"filename":"references/prek.md","content":"# prek: Fast Pre-commit Hooks\n\n[prek](https://github.com/j178/prek) is a fast, Rust-native drop-in replacement for pre-commit. It uses the same `.pre-commit-config.yaml` format and is fully compatible with existing configurations.\n\n## Why prek over pre-commit?\n\n| Feature | prek | pre-commit |\n|---------|------|------------|\n| Speed | ~7x faster hook installation | Slower |\n| Dependencies | Single binary, no runtime needed | Requires Python |\n| Disk usage | Shared toolchains between hooks | Isolated environments |\n| Parallelism | Parallel repo cloning and hook execution | Sequential |\n| Python management | Uses uv automatically | Manual Python setup |\n| Monorepo support | Built-in workspace mode | Not supported |\n\n**Already using prek:** CPython, Apache Airflow, FastAPI, Ruff, Home Assistant, and [many more](https://github.com/j178/prek#who-is-using-prek).\n\n## Installation\n\nSee [security-setup.md](./security-setup.md#tool-installation) for installation options.\n\n## Quick Start\n\n### For Existing pre-commit Users\n\nprek is fully compatible with `.pre-commit-config.yaml`. Just replace commands:\n\n```bash\n# Instead of: pre-commit install\nprek install\n\n# Instead of: pre-commit run --all-files\nprek run --all-files\n\n# Instead of: pre-commit autoupdate\nprek auto-update\n```\n\n### New Setup\n\n1. Create `.pre-commit-config.yaml`:\n\n```yaml\nrepos:\n - repo: https://github.com/astral-sh/ruff-pre-commit\n rev: \u003clatest> # https://github.com/astral-sh/ruff-pre-commit/releases\n hooks:\n - id: ruff\n args: [--fix]\n - id: ruff-format\n```\n\n2. Install and run:\n\n```bash\n# Install git hooks\nprek install\n\n# Run manually on all files\nprek run --all-files\n\n# Run specific hook\nprek run ruff\n```\n\n## Configuration\n\nFor a complete, copy-paste-ready configuration, see [templates/pre-commit-config.yaml](../templates/pre-commit-config.yaml).\n\n### Recommended `.pre-commit-config.yaml`\n\n> **Note:** Versions shown as `\u003clatest>` are placeholders. Always check the linked releases for current stable versions before use.\n\n```yaml\n# See https://pre-commit.com for more information\ndefault_language_version:\n python: python3.12\n\nrepos:\n # Ruff - linting and formatting\n - repo: https://github.com/astral-sh/ruff-pre-commit\n rev: \u003clatest> # https://github.com/astral-sh/ruff-pre-commit/releases\n hooks:\n - id: ruff\n args: [--fix]\n - id: ruff-format\n\n # General file checks (prek builtin - faster, no external deps)\n - repo: builtin\n hooks:\n - id: trailing-whitespace\n - id: end-of-file-fixer\n - id: check-yaml\n - id: check-merge-conflict\n\n # Security hooks - see security-setup.md for detailed guidance\n # Shell script linting\n - repo: https://github.com/koalaman/shellcheck-precommit\n rev: \u003clatest> # https://github.com/koalaman/shellcheck-precommit/tags\n hooks:\n - id: shellcheck\n args: [--severity=error]\n\n # Secret detection\n - repo: https://github.com/Yelp/detect-secrets\n rev: \u003clatest> # https://github.com/Yelp/detect-secrets/releases\n hooks:\n - id: detect-secrets\n args: [--baseline, .secrets.baseline]\n\n # GitHub Actions linting\n - repo: https://github.com/rhysd/actionlint\n rev: \u003clatest> # https://github.com/rhysd/actionlint/releases\n hooks:\n - id: actionlint\n\n # GitHub Actions security audit\n - repo: https://github.com/zizmorcore/zizmor-pre-commit\n rev: \u003clatest> # https://github.com/zizmorcore/zizmor-pre-commit/releases\n hooks:\n - id: zizmor\n args: [--persona=regular, --min-severity=medium, --min-confidence=medium]\n```\n\nSee [security-setup.md](./security-setup.md) for detailed guidance on each security hook.\n\n### Using Built-in Hooks\n\nprek includes Rust-native implementations of common hooks for extra speed:\n\n```yaml\nrepos:\n - repo: builtin\n hooks:\n - id: trailing-whitespace\n - id: end-of-file-fixer\n - id: check-yaml\n - id: check-json\n - id: check-toml\n```\n\n## Commands\n\n| Command | Description |\n|---------|-------------|\n| `prek install` | Install git hooks |\n| `prek uninstall` | Remove git hooks |\n| `prek run` | Run hooks on staged files |\n| `prek run --all-files` | Run on all files |\n| `prek run --last-commit` | Run on last commit's files |\n| `prek run HOOK [HOOK...]` | Run specific hook(s) |\n| `prek run -d src/` | Run on files in directory |\n| `prek auto-update` | Update hook versions |\n| `prek list` | List configured hooks |\n| `prek clean` | Remove cached environments |\n\n## CI Configuration\n\n### GitHub Actions\n\n```yaml\nname: Pre-commit\non: [push, pull_request]\n\njobs:\n prek:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@\u003csha> # \u003clatest> https://github.com/actions/checkout/releases\n - uses: j178/prek-action@\u003csha> # \u003clatest> https://github.com/j178/prek-action/releases\n```\n\nOr manually:\n\n```yaml\n- name: Install prek\n run: uv tool install prek\n\n- name: Run hooks\n run: prek run --all-files\n```\n\n## Makefile Integration\n\n```makefile\n.PHONY: hooks hooks-install\n\nhooks:\n\tprek run --all-files\n\nhooks-install:\n\tprek install\n```\n\n## Migration from pre-commit\n\n1. Install prek: `uv tool install prek`\n2. Remove pre-commit: `pip uninstall pre-commit` or `uv tool uninstall pre-commit`\n3. Re-install hooks: `prek install`\n4. (Optional) Clean old environments: `rm -rf ~/.cache/pre-commit`\n\nYour existing `.pre-commit-config.yaml` works unchanged.\n\n## Best Practices\n\n1. **Use `prek run --all-files` in CI** - Ensures all files are checked, not just changed ones\n2. **Pin hook versions** - Use specific `rev` values, not branches\n3. **Use `--cooldown-days` for auto-update** - Mitigates supply chain attacks: `prek auto-update --cooldown-days 7`\n4. **Prefer built-in hooks** - Use `repo: builtin` for common checks (faster, offline)\n5. **Run hooks before commit** - `prek install` sets this up automatically\n6. **Initialize detect-secrets baseline** - Run `detect-secrets scan > .secrets.baseline` before first commit\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":5951,"content_sha256":"4be1c181c71aab64ba58573242a1c451d576a5c61ceeb400bb5827f4e1f9532a"},{"filename":"references/pyproject.md","content":"# pyproject.toml Configuration Reference\n\nComplete reference for configuring `pyproject.toml` for modern Python projects.\n\n**Important**: Always use `uv add` and `uv remove` to manage dependencies. Do not edit the `dependencies` or `dependency-groups` sections directly.\n\n## Complete Example\n\n```toml\n[project]\nname = \"myproject\"\nversion = \"0.1.0\"\ndescription = \"A modern Python project\"\nreadme = \"README.md\"\nlicense = \"MIT\"\nrequires-python = \">=3.11\"\nauthors = [\n { name = \"Your Name\", email = \"[email protected]\" }\n]\nclassifiers = [\n \"Development Status :: 4 - Beta\",\n \"Programming Language :: Python :: 3\",\n \"Programming Language :: Python :: 3.11\",\n \"Programming Language :: Python :: 3.12\",\n \"Programming Language :: Python :: 3.13\",\n]\ndependencies = [\n \"requests\",\n \"rich\",\n]\n\n[project.optional-dependencies]\n# Use for optional features users can install\ncli = [\"typer\"]\n\n[project.scripts]\nmyproject = \"myproject.cli:main\"\n\n[project.urls]\nHomepage = \"https://github.com/org/myproject\"\nDocumentation = \"https://myproject.readthedocs.io\"\nRepository = \"https://github.com/org/myproject\"\n\n[build-system]\nrequires = [\"uv_build>=0.9,\u003c1\"] # Use latest 0.x; check https://pypi.org/project/uv-build/\nbuild-backend = \"uv_build\"\n\n[dependency-groups]\ndev = [\"ruff\", \"ty\"]\ntest = [\"pytest\", \"pytest-cov\", \"hypothesis\"]\ndocs = [\"sphinx\", \"myst-parser\"]\n\n[tool.uv]\ndefault-groups = [\"dev\", \"test\"]\n\n[tool.ruff]\nline-length = 100\ntarget-version = \"py311\"\nsrc = [\"src\"]\n\n[tool.ruff.lint]\nselect = [\"ALL\"]\nignore = [\n \"D\", # pydocstyle (enable selectively)\n \"COM812\", # trailing comma (conflicts with formatter)\n \"ISC001\", # implicit string concat (conflicts with formatter)\n]\n\n[tool.ruff.lint.per-file-ignores]\n\"tests/**/*.py\" = [\n \"S101\", # assert allowed in tests\n \"PLR2004\", # magic values allowed in tests\n \"ANN\", # annotations optional in tests\n]\n\n[tool.ruff.format]\nquote-style = \"double\"\nindent-style = \"space\"\ndocstring-code-format = true\n\n[tool.pytest]\ntestpaths = [\"tests\"]\npythonpath = [\"src\"]\naddopts = [\n \"--cov=myproject\",\n \"--cov-report=term-missing\",\n \"--cov-fail-under=80\",\n]\n\n[tool.coverage.run]\nbranch = true\nsource = [\"src/myproject\"]\n\n[tool.coverage.report]\nexclude_lines = [\n \"pragma: no cover\",\n \"if TYPE_CHECKING:\",\n \"if __name__ == .__main__.:\",\n]\n```\n\n## Section Reference\n\n### [project]\n\nCore project metadata following PEP 621.\n\n| Field | Required | Description |\n|-------|----------|-------------|\n| `name` | Yes | Package name (lowercase, hyphens) |\n| `version` | Yes | Semantic version |\n| `description` | No | One-line description |\n| `readme` | No | Path to README file |\n| `license` | No | SPDX license identifier |\n| `requires-python` | Recommended | Python version constraint |\n| `authors` | No | List of author dicts |\n| `dependencies` | No | Runtime dependencies |\n\n### [project.optional-dependencies]\n\n**Rarely needed.** Only use for optional *runtime* features that end users install:\n\n```toml\n[project.optional-dependencies]\n# User installs with: uv add myproject[postgres]\npostgres = [\"psycopg2\"]\n```\n\n**Do NOT use for dev tools**—use `[dependency-groups]` instead.\n\n### [project.scripts]\n\nConsole entry points:\n\n```toml\n[project.scripts]\nmyproject = \"myproject.cli:main\"\nmyproject-serve = \"myproject.server:run\"\n```\n\n### [build-system]\n\nBuild backend configuration. Use `uv_build` for most projects:\n\n```toml\n[build-system]\nrequires = [\"uv_build>=0.9,\u003c1\"] # Use latest 0.x; check https://pypi.org/project/uv-build/\nbuild-backend = \"uv_build\"\n```\n\n`uv_build` is simpler and sufficient for most use cases. Use static versioning in `[project] version` rather than VCS-aware dynamic versioning.\n\nFor flat layout (no `src/` directory), configure the module root:\n\n```toml\n[tool.uv.build-backend]\nmodule-root = \"\"\n```\n\n> **Note:** These tools evolve rapidly. Prefer `>=X.Y,\u003cX+1` constraints to automatically get newer releases within the same major version.\n\n### [dependency-groups]\n\nDevelopment dependencies (PEP 735). Unlike optional-dependencies, these are NOT installed by users:\n\n```toml\n[dependency-groups]\ndev = [{include-group = \"lint\"}, {include-group = \"test\"}, {include-group = \"audit\"}]\nlint = [\"ruff\", \"ty\"]\ntest = [\"pytest\", \"pytest-cov\"]\naudit = [\"pip-audit\"]\ndocs = [\"sphinx\", \"myst-parser\"]\n```\n\nInstall with: `uv sync --group dev --group test`\n\n### [tool.uv]\n\nuv-specific configuration:\n\n```toml\n[tool.uv]\n# Default groups to install with `uv sync`\ndefault-groups = [\"dev\", \"test\"]\n\n# Python version management\npython-preference = \"managed\"\n```\n\n## Version Specifiers\n\n| Specifier | Meaning |\n|-----------|---------|\n| `>=1.0` | At least version 1.0 |\n| `>=1.0,\u003c2.0` | Version 1.x only |\n| `~=1.4` | Compatible release (>=1.4, \u003c2.0) |\n| `==1.4.*` | Any 1.4.x version |\n\n## uv.lock Handling\n\n| Project Type | uv.lock in Git? | Why |\n|--------------|-----------------|-----|\n| Application | ✅ Commit | Reproducible deploys |\n| Library | ❌ .gitignore | Users resolve their own deps |\n\n## Common Patterns\n\n### Library Package\n\n```toml\n[project]\ndependencies = [] # Minimal runtime deps\n\n[project.optional-dependencies]\n# Optional runtime features (user installs with mylib[async])\nasync = [\"httpx\"]\n\n[dependency-groups]\ndev = [\"ruff\", \"ty\"]\ntest = [\"pytest\", \"pytest-cov\"]\n```\n\n### Application Package\n\n```toml\n[project]\ndependencies = [\n \"fastapi\",\n \"uvicorn\",\n \"sqlalchemy\",\n]\n\n[project.scripts]\nmyapp = \"myapp.main:run\"\n\n[dependency-groups]\ndev = [\"ruff\", \"ty\", \"pytest\"]\n```\n\n### CLI Tool\n\n```toml\n[project]\ndependencies = [\n \"typer\",\n \"rich\",\n]\n\n[project.scripts]\nmytool = \"mytool.cli:app\"\n\n[dependency-groups]\ndev = [\"ruff\", \"ty\", \"pytest\"]\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":5694,"content_sha256":"aec906835ec687024700d31e5c146baaabc9524129384304857b3aa81809401b"},{"filename":"references/ruff-config.md","content":"# Ruff Configuration Reference\n\nRuff is an extremely fast Python linter and formatter written in Rust. It replaces flake8, black, isort, pyupgrade, pydocstyle, and many other tools.\n\n## Basic Setup\n\nAdd to `pyproject.toml`:\n\n```toml\n[tool.ruff]\nline-length = 100\ntarget-version = \"py311\"\nsrc = [\"src\"]\n\n[tool.ruff.lint]\nselect = [\"ALL\"]\nignore = [\n \"D\", # pydocstyle\n \"COM812\", # trailing comma (formatter conflict)\n \"ISC001\", # string concat (formatter conflict)\n]\n\n[tool.ruff.format]\nquote-style = \"double\"\nindent-style = \"space\"\ndocstring-code-format = true\n```\n\n## Running Ruff\n\n```bash\n# Lint\nuv run ruff check .\nuv run ruff check --fix . # Auto-fix\nuv run ruff check --fix --unsafe-fixes . # Including unsafe fixes\n\n# Format\nuv run ruff format .\nuv run ruff format --check . # Check only\nuv run ruff format --diff . # Show diff\n```\n\n## Rule Categories\n\nUsing `select = [\"ALL\"]` enables all rules. Common categories:\n\n| Code | Category | Description |\n|------|----------|-------------|\n| `E`, `W` | pycodestyle | Style errors and warnings |\n| `F` | Pyflakes | Logical errors |\n| `I` | isort | Import sorting |\n| `N` | pep8-naming | Naming conventions |\n| `D` | pydocstyle | Docstring conventions |\n| `UP` | pyupgrade | Python upgrade suggestions |\n| `B` | flake8-bugbear | Bug detection |\n| `S` | flake8-bandit | Security issues |\n| `A` | flake8-builtins | Built-in shadowing |\n| `C4` | flake8-comprehensions | Comprehension improvements |\n| `DTZ` | flake8-datetimez | Timezone-aware datetime |\n| `T10` | flake8-debugger | Debugger statements |\n| `T20` | flake8-print | Print statements |\n| `PT` | flake8-pytest-style | Pytest style |\n| `Q` | flake8-quotes | Quote consistency |\n| `SIM` | flake8-simplify | Simplification suggestions |\n| `TID` | flake8-tidy-imports | Import hygiene |\n| `ARG` | flake8-unused-arguments | Unused arguments |\n| `ERA` | eradicate | Commented-out code |\n| `PL` | Pylint | Pylint rules |\n| `RUF` | Ruff-specific | Ruff's own rules |\n| `ANN` | flake8-annotations | Type annotation checks |\n\n## Recommended Ignores\n\n### Always Ignore (Formatter Conflicts)\n\n```toml\nignore = [\n \"COM812\", # missing-trailing-comma\n \"ISC001\", # single-line-implicit-string-concatenation\n]\n```\n\n### Common Ignores\n\n```toml\nignore = [\n \"D\", # Docstrings (enable selectively)\n \"ANN401\", # Dynamically typed Any\n \"TD002\", # Missing TODO author\n \"TD003\", # Missing TODO link\n \"FIX002\", # Line contains TODO\n]\n```\n\n## Per-File Ignores\n\n```toml\n[tool.ruff.lint.per-file-ignores]\n# Tests\n\"tests/**/*.py\" = [\n \"S101\", # assert usage\n \"PLR2004\", # magic values\n \"ANN\", # type annotations\n \"D\", # docstrings\n]\n\n# Scripts\n\"scripts/**/*.py\" = [\n \"T20\", # print statements\n \"INP001\", # implicit namespace package\n]\n\n# __init__.py\n\"__init__.py\" = [\n \"F401\", # unused imports (re-exports)\n]\n\n# Migrations\n\"**/migrations/*.py\" = [\n \"ALL\", # ignore all\n]\n```\n\n## Import Sorting (isort)\n\n```toml\n[tool.ruff.lint.isort]\nforce-single-line = false\nknown-first-party = [\"myproject\"]\nrequired-imports = [\"from __future__ import annotations\"]\nsection-order = [\n \"future\",\n \"standard-library\",\n \"third-party\",\n \"first-party\",\n \"local-folder\",\n]\n```\n\n## Docstring Style (pydocstyle)\n\nIf enabling docstring checks:\n\n```toml\n[tool.ruff.lint]\nselect = [\"D\"]\nignore = [\n \"D100\", # Missing module docstring\n \"D104\", # Missing public package docstring\n \"D203\", # 1 blank line before class docstring (conflicts D211)\n \"D213\", # Multi-line summary second line (conflicts D212)\n]\n\n[tool.ruff.lint.pydocstyle]\nconvention = \"google\" # or \"numpy\", \"pep257\"\n```\n\n## Formatter Configuration\n\n```toml\n[tool.ruff.format]\nquote-style = \"double\" # or \"single\"\nindent-style = \"space\" # or \"tab\"\nskip-magic-trailing-comma = false\nline-ending = \"auto\" # or \"lf\", \"crlf\"\ndocstring-code-format = true\ndocstring-code-line-length = 80\n```\n\n## Type Checking\n\nRuff does NOT do type checking. Use **ty** (from Astral, the same team behind ruff and uv):\n\n```bash\n# Add ty to dev dependencies\nuv add --group dev ty\n\n# Run type checking\nuv run ty check src/\n```\n\nty is significantly faster than mypy or pyright and integrates well with the modern Python toolchain.\n\n## CI Configuration\n\n```yaml\n# GitHub Actions\n- name: Lint\n run: uv run ruff check --output-format=github .\n\n- name: Format check\n run: uv run ruff format --check .\n```\n\n## Migration from Other Tools\n\n### From flake8\n\nRuff covers most flake8 plugins. Remove:\n- flake8\n- flake8-* plugins\n- .flake8 config file\n\n### From black\n\nRemove black and use `ruff format`. Remove:\n- black\n- [tool.black] config\n\n### From isort\n\nRuff includes isort. Remove:\n- isort\n- [tool.isort] config\n\nUse `[tool.ruff.lint.isort]` for isort settings.\n\n## Code Modernization\n\nRun pyupgrade rules to modernize syntax to your target Python version:\n\n```bash\nuv run ruff check --select=UP --fix . # Auto-fix upgrades\nuv run ruff check --select=UP . # Preview only\n```\n\nCommon modernizations include:\n- `typing.Optional[X]` → `X | None`\n- `typing.List[X]` → `list[X]`\n- `super(ClassName, self)` → `super()`\n- Format strings and other syntax upgrades\n\n## Line Length Migration\n\nIf migrating from 120 to 100 char lines, expect manual fixes.\nFor less churn during initial migration, keep existing:\n\n```toml\nline-length = 120 # Match existing; tighten later\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":5476,"content_sha256":"8d247862f1beaf76816ed6775f5a0c8dc96d74c7f2b71bbf1aaedc4937373b17"},{"filename":"references/security-setup.md","content":"# Security Setup\n\nSecurity tooling for Python projects: pre-commit hooks, CI auditing, and dependency scanning.\n\n## Tool Installation\n\nInstall these tools before running the quick setup commands below.\n\n### prek (pre-commit runner)\n\n```bash\n# Homebrew (recommended)\nbrew install prek\n\n# Cargo\ncargo install prek\n\n# Standalone installer\ncurl --proto '=https' --tlsv1.2 -LsSf https://github.com/j178/prek/releases/latest/download/prek-installer.sh | sh\n```\n\n### Security tools\n\nPre-commit hooks auto-install tools when run via prek. For manual CLI usage:\n\n```bash\n# Homebrew (macOS/Linux)\nbrew install actionlint shellcheck\n\n# Python tools via uv\nuv tool install detect-secrets\nuv tool install zizmor\n```\n\nAlternative installation methods:\n\n- **actionlint**: `go install github.com/rhysd/actionlint/cmd/actionlint@latest`\n- **zizmor**: `cargo install zizmor`\n- **detect-secrets**: `pipx install detect-secrets`\n\n## Quick Setup\n\n```bash\n# 1. Install security hooks\nprek install\n\n# 2. Initialize secrets baseline\ndetect-secrets scan > .secrets.baseline\n\n# 3. Audit existing workflows\nactionlint .github/workflows/\nzizmor .github/workflows/\n```\n\nSee [templates/pre-commit-config.yaml](../templates/pre-commit-config.yaml) for a complete hook configuration.\n\n## Tool Matrix\n\n| Tool | Runs | Catches |\n|------|------|---------|\n| **shellcheck** | pre-commit | Shell script bugs, quoting issues |\n| **detect-secrets** | pre-commit | Leaked API keys, passwords, tokens |\n| **actionlint** | pre-commit, CI | Workflow syntax errors, invalid refs |\n| **zizmor** | pre-commit, CI | Workflow security issues, excessive permissions |\n| **pip-audit** | CI, manual | Known CVEs in dependencies |\n| **Dependabot** | scheduled | Outdated dependencies with vulnerabilities |\n\n## Pre-commit Hooks\n\nThese run locally before each commit via prek.\n\n### shellcheck - Shell Script Linting\n\nCatches common shell scripting errors: unquoted variables, undefined variables, deprecated syntax.\n\n```yaml\n# In .pre-commit-config.yaml\n- repo: https://github.com/koalaman/shellcheck-precommit\n rev: \u003clatest> # https://github.com/koalaman/shellcheck-precommit/tags\n hooks:\n - id: shellcheck\n args: [--severity=error] # Start strict, adjust if needed\n```\n\nCommon findings:\n- `SC2086`: Unquoted variable expansion (word splitting risk)\n- `SC2046`: Unquoted command substitution\n- `SC2155`: Declare and assign separately to avoid masking return values\n\n### detect-secrets - Secret Detection\n\nPrevents accidentally committing API keys, passwords, and tokens.\n\n```yaml\n- repo: https://github.com/Yelp/detect-secrets\n rev: \u003clatest> # https://github.com/Yelp/detect-secrets/releases\n hooks:\n - id: detect-secrets\n args: [--baseline, .secrets.baseline]\n```\n\n**First-time setup:**\n\n```bash\n# Generate baseline of existing \"secrets\" (false positives to ignore)\ndetect-secrets scan > .secrets.baseline\n\n# Review the baseline - ensure no real secrets\ncat .secrets.baseline\n\n# Commit the baseline\ngit add .secrets.baseline\n```\n\n**When hook fails:**\n\n```bash\n# View the finding (non-interactive)\ndetect-secrets audit --report .secrets.baseline\n```\n\nIf false positive: update baseline with `detect-secrets scan --update .secrets.baseline`\nIf real secret: remove from code and rotate the credential.\n\n## CI Security\n\nThese run in GitHub Actions on every push/PR.\n\n### actionlint - Workflow Syntax Validation\n\nCatches syntax errors, invalid action references, and type mismatches before they fail in CI.\n\n```yaml\n- repo: https://github.com/rhysd/actionlint\n rev: \u003clatest> # https://github.com/rhysd/actionlint/releases\n hooks:\n - id: actionlint\n```\n\nRun manually:\n\n```bash\nactionlint .github/workflows/\n```\n\nCommon findings:\n- Invalid event triggers\n- Undefined workflow inputs\n- Shell syntax errors in `run:` blocks\n- Invalid action version references\n\n### zizmor - Workflow Security Audit\n\nFinds security issues in GitHub Actions workflows: excessive permissions, injection risks, untrusted inputs.\n\n```yaml\n- repo: https://github.com/zizmorcore/zizmor-pre-commit\n rev: \u003clatest> # https://github.com/zizmorcore/zizmor-pre-commit/releases\n hooks:\n - id: zizmor\n args: [--persona=regular, --min-severity=medium, --min-confidence=medium]\n```\n\nRun manually:\n\n```bash\nzizmor .github/workflows/\n```\n\n**Fixing `excessive-permissions`:**\n\nBy default, workflows get `write` access to everything. Lock down with explicit permissions:\n\n```yaml\n# Read-only workflows (lint, test, audit)\npermissions:\n contents: read\n\n# Workflows that push or create releases\npermissions:\n contents: write\n\n# Workflows that comment on PRs\npermissions:\n contents: read\n pull-requests: write\n```\n\nCommon findings:\n- `excessive-permissions`: No `permissions:` block\n- `template-injection`: Using `${{ github.event.* }}` unsafely\n- `unpinned-action`: Actions not pinned to SHA\n- `dangerous-triggers`: `pull_request_target` with checkout\n\n## Dependency Security\n\n### pip-audit - Vulnerability Scanning\n\nChecks installed packages against the Python Advisory Database (PyPA) for known CVEs.\n\n**Setup:**\n\n```toml\n# pyproject.toml\n[dependency-groups]\naudit = [\"pip-audit\"]\n```\n\n**Usage:**\n\n```bash\n# Audit current environment\nuv run pip-audit\n\n# Audit without installing (faster for CI)\nuv run pip-audit .\n\n# Fix automatically (upgrades vulnerable packages)\nuv run pip-audit --fix\n```\n\n**In CI:**\n\n```yaml\n- name: Security audit\n run: uv run pip-audit .\n```\n\n**When vulnerabilities found:**\n\n1. Check if the CVE affects your usage (many are in unused code paths)\n2. Update the package: `uv add \u003cpackage>@latest`\n3. If no fix available: evaluate risk, consider alternatives, or add to ignore list\n\n### Dependabot - Automated Updates\n\nAutomatically creates PRs for outdated dependencies.\n\nCopy [templates/dependabot.yml](../templates/dependabot.yml) to `.github/dependabot.yml`.\n\n**How pip-audit and Dependabot work together:**\n\n| Tool | Trigger | Scope |\n|------|---------|-------|\n| pip-audit | Every CI run | Known CVEs in current deps |\n| Dependabot | Weekly schedule | All outdated deps, security + non-security |\n\n- **pip-audit** catches: \"You have a vulnerable version right now\"\n- **Dependabot** prevents: \"You'll fall behind and accumulate vulnerabilities\"\n\nThe 7-day cooldown protects against attackers publishing malicious updates and hoping for quick adoption before detection.\n\nSee [dependabot.md](./dependabot.md) for advanced configuration.\n\nSee [prek.md](./prek.md) for complete pre-commit hook configuration including security hooks.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":6504,"content_sha256":"32d6754a87d5006f923706d10446cc617cb22d36cfc30b55d39bd7f4c61d864c"},{"filename":"references/testing.md","content":"# Testing with pytest\n\nConfiguration and best practices for pytest with coverage enforcement.\n\n## Setup\n\nAdd test dependencies:\n\n```bash\nuv add --group test pytest pytest-cov hypothesis\n```\n\n## pyproject.toml Configuration\n\n```toml\n[tool.pytest]\ntestpaths = [\"tests\"]\npythonpath = [\"src\"]\naddopts = [\n \"-ra\", # Show summary of all test outcomes\n \"--strict-markers\", # Error on unknown markers\n \"--strict-config\", # Error on config issues\n \"--cov=myproject\", # Coverage for package\n \"--cov-report=term-missing\", # Show missing lines\n \"--cov-fail-under=80\", # Minimum coverage\n]\nmarkers = [\n \"slow: marks tests as slow\",\n \"integration: marks integration tests\",\n]\nfilterwarnings = [\n \"error\", # Treat warnings as errors\n \"ignore::DeprecationWarning:third_party.*\",\n]\n\n[tool.coverage.run]\nbranch = true\nsource = [\"src/myproject\"]\nomit = [\n \"*/__main__.py\",\n \"*/conftest.py\",\n]\n\n[tool.coverage.report]\nexclude_lines = [\n \"pragma: no cover\",\n \"if TYPE_CHECKING:\",\n \"if __name__ == .__main__.:\",\n \"raise NotImplementedError\",\n \"@abstractmethod\",\n]\nfail_under = 80\nshow_missing = true\n```\n\n## Project Structure\n\n```\nmyproject/\n├── src/\n│ └── myproject/\n│ ├── __init__.py\n│ └── core.py\n├── tests/\n│ ├── __init__.py\n│ ├── conftest.py # Shared fixtures\n│ ├── test_core.py\n│ └── integration/\n│ └── test_api.py\n└── pyproject.toml\n```\n\n## Running Tests\n\n```bash\n# Run all tests\nuv run pytest\n\n# Run with verbose output\nuv run pytest -v\n\n# Run specific file\nuv run pytest tests/test_core.py\n\n# Run specific test\nuv run pytest tests/test_core.py::test_function_name\n\n# Run tests matching pattern\nuv run pytest -k \"test_parse\"\n\n# Run marked tests\nuv run pytest -m \"not slow\"\n\n# Stop on first failure\nuv run pytest -x\n\n# Run last failed\nuv run pytest --lf\n```\n\n## Coverage Commands\n\n```bash\n# Run with coverage\nuv run pytest --cov=myproject\n\n# Generate HTML report\nuv run pytest --cov=myproject --cov-report=html\nopen htmlcov/index.html\n\n# Coverage without running tests (use existing data)\nuv run coverage report\nuv run coverage html\n```\n\n## Writing Tests\n\n### Basic Test\n\n```python\n# tests/test_core.py\nfrom myproject.core import add_numbers\n\ndef test_add_numbers():\n assert add_numbers(2, 3) == 5\n\ndef test_add_negative():\n assert add_numbers(-1, 1) == 0\n```\n\n### Using Fixtures\n\n```python\n# tests/conftest.py\nimport pytest\nfrom myproject.db import Database\n\[email protected]\ndef db():\n \"\"\"Provide a test database.\"\"\"\n database = Database(\":memory:\")\n database.init()\n yield database\n database.close()\n\[email protected]\ndef sample_data(db):\n \"\"\"Populate database with sample data.\"\"\"\n db.insert({\"name\": \"test\"})\n return db\n```\n\n```python\n# tests/test_db.py\ndef test_query(sample_data):\n result = sample_data.query(\"test\")\n assert result is not None\n```\n\n### Parametrized Tests\n\n```python\nimport pytest\n\[email protected](\"input,expected\", [\n (\"hello\", 5),\n (\"\", 0),\n (\"test\", 4),\n])\ndef test_string_length(input, expected):\n assert len(input) == expected\n```\n\n### Testing Exceptions\n\n```python\nimport pytest\nfrom myproject.core import divide\n\ndef test_divide_by_zero():\n with pytest.raises(ZeroDivisionError):\n divide(1, 0)\n\ndef test_divide_by_zero_message():\n with pytest.raises(ZeroDivisionError, match=\"division by zero\"):\n divide(1, 0)\n```\n\n### Async Tests\n\n```bash\nuv add --group test pytest-asyncio\n```\n\n```python\nimport pytest\n\[email protected]\nasync def test_async_function():\n result = await fetch_data()\n assert result is not None\n```\n\n## Property-Based Testing with Hypothesis\n\n```bash\nuv add --group test hypothesis\n```\n\n```python\nfrom hypothesis import given, strategies as st\nfrom myproject.core import reverse_string\n\n@given(st.text())\ndef test_reverse_is_reversible(s):\n assert reverse_string(reverse_string(s)) == s\n\n@given(st.integers(), st.integers())\ndef test_add_commutative(a, b):\n assert add(a, b) == add(b, a)\n```\n\n## Markers\n\n```python\nimport pytest\n\[email protected]\ndef test_slow_operation():\n # Long running test\n pass\n\[email protected]\ndef test_api_call():\n # Requires external service\n pass\n\[email protected](reason=\"Not implemented yet\")\ndef test_future_feature():\n pass\n\[email protected](sys.platform == \"win32\", reason=\"Unix only\")\ndef test_unix_feature():\n pass\n```\n\n## CI Configuration\n\n```yaml\n# GitHub Actions\n- name: Checkout\n uses: actions/checkout@\u003csha> # \u003clatest> https://github.com/actions/checkout/releases\n\n- name: Run tests\n run: |\n uv sync --group test\n uv run pytest --cov-report=xml\n\n- name: Security audit\n run: |\n uv sync --group audit\n uv run pip-audit\n\n- name: Upload coverage\n uses: codecov/codecov-action@\u003csha> # \u003clatest> https://github.com/codecov/codecov-action/releases\n with:\n files: ./coverage.xml\n```\n\n## Makefile Target\n\n```makefile\n.PHONY: test\n\ntest:\n\tuv run pytest\n\ntest-cov:\n\tuv run pytest --cov-report=html\n\topen htmlcov/index.html\n\ntest-fast:\n\tuv run pytest -x -q --no-cov\n```\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":5214,"content_sha256":"82e36068fbf28a9615d3c96e5d946e304ce8f89ae1ba7475d20934501d55b0d9"},{"filename":"references/uv-commands.md","content":"# uv Command Reference\n\n`uv` is an extremely fast Python package and project manager written in Rust. It replaces pip, virtualenv, pip-tools, pipx, and pyenv.\n\n**Key principle:** Always use `uv run` to execute commands. Never manually activate virtual environments.\n\n## Installation\n\n```bash\n# macOS/Linux\ncurl -LsSf https://astral.sh/uv/install.sh | sh\n\n# Windows\npowershell -ExecutionPolicy ByPass -c \"irm https://astral.sh/uv/install.ps1 | iex\"\n\n# Homebrew\nbrew install uv\n\n# pipx\npipx install uv\n```\n\n## Project Commands\n\n### Initialize Projects\n\n| Command | Description |\n|---------|-------------|\n| `uv init` | Create new project (application) |\n| `uv init --package` | Create distributable package with src/ layout |\n| `uv init --lib` | Create library package |\n| `uv init --script file.py` | Create script with PEP 723 metadata |\n\n### Dependency Management\n\n| Command | Description |\n|---------|-------------|\n| `uv add \u003cpkg>` | Add dependency to project |\n| `uv add \u003cpkg> --group dev` | Add to dependency group |\n| `uv add \u003cpkg> --optional feature` | Add to optional dependency |\n| `uv remove \u003cpkg>` | Remove dependency |\n| `uv lock` | Update lock file without installing |\n\n### Environment Management\n\nuv manages virtual environments automatically. Do not manually create or activate venvs.\n\n| Command | Description |\n|---------|-------------|\n| `uv sync` | Install dependencies (creates venv if needed) |\n| `uv sync --all-groups` | Install all dependency groups |\n| `uv sync --group dev` | Install specific group |\n| `uv sync --frozen` | Install from lock file exactly |\n\n### Running Code\n\n| Command | Description |\n|---------|-------------|\n| `uv run \u003ccmd>` | Run command in project venv |\n| `uv run python script.py` | Run Python script |\n| `uv run pytest` | Run pytest |\n| `uv run --with pkg cmd` | Run with temporary dependency |\n\n### Building & Publishing\n\n| Command | Description |\n|---------|-------------|\n| `uv build` | Build wheel and sdist |\n| `uv build --wheel` | Build wheel only |\n| `uv build --sdist` | Build sdist only |\n| `uv publish` | Publish to PyPI |\n| `uv publish --token $TOKEN` | Publish with API token |\n\n## Tool Commands\n\nRun Python tools without installing globally:\n\n```bash\n# Run any tool\nuv tool run ruff check .\nuvx ruff check . # shorthand\n\n# Install tool globally\nuv tool install ruff\n\n# List installed tools\nuv tool list\n\n# Upgrade tool\nuv tool upgrade ruff\n```\n\n## Python Version Management\n\n```bash\n# Install Python version\nuv python install 3.12\n\n# List available versions\nuv python list\n\n# Pin project to Python version\nuv python pin 3.12\n\n# Use specific version\nuv run --python 3.11 pytest\n```\n\n## Script Commands (PEP 723)\n\n```bash\n# Create script with inline metadata\nuv init --script myscript.py\n\n# Add dependency to script\nuv add --script myscript.py requests\n\n# Run script (auto-installs deps)\nuv run myscript.py\n```\n\n## Common Workflows\n\n### New Application Project\n\n```bash\nuv init myapp\ncd myapp\nuv add fastapi uvicorn\nuv add --group dev ruff pytest\nuv sync --all-groups\nuv run uvicorn myapp:app\n```\n\n### New Library Package\n\n```bash\nuv init --package mylib\ncd mylib\nuv add --group dev ruff pytest pytest-cov\nuv add --group docs sphinx\nuv sync --all-groups\nuv run pytest\nuv build\n```\n\n### Add Tool to Existing Project\n\n```bash\ncd existing-project\nuv add --group dev ruff\nuv run ruff check .\n```\n\n### One-off Script Execution\n\n```bash\n# Run script with dependencies (no project needed)\nuv run --with requests --with rich script.py\n\n# Or use PEP 723 inline metadata\nuv run script_with_metadata.py\n```\n\n## Environment Variables\n\n| Variable | Description |\n|----------|-------------|\n| `UV_CACHE_DIR` | Cache directory location |\n| `UV_NO_CACHE` | Disable caching |\n| `UV_PYTHON` | Default Python version |\n| `UV_PROJECT` | Project directory path |\n| `UV_PROJECT_ENVIRONMENT` | Custom venv directory (e.g., `.venv-dev`) |\n| `UV_SYSTEM_PYTHON` | Use system Python |\n\n## Container/Host Development\n\nWhen developing on a host machine while also running in containers, you can use separate venvs to avoid rebuilding on each context switch:\n\n```bash\n# On host machine (add to shell profile or .envrc)\nexport UV_PROJECT_ENVIRONMENT=.venv-dev\n\n# Now host uses .venv-dev, containers use default .venv\nuv sync # creates .venv-dev on host\n```\n\nAdd both to `.gitignore`:\n```\n.venv/\n.venv-dev/\n```\n\nThis avoids rebuilding the venv when switching between host and container (different OS, Python versions, or native dependencies).\n\n## Performance Tips\n\n- uv caches aggressively; first install may be slower\n- Use `uv sync --frozen` in CI for reproducible builds\n- Use `uv cache clean` if cache grows too large\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":4653,"content_sha256":"348cd69e8c780a0c7d54a2fac3c2956c7efe5630229782753da1685416672cdc"},{"filename":"templates/dependabot.yml","content":"# Dependabot configuration for Python projects\n# Copy to .github/dependabot.yml\n#\n# See references/dependabot.md for advanced configuration.\n\nversion: 2\nupdates:\n # Python dependencies (pyproject.toml, requirements.txt)\n - package-ecosystem: pip\n directory: /\n schedule:\n interval: weekly\n # 7-day cooldown: don't update packages published \u003c 7 days ago\n # Mitigates supply chain attacks via malicious updates\n cooldown:\n default-days: 7\n # Group minor/patch updates to reduce PR noise\n groups:\n dev-dependencies:\n dependency-type: development\n update-types: [minor, patch]\n production-dependencies:\n dependency-type: production\n update-types: [patch]\n\n # GitHub Actions\n - package-ecosystem: github-actions\n directory: /\n schedule:\n interval: weekly\n cooldown:\n default-days: 7\n groups:\n actions:\n patterns: [\"*\"]\n update-types: [minor, patch]\n","content_type":"application/yaml; charset=utf-8","language":"yaml","size":958,"content_sha256":"a85ede8ff9cc3a2f63cb1fba24e65c36a5885ecc95722af15157dc5258f28a12"},{"filename":"templates/pre-commit-config.yaml","content":"# Pre-commit configuration for Python projects\n# Copy to your repo root as .pre-commit-config.yaml\n#\n# IMPORTANT: Replace all \u003clatest> placeholders with actual versions.\n# Check each linked releases page for current stable versions.\n#\n# Usage:\n# prek install # Install git hooks\n# prek run --all-files # Run on all files\n#\n# See references/prek.md for more commands.\n\ndefault_language_version:\n python: python3.12\n\nrepos:\n # === Code Quality ===\n\n # Ruff - linting and formatting (replaces black, isort, flake8, pylint)\n - repo: https://github.com/astral-sh/ruff-pre-commit\n rev: \u003clatest> # https://github.com/astral-sh/ruff-pre-commit/releases\n hooks:\n - id: ruff\n args: [--fix]\n - id: ruff-format\n\n # === General File Checks ===\n # prek builtin hooks - faster, no external deps\n - repo: builtin\n hooks:\n - id: trailing-whitespace\n - id: end-of-file-fixer\n - id: check-yaml\n - id: check-toml\n - id: check-merge-conflict\n\n # === Security Hooks ===\n # See references/security-setup.md for detailed guidance on each hook.\n\n # Shell script linting - catches unquoted vars, undefined vars, deprecated syntax\n - repo: https://github.com/koalaman/shellcheck-precommit\n rev: \u003clatest> # https://github.com/koalaman/shellcheck-precommit/tags\n hooks:\n - id: shellcheck\n args: [--severity=error]\n\n # Secret detection - prevents committing API keys, passwords, tokens\n # Run `detect-secrets scan > .secrets.baseline` before first commit\n - repo: https://github.com/Yelp/detect-secrets\n rev: \u003clatest> # https://github.com/Yelp/detect-secrets/releases\n hooks:\n - id: detect-secrets\n args: [--baseline, .secrets.baseline]\n\n # GitHub Actions linting - catches syntax errors, invalid refs\n - repo: https://github.com/rhysd/actionlint\n rev: \u003clatest> # https://github.com/rhysd/actionlint/releases\n hooks:\n - id: actionlint\n\n # GitHub Actions security audit - excessive permissions, injection risks\n - repo: https://github.com/zizmorcore/zizmor-pre-commit\n rev: \u003clatest> # https://github.com/zizmorcore/zizmor-pre-commit/releases\n hooks:\n - id: zizmor\n args: [--persona=regular, --min-severity=medium, --min-confidence=medium]\n","content_type":"application/yaml; charset=utf-8","language":"yaml","size":2259,"content_sha256":"18efd067e75cba5fc71705c2f90c548a03c3cded4cd2a7f9b4a1d617e115db0d"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"Modern Python","type":"text"}]},{"type":"paragraph","content":[{"text":"Guide for modern Python tooling and best practices, based on ","type":"text"},{"text":"trailofbits/cookiecutter-python","type":"text","marks":[{"type":"link","attrs":{"href":"https://github.com/trailofbits/cookiecutter-python","title":null}}]},{"text":".","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"When to Use This Skill","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Creating a new Python project or package","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Setting up ","type":"text"},{"text":"pyproject.toml","type":"text","marks":[{"type":"code_inline"}]},{"text":" configuration","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Configuring development tools (linting, formatting, testing)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Writing Python scripts with external dependencies","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Migrating from legacy tools (when user requests it)","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"When NOT to Use This Skill","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"User wants to keep legacy tooling","type":"text","marks":[{"type":"strong"}]},{"text":": Respect existing workflows if explicitly requested","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Python \u003c 3.11 required","type":"text","marks":[{"type":"strong"}]},{"text":": These tools target modern Python","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Non-Python projects","type":"text","marks":[{"type":"strong"}]},{"text":": Mixed codebases where Python isn't primary","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Anti-Patterns to Avoid","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Avoid","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Use Instead","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"[tool.ty]","type":"text","marks":[{"type":"code_inline"}]},{"text":" python-version","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"[tool.ty.environment]","type":"text","marks":[{"type":"code_inline"}]},{"text":" python-version","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"uv pip install","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"uv add","type":"text","marks":[{"type":"code_inline"}]},{"text":" and ","type":"text"},{"text":"uv sync","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Editing pyproject.toml manually to add deps","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"uv add \u003cpkg>","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"uv remove \u003cpkg>","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"hatchling","type":"text","marks":[{"type":"code_inline"}]},{"text":" build backend","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"uv_build","type":"text","marks":[{"type":"code_inline"}]},{"text":" (simpler, sufficient for most cases)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Poetry","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"uv (faster, simpler, better ecosystem integration)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"requirements.txt","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"PEP 723 for scripts, pyproject.toml for projects","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"mypy / pyright","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ty (faster, from Astral team)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"[project.optional-dependencies]","type":"text","marks":[{"type":"code_inline"}]},{"text":" for dev tools","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"[dependency-groups]","type":"text","marks":[{"type":"code_inline"}]},{"text":" (PEP 735)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Manual virtualenv activation (","type":"text"},{"text":"source .venv/bin/activate","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"uv run \u003ccmd>","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"pre-commit","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"prek (faster, no Python runtime needed)","type":"text"}]}]}]}]},{"type":"paragraph","content":[{"text":"Key principles:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Always use ","type":"text"},{"text":"uv add","type":"text","marks":[{"type":"code_inline"}]},{"text":" and ","type":"text"},{"text":"uv remove","type":"text","marks":[{"type":"code_inline"}]},{"text":" to manage dependencies","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Never manually activate or manage virtual environments—use ","type":"text"},{"text":"uv run","type":"text","marks":[{"type":"code_inline"}]},{"text":" for all commands","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use ","type":"text"},{"text":"[dependency-groups]","type":"text","marks":[{"type":"code_inline"}]},{"text":" for dev/test/docs dependencies, not ","type":"text"},{"text":"[project.optional-dependencies]","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Decision Tree","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"What are you doing?\n│\n├─ Single-file script with dependencies?\n│ └─ Use PEP 723 inline metadata (./references/pep723-scripts.md)\n│\n├─ New multi-file project (not distributed)?\n│ └─ Minimal uv setup (see Quick Start below)\n│\n├─ New reusable package/library?\n│ └─ Full project setup (see Full Setup below)\n│\n└─ Migrating existing project?\n └─ See Migration Guide below","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Tool Overview","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Tool","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Purpose","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Replaces","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"uv","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Package/dependency management","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"pip, virtualenv, pip-tools, pipx, pyenv","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ruff","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Linting AND formatting","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"flake8, black, isort, pyupgrade, pydocstyle","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ty","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Type checking","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"mypy, pyright (faster alternative)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"pytest","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Testing with coverage","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"unittest","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"prek","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Pre-commit hooks (","type":"text"},{"text":"setup","type":"text","marks":[{"type":"link","attrs":{"href":"./references/prek.md","title":null}}]},{"text":")","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"pre-commit (faster, Rust-native)","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Security Tools","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Tool","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Purpose","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"When It Runs","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"shellcheck","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Shell script linting","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"pre-commit","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"detect-secrets","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Secret detection","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"pre-commit","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"actionlint","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Workflow syntax validation","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"pre-commit, CI","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"zizmor","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Workflow security audit","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"pre-commit, CI","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"pip-audit","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Dependency vulnerability scanning","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"CI, manual","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Dependabot","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Automated dependency updates","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"scheduled","type":"text"}]}]}]}]},{"type":"paragraph","content":[{"text":"See ","type":"text"},{"text":"security-setup.md","type":"text","marks":[{"type":"link","attrs":{"href":"./references/security-setup.md","title":null}}]},{"text":" for configuration and usage.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Quick Start: Minimal Project","type":"text"}]},{"type":"paragraph","content":[{"text":"For simple multi-file projects not intended for distribution:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Create project with uv\nuv init myproject\ncd myproject\n\n# Add dependencies\nuv add requests rich\n\n# Add dev dependencies\nuv add --group dev pytest ruff ty\n\n# Run code\nuv run python src/myproject/main.py\n\n# Run tools\nuv run pytest\nuv run ruff check .","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Full Project Setup","type":"text"}]},{"type":"paragraph","content":[{"text":"If starting from scratch, ask the user if they prefer to use the Trail of Bits cookiecutter template to bootstrap a complete project with already preconfigured tooling.","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"uvx cookiecutter gh:trailofbits/cookiecutter-python","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"1. Create Project Structure","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"uv init --package myproject\ncd myproject","type":"text"}]},{"type":"paragraph","content":[{"text":"This creates:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"myproject/\n├── pyproject.toml\n├── README.md\n├── src/\n│ └── myproject/\n│ └── __init__.py\n└── .python-version","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"2. Configure pyproject.toml","type":"text"}]},{"type":"paragraph","content":[{"text":"See ","type":"text"},{"text":"pyproject.md","type":"text","marks":[{"type":"link","attrs":{"href":"./references/pyproject.md","title":null}}]},{"text":" for complete configuration reference.","type":"text"}]},{"type":"paragraph","content":[{"text":"Key sections:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"toml"},"content":[{"text":"[project]\nname = \"myproject\"\nversion = \"0.1.0\"\nrequires-python = \">=3.11\"\ndependencies = []\n\n[dependency-groups]\ndev = [{include-group = \"lint\"}, {include-group = \"test\"}, {include-group = \"audit\"}]\nlint = [\"ruff\", \"ty\"]\ntest = [\"pytest\", \"pytest-cov\"]\naudit = [\"pip-audit\"]\n\n[tool.ruff]\nline-length = 100\ntarget-version = \"py311\"\n\n[tool.ruff.lint]\nselect = [\"ALL\"]\nignore = [\"D\", \"COM812\", \"ISC001\"]\n\n[tool.pytest]\naddopts = [\"--cov=myproject\", \"--cov-fail-under=80\"]\n\n[tool.ty.terminal]\nerror-on-warning = true\n\n[tool.ty.environment]\npython-version = \"3.11\"\n\n[tool.ty.rules]\n# Strict from day 1 for new projects\npossibly-unresolved-reference = \"error\"\nunused-ignore-comment = \"warn\"","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"3. Install Dependencies","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Install all dependency groups\nuv sync --all-groups\n\n# Or install specific groups\nuv sync --group dev","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"4. Add Makefile","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"makefile"},"content":[{"text":".PHONY: dev lint format test build\n\ndev:\n\tuv sync --all-groups\n\nlint:\n\tuv run ruff format --check && uv run ruff check && uv run ty check src/\n\nformat:\n\tuv run ruff format .\n\ntest:\n\tuv run pytest\n\nbuild:\n\tuv build","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Migration Guide","type":"text"}]},{"type":"paragraph","content":[{"text":"When a user requests migration from legacy tooling:","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"From requirements.txt + pip","type":"text"}]},{"type":"paragraph","content":[{"text":"First, determine the nature of the code:","type":"text"}]},{"type":"paragraph","content":[{"text":"For standalone scripts","type":"text","marks":[{"type":"strong"}]},{"text":": Convert to PEP 723 inline metadata (see ","type":"text"},{"text":"pep723-scripts.md","type":"text","marks":[{"type":"link","attrs":{"href":"./references/pep723-scripts.md","title":null}}]},{"text":")","type":"text"}]},{"type":"paragraph","content":[{"text":"For projects","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Initialize uv in existing project\nuv init --bare\n\n# Add dependencies using uv (not by editing pyproject.toml)\nuv add requests rich # add each package\n\n# Or import from requirements.txt (review each package before adding)\n# Note: Complex version specifiers may need manual handling\ngrep -v '^#' requirements.txt | grep -v '^-' | grep -v '^\\s*

Modern Python Guide for modern Python tooling and best practices, based on trailofbits/cookiecutter-python. When to Use This Skill - Creating a new Python project or package - Setting up configuration - Configuring development tools (linting, formatting, testing) - Writing Python scripts with external dependencies - Migrating from legacy tools (when user requests it) When NOT to Use This Skill - User wants to keep legacy tooling : Respect existing workflows if explicitly requested - Python < 3.11 required : These tools target modern Python - Non-Python projects : Mixed codebases where Python…

| while read -r pkg; do\n uv add \"$pkg\" || echo \"Failed to add: $pkg\"\ndone\n\nuv sync","type":"text"}]},{"type":"paragraph","content":[{"text":"Then:","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Delete ","type":"text"},{"text":"requirements.txt","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"requirements-dev.txt","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Delete virtual environment (","type":"text"},{"text":"venv/","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":".venv/","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Add ","type":"text"},{"text":"uv.lock","type":"text","marks":[{"type":"code_inline"}]},{"text":" to version control","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"From setup.py / setup.cfg","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Run ","type":"text"},{"text":"uv init --bare","type":"text","marks":[{"type":"code_inline"}]},{"text":" to create pyproject.toml","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use ","type":"text"},{"text":"uv add","type":"text","marks":[{"type":"code_inline"}]},{"text":" to add each dependency from ","type":"text"},{"text":"install_requires","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use ","type":"text"},{"text":"uv add --group dev","type":"text","marks":[{"type":"code_inline"}]},{"text":" for dev dependencies","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Copy non-dependency metadata (name, version, description, etc.) to ","type":"text"},{"text":"[project]","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Delete ","type":"text"},{"text":"setup.py","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"setup.cfg","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"MANIFEST.in","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"From flake8 + black + isort","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Remove flake8, black, isort via ","type":"text"},{"text":"uv remove","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Delete ","type":"text"},{"text":".flake8","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"pyproject.toml [tool.black]","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"[tool.isort]","type":"text","marks":[{"type":"code_inline"}]},{"text":" configs","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Add ruff: ","type":"text"},{"text":"uv add --group dev ruff","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Add ruff configuration (see ","type":"text"},{"text":"ruff-config.md","type":"text","marks":[{"type":"link","attrs":{"href":"./references/ruff-config.md","title":null}}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Run ","type":"text"},{"text":"uv run ruff check --fix .","type":"text","marks":[{"type":"code_inline"}]},{"text":" to apply fixes","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Run ","type":"text"},{"text":"uv run ruff format .","type":"text","marks":[{"type":"code_inline"}]},{"text":" to format","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"From mypy / pyright","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Remove mypy/pyright via ","type":"text"},{"text":"uv remove","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Delete ","type":"text"},{"text":"mypy.ini","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"pyrightconfig.json","type":"text","marks":[{"type":"code_inline"}]},{"text":", or ","type":"text"},{"text":"[tool.mypy]","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"[tool.pyright]","type":"text","marks":[{"type":"code_inline"}]},{"text":" sections","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Add ty: ","type":"text"},{"text":"uv add --group dev ty","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Run ","type":"text"},{"text":"uv run ty check src/","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Quick Reference: uv Commands","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Command","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Description","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"uv init","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Create new project","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"uv init --package","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Create distributable package","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"uv add \u003cpkg>","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Add dependency","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"uv add --group dev \u003cpkg>","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Add to dependency group","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"uv remove \u003cpkg>","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Remove dependency","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"uv sync","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Install dependencies","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"uv sync --all-groups","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Install all dependency groups","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"uv run \u003ccmd>","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Run command in venv","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"uv run --with \u003cpkg> \u003ccmd>","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Run with temporary dependency","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"uv build","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Build package","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"uv publish","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Publish to PyPI","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Ad-hoc Dependencies with ","type":"text"},{"text":"--with","type":"text","marks":[{"type":"code_inline"}]}]},{"type":"paragraph","content":[{"text":"Use ","type":"text"},{"text":"uv run --with","type":"text","marks":[{"type":"code_inline"}]},{"text":" for one-off commands that need packages not in your project:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Run Python with a temporary package\nuv run --with requests python -c \"import requests; print(requests.get('https://httpbin.org/ip').json())\"\n\n# Run a module with temporary deps\nuv run --with rich python -m rich.progress\n\n# Multiple packages\nuv run --with requests --with rich python script.py\n\n# Combine with project deps (adds to existing venv)\nuv run --with httpx pytest # project deps + httpx","type":"text"}]},{"type":"paragraph","content":[{"text":"When to use ","type":"text","marks":[{"type":"strong"}]},{"text":"--with","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" vs ","type":"text","marks":[{"type":"strong"}]},{"text":"uv add","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":":","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"uv add","type":"text","marks":[{"type":"code_inline"}]},{"text":": Package is a project dependency (goes in pyproject.toml/uv.lock)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"--with","type":"text","marks":[{"type":"code_inline"}]},{"text":": One-off usage, testing, or scripts outside a project context","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"See ","type":"text"},{"text":"uv-commands.md","type":"text","marks":[{"type":"link","attrs":{"href":"./references/uv-commands.md","title":null}}]},{"text":" for complete reference.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Quick Reference: Dependency Groups","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"toml"},"content":[{"text":"[dependency-groups]\ndev = [\"ruff\", \"ty\"]\ntest = [\"pytest\", \"pytest-cov\", \"hypothesis\"]\ndocs = [\"sphinx\", \"myst-parser\"]","type":"text"}]},{"type":"paragraph","content":[{"text":"Install with: ","type":"text"},{"text":"uv sync --group dev --group test","type":"text","marks":[{"type":"code_inline"}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Best Practices Checklist","type":"text"}]},{"type":"checkbox_list","attrs":{"id":null},"content":[{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"Use ","type":"text"},{"text":"src/","type":"text","marks":[{"type":"code_inline"}]},{"text":" layout for packages","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"Set ","type":"text"},{"text":"requires-python = \">=3.11\"","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"Configure ruff with ","type":"text"},{"text":"select = [\"ALL\"]","type":"text","marks":[{"type":"code_inline"}]},{"text":" and explicit ignores","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"Use ty for type checking","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"Enforce test coverage minimum (80%+)","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"Use dependency groups instead of extras for dev tools","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"Add ","type":"text"},{"text":"uv.lock","type":"text","marks":[{"type":"code_inline"}]},{"text":" to version control","type":"text"}]}]},{"type":"checkbox_item","attrs":{"checked":false},"content":[{"type":"paragraph","content":[{"text":"Use PEP 723 for standalone scripts","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Read Next","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"migration-checklist.md","type":"text","marks":[{"type":"link","attrs":{"href":"./references/migration-checklist.md","title":null}}]},{"text":" - Step-by-step migration cleanup","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"pyproject.md","type":"text","marks":[{"type":"link","attrs":{"href":"./references/pyproject.md","title":null}}]},{"text":" - Complete pyproject.toml reference","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"uv-commands.md","type":"text","marks":[{"type":"link","attrs":{"href":"./references/uv-commands.md","title":null}}]},{"text":" - uv command reference","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"ruff-config.md","type":"text","marks":[{"type":"link","attrs":{"href":"./references/ruff-config.md","title":null}}]},{"text":" - Ruff linting/formatting configuration","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"testing.md","type":"text","marks":[{"type":"link","attrs":{"href":"./references/testing.md","title":null}}]},{"text":" - pytest and coverage setup","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"pep723-scripts.md","type":"text","marks":[{"type":"link","attrs":{"href":"./references/pep723-scripts.md","title":null}}]},{"text":" - PEP 723 inline script metadata","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"prek.md","type":"text","marks":[{"type":"link","attrs":{"href":"./references/prek.md","title":null}}]},{"text":" - Fast pre-commit hooks with prek","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"security-setup.md","type":"text","marks":[{"type":"link","attrs":{"href":"./references/security-setup.md","title":null}}]},{"text":" - Security hooks and dependency scanning","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"dependabot.md","type":"text","marks":[{"type":"link","attrs":{"href":"./references/dependabot.md","title":null}}]},{"text":" - Automated dependency updates","type":"text"}]}]}]}]},"metadata":{"date":"2026-11-02","name":"modern-python","author":"@skillopedia","source":{"stars":7957,"repo_name":"skills","origin_url":"https://github.com/trailofbits/skills/blob/HEAD/plugins/modern-python/skills/modern-python/SKILL.md","repo_owner":"trailofbits","body_sha256":"ef774b925eb1d1fc12e4f5ddc3f5ad925ecd795315827447228c70cc44c6170c","cluster_key":"2f4832824aea6d79a51bbb2f8d98865de4655631cc046d9b74d2ade21af8238e","clean_bundle":{"format":"clean-skill-bundle-v1","source":"trailofbits/skills/plugins/modern-python/skills/modern-python/SKILL.md","text_bytes":46940,"source_commit":"d016e08cc7408ecb1853a299d06d4a56e363ad5e","skills_sh_rank":2728,"attachment_count":12,"text_attachments":12,"attachment_storage":"skill_attachments","binary_attachments":0},"cluster_size":1,"skill_md_path":"plugins/modern-python/skills/modern-python/SKILL.md","import_metadata":{"date":"2026-11-02","author":"@skillopedia","version":"v1","category":"software-engineering","category_label":"Engineering"},"exact_dupes_collapsed_into_this":0},"version":"v1","category":"software-engineering","import_tag":"skills-sh-top20k-2026-11","description":"Configures Python projects with modern tooling (uv, ruff, ty). Use when creating projects, writing standalone scripts, or migrating from pip/Poetry/mypy/black."}},"renderedAt":1793671046597}

Modern Python Guide for modern Python tooling and best practices, based on trailofbits/cookiecutter-python. When to Use This Skill - Creating a new Python project or package - Setting up configuration - Configuring development tools (linting, formatting, testing) - Writing Python scripts with external dependencies - Migrating from legacy tools (when user requests it) When NOT to Use This Skill - User wants to keep legacy tooling : Respect existing workflows if explicitly requested - Python < 3.11 required : These tools target modern Python - Non-Python projects : Mixed codebases where Python…