230 lines
5.1 KiB
Markdown
230 lines
5.1 KiB
Markdown
# Ruff Configuration Guide
|
|
|
|
Ruff is a fast Python linter and formatter that replaces multiple tools (isort, flake8, pyupgrade, etc.).
|
|
|
|
## Basic Configuration
|
|
|
|
Add to `pyproject.toml`:
|
|
|
|
```toml
|
|
[tool.ruff]
|
|
line-length = 100
|
|
target-version = "py311"
|
|
src = ["src", "tests"]
|
|
|
|
[tool.ruff.lint]
|
|
select = [
|
|
"E", # pycodestyle errors
|
|
"W", # pycodestyle warnings
|
|
"F", # pyflakes
|
|
"I", # isort
|
|
"B", # flake8-bugbear
|
|
"C4", # flake8-comprehensions
|
|
"UP", # pyupgrade
|
|
"ARG", # flake8-unused-arguments
|
|
"SIM", # flake8-simplify
|
|
"TCH", # flake8-type-checking
|
|
"RUF", # Ruff-specific rules
|
|
]
|
|
|
|
ignore = [
|
|
"E501", # line too long (handled by formatter)
|
|
"B008", # do not perform function calls in argument defaults
|
|
]
|
|
|
|
[tool.ruff.lint.per-file-ignores]
|
|
"tests/**/*.py" = [
|
|
"ARG", # Unused function arguments allowed in tests
|
|
"S101", # Assert allowed in tests
|
|
]
|
|
"__init__.py" = [
|
|
"F401", # Unused imports allowed in __init__.py
|
|
]
|
|
|
|
[tool.ruff.format]
|
|
quote-style = "double"
|
|
indent-style = "space"
|
|
line-ending = "auto"
|
|
|
|
[tool.ruff.lint.isort]
|
|
known-first-party = ["project_name"]
|
|
```
|
|
|
|
## Rule Categories
|
|
|
|
### Error Detection (E, W, F)
|
|
- **E**: PEP 8 style errors
|
|
- **W**: PEP 8 style warnings
|
|
- **F**: PyFlakes logical errors
|
|
|
|
### Code Quality (B, C4, SIM)
|
|
- **B**: Bugbear - likely bugs and design problems
|
|
- **C4**: Comprehensions - simplify list/dict/set comprehensions
|
|
- **SIM**: Simplify - code simplification suggestions
|
|
|
|
### Modernization (UP)
|
|
- **UP**: PyUpgrade - use modern Python syntax
|
|
- `typing.List` → `list`
|
|
- `Optional[str]` → `str | None` (Python 3.10+)
|
|
|
|
### Organization (I)
|
|
- **I**: isort - import sorting and organization
|
|
|
|
### Performance (ARG, TCH)
|
|
- **ARG**: Detect unused function arguments
|
|
- **TCH**: Type checking imports (move to TYPE_CHECKING block)
|
|
|
|
## Common Rules
|
|
|
|
### E/W Series (PEP 8)
|
|
- `E111`: Indentation is not a multiple of 4
|
|
- `E201`: Whitespace after '('
|
|
- `E202`: Whitespace before ')'
|
|
- `E203`: Whitespace before ':'
|
|
- `E302`: Expected 2 blank lines
|
|
- `E303`: Too many blank lines
|
|
- `W291`: Trailing whitespace
|
|
|
|
### F Series (PyFlakes)
|
|
- `F401`: Unused import
|
|
- `F811`: Redefinition of unused name
|
|
- `F821`: Undefined name
|
|
- `F841`: Local variable assigned but never used
|
|
|
|
### B Series (Bugbear)
|
|
- `B002`: Using * in exception handling
|
|
- `B006`: Mutable default argument
|
|
- `B007`: Loop variable not used
|
|
- `B008`: Function calls in default arguments
|
|
- `B904`: Use `raise ... from ...` for exception chaining
|
|
|
|
### UP Series (PyUpgrade)
|
|
- `UP006`: Use `list` instead of `typing.List`
|
|
- `UP007`: Use `X | Y` instead of `typing.Union[X, Y]`
|
|
- `UP032`: Use f-strings instead of `.format()`
|
|
|
|
## Commands Reference
|
|
|
|
### Linting
|
|
|
|
```bash
|
|
# Check all files
|
|
ruff check .
|
|
|
|
# Check specific file
|
|
ruff check src/module.py
|
|
|
|
# Auto-fix issues
|
|
ruff check --fix .
|
|
|
|
# Show fixes without applying
|
|
ruff check --diff .
|
|
|
|
# Watch mode (re-run on file changes)
|
|
ruff check --watch .
|
|
|
|
# Output JSON format
|
|
ruff check --output-format=json .
|
|
```
|
|
|
|
### Formatting
|
|
|
|
```bash
|
|
# Format all files
|
|
ruff format .
|
|
|
|
# Format specific file
|
|
ruff format src/module.py
|
|
|
|
# Check if formatting needed (CI)
|
|
ruff format --check .
|
|
|
|
# Show diff without applying
|
|
ruff format --diff .
|
|
```
|
|
|
|
### Configuration Testing
|
|
|
|
```bash
|
|
# Show active configuration
|
|
ruff check --show-settings
|
|
|
|
# Show all available rules
|
|
ruff rule --all
|
|
|
|
# Show specific rule documentation
|
|
ruff rule F401
|
|
```
|
|
|
|
## Per-File Ignores
|
|
|
|
Ignore specific rules for specific files:
|
|
|
|
```toml
|
|
[tool.ruff.lint.per-file-ignores]
|
|
"tests/**/*.py" = ["ARG", "S101"] # Tests can use assert and unused args
|
|
"__init__.py" = ["F401"] # Unused imports OK in __init__
|
|
"scripts/**/*.py" = ["T201"] # print() OK in scripts
|
|
"migrations/**/*.py" = ["E501"] # Long lines OK in migrations
|
|
```
|
|
|
|
## VSCode Integration
|
|
|
|
Add to `.vscode/settings.json`:
|
|
|
|
```json
|
|
{
|
|
"[python]": {
|
|
"editor.defaultFormatter": "charliermarsh.ruff",
|
|
"editor.formatOnSave": true,
|
|
"editor.codeActionsOnSave": {
|
|
"source.organizeImports": "explicit",
|
|
"source.fixAll": "explicit"
|
|
}
|
|
},
|
|
"ruff.enable": true,
|
|
"ruff.lint.enable": true,
|
|
"ruff.format.enable": true
|
|
}
|
|
```
|
|
|
|
## Performance Tips
|
|
|
|
Ruff is extremely fast (10-100x faster than alternatives):
|
|
- Written in Rust for performance
|
|
- Parallel processing by default
|
|
- Incremental linting in watch mode
|
|
- Caching for repeated runs
|
|
|
|
## Migration from Other Tools
|
|
|
|
### From Black
|
|
Ruff's formatter is compatible with Black:
|
|
```bash
|
|
ruff format . # Replaces: black .
|
|
```
|
|
|
|
### From isort
|
|
```bash
|
|
ruff check --select I --fix . # Replaces: isort .
|
|
```
|
|
|
|
### From flake8
|
|
```bash
|
|
ruff check . # Replaces: flake8 .
|
|
```
|
|
|
|
### From pyupgrade
|
|
```bash
|
|
ruff check --select UP --fix . # Replaces: pyupgrade .
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
1. **Run formatter last**: `ruff check --fix . && ruff format .`
|
|
2. **Use in CI**: Check both linting and formatting
|
|
3. **Configure per-file ignores**: For tests, init files, migrations
|
|
4. **Enable auto-fix**: Most issues can be fixed automatically
|
|
5. **Use with pre-commit**: Run checks before commits
|
|
6. **Review rule changes**: Stay updated with new releases
|