mirror of
				https://github.com/astral-sh/ruff.git
				synced 2025-10-31 03:55:09 +00:00 
			
		
		
		
	 acf35c55f8
			
		
	
	
		acf35c55f8
		
			
		
	
	
	
	
		
			
			## Summary Adds @dylwil3's new `noqa` specification to the linter `Error suppression` page instead of the release blog post. Originally taken from his PR comment [here](https://github.com/astral-sh/ruff/pull/16483#issuecomment-2711985479). ## Test Plan None
		
			
				
	
	
		
			412 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			412 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| # The Ruff Linter
 | |
| 
 | |
| The Ruff Linter is an extremely fast Python linter designed as a drop-in replacement for [Flake8](https://pypi.org/project/flake8/)
 | |
| (plus dozens of plugins), [isort](https://pypi.org/project/isort/), [pydocstyle](https://pypi.org/project/pydocstyle/),
 | |
| [pyupgrade](https://pypi.org/project/pyupgrade/), [autoflake](https://pypi.org/project/autoflake/),
 | |
| and more.
 | |
| 
 | |
| ## `ruff check`
 | |
| 
 | |
| `ruff check` is the primary entrypoint to the Ruff linter. It accepts a list of files or
 | |
| directories, and lints all discovered Python files, optionally fixing any fixable errors.
 | |
| When linting a directory, Ruff searches for Python files recursively in that directory
 | |
| and all its subdirectories:
 | |
| 
 | |
| ```console
 | |
| $ ruff check                  # Lint files in the current directory.
 | |
| $ ruff check --fix            # Lint files in the current directory and fix any fixable errors.
 | |
| $ ruff check --watch          # Lint files in the current directory and re-lint on change.
 | |
| $ ruff check path/to/code/    # Lint files in `path/to/code`.
 | |
| ```
 | |
| 
 | |
| For the full list of supported options, run `ruff check --help`.
 | |
| 
 | |
| ## Rule selection
 | |
| 
 | |
| The set of enabled rules is controlled via the [`lint.select`](settings.md#lint_select),
 | |
| [`lint.extend-select`](settings.md#lint_extend-select), and [`lint.ignore`](settings.md#lint_ignore) settings.
 | |
| 
 | |
| Ruff's linter mirrors Flake8's rule code system, in which each rule code consists of a one-to-three
 | |
| letter prefix, followed by three digits (e.g., `F401`). The prefix indicates that "source" of the rule
 | |
| (e.g., `F` for Pyflakes, `E` for pycodestyle, `ANN` for flake8-annotations).
 | |
| 
 | |
| Rule selectors like [`lint.select`](settings.md#lint_select) and [`lint.ignore`](settings.md#lint_ignore) accept either
 | |
| a full rule code (e.g., `F401`) or any valid prefix (e.g., `F`). For example, given the following
 | |
| configuration file:
 | |
| 
 | |
| === "pyproject.toml"
 | |
| 
 | |
|     ```toml
 | |
|     [tool.ruff.lint]
 | |
|     select = ["E", "F"]
 | |
|     ignore = ["F401"]
 | |
|     ```
 | |
| 
 | |
| === "ruff.toml"
 | |
| 
 | |
|     ```toml
 | |
|     [lint]
 | |
|     select = ["E", "F"]
 | |
|     ignore = ["F401"]
 | |
|     ```
 | |
| 
 | |
| Ruff would enable all rules with the `E` (pycodestyle) or `F` (Pyflakes) prefix, with the exception
 | |
| of `F401`. For more on configuring Ruff via `pyproject.toml`, see [_Configuring Ruff_](configuration.md).
 | |
| 
 | |
| As a special-case, Ruff also supports the `ALL` code, which enables all rules. Note that some
 | |
| pydocstyle rules conflict (e.g., `D203` and `D211`) as they represent alternative docstring
 | |
| formats. Ruff will automatically disable any conflicting rules when `ALL` is enabled.
 | |
| 
 | |
| If you're wondering how to configure Ruff, here are some **recommended guidelines**:
 | |
| 
 | |
| - Prefer [`lint.select`](settings.md#lint_select) over [`lint.extend-select`](settings.md#lint_extend-select) to make your rule set explicit.
 | |
| - Use `ALL` with discretion. Enabling `ALL` will implicitly enable new rules whenever you upgrade.
 | |
| - Start with a small set of rules (`select = ["E", "F"]`) and add a category at-a-time. For example,
 | |
|     you might consider expanding to `select = ["E", "F", "B"]` to enable the popular flake8-bugbear
 | |
|     extension.
 | |
| 
 | |
| For example, a configuration that enables some of the most popular rules (without being too
 | |
| pedantic) might look like the following:
 | |
| 
 | |
| === "pyproject.toml"
 | |
| 
 | |
|     ```toml
 | |
|     [tool.ruff.lint]
 | |
|     select = [
 | |
|         # pycodestyle
 | |
|         "E",
 | |
|         # Pyflakes
 | |
|         "F",
 | |
|         # pyupgrade
 | |
|         "UP",
 | |
|         # flake8-bugbear
 | |
|         "B",
 | |
|         # flake8-simplify
 | |
|         "SIM",
 | |
|         # isort
 | |
|         "I",
 | |
|     ]
 | |
|     ```
 | |
| 
 | |
| === "ruff.toml"
 | |
| 
 | |
|     ```toml
 | |
|     [lint]
 | |
|     select = [
 | |
|         # pycodestyle
 | |
|         "E",
 | |
|         # Pyflakes
 | |
|         "F",
 | |
|         # pyupgrade
 | |
|         "UP",
 | |
|         # flake8-bugbear
 | |
|         "B",
 | |
|         # flake8-simplify
 | |
|         "SIM",
 | |
|         # isort
 | |
|         "I",
 | |
|     ]
 | |
|     ```
 | |
| 
 | |
| To resolve the enabled rule set, Ruff may need to reconcile [`lint.select`](settings.md#lint_select) and
 | |
| [`lint.ignore`](settings.md#lint_ignore) from a variety of sources, including the current `pyproject.toml`,
 | |
| any inherited `pyproject.toml` files, and the CLI (e.g., [`--select`](settings.md#lint_select)).
 | |
| 
 | |
| In those scenarios, Ruff uses the "highest-priority" [`select`](settings.md#lint_select) as the basis for
 | |
| the rule set, and then applies [`extend-select`](settings.md#lint_extend-select) and
 | |
| [`ignore`](settings.md#lint_ignore) adjustments. CLI options are given higher priority than
 | |
| `pyproject.toml` options, and the current `pyproject.toml` file is given higher priority than any
 | |
| inherited `pyproject.toml` files.
 | |
| 
 | |
| For example, given the following configuration file:
 | |
| 
 | |
| === "pyproject.toml"
 | |
| 
 | |
|     ```toml
 | |
|     [tool.ruff.lint]
 | |
|     select = ["E", "F"]
 | |
|     ignore = ["F401"]
 | |
|     ```
 | |
| 
 | |
| === "ruff.toml"
 | |
| 
 | |
|     ```toml
 | |
|     [lint]
 | |
|     select = ["E", "F"]
 | |
|     ignore = ["F401"]
 | |
|     ```
 | |
| 
 | |
| Running `ruff check --select F401` would result in Ruff enforcing `F401`, and no other rules.
 | |
| 
 | |
| Running `ruff check --extend-select B` would result in Ruff enforcing the `E`, `F`, and `B` rules,
 | |
| with the exception of `F401`.
 | |
| 
 | |
| ## Fixes
 | |
| 
 | |
| Ruff supports automatic fixes for a variety of lint errors. For example, Ruff can remove unused
 | |
| imports, reformat docstrings, rewrite type annotations to use newer Python syntax, and more.
 | |
| 
 | |
| To enable fixes, pass the `--fix` flag to `ruff check`:
 | |
| 
 | |
| ```console
 | |
| $ ruff check --fix
 | |
| ```
 | |
| 
 | |
| By default, Ruff will fix all violations for which safe fixes are available; to determine
 | |
| whether a rule supports fixing, see [_Rules_](rules.md).
 | |
| 
 | |
| ### Fix safety
 | |
| 
 | |
| Ruff labels fixes as "safe" and "unsafe". The meaning and intent of your code will be retained when
 | |
| applying safe fixes, but the meaning could change when applying unsafe fixes.
 | |
| 
 | |
| Specifically, an unsafe fix could lead to a change in runtime behavior, the removal of comments, or both,
 | |
| while safe fixes are intended to preserve runtime behavior and will only remove comments when deleting
 | |
| entire statements or expressions (e.g., removing unused imports).
 | |
| 
 | |
| For example, [`unnecessary-iterable-allocation-for-first-element`](rules/unnecessary-iterable-allocation-for-first-element.md)
 | |
| (`RUF015`) is a rule which checks for potentially unperformant use of `list(...)[0]`. The fix
 | |
| replaces this pattern with `next(iter(...))` which can result in a drastic speedup:
 | |
| 
 | |
| ```console
 | |
| $ python -m timeit "head = list(range(99999999))[0]"
 | |
| 1 loop, best of 5: 1.69 sec per loop
 | |
| ```
 | |
| 
 | |
| ```console
 | |
| $ python -m timeit "head = next(iter(range(99999999)))"
 | |
| 5000000 loops, best of 5: 70.8 nsec per loop
 | |
| ```
 | |
| 
 | |
| However, when the collection is empty, this raised exception changes from an `IndexError` to `StopIteration`:
 | |
| 
 | |
| ```console
 | |
| $ python -c 'list(range(0))[0]'
 | |
| Traceback (most recent call last):
 | |
|   File "<string>", line 1, in <module>
 | |
| IndexError: list index out of range
 | |
| ```
 | |
| 
 | |
| ```console
 | |
| $ python -c 'next(iter(range(0)))[0]'
 | |
| Traceback (most recent call last):
 | |
|   File "<string>", line 1, in <module>
 | |
| StopIteration
 | |
| ```
 | |
| 
 | |
| Since the change in exception type could break error handling upstream, this fix is categorized as unsafe.
 | |
| 
 | |
| Ruff only enables safe fixes by default. Unsafe fixes can be enabled by settings [`unsafe-fixes`](settings.md#unsafe-fixes) in your configuration file or passing the `--unsafe-fixes` flag to `ruff check`:
 | |
| 
 | |
| ```console
 | |
| # Show unsafe fixes
 | |
| ruff check --unsafe-fixes
 | |
| 
 | |
| # Apply unsafe fixes
 | |
| ruff check --fix --unsafe-fixes
 | |
| ```
 | |
| 
 | |
| By default, Ruff will display a hint when unsafe fixes are available but not enabled. The suggestion can be silenced
 | |
| by setting the [`unsafe-fixes`](settings.md#unsafe-fixes) setting to `false` or using the `--no-unsafe-fixes` flag.
 | |
| 
 | |
| The safety of fixes can be adjusted per rule using the [`lint.extend-safe-fixes`](settings.md#lint_extend-safe-fixes) and [`lint.extend-unsafe-fixes`](settings.md#lint_extend-unsafe-fixes) settings.
 | |
| 
 | |
| For example, the following configuration would promote unsafe fixes for `F601` to safe fixes and demote safe fixes for `UP034` to unsafe fixes:
 | |
| 
 | |
| === "pyproject.toml"
 | |
| 
 | |
|     ```toml
 | |
|     [tool.ruff.lint]
 | |
|     extend-safe-fixes = ["F601"]
 | |
|     extend-unsafe-fixes = ["UP034"]
 | |
|     ```
 | |
| 
 | |
| === "ruff.toml"
 | |
| 
 | |
|     ```toml
 | |
|     [lint]
 | |
|     extend-safe-fixes = ["F601"]
 | |
|     extend-unsafe-fixes = ["UP034"]
 | |
|     ```
 | |
| 
 | |
| You may use prefixes to select rules as well, e.g., `F` can be used to promote fixes for all rules in Pyflakes to safe.
 | |
| 
 | |
| !!! note
 | |
|     All fixes will always be displayed by Ruff when using the `json` output format. The safety of each fix is available under the `applicability` field.
 | |
| 
 | |
| ### Disabling fixes
 | |
| 
 | |
| To limit the set of rules that Ruff should fix, use the [`lint.fixable`](settings.md#lint_fixable)
 | |
| or [`lint.extend-fixable`](settings.md#lint_extend-fixable), and [`lint.unfixable`](settings.md#lint_unfixable) settings.
 | |
| 
 | |
| For example, the following configuration would enable fixes for all rules except
 | |
| [`unused-imports`](rules/unused-import.md) (`F401`):
 | |
| 
 | |
| === "pyproject.toml"
 | |
| 
 | |
|     ```toml
 | |
|     [tool.ruff.lint]
 | |
|     fixable = ["ALL"]
 | |
|     unfixable = ["F401"]
 | |
|     ```
 | |
| 
 | |
| === "ruff.toml"
 | |
| 
 | |
|     ```toml
 | |
|     [lint]
 | |
|     fixable = ["ALL"]
 | |
|     unfixable = ["F401"]
 | |
|     ```
 | |
| 
 | |
| Conversely, the following configuration would only enable fixes for `F401`:
 | |
| 
 | |
| === "pyproject.toml"
 | |
| 
 | |
|     ```toml
 | |
|     [tool.ruff.lint]
 | |
|     fixable = ["F401"]
 | |
|     ```
 | |
| 
 | |
| === "ruff.toml"
 | |
| 
 | |
|     ```toml
 | |
|     [lint]
 | |
|     fixable = ["F401"]
 | |
|     ```
 | |
| 
 | |
| ## Error suppression
 | |
| 
 | |
| Ruff supports several mechanisms for suppressing lint errors, be they false positives or
 | |
| permissible violations.
 | |
| 
 | |
| To omit a lint rule entirely, add it to the "ignore" list via the [`lint.ignore`](settings.md#lint_ignore)
 | |
| setting, either on the command-line or in your `pyproject.toml` or `ruff.toml` file.
 | |
| 
 | |
| To suppress a violation inline, Ruff uses a `noqa` system similar to [Flake8](https://flake8.pycqa.org/en/3.1.1/user/ignoring-errors.html).
 | |
| To ignore an individual violation, add `# noqa: {code}` to the end of the line, like so:
 | |
| 
 | |
| ```python
 | |
| # Ignore F841.
 | |
| x = 1  # noqa: F841
 | |
| 
 | |
| # Ignore E741 and F841.
 | |
| i = 1  # noqa: E741, F841
 | |
| 
 | |
| # Ignore _all_ violations.
 | |
| x = 1  # noqa
 | |
| ```
 | |
| 
 | |
| For multi-line strings (like docstrings), the `noqa` directive should come at the end of the string
 | |
| (after the closing triple quote), and will apply to the entire string, like so:
 | |
| 
 | |
| ```python
 | |
| """Lorem ipsum dolor sit amet.
 | |
| 
 | |
| Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor.
 | |
| """  # noqa: E501
 | |
| ```
 | |
| 
 | |
| For import sorting, the `noqa` should come at the end of the first line in the import block, and
 | |
| will apply to all imports in the block, like so:
 | |
| 
 | |
| ```python
 | |
| import os  # noqa: I001
 | |
| import abc
 | |
| ```
 | |
| 
 | |
| To ignore all violations across an entire file, add the line `# ruff: noqa` anywhere in the file,
 | |
| preferably towards the top, like so:
 | |
| 
 | |
| ```python
 | |
| # ruff: noqa
 | |
| ```
 | |
| 
 | |
| To ignore a specific rule across an entire file, add the line `# ruff: noqa: {code}` anywhere in the
 | |
| file, preferably towards the top, like so:
 | |
| 
 | |
| ```python
 | |
| # ruff: noqa: F841
 | |
| ```
 | |
| 
 | |
| Or see the [`lint.per-file-ignores`](settings.md#lint_per-file-ignores) setting, which enables the same
 | |
| functionality from within your `pyproject.toml` or `ruff.toml` file.
 | |
| 
 | |
| Global `noqa` comments must be on their own line to disambiguate from comments which ignore
 | |
| violations on a single line.
 | |
| 
 | |
| Note that Ruff will also respect Flake8's `# flake8: noqa` directive, and will treat it as
 | |
| equivalent to `# ruff: noqa`.
 | |
| 
 | |
| ### Full suppression comment specification
 | |
| 
 | |
| The full specification is as follows:
 | |
| 
 | |
| - An inline blanket `noqa` comment is given by a case-insensitive match for
 | |
|   `#noqa` with optional whitespace after the `#` symbol, followed by either: the
 | |
|   end of the comment, the beginning of a new comment (`#`), or whitespace
 | |
|   followed by any character other than `:`.
 | |
| - An inline rule suppression is given by first finding a case-insensitive match
 | |
|   for `#noqa` with optional whitespace after the `#` symbol, optional whitespace
 | |
|   after `noqa`, and followed by the symbol `:`. After this we are expected to
 | |
|   have a list of rule codes which is given by sequences of uppercase ASCII
 | |
|   characters followed by ASCII digits, separated by whitespace or commas. The
 | |
|   list ends at the last valid code. We will attempt to interpret rules with a
 | |
|   missing delimiter (e.g. `F401F841`), though a warning will be emitted in this
 | |
|   case.
 | |
| - A file-level exemption comment is given by a case-sensitive match for `#ruff:`
 | |
|   or `#flake8:`, with optional whitespace after `#` and before `:`, followed by
 | |
|   optional whitespace and a case-insensitive match for `noqa`. After this, the
 | |
|   specification is as in the inline case.
 | |
| 
 | |
| ### Detecting unused suppression comments
 | |
| 
 | |
| Ruff implements a special rule, [`unused-noqa`](https://docs.astral.sh/ruff/rules/unused-noqa/),
 | |
| under the `RUF100` code, to enforce that your `noqa` directives are "valid", in that the violations
 | |
| they _say_ they ignore are actually being triggered on that line (and thus suppressed). To flag
 | |
| unused `noqa` directives, run: `ruff check /path/to/file.py --extend-select RUF100`.
 | |
| 
 | |
| Ruff can also _remove_ any unused `noqa` directives via its fix functionality. To remove any
 | |
| unused `noqa` directives, run: `ruff check /path/to/file.py --extend-select RUF100 --fix`.
 | |
| 
 | |
| ### Inserting necessary suppression comments
 | |
| 
 | |
| Ruff can _automatically add_ `noqa` directives to all lines that contain violations, which is
 | |
| useful when migrating a new codebase to Ruff. To automatically add `noqa` directives to all
 | |
| relevant lines (with the appropriate rule codes), run: `ruff check /path/to/file.py --add-noqa`.
 | |
| 
 | |
| ### Action comments
 | |
| 
 | |
| Ruff respects isort's [action comments](https://pycqa.github.io/isort/docs/configuration/action_comments.html)
 | |
| (`# isort: skip_file`, `# isort: on`, `# isort: off`, `# isort: skip`, and `# isort: split`), which
 | |
| enable selectively enabling and disabling import sorting for blocks of code and other inline
 | |
| configuration.
 | |
| 
 | |
| Ruff will also respect variants of these action comments with a `# ruff:` prefix
 | |
| (e.g., `# ruff: isort: skip_file`, `# ruff: isort: on`, and so on). These variants more clearly
 | |
| convey that the action comment is intended for Ruff, but are functionally equivalent to the
 | |
| isort variants.
 | |
| 
 | |
| Unlike isort, Ruff does not respect action comments within docstrings.
 | |
| 
 | |
| See the [isort documentation](https://pycqa.github.io/isort/docs/configuration/action_comments.html)
 | |
| for more.
 | |
| 
 | |
| ## Exit codes
 | |
| 
 | |
| By default, `ruff check` exits with the following status codes:
 | |
| 
 | |
| - `0` if no violations were found, or if all present violations were fixed automatically.
 | |
| - `1` if violations were found.
 | |
| - `2` if Ruff terminates abnormally due to invalid configuration, invalid CLI options, or an
 | |
|     internal error.
 | |
| 
 | |
| This convention mirrors that of tools like ESLint, Prettier, and RuboCop.
 | |
| 
 | |
| `ruff check` supports two command-line flags that alter its exit code behavior:
 | |
| 
 | |
| - `--exit-zero` will cause Ruff to exit with a status code of `0` even if violations were found.
 | |
|     Note that Ruff will still exit with a status code of `2` if it terminates abnormally.
 | |
| - `--exit-non-zero-on-fix` will cause Ruff to exit with a status code of `1` if violations were
 | |
|     found, _even if_ all such violations were fixed automatically. Note that the use of
 | |
|     `--exit-non-zero-on-fix` can result in a non-zero exit code even if no violations remain after
 | |
|     fixing.
 |