Compare commits
206 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c21a5912b9 | ||
|
|
48a5cd1dd9 | ||
|
|
63f3d5e610 | ||
|
|
7dab4807d0 | ||
|
|
83f6e52c92 | ||
|
|
5ce7ce5bc3 | ||
|
|
749d197119 | ||
|
|
46c184600f | ||
|
|
e2051ef72f | ||
|
|
1abaece9ed | ||
|
|
8b35b052b8 | ||
|
|
5a34504149 | ||
|
|
0e53ddc2b3 | ||
|
|
1f07ad6e61 | ||
|
|
1666e8ba1e | ||
|
|
c399b3e6c1 | ||
|
|
9089ef74bc | ||
|
|
28c9263722 | ||
|
|
fc4c927788 | ||
|
|
26f39cac2f | ||
|
|
02897a141b | ||
|
|
fc465cc2af | ||
|
|
ca8a122889 | ||
|
|
6769a5bce7 | ||
|
|
fda93c6245 | ||
|
|
099d5414f2 | ||
|
|
9ddd5e4cfe | ||
|
|
b8835c2e35 | ||
|
|
1d4422f004 | ||
|
|
2dccb7611a | ||
|
|
f8ac6d7bf0 | ||
|
|
0123425be1 | ||
|
|
c53f91d943 | ||
|
|
4a12ebb9b1 | ||
|
|
0e4d5eeea7 | ||
|
|
bbe44360e8 | ||
|
|
37e80d98ab | ||
|
|
306393063d | ||
|
|
f5a3c90288 | ||
|
|
8289ede00f | ||
|
|
77e65c9ff5 | ||
|
|
d827a9156e | ||
|
|
418808895e | ||
|
|
ac4e212ed2 | ||
|
|
551b810aeb | ||
|
|
1b61d4e18b | ||
|
|
752c0150e1 | ||
|
|
81651a8479 | ||
|
|
86d0749ed7 | ||
|
|
19fc410683 | ||
|
|
5a70a573cd | ||
|
|
74731a3456 | ||
|
|
863e39fe5f | ||
|
|
d0f9ee33ec | ||
|
|
1cf3d880a7 | ||
|
|
97dcb738fa | ||
|
|
ffb4e89a98 | ||
|
|
43b7ee215c | ||
|
|
77099dcd4d | ||
|
|
70ff65154d | ||
|
|
7db6a2d6d4 | ||
|
|
42924c0d9a | ||
|
|
31d00936ee | ||
|
|
c3c5d9a852 | ||
|
|
7e5c19385c | ||
|
|
5b54325c81 | ||
|
|
e6538a7969 | ||
|
|
24faabf1f4 | ||
|
|
9b0a160239 | ||
|
|
9fd29e2c54 | ||
|
|
e83ed0ecba | ||
|
|
dadbfea497 | ||
|
|
9f84c497f9 | ||
|
|
0ec25d1514 | ||
|
|
6a87c99004 | ||
|
|
c8f60c9588 | ||
|
|
113610a8d4 | ||
|
|
6376e5915e | ||
|
|
3d8fb5be20 | ||
|
|
0040991778 | ||
|
|
acb70520f8 | ||
|
|
6eb9268675 | ||
|
|
e5f5142e3e | ||
|
|
98d5ffb817 | ||
|
|
3f20f73413 | ||
|
|
a5e42d2f7c | ||
|
|
0bc1f68111 | ||
|
|
d2b09d77c5 | ||
|
|
0377834f9f | ||
|
|
3d650f9dd6 | ||
|
|
a72590ecde | ||
|
|
812b227334 | ||
|
|
6f58717ba4 | ||
|
|
8aab96fb9e | ||
|
|
9e6f7153a9 | ||
|
|
cda2ff0b18 | ||
|
|
ec63658250 | ||
|
|
1a97de0b01 | ||
|
|
1cbe48522e | ||
|
|
bfbde537af | ||
|
|
cba91b758b | ||
|
|
0bab642f5a | ||
|
|
bd09a1819f | ||
|
|
682d206992 | ||
|
|
c32441e4ab | ||
|
|
6f16f1c39b | ||
|
|
9011456aa1 | ||
|
|
fa191cceeb | ||
|
|
ac6c3affdd | ||
|
|
9a018c1650 | ||
|
|
0aef5c67a3 | ||
|
|
a048594416 | ||
|
|
5437f1299b | ||
|
|
41c0608a69 | ||
|
|
eb0d42187f | ||
|
|
48daa0f0ca | ||
|
|
417fe4355f | ||
|
|
a129181407 | ||
|
|
fc628de667 | ||
|
|
9e2418097c | ||
|
|
d4e5639aaf | ||
|
|
67e58a024a | ||
|
|
233be0e074 | ||
|
|
7750087f56 | ||
|
|
7d5fb0de8a | ||
|
|
8a98cfc4b8 | ||
|
|
54d1719424 | ||
|
|
0f622f0126 | ||
|
|
739a92e99d | ||
|
|
5a07c9f57c | ||
|
|
31027497c6 | ||
|
|
dabfdf718e | ||
|
|
5829bae976 | ||
|
|
ff3665a24b | ||
|
|
125615af12 | ||
|
|
6339f8e009 | ||
|
|
81abc5d7d8 | ||
|
|
75fad989f4 | ||
|
|
cb4a221905 | ||
|
|
286d8c18dd | ||
|
|
124461bddf | ||
|
|
7482a4a5b8 | ||
|
|
9f9f25ff7c | ||
|
|
9cd1bf9c03 | ||
|
|
3862dc2626 | ||
|
|
2a0927a5ef | ||
|
|
824c0d2680 | ||
|
|
f5efdd058e | ||
|
|
4c35feaa18 | ||
|
|
8261d0656e | ||
|
|
a9aa96b24f | ||
|
|
367f115d83 | ||
|
|
56398e0002 | ||
|
|
4b49fd9494 | ||
|
|
271e4fda8c | ||
|
|
f1cdd108e6 | ||
|
|
8fd29b3b60 | ||
|
|
e427171323 | ||
|
|
be08384fb0 | ||
|
|
2f7f4943e3 | ||
|
|
67e9ff7cc8 | ||
|
|
0355ba571e | ||
|
|
38db7fd114 | ||
|
|
8ee51eb5c6 | ||
|
|
2bc16eb4e3 | ||
|
|
4e36225145 | ||
|
|
850069d0aa | ||
|
|
9fa98ed90b | ||
|
|
2b4ce78830 | ||
|
|
7647cafe12 | ||
|
|
7686179318 | ||
|
|
bf718fdf26 | ||
|
|
3b3466f6da | ||
|
|
f981f491aa | ||
|
|
95fef43c4d | ||
|
|
097c679cf3 | ||
|
|
3bca987665 | ||
|
|
60ee1d2c17 | ||
|
|
2dd04dd6a3 | ||
|
|
e59b75d31b | ||
|
|
610f150dd1 | ||
|
|
cee0d0abaa | ||
|
|
12ed1837ee | ||
|
|
6272293180 | ||
|
|
f8b8b05b80 | ||
|
|
79776c12e2 | ||
|
|
7fa5ce8b63 | ||
|
|
f6864a96f6 | ||
|
|
291ef9856a | ||
|
|
87d0aa5561 | ||
|
|
ecc9f5de99 | ||
|
|
f40b974206 | ||
|
|
cd8be8c0be | ||
|
|
e3dfa2e04e | ||
|
|
f03c8fff14 | ||
|
|
452b5a4b79 | ||
|
|
1e1dc3a7ed | ||
|
|
84be1df9d5 | ||
|
|
6b3ae1a8e1 | ||
|
|
5275f6c90e | ||
|
|
6683ed49bc | ||
|
|
ced55084db | ||
|
|
f8f36a7ee0 | ||
|
|
4190031618 | ||
|
|
5a9258327b | ||
|
|
dd0145624b |
18
.github/workflows/ci.yaml
vendored
18
.github/workflows/ci.yaml
vendored
@@ -40,9 +40,20 @@ jobs:
|
||||
run: rustup component add rustfmt
|
||||
- run: cargo fmt --all --check
|
||||
|
||||
cargo_clippy:
|
||||
cargo-clippy:
|
||||
name: "cargo clippy"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: "Install Rust toolchain"
|
||||
run: |
|
||||
rustup component add clippy
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- run: cargo clippy --workspace --all-targets --all-features -- -D warnings
|
||||
|
||||
cargo-clippy-wasm:
|
||||
name: "cargo clippy (wasm)"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: "Install Rust toolchain"
|
||||
@@ -50,7 +61,6 @@ jobs:
|
||||
rustup component add clippy
|
||||
rustup target add wasm32-unknown-unknown
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- run: cargo clippy --workspace --all-targets --all-features -- -D warnings
|
||||
- run: cargo clippy -p ruff --target wasm32-unknown-unknown --all-features -- -D warnings
|
||||
|
||||
cargo-test:
|
||||
@@ -69,13 +79,13 @@ jobs:
|
||||
- name: "Run tests (Ubuntu)"
|
||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||
run: |
|
||||
cargo insta test --all --delete-unreferenced-snapshots
|
||||
cargo insta test --all --all-features --delete-unreferenced-snapshots
|
||||
git diff --exit-code
|
||||
- name: "Run tests (Windows)"
|
||||
if: ${{ matrix.os == 'windows-latest' }}
|
||||
shell: bash
|
||||
run: |
|
||||
cargo insta test --all
|
||||
cargo insta test --all --all-features
|
||||
git diff --exit-code
|
||||
- run: cargo test --package ruff_cli --test black_compatibility_test -- --ignored
|
||||
# Check for broken links in the documentation.
|
||||
|
||||
10
.github/workflows/docs.yaml
vendored
10
.github/workflows/docs.yaml
vendored
@@ -1,12 +1,8 @@
|
||||
name: mkdocs
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- README.md
|
||||
- mkdocs.template.yml
|
||||
- .github/workflows/docs.yaml
|
||||
branches: [main]
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
@@ -19,7 +15,7 @@ jobs:
|
||||
- uses: actions/setup-python@v4
|
||||
- name: "Install dependencies"
|
||||
run: |
|
||||
pip install "mkdocs~=1.4.2" "mkdocs-material~=9.0.6"
|
||||
pip install -r docs/requirements.txt
|
||||
- name: "Copy README File"
|
||||
run: |
|
||||
python scripts/transform_readme.py --target mkdocs
|
||||
|
||||
2
.github/workflows/playground.yaml
vendored
2
.github/workflows/playground.yaml
vendored
@@ -28,7 +28,7 @@ jobs:
|
||||
- uses: jetli/wasm-pack-action@v0.4.0
|
||||
- uses: jetli/wasm-bindgen-action@v0.2.0
|
||||
- name: "Run wasm-pack"
|
||||
run: wasm-pack build --target web --out-dir playground/src/pkg . -- -p ruff
|
||||
run: wasm-pack build --target web --out-dir ../../playground/src/pkg crates/ruff
|
||||
- name: "Install Node dependencies"
|
||||
run: npm ci
|
||||
working-directory: playground
|
||||
|
||||
5
.github/workflows/ruff.yaml
vendored
5
.github/workflows/ruff.yaml
vendored
@@ -2,8 +2,9 @@ name: "[ruff] Release"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [published]
|
||||
push:
|
||||
tags:
|
||||
- '**'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -1,7 +1,10 @@
|
||||
# Local cache
|
||||
.ruff_cache
|
||||
resources/test/cpython
|
||||
docs/
|
||||
crates/ruff/resources/test/cpython
|
||||
docs/*
|
||||
!docs/rules
|
||||
!docs/assets
|
||||
!docs/requirements.txt
|
||||
mkdocs.yml
|
||||
.overrides
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ repos:
|
||||
language: rust
|
||||
types_or: [python, pyi]
|
||||
require_serial: true
|
||||
exclude: ^resources
|
||||
exclude: ^crates/ruff/resources
|
||||
- id: dev-generate-all
|
||||
name: dev-generate-all
|
||||
entry: cargo dev generate-all
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
# Breaking Changes
|
||||
|
||||
## 0.0.246
|
||||
|
||||
### `multiple-statements-on-one-line-def` (`E704`) was removed ([#2773](https://github.com/charliermarsh/ruff/pull/2773))
|
||||
|
||||
This rule was introduced in v0.0.245. However, it turns out that pycodestyle and Flake8 ignore this
|
||||
rule by default, as it is not part of PEP 8. As such, we've removed it from Ruff.
|
||||
|
||||
## 0.0.245
|
||||
|
||||
### Ruff's public `check` method was removed ([#2709](https://github.com/charliermarsh/ruff/pull/2709))
|
||||
|
||||
Previously, Ruff exposed a `check` method as a public Rust API. This method was used by few,
|
||||
if any clients, and was not well documented or supported. As such, it has been removed, with
|
||||
the intention of adding a stable public API in the future.
|
||||
|
||||
## 0.0.238
|
||||
|
||||
### `select`, `extend-select`, `ignore`, and `extend-ignore` have new semantics ([#2312](https://github.com/charliermarsh/ruff/pull/2312))
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
- [Our Pledge](#our-pledge)
|
||||
- [Our Standards](#our-standards)
|
||||
- [Enforcement Responsibilities](#enforcement-responsibilities)
|
||||
- [Scope](#scope)
|
||||
- [Enforcement](#enforcement)
|
||||
- [Enforcement Guidelines](#enforcement-guidelines)
|
||||
- [1. Correction](#1-correction)
|
||||
- [2. Warning](#2-warning)
|
||||
- [3. Temporary Ban](#3-temporary-ban)
|
||||
- [4. Permanent Ban](#4-permanent-ban)
|
||||
- [Attribution](#attribution)
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
|
||||
171
CONTRIBUTING.md
171
CONTRIBUTING.md
@@ -2,7 +2,18 @@
|
||||
|
||||
Welcome! We're happy to have you here. Thank you in advance for your contribution to Ruff.
|
||||
|
||||
## The basics
|
||||
- [The Basics](#the-basics)
|
||||
- [Prerequisites](#prerequisites)
|
||||
- [Development](#development)
|
||||
- [Project Structure](#project-structure)
|
||||
- [Example: Adding a new lint rule](#example-adding-a-new-lint-rule)
|
||||
- [Rule naming convention](#rule-naming-convention)
|
||||
- [Example: Adding a new configuration option](#example-adding-a-new-configuration-option)
|
||||
- [MkDocs](#mkdocs)
|
||||
- [Release Process](#release-process)
|
||||
- [Benchmarks](#benchmarks)
|
||||
|
||||
## The Basics
|
||||
|
||||
Ruff welcomes contributions in the form of Pull Requests.
|
||||
|
||||
@@ -10,7 +21,7 @@ For small changes (e.g., bug fixes), feel free to submit a PR.
|
||||
|
||||
For larger changes (e.g., new lint rules, new functionality, new configuration options), consider
|
||||
creating an [**issue**](https://github.com/charliermarsh/ruff/issues) outlining your proposed
|
||||
change. You can also join us on [**Discord**](https://discord.gg/Z8KbeK24) to discuss your idea with
|
||||
change. You can also join us on [**Discord**](https://discord.gg/c9MhzV8aU5) to discuss your idea with
|
||||
the community.
|
||||
|
||||
If you're looking for a place to start, we recommend implementing a new lint rule (see:
|
||||
@@ -20,8 +31,10 @@ existing Python plugins, which can be used as a reference implementation.
|
||||
|
||||
As a concrete example: consider taking on one of the rules from the [`tryceratops`](https://github.com/charliermarsh/ruff/issues/2056)
|
||||
plugin, and looking to the originating [Python source](https://github.com/guilatrova/tryceratops)
|
||||
for guidance. [`flake8-simplify`](https://github.com/charliermarsh/ruff/issues/998) has a few rules
|
||||
left too.
|
||||
for guidance.
|
||||
|
||||
Alternatively, we've started work on the [`flake8-pyi`](https://github.com/charliermarsh/ruff/issues/848)
|
||||
plugin (see the [Python source](https://github.com/PyCQA/flake8-pyi)) -- another good place to start.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
@@ -39,16 +52,16 @@ cargo install cargo-insta
|
||||
After cloning the repository, run Ruff locally with:
|
||||
|
||||
```shell
|
||||
cargo run resources/test/fixtures --no-cache
|
||||
cargo run check /path/to/file.py --no-cache
|
||||
```
|
||||
|
||||
Prior to opening a pull request, ensure that your code has been auto-formatted,
|
||||
and that it passes both the lint and test validation checks:
|
||||
|
||||
```shell
|
||||
cargo fmt --all # Auto-formatting...
|
||||
cargo fmt --all # Auto-formatting...
|
||||
cargo clippy --fix --workspace --all-targets --all-features # Linting...
|
||||
cargo test --all # Testing...
|
||||
cargo test --all # Testing...
|
||||
```
|
||||
|
||||
These checks will run on GitHub Actions when you open your Pull Request, but running them locally
|
||||
@@ -71,58 +84,88 @@ pre-commit run --all-files
|
||||
Your Pull Request will be reviewed by a maintainer, which may involve a few rounds of iteration
|
||||
prior to merging.
|
||||
|
||||
### Project Structure
|
||||
|
||||
Ruff is structured as a monorepo with a [flat crate structure](https://matklad.github.io/2021/08/22/large-rust-workspaces.html),
|
||||
such that all crates are contained in a flat `crates` directory.
|
||||
|
||||
The vast majority of the code, including all lint rules, lives in the `ruff` crate (located at
|
||||
`crates/ruff`). As a contributor, that's the crate that'll be most relevant to you.
|
||||
|
||||
At time of writing, the repository includes the following crates:
|
||||
|
||||
- `crates/ruff`: library crate containing all lint rules and the core logic for running them.
|
||||
- `crates/ruff_cli`: binary crate containing Ruff's command-line interface.
|
||||
- `crates/ruff_dev`: binary crate containing utilities used in the development of Ruff itself (e.g., `cargo dev generate-all`).
|
||||
- `crates/ruff_macros`: library crate containing macros used by Ruff.
|
||||
- `crates/ruff_python`: library crate implementing Python-specific functionality (e.g., lists of standard library modules by versionb).
|
||||
- `crates/flake8_to_ruff`: binary crate for generating Ruff configuration from Flake8 configuration.
|
||||
|
||||
### Example: Adding a new lint rule
|
||||
|
||||
At a high level, the steps involved in adding a new lint rule are as follows:
|
||||
|
||||
1. Create a file for your rule (e.g., `src/rules/flake8_bugbear/rules/abstract_base_class.rs`).
|
||||
2. In that file, define a violation struct. You can grep for `define_violation!` to see examples.
|
||||
3. Map the violation struct to a rule code in `src/registry.rs` (e.g., `E402`).
|
||||
4. Define the logic for triggering the violation in `src/checkers/ast.rs` (for AST-based checks),
|
||||
`src/checkers/tokens.rs` (for token-based checks), `src/checkers/lines.rs` (for text-based
|
||||
checks), or `src/checkers/filesystem.rs` (for filesystem-based checks).
|
||||
5. Add a test fixture.
|
||||
6. Update the generated files (documentation and generated code).
|
||||
1. Determine a name for the new rule as per our [rule naming convention](#rule-naming-convention).
|
||||
2. Create a file for your rule (e.g., `crates/ruff/src/rules/flake8_bugbear/rules/abstract_base_class.rs`).
|
||||
3. In that file, define a violation struct. You can grep for `define_violation!` to see examples.
|
||||
4. Map the violation struct to a rule code in `crates/ruff/src/registry.rs` (e.g., `E402`).
|
||||
5. Define the logic for triggering the violation in `crates/ruff/src/checkers/ast.rs` (for AST-based
|
||||
checks), `crates/ruff/src/checkers/tokens.rs` (for token-based checks), `crates/ruff/src/checkers/lines.rs`
|
||||
(for text-based checks), or `crates/ruff/src/checkers/filesystem.rs` (for filesystem-based
|
||||
checks).
|
||||
6. Add a test fixture.
|
||||
7. Update the generated files (documentation and generated code).
|
||||
|
||||
To define the violation, start by creating a dedicated file for your rule under the appropriate
|
||||
rule linter (e.g., `src/rules/flake8_bugbear/rules/abstract_base_class.rs`). That file should
|
||||
rule linter (e.g., `crates/ruff/src/rules/flake8_bugbear/rules/abstract_base_class.rs`). That file should
|
||||
contain a struct defined via `define_violation!`, along with a function that creates the violation
|
||||
based on any required inputs. (Many of the existing examples live in `src/violations.rs`, but we're
|
||||
looking to place new rules in their own files.)
|
||||
based on any required inputs. (Many of the existing examples live in `crates/ruff/src/violations.rs`,
|
||||
but we're looking to place new rules in their own files.)
|
||||
|
||||
To trigger the violation, you'll likely want to augment the logic in `src/checkers/ast.rs`, which
|
||||
defines the Python AST visitor, responsible for iterating over the abstract syntax tree and
|
||||
To trigger the violation, you'll likely want to augment the logic in `crates/ruff/src/checkers/ast.rs`,
|
||||
which defines the Python AST visitor, responsible for iterating over the abstract syntax tree and
|
||||
collecting diagnostics as it goes.
|
||||
|
||||
If you need to inspect the AST, you can run `cargo dev print-ast` with a Python file. Grep
|
||||
for the `Check::new` invocations to understand how other, similar rules are implemented.
|
||||
|
||||
To add a test fixture, create a file under `resources/test/fixtures/[linter]`, named to match
|
||||
the code you defined earlier (e.g., `resources/test/fixtures/pycodestyle/E402.py`). This file should
|
||||
To add a test fixture, create a file under `crates/ruff/resources/test/fixtures/[linter]`, named to match
|
||||
the code you defined earlier (e.g., `crates/ruff/resources/test/fixtures/pycodestyle/E402.py`). This file should
|
||||
contain a variety of violations and non-violations designed to evaluate and demonstrate the behavior
|
||||
of your lint rule.
|
||||
|
||||
Run `cargo dev generate-all` to generate the code for your new fixture. Then run Ruff
|
||||
locally with (e.g.) `cargo run resources/test/fixtures/pycodestyle/E402.py --no-cache --select E402`.
|
||||
locally with (e.g.) `cargo run check crates/ruff/resources/test/fixtures/pycodestyle/E402.py --no-cache --select E402`.
|
||||
|
||||
Once you're satisfied with the output, codify the behavior as a snapshot test by adding a new
|
||||
`test_case` macro in the relevant `src/[linter]/mod.rs` file. Then, run `cargo test --all`.
|
||||
`test_case` macro in the relevant `crates/ruff/src/[linter]/mod.rs` file. Then, run `cargo test --all`.
|
||||
Your test will fail, but you'll be prompted to follow-up with `cargo insta review`. Accept the
|
||||
generated snapshot, then commit the snapshot file alongside the rest of your changes.
|
||||
|
||||
Finally, regenerate the documentation and generated code with `cargo dev generate-all`.
|
||||
|
||||
#### Rule naming convention
|
||||
|
||||
The rule name should make sense when read as "allow *rule-name*" or "allow *rule-name* items".
|
||||
|
||||
This implies that rule names:
|
||||
|
||||
* should state the bad thing being checked for
|
||||
|
||||
* should not contain instructions on what you what you should use instead
|
||||
(these belong in the rule documentation and the `autofix_title` for rules that have autofix)
|
||||
|
||||
### Example: Adding a new configuration option
|
||||
|
||||
Ruff's user-facing settings live in a few different places.
|
||||
|
||||
First, the command-line options are defined via the `Cli` struct in `src/cli.rs`.
|
||||
First, the command-line options are defined via the `Cli` struct in `crates/ruff/src/cli.rs`.
|
||||
|
||||
Second, the `pyproject.toml` options are defined in `src/settings/options.rs` (via the `Options`
|
||||
struct), `src/settings/configuration.rs` (via the `Configuration` struct), and `src/settings/mod.rs`
|
||||
(via the `Settings` struct). These represent, respectively: the schema used to parse the
|
||||
`pyproject.toml` file; an internal, intermediate representation; and the final, internal
|
||||
representation used to power Ruff.
|
||||
Second, the `pyproject.toml` options are defined in `crates/ruff/src/settings/options.rs` (via the
|
||||
`Options` struct), `crates/ruff/src/settings/configuration.rs` (via the `Configuration` struct), and
|
||||
`crates/ruff/src/settings/mod.rs` (via the `Settings` struct). These represent, respectively: the
|
||||
schema used to parse the `pyproject.toml` file; an internal, intermediate representation; and the
|
||||
final, internal representation used to power Ruff.
|
||||
|
||||
To add a new configuration option, you'll likely want to modify these latter few files (along with
|
||||
`cli.rs`, if appropriate). If you want to pattern-match against an existing example, grep for
|
||||
@@ -130,15 +173,35 @@ To add a new configuration option, you'll likely want to modify these latter few
|
||||
variables (e.g., `_`).
|
||||
|
||||
Note that plugin-specific configuration options are defined in their own modules (e.g.,
|
||||
`src/flake8_unused_arguments/settings.rs`).
|
||||
`crates/ruff/src/flake8_unused_arguments/settings.rs`).
|
||||
|
||||
You may also want to add the new configuration option to the `flake8-to-ruff` tool, which is
|
||||
responsible for converting `flake8` configuration files to Ruff's TOML format. This logic
|
||||
lives in `flake8_to_ruff/src/converter.rs`.
|
||||
lives in `crates/ruff/src/flake8_to_ruff/converter.rs`.
|
||||
|
||||
Finally, regenerate the documentation and generated code with `cargo dev generate-all`.
|
||||
|
||||
## Release process
|
||||
## MkDocs
|
||||
|
||||
To preview any changes to the documentation locally:
|
||||
|
||||
1. Install MkDocs and Material for MkDocs with:
|
||||
```shell
|
||||
pip install -r docs/requirements.txt
|
||||
```
|
||||
2. Generate the MkDocs site with:
|
||||
```shell
|
||||
python scripts/generate_mkdocs.py
|
||||
```
|
||||
3. Run the development server with:
|
||||
```shell
|
||||
mkdocs serve
|
||||
```
|
||||
|
||||
The documentation should then be available locally at
|
||||
[http://127.0.0.1:8000/docs/](http://127.0.0.1:8000/docs/).
|
||||
|
||||
## Release Process
|
||||
|
||||
As of now, Ruff has an ad hoc release process: releases are cut with high frequency via GitHub
|
||||
Actions, which automatically generates the appropriate wheels across architectures and publishes
|
||||
@@ -153,50 +216,50 @@ First, clone [CPython](https://github.com/python/cpython). It's a large and dive
|
||||
which makes it a good target for benchmarking.
|
||||
|
||||
```shell
|
||||
git clone --branch 3.10 https://github.com/python/cpython.git resources/test/cpython
|
||||
git clone --branch 3.10 https://github.com/python/cpython.git crates/ruff/resources/test/cpython
|
||||
```
|
||||
|
||||
To benchmark the release build:
|
||||
|
||||
```shell
|
||||
cargo build --release && hyperfine --ignore-failure --warmup 10 \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache" \
|
||||
"./target/release/ruff ./resources/test/cpython/"
|
||||
"./target/release/ruff ./crates/ruff/resources/test/cpython/ --no-cache" \
|
||||
"./target/release/ruff ./crates/ruff/resources/test/cpython/"
|
||||
|
||||
Benchmark 1: ./target/release/ruff ./resources/test/cpython/ --no-cache
|
||||
Benchmark 1: ./target/release/ruff ./crates/ruff/resources/test/cpython/ --no-cache
|
||||
Time (mean ± σ): 293.8 ms ± 3.2 ms [User: 2384.6 ms, System: 90.3 ms]
|
||||
Range (min … max): 289.9 ms … 301.6 ms 10 runs
|
||||
|
||||
Warning: Ignoring non-zero exit code.
|
||||
|
||||
Benchmark 2: ./target/release/ruff ./resources/test/cpython/
|
||||
Benchmark 2: ./target/release/ruff ./crates/ruff/resources/test/cpython/
|
||||
Time (mean ± σ): 48.0 ms ± 3.1 ms [User: 65.2 ms, System: 124.7 ms]
|
||||
Range (min … max): 45.0 ms … 66.7 ms 62 runs
|
||||
|
||||
Warning: Ignoring non-zero exit code.
|
||||
|
||||
Summary
|
||||
'./target/release/ruff ./resources/test/cpython/' ran
|
||||
6.12 ± 0.41 times faster than './target/release/ruff ./resources/test/cpython/ --no-cache'
|
||||
'./target/release/ruff ./crates/ruff/resources/test/cpython/' ran
|
||||
6.12 ± 0.41 times faster than './target/release/ruff ./crates/ruff/resources/test/cpython/ --no-cache'
|
||||
```
|
||||
|
||||
To benchmark against the ecosystem's existing tools:
|
||||
|
||||
```shell
|
||||
hyperfine --ignore-failure --warmup 5 \
|
||||
"./target/release/ruff ./resources/test/cpython/ --no-cache" \
|
||||
"pyflakes resources/test/cpython" \
|
||||
"./target/release/ruff ./crates/ruff/resources/test/cpython/ --no-cache" \
|
||||
"pyflakes crates/ruff/resources/test/cpython" \
|
||||
"autoflake --recursive --expand-star-imports --remove-all-unused-imports --remove-unused-variables --remove-duplicate-keys resources/test/cpython" \
|
||||
"pycodestyle resources/test/cpython" \
|
||||
"flake8 resources/test/cpython"
|
||||
"pycodestyle crates/ruff/resources/test/cpython" \
|
||||
"flake8 crates/ruff/resources/test/cpython"
|
||||
|
||||
Benchmark 1: ./target/release/ruff ./resources/test/cpython/ --no-cache
|
||||
Benchmark 1: ./target/release/ruff ./crates/ruff/resources/test/cpython/ --no-cache
|
||||
Time (mean ± σ): 294.3 ms ± 3.3 ms [User: 2467.5 ms, System: 89.6 ms]
|
||||
Range (min … max): 291.1 ms … 302.8 ms 10 runs
|
||||
|
||||
Warning: Ignoring non-zero exit code.
|
||||
|
||||
Benchmark 2: pyflakes resources/test/cpython
|
||||
Benchmark 2: pyflakes crates/ruff/resources/test/cpython
|
||||
Time (mean ± σ): 15.786 s ± 0.143 s [User: 15.560 s, System: 0.214 s]
|
||||
Range (min … max): 15.640 s … 16.157 s 10 runs
|
||||
|
||||
@@ -206,24 +269,24 @@ Benchmark 3: autoflake --recursive --expand-star-imports --remove-all-unused-imp
|
||||
Time (mean ± σ): 6.175 s ± 0.169 s [User: 54.102 s, System: 1.057 s]
|
||||
Range (min … max): 5.950 s … 6.391 s 10 runs
|
||||
|
||||
Benchmark 4: pycodestyle resources/test/cpython
|
||||
Benchmark 4: pycodestyle crates/ruff/resources/test/cpython
|
||||
Time (mean ± σ): 46.921 s ± 0.508 s [User: 46.699 s, System: 0.202 s]
|
||||
Range (min … max): 46.171 s … 47.863 s 10 runs
|
||||
|
||||
Warning: Ignoring non-zero exit code.
|
||||
|
||||
Benchmark 5: flake8 resources/test/cpython
|
||||
Benchmark 5: flake8 crates/ruff/resources/test/cpython
|
||||
Time (mean ± σ): 12.260 s ± 0.321 s [User: 102.934 s, System: 1.230 s]
|
||||
Range (min … max): 11.848 s … 12.933 s 10 runs
|
||||
|
||||
Warning: Ignoring non-zero exit code.
|
||||
|
||||
Summary
|
||||
'./target/release/ruff ./resources/test/cpython/ --no-cache' ran
|
||||
'./target/release/ruff ./crates/ruff/resources/test/cpython/ --no-cache' ran
|
||||
20.98 ± 0.62 times faster than 'autoflake --recursive --expand-star-imports --remove-all-unused-imports --remove-unused-variables --remove-duplicate-keys resources/test/cpython'
|
||||
41.66 ± 1.18 times faster than 'flake8 resources/test/cpython'
|
||||
53.64 ± 0.77 times faster than 'pyflakes resources/test/cpython'
|
||||
159.43 ± 2.48 times faster than 'pycodestyle resources/test/cpython'
|
||||
41.66 ± 1.18 times faster than 'flake8 crates/ruff/resources/test/cpython'
|
||||
53.64 ± 0.77 times faster than 'pyflakes crates/ruff/resources/test/cpython'
|
||||
159.43 ± 2.48 times faster than 'pycodestyle crates/ruff/resources/test/cpython'
|
||||
```
|
||||
|
||||
You can run `poetry install` from `./scripts` to create a working environment for the above. All
|
||||
@@ -256,10 +319,10 @@ rm Lib/test/bad_coding.py \
|
||||
Lib/test/test_typing.py
|
||||
```
|
||||
|
||||
Then, from `resources/test/cpython`, run: `time pylint -j 0 -E $(git ls-files '*.py')`. This
|
||||
Then, from `crates/ruff/resources/test/cpython`, run: `time pylint -j 0 -E $(git ls-files '*.py')`. This
|
||||
will execute Pylint with maximum parallelism and only report errors.
|
||||
|
||||
To benchmark Pyupgrade, run the following from `resources/test/cpython`:
|
||||
To benchmark Pyupgrade, run the following from `crates/ruff/resources/test/cpython`:
|
||||
|
||||
```shell
|
||||
hyperfine --ignore-failure --warmup 5 --prepare "git reset --hard HEAD" \
|
||||
|
||||
1067
Cargo.lock
generated
1067
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
87
Cargo.toml
87
Cargo.toml
@@ -1,88 +1,11 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"flake8_to_ruff",
|
||||
"ruff_dev",
|
||||
"ruff_cli",
|
||||
]
|
||||
default-members = [".", "ruff_cli"]
|
||||
members = ["crates/*"]
|
||||
default-members = ["crates/ruff", "crates/ruff_cli"]
|
||||
|
||||
[package]
|
||||
name = "ruff"
|
||||
version = "0.0.241"
|
||||
authors = ["Charlie Marsh <charlie.r.marsh@gmail.com>"]
|
||||
edition = "2021"
|
||||
rust-version = "1.65.0"
|
||||
documentation = "https://github.com/charliermarsh/ruff"
|
||||
homepage = "https://github.com/charliermarsh/ruff"
|
||||
repository = "https://github.com/charliermarsh/ruff"
|
||||
readme = "README.md"
|
||||
license = "MIT"
|
||||
|
||||
[lib]
|
||||
name = "ruff"
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
anyhow = { version = "1.0.66" }
|
||||
bitflags = { version = "1.3.2" }
|
||||
cfg-if = { version = "1.0.0" }
|
||||
chrono = { version = "0.4.21", default-features = false, features = ["clock"] }
|
||||
clap = { version = "4.0.1", features = ["derive", "env"] }
|
||||
colored = { version = "2.0.0" }
|
||||
dirs = { version = "4.0.0" }
|
||||
fern = { version = "0.6.1" }
|
||||
glob = { version = "0.3.0" }
|
||||
globset = { version = "0.4.9" }
|
||||
ignore = { version = "0.4.18" }
|
||||
imperative = { version = "1.0.3" }
|
||||
itertools = { version = "0.10.5" }
|
||||
[workspace.dependencies]
|
||||
libcst = { git = "https://github.com/charliermarsh/LibCST", rev = "f2f0b7a487a8725d161fe8b3ed73a6758b21e177" }
|
||||
log = { version = "0.4.17" }
|
||||
natord = { version = "1.0.9" }
|
||||
nohash-hasher = { version = "0.2.0" }
|
||||
num-bigint = { version = "0.4.3" }
|
||||
num-traits = "0.2.15"
|
||||
once_cell = { version = "1.16.0" }
|
||||
path-absolutize = { version = "3.0.14", features = ["once_cell_cache", "use_unix_paths_on_wasm"] }
|
||||
regex = { version = "1.6.0" }
|
||||
ruff_macros = { version = "0.0.241", path = "ruff_macros" }
|
||||
rustc-hash = { version = "1.1.0" }
|
||||
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "adc23253e4b58980b407ba2760dbe61681d752fc" }
|
||||
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "adc23253e4b58980b407ba2760dbe61681d752fc" }
|
||||
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "adc23253e4b58980b407ba2760dbe61681d752fc" }
|
||||
schemars = { version = "0.8.11" }
|
||||
semver = { version = "1.0.16" }
|
||||
serde = { version = "1.0.147", features = ["derive"] }
|
||||
shellexpand = { version = "3.0.0" }
|
||||
smallvec = { version = "1.10.0" }
|
||||
strum = { version = "0.24.1", features = ["strum_macros"] }
|
||||
strum_macros = { version = "0.24.3" }
|
||||
textwrap = { version = "0.16.0" }
|
||||
thiserror = { version = "1.0" }
|
||||
titlecase = { version = "2.2.1" }
|
||||
toml = { version = "0.6.0" }
|
||||
|
||||
# https://docs.rs/getrandom/0.2.7/getrandom/#webassembly-support
|
||||
# For (future) wasm-pack support
|
||||
[target.'cfg(all(target_family = "wasm", target_os = "unknown"))'.dependencies]
|
||||
getrandom = { version = "0.2.7", features = ["js"] }
|
||||
console_error_panic_hook = { version = "0.1.7" }
|
||||
console_log = { version = "0.2.0" }
|
||||
serde-wasm-bindgen = { version = "0.4" }
|
||||
js-sys = { version = "0.3.60" }
|
||||
wasm-bindgen = { version = "0.2.83" }
|
||||
|
||||
[target.'cfg(not(target_family = "wasm"))'.dependencies]
|
||||
is_executable = "1.0.1"
|
||||
|
||||
[dev-dependencies]
|
||||
insta = { version = "1.19.0", features = ["yaml", "redactions"] }
|
||||
test-case = { version = "2.2.2" }
|
||||
wasm-bindgen-test = { version = "0.3.33" }
|
||||
|
||||
[target.'cfg(not(target_family = "wasm"))'.dev-dependencies]
|
||||
criterion = { version = "0.4.0" }
|
||||
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "61b48f108982d865524f86624a9d5bc2ae3bccef" }
|
||||
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "61b48f108982d865524f86624a9d5bc2ae3bccef" }
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
|
||||
27
LICENSE
27
LICENSE
@@ -245,6 +245,31 @@ are:
|
||||
SOFTWARE.
|
||||
"""
|
||||
|
||||
- flake8-pyi, licensed as follows:
|
||||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Łukasz Langa
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
"""
|
||||
|
||||
- flake8-print, licensed as follows:
|
||||
"""
|
||||
MIT License
|
||||
@@ -1035,3 +1060,5 @@ are:
|
||||
"""
|
||||
Freely Distributable
|
||||
"""
|
||||
|
||||
- flake8-django, licensed under the GPL license.
|
||||
|
||||
410
README.md
410
README.md
@@ -9,7 +9,7 @@
|
||||
[](https://github.com/charliermarsh/ruff/actions)
|
||||
[](https://info.jetbrains.com/PyCharm-Webinar-February14-2023.html)
|
||||
|
||||
[**Discord**](https://discord.gg/Z8KbeK24) | [**Docs**](https://beta.ruff.rs/docs/) | [**Playground**](https://play.ruff.rs/)
|
||||
[**Discord**](https://discord.gg/c9MhzV8aU5) | [**Docs**](https://beta.ruff.rs/docs/) | [**Playground**](https://play.ruff.rs/)
|
||||
|
||||
An extremely fast Python linter, written in Rust.
|
||||
|
||||
@@ -137,6 +137,7 @@ This README is also available as [documentation](https://beta.ruff.rs/docs/).
|
||||
1. [flake8-comprehensions (C4)](#flake8-comprehensions-c4)
|
||||
1. [flake8-datetimez (DTZ)](#flake8-datetimez-dtz)
|
||||
1. [flake8-debugger (T10)](#flake8-debugger-t10)
|
||||
1. [flake8-django (DJ)](#flake8-django-dj)
|
||||
1. [flake8-errmsg (EM)](#flake8-errmsg-em)
|
||||
1. [flake8-executable (EXE)](#flake8-executable-exe)
|
||||
1. [flake8-implicit-str-concat (ISC)](#flake8-implicit-str-concat-isc)
|
||||
@@ -145,6 +146,7 @@ This README is also available as [documentation](https://beta.ruff.rs/docs/).
|
||||
1. [flake8-no-pep420 (INP)](#flake8-no-pep420-inp)
|
||||
1. [flake8-pie (PIE)](#flake8-pie-pie)
|
||||
1. [flake8-print (T20)](#flake8-print-t20)
|
||||
1. [flake8-pyi (PYI)](#flake8-pyi-pyi)
|
||||
1. [flake8-pytest-style (PT)](#flake8-pytest-style-pt)
|
||||
1. [flake8-quotes (Q)](#flake8-quotes-q)
|
||||
1. [flake8-return (RET)](#flake8-return-ret)
|
||||
@@ -213,16 +215,16 @@ apk add ruff
|
||||
To run Ruff, try any of the following:
|
||||
|
||||
```shell
|
||||
ruff . # Lint all files in the current directory (and any subdirectories)
|
||||
ruff path/to/code/ # Lint all files in `/path/to/code` (and any subdirectories)
|
||||
ruff path/to/code/*.py # Lint all `.py` files in `/path/to/code`
|
||||
ruff path/to/code/to/file.py # Lint `file.py`
|
||||
ruff check . # Lint all files in the current directory (and any subdirectories)
|
||||
ruff check path/to/code/ # Lint all files in `/path/to/code` (and any subdirectories)
|
||||
ruff check path/to/code/*.py # Lint all `.py` files in `/path/to/code`
|
||||
ruff check path/to/code/to/file.py # Lint `file.py`
|
||||
```
|
||||
|
||||
You can run Ruff in `--watch` mode to automatically re-run on-change:
|
||||
|
||||
```shell
|
||||
ruff path/to/code/ --watch
|
||||
ruff check path/to/code/ --watch
|
||||
```
|
||||
|
||||
Ruff also works with [pre-commit](https://pre-commit.com):
|
||||
@@ -230,11 +232,22 @@ Ruff also works with [pre-commit](https://pre-commit.com):
|
||||
```yaml
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: 'v0.0.241'
|
||||
rev: 'v0.0.246'
|
||||
hooks:
|
||||
- id: ruff
|
||||
```
|
||||
|
||||
Or, to enable autofix:
|
||||
|
||||
```yaml
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: 'v0.0.246'
|
||||
hooks:
|
||||
- id: ruff
|
||||
args: [--fix, --exit-non-zero-on-fix]
|
||||
```
|
||||
|
||||
<!-- End section: Installation and Usage -->
|
||||
|
||||
## Configuration
|
||||
@@ -377,7 +390,7 @@ Some configuration settings can be provided via the command-line, such as those
|
||||
rule enablement and disablement, file discovery, logging level, and more:
|
||||
|
||||
```shell
|
||||
ruff path/to/code/ --select F401 --select F403 --quiet
|
||||
ruff check path/to/code/ --select F401 --select F403 --quiet
|
||||
```
|
||||
|
||||
See `ruff help` for more on Ruff's top-level commands:
|
||||
@@ -392,6 +405,7 @@ Usage: ruff [OPTIONS] <COMMAND>
|
||||
Commands:
|
||||
check Run Ruff on the given files or directories (default)
|
||||
rule Explain a rule
|
||||
config List or describe the available configuration options
|
||||
linter List all supported upstream linters
|
||||
clean Clear any caches in the current directory and any subdirectories
|
||||
help Print this message or the help of the given subcommand(s)
|
||||
@@ -425,6 +439,7 @@ Arguments:
|
||||
Options:
|
||||
--fix Attempt to automatically fix lint violations
|
||||
--show-source Show violations with source code
|
||||
--show-fixes Show an enumeration of all autofixed lint violations
|
||||
--diff Avoid writing any fixed files back; instead, output a diff for each changed file to stdout
|
||||
-w, --watch Run in watch mode by re-running whenever files change
|
||||
--fix-only Fix any fixable lint violations, but don't report on leftover violations. Implies `--fix`
|
||||
@@ -456,14 +471,6 @@ File selection:
|
||||
--respect-gitignore Respect file exclusions via `.gitignore` and other standard ignore files
|
||||
--force-exclude Enforce exclusions, even for paths passed to Ruff directly on the command-line
|
||||
|
||||
Rule configuration:
|
||||
--target-version <TARGET_VERSION>
|
||||
The minimum Python version that should be supported
|
||||
--line-length <LINE_LENGTH>
|
||||
Set the line-length for length-associated rules and automatic formatting
|
||||
--dummy-variable-rgx <DUMMY_VARIABLE_RGX>
|
||||
Regular expression matching the name of dummy variables
|
||||
|
||||
Miscellaneous:
|
||||
-n, --no-cache
|
||||
Disable cache reads
|
||||
@@ -475,6 +482,8 @@ Miscellaneous:
|
||||
The name of the file when passing it through stdin
|
||||
-e, --exit-zero
|
||||
Exit with status code "0", even upon detecting lint violations
|
||||
--exit-non-zero-on-fix
|
||||
Exit with a non-zero status code if any files were modified via autofix, even if no lint violations remain
|
||||
|
||||
Log levels:
|
||||
-v, --verbose Enable verbose logging
|
||||
@@ -533,7 +542,7 @@ By default, Ruff will also skip any files that are omitted via `.ignore`, `.giti
|
||||
`.git/info/exclude`, and global `gitignore` files (see: [`respect-gitignore`](#respect-gitignore)).
|
||||
|
||||
Files that are passed to `ruff` directly are always linted, regardless of the above criteria.
|
||||
For example, `ruff /path/to/excluded/file.py` will always lint `file.py`.
|
||||
For example, `ruff check /path/to/excluded/file.py` will always lint `file.py`.
|
||||
|
||||
### Rule resolution
|
||||
|
||||
@@ -557,9 +566,9 @@ select = ["E", "F"]
|
||||
ignore = ["F401"]
|
||||
```
|
||||
|
||||
Running `ruff --select F401` would result in Ruff enforcing `F401`, and no other rules.
|
||||
Running `ruff check --select F401` would result in Ruff enforcing `F401`, and no other rules.
|
||||
|
||||
Running `ruff --extend-select B` would result in Ruff enforcing the `E`, `F`, and `B` rules, with
|
||||
Running `ruff check --extend-select B` would result in Ruff enforcing the `E`, `F`, and `B` rules, with
|
||||
the exception of `F401`.
|
||||
|
||||
### Suppressing errors
|
||||
@@ -604,15 +613,15 @@ Ruff supports several workflows to aid in `noqa` management.
|
||||
|
||||
First, Ruff provides a special rule code, `RUF100`, 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). You can run `ruff /path/to/file.py --extend-select RUF100` to flag unused `noqa`
|
||||
thus suppressed). You can run `ruff check /path/to/file.py --extend-select RUF100` to flag unused `noqa`
|
||||
directives.
|
||||
|
||||
Second, Ruff can _automatically remove_ unused `noqa` directives via its autofix functionality.
|
||||
You can run `ruff /path/to/file.py --extend-select RUF100 --fix` to automatically remove unused
|
||||
You can run `ruff check /path/to/file.py --extend-select RUF100 --fix` to automatically remove unused
|
||||
`noqa` directives.
|
||||
|
||||
Third, Ruff can _automatically add_ `noqa` directives to all failing lines. This is useful when
|
||||
migrating a new codebase to Ruff. You can run `ruff /path/to/file.py --add-noqa` to automatically
|
||||
migrating a new codebase to Ruff. You can run `ruff check /path/to/file.py --add-noqa` to automatically
|
||||
add `noqa` directives to all failing lines, with the appropriate rule codes.
|
||||
|
||||
#### Action comments
|
||||
@@ -625,6 +634,44 @@ configuration.
|
||||
See the [`isort` documentation](https://pycqa.github.io/isort/docs/configuration/action_comments.html)
|
||||
for more.
|
||||
|
||||
### Exit codes
|
||||
|
||||
By default, Ruff 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 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
|
||||
autofixing.
|
||||
|
||||
### Autocompletion
|
||||
|
||||
Ruff supports autocompletion for most shells. A shell-specific completion script can be generated
|
||||
by `ruff completion <SHELL>`, where `<SHELL>` is one of `bash`, `elvish`, `fig`, `fish`,
|
||||
`powershell`, or `zsh`.
|
||||
|
||||
The exact steps required to enable autocompletion will vary by shell. For example instructions,
|
||||
see the [Poetry](https://python-poetry.org/docs/#enable-tab-completion-for-bash-fish-or-zsh) or
|
||||
[ripgrep](https://github.com/BurntSushi/ripgrep/blob/master/FAQ.md#complete) documentation.
|
||||
|
||||
As an example: to enable autocompletion for Zsh, run
|
||||
`ruff generate-shell-completion zsh > ~/.zfunc/_ruff`. Then add the following line to your
|
||||
`~/.zshrc` file, if they're not already present:
|
||||
|
||||
```zsh
|
||||
fpath+=~/.zfunc
|
||||
autoload -Uz compinit && compinit
|
||||
```
|
||||
|
||||
<!-- End section: Configuration -->
|
||||
|
||||
## Supported Rules
|
||||
@@ -650,7 +697,7 @@ For more, see [Pyflakes](https://pypi.org/project/pyflakes/) on PyPI.
|
||||
| ---- | ---- | ------- | --- |
|
||||
| F401 | unused-import | `{name}` imported but unused; consider adding to `__all__` or using a redundant alias | 🛠 |
|
||||
| F402 | import-shadowed-by-loop-var | Import `{name}` from line {line} shadowed by loop variable | |
|
||||
| F403 | import-star-used | `from {name} import *` used; unable to detect undefined names | |
|
||||
| F403 | import-star | `from {name} import *` used; unable to detect undefined names | |
|
||||
| F404 | late-future-import | `from __future__` imports must occur at the beginning of the file | |
|
||||
| F405 | import-star-usage | `{name}` may be undefined, or defined from star imports: {sources} | |
|
||||
| F406 | import-star-not-permitted | `from {name} import *` only allowed at module level | |
|
||||
@@ -669,7 +716,7 @@ For more, see [Pyflakes](https://pypi.org/project/pyflakes/) on PyPI.
|
||||
| F523 | string-dot-format-extra-positional-arguments | `.format` call has unused arguments at position(s): {message} | |
|
||||
| F524 | string-dot-format-missing-arguments | `.format` call is missing argument(s) for placeholder(s): {message} | |
|
||||
| F525 | string-dot-format-mixing-automatic | `.format` string mixes automatic and manual numbering | |
|
||||
| F541 | f-string-missing-placeholders | f-string without any placeholders | 🛠 |
|
||||
| F541 | [f-string-missing-placeholders](https://github.com/charliermarsh/ruff/blob/main/docs/rules/f-string-missing-placeholders.md) | f-string without any placeholders | 🛠 |
|
||||
| F601 | multi-value-repeated-key-literal | Dictionary key literal `{name}` repeated | 🛠 |
|
||||
| F602 | multi-value-repeated-key-variable | Dictionary key `{name}` repeated | 🛠 |
|
||||
| F621 | expressions-in-star-assignment | Too many expressions in star-unpacking assignment | |
|
||||
@@ -688,7 +735,7 @@ For more, see [Pyflakes](https://pypi.org/project/pyflakes/) on PyPI.
|
||||
| F821 | undefined-name | Undefined name `{name}` | |
|
||||
| F822 | undefined-export | Undefined name `{name}` in `__all__` | |
|
||||
| F823 | undefined-local | Local variable `{name}` referenced before assignment | |
|
||||
| F841 | unused-variable | Local variable `{name}` is assigned to but never used | 🛠 |
|
||||
| F841 | [unused-variable](https://github.com/charliermarsh/ruff/blob/main/docs/rules/unused-variable.md) | Local variable `{name}` is assigned to but never used | 🛠 |
|
||||
| F842 | unused-annotation | Local variable `{name}` is annotated but never used | |
|
||||
| F901 | raise-not-implemented | `raise NotImplemented` should be `raise NotImplementedError` | 🛠 |
|
||||
|
||||
@@ -704,13 +751,16 @@ For more, see [pycodestyle](https://pypi.org/project/pycodestyle/) on PyPI.
|
||||
| E401 | multiple-imports-on-one-line | Multiple imports on one line | |
|
||||
| E402 | module-import-not-at-top-of-file | Module level import not at top of file | |
|
||||
| E501 | line-too-long | Line too long ({length} > {limit} characters) | |
|
||||
| E701 | multiple-statements-on-one-line-colon | Multiple statements on one line (colon) | |
|
||||
| E702 | multiple-statements-on-one-line-semicolon | Multiple statements on one line (semicolon) | |
|
||||
| E703 | useless-semicolon | Statement ends with an unnecessary semicolon | |
|
||||
| E711 | none-comparison | Comparison to `None` should be `cond is None` | 🛠 |
|
||||
| E712 | true-false-comparison | Comparison to `True` should be `cond is True` | 🛠 |
|
||||
| E713 | not-in-test | Test for membership should be `not in` | 🛠 |
|
||||
| E714 | not-is-test | Test for object identity should be `is not` | 🛠 |
|
||||
| E721 | type-comparison | Do not compare types, use `isinstance()` | |
|
||||
| E722 | do-not-use-bare-except | Do not use bare `except` | |
|
||||
| E731 | do-not-assign-lambda | Do not assign a `lambda` expression, use a `def` | 🛠 |
|
||||
| E722 | [bare-except](https://github.com/charliermarsh/ruff/blob/main/docs/rules/bare-except.md) | Do not use bare `except` | |
|
||||
| E731 | lambda-assignment | Do not assign a `lambda` expression, use a `def` | 🛠 |
|
||||
| E741 | ambiguous-variable-name | Ambiguous variable name: `{name}` | |
|
||||
| E742 | ambiguous-class-name | Ambiguous class name: `{name}` | |
|
||||
| E743 | ambiguous-function-name | Ambiguous function name: `{name}` | |
|
||||
@@ -731,7 +781,7 @@ For more, see [mccabe](https://pypi.org/project/mccabe/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| C901 | function-is-too-complex | `{name}` is too complex ({complexity}) | |
|
||||
| C901 | [complex-structure](https://github.com/charliermarsh/ruff/blob/main/docs/rules/complex-structure.md) | `{name}` is too complex ({complexity}) | |
|
||||
|
||||
### isort (I)
|
||||
|
||||
@@ -739,8 +789,8 @@ For more, see [isort](https://pypi.org/project/isort/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| I001 | unsorted-imports | Import block is un-sorted or un-formatted | 🛠 |
|
||||
| I002 | missing-required-import | Missing required import: `{name}` | 🛠 |
|
||||
| I001 | [unsorted-imports](https://github.com/charliermarsh/ruff/blob/main/docs/rules/unsorted-imports.md) | Import block is un-sorted or un-formatted | 🛠 |
|
||||
| I002 | [missing-required-import](https://github.com/charliermarsh/ruff/blob/main/docs/rules/missing-required-import.md) | Missing required import: `{name}` | 🛠 |
|
||||
|
||||
### pep8-naming (N)
|
||||
|
||||
@@ -794,13 +844,13 @@ For more, see [pydocstyle](https://pypi.org/project/pydocstyle/) on PyPI.
|
||||
| D213 | multi-line-summary-second-line | Multi-line docstring summary should start at the second line | 🛠 |
|
||||
| D214 | section-not-over-indented | Section is over-indented ("{name}") | 🛠 |
|
||||
| D215 | section-underline-not-over-indented | Section underline is over-indented ("{name}") | 🛠 |
|
||||
| D300 | uses-triple-quotes | Use """triple double quotes""" | |
|
||||
| D301 | uses-r-prefix-for-backslashed-content | Use r""" if any backslashes in a docstring | |
|
||||
| D300 | triple-single-quotes | Use """triple double quotes""" | |
|
||||
| D301 | escape-sequence-in-docstring | Use r""" if any backslashes in a docstring | |
|
||||
| D400 | ends-in-period | First line should end with a period | 🛠 |
|
||||
| D401 | non-imperative-mood | First line of docstring should be in imperative mood: "{first_line}" | |
|
||||
| D402 | no-signature | First line should not be the function's signature | |
|
||||
| D403 | first-line-capitalized | First word of the first line should be properly capitalized | |
|
||||
| D404 | no-this-prefix | First word of the docstring should not be "This" | |
|
||||
| D404 | docstring-starts-with-this | First word of the docstring should not be "This" | |
|
||||
| D405 | capitalize-section-name | Section name should be properly capitalized ("{name}") | 🛠 |
|
||||
| D406 | new-line-after-section-name | Section name should end with a newline ("{name}") | 🛠 |
|
||||
| D407 | dashed-underline-after-section | Missing dashed underline after section ("{name}") | 🛠 |
|
||||
@@ -810,12 +860,12 @@ For more, see [pydocstyle](https://pypi.org/project/pydocstyle/) on PyPI.
|
||||
| D411 | blank-line-before-section | Missing blank line before section ("{name}") | 🛠 |
|
||||
| D412 | no-blank-lines-between-header-and-content | No blank lines allowed between a section header and its content ("{name}") | 🛠 |
|
||||
| D413 | blank-line-after-last-section | Missing blank line after last section ("{name}") | 🛠 |
|
||||
| D414 | non-empty-section | Section has no content ("{name}") | |
|
||||
| D414 | empty-docstring-section | Section has no content ("{name}") | |
|
||||
| D415 | ends-in-punctuation | First line should end with a period, question mark, or exclamation point | 🛠 |
|
||||
| D416 | section-name-ends-in-colon | Section name should end with a colon ("{name}") | 🛠 |
|
||||
| D417 | document-all-arguments | Missing argument description in the docstring: `{name}` | |
|
||||
| D418 | skip-docstring | Function decorated with `@overload` shouldn't contain a docstring | |
|
||||
| D419 | non-empty | Docstring is empty | |
|
||||
| D417 | undocumented-param | Missing argument description in the docstring: `{name}` | |
|
||||
| D418 | overload-with-docstring | Function decorated with `@overload` shouldn't contain a docstring | |
|
||||
| D419 | empty-docstring | Docstring is empty | |
|
||||
|
||||
### pyupgrade (UP)
|
||||
|
||||
@@ -827,10 +877,10 @@ For more, see [pyupgrade](https://pypi.org/project/pyupgrade/) on PyPI.
|
||||
| UP003 | type-of-primitive | Use `{}` instead of `type(...)` | 🛠 |
|
||||
| UP004 | useless-object-inheritance | Class `{name}` inherits from `object` | 🛠 |
|
||||
| UP005 | deprecated-unittest-alias | `{alias}` is deprecated, use `{target}` | 🛠 |
|
||||
| UP006 | use-pep585-annotation | Use `{}` instead of `{}` for type annotations | 🛠 |
|
||||
| UP007 | use-pep604-annotation | Use `X \| Y` for type annotations | 🛠 |
|
||||
| UP006 | deprecated-collection-type | Use `{}` instead of `{}` for type annotations | 🛠 |
|
||||
| UP007 | typing-union | Use `X \| Y` for type annotations | 🛠 |
|
||||
| UP008 | super-call-with-parameters | Use `super()` instead of `super(__class__, self)` | 🛠 |
|
||||
| UP009 | pep3120-unnecessary-coding-comment | UTF-8 encoding declaration is unnecessary | 🛠 |
|
||||
| UP009 | utf8-encoding-declaration | UTF-8 encoding declaration is unnecessary | 🛠 |
|
||||
| UP010 | unnecessary-future-import | Unnecessary `__future__` import `{import}` for target Python version | 🛠 |
|
||||
| UP011 | lru-cache-without-parameters | Unnecessary parameters to `functools.lru_cache` | 🛠 |
|
||||
| UP012 | unnecessary-encode-utf8 | Unnecessary call to `encode` as UTF-8 | 🛠 |
|
||||
@@ -857,6 +907,7 @@ For more, see [pyupgrade](https://pypi.org/project/pyupgrade/) on PyPI.
|
||||
| UP034 | extraneous-parentheses | Avoid extraneous parentheses | 🛠 |
|
||||
| UP035 | import-replacements | Import from `{module}` instead: {names} | 🛠 |
|
||||
| UP036 | outdated-version-block | Version block is outdated for minimum Python version | 🛠 |
|
||||
| UP037 | quoted-annotation | Remove quotes from type annotation | 🛠 |
|
||||
|
||||
### flake8-2020 (YTT)
|
||||
|
||||
@@ -881,17 +932,17 @@ For more, see [flake8-annotations](https://pypi.org/project/flake8-annotations/)
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| ANN001 | missing-type-function-argument | Missing type annotation for function argument `{name}` | |
|
||||
| ANN002 | missing-type-args | Missing type annotation for `*{name}` | |
|
||||
| ANN003 | missing-type-kwargs | Missing type annotation for `**{name}` | |
|
||||
| ANN101 | missing-type-self | Missing type annotation for `{name}` in method | |
|
||||
| ANN102 | missing-type-cls | Missing type annotation for `{name}` in classmethod | |
|
||||
| ANN201 | missing-return-type-public-function | Missing return type annotation for public function `{name}` | |
|
||||
| ANN202 | missing-return-type-private-function | Missing return type annotation for private function `{name}` | |
|
||||
| ANN204 | missing-return-type-special-method | Missing return type annotation for special method `{name}` | 🛠 |
|
||||
| ANN205 | missing-return-type-static-method | Missing return type annotation for staticmethod `{name}` | |
|
||||
| ANN206 | missing-return-type-class-method | Missing return type annotation for classmethod `{name}` | |
|
||||
| ANN401 | dynamically-typed-expression | Dynamically typed expressions (typing.Any) are disallowed in `{name}` | |
|
||||
| ANN001 | [missing-type-function-argument](https://github.com/charliermarsh/ruff/blob/main/docs/rules/missing-type-function-argument.md) | Missing type annotation for function argument `{name}` | |
|
||||
| ANN002 | [missing-type-args](https://github.com/charliermarsh/ruff/blob/main/docs/rules/missing-type-args.md) | Missing type annotation for `*{name}` | |
|
||||
| ANN003 | [missing-type-kwargs](https://github.com/charliermarsh/ruff/blob/main/docs/rules/missing-type-kwargs.md) | Missing type annotation for `**{name}` | |
|
||||
| ANN101 | [missing-type-self](https://github.com/charliermarsh/ruff/blob/main/docs/rules/missing-type-self.md) | Missing type annotation for `{name}` in method | |
|
||||
| ANN102 | [missing-type-cls](https://github.com/charliermarsh/ruff/blob/main/docs/rules/missing-type-cls.md) | Missing type annotation for `{name}` in classmethod | |
|
||||
| ANN201 | [missing-return-type-public-function](https://github.com/charliermarsh/ruff/blob/main/docs/rules/missing-return-type-public-function.md) | Missing return type annotation for public function `{name}` | |
|
||||
| ANN202 | [missing-return-type-private-function](https://github.com/charliermarsh/ruff/blob/main/docs/rules/missing-return-type-private-function.md) | Missing return type annotation for private function `{name}` | |
|
||||
| ANN204 | [missing-return-type-special-method](https://github.com/charliermarsh/ruff/blob/main/docs/rules/missing-return-type-special-method.md) | Missing return type annotation for special method `{name}` | 🛠 |
|
||||
| ANN205 | [missing-return-type-static-method](https://github.com/charliermarsh/ruff/blob/main/docs/rules/missing-return-type-static-method.md) | Missing return type annotation for staticmethod `{name}` | |
|
||||
| ANN206 | [missing-return-type-class-method](https://github.com/charliermarsh/ruff/blob/main/docs/rules/missing-return-type-class-method.md) | Missing return type annotation for classmethod `{name}` | |
|
||||
| ANN401 | [any-type](https://github.com/charliermarsh/ruff/blob/main/docs/rules/any-type.md) | Dynamically typed expressions (typing.Any) are disallowed in `{name}` | |
|
||||
|
||||
### flake8-bandit (S)
|
||||
|
||||
@@ -899,8 +950,8 @@ For more, see [flake8-bandit](https://pypi.org/project/flake8-bandit/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| S101 | assert-used | Use of `assert` detected | |
|
||||
| S102 | exec-used | Use of `exec` detected | |
|
||||
| S101 | assert | Use of `assert` detected | |
|
||||
| S102 | exec-builtin | Use of `exec` detected | |
|
||||
| S103 | bad-file-permissions | `os.chmod` setting a permissive mask `{mask:#o}` on file or directory | |
|
||||
| S104 | hardcoded-bind-all-interfaces | Possible binding to all interfaces | |
|
||||
| S105 | hardcoded-password-string | Possible hardcoded password: "{}" | |
|
||||
@@ -908,12 +959,14 @@ For more, see [flake8-bandit](https://pypi.org/project/flake8-bandit/) on PyPI.
|
||||
| S107 | hardcoded-password-default | Possible hardcoded password: "{}" | |
|
||||
| S108 | hardcoded-temp-file | Probable insecure usage of temporary file or directory: "{}" | |
|
||||
| S110 | try-except-pass | `try`-`except`-`pass` detected, consider logging the exception | |
|
||||
| S112 | try-except-continue | `try`-`except`-`continue` detected, consider logging the exception | |
|
||||
| S113 | request-without-timeout | Probable use of requests call with timeout set to `{value}` | |
|
||||
| S324 | hashlib-insecure-hash-function | Probable use of insecure hash functions in `hashlib`: "{}" | |
|
||||
| S501 | request-with-no-cert-validation | Probable use of `{string}` call with `verify=False` disabling SSL certificate checks | |
|
||||
| S506 | unsafe-yaml-load | Probable use of unsafe loader `{name}` with `yaml.load`. Allows instantiation of arbitrary objects. Consider `yaml.safe_load`. | |
|
||||
| S508 | snmp-insecure-version | The use of SNMPv1 and SNMPv2 is insecure. Use SNMPv3 if able. | |
|
||||
| S509 | snmp-weak-cryptography | You should not use SNMPv3 without encryption. `noAuthNoPriv` & `authNoPriv` is insecure. | |
|
||||
| S608 | [hardcoded-sql-expression](https://github.com/charliermarsh/ruff/blob/main/docs/rules/hardcoded-sql-expression.md) | Possible SQL injection vector through string-based query construction | |
|
||||
| S612 | logging-config-insecure-listen | Use of insecure `logging.config.listen` detected | |
|
||||
| S701 | jinja2-autoescape-false | Using jinja2 templates with `autoescape=False` is dangerous and can lead to XSS. Ensure `autoescape=True` or use the `select_autoescape` function. | |
|
||||
|
||||
@@ -950,13 +1003,13 @@ For more, see [flake8-bugbear](https://pypi.org/project/flake8-bugbear/) on PyPI
|
||||
| B008 | function-call-argument-default | Do not perform function call `{name}` in argument defaults | |
|
||||
| B009 | get-attr-with-constant | Do not call `getattr` with a constant attribute value. It is not any safer than normal property access. | 🛠 |
|
||||
| B010 | set-attr-with-constant | Do not call `setattr` with a constant attribute value. It is not any safer than normal property access. | 🛠 |
|
||||
| B011 | do-not-assert-false | Do not `assert False` (`python -O` removes these calls), raise `AssertionError()` | 🛠 |
|
||||
| B011 | assert-false | Do not `assert False` (`python -O` removes these calls), raise `AssertionError()` | 🛠 |
|
||||
| B012 | jump-statement-in-finally | `{name}` inside `finally` blocks cause exceptions to be silenced | |
|
||||
| B013 | redundant-tuple-in-exception-handler | A length-one tuple literal is redundant. Write `except {name}` instead of `except ({name},)`. | 🛠 |
|
||||
| B014 | duplicate-handler-exception | Exception handler with duplicate exception: `{name}` | 🛠 |
|
||||
| B015 | useless-comparison | Pointless comparison. This comparison does nothing but waste CPU instructions. Either prepend `assert` or remove it. | |
|
||||
| B016 | cannot-raise-literal | Cannot raise a literal. Did you intend to return it or raise an Exception? | |
|
||||
| B017 | no-assert-raises-exception | `assertRaises(Exception)` should be considered evil | |
|
||||
| B017 | [assert-raises-exception](https://github.com/charliermarsh/ruff/blob/main/docs/rules/assert-raises-exception.md) | `assertRaises(Exception)` should be considered evil | |
|
||||
| B018 | useless-expression | Found useless expression. Either assign it to a variable or remove it. | |
|
||||
| B019 | cached-instance-method | Use of `functools.lru_cache` or `functools.cache` on methods can lead to memory leaks | |
|
||||
| B020 | loop-variable-overrides-iterator | Loop control variable `{name}` overrides iterable it iterates | |
|
||||
@@ -996,9 +1049,9 @@ For more, see [flake8-comprehensions](https://pypi.org/project/flake8-comprehens
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| C400 | unnecessary-generator-list | Unnecessary generator (rewrite as a `list` comprehension) | 🛠 |
|
||||
| C401 | unnecessary-generator-set | Unnecessary generator (rewrite as a `set` comprehension) | 🛠 |
|
||||
| C402 | unnecessary-generator-dict | Unnecessary generator (rewrite as a `dict` comprehension) | 🛠 |
|
||||
| C400 | [unnecessary-generator-list](https://github.com/charliermarsh/ruff/blob/main/docs/rules/unnecessary-generator-list.md) | Unnecessary generator (rewrite as a `list` comprehension) | 🛠 |
|
||||
| C401 | [unnecessary-generator-set](https://github.com/charliermarsh/ruff/blob/main/docs/rules/unnecessary-generator-set.md) | Unnecessary generator (rewrite as a `set` comprehension) | 🛠 |
|
||||
| C402 | [unnecessary-generator-dict](https://github.com/charliermarsh/ruff/blob/main/docs/rules/unnecessary-generator-dict.md) | Unnecessary generator (rewrite as a `dict` comprehension) | 🛠 |
|
||||
| C403 | unnecessary-list-comprehension-set | Unnecessary `list` comprehension (rewrite as a `set` comprehension) | 🛠 |
|
||||
| C404 | unnecessary-list-comprehension-dict | Unnecessary `list` comprehension (rewrite as a `dict` comprehension) | 🛠 |
|
||||
| C405 | unnecessary-literal-set | Unnecessary `{obj_type}` literal (rewrite as a `set` literal) | 🛠 |
|
||||
@@ -1007,11 +1060,11 @@ For more, see [flake8-comprehensions](https://pypi.org/project/flake8-comprehens
|
||||
| C409 | unnecessary-literal-within-tuple-call | Unnecessary `{literal}` literal passed to `tuple()` (rewrite as a `tuple` literal) | 🛠 |
|
||||
| C410 | unnecessary-literal-within-list-call | Unnecessary `{literal}` literal passed to `list()` (remove the outer call to `list()`) | 🛠 |
|
||||
| C411 | unnecessary-list-call | Unnecessary `list` call (remove the outer call to `list()`) | 🛠 |
|
||||
| C413 | unnecessary-call-around-sorted | Unnecessary `{func}` call around `sorted()` | 🛠 |
|
||||
| C414 | unnecessary-double-cast-or-process | Unnecessary `{inner}` call within `{outer}()` | |
|
||||
| C413 | [unnecessary-call-around-sorted](https://github.com/charliermarsh/ruff/blob/main/docs/rules/unnecessary-call-around-sorted.md) | Unnecessary `{func}` call around `sorted()` | 🛠 |
|
||||
| C414 | [unnecessary-double-cast-or-process](https://github.com/charliermarsh/ruff/blob/main/docs/rules/unnecessary-double-cast-or-process.md) | Unnecessary `{inner}` call within `{outer}()` | 🛠 |
|
||||
| C415 | unnecessary-subscript-reversal | Unnecessary subscript reversal of iterable within `{func}()` | |
|
||||
| C416 | unnecessary-comprehension | Unnecessary `{obj_type}` comprehension (rewrite using `{obj_type}()`) | 🛠 |
|
||||
| C417 | unnecessary-map | Unnecessary `map` usage (rewrite using a generator expression) | |
|
||||
| C417 | [unnecessary-map](https://github.com/charliermarsh/ruff/blob/main/docs/rules/unnecessary-map.md) | Unnecessary `map` usage (rewrite using a generator expression) | 🛠 |
|
||||
|
||||
### flake8-datetimez (DTZ)
|
||||
|
||||
@@ -1037,6 +1090,16 @@ For more, see [flake8-debugger](https://pypi.org/project/flake8-debugger/) on Py
|
||||
| ---- | ---- | ------- | --- |
|
||||
| T100 | debugger | Trace found: `{name}` used | |
|
||||
|
||||
### flake8-django (DJ)
|
||||
|
||||
For more, see [flake8-django](https://pypi.org/project/flake8-django/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| DJ001 | [model-string-field-nullable](https://github.com/charliermarsh/ruff/blob/main/docs/rules/model-string-field-nullable.md) | Avoid using `null=True` on string-based fields such as {field_name} | |
|
||||
| DJ008 | [model-dunder-str](https://github.com/charliermarsh/ruff/blob/main/docs/rules/model-dunder-str.md) | Model does not define `__str__` method | |
|
||||
| DJ013 | [receiver-decorator-checker](https://github.com/charliermarsh/ruff/blob/main/docs/rules/receiver-decorator-checker.md) | `@receiver` decorator must be on top of all the other decorators | |
|
||||
|
||||
### flake8-errmsg (EM)
|
||||
|
||||
For more, see [flake8-errmsg](https://pypi.org/project/flake8-errmsg/) on PyPI.
|
||||
@@ -1075,7 +1138,7 @@ For more, see [flake8-import-conventions](https://github.com/joaopalmeiro/flake8
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| ICN001 | import-alias-is-not-conventional | `{name}` should be imported as `{asname}` | |
|
||||
| ICN001 | [unconventional-import-alias](https://github.com/charliermarsh/ruff/blob/main/docs/rules/unconventional-import-alias.md) | `{name}` should be imported as `{asname}` | |
|
||||
|
||||
### flake8-logging-format (G)
|
||||
|
||||
@@ -1098,7 +1161,7 @@ For more, see [flake8-no-pep420](https://pypi.org/project/flake8-no-pep420/) on
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| INP001 | implicit-namespace-package | File `{filename}` is part of an implicit namespace package. Add an `__init__.py`. | |
|
||||
| INP001 | [implicit-namespace-package](https://github.com/charliermarsh/ruff/blob/main/docs/rules/implicit-namespace-package.md) | File `{filename}` is part of an implicit namespace package. Add an `__init__.py`. | |
|
||||
|
||||
### flake8-pie (PIE)
|
||||
|
||||
@@ -1106,12 +1169,13 @@ For more, see [flake8-pie](https://pypi.org/project/flake8-pie/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| PIE790 | no-unnecessary-pass | Unnecessary `pass` statement | 🛠 |
|
||||
| PIE790 | unnecessary-pass | Unnecessary `pass` statement | 🛠 |
|
||||
| PIE794 | dupe-class-field-definitions | Class field `{name}` is defined multiple times | 🛠 |
|
||||
| PIE796 | prefer-unique-enums | Enum contains duplicate value: `{value}` | |
|
||||
| PIE800 | no-unnecessary-spread | Unnecessary spread `**` | |
|
||||
| PIE804 | no-unnecessary-dict-kwargs | Unnecessary `dict` kwargs | |
|
||||
| PIE800 | unnecessary-spread | Unnecessary spread `**` | |
|
||||
| PIE804 | unnecessary-dict-kwargs | Unnecessary `dict` kwargs | |
|
||||
| PIE807 | prefer-list-builtin | Prefer `list` over useless lambda | 🛠 |
|
||||
| PIE810 | single-starts-ends-with | Call `{attr}` once with a `tuple` | |
|
||||
|
||||
### flake8-print (T20)
|
||||
|
||||
@@ -1119,8 +1183,18 @@ For more, see [flake8-print](https://pypi.org/project/flake8-print/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| T201 | print-found | `print` found | 🛠 |
|
||||
| T203 | p-print-found | `pprint` found | 🛠 |
|
||||
| T201 | print-found | `print` found | |
|
||||
| T203 | p-print-found | `pprint` found | |
|
||||
|
||||
### flake8-pyi (PYI)
|
||||
|
||||
For more, see [flake8-pyi](https://pypi.org/project/flake8-pyi/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| PYI001 | [prefix-type-params](https://github.com/charliermarsh/ruff/blob/main/docs/rules/prefix-type-params.md) | Name of private `{kind}` must start with _ | |
|
||||
| PYI007 | [unrecognized-platform-check](https://github.com/charliermarsh/ruff/blob/main/docs/rules/unrecognized-platform-check.md) | Unrecognized sys.platform check | |
|
||||
| PYI008 | [unrecognized-platform-name](https://github.com/charliermarsh/ruff/blob/main/docs/rules/unrecognized-platform-name.md) | Unrecognized platform `{platform}` | |
|
||||
|
||||
### flake8-pytest-style (PT)
|
||||
|
||||
@@ -1160,10 +1234,10 @@ For more, see [flake8-quotes](https://pypi.org/project/flake8-quotes/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| Q000 | bad-quotes-inline-string | Double quotes found but single quotes preferred | 🛠 |
|
||||
| Q001 | bad-quotes-multiline-string | Double quote multiline found but single quotes preferred | 🛠 |
|
||||
| Q002 | bad-quotes-docstring | Double quote docstring found but single quotes preferred | 🛠 |
|
||||
| Q003 | avoid-quote-escape | Change outer quotes to avoid escaping inner quotes | 🛠 |
|
||||
| Q000 | [bad-quotes-inline-string](https://github.com/charliermarsh/ruff/blob/main/docs/rules/bad-quotes-inline-string.md) | Double quotes found but single quotes preferred | 🛠 |
|
||||
| Q001 | [bad-quotes-multiline-string](https://github.com/charliermarsh/ruff/blob/main/docs/rules/bad-quotes-multiline-string.md) | Double quote multiline found but single quotes preferred | 🛠 |
|
||||
| Q002 | [bad-quotes-docstring](https://github.com/charliermarsh/ruff/blob/main/docs/rules/bad-quotes-docstring.md) | Double quote docstring found but single quotes preferred | 🛠 |
|
||||
| Q003 | [avoidable-escaped-quote](https://github.com/charliermarsh/ruff/blob/main/docs/rules/avoidable-escaped-quote.md) | Change outer quotes to avoid escaping inner quotes | 🛠 |
|
||||
|
||||
### flake8-return (RET)
|
||||
|
||||
@@ -1187,8 +1261,8 @@ For more, see [flake8-simplify](https://pypi.org/project/flake8-simplify/) on Py
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| SIM101 | duplicate-isinstance-call | Multiple `isinstance` calls for `{name}`, merge into a single call | 🛠 |
|
||||
| SIM102 | nested-if-statements | Use a single `if` statement instead of nested `if` statements | 🛠 |
|
||||
| SIM103 | return-bool-condition-directly | Return the condition `{cond}` directly | 🛠 |
|
||||
| SIM102 | collapsible-if | Use a single `if` statement instead of nested `if` statements | 🛠 |
|
||||
| SIM103 | needless-bool | Return the condition `{condition}` directly | 🛠 |
|
||||
| SIM105 | use-contextlib-suppress | Use `contextlib.suppress({exception})` instead of try-except-pass | |
|
||||
| SIM107 | return-in-try-except-finally | Don't use `return` in `try`/`except` and `finally` | |
|
||||
| SIM108 | use-ternary-operator | Use ternary operator `{contents}` instead of if-else-block | 🛠 |
|
||||
@@ -1196,6 +1270,7 @@ For more, see [flake8-simplify](https://pypi.org/project/flake8-simplify/) on Py
|
||||
| SIM110 | convert-loop-to-any | Use `{any}` instead of `for` loop | 🛠 |
|
||||
| SIM111 | convert-loop-to-all | Use `{all}` instead of `for` loop | 🛠 |
|
||||
| SIM112 | use-capital-environment-variables | Use capitalized environment variable `{expected}` instead of `{original}` | 🛠 |
|
||||
| SIM114 | [if-with-same-arms](https://github.com/charliermarsh/ruff/blob/main/docs/rules/if-with-same-arms.md) | Combine `if` branches using logical `or` operator | |
|
||||
| SIM115 | open-file-with-context-handler | Use context handler for opening files | |
|
||||
| SIM117 | multiple-with-statements | Use a single `with` statement with multiple contexts instead of nested `with` statements | 🛠 |
|
||||
| SIM118 | key-in-dict | Use `{key} in {dict}` instead of `{key} in {dict}.keys()` | 🛠 |
|
||||
@@ -1218,8 +1293,8 @@ For more, see [flake8-tidy-imports](https://pypi.org/project/flake8-tidy-imports
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| TID251 | banned-api | `{name}` is banned: {message} | |
|
||||
| TID252 | relative-imports | Relative imports from parent modules are banned | |
|
||||
| TID251 | [banned-api](https://github.com/charliermarsh/ruff/blob/main/docs/rules/banned-api.md) | `{name}` is banned: {message} | |
|
||||
| TID252 | [relative-imports](https://github.com/charliermarsh/ruff/blob/main/docs/rules/relative-imports.md) | Relative imports from parent modules are banned | 🛠 |
|
||||
|
||||
### flake8-type-checking (TCH)
|
||||
|
||||
@@ -1231,7 +1306,7 @@ For more, see [flake8-type-checking](https://pypi.org/project/flake8-type-checki
|
||||
| TCH002 | typing-only-third-party-import | Move third-party import `{}` into a type-checking block | |
|
||||
| TCH003 | typing-only-standard-library-import | Move standard library import `{}` into a type-checking block | |
|
||||
| TCH004 | runtime-import-in-type-checking-block | Move import `{}` out of type-checking block. Import is used for more than type hinting. | |
|
||||
| TCH005 | empty-type-checking-block | Found empty type-checking block | |
|
||||
| TCH005 | empty-type-checking-block | Found empty type-checking block | 🛠 |
|
||||
|
||||
### flake8-unused-arguments (ARG)
|
||||
|
||||
@@ -1283,7 +1358,7 @@ For more, see [eradicate](https://pypi.org/project/eradicate/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| ERA001 | commented-out-code | Found commented-out code | 🛠 |
|
||||
| ERA001 | [commented-out-code](https://github.com/charliermarsh/ruff/blob/main/docs/rules/commented-out-code.md) | Found commented-out code | 🛠 |
|
||||
|
||||
### pandas-vet (PD)
|
||||
|
||||
@@ -1291,7 +1366,7 @@ For more, see [pandas-vet](https://pypi.org/project/pandas-vet/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| PD002 | use-of-inplace-argument | `inplace=True` should be avoided; it has inconsistent behavior | 🛠 |
|
||||
| PD002 | [use-of-inplace-argument](https://github.com/charliermarsh/ruff/blob/main/docs/rules/use-of-inplace-argument.md) | `inplace=True` should be avoided; it has inconsistent behavior | 🛠 |
|
||||
| PD003 | use-of-dot-is-null | `.isna` is preferred to `.isnull`; functionality is equivalent | |
|
||||
| PD004 | use-of-dot-not-null | `.notna` is preferred to `.notnull`; functionality is equivalent | |
|
||||
| PD007 | use-of-dot-ix | `.ix` is deprecated; use more explicit `.loc` or `.iloc` | |
|
||||
@@ -1330,11 +1405,15 @@ For more, see [Pylint](https://pypi.org/project/pylint/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| PLE0100 | [yield-in-init](https://github.com/charliermarsh/ruff/blob/main/docs/rules/yield-in-init.md) | `__init__` method is a generator | |
|
||||
| PLE0117 | nonlocal-without-binding | Nonlocal name `{name}` found without binding | |
|
||||
| PLE0118 | used-prior-global-declaration | Name `{name}` is used prior to global declaration on line {line} | |
|
||||
| PLE0604 | invalid-all-object | Invalid object in `__all__`, must contain only strings | |
|
||||
| PLE0605 | invalid-all-format | Invalid format for `__all__`, must be `tuple` or `list` | |
|
||||
| PLE1142 | await-outside-async | `await` should be used within an async function | |
|
||||
| PLE1307 | [bad-string-format-type](https://github.com/charliermarsh/ruff/blob/main/docs/rules/bad-string-format-type.md) | Format type does not match argument type | |
|
||||
| PLE1310 | bad-str-strip-call | String `{strip}` call contains duplicate characters (did you mean `{removal}`?) | |
|
||||
| PLE2502 | bidirectional-unicode | Contains control characters that can permit obfuscated code | |
|
||||
|
||||
#### Refactor (PLR)
|
||||
|
||||
@@ -1343,6 +1422,8 @@ For more, see [Pylint](https://pypi.org/project/pylint/) on PyPI.
|
||||
| PLR0133 | comparison-of-constant | Two constants compared in a comparison, consider replacing `{left_constant} {op} {right_constant}` | |
|
||||
| PLR0206 | property-with-parameters | Cannot have defined parameters for properties | |
|
||||
| PLR0402 | consider-using-from-import | Use `from {module} import {name}` in lieu of alias | 🛠 |
|
||||
| PLR0911 | too-many-return-statements | Too many return statements ({returns}/{max_returns}) | |
|
||||
| PLR0912 | too-many-branches | Too many branches ({branches}/{max_branches}) | |
|
||||
| PLR0913 | too-many-arguments | Too many arguments to function call ({c_args}/{max_args}) | |
|
||||
| PLR0915 | too-many-statements | Too many statements ({statements}/{max_statements}) | |
|
||||
| PLR1701 | consider-merging-isinstance | Merge these isinstance calls: `isinstance({obj}, ({types}))` | |
|
||||
@@ -1362,7 +1443,7 @@ For more, see [tryceratops](https://pypi.org/project/tryceratops/1.1.0/) on PyPI
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| TRY002 | raise-vanilla-class | Create your own exception | |
|
||||
| TRY002 | [raise-vanilla-class](https://github.com/charliermarsh/ruff/blob/main/docs/rules/raise-vanilla-class.md) | Create your own exception | |
|
||||
| TRY003 | raise-vanilla-args | Avoid specifying long messages outside the exception class | |
|
||||
| TRY004 | prefer-type-error | Prefer `TypeError` exception for invalid type | 🛠 |
|
||||
| TRY200 | reraise-no-cause | Use `raise from` to specify exception cause | |
|
||||
@@ -1377,7 +1458,7 @@ For more, see [flake8-raise](https://pypi.org/project/flake8-raise/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| RSE102 | unnecessary-paren-on-raise-exception | Unnecessary parentheses on raised exception | |
|
||||
| RSE102 | unnecessary-paren-on-raise-exception | Unnecessary parentheses on raised exception | 🛠 |
|
||||
|
||||
### flake8-self (SLF)
|
||||
|
||||
@@ -1395,7 +1476,7 @@ For more, see [flake8-self](https://pypi.org/project/flake8-self/) on PyPI.
|
||||
| RUF002 | ambiguous-unicode-character-docstring | Docstring contains ambiguous unicode character '{confusable}' (did you mean '{representant}'?) | 🛠 |
|
||||
| RUF003 | ambiguous-unicode-character-comment | Comment contains ambiguous unicode character '{confusable}' (did you mean '{representant}'?) | 🛠 |
|
||||
| RUF004 | keyword-argument-before-star-argument | Keyword argument `{name}` must come after starred arguments | |
|
||||
| RUF005 | unpack-instead-of-concatenating-to-collection-literal | Consider `{expr}` instead of concatenation | |
|
||||
| RUF005 | unpack-instead-of-concatenating-to-collection-literal | Consider `{expr}` instead of concatenation | 🛠 |
|
||||
| RUF100 | unused-noqa | Unused blanket `noqa` directive | 🛠 |
|
||||
|
||||
<!-- End auto-generated sections. -->
|
||||
@@ -1556,11 +1637,11 @@ let g:ale_fixers = {
|
||||
```yaml
|
||||
tools:
|
||||
python-ruff: &python-ruff
|
||||
lint-command: "ruff --config ~/myconfigs/linters/ruff.toml --quiet ${INPUT}"
|
||||
lint-command: "ruff check --config ~/myconfigs/linters/ruff.toml --quiet ${INPUT}"
|
||||
lint-stdin: true
|
||||
lint-formats:
|
||||
- "%f:%l:%c: %m"
|
||||
format-command: "ruff --stdin-filename ${INPUT} --config ~/myconfigs/linters/ruff.toml --fix --exit-zero --quiet -"
|
||||
format-command: "ruff check --stdin-filename ${INPUT} --config ~/myconfigs/linters/ruff.toml --fix --exit-zero --quiet -"
|
||||
format-stdin: true
|
||||
```
|
||||
|
||||
@@ -1622,7 +1703,7 @@ jobs:
|
||||
pip install ruff
|
||||
# Include `--format=github` to enable automatic inline annotations.
|
||||
- name: Run Ruff
|
||||
run: ruff --format=github .
|
||||
run: ruff check --format=github .
|
||||
```
|
||||
|
||||
<!-- End section: Editor Integrations -->
|
||||
@@ -1667,6 +1748,7 @@ natively, including:
|
||||
* [flake8-comprehensions](https://pypi.org/project/flake8-comprehensions/)
|
||||
* [flake8-datetimez](https://pypi.org/project/flake8-datetimez/)
|
||||
* [flake8-debugger](https://pypi.org/project/flake8-debugger/)
|
||||
* [flake8-django](https://pypi.org/project/flake8-django/) ([#2817](https://github.com/charliermarsh/ruff/issues/2817))
|
||||
* [flake8-docstrings](https://pypi.org/project/flake8-docstrings/)
|
||||
* [flake8-eradicate](https://pypi.org/project/flake8-eradicate/)
|
||||
* [flake8-errmsg](https://pypi.org/project/flake8-errmsg/)
|
||||
@@ -1677,6 +1759,7 @@ natively, including:
|
||||
* [flake8-no-pep420](https://pypi.org/project/flake8-no-pep420)
|
||||
* [flake8-pie](https://pypi.org/project/flake8-pie/)
|
||||
* [flake8-print](https://pypi.org/project/flake8-print/)
|
||||
* [flake8-pyi](https://pypi.org/project/flake8-pyi/)
|
||||
* [flake8-pytest-style](https://pypi.org/project/flake8-pytest-style/)
|
||||
* [flake8-quotes](https://pypi.org/project/flake8-quotes/)
|
||||
* [flake8-raise](https://pypi.org/project/flake8-raise/)
|
||||
@@ -1764,6 +1847,7 @@ Today, Ruff can be used to replace Flake8 when used with any of the following pl
|
||||
* [flake8-comprehensions](https://pypi.org/project/flake8-comprehensions/)
|
||||
* [flake8-datetimez](https://pypi.org/project/flake8-datetimez/)
|
||||
* [flake8-debugger](https://pypi.org/project/flake8-debugger/)
|
||||
* [flake8-django](https://pypi.org/project/flake8-django/) ([#2817](https://github.com/charliermarsh/ruff/issues/2817))
|
||||
* [flake8-docstrings](https://pypi.org/project/flake8-docstrings/)
|
||||
* [flake8-eradicate](https://pypi.org/project/flake8-eradicate/)
|
||||
* [flake8-errmsg](https://pypi.org/project/flake8-errmsg/)
|
||||
@@ -1888,7 +1972,7 @@ matter how they're provided, which avoids accidental incompatibilities and simpl
|
||||
|
||||
### How can I tell what settings Ruff is using to check my code?
|
||||
|
||||
Run `ruff /path/to/code.py --show-settings` to view the resolved settings for a given file.
|
||||
Run `ruff check /path/to/code.py --show-settings` to view the resolved settings for a given file.
|
||||
|
||||
### I want to use Ruff, but I don't want to use `pyproject.toml`. Is that possible?
|
||||
|
||||
@@ -1948,20 +2032,29 @@ unfixable = ["B", "SIM", "TRY", "RUF"]
|
||||
|
||||
If you find a case where Ruff's autofix breaks your code, please file an Issue!
|
||||
|
||||
### How can I disable Ruff's color output?
|
||||
|
||||
Ruff's color output is powered by the [`colored`](https://crates.io/crates/colored) crate, which
|
||||
attempts to automatically detect whether the output stream supports color. However, you can force
|
||||
colors off by setting the `NO_COLOR` environment variable to any value (e.g., `NO_COLOR=1`).
|
||||
|
||||
[`colored`](https://crates.io/crates/colored) also supports the the `CLICOLOR` and `CLICOLOR_FORCE`
|
||||
environment variables (see the [spec](https://bixense.com/clicolors/)).
|
||||
|
||||
<!-- End section: FAQ -->
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome and highly appreciated. To get started, check out the
|
||||
[**contributing guidelines**](https://github.com/charliermarsh/ruff/blob/main/CONTRIBUTING.md). You
|
||||
can also join us on [**Discord**](https://discord.gg/Z8KbeK24).
|
||||
can also join us on [**Discord**](https://discord.gg/c9MhzV8aU5).
|
||||
|
||||
## Support
|
||||
|
||||
Having trouble? Check out the existing issues on [**GitHub**](https://github.com/charliermarsh/ruff/issues),
|
||||
or feel free to [**open a new one**](https://github.com/charliermarsh/ruff/issues/new).
|
||||
|
||||
You can also ask for help on [**Discord**](https://discord.gg/Z8KbeK24).
|
||||
You can also ask for help on [**Discord**](https://discord.gg/c9MhzV8aU5).
|
||||
|
||||
## Reference
|
||||
|
||||
@@ -2245,8 +2338,8 @@ fix-only = true
|
||||
|
||||
#### [`fixable`](#fixable)
|
||||
|
||||
A list of rule codes or prefixes to consider autofixable. By default, all rules are
|
||||
considered autofixable.
|
||||
A list of rule codes or prefixes to consider autofixable. By default,
|
||||
all rules are considered autofixable.
|
||||
|
||||
**Default value**: `["A", "ANN", "ARG", "B", "BLE", "C", "COM", "D", "DTZ", "E", "EM", "ERA", "EXE", "F", "FBT", "G", "I", "ICN", "INP", "ISC", "N", "PD", "PGH", "PIE", "PL", "PT", "PTH", "Q", "RET", "RUF", "S", "SIM", "T", "TCH", "TID", "TRY", "UP", "W", "YTT"]`
|
||||
|
||||
@@ -2475,6 +2568,25 @@ select = ["E", "F", "B", "Q"]
|
||||
|
||||
---
|
||||
|
||||
#### [`show-fixes`](#show-fixes)
|
||||
|
||||
Whether to show an enumeration of all autofixed lint violations
|
||||
(overridden by the `--show-fixes` command-line flag).
|
||||
|
||||
**Default value**: `false`
|
||||
|
||||
**Type**: `bool`
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```toml
|
||||
[tool.ruff]
|
||||
# By default, always enumerate fixed violations.
|
||||
show-fixes = true
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### [`show-source`](#show-source)
|
||||
|
||||
Whether to show source code snippets when reporting lint violations
|
||||
@@ -2657,6 +2769,25 @@ allow-star-arg-any = true
|
||||
|
||||
---
|
||||
|
||||
#### [`ignore-fully-untyped`](#ignore-fully-untyped)
|
||||
|
||||
Whether to suppress `ANN*` rules for any declaration
|
||||
that hasn't been typed at all.
|
||||
This makes it easier to gradually add types to a codebase.
|
||||
|
||||
**Default value**: `false`
|
||||
|
||||
**Type**: `bool`
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```toml
|
||||
[tool.ruff.flake8-annotations]
|
||||
ignore-fully-untyped = true
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### [`mypy-init-return`](#mypy-init-return)
|
||||
|
||||
Whether to allow the omission of a return type hint for `__init__` if at
|
||||
@@ -2719,8 +2850,9 @@ suppress-none-returning = true
|
||||
|
||||
#### [`check-typed-exception`](#check-typed-exception)
|
||||
|
||||
Whether to disallow `try`-`except`-`pass` (`S110`) for specific exception types. By default,
|
||||
`try`-`except`-`pass` is only disallowed for `Exception` and `BaseException`.
|
||||
Whether to disallow `try`-`except`-`pass` (`S110`) for specific
|
||||
exception types. By default, `try`-`except`-`pass` is only
|
||||
disallowed for `Exception` and `BaseException`.
|
||||
|
||||
**Default value**: `false`
|
||||
|
||||
@@ -2954,8 +3086,8 @@ The following values are supported:
|
||||
|
||||
* `csv` — a comma-separated list, e.g.
|
||||
`@pytest.mark.parametrize('name1,name2', ...)`
|
||||
* `tuple` (default) — e.g.
|
||||
`@pytest.mark.parametrize(('name1', 'name2'), ...)`
|
||||
* `tuple` (default) — e.g. `@pytest.mark.parametrize(('name1', 'name2'),
|
||||
...)`
|
||||
* `list` — e.g. `@pytest.mark.parametrize(['name1', 'name2'], ...)`
|
||||
|
||||
**Default value**: `tuple`
|
||||
@@ -2976,10 +3108,10 @@ parametrize-names-type = "list"
|
||||
Expected type for each row of values in `@pytest.mark.parametrize` in
|
||||
case of multiple parameters. The following values are supported:
|
||||
|
||||
* `tuple` (default) — e.g.
|
||||
`@pytest.mark.parametrize(('name1', 'name2'), [(1, 2), (3, 4)])`
|
||||
* `list` — e.g.
|
||||
`@pytest.mark.parametrize(('name1', 'name2'), [[1, 2], [3, 4]])`
|
||||
* `tuple` (default) — e.g. `@pytest.mark.parametrize(('name1', 'name2'),
|
||||
[(1, 2), (3, 4)])`
|
||||
* `list` — e.g. `@pytest.mark.parametrize(('name1', 'name2'), [[1, 2],
|
||||
[3, 4]])`
|
||||
|
||||
**Default value**: `tuple`
|
||||
|
||||
@@ -3349,7 +3481,7 @@ alias (e.g., `import A as B`) to wrap such that every line contains
|
||||
exactly one member. For example, this formatting would be retained,
|
||||
rather than condensing to a single line:
|
||||
|
||||
```py
|
||||
```python
|
||||
from .utils import (
|
||||
test_directory as test_directory,
|
||||
test_id as test_id
|
||||
@@ -3411,6 +3543,24 @@ known-first-party = ["src"]
|
||||
|
||||
---
|
||||
|
||||
#### [`known-local-folder`](#known-local-folder)
|
||||
|
||||
A list of modules to consider being a local folder.
|
||||
Generally, this is reserved for relative imports (`from . import module`).
|
||||
|
||||
**Default value**: `[]`
|
||||
|
||||
**Type**: `list[str]`
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```toml
|
||||
[tool.ruff.isort]
|
||||
known-local-folder = ["src"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### [`known-third-party`](#known-third-party)
|
||||
|
||||
A list of modules to consider third-party, regardless of whether they
|
||||
@@ -3432,7 +3582,7 @@ known-third-party = ["src"]
|
||||
#### [`lines-after-imports`](#lines-after-imports)
|
||||
|
||||
The number of blank lines to place after imports.
|
||||
-1 for automatic determination.
|
||||
Use `-1` for automatic determination.
|
||||
|
||||
**Default value**: `-1`
|
||||
|
||||
@@ -3448,6 +3598,24 @@ lines-after-imports = 1
|
||||
|
||||
---
|
||||
|
||||
#### [`lines-between-types`](#lines-between-types)
|
||||
|
||||
The number of lines to place between "direct" and `import from` imports.
|
||||
|
||||
**Default value**: `0`
|
||||
|
||||
**Type**: `int`
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```toml
|
||||
[tool.ruff.isort]
|
||||
# Use a single line between direct and from import
|
||||
lines-between-types = 1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### [`no-lines-before`](#no-lines-before)
|
||||
|
||||
A list of sections that should _not_ be delineated from the previous
|
||||
@@ -3742,7 +3910,8 @@ allow-magic-value-types = ["int"]
|
||||
|
||||
#### [`max-args`](#max-args)
|
||||
|
||||
Maximum number of arguments allowed for a function definition (see: `PLR0913`).
|
||||
Maximum number of arguments allowed for a function or method definition
|
||||
(see: `PLR0913`).
|
||||
|
||||
**Default value**: `5`
|
||||
|
||||
@@ -3757,9 +3926,46 @@ max-args = 5
|
||||
|
||||
---
|
||||
|
||||
#### [`max-branches`](#max-branches)
|
||||
|
||||
Maximum number of branches allowed for a function or method body (see:
|
||||
`PLR0912`).
|
||||
|
||||
**Default value**: `12`
|
||||
|
||||
**Type**: `int`
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```toml
|
||||
[tool.ruff.pylint]
|
||||
max-branches = 12
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### [`max-returns`](#max-returns)
|
||||
|
||||
Maximum number of return statements allowed for a function or method
|
||||
body (see `PLR0911`)
|
||||
|
||||
**Default value**: `6`
|
||||
|
||||
**Type**: `int`
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```toml
|
||||
[tool.ruff.pylint]
|
||||
max-returns = 6
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### [`max-statements`](#max-statements)
|
||||
|
||||
Maximum number of statements allowed for a method or a statement (see: `PLR0915`).
|
||||
Maximum number of statements allowed for a function or method body (see:
|
||||
`PLR0915`).
|
||||
|
||||
**Default value**: `50`
|
||||
|
||||
|
||||
2
_typos.toml
Normal file
2
_typos.toml
Normal file
@@ -0,0 +1,2 @@
|
||||
[files]
|
||||
extend-exclude = ["snapshots"]
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.241"
|
||||
version = "0.0.246"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
@@ -10,14 +10,10 @@ colored = { version = "2.0.0" }
|
||||
configparser = { version = "3.0.2" }
|
||||
once_cell = { version = "1.16.0" }
|
||||
regex = { version = "1.6.0" }
|
||||
ruff = { path = "..", default-features = false }
|
||||
ruff = { path = "../ruff", default-features = false }
|
||||
rustc-hash = { version = "1.1.0" }
|
||||
serde = { version = "1.0.147", features = ["derive"] }
|
||||
serde_json = { version = "1.0.87" }
|
||||
strum = { version = "0.24.1", features = ["strum_macros"] }
|
||||
strum_macros = { version = "0.24.3" }
|
||||
toml = { version = "0.6.0" }
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
[features]
|
||||
@@ -5,7 +5,9 @@ use std::path::PathBuf;
|
||||
use anyhow::Result;
|
||||
use clap::Parser;
|
||||
use configparser::ini::Ini;
|
||||
|
||||
use ruff::flake8_to_ruff::{self, ExternalConfig};
|
||||
use ruff::logging::{set_up_logging, LogLevel};
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(
|
||||
@@ -27,6 +29,8 @@ struct Args {
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
set_up_logging(&LogLevel::Default)?;
|
||||
|
||||
let args = Args::parse();
|
||||
|
||||
// Read the INI file.
|
||||
82
crates/ruff/Cargo.toml
Normal file
82
crates/ruff/Cargo.toml
Normal file
@@ -0,0 +1,82 @@
|
||||
[package]
|
||||
name = "ruff"
|
||||
version = "0.0.246"
|
||||
authors = ["Charlie Marsh <charlie.r.marsh@gmail.com>"]
|
||||
edition = "2021"
|
||||
rust-version = "1.65.0"
|
||||
documentation = "https://github.com/charliermarsh/ruff"
|
||||
homepage = "https://github.com/charliermarsh/ruff"
|
||||
repository = "https://github.com/charliermarsh/ruff"
|
||||
readme = "README.md"
|
||||
license = "MIT"
|
||||
|
||||
[lib]
|
||||
name = "ruff"
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
anyhow = { version = "1.0.66" }
|
||||
bisection = { version = "0.1.0" }
|
||||
bitflags = { version = "1.3.2" }
|
||||
cfg-if = { version = "1.0.0" }
|
||||
chrono = { version = "0.4.21", default-features = false, features = ["clock"] }
|
||||
clap = { version = "4.0.1", features = ["derive", "env"] }
|
||||
colored = { version = "2.0.0" }
|
||||
dirs = { version = "4.0.0" }
|
||||
fern = { version = "0.6.1" }
|
||||
glob = { version = "0.3.0" }
|
||||
globset = { version = "0.4.9" }
|
||||
ignore = { version = "0.4.18" }
|
||||
imperative = { version = "1.0.3" }
|
||||
itertools = { version = "0.10.5" }
|
||||
libcst = { workspace = true }
|
||||
log = { version = "0.4.17" }
|
||||
natord = { version = "1.0.9" }
|
||||
nohash-hasher = { version = "0.2.0" }
|
||||
num-bigint = { version = "0.4.3" }
|
||||
num-traits = "0.2.15"
|
||||
once_cell = { version = "1.16.0" }
|
||||
path-absolutize = { version = "3.0.14", features = ["once_cell_cache", "use_unix_paths_on_wasm"] }
|
||||
regex = { version = "1.6.0" }
|
||||
ruff_macros = { version = "0.0.246", path = "../ruff_macros" }
|
||||
ruff_python = { version = "0.0.246", path = "../ruff_python" }
|
||||
rustc-hash = { version = "1.1.0" }
|
||||
rustpython-common = { workspace = true }
|
||||
rustpython-parser = { workspace = true }
|
||||
schemars = { version = "0.8.11" }
|
||||
semver = { version = "1.0.16" }
|
||||
serde = { version = "1.0.147", features = ["derive"] }
|
||||
shellexpand = { version = "3.0.0" }
|
||||
smallvec = { version = "1.10.0" }
|
||||
strum = { version = "0.24.1", features = ["strum_macros"] }
|
||||
strum_macros = { version = "0.24.3" }
|
||||
textwrap = { version = "0.16.0" }
|
||||
thiserror = { version = "1.0" }
|
||||
titlecase = { version = "2.2.1" }
|
||||
toml = { version = "0.6.0" }
|
||||
|
||||
# https://docs.rs/getrandom/0.2.7/getrandom/#webassembly-support
|
||||
# For (future) wasm-pack support
|
||||
[target.'cfg(all(target_family = "wasm", target_os = "unknown"))'.dependencies]
|
||||
getrandom = { version = "0.2.7", features = ["js"] }
|
||||
console_error_panic_hook = { version = "0.1.7" }
|
||||
console_log = { version = "0.2.0" }
|
||||
serde-wasm-bindgen = { version = "0.4" }
|
||||
js-sys = { version = "0.3.60" }
|
||||
wasm-bindgen = { version = "0.2.83" }
|
||||
|
||||
[target.'cfg(not(target_family = "wasm"))'.dependencies]
|
||||
is_executable = "1.0.1"
|
||||
|
||||
[dev-dependencies]
|
||||
insta = { version = "1.19.0", features = ["yaml", "redactions"] }
|
||||
test-case = { version = "2.2.2" }
|
||||
wasm-bindgen-test = { version = "0.3.33" }
|
||||
|
||||
[target.'cfg(not(target_family = "wasm"))'.dev-dependencies]
|
||||
criterion = { version = "0.4.0" }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
logical_lines = []
|
||||
4
crates/ruff/resources/test/disallowed_rule_names.txt
Normal file
4
crates/ruff/resources/test/disallowed_rule_names.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
avoid-*
|
||||
do-not-*
|
||||
uses-*
|
||||
*-used
|
||||
44
crates/ruff/resources/test/fixtures/flake8_annotations/ignore_fully_untyped.py
vendored
Normal file
44
crates/ruff/resources/test/fixtures/flake8_annotations/ignore_fully_untyped.py
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
"""Test case expected to be run with `ignore_fully_untyped = True`."""
|
||||
|
||||
|
||||
def ok_fully_untyped_1(a, b):
|
||||
pass
|
||||
|
||||
|
||||
def ok_fully_untyped_2():
|
||||
pass
|
||||
|
||||
|
||||
def ok_fully_typed_1(a: int, b: int) -> int:
|
||||
pass
|
||||
|
||||
|
||||
def ok_fully_typed_2() -> int:
|
||||
pass
|
||||
|
||||
|
||||
def ok_fully_typed_3(a: int, *args: str, **kwargs: str) -> int:
|
||||
pass
|
||||
|
||||
|
||||
def error_partially_typed_1(a: int, b):
|
||||
pass
|
||||
|
||||
|
||||
def error_partially_typed_2(a: int, b) -> int:
|
||||
pass
|
||||
|
||||
|
||||
def error_partially_typed_3(a: int, b: int):
|
||||
pass
|
||||
|
||||
|
||||
class X:
|
||||
def ok_untyped_method_with_arg(self, a):
|
||||
pass
|
||||
|
||||
def ok_untyped_method(self):
|
||||
pass
|
||||
|
||||
def error_typed_self(self: X):
|
||||
pass
|
||||
@@ -53,3 +53,8 @@ def foo():
|
||||
return True
|
||||
else:
|
||||
return
|
||||
|
||||
|
||||
# Error (on the argument, but not the return type)
|
||||
def foo(a):
|
||||
a = 2 + 2
|
||||
29
crates/ruff/resources/test/fixtures/flake8_bandit/S112.py
vendored
Normal file
29
crates/ruff/resources/test/fixtures/flake8_bandit/S112.py
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
try:
|
||||
pass
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
try:
|
||||
pass
|
||||
except:
|
||||
continue
|
||||
|
||||
try:
|
||||
pass
|
||||
except (Exception,):
|
||||
continue
|
||||
|
||||
try:
|
||||
pass
|
||||
except (Exception, ValueError):
|
||||
continue
|
||||
|
||||
try:
|
||||
pass
|
||||
except ValueError:
|
||||
continue
|
||||
|
||||
try:
|
||||
pass
|
||||
except (ValueError,):
|
||||
continue
|
||||
95
crates/ruff/resources/test/fixtures/flake8_bandit/S608.py
vendored
Normal file
95
crates/ruff/resources/test/fixtures/flake8_bandit/S608.py
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
# single-line failures
|
||||
query1 = "SELECT %s FROM table" % (var,) # bad
|
||||
query2 = "SELECT var FROM " + table
|
||||
query3 = "SELECT " + val + " FROM " + table
|
||||
query4 = "SELECT {} FROM table;".format(var)
|
||||
query5 = f"SELECT * FROM table WHERE var = {var}"
|
||||
|
||||
query6 = "DELETE FROM table WHERE var = %s" % (var,)
|
||||
query7 = "DELETE FROM table WHERE VAR = " + var
|
||||
query8 = "DELETE FROM " + table + "WHERE var = " + var
|
||||
query9 = "DELETE FROM table WHERE var = {}".format(var)
|
||||
query10 = f"DELETE FROM table WHERE var = {var}"
|
||||
|
||||
query11 = "INSERT INTO table VALUES (%s)" % (var,)
|
||||
query12 = "INSERT INTO TABLE VALUES (" + var + ")"
|
||||
query13 = "INSERT INTO {} VALUES ({})".format(table, var)
|
||||
query14 = f"INSERT INTO {table} VALUES var = {var}"
|
||||
|
||||
query15 = "UPDATE %s SET var = %s" % (table, var)
|
||||
query16 = "UPDATE " + table + " SET var = " + var
|
||||
query17 = "UPDATE {} SET var = {}".format(table, var)
|
||||
query18 = f"UPDATE {table} SET var = {var}"
|
||||
|
||||
query19 = "select %s from table" % (var,)
|
||||
query20 = "select var from " + table
|
||||
query21 = "select " + val + " from " + table
|
||||
query22 = "select {} from table;".format(var)
|
||||
query23 = f"select * from table where var = {var}"
|
||||
|
||||
query24 = "delete from table where var = %s" % (var,)
|
||||
query25 = "delete from table where var = " + var
|
||||
query26 = "delete from " + table + "where var = " + var
|
||||
query27 = "delete from table where var = {}".format(var)
|
||||
query28 = f"delete from table where var = {var}"
|
||||
|
||||
query29 = "insert into table values (%s)" % (var,)
|
||||
query30 = "insert into table values (" + var + ")"
|
||||
query31 = "insert into {} values ({})".format(table, var)
|
||||
query32 = f"insert into {table} values var = {var}"
|
||||
|
||||
query33 = "update %s set var = %s" % (table, var)
|
||||
query34 = "update " + table + " set var = " + var
|
||||
query35 = "update {} set var = {}".format(table, var)
|
||||
query36 = f"update {table} set var = {var}"
|
||||
|
||||
# multi-line failures
|
||||
def query37():
|
||||
return """
|
||||
SELECT *
|
||||
FROM table
|
||||
WHERE var = %s
|
||||
""" % var
|
||||
|
||||
def query38():
|
||||
return """
|
||||
SELECT *
|
||||
FROM TABLE
|
||||
WHERE var =
|
||||
""" + var
|
||||
|
||||
def query39():
|
||||
return """
|
||||
SELECT *
|
||||
FROM table
|
||||
WHERE var = {}
|
||||
""".format(var)
|
||||
|
||||
def query40():
|
||||
return f"""
|
||||
SELECT *
|
||||
FROM table
|
||||
WHERE var = {var}
|
||||
"""
|
||||
|
||||
def query41():
|
||||
return (
|
||||
"SELECT *"
|
||||
"FROM table"
|
||||
f"WHERE var = {var}"
|
||||
)
|
||||
|
||||
# # cursor-wrapped failures
|
||||
query42 = cursor.execute("SELECT * FROM table WHERE var = %s" % var)
|
||||
query43 = cursor.execute(f"SELECT * FROM table WHERE var = {var}")
|
||||
query44 = cursor.execute("SELECT * FROM table WHERE var = {}".format(var))
|
||||
query45 = cursor.executemany("SELECT * FROM table WHERE var = %s" % var, [])
|
||||
|
||||
# # pass
|
||||
query = "SELECT * FROM table WHERE id = 1"
|
||||
query = "DELETE FROM table WHERE id = 1"
|
||||
query = "INSERT INTO table VALUES (1)"
|
||||
query = "UPDATE table SET id = 1"
|
||||
cursor.execute('SELECT * FROM table WHERE id = %s', var)
|
||||
cursor.execute('SELECT * FROM table WHERE id = 1')
|
||||
cursor.executemany('SELECT * FROM table WHERE id = %s', [var, var2])
|
||||
@@ -57,3 +57,12 @@ dict.fromkeys(("world",), True)
|
||||
{}.deploy(True, False)
|
||||
getattr(someobj, attrname, False)
|
||||
mylist.index(True)
|
||||
|
||||
|
||||
class Registry:
|
||||
def __init__(self) -> None:
|
||||
self._switches = [False] * len(Switch)
|
||||
|
||||
# FBT001: Boolean positional arg in function definition
|
||||
def __setitem__(self, switch: Switch, value: bool) -> None:
|
||||
self._switches[switch.value] = value
|
||||
@@ -80,3 +80,9 @@ def f():
|
||||
|
||||
bar = 1
|
||||
print(bar)
|
||||
|
||||
|
||||
# Unfixable due to trailing underscore (`_line_` wouldn't be considered an ignorable
|
||||
# variable name).
|
||||
for line_ in range(self.header_lines):
|
||||
fp.readline()
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user