Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 18:49:58 +08:00
commit 5007abf04b
89 changed files with 44129 additions and 0 deletions

View File

@@ -0,0 +1,548 @@
---
title: "PEP 723 - Inline Script Metadata"
description: "Official Python specification for embedding dependency metadata in single-file scripts"
version: "1.0.0"
last_updated: "2025-11-04"
document_type: "reference"
official_specification: "https://peps.python.org/pep-0723/"
python_compatibility: "3.11+"
related_docs:
- "../SKILL.md"
- "./python-development-orchestration.md"
---
# PEP 723 - Inline Script Metadata
## What is PEP 723?
PEP 723 is the official Python specification that defines a standard format for embedding metadata in single-file Python scripts. It allows scripts to declare their dependencies and Python version requirements without requiring separate configuration files like `pyproject.toml` or `requirements.txt`.
## Official Specification
The model must WebFetch this url before discussing the topic with the user [pep-0723](https://peps.python.org/pep-0723/)
## Key Concept
PEP 723 metadata is embedded **inside Python comments** using a special syntax, making the metadata human-readable and machine-parseable while keeping the script as a single portable file.
If implementing anything to interact with this metadata, such as a linting enhancer you must WebFetch [inline-script-metadata](https://packaging.python.org/en/latest/specifications/inline-script-metadata/#inline-script-metadata) to get the schema and syntax and implementation.
## The Problem It Solves
### The Challenge
When sharing Python scripts as standalone files (via email, gists, URLs, or chat), there's a fundamental problem:
- **Scripts often need external dependencies** (requests, rich, pandas, etc.)
- **No standard way** to declare these dependencies within the script itself
- **Tools can't automatically know** what packages to install to run the script
- **Users must read documentation** or comments to figure out requirements
### The Solution
PEP 723 provides a **standardized comment-based format** that:
- ✅ Embeds dependency declarations directly in the script
- ✅ Remains a valid Python file (metadata is in comments)
- ✅ Is machine-readable by package managers (uv, PDM, Hatch)
- ✅ Keeps everything in a single portable file
## Syntax
### Format
PEP 723 metadata is written as **TOML inside specially-formatted Python comments**:
```python
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "requests<3",
# "rich",
# ]
# ///
```
### Rules
1. **Opening marker**: `# /// script` (exactly, with spaces)
2. **Content**: Valid TOML, with each line prefixed by `#` and a space
3. **Closing marker**: `# ///` (exactly, with spaces)
4. **Location**: Typically near the top of the file, after shebang and module docstring
5. **Indentation**: Use consistent comment formatting
### Supported Fields
```toml
# /// script
# requires-python = ">=3.11" # Minimum Python version
# dependencies = [ # External packages
# "requests>=2.31.0,<3",
# "rich>=13.0",
# "typer[all]>=0.12.0",
# ]
# ///
```
## When to Use PEP 723
### ✅ Use PEP 723 When
1. **Script has external dependencies**
- Uses packages from PyPI (requests, pandas, rich, etc.)
- Needs specific package versions
- Example: A CLI tool that fetches data from APIs
2. **Sharing standalone scripts**
- Sending scripts via email, gists, or chat
- Publishing example scripts in documentation
- Creating portable automation tools
3. **Scripts need reproducibility**
- Version-pinned dependencies for consistent behavior
- Specific Python version requirements
- Example: Deployment scripts that must work identically across environments
### ❌ Don't Use PEP 723 When
1. **Script uses only stdlib**
- No external dependencies = nothing to declare
- Use simple shebang: `#!/usr/bin/env python3`
- Example: A script that uses only `argparse`, `pathlib`, `json`
2. **Full project with pyproject.toml**
- Projects have proper package structure
- Use `pyproject.toml` for dependency management
- PEP 723 is for **single-file scripts**, not projects
3. **Script is part of a package**
- Package dependencies are declared in `pyproject.toml`
- Script uses package-level dependencies
- No need to duplicate declarations
## Shebang Requirements
### Scripts with PEP 723 Metadata
**Must use** the uv-based shebang for automatic dependency installation:
```python
#!/usr/bin/env -S uv --quiet run --active --script
# /// script
# requires-python = ">=3.11"
# dependencies = ["requests", "rich"]
# ///
import requests
from rich import print
```
**Why this shebang?**
- `uv --quiet run --active --script`: Tells uv to:
- Read PEP 723 metadata from the script
- Install declared dependencies automatically
- Execute the script with correct environment
### Stdlib-Only Scripts
**Use** the standard Python shebang (no PEP 723 needed):
```python
#!/usr/bin/env python3
import argparse
import pathlib
import json
# No dependencies to declare
```
**Why no PEP 723?**
- Stdlib is always available (bundled with Python)
- Nothing to declare = no metadata needed
- Simpler is better when appropriate
## Complete Example
### Script with External Dependencies
```python
#!/usr/bin/env -S uv --quiet run --active --script
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "requests>=2.31.0,<3",
# "rich>=13.0",
# ]
# ///
"""Fetch GitHub user info and display with rich formatting."""
import sys
from typing import Any
import requests
from rich.console import Console
from rich.panel import Panel
console = Console()
def fetch_user(username: str) -> dict[str, Any] | None:
"""Fetch GitHub user data."""
response = requests.get(f"https://api.github.com/users/{username}")
if response.status_code == 200:
return response.json()
return None
def main() -> None:
"""Main entry point."""
if len(sys.argv) != 2:
console.print("[red]Usage: script.py <github-username>[/red]")
sys.exit(1)
username = sys.argv[1]
user = fetch_user(username)
if user:
console.print(
Panel(
f"[bold]{user['name']}[/bold]\n"
f"Followers: {user['followers']}\n"
f"Public Repos: {user['public_repos']}",
title=f"GitHub: {username}",
)
)
else:
console.print(f"[red]User '{username}' not found[/red]")
if __name__ == "__main__":
main()
```
**To run**:
```bash
chmod +x script.py
./script.py octocat
```
The script will:
1. Read PEP 723 metadata
2. Install `requests` and `rich` if not present
3. Execute with dependencies available
### Stdlib-Only Script
```python
#!/usr/bin/env python3
"""Simple JSON formatter using only stdlib."""
import argparse
import json
import sys
from pathlib import Path
def format_json(input_path: Path, indent: int = 2) -> None:
"""Format JSON file with specified indentation."""
data = json.loads(input_path.read_text())
formatted = json.dumps(data, indent=indent, sort_keys=True)
print(formatted)
def main() -> None:
"""Main entry point."""
parser = argparse.ArgumentParser(description="Format JSON files")
parser.add_argument("file", type=Path, help="JSON file to format")
parser.add_argument("--indent", type=int, default=2, help="Indentation spaces")
args = parser.parse_args()
format_json(args.file, args.indent)
if __name__ == "__main__":
main()
```
**No PEP 723 needed** - all imports are from Python's standard library.
## Tool Support
### Package Managers
The following tools support PEP 723 inline script metadata:
- **uv**: [https://docs.astral.sh/uv/](https://docs.astral.sh/uv/)
- **PDM**: [https://pdm-project.org/](https://pdm-project.org/)
- **Hatch**: [https://hatch.pypa.io/](https://hatch.pypa.io/)
### Running Scripts with uv
```bash
# Make script executable
chmod +x script.py
# Run directly (uv reads PEP 723 metadata)
./script.py
# Or explicitly with uv
uv run script.py
```
### Alternative: PDM
```bash
pdm run script.py
```
## Common Patterns
### Version Constraints
```python
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "requests>=2.31.0,<3", # Major version constraint
# "rich~=13.7", # Compatible release
# "typer[all]", # With extras
# ]
# ///
```
### Development vs Production
**For scripts**, there's typically no separation - all dependencies are runtime dependencies. If you need development tools (testing, linting), those belong in a full project with `pyproject.toml`.
### Git-Based Dependencies
```python
# /// script
# dependencies = [
# "mylib @ git+https://github.com/user/mylib.git@v1.0.0",
# ]
# ///
```
## Best Practices
### 1. Pin Major Versions
```python
# Good - prevents breaking changes
"requests>=2.31.0,<3"
# Avoid - might break on major updates
"requests"
```
### 2. Document the Script
```python
#!/usr/bin/env -S uv --quiet run --active --script
# /// script
# requires-python = ">=3.11"
# dependencies = ["requests", "rich"]
# ///
"""
Fetch and display GitHub user statistics.
Usage:
./github_stats.py <username>
Example:
./github_stats.py octocat
"""
```
### 3. Keep Scripts Focused
PEP 723 is for **single-file scripts**. If your script is growing large or needs multiple modules, consider creating a proper Python package with `pyproject.toml`.
### 4. Test Portability
```bash
# Test on clean environment
uv run --isolated script.py args
```
## Comparison: PEP 723 vs pyproject.toml
| Aspect | PEP 723 (Script) | pyproject.toml (Project) |
| ---------------- | ------------------------- | -------------------------- |
| **Use case** | Single-file scripts | Multi-module packages |
| **Dependencies** | Inline comments | Separate TOML file |
| **Portability** | Single file to share | Requires project structure |
| **Complexity** | Simple, focused | Full project metadata |
| **When to use** | Scripts with dependencies | Libraries, applications |
## Validation
### Using /shebangpython Command
The `/shebangpython` command validates PEP 723 compliance:
```bash
/shebangpython script.py
```
**Checks**:
- ✅ Correct shebang for dependency type
- ✅ PEP 723 syntax if external dependencies detected
- ✅ Metadata fields are valid
- ✅ Execute permission set
See: [/shebangpython command reference](~/.claude/commands/shebangpython.md)
## Troubleshooting
### Script Won't Execute
**Problem**: `./script.py` fails with "dependencies not found"
**Solution**: Check shebang is correct for PEP 723:
```python
#!/usr/bin/env -S uv --quiet run --active --script
```
### Syntax Errors in Metadata
**Problem**: TOML parsing fails
**Solution**: Validate TOML syntax:
```python
# /// script
# requires-python = ">=3.11" # ✅ Correct
# dependencies = [ # ✅ Correct - list syntax
# "requests",
# ]
# ///
```
### Performance Concerns
**Problem**: Script slow to start (installing dependencies)
**Solution**: uv caches dependencies. First run may be slow, subsequent runs are fast. For production, consider packaging as a proper project.
## Migration
### From requirements.txt
**Before** (two files):
```text
# requirements.txt
requests>=2.31.0
rich>=13.0
```
```python
#!/usr/bin/env python3
# script.py (separate file)
import requests
from rich import print
```
**After** (single file):
```python
#!/usr/bin/env -S uv --quiet run --active --script
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "requests>=2.31.0",
# "rich>=13.0",
# ]
# ///
import requests
from rich import print
```
### From Setup.py Scripts
**Before** (package structure):
```text
myproject/
├── setup.py
├── requirements.txt
└── scripts/
└── tool.py
```
**After** (standalone script):
```python
#!/usr/bin/env -S uv --quiet run --active --script
# /// script
# requires-python = ">=3.11"
# dependencies = ["requests", "rich"]
# ///
# tool.py - now fully self-contained
```
## Summary
### Key Takeaways
1. **PEP 723 = Dependency Metadata for Single-File Scripts**
- Standard format for declaring dependencies in comments
- TOML content inside `# ///` delimiters
2. **When to Use**
- Scripts **with external dependencies**
- Need portability (single file to share)
- Want automatic dependency installation
3. **When NOT to Use**
- Stdlib-only scripts (nothing to declare)
- Full projects (use `pyproject.toml`)
- Package modules (use package dependencies)
4. **Shebang Requirements**
- With PEP 723: `#!/usr/bin/env -S uv --quiet run --active --script`
- Stdlib only: `#!/usr/bin/env python3`
5. **Tool Support**
- uv, PDM, Hatch all support PEP 723
- Automatic dependency installation on script execution
### Quick Reference
```python
# Template for PEP 723 script
#!/usr/bin/env -S uv --quiet run --active --script
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "package-name>=version",
# ]
# ///
"""Script description."""
import package_name
# Your code here
```
## See Also
- **Official PEP**: [https://peps.python.org/pep-0723/](https://peps.python.org/pep-0723/)
- **uv Documentation**: [https://docs.astral.sh/uv/](https://docs.astral.sh/uv/)
- **Skill Reference**: [Python Development SKILL.md](../SKILL.md)
- **Shebang Validation**: [/shebangpython command](~/.claude/commands/shebangpython.md)