This document explains how python-mode configuration options map to Ruff settings, and how to migrate from the old linting tools to Ruff.
Python-mode now uses Ruff for linting and formatting, replacing:
- pyflakes - Syntax errors and undefined names
- pycodestyle - PEP 8 style guide enforcement
- mccabe - Cyclomatic complexity checking
- pylint - Comprehensive static analysis
- pydocstyle - Docstring style checking
- pylama - Multi-tool linting wrapper
- autopep8 - Automatic PEP 8 formatting
These options are maintained for backward compatibility and are automatically converted to Ruff rules:
Default: ['pyflakes', 'pycodestyle', 'mccabe']
Maps to Ruff rule categories:
'pyflakes'→ RuffFrules (pyflakes)'pycodestyle'→ RuffEandWrules (pycodestyle)'mccabe'→ RuffC90rule (mccabe complexity)'pylint'→ RuffPLrules (pylint)'pydocstyle'→ RuffDrules (pydocstyle)
Example:
let g:pymode_lint_checkers = ['pyflakes', 'pycodestyle']
" This enables Ruff rules: F (pyflakes), E (pycodestyle errors), W (pycodestyle warnings)Default: []
Maps to Ruff --ignore patterns. Supports both legacy error codes (E501, W503) and Ruff rule codes.
Example:
let g:pymode_lint_ignore = ['E501', 'W503', 'F401']
" Ruff will ignore: E501 (line too long), W503 (line break before binary operator), F401 (unused import)Default: []
Maps to Ruff --select patterns. Selects specific rules to enable.
Example:
let g:pymode_lint_select = ['E', 'F']
" Ruff will only check E (pycodestyle errors) and F (pyflakes) rulesThese options provide direct control over Ruff behavior:
Default: 1
Enable or disable Ruff linting entirely.
Example:
let g:pymode_ruff_enabled = 1 " Enable Ruff (default)
let g:pymode_ruff_enabled = 0 " Disable RuffDefault: 1
Enable or disable Ruff formatting (replaces autopep8).
Example:
let g:pymode_ruff_format_enabled = 1 " Enable Ruff formatting (default)
let g:pymode_ruff_format_enabled = 0 " Disable Ruff formattingDefault: []
Ruff-specific select rules. If set, overrides g:pymode_lint_select.
Example:
let g:pymode_ruff_select = ['E', 'F', 'W', 'C90']
" Enable pycodestyle errors, pyflakes, pycodestyle warnings, and mccabe complexityDefault: []
Ruff-specific ignore patterns. If set, overrides g:pymode_lint_ignore.
Example:
let g:pymode_ruff_ignore = ['E501', 'F401']
" Ignore line too long and unused import warningsDefault: ""
Path to Ruff configuration file (pyproject.toml, ruff.toml, etc.). If empty, Ruff will search for configuration files automatically.
Example:
let g:pymode_ruff_config_file = '/path/to/pyproject.toml'
" Use specific Ruff configuration fileDefault: "local_override"
Controls how Ruff configuration is resolved. This option determines whether local project configuration files (ruff.toml, pyproject.toml) or python-mode settings take precedence.
Modes:
"local": Use only the project's local Ruff config. Python-mode settings are ignored. Ruff will auto-discover configuration files in the project hierarchy."local_override": Local config takes priority. If a local Ruff config file exists, it will be used. If no local config exists, python-mode settings serve as fallback."global": Use only python-mode settings. Local config files are ignored (uses--isolatedflag). This restores the previous behavior where python-mode settings always override local configs.
Example:
" Respect project's local Ruff config (recommended for team projects)
let g:pymode_ruff_config_mode = "local"
" Use local config if available, otherwise use pymode defaults (default)
let g:pymode_ruff_config_mode = "local_override"
" Always use pymode settings, ignore project configs
let g:pymode_ruff_config_mode = "global"Note: The default "local_override" mode provides the best user experience by respecting project-specific configurations while providing sensible defaults when no local config exists.
Before (using legacy tools):
let g:pymode_lint_checkers = ['pyflakes', 'pycodestyle']
let g:pymode_lint_ignore = ['E501', 'W503']After (using Ruff - backward compatible):
" Same configuration works automatically!
let g:pymode_lint_checkers = ['pyflakes', 'pycodestyle']
let g:pymode_lint_ignore = ['E501', 'W503']After (using Ruff-specific options):
let g:pymode_ruff_select = ['F', 'E', 'W'] " pyflakes, pycodestyle errors/warnings
let g:pymode_ruff_ignore = ['E501', 'W503']Before:
let g:pymode_lint_checkers = ['pyflakes', 'pycodestyle', 'mccabe', 'pylint']
let g:pymode_lint_options_mccabe = {'complexity': 10}
let g:pymode_lint_options_pycodestyle = {'max_line_length': 88}After:
" Option 1: Use legacy options (still works)
let g:pymode_lint_checkers = ['pyflakes', 'pycodestyle', 'mccabe', 'pylint']
let g:pymode_lint_options_mccabe = {'complexity': 10}
let g:pymode_lint_options_pycodestyle = {'max_line_length': 88}
" Option 2: Use Ruff-specific options + config file
let g:pymode_ruff_select = ['F', 'E', 'W', 'C90', 'PL']
let g:pymode_ruff_config_file = 'pyproject.toml'
" In pyproject.toml:
" [tool.ruff]
" line-length = 88
" [tool.ruff.mccabe]
" max-complexity = 10Before:
" No direct way to disable autopep8After:
let g:pymode_ruff_format_enabled = 0 " Disable Ruff formatting- E - Errors (syntax, indentation, etc.)
- W - Warnings (whitespace, line breaks, etc.)
- Common codes:
E501(line too long),E302(expected blank lines),W503(line break before binary operator)
- F - Pyflakes errors
- Common codes:
F401(unused import),F811(redefined while unused),F841(unused variable)
- C90 - Cyclomatic complexity
- Configured via
g:pymode_lint_options_mccabeor Ruff config file
- PL - Pylint rules
- Common codes:
PLR0913(too many arguments),PLR2004(magic value)
- D - Docstring style rules
- Common codes:
D100(missing docstring),D400(first line should end with period)
Ruff supports configuration via pyproject.toml or ruff.toml files. Python-mode will automatically use these if found, or you can specify a path with g:pymode_ruff_config_file.
Example pyproject.toml:
[tool.ruff]
line-length = 88
select = ["E", "F", "W", "C90"]
ignore = ["E501"]
[tool.ruff.mccabe]
max-complexity = 10All legacy configuration options continue to work. The migration is transparent - your existing configuration will automatically use Ruff under the hood.
If you see "Ruff is not available", install it:
pip install ruffVerify installation:
./scripts/verify_ruff_installation.sh- Check that
g:pymode_ruff_enabled = 1(default) - Verify Ruff is installed:
ruff --version - Check configuration file path if using
g:pymode_ruff_config_file - Review Ruff output:
:PymodeLintand check for errors
Ruff is significantly faster than the old tools. If you experience slowdowns:
- Check if Ruff config file is being read correctly
- Verify Ruff version:
ruff --version(should be recent) - Check for large ignore/select lists that might slow down rule processing