From open-python-skills
Python linting with Ruff - an extremely fast linter written in Rust. Use when: (1) Standardizing code quality, (2) Fixing style warnings, (3) Enforcing rules in CI, (4) Replacing flake8/isort/pyupgrade/autoflake, (5) Configuring lint rules and suppressions.
npx claudepluginhub jiatastic/open-python-skills --plugin open-python-skillsThis skill uses the workspace's default tool permissions.
Ruff is an extremely fast Python linter designed as a drop-in replacement for Flake8 (plus dozens of plugins), isort, pydocstyle, pyupgrade, autoflake, and more. Written in Rust, it offers 10-100x performance improvements over traditional Python linters.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Checks Next.js compilation errors using a running Turbopack dev server after code edits. Fixes actionable issues before reporting complete. Replaces `next build`.
Ruff is an extremely fast Python linter designed as a drop-in replacement for Flake8 (plus dozens of plugins), isort, pydocstyle, pyupgrade, autoflake, and more. Written in Rust, it offers 10-100x performance improvements over traditional Python linters.
Ruff provides a single CLI for linting with optional auto-fix. It supports an extensive rule set with 800+ built-in rules and integrates cleanly with pre-commit, CI systems, and modern editors.
# Install Ruff
uv pip install ruff
# or
pip install ruff
# Run linting on current directory
ruff check .
# Run linting with auto-fix
ruff check . --fix
# Watch mode for development
ruff check --watch
E and F rules first, then gradually expandruff check --fix for safe fixes onlyruff check --output-format github for GitHub Actionspyproject.toml or ruff.tomlRuff uses a code system where each rule consists of a 1-3 letter prefix followed by digits (e.g., F401). Rules are controlled via lint.select, lint.extend-select, and lint.ignore.
Minimal (Start Here):
[tool.ruff.lint]
select = ["E", "F"] # pycodestyle errors + Pyflakes
Balanced (Recommended):
[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"F", # Pyflakes
"UP", # pyupgrade
"B", # flake8-bugbear
"SIM", # flake8-simplify
"I", # isort
]
Comprehensive:
[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # Pyflakes
"UP", # pyupgrade
"B", # flake8-bugbear
"SIM", # flake8-simplify
"I", # isort
"N", # pep8-naming
"S", # flake8-bandit (security)
"C4", # flake8-comprehensions
"DTZ", # flake8-datetimez
"T20", # flake8-print
"RUF", # Ruff-specific rules
]
ignore = ["E501"] # Line too long (handled by formatter)
CLI options override pyproject.toml, which overrides inherited configs:
--select, --ignore) - highest prioritypyproject.tomlpyproject.toml filesFor detailed rule configuration, see references/rule_selection.md.
[tool.ruff]
line-length = 88
target-version = "py311"
exclude = [".venv", "dist", "build", "*.pyi"]
[tool.ruff.lint]
select = ["E", "F", "UP", "B", "SIM", "I"]
ignore = ["E501"]
fixable = ["ALL"]
unfixable = []
[tool.ruff.lint.per-file-ignores]
"tests/**/*.py" = ["S101"] # Allow assert in tests
"__init__.py" = ["F401"] # Allow unused imports
"**/{tests,docs,tools}/*" = ["E402"] # Allow late imports
[tool.ruff.lint.isort]
known-first-party = ["myproject"]
[tool.ruff.lint.pydocstyle]
convention = "google"
line-length = 88
target-version = "py311"
[lint]
select = ["E", "F", "UP", "B", "SIM", "I"]
ignore = ["E501"]
[lint.per-file-ignores]
"tests/**/*.py" = ["S101"]
Ruff categorizes fixes as safe or unsafe:
| Type | Behavior | Default |
|---|---|---|
| Safe | Preserves code semantics | Enabled |
| Unsafe | May change runtime behavior | Disabled |
# Apply only safe fixes (default)
ruff check --fix
# Apply all fixes including unsafe
ruff check --fix --unsafe-fixes
# Show what unsafe fixes are available
ruff check --unsafe-fixes
[tool.ruff.lint]
# Promote unsafe fixes to safe
extend-safe-fixes = ["F601"]
# Demote safe fixes to unsafe
extend-unsafe-fixes = ["UP034"]
# Control which rules can be fixed
fixable = ["ALL"]
unfixable = ["F401"] # Never auto-fix unused imports
For detailed fix safety documentation, see references/fix_safety.md.
x = 1 # noqa: F841 # Ignore specific rule
i = 1 # noqa: E741, F841 # Ignore multiple rules
x = 1 # noqa # Ignore all rules (avoid this)
# ruff: noqa # Ignore all rules in file
# ruff: noqa: F841 # Ignore specific rule in file
# ruff: disable[E501]
VALUE_1 = "Very long string..."
VALUE_2 = "Another long string..."
# ruff: enable[E501]
For detailed suppression patterns, see references/error_suppression.md.
# Basic linting
ruff check . # Lint current directory
ruff check path/to/file.py # Lint specific file
ruff check . --fix # Lint and auto-fix
ruff check . --fix --unsafe-fixes # Include unsafe fixes
# Output formats
ruff check . --output-format text # Default human-readable
ruff check . --output-format github # GitHub Actions annotations
ruff check . --output-format json # JSON output
ruff check . --output-format sarif # SARIF format
# Inspection
ruff check . --diff # Show what would change
ruff check . --show-fixes # Show available fixes
ruff check . --statistics # Show rule statistics
ruff rule F401 # Explain a specific rule
# Development
ruff check --watch # Watch mode
ruff check . --add-noqa # Add noqa comments
ruff check . --extend-select RUF100 # Find unused noqa comments
| Code | Meaning |
|---|---|
| 0 | No violations found, or all fixed |
| 1 | Violations found |
| 2 | Configuration error or internal error |
Modify exit behavior:
ruff check . --exit-zero # Always exit 0
ruff check . --exit-non-zero-on-fix # Exit 1 if any violations (even if fixed)
name: Lint
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/ruff-action@v3
with:
args: "check --output-format github"
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.8.0
hooks:
- id: ruff
args: [--fix]
- id: ruff-format
| Issue | Solution |
|---|---|
| Rule conflicts with formatter | Ignore formatting rules (E501) when using ruff format |
| Too many violations | Start with minimal rules (E, F), expand gradually |
| Too many per-file ignores | Review rule selection, consider disabling noisy rules |
| Slow on large codebase | Ensure .venv excluded, check for recursive symlinks |
| noqa not working | Check syntax: # noqa: F401 (colon required) |
| Prefix | Source | Description |
|---|---|---|
| E/W | pycodestyle | Style errors/warnings |
| F | Pyflakes | Logical errors |
| B | flake8-bugbear | Common bugs |
| I | isort | Import sorting |
| UP | pyupgrade | Python version upgrades |
| SIM | flake8-simplify | Code simplification |
| N | pep8-naming | Naming conventions |
| S | flake8-bandit | Security issues |
| C4 | flake8-comprehensions | Comprehension style |
| RUF | Ruff | Ruff-specific rules |