Compare commits
133 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2fe22a223b | ||
|
|
e762dec677 | ||
|
|
19baa50003 | ||
|
|
ab0df03a05 | ||
|
|
808b348c5f | ||
|
|
e55daa89e6 | ||
|
|
b8e7d86696 | ||
|
|
ced7868559 | ||
|
|
7c344e8e4c | ||
|
|
ca38c7ac48 | ||
|
|
602291c0c2 | ||
|
|
d4cf376e9b | ||
|
|
0e6a38e6d8 | ||
|
|
058fd8748d | ||
|
|
e8247e3ed9 | ||
|
|
ea73c717be | ||
|
|
427e0c3158 | ||
|
|
dca994d05f | ||
|
|
9944246f98 | ||
|
|
82b0b7941a | ||
|
|
72453695d6 | ||
|
|
1617d715f2 | ||
|
|
c4a7344791 | ||
|
|
ea9acda732 | ||
|
|
6c8021e970 | ||
|
|
61b6ad46ea | ||
|
|
041d8108e6 | ||
|
|
e2c4a098de | ||
|
|
e865f58426 | ||
|
|
23b4e16b1d | ||
|
|
ae2ac905dc | ||
|
|
55619b321a | ||
|
|
6f31b002f8 | ||
|
|
1a79965aa0 | ||
|
|
16da183f8e | ||
|
|
3f689917cb | ||
|
|
a4a215e8a3 | ||
|
|
aa1c884910 | ||
|
|
7fb55c6d99 | ||
|
|
04ea523ad8 | ||
|
|
9897f81cf3 | ||
|
|
1a2559b001 | ||
|
|
721a1e9443 | ||
|
|
f38bba18ee | ||
|
|
14cf36f922 | ||
|
|
d28e026525 | ||
|
|
d19a8aa54d | ||
|
|
f299940452 | ||
|
|
e1ab7163ac | ||
|
|
9edc479c6c | ||
|
|
560558b814 | ||
|
|
bef601b994 | ||
|
|
7445d00b88 | ||
|
|
7c78d4e103 | ||
|
|
8b14f1b8cc | ||
|
|
5a6b51e623 | ||
|
|
0b60242fb7 | ||
|
|
65b77feeb8 | ||
|
|
04b9c0a31d | ||
|
|
49dc8231be | ||
|
|
92ca114882 | ||
|
|
553bc7443a | ||
|
|
a3af6c1ea5 | ||
|
|
b50016fe89 | ||
|
|
2cf2805848 | ||
|
|
33fbef7700 | ||
|
|
68668a584b | ||
|
|
6cd8655d29 | ||
|
|
72a9bd3cfb | ||
|
|
58aac21a36 | ||
|
|
77e0be3464 | ||
|
|
bd08fc359d | ||
|
|
19ad6ab4f5 | ||
|
|
4b2df99e78 | ||
|
|
66975876b2 | ||
|
|
7316b120ba | ||
|
|
fec887e481 | ||
|
|
bdd32c0850 | ||
|
|
10dcd5fd0a | ||
|
|
b922e6ecc8 | ||
|
|
f59799e0c4 | ||
|
|
814ddeb7ea | ||
|
|
9315b9f459 | ||
|
|
113b5a10bf | ||
|
|
fe77fb70a1 | ||
|
|
c3f6170503 | ||
|
|
a46160f0e2 | ||
|
|
9a66cf2ffb | ||
|
|
3205473612 | ||
|
|
0bb8b14ae1 | ||
|
|
9cf4621071 | ||
|
|
bbc9ed1b21 | ||
|
|
517ca2604a | ||
|
|
348ff509c0 | ||
|
|
fb545551f8 | ||
|
|
3b33a431d6 | ||
|
|
bc95690725 | ||
|
|
9dc788d089 | ||
|
|
15f63494a7 | ||
|
|
68668c20e8 | ||
|
|
9462335371 | ||
|
|
3dd6522b4f | ||
|
|
6b935121a7 | ||
|
|
8d9d9b3204 | ||
|
|
0a506eff34 | ||
|
|
7c7489c1dd | ||
|
|
ae90eccb7f | ||
|
|
7a61edbe46 | ||
|
|
59615486d8 | ||
|
|
ce116a80ad | ||
|
|
731fba9006 | ||
|
|
9bcf194fdc | ||
|
|
58949b564e | ||
|
|
6b9e57fb78 | ||
|
|
cb119401a7 | ||
|
|
0b9188011b | ||
|
|
b657d912d9 | ||
|
|
1559671093 | ||
|
|
70a53bf12b | ||
|
|
cd1e07f37c | ||
|
|
7bd6db62d9 | ||
|
|
f8b49f308d | ||
|
|
b1f9c7b6bd | ||
|
|
0867d2ded9 | ||
|
|
3f597a3b30 | ||
|
|
6733aad216 | ||
|
|
89980ad651 | ||
|
|
38f896502a | ||
|
|
7cab541343 | ||
|
|
1a3d2ead41 | ||
|
|
f96c64b40d | ||
|
|
0791869451 | ||
|
|
965918744b |
2
.github/workflows/ci.yaml
vendored
2
.github/workflows/ci.yaml
vendored
@@ -82,7 +82,7 @@ jobs:
|
||||
${{ runner.os }}-build-${{ env.cache-name }}-
|
||||
${{ runner.os }}-build-
|
||||
${{ runner.os }}-
|
||||
- run: cargo clippy --workspace --all-targets --all-features -- -D warnings
|
||||
- run: cargo clippy --workspace --all-targets --all-features -- -D warnings -W clippy::pedantic
|
||||
|
||||
cargo_test:
|
||||
name: "cargo test"
|
||||
|
||||
8
.github/workflows/flake8-to-ruff.yaml
vendored
8
.github/workflows/flake8-to-ruff.yaml
vendored
@@ -34,7 +34,6 @@ jobs:
|
||||
with:
|
||||
target: x86_64
|
||||
args: --release --out dist --sdist -m ./${{ env.CRATE_NAME }}/Cargo.toml
|
||||
maturin-version: "v0.13.0"
|
||||
- name: Install built wheel - x86_64
|
||||
run: |
|
||||
pip install dist/${{ env.CRATE_NAME }}-*.whl --force-reinstall
|
||||
@@ -61,7 +60,6 @@ jobs:
|
||||
uses: messense/maturin-action@v1
|
||||
with:
|
||||
args: --release --universal2 --out dist -m ./${{ env.CRATE_NAME }}/Cargo.toml
|
||||
maturin-version: "v0.13.0"
|
||||
- name: Install built wheel - universal2
|
||||
run: |
|
||||
pip install dist/${{ env.CRATE_NAME }}-*universal2.whl --force-reinstall
|
||||
@@ -93,7 +91,6 @@ jobs:
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
args: --release --out dist -m ./${{ env.CRATE_NAME }}/Cargo.toml
|
||||
maturin-version: "v0.13.0"
|
||||
- name: Install built wheel
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -121,7 +118,6 @@ jobs:
|
||||
target: ${{ matrix.target }}
|
||||
manylinux: auto
|
||||
args: --release --out dist -m ./${{ env.CRATE_NAME }}/Cargo.toml
|
||||
maturin-version: "v0.13.0"
|
||||
- name: Install built wheel
|
||||
if: matrix.target == 'x86_64'
|
||||
run: |
|
||||
@@ -148,7 +144,6 @@ jobs:
|
||||
target: ${{ matrix.target }}
|
||||
manylinux: auto
|
||||
args: --no-default-features --release --out dist -m ./${{ env.CRATE_NAME }}/Cargo.toml
|
||||
maturin-version: "v0.13.0"
|
||||
- uses: uraimo/run-on-arch-action@v2.0.5
|
||||
if: matrix.target != 'ppc64'
|
||||
name: Install built wheel
|
||||
@@ -187,7 +182,6 @@ jobs:
|
||||
target: ${{ matrix.target }}
|
||||
manylinux: musllinux_1_2
|
||||
args: --release --out dist -m ./${{ env.CRATE_NAME }}/Cargo.toml
|
||||
maturin-version: "v0.13.0"
|
||||
- name: Install built wheel
|
||||
if: matrix.target == 'x86_64-unknown-linux-musl'
|
||||
uses: addnab/docker-run-action@v3
|
||||
@@ -223,7 +217,6 @@ jobs:
|
||||
target: ${{ matrix.platform.target }}
|
||||
manylinux: musllinux_1_2
|
||||
args: --release --out dist -m ./${{ env.CRATE_NAME }}/Cargo.toml
|
||||
maturin-version: "v0.13.0"
|
||||
- uses: uraimo/run-on-arch-action@master
|
||||
name: Install built wheel
|
||||
with:
|
||||
@@ -261,7 +254,6 @@ jobs:
|
||||
- name: Build wheels
|
||||
uses: messense/maturin-action@v1
|
||||
with:
|
||||
maturin-version: "v0.13.0"
|
||||
target: ${{ matrix.target }}
|
||||
manylinux: auto
|
||||
args: --release --out dist -i pypy${{ matrix.python-version }} -m ./${{ env.CRATE_NAME }}/Cargo.toml
|
||||
|
||||
8
.github/workflows/ruff.yaml
vendored
8
.github/workflows/ruff.yaml
vendored
@@ -36,7 +36,6 @@ jobs:
|
||||
with:
|
||||
target: x86_64
|
||||
args: --release --out dist --sdist
|
||||
maturin-version: "v0.13.0"
|
||||
- name: Install built wheel - x86_64
|
||||
run: |
|
||||
pip install dist/${{ env.PACKAGE_NAME }}-*.whl --force-reinstall
|
||||
@@ -63,7 +62,6 @@ jobs:
|
||||
uses: messense/maturin-action@v1
|
||||
with:
|
||||
args: --release --universal2 --out dist
|
||||
maturin-version: "v0.13.0"
|
||||
- name: Install built wheel - universal2
|
||||
run: |
|
||||
pip install dist/${{ env.PACKAGE_NAME }}-*universal2.whl --force-reinstall
|
||||
@@ -95,7 +93,6 @@ jobs:
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
args: --release --out dist
|
||||
maturin-version: "v0.13.0"
|
||||
- name: Install built wheel
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -123,7 +120,6 @@ jobs:
|
||||
target: ${{ matrix.target }}
|
||||
manylinux: auto
|
||||
args: --release --out dist
|
||||
maturin-version: "v0.13.0"
|
||||
- name: Install built wheel
|
||||
if: matrix.target == 'x86_64'
|
||||
run: |
|
||||
@@ -150,7 +146,6 @@ jobs:
|
||||
target: ${{ matrix.target }}
|
||||
manylinux: auto
|
||||
args: --no-default-features --release --out dist
|
||||
maturin-version: "v0.13.0"
|
||||
- uses: uraimo/run-on-arch-action@v2.0.5
|
||||
if: matrix.target != 'ppc64'
|
||||
name: Install built wheel
|
||||
@@ -189,7 +184,6 @@ jobs:
|
||||
target: ${{ matrix.target }}
|
||||
manylinux: musllinux_1_2
|
||||
args: --release --out dist
|
||||
maturin-version: "v0.13.0"
|
||||
- name: Install built wheel
|
||||
if: matrix.target == 'x86_64-unknown-linux-musl'
|
||||
uses: addnab/docker-run-action@v3
|
||||
@@ -225,7 +219,6 @@ jobs:
|
||||
target: ${{ matrix.platform.target }}
|
||||
manylinux: musllinux_1_2
|
||||
args: --release --out dist
|
||||
maturin-version: "v0.13.0"
|
||||
- uses: uraimo/run-on-arch-action@master
|
||||
name: Install built wheel
|
||||
with:
|
||||
@@ -263,7 +256,6 @@ jobs:
|
||||
- name: Build wheels
|
||||
uses: messense/maturin-action@v1
|
||||
with:
|
||||
maturin-version: "v0.13.0"
|
||||
target: ${{ matrix.target }}
|
||||
manylinux: auto
|
||||
args: --release --out dist -i pypy${{ matrix.python-version }}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
repos:
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
rev: v0.0.131
|
||||
rev: v0.0.147
|
||||
hooks:
|
||||
- id: ruff
|
||||
|
||||
|
||||
75
Cargo.lock
generated
75
Cargo.lock
generated
@@ -290,6 +290,36 @@ dependencies = [
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_complete"
|
||||
version = "4.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7b3c9eae0de7bf8e3f904a5e40612b21fb2e2e566456d177809a48b892d24da"
|
||||
dependencies = [
|
||||
"clap 4.0.22",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_complete_command"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4160b4a4f72ef58bd766bad27c09e6ef1cc9d82a22f6a0f55d152985a4a48e31"
|
||||
dependencies = [
|
||||
"clap 4.0.22",
|
||||
"clap_complete",
|
||||
"clap_complete_fig",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_complete_fig"
|
||||
version = "4.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46b30e010e669cd021e5004f3be26cff6b7c08d2a8a0d65b48d43a8cc0efd6c3"
|
||||
dependencies = [
|
||||
"clap 4.0.22",
|
||||
"clap_complete",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.0.21"
|
||||
@@ -670,15 +700,15 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.131-dev.0"
|
||||
version = "0.0.147-dev.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.0.22",
|
||||
"configparser",
|
||||
"fnv",
|
||||
"once_cell",
|
||||
"regex",
|
||||
"ruff",
|
||||
"rustc-hash",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"toml",
|
||||
@@ -769,10 +799,17 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.0"
|
||||
name = "globset"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||
checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"bstr 0.2.17",
|
||||
"fnv",
|
||||
"log",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
@@ -1029,7 +1066,7 @@ checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
|
||||
[[package]]
|
||||
name = "libcst"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/charliermarsh/LibCST?rev=a13ec97dd4eb925bde4d426c6e422582793b260c#a13ec97dd4eb925bde4d426c6e422582793b260c"
|
||||
source = "git+https://github.com/charliermarsh/LibCST?rev=f2f0b7a487a8725d161fe8b3ed73a6758b21e177#f2f0b7a487a8725d161fe8b3ed73a6758b21e177"
|
||||
dependencies = [
|
||||
"chic",
|
||||
"itertools",
|
||||
@@ -1044,7 +1081,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "libcst_derive"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/charliermarsh/LibCST?rev=a13ec97dd4eb925bde4d426c6e422582793b260c#a13ec97dd4eb925bde4d426c6e422582793b260c"
|
||||
source = "git+https://github.com/charliermarsh/LibCST?rev=f2f0b7a487a8725d161fe8b3ed73a6758b21e177#f2f0b7a487a8725d161fe8b3ed73a6758b21e177"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
@@ -1768,7 +1805,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.131"
|
||||
version = "0.0.147"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.9.1",
|
||||
"anyhow",
|
||||
@@ -1779,6 +1816,7 @@ dependencies = [
|
||||
"cachedir",
|
||||
"chrono",
|
||||
"clap 4.0.22",
|
||||
"clap_complete_command",
|
||||
"clearscreen",
|
||||
"colored",
|
||||
"common-path",
|
||||
@@ -1786,9 +1824,8 @@ dependencies = [
|
||||
"dirs 4.0.0",
|
||||
"fern",
|
||||
"filetime",
|
||||
"fnv",
|
||||
"getrandom 0.2.8",
|
||||
"glob",
|
||||
"globset",
|
||||
"insta",
|
||||
"itertools",
|
||||
"libcst",
|
||||
@@ -1801,6 +1838,7 @@ dependencies = [
|
||||
"rayon",
|
||||
"regex",
|
||||
"ropey",
|
||||
"rustc-hash",
|
||||
"rustpython-ast",
|
||||
"rustpython-common",
|
||||
"rustpython-parser",
|
||||
@@ -1818,7 +1856,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_dev"
|
||||
version = "0.0.131"
|
||||
version = "0.0.147"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.0.22",
|
||||
@@ -1833,6 +1871,12 @@ dependencies = [
|
||||
"strum_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.20.7"
|
||||
@@ -1848,7 +1892,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-ast"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb#27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=f885db8c61514f069979861f6b3bd83292086231#f885db8c61514f069979861f6b3bd83292086231"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"rustpython-common",
|
||||
@@ -1858,7 +1902,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-common"
|
||||
version = "0.0.0"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb#27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=f885db8c61514f069979861f6b3bd83292086231#f885db8c61514f069979861f6b3bd83292086231"
|
||||
dependencies = [
|
||||
"ascii",
|
||||
"cfg-if 1.0.0",
|
||||
@@ -1881,7 +1925,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-compiler-core"
|
||||
version = "0.1.2"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb#27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=f885db8c61514f069979861f6b3bd83292086231#f885db8c61514f069979861f6b3bd83292086231"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"bitflags",
|
||||
@@ -1898,7 +1942,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-parser"
|
||||
version = "0.1.2"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb#27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=f885db8c61514f069979861f6b3bd83292086231#f885db8c61514f069979861f6b3bd83292086231"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"anyhow",
|
||||
@@ -1910,6 +1954,7 @@ dependencies = [
|
||||
"num-traits",
|
||||
"phf 0.10.1",
|
||||
"phf_codegen 0.10.0",
|
||||
"rustc-hash",
|
||||
"rustpython-ast",
|
||||
"rustpython-compiler-core",
|
||||
"thiserror",
|
||||
|
||||
16
Cargo.toml
16
Cargo.toml
@@ -6,8 +6,9 @@ members = [
|
||||
|
||||
[package]
|
||||
name = "ruff"
|
||||
version = "0.0.131"
|
||||
version = "0.0.147"
|
||||
edition = "2021"
|
||||
rust-version = "1.65.0"
|
||||
|
||||
[lib]
|
||||
name = "ruff"
|
||||
@@ -21,15 +22,15 @@ bitflags = { version = "1.3.2" }
|
||||
cachedir = { version = "0.3.0" }
|
||||
chrono = { version = "0.4.21", default-features = false, features = ["clock"] }
|
||||
clap = { version = "4.0.1", features = ["derive"] }
|
||||
clap_complete_command = "0.4.0"
|
||||
colored = { version = "2.0.0" }
|
||||
common-path = { version = "1.0.0" }
|
||||
dirs = { version = "4.0.0" }
|
||||
fern = { version = "0.6.1" }
|
||||
filetime = { version = "0.2.17" }
|
||||
fnv = { version = "1.0.7" }
|
||||
glob = { version = "0.3.0" }
|
||||
globset = {version = "0.4.9" }
|
||||
itertools = { version = "0.10.5" }
|
||||
libcst = { git = "https://github.com/charliermarsh/LibCST", rev = "a13ec97dd4eb925bde4d426c6e422582793b260c" }
|
||||
libcst = { git = "https://github.com/charliermarsh/LibCST", rev = "f2f0b7a487a8725d161fe8b3ed73a6758b21e177" }
|
||||
log = { version = "0.4.17" }
|
||||
nohash-hasher = { version = "0.2.0" }
|
||||
notify = { version = "4.0.17" }
|
||||
@@ -39,9 +40,10 @@ path-absolutize = { version = "3.0.14", features = ["once_cell_cache", "use_unix
|
||||
rayon = { version = "1.5.3" }
|
||||
regex = { version = "1.6.0" }
|
||||
ropey = { version = "1.5.0", features = ["cr_lines", "simd"], default-features = false }
|
||||
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb" }
|
||||
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb" }
|
||||
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb" }
|
||||
rustc-hash = { version = "1.1.0" }
|
||||
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "f885db8c61514f069979861f6b3bd83292086231" }
|
||||
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "f885db8c61514f069979861f6b3bd83292086231" }
|
||||
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "f885db8c61514f069979861f6b3bd83292086231" }
|
||||
serde = { version = "1.0.147", features = ["derive"] }
|
||||
serde_json = { version = "1.0.87" }
|
||||
strum = { version = "0.24.1", features = ["strum_macros"] }
|
||||
|
||||
75
LICENSE
75
LICENSE
@@ -242,6 +242,56 @@ are:
|
||||
SOFTWARE.
|
||||
"""
|
||||
|
||||
- flake8-debugger, licensed as follows:
|
||||
"""
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2016 Joseph Kahn
|
||||
|
||||
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-eradicate, licensed as follows:
|
||||
"""
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Nikita Sobolev
|
||||
|
||||
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-tidy-imports, licensed as follows:
|
||||
"""
|
||||
MIT License
|
||||
@@ -443,3 +493,28 @@ are:
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
"""
|
||||
|
||||
- RustPython, licensed as follows:
|
||||
"""
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 RustPython Team
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
@@ -10,7 +10,7 @@ fn criterion_benchmark(c: &mut Criterion) {
|
||||
b.iter(|| {
|
||||
let rope = Rope::from_str(black_box(&contents));
|
||||
rope.line_to_char(black_box(4));
|
||||
})
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
16
flake8_to_ruff/Cargo.lock
generated
16
flake8_to_ruff/Cargo.lock
generated
@@ -771,7 +771,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8_to_ruff"
|
||||
version = "0.0.131"
|
||||
version = "0.0.147"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@@ -1265,7 +1265,7 @@ checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
|
||||
[[package]]
|
||||
name = "libcst"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/charliermarsh/LibCST?rev=a13ec97dd4eb925bde4d426c6e422582793b260c#a13ec97dd4eb925bde4d426c6e422582793b260c"
|
||||
source = "git+https://github.com/charliermarsh/LibCST?rev=f2f0b7a487a8725d161fe8b3ed73a6758b21e177#f2f0b7a487a8725d161fe8b3ed73a6758b21e177"
|
||||
dependencies = [
|
||||
"chic",
|
||||
"itertools",
|
||||
@@ -1280,7 +1280,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "libcst_derive"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/charliermarsh/LibCST?rev=a13ec97dd4eb925bde4d426c6e422582793b260c#a13ec97dd4eb925bde4d426c6e422582793b260c"
|
||||
source = "git+https://github.com/charliermarsh/LibCST?rev=f2f0b7a487a8725d161fe8b3ed73a6758b21e177#f2f0b7a487a8725d161fe8b3ed73a6758b21e177"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
@@ -1975,7 +1975,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.131"
|
||||
version = "0.0.147"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
@@ -2028,7 +2028,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-ast"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb#27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=f885db8c61514f069979861f6b3bd83292086231#f885db8c61514f069979861f6b3bd83292086231"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"rustpython-common",
|
||||
@@ -2038,7 +2038,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-common"
|
||||
version = "0.0.0"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb#27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=f885db8c61514f069979861f6b3bd83292086231#f885db8c61514f069979861f6b3bd83292086231"
|
||||
dependencies = [
|
||||
"ascii",
|
||||
"cfg-if 1.0.0",
|
||||
@@ -2061,7 +2061,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-compiler-core"
|
||||
version = "0.1.2"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb#27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=f885db8c61514f069979861f6b3bd83292086231#f885db8c61514f069979861f6b3bd83292086231"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"bitflags",
|
||||
@@ -2078,7 +2078,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-parser"
|
||||
version = "0.1.2"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb#27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=f885db8c61514f069979861f6b3bd83292086231#f885db8c61514f069979861f6b3bd83292086231"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"anyhow",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.131-dev.0"
|
||||
version = "0.0.147-dev.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
@@ -10,10 +10,10 @@ name = "flake8_to_ruff"
|
||||
anyhow = { version = "1.0.66" }
|
||||
clap = { version = "4.0.1", features = ["derive"] }
|
||||
configparser = { version = "3.0.2" }
|
||||
fnv = { version = "1.0.7" }
|
||||
once_cell = { version = "1.16.0" }
|
||||
regex = { version = "1.6.0" }
|
||||
ruff = { path = "..", default-features = false }
|
||||
rustc-hash = { version = "1.1.0" }
|
||||
serde = { version = "1.0.147", features = ["derive"] }
|
||||
serde_json = { version = "1.0.87" }
|
||||
toml = { version = "0.5.9" }
|
||||
|
||||
@@ -25,7 +25,7 @@ requires-python = ">=3.7"
|
||||
repository = "https://github.com/charliermarsh/ruff#subdirectory=crates/flake8_to_ruff"
|
||||
|
||||
[build-system]
|
||||
requires = ["maturin>=0.13,<0.14"]
|
||||
requires = ["maturin>=0.14,<0.15"]
|
||||
build-backend = "maturin"
|
||||
|
||||
[tool.maturin]
|
||||
|
||||
@@ -18,7 +18,7 @@ pub fn convert(
|
||||
plugins: Option<Vec<Plugin>>,
|
||||
) -> Result<Pyproject> {
|
||||
// Extract all referenced check code prefixes, to power plugin inference.
|
||||
let mut referenced_codes: BTreeSet<CheckCodePrefix> = Default::default();
|
||||
let mut referenced_codes: BTreeSet<CheckCodePrefix> = BTreeSet::default();
|
||||
for (key, value) in flake8 {
|
||||
if let Some(value) = value {
|
||||
match key.as_str() {
|
||||
@@ -70,13 +70,13 @@ pub fn convert(
|
||||
.unwrap_or_default();
|
||||
|
||||
// Parse each supported option.
|
||||
let mut options: Options = Default::default();
|
||||
let mut flake8_annotations: flake8_annotations::settings::Options = Default::default();
|
||||
let mut flake8_bugbear: flake8_bugbear::settings::Options = Default::default();
|
||||
let mut flake8_quotes: flake8_quotes::settings::Options = Default::default();
|
||||
let mut flake8_tidy_imports: flake8_tidy_imports::settings::Options = Default::default();
|
||||
let mut mccabe: mccabe::settings::Options = Default::default();
|
||||
let mut pep8_naming: pep8_naming::settings::Options = Default::default();
|
||||
let mut options = Options::default();
|
||||
let mut flake8_annotations = flake8_annotations::settings::Options::default();
|
||||
let mut flake8_bugbear = flake8_bugbear::settings::Options::default();
|
||||
let mut flake8_quotes = flake8_quotes::settings::Options::default();
|
||||
let mut flake8_tidy_imports = flake8_tidy_imports::settings::Options::default();
|
||||
let mut mccabe = mccabe::settings::Options::default();
|
||||
let mut pep8_naming = pep8_naming::settings::Options::default();
|
||||
for (key, value) in flake8 {
|
||||
if let Some(value) = value {
|
||||
match key.as_str() {
|
||||
@@ -110,7 +110,7 @@ pub fn convert(
|
||||
match parser::parse_files_to_codes_mapping(value.as_ref()) {
|
||||
Ok(per_file_ignores) => {
|
||||
options.per_file_ignores =
|
||||
Some(parser::collect_per_file_ignores(per_file_ignores))
|
||||
Some(parser::collect_per_file_ignores(per_file_ignores));
|
||||
}
|
||||
Err(e) => eprintln!("Unable to parse '{key}' property: {e}"),
|
||||
}
|
||||
@@ -181,7 +181,7 @@ pub fn convert(
|
||||
"ban-relative-imports" | "ban_relative_imports" => match value.trim() {
|
||||
"true" => flake8_tidy_imports.ban_relative_imports = Some(Strictness::All),
|
||||
"parents" => {
|
||||
flake8_tidy_imports.ban_relative_imports = Some(Strictness::Parents)
|
||||
flake8_tidy_imports.ban_relative_imports = Some(Strictness::Parents);
|
||||
}
|
||||
_ => eprintln!("Unexpected '{key}' value: {value}"),
|
||||
},
|
||||
@@ -203,22 +203,22 @@ pub fn convert(
|
||||
// Deduplicate and sort.
|
||||
options.select = Some(Vec::from_iter(select));
|
||||
options.ignore = Some(Vec::from_iter(ignore));
|
||||
if flake8_annotations != Default::default() {
|
||||
if flake8_annotations != flake8_annotations::settings::Options::default() {
|
||||
options.flake8_annotations = Some(flake8_annotations);
|
||||
}
|
||||
if flake8_bugbear != Default::default() {
|
||||
if flake8_bugbear != flake8_bugbear::settings::Options::default() {
|
||||
options.flake8_bugbear = Some(flake8_bugbear);
|
||||
}
|
||||
if flake8_quotes != Default::default() {
|
||||
if flake8_quotes != flake8_quotes::settings::Options::default() {
|
||||
options.flake8_quotes = Some(flake8_quotes);
|
||||
}
|
||||
if flake8_tidy_imports != Default::default() {
|
||||
if flake8_tidy_imports != flake8_tidy_imports::settings::Options::default() {
|
||||
options.flake8_tidy_imports = Some(flake8_tidy_imports);
|
||||
}
|
||||
if mccabe != Default::default() {
|
||||
if mccabe != mccabe::settings::Options::default() {
|
||||
options.mccabe = Some(mccabe);
|
||||
}
|
||||
if pep8_naming != Default::default() {
|
||||
if pep8_naming != pep8_naming::settings::Options::default() {
|
||||
options.pep8_naming = Some(pep8_naming);
|
||||
}
|
||||
|
||||
@@ -248,8 +248,10 @@ mod tests {
|
||||
extend_exclude: None,
|
||||
extend_ignore: None,
|
||||
extend_select: None,
|
||||
external: None,
|
||||
fix: None,
|
||||
fixable: None,
|
||||
format: None,
|
||||
ignore: Some(vec![]),
|
||||
line_length: None,
|
||||
per_file_ignores: None,
|
||||
@@ -269,6 +271,7 @@ mod tests {
|
||||
isort: None,
|
||||
mccabe: None,
|
||||
pep8_naming: None,
|
||||
pyupgrade: None,
|
||||
});
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
@@ -287,8 +290,10 @@ mod tests {
|
||||
extend_exclude: None,
|
||||
extend_ignore: None,
|
||||
extend_select: None,
|
||||
external: None,
|
||||
fix: None,
|
||||
fixable: None,
|
||||
format: None,
|
||||
ignore: Some(vec![]),
|
||||
line_length: Some(100),
|
||||
per_file_ignores: None,
|
||||
@@ -308,6 +313,7 @@ mod tests {
|
||||
isort: None,
|
||||
mccabe: None,
|
||||
pep8_naming: None,
|
||||
pyupgrade: None,
|
||||
});
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
@@ -326,8 +332,10 @@ mod tests {
|
||||
extend_exclude: None,
|
||||
extend_ignore: None,
|
||||
extend_select: None,
|
||||
external: None,
|
||||
fix: None,
|
||||
fixable: None,
|
||||
format: None,
|
||||
ignore: Some(vec![]),
|
||||
line_length: Some(100),
|
||||
per_file_ignores: None,
|
||||
@@ -347,6 +355,7 @@ mod tests {
|
||||
isort: None,
|
||||
mccabe: None,
|
||||
pep8_naming: None,
|
||||
pyupgrade: None,
|
||||
});
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
@@ -365,8 +374,10 @@ mod tests {
|
||||
extend_exclude: None,
|
||||
extend_ignore: None,
|
||||
extend_select: None,
|
||||
external: None,
|
||||
fix: None,
|
||||
fixable: None,
|
||||
format: None,
|
||||
ignore: Some(vec![]),
|
||||
line_length: None,
|
||||
per_file_ignores: None,
|
||||
@@ -386,6 +397,7 @@ mod tests {
|
||||
isort: None,
|
||||
mccabe: None,
|
||||
pep8_naming: None,
|
||||
pyupgrade: None,
|
||||
});
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
@@ -404,8 +416,10 @@ mod tests {
|
||||
extend_exclude: None,
|
||||
extend_ignore: None,
|
||||
extend_select: None,
|
||||
external: None,
|
||||
fix: None,
|
||||
fixable: None,
|
||||
format: None,
|
||||
ignore: Some(vec![]),
|
||||
line_length: None,
|
||||
per_file_ignores: None,
|
||||
@@ -430,6 +444,7 @@ mod tests {
|
||||
isort: None,
|
||||
mccabe: None,
|
||||
pep8_naming: None,
|
||||
pyupgrade: None,
|
||||
});
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
@@ -451,8 +466,10 @@ mod tests {
|
||||
extend_exclude: None,
|
||||
extend_ignore: None,
|
||||
extend_select: None,
|
||||
external: None,
|
||||
fix: None,
|
||||
fixable: None,
|
||||
format: None,
|
||||
ignore: Some(vec![]),
|
||||
line_length: None,
|
||||
per_file_ignores: None,
|
||||
@@ -507,6 +524,7 @@ mod tests {
|
||||
isort: None,
|
||||
mccabe: None,
|
||||
pep8_naming: None,
|
||||
pyupgrade: None,
|
||||
});
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
@@ -525,8 +543,10 @@ mod tests {
|
||||
extend_exclude: None,
|
||||
extend_ignore: None,
|
||||
extend_select: None,
|
||||
external: None,
|
||||
fix: None,
|
||||
fixable: None,
|
||||
format: None,
|
||||
ignore: Some(vec![]),
|
||||
line_length: None,
|
||||
per_file_ignores: None,
|
||||
@@ -552,6 +572,7 @@ mod tests {
|
||||
isort: None,
|
||||
mccabe: None,
|
||||
pep8_naming: None,
|
||||
pyupgrade: None,
|
||||
});
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
|
||||
@@ -1,4 +1,15 @@
|
||||
#![allow(clippy::collapsible_if, clippy::collapsible_else_if)]
|
||||
#![allow(
|
||||
clippy::collapsible_else_if,
|
||||
clippy::collapsible_if,
|
||||
clippy::implicit_hasher,
|
||||
clippy::match_same_arms,
|
||||
clippy::missing_errors_doc,
|
||||
clippy::missing_panics_doc,
|
||||
clippy::module_name_repetitions,
|
||||
clippy::must_use_candidate,
|
||||
clippy::similar_names,
|
||||
clippy::too_many_lines
|
||||
)]
|
||||
|
||||
pub mod converter;
|
||||
mod parser;
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
//! Utility to generate Ruff's pyproject.toml section from a Flake8 INI file.
|
||||
#![allow(
|
||||
clippy::collapsible_else_if,
|
||||
clippy::collapsible_if,
|
||||
clippy::implicit_hasher,
|
||||
clippy::match_same_arms,
|
||||
clippy::missing_errors_doc,
|
||||
clippy::missing_panics_doc,
|
||||
clippy::module_name_repetitions,
|
||||
clippy::must_use_candidate,
|
||||
clippy::similar_names,
|
||||
clippy::too_many_lines
|
||||
)]
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use anyhow::Result;
|
||||
use fnv::FnvHashMap;
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use ruff::checks_gen::CheckCodePrefix;
|
||||
use ruff::settings::types::PatternPrefixPair;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
static COMMA_SEPARATED_LIST_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"[,\s]").unwrap());
|
||||
|
||||
@@ -31,7 +31,7 @@ pub fn parse_prefix_codes(value: &str) -> Vec<CheckCodePrefix> {
|
||||
pub fn parse_strings(value: &str) -> Vec<String> {
|
||||
COMMA_SEPARATED_LIST_RE
|
||||
.split(value)
|
||||
.map(|part| part.trim())
|
||||
.map(str::trim)
|
||||
.filter(|part| !part.is_empty())
|
||||
.map(String::from)
|
||||
.collect()
|
||||
@@ -92,7 +92,7 @@ impl State {
|
||||
});
|
||||
}
|
||||
}
|
||||
Err(_) => eprintln!("Skipping unrecognized prefix: {}", code),
|
||||
Err(_) => eprintln!("Skipping unrecognized prefix: {code}"),
|
||||
}
|
||||
}
|
||||
codes
|
||||
@@ -129,14 +129,14 @@ fn tokenize_files_to_codes_mapping(value: &str) -> Vec<Token> {
|
||||
}
|
||||
tokens.push(Token {
|
||||
token_name: TokenType::Eof,
|
||||
src: "".to_string(),
|
||||
src: String::new(),
|
||||
});
|
||||
tokens
|
||||
}
|
||||
|
||||
/// Parse a 'files-to-codes' mapping, mimicking Flake8's internal logic.
|
||||
///
|
||||
/// See: https://github.com/PyCQA/flake8/blob/7dfe99616fc2f07c0017df2ba5fa884158f3ea8a/src/flake8/utils.py#L45
|
||||
/// See: <https://github.com/PyCQA/flake8/blob/7dfe99616fc2f07c0017df2ba5fa884158f3ea8a/src/flake8/utils.py#L45>
|
||||
pub fn parse_files_to_codes_mapping(value: &str) -> Result<Vec<PatternPrefixPair>> {
|
||||
if value.trim().is_empty() {
|
||||
return Ok(vec![]);
|
||||
@@ -179,8 +179,8 @@ pub fn parse_files_to_codes_mapping(value: &str) -> Result<Vec<PatternPrefixPair
|
||||
/// Collect a list of `PatternPrefixPair` structs as a `BTreeMap`.
|
||||
pub fn collect_per_file_ignores(
|
||||
pairs: Vec<PatternPrefixPair>,
|
||||
) -> FnvHashMap<String, Vec<CheckCodePrefix>> {
|
||||
let mut per_file_ignores: FnvHashMap<String, Vec<CheckCodePrefix>> = FnvHashMap::default();
|
||||
) -> FxHashMap<String, Vec<CheckCodePrefix>> {
|
||||
let mut per_file_ignores: FxHashMap<String, Vec<CheckCodePrefix>> = FxHashMap::default();
|
||||
for pair in pairs {
|
||||
per_file_ignores
|
||||
.entry(pair.pattern)
|
||||
|
||||
@@ -6,17 +6,19 @@ use ruff::checks_gen::CheckCodePrefix;
|
||||
|
||||
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
|
||||
pub enum Plugin {
|
||||
Flake8Annotations,
|
||||
Flake8Bandit,
|
||||
Flake8BlindExcept,
|
||||
Flake8Bugbear,
|
||||
Flake8Builtins,
|
||||
Flake8Comprehensions,
|
||||
Flake8Debugger,
|
||||
Flake8Docstrings,
|
||||
Flake8TidyImports,
|
||||
Flake8Eradicate,
|
||||
Flake8Print,
|
||||
Flake8Quotes,
|
||||
Flake8Annotations,
|
||||
Flake8TidyImports,
|
||||
McCabe,
|
||||
Flake8BlindExcept,
|
||||
PEP8Naming,
|
||||
Pyupgrade,
|
||||
}
|
||||
@@ -26,16 +28,18 @@ impl FromStr for Plugin {
|
||||
|
||||
fn from_str(string: &str) -> Result<Self, Self::Err> {
|
||||
match string {
|
||||
"flake8-annotations" => Ok(Plugin::Flake8Annotations),
|
||||
"flake8-bandit" => Ok(Plugin::Flake8Bandit),
|
||||
"flake8-blind-except" => Ok(Plugin::Flake8BlindExcept),
|
||||
"flake8-bugbear" => Ok(Plugin::Flake8Bugbear),
|
||||
"flake8-builtins" => Ok(Plugin::Flake8Builtins),
|
||||
"flake8-comprehensions" => Ok(Plugin::Flake8Comprehensions),
|
||||
"flake8-debugger" => Ok(Plugin::Flake8Debugger),
|
||||
"flake8-docstrings" => Ok(Plugin::Flake8Docstrings),
|
||||
"flake8-tidy-imports" => Ok(Plugin::Flake8TidyImports),
|
||||
"flake8-eradicate" => Ok(Plugin::Flake8BlindExcept),
|
||||
"flake8-print" => Ok(Plugin::Flake8Print),
|
||||
"flake8-quotes" => Ok(Plugin::Flake8Quotes),
|
||||
"flake8-annotations" => Ok(Plugin::Flake8Annotations),
|
||||
"flake8-blind-except" => Ok(Plugin::Flake8BlindExcept),
|
||||
"flake8-tidy-imports" => Ok(Plugin::Flake8TidyImports),
|
||||
"mccabe" => Ok(Plugin::McCabe),
|
||||
"pep8-naming" => Ok(Plugin::PEP8Naming),
|
||||
"pyupgrade" => Ok(Plugin::Pyupgrade),
|
||||
@@ -47,16 +51,18 @@ impl FromStr for Plugin {
|
||||
impl Plugin {
|
||||
pub fn default(&self) -> CheckCodePrefix {
|
||||
match self {
|
||||
Plugin::Flake8Annotations => CheckCodePrefix::ANN,
|
||||
Plugin::Flake8Bandit => CheckCodePrefix::S,
|
||||
Plugin::Flake8BlindExcept => CheckCodePrefix::BLE,
|
||||
Plugin::Flake8Bugbear => CheckCodePrefix::B,
|
||||
Plugin::Flake8Builtins => CheckCodePrefix::A,
|
||||
Plugin::Flake8Comprehensions => CheckCodePrefix::C4,
|
||||
Plugin::Flake8Debugger => CheckCodePrefix::T1,
|
||||
Plugin::Flake8Docstrings => CheckCodePrefix::D,
|
||||
Plugin::Flake8TidyImports => CheckCodePrefix::I25,
|
||||
Plugin::Flake8Print => CheckCodePrefix::T,
|
||||
Plugin::Flake8Eradicate => CheckCodePrefix::ERA,
|
||||
Plugin::Flake8Print => CheckCodePrefix::T2,
|
||||
Plugin::Flake8Quotes => CheckCodePrefix::Q,
|
||||
Plugin::Flake8Annotations => CheckCodePrefix::ANN,
|
||||
Plugin::Flake8BlindExcept => CheckCodePrefix::BLE,
|
||||
Plugin::Flake8TidyImports => CheckCodePrefix::I25,
|
||||
Plugin::McCabe => CheckCodePrefix::C9,
|
||||
Plugin::PEP8Naming => CheckCodePrefix::N,
|
||||
Plugin::Pyupgrade => CheckCodePrefix::U,
|
||||
@@ -65,10 +71,13 @@ impl Plugin {
|
||||
|
||||
pub fn select(&self, flake8: &HashMap<String, Option<String>>) -> Vec<CheckCodePrefix> {
|
||||
match self {
|
||||
Plugin::Flake8Annotations => vec![CheckCodePrefix::ANN],
|
||||
Plugin::Flake8Bandit => vec![CheckCodePrefix::S],
|
||||
Plugin::Flake8BlindExcept => vec![CheckCodePrefix::BLE],
|
||||
Plugin::Flake8Bugbear => vec![CheckCodePrefix::B],
|
||||
Plugin::Flake8Builtins => vec![CheckCodePrefix::A],
|
||||
Plugin::Flake8Comprehensions => vec![CheckCodePrefix::C4],
|
||||
Plugin::Flake8Debugger => vec![CheckCodePrefix::T1],
|
||||
Plugin::Flake8Docstrings => {
|
||||
// Use the user-provided docstring.
|
||||
for key in ["docstring-convention", "docstring_convention"] {
|
||||
@@ -85,11 +94,10 @@ impl Plugin {
|
||||
// Default to PEP8.
|
||||
DocstringConvention::PEP8.select()
|
||||
}
|
||||
Plugin::Flake8TidyImports => vec![CheckCodePrefix::I25],
|
||||
Plugin::Flake8Print => vec![CheckCodePrefix::T],
|
||||
Plugin::Flake8Eradicate => vec![CheckCodePrefix::ERA],
|
||||
Plugin::Flake8Print => vec![CheckCodePrefix::T2],
|
||||
Plugin::Flake8Quotes => vec![CheckCodePrefix::Q],
|
||||
Plugin::Flake8Annotations => vec![CheckCodePrefix::ANN],
|
||||
Plugin::Flake8BlindExcept => vec![CheckCodePrefix::BLE],
|
||||
Plugin::Flake8TidyImports => vec![CheckCodePrefix::I25],
|
||||
Plugin::McCabe => vec![CheckCodePrefix::C9],
|
||||
Plugin::PEP8Naming => vec![CheckCodePrefix::N],
|
||||
Plugin::Pyupgrade => vec![CheckCodePrefix::U],
|
||||
@@ -277,31 +285,6 @@ pub fn infer_plugins_from_options(flake8: &HashMap<String, Option<String>>) -> V
|
||||
let mut plugins = BTreeSet::new();
|
||||
for key in flake8.keys() {
|
||||
match key.as_str() {
|
||||
// flake8-docstrings
|
||||
"docstring-convention" | "docstring_convention" => {
|
||||
plugins.insert(Plugin::Flake8Docstrings);
|
||||
}
|
||||
// flake8-bugbear
|
||||
"extend-immutable-calls" | "extend_immutable_calls" => {
|
||||
plugins.insert(Plugin::Flake8Bugbear);
|
||||
}
|
||||
// flake8-builtins
|
||||
"builtins-ignorelist" | "builtins_ignorelist" => {
|
||||
plugins.insert(Plugin::Flake8Builtins);
|
||||
}
|
||||
// flake8-quotes
|
||||
"quotes" | "inline-quotes" | "inline_quotes" => {
|
||||
plugins.insert(Plugin::Flake8Quotes);
|
||||
}
|
||||
"multiline-quotes" | "multiline_quotes" => {
|
||||
plugins.insert(Plugin::Flake8Quotes);
|
||||
}
|
||||
"docstring-quotes" | "docstring_quotes" => {
|
||||
plugins.insert(Plugin::Flake8Quotes);
|
||||
}
|
||||
"avoid-escape" | "avoid_escape" => {
|
||||
plugins.insert(Plugin::Flake8Quotes);
|
||||
}
|
||||
// flake8-annotations
|
||||
"suppress-none-returning" | "suppress_none_returning" => {
|
||||
plugins.insert(Plugin::Flake8Annotations);
|
||||
@@ -327,6 +310,41 @@ pub fn infer_plugins_from_options(flake8: &HashMap<String, Option<String>>) -> V
|
||||
"allow-star-arg-any" | "allow_star_arg_any" => {
|
||||
plugins.insert(Plugin::Flake8Annotations);
|
||||
}
|
||||
// flake8-bugbear
|
||||
"extend-immutable-calls" | "extend_immutable_calls" => {
|
||||
plugins.insert(Plugin::Flake8Bugbear);
|
||||
}
|
||||
// flake8-builtins
|
||||
"builtins-ignorelist" | "builtins_ignorelist" => {
|
||||
plugins.insert(Plugin::Flake8Builtins);
|
||||
}
|
||||
// flake8-docstrings
|
||||
"docstring-convention" | "docstring_convention" => {
|
||||
plugins.insert(Plugin::Flake8Docstrings);
|
||||
}
|
||||
// flake8-eradicate
|
||||
"eradicate-aggressive" | "eradicate_aggressive" => {
|
||||
plugins.insert(Plugin::Flake8Eradicate);
|
||||
}
|
||||
"eradicate-whitelist" | "eradicate_whitelist" => {
|
||||
plugins.insert(Plugin::Flake8Eradicate);
|
||||
}
|
||||
"eradicate-whitelist-extend" | "eradicate_whitelist_extend" => {
|
||||
plugins.insert(Plugin::Flake8Eradicate);
|
||||
}
|
||||
// flake8-quotes
|
||||
"quotes" | "inline-quotes" | "inline_quotes" => {
|
||||
plugins.insert(Plugin::Flake8Quotes);
|
||||
}
|
||||
"multiline-quotes" | "multiline_quotes" => {
|
||||
plugins.insert(Plugin::Flake8Quotes);
|
||||
}
|
||||
"docstring-quotes" | "docstring_quotes" => {
|
||||
plugins.insert(Plugin::Flake8Quotes);
|
||||
}
|
||||
"avoid-escape" | "avoid_escape" => {
|
||||
plugins.insert(Plugin::Flake8Quotes);
|
||||
}
|
||||
// flake8-tidy-imports
|
||||
"ban-relative-imports" | "ban_relative_imports" => {
|
||||
plugins.insert(Plugin::Flake8TidyImports);
|
||||
@@ -360,16 +378,18 @@ pub fn infer_plugins_from_options(flake8: &HashMap<String, Option<String>>) -> V
|
||||
/// `flake8-annotations` is active.
|
||||
pub fn infer_plugins_from_codes(codes: &BTreeSet<CheckCodePrefix>) -> Vec<Plugin> {
|
||||
[
|
||||
Plugin::Flake8Annotations,
|
||||
Plugin::Flake8Bandit,
|
||||
Plugin::Flake8BlindExcept,
|
||||
Plugin::Flake8Bugbear,
|
||||
Plugin::Flake8Builtins,
|
||||
Plugin::Flake8Comprehensions,
|
||||
Plugin::Flake8Debugger,
|
||||
Plugin::Flake8Docstrings,
|
||||
Plugin::Flake8TidyImports,
|
||||
Plugin::Flake8Eradicate,
|
||||
Plugin::Flake8Print,
|
||||
Plugin::Flake8Quotes,
|
||||
Plugin::Flake8Annotations,
|
||||
Plugin::Flake8BlindExcept,
|
||||
Plugin::Flake8TidyImports,
|
||||
Plugin::PEP8Naming,
|
||||
Plugin::Pyupgrade,
|
||||
]
|
||||
|
||||
@@ -25,14 +25,9 @@ requires-python = ">=3.7"
|
||||
repository = "https://github.com/charliermarsh/ruff"
|
||||
|
||||
[build-system]
|
||||
requires = ["maturin>=0.13,<0.14"]
|
||||
requires = ["maturin>=0.14,<0.15"]
|
||||
build-backend = "maturin"
|
||||
|
||||
[tool.maturin]
|
||||
bindings = "bin"
|
||||
sdist-include = ["Cargo.lock"]
|
||||
strip = true
|
||||
|
||||
[tool.isort]
|
||||
profile = "black"
|
||||
known_third_party = ["fastapi", "pydantic", "starlette"]
|
||||
|
||||
82
resources/test/fixtures/B023.py
vendored
Normal file
82
resources/test/fixtures/B023.py
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
"""
|
||||
Should emit:
|
||||
B023 - on lines 12, 13, 16, 28, 29, 30, 31, 40, 42, 50, 51, 52, 53, 61, 68.
|
||||
"""
|
||||
|
||||
functions = []
|
||||
z = 0
|
||||
|
||||
for x in range(3):
|
||||
y = x + 1
|
||||
# Subject to late-binding problems
|
||||
functions.append(lambda: x)
|
||||
functions.append(lambda: y) # not just the loop var
|
||||
|
||||
def f_bad_1():
|
||||
return x
|
||||
|
||||
# Actually OK
|
||||
functions.append(lambda x: x * 2)
|
||||
functions.append(lambda x=x: x)
|
||||
functions.append(lambda: z) # OK because not assigned in the loop
|
||||
|
||||
def f_ok_1(x):
|
||||
return x * 2
|
||||
|
||||
|
||||
def check_inside_functions_too():
|
||||
ls = [lambda: x for x in range(2)]
|
||||
st = {lambda: x for x in range(2)}
|
||||
gn = (lambda: x for x in range(2))
|
||||
dt = {x: lambda: x for x in range(2)}
|
||||
|
||||
|
||||
async def pointless_async_iterable():
|
||||
yield 1
|
||||
|
||||
|
||||
async def container_for_problems():
|
||||
async for x in pointless_async_iterable():
|
||||
functions.append(lambda: x)
|
||||
|
||||
[lambda: x async for x in pointless_async_iterable()]
|
||||
|
||||
|
||||
a = 10
|
||||
b = 0
|
||||
while True:
|
||||
a = a_ = a - 1
|
||||
b += 1
|
||||
functions.append(lambda: a)
|
||||
functions.append(lambda: a_)
|
||||
functions.append(lambda: b)
|
||||
functions.append(lambda: c) # not a name error because of late binding!
|
||||
c: bool = a > 3
|
||||
if not c:
|
||||
break
|
||||
|
||||
# Nested loops should not duplicate reports
|
||||
for j in range(2):
|
||||
for k in range(3):
|
||||
lambda: j * k
|
||||
|
||||
|
||||
for j, k, l in [(1, 2, 3)]:
|
||||
|
||||
def f():
|
||||
j = None # OK because it's an assignment
|
||||
[l for k in range(2)] # error for l, not for k
|
||||
|
||||
assert a and functions
|
||||
|
||||
a.attribute = 1 # modifying an attribute doesn't make it a loop variable
|
||||
functions[0] = lambda: None # same for an element
|
||||
|
||||
for var in range(2):
|
||||
|
||||
def explicit_capture(captured=var):
|
||||
return captured
|
||||
|
||||
|
||||
for i in range(3):
|
||||
lambda: f"{i}"
|
||||
55
resources/test/fixtures/B904.py
vendored
Normal file
55
resources/test/fixtures/B904.py
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
"""
|
||||
Should emit:
|
||||
B904 - on lines 10, 11 and 16
|
||||
"""
|
||||
|
||||
try:
|
||||
raise ValueError
|
||||
except ValueError:
|
||||
if "abc":
|
||||
raise TypeError
|
||||
raise UserWarning
|
||||
except AssertionError:
|
||||
raise # Bare `raise` should not be an error
|
||||
except Exception as err:
|
||||
assert err
|
||||
raise Exception("No cause here...")
|
||||
except BaseException as base_err:
|
||||
# Might use this instead of bare raise with the `.with_traceback()` method
|
||||
raise base_err
|
||||
finally:
|
||||
raise Exception("Nothing to chain from, so no warning here")
|
||||
|
||||
try:
|
||||
raise ValueError
|
||||
except ValueError:
|
||||
# should not emit, since we are not raising something
|
||||
def proxy():
|
||||
raise NameError
|
||||
|
||||
|
||||
try:
|
||||
from preferred_library import Thing
|
||||
except ImportError:
|
||||
try:
|
||||
from fallback_library import Thing
|
||||
except ImportError:
|
||||
|
||||
class Thing:
|
||||
def __getattr__(self, name):
|
||||
# same as the case above, should not emit.
|
||||
raise AttributeError
|
||||
|
||||
|
||||
try:
|
||||
from preferred_library import Thing
|
||||
except ImportError:
|
||||
try:
|
||||
from fallback_library import Thing
|
||||
except ImportError:
|
||||
|
||||
def context_switch():
|
||||
try:
|
||||
raise ValueError
|
||||
except ValueError:
|
||||
raise
|
||||
30
resources/test/fixtures/C901.py
vendored
30
resources/test/fixtures/C901.py
vendored
@@ -106,3 +106,33 @@ async def foobar(a, b, c):
|
||||
# Complexity = 1
|
||||
def annotated_assign():
|
||||
x: Any = None
|
||||
|
||||
|
||||
# Complexity = 9
|
||||
class Class:
|
||||
def handle(self, *args, **options):
|
||||
if args:
|
||||
return
|
||||
|
||||
class ServiceProvider:
|
||||
def a(self):
|
||||
pass
|
||||
|
||||
def b(self, data):
|
||||
if not args:
|
||||
pass
|
||||
|
||||
class Logger:
|
||||
def c(*args, **kwargs):
|
||||
pass
|
||||
|
||||
def error(self, message):
|
||||
pass
|
||||
|
||||
def info(self, message):
|
||||
pass
|
||||
|
||||
def exception(self):
|
||||
pass
|
||||
|
||||
return ServiceProvider(Logger())
|
||||
|
||||
7
resources/test/fixtures/D.py
vendored
7
resources/test/fixtures/D.py
vendored
@@ -3,6 +3,7 @@ from functools import wraps
|
||||
import os
|
||||
from .expected import Expectation
|
||||
from typing import overload
|
||||
from typing_extensions import override
|
||||
|
||||
|
||||
expectation = Expectation()
|
||||
@@ -42,9 +43,13 @@ class class_:
|
||||
"D418: Function/ Method decorated with @overload"
|
||||
" shouldn't contain a docstring")
|
||||
|
||||
@override
|
||||
def overridden_method(a):
|
||||
return str(a)
|
||||
|
||||
@property
|
||||
def foo(self):
|
||||
"""The foo of the thing, which isn't in imperitive mood."""
|
||||
"""The foo of the thing, which isn't in imperative mood."""
|
||||
return "hello"
|
||||
|
||||
@expect('D102: Missing docstring in public method')
|
||||
|
||||
6
resources/test/fixtures/E501.py
vendored
6
resources/test/fixtures/E501.py
vendored
@@ -49,3 +49,9 @@ sit amet consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labor
|
||||
sit amet consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
||||
""", # noqa: E501
|
||||
}
|
||||
|
||||
# OK
|
||||
# A very long URL: https://loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong.url.com
|
||||
|
||||
# OK
|
||||
# https://loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong.url.com
|
||||
|
||||
13
resources/test/fixtures/ERA001.py
vendored
Normal file
13
resources/test/fixtures/ERA001.py
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
#import os
|
||||
# from foo import junk
|
||||
#a = 3
|
||||
a = 4
|
||||
#foo(1, 2, 3)
|
||||
|
||||
def foo(x, y, z):
|
||||
contentet = 1 # print('hello')
|
||||
print(x, y, z)
|
||||
|
||||
# This is a real comment.
|
||||
#return True
|
||||
return False
|
||||
13
resources/test/fixtures/F502.py
vendored
Normal file
13
resources/test/fixtures/F502.py
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
dog = {"bob": "bob"}
|
||||
|
||||
"%(bob)s" % dog
|
||||
"%(bob)s" % {"bob": "bob"}
|
||||
"%(bob)s" % {**{"bob": "bob"}}
|
||||
"%(bob)s" % ["bob"] # F202
|
||||
"%(bob)s" % ("bob",) # F202
|
||||
"%(bob)s" % {"bob"} # F202
|
||||
"%(bob)s" % [*["bob"]] # F202
|
||||
"%(bob)s" % {"bob": "bob" for _ in range(1)}
|
||||
"%(bob)s" % ["bob" for _ in range(1)] # F202
|
||||
"%(bob)s" % ("bob" for _ in range(1)) # F202
|
||||
"%(bob)s" % {"bob" for _ in range(1)} # F202
|
||||
26
resources/test/fixtures/F503.py
vendored
Normal file
26
resources/test/fixtures/F503.py
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
dog = {"bob": "bob"}
|
||||
|
||||
# Single placeholder always fine
|
||||
"%s" % dog
|
||||
"%s" % {"bob": "bob"}
|
||||
"%s" % {**{"bob": "bob"}}
|
||||
"%s" % ["bob"]
|
||||
"%s" % ("bob",)
|
||||
"%s" % {"bob"}
|
||||
"%s" % [*["bob"]]
|
||||
"%s" % {"bob": "bob" for _ in range(1)}
|
||||
"%s" % ["bob" for _ in range(1)]
|
||||
"%s" % ("bob" for _ in range(1))
|
||||
"%s" % {"bob" for _ in range(1)}
|
||||
# Multiple placeholders
|
||||
"%s %s" % dog
|
||||
"%s %s" % {"bob": "bob"} # F503
|
||||
"%s %s" % {**{"bob": "bob"}} # F503
|
||||
"%s %s" % ["bob"]
|
||||
"%s %s" % ("bob",)
|
||||
"%s %s" % {"bob"}
|
||||
"%s %s" % [*["bob"]]
|
||||
"%s %s" % {"bob": "bob" for _ in range(1)} # F503
|
||||
"%s %s" % ["bob" for _ in range(1)]
|
||||
"%s %s" % ("bob" for _ in range(1))
|
||||
"%s %s" % {"bob" for _ in range(1)}
|
||||
6
resources/test/fixtures/F504.py
vendored
Normal file
6
resources/test/fixtures/F504.py
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
# Ruff has no way of knowing if the following are F505s
|
||||
a = "wrong"
|
||||
"%(a)s %(c)s" % {a: "?", "b": "!"} # F504 ("b" not used)
|
||||
|
||||
hidden = {"a": "!"}
|
||||
"%(a)s %(c)s" % {"x": 1, **hidden} # Ok (cannot see through splat)
|
||||
25
resources/test/fixtures/F50x.py
vendored
Normal file
25
resources/test/fixtures/F50x.py
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
'%(foo)' % {'foo': 'bar'} # F501
|
||||
'%s %(foo)s' % {'foo': 'bar'} # F506
|
||||
'%(foo)s %s' % {'foo': 'bar'} # F506
|
||||
'%j' % (1,) # F509
|
||||
'%s %s' % (1,) # F507
|
||||
'%s %s' % (1, 2, 3) # F507
|
||||
'%(bar)s' % {} # F505
|
||||
'%(bar)s' % {'bar': 1, 'baz': 2} # F504
|
||||
'%(bar)s' % (1, 2, 3) # F502
|
||||
'%s %s' % {'k': 'v'} # F503
|
||||
'%(bar)*s' % {'bar': 'baz'} # F506, F508
|
||||
|
||||
# ok: single %s with mapping
|
||||
'%s' % {'foo': 'bar', 'baz': 'womp'}
|
||||
# ok: %% should not count towards placeholder count
|
||||
'%% %s %% %s' % (1, 2)
|
||||
# ok: * consumes one positional argument
|
||||
'%.*f' % (2, 1.1234)
|
||||
'%*.*f' % (5, 2, 3.1234)
|
||||
# ok *args and **kwargs
|
||||
a = []
|
||||
'%s %s' % [*a]
|
||||
'%s %s' % (*a,)
|
||||
k = {}
|
||||
'%(k)s' % {**k}
|
||||
21
resources/test/fixtures/F521.py
vendored
Normal file
21
resources/test/fixtures/F521.py
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
"{".format(1)
|
||||
"}".format(1)
|
||||
"{foo[}".format(foo=1)
|
||||
# too much string recursion (placeholder-in-placeholder)
|
||||
"{:{:{}}}".format(1, 2, 3)
|
||||
# ruff picks these issues up, but flake8 doesn't
|
||||
"{foo[]}".format(foo={"": 1})
|
||||
"{foo..}".format(foo=1)
|
||||
"{foo..bar}".format(foo=1)
|
||||
|
||||
# The following are all "good" uses of .format
|
||||
"{.__class__}".format("")
|
||||
"{foo[bar]}".format(foo={"bar": "barv"})
|
||||
"{[bar]}".format({"bar": "barv"})
|
||||
"{:{}} {}".format(1, 15, 2)
|
||||
"{:2}".format(1)
|
||||
"{foo}-{}".format(1, foo=2)
|
||||
a = ()
|
||||
"{}".format(*a)
|
||||
k = {}
|
||||
"{foo}".format(**k)
|
||||
4
resources/test/fixtures/F522.py
vendored
Normal file
4
resources/test/fixtures/F522.py
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
"{}".format(1, bar=2) # F522
|
||||
"{bar}{}".format(1, bar=2, spam=3) # F522
|
||||
"{bar:{spam}}".format(bar=2, spam=3) # No issues
|
||||
"{bar:{spam}}".format(bar=2, spam=3, eggs=4, ham=5) # F522
|
||||
12
resources/test/fixtures/F523.py
vendored
Normal file
12
resources/test/fixtures/F523.py
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
# With indexes
|
||||
"{0}".format(1, 2) # F523
|
||||
"{1}".format(1, 2, 3) # F523
|
||||
"{1:{0}}".format(1, 2) # No issues
|
||||
"{1:{0}}".format(1, 2, 3) # F523
|
||||
"{0}{2}".format(1, 2) # F523, # F524
|
||||
|
||||
# With no indexes
|
||||
"{}".format(1, 2) # F523
|
||||
"{}".format(1, 2, 3) # F523
|
||||
"{:{}}".format(1, 2) # No issues
|
||||
"{:{}}".format(1, 2, 3) # F523
|
||||
6
resources/test/fixtures/F524.py
vendored
Normal file
6
resources/test/fixtures/F524.py
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
"{} {}".format(1) # F524
|
||||
"{2}".format() # F524
|
||||
"{bar}".format() # F524
|
||||
"{0} {bar}".format(1) # F524
|
||||
"{0} {bar}".format() # F524
|
||||
"{bar} {0}".format() # F524
|
||||
2
resources/test/fixtures/F525.py
vendored
Normal file
2
resources/test/fixtures/F525.py
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
"{} {1}".format(1, 2) # F525
|
||||
"{0} {}".format(1, 2) # F523, F525
|
||||
10
resources/test/fixtures/F821_3.py
vendored
10
resources/test/fixtures/F821_3.py
vendored
@@ -12,3 +12,13 @@ x: dict["key", "value"]
|
||||
|
||||
# OK
|
||||
x: dict[str, str]
|
||||
|
||||
# OK
|
||||
def unimportant(name):
|
||||
pass
|
||||
|
||||
|
||||
def dang(dict, set, list):
|
||||
unimportant(name=dict["name"])
|
||||
unimportant(name=set["name"])
|
||||
unimportant(name=list["name"])
|
||||
|
||||
13
resources/test/fixtures/F841.py
vendored
13
resources/test/fixtures/F841.py
vendored
@@ -52,3 +52,16 @@ def f5():
|
||||
|
||||
def f7():
|
||||
nonlocal b
|
||||
|
||||
|
||||
def f6():
|
||||
annotations = []
|
||||
assert len([annotations for annotations in annotations])
|
||||
|
||||
|
||||
def f7():
|
||||
def connect():
|
||||
return None, None
|
||||
|
||||
with connect() as (connection, cursor):
|
||||
cursor.execute("SELECT * FROM users")
|
||||
|
||||
15
resources/test/fixtures/FBT.py
vendored
15
resources/test/fixtures/FBT.py
vendored
@@ -38,5 +38,20 @@ def function(
|
||||
def used(do):
|
||||
return do
|
||||
|
||||
|
||||
used("a", True)
|
||||
used(do=True)
|
||||
|
||||
|
||||
# Avoid FBT003 for explicitly allowed methods.
|
||||
"""
|
||||
FBT003 Boolean positional value on dict
|
||||
"""
|
||||
a = {"a": "b"}
|
||||
a.get("hello", False)
|
||||
{}.get("hello", False)
|
||||
{}.setdefault("hello", True)
|
||||
{}.pop("hello", False)
|
||||
{}.pop(True, False)
|
||||
dict.fromkeys(("world",), True)
|
||||
{}.deploy(True, False)
|
||||
|
||||
3
resources/test/fixtures/M001.py
vendored
3
resources/test/fixtures/M001.py
vendored
@@ -18,6 +18,9 @@ def f() -> None:
|
||||
# Invalid (and unimplemented)
|
||||
d = 1 # noqa: F841, W191
|
||||
|
||||
# Invalid (but external)
|
||||
d = 1 # noqa: F841, V101
|
||||
|
||||
# fmt: off
|
||||
# Invalid - no space before #
|
||||
d = 1# noqa: E501
|
||||
|
||||
8
resources/test/fixtures/N804.py
vendored
8
resources/test/fixtures/N804.py
vendored
@@ -30,6 +30,14 @@ class Class:
|
||||
def __init_subclass__(self, default_name, **kwargs):
|
||||
...
|
||||
|
||||
@classmethod
|
||||
def class_method_with_positional_only_argument(cls, x, /, other):
|
||||
...
|
||||
|
||||
@classmethod
|
||||
def bad_class_method_with_positional_only_argument(self, x, /, other):
|
||||
...
|
||||
|
||||
|
||||
class MetaClass(ABCMeta):
|
||||
def bad_method(self):
|
||||
|
||||
21
resources/test/fixtures/N807.py
vendored
21
resources/test/fixtures/N807.py
vendored
@@ -10,6 +10,27 @@ def good__():
|
||||
pass
|
||||
|
||||
|
||||
def nested():
|
||||
def __bad__():
|
||||
pass
|
||||
|
||||
def __good():
|
||||
pass
|
||||
|
||||
def good__():
|
||||
pass
|
||||
|
||||
|
||||
class Class:
|
||||
def __good__(self):
|
||||
pass
|
||||
|
||||
|
||||
# https://peps.python.org/pep-0562/
|
||||
def __getattr__(name):
|
||||
pass
|
||||
|
||||
|
||||
# https://peps.python.org/pep-0562/
|
||||
def __dir__():
|
||||
pass
|
||||
|
||||
5
resources/test/fixtures/RUF101_0.py
vendored
Normal file
5
resources/test/fixtures/RUF101_0.py
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
exit(0)
|
||||
|
||||
|
||||
def main():
|
||||
exit(2)
|
||||
10
resources/test/fixtures/RUF101_1.py
vendored
Normal file
10
resources/test/fixtures/RUF101_1.py
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
import sys
|
||||
|
||||
exit(0)
|
||||
|
||||
|
||||
def main():
|
||||
exit(1)
|
||||
|
||||
|
||||
sys.exit(2)
|
||||
7
resources/test/fixtures/RUF101_2.py
vendored
Normal file
7
resources/test/fixtures/RUF101_2.py
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
import sys as sys2
|
||||
|
||||
exit(0)
|
||||
|
||||
|
||||
def main():
|
||||
exit(1)
|
||||
7
resources/test/fixtures/RUF101_3.py
vendored
Normal file
7
resources/test/fixtures/RUF101_3.py
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
from sys import exit
|
||||
|
||||
exit(0)
|
||||
|
||||
|
||||
def main():
|
||||
exit(1)
|
||||
7
resources/test/fixtures/RUF101_4.py
vendored
Normal file
7
resources/test/fixtures/RUF101_4.py
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
from sys import exit as exit2
|
||||
|
||||
exit(0)
|
||||
|
||||
|
||||
def main():
|
||||
exit(1)
|
||||
7
resources/test/fixtures/RUF101_5.py
vendored
Normal file
7
resources/test/fixtures/RUF101_5.py
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
from sys import *
|
||||
|
||||
exit(0)
|
||||
|
||||
|
||||
def main():
|
||||
exit(1)
|
||||
12
resources/test/fixtures/RUF101_6.py
vendored
Normal file
12
resources/test/fixtures/RUF101_6.py
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
exit(0)
|
||||
|
||||
|
||||
def exit(e):
|
||||
pass
|
||||
|
||||
|
||||
exit(1)
|
||||
|
||||
|
||||
def main():
|
||||
exit(2)
|
||||
14
resources/test/fixtures/T100.py
vendored
Normal file
14
resources/test/fixtures/T100.py
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
breakpoint()
|
||||
|
||||
|
||||
import pdb
|
||||
from builtins import breakpoint
|
||||
from pdb import set_trace as st
|
||||
from celery.contrib.rdb import set_trace
|
||||
from celery.contrib import rdb
|
||||
import celery.contrib.rdb
|
||||
|
||||
|
||||
breakpoint()
|
||||
st()
|
||||
set_trace()
|
||||
4
resources/test/fixtures/U006.py
vendored
4
resources/test/fixtures/U006.py
vendored
@@ -24,3 +24,7 @@ from typing import List as IList
|
||||
|
||||
def f(x: IList[str]) -> None:
|
||||
...
|
||||
|
||||
|
||||
def f(x: "List[str]") -> None:
|
||||
...
|
||||
|
||||
29
resources/test/fixtures/U007.py
vendored
29
resources/test/fixtures/U007.py
vendored
@@ -1,40 +1,43 @@
|
||||
import typing
|
||||
from typing import Optional
|
||||
from typing import Union
|
||||
|
||||
|
||||
def f(x: Optional[str]) -> None:
|
||||
...
|
||||
|
||||
|
||||
import typing
|
||||
|
||||
|
||||
def f(x: typing.Optional[str]) -> None:
|
||||
...
|
||||
|
||||
|
||||
from typing import Union
|
||||
|
||||
|
||||
def f(x: Union[str, int, Union[float, bytes]]) -> None:
|
||||
...
|
||||
|
||||
|
||||
import typing
|
||||
|
||||
|
||||
def f(x: typing.Union[str, int]) -> None:
|
||||
...
|
||||
|
||||
|
||||
from typing import Union
|
||||
def f(x: typing.Union[(str, int)]) -> None:
|
||||
...
|
||||
|
||||
|
||||
def f(x: typing.Union[(str, int), float]) -> None:
|
||||
...
|
||||
|
||||
|
||||
def f(x: "Union[str, int, Union[float, bytes]]") -> None:
|
||||
...
|
||||
|
||||
|
||||
import typing
|
||||
|
||||
|
||||
def f(x: "typing.Union[str, int]") -> None:
|
||||
...
|
||||
|
||||
|
||||
def f(x: Union["str", int]) -> None:
|
||||
...
|
||||
|
||||
|
||||
def f(x: Union[("str", "int"), float]) -> None:
|
||||
...
|
||||
|
||||
2
resources/test/fixtures/U009_0.py
vendored
2
resources/test/fixtures/U009_0.py
vendored
@@ -1,3 +1,3 @@
|
||||
# coding=utf8
|
||||
|
||||
print('Hello world')
|
||||
print("Hello world")
|
||||
|
||||
3
resources/test/fixtures/U009_4.py
vendored
Normal file
3
resources/test/fixtures/U009_4.py
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# coding=utf8 # noqa: U009
|
||||
|
||||
print("Hello world")
|
||||
80
resources/test/fixtures/U015.py
vendored
Normal file
80
resources/test/fixtures/U015.py
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
open("foo", "U")
|
||||
open("foo", "Ur")
|
||||
open("foo", "Ub")
|
||||
open("foo", "rUb")
|
||||
open("foo", "r")
|
||||
open("foo", "rt")
|
||||
open("f", "r", encoding="UTF-8")
|
||||
open("f", "wt")
|
||||
|
||||
with open("foo", "U") as f:
|
||||
pass
|
||||
with open("foo", "Ur") as f:
|
||||
pass
|
||||
with open("foo", "Ub") as f:
|
||||
pass
|
||||
with open("foo", "rUb") as f:
|
||||
pass
|
||||
with open("foo", "r") as f:
|
||||
pass
|
||||
with open("foo", "rt") as f:
|
||||
pass
|
||||
with open("foo", "r", encoding="UTF-8") as f:
|
||||
pass
|
||||
with open("foo", "wt") as f:
|
||||
pass
|
||||
|
||||
open(f("a", "b", "c"), "U")
|
||||
open(f("a", "b", "c"), "Ub")
|
||||
|
||||
with open(f("a", "b", "c"), "U") as f:
|
||||
pass
|
||||
with open(f("a", "b", "c"), "Ub") as f:
|
||||
pass
|
||||
|
||||
with open("foo", "U") as fa, open("bar", "U") as fb:
|
||||
pass
|
||||
with open("foo", "Ub") as fa, open("bar", "Ub") as fb:
|
||||
pass
|
||||
|
||||
open("foo", mode="U")
|
||||
open(name="foo", mode="U")
|
||||
open(mode="U", name="foo")
|
||||
|
||||
with open("foo", mode="U") as f:
|
||||
pass
|
||||
with open(name="foo", mode="U") as f:
|
||||
pass
|
||||
with open(mode="U", name="foo") as f:
|
||||
pass
|
||||
|
||||
open("foo", mode="Ub")
|
||||
open(name="foo", mode="Ub")
|
||||
open(mode="Ub", name="foo")
|
||||
|
||||
with open("foo", mode="Ub") as f:
|
||||
pass
|
||||
with open(name="foo", mode="Ub") as f:
|
||||
pass
|
||||
with open(mode="Ub", name="foo") as f:
|
||||
pass
|
||||
|
||||
open(file="foo", mode='U', buffering=- 1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
|
||||
open(file="foo", buffering=- 1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='U')
|
||||
open(file="foo", buffering=- 1, encoding=None, errors=None, mode='U', newline=None, closefd=True, opener=None)
|
||||
open(mode='U', file="foo", buffering=- 1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
|
||||
|
||||
open(file="foo", mode='Ub', buffering=- 1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
|
||||
open(file="foo", buffering=- 1, encoding=None, errors=None, newline=None, closefd=True, opener=None, mode='Ub')
|
||||
open(file="foo", buffering=- 1, encoding=None, errors=None, mode='Ub', newline=None, closefd=True, opener=None)
|
||||
open(mode='Ub', file="foo", buffering=- 1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
|
||||
|
||||
open = 1
|
||||
open("foo", "U")
|
||||
open("foo", "Ur")
|
||||
open("foo", "Ub")
|
||||
open("foo", "rUb")
|
||||
open("foo", "r")
|
||||
open("foo", "rt")
|
||||
open("f", "r", encoding="UTF-8")
|
||||
open("f", "wt")
|
||||
@@ -44,7 +44,7 @@ expectation.expected.add((
|
||||
@expect("D407: Missing dashed underline after section ('Returns')",
|
||||
arg_count=3)
|
||||
@expect("D413: Missing blank line after last section ('Raises')", arg_count=3)
|
||||
def fetch_bigtable_rows(big_table, keys, other_silly_variable=None):
|
||||
def fetch_bigtable_rows(big_table, keys, other_silly_variable=None, **kwargs):
|
||||
"""Fetches rows from a Bigtable.
|
||||
|
||||
Retrieves rows pertaining to the given keys from the Table instance
|
||||
@@ -57,6 +57,7 @@ def fetch_bigtable_rows(big_table, keys, other_silly_variable=None):
|
||||
to fetch.
|
||||
other_silly_variable: Another optional variable, that has a much
|
||||
longer name than the other args, and which does nothing.
|
||||
**kwargs: More keyword arguments.
|
||||
|
||||
Returns:
|
||||
A dict mapping keys to the corresponding table row data
|
||||
|
||||
@@ -73,7 +73,7 @@ expectation.expected.add((
|
||||
"(found 'A')", arg_count=3)
|
||||
@expect("D413: Missing blank line after last section ('Examples')",
|
||||
arg_count=3)
|
||||
def foo(var1, var2, long_var_name='hi'):
|
||||
def foo(var1, var2, long_var_name='hi', **kwargs):
|
||||
r"""A one-line summary that does not use variable names.
|
||||
|
||||
Several sentences providing an extended description. Refer to
|
||||
@@ -91,6 +91,8 @@ def foo(var1, var2, long_var_name='hi'):
|
||||
detail, e.g. ``(N,) ndarray`` or ``array_like``.
|
||||
long_var_name : {'hi', 'ho'}, optional
|
||||
Choices in brackets, default first when optional.
|
||||
**kwargs : int
|
||||
More keyword arguments.
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
||||
10
resources/test/fixtures/future_annotations.py
vendored
10
resources/test/fixtures/future_annotations.py
vendored
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import List, Optional
|
||||
|
||||
from models import (
|
||||
Fruit,
|
||||
@@ -28,3 +29,12 @@ class Foo:
|
||||
@classmethod
|
||||
def d(cls) -> Fruit:
|
||||
return cls(x=0, y=0)
|
||||
|
||||
|
||||
def f(x: int) -> List[int]:
|
||||
y = List[int]()
|
||||
y.append(x)
|
||||
return y
|
||||
|
||||
|
||||
x: Optional[int] = None
|
||||
|
||||
4
resources/test/fixtures/isort/order_relative_imports_by_level.py
vendored
Normal file
4
resources/test/fixtures/isort/order_relative_imports_by_level.py
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
from .a import a
|
||||
from ..a import a
|
||||
from ..b import a
|
||||
from .b import a
|
||||
1
resources/test/fixtures/pyproject.toml
vendored
1
resources/test/fixtures/pyproject.toml
vendored
@@ -5,6 +5,7 @@ extend-exclude = [
|
||||
"migrations",
|
||||
"with_excluded_file/other_excluded_file.py",
|
||||
]
|
||||
external = ["V101"]
|
||||
per-file-ignores = { "__init__.py" = ["F401"] }
|
||||
|
||||
[tool.ruff.flake8-bugbear]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff_dev"
|
||||
version = "0.0.131"
|
||||
version = "0.0.147"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
@@ -8,10 +8,10 @@ anyhow = { version = "1.0.66" }
|
||||
clap = { version = "4.0.1", features = ["derive"] }
|
||||
codegen = { version = "0.2.0" }
|
||||
itertools = { version = "0.10.5" }
|
||||
libcst = { git = "https://github.com/charliermarsh/LibCST", rev = "a13ec97dd4eb925bde4d426c6e422582793b260c" }
|
||||
libcst = { git = "https://github.com/charliermarsh/LibCST", rev = "f2f0b7a487a8725d161fe8b3ed73a6758b21e177" }
|
||||
ruff = { path = ".." }
|
||||
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb" }
|
||||
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb" }
|
||||
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb" }
|
||||
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "f885db8c61514f069979861f6b3bd83292086231" }
|
||||
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "f885db8c61514f069979861f6b3bd83292086231" }
|
||||
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "f885db8c61514f069979861f6b3bd83292086231" }
|
||||
strum = { version = "0.24.1", features = ["strum_macros"] }
|
||||
strum_macros = { version = "0.24.3" }
|
||||
|
||||
@@ -24,7 +24,7 @@ pub struct Cli {
|
||||
|
||||
pub fn main(cli: &Cli) -> Result<()> {
|
||||
// Build up a map from prefix to matching CheckCodes.
|
||||
let mut prefix_to_codes: BTreeMap<String, BTreeSet<CheckCode>> = Default::default();
|
||||
let mut prefix_to_codes: BTreeMap<String, BTreeSet<CheckCode>> = BTreeMap::default();
|
||||
for check_code in CheckCode::iter() {
|
||||
let as_ref: String = check_code.as_ref().to_string();
|
||||
let prefix_len = as_ref
|
||||
@@ -77,6 +77,7 @@ pub fn main(cli: &Cli) -> Result<()> {
|
||||
.arg_ref_self()
|
||||
.ret(Type::new("Vec<CheckCode>"))
|
||||
.vis("pub")
|
||||
.line("#[allow(clippy::match_same_arms)]")
|
||||
.line("match self {");
|
||||
for (prefix, codes) in &prefix_to_codes {
|
||||
gen = gen.line(format!(
|
||||
@@ -96,6 +97,7 @@ pub fn main(cli: &Cli) -> Result<()> {
|
||||
.arg_ref_self()
|
||||
.ret(Type::new("PrefixSpecificity"))
|
||||
.vis("pub")
|
||||
.line("#[allow(clippy::match_same_arms)]")
|
||||
.line("match self {");
|
||||
for prefix in prefix_to_codes.keys() {
|
||||
let num_numeric = prefix.chars().filter(|char| char.is_numeric()).count();
|
||||
@@ -104,7 +106,7 @@ pub fn main(cli: &Cli) -> Result<()> {
|
||||
2 => "Tens",
|
||||
1 => "Hundreds",
|
||||
0 => "Category",
|
||||
_ => panic!("Invalid prefix: {}", prefix),
|
||||
_ => panic!("Invalid prefix: {prefix}"),
|
||||
};
|
||||
gen = gen.line(format!(
|
||||
"CheckCodePrefix::{prefix} => PrefixSpecificity::{},",
|
||||
@@ -115,7 +117,8 @@ pub fn main(cli: &Cli) -> Result<()> {
|
||||
|
||||
// Construct the output contents.
|
||||
let mut output = String::new();
|
||||
output.push_str("//! File automatically generated by examples/generate_check_code_prefix.rs.");
|
||||
output
|
||||
.push_str("//! File automatically generated by `examples/generate_check_code_prefix.rs`.");
|
||||
output.push('\n');
|
||||
output.push('\n');
|
||||
output.push_str("use serde::{{Serialize, Deserialize}};");
|
||||
@@ -127,13 +130,28 @@ pub fn main(cli: &Cli) -> Result<()> {
|
||||
output.push('\n');
|
||||
output.push('\n');
|
||||
output.push_str(&scope.to_string());
|
||||
output.push('\n');
|
||||
output.push('\n');
|
||||
|
||||
// Add the list of output categories (not generated).
|
||||
output.push_str("pub const CATEGORIES: &[CheckCodePrefix] = &[");
|
||||
output.push('\n');
|
||||
for prefix in prefix_to_codes.keys() {
|
||||
if prefix.chars().all(char::is_alphabetic) {
|
||||
output.push_str(&format!("CheckCodePrefix::{prefix},"));
|
||||
output.push('\n');
|
||||
}
|
||||
}
|
||||
output.push_str("];");
|
||||
output.push('\n');
|
||||
output.push('\n');
|
||||
|
||||
// Write the output to `src/checks_gen.rs` (or stdout).
|
||||
if cli.dry_run {
|
||||
println!("{}", output);
|
||||
println!("{output}");
|
||||
} else {
|
||||
let mut f = OpenOptions::new().write(true).truncate(true).open(FILE)?;
|
||||
write!(f, "{}", output)?;
|
||||
write!(f, "{output}")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -61,7 +61,7 @@ pub fn main(cli: &Cli) -> Result<()> {
|
||||
}
|
||||
|
||||
if cli.dry_run {
|
||||
print!("{}", output);
|
||||
print!("{output}");
|
||||
} else {
|
||||
// Read the existing file.
|
||||
let file = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||
@@ -84,9 +84,9 @@ pub fn main(cli: &Cli) -> Result<()> {
|
||||
|
||||
// Write the prefix, new contents, and suffix.
|
||||
let mut f = OpenOptions::new().write(true).truncate(true).open(&file)?;
|
||||
write!(f, "{}\n\n", prefix)?;
|
||||
write!(f, "{}", output)?;
|
||||
write!(f, "{}", suffix)?;
|
||||
write!(f, "{prefix}\n\n")?;
|
||||
write!(f, "{output}")?;
|
||||
write!(f, "{suffix}")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -19,7 +19,7 @@ pub fn main(cli: &Cli) -> Result<()> {
|
||||
let contents = fs::read_to_string(&cli.file)?;
|
||||
let python_ast = parser::parse_program(&contents, &cli.file.to_string_lossy())?;
|
||||
let mut generator = SourceGenerator::new();
|
||||
generator.unparse_suite(&python_ast)?;
|
||||
generator.unparse_suite(&python_ast);
|
||||
println!("{}", generator.generate()?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
#![allow(
|
||||
clippy::collapsible_else_if,
|
||||
clippy::collapsible_if,
|
||||
clippy::implicit_hasher,
|
||||
clippy::match_same_arms,
|
||||
clippy::missing_errors_doc,
|
||||
clippy::missing_panics_doc,
|
||||
clippy::module_name_repetitions,
|
||||
clippy::must_use_candidate,
|
||||
clippy::similar_names,
|
||||
clippy::too_many_lines
|
||||
)]
|
||||
|
||||
pub mod generate_check_code_prefix;
|
||||
pub mod generate_rules_table;
|
||||
pub mod generate_source_code;
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
#![allow(
|
||||
clippy::collapsible_else_if,
|
||||
clippy::collapsible_if,
|
||||
clippy::implicit_hasher,
|
||||
clippy::match_same_arms,
|
||||
clippy::missing_errors_doc,
|
||||
clippy::missing_panics_doc,
|
||||
clippy::module_name_repetitions,
|
||||
clippy::must_use_candidate,
|
||||
clippy::similar_names,
|
||||
clippy::too_many_lines
|
||||
)]
|
||||
|
||||
use anyhow::Result;
|
||||
use clap::{Parser, Subcommand};
|
||||
use ruff_dev::{
|
||||
|
||||
@@ -17,6 +17,6 @@ pub struct Cli {
|
||||
pub fn main(cli: &Cli) -> Result<()> {
|
||||
let contents = fs::read_to_string(&cli.file)?;
|
||||
let python_ast = parser::parse_program(&contents, &cli.file.to_string_lossy())?;
|
||||
println!("{:#?}", python_ast);
|
||||
println!("{python_ast:#?}");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//! Print the LibCST CST for a given Python file.
|
||||
//! Print the `LibCST` CST for a given Python file.
|
||||
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
@@ -17,7 +17,7 @@ pub fn main(cli: &Cli) -> Result<()> {
|
||||
let contents = fs::read_to_string(&cli.file)?;
|
||||
match libcst_native::parse_module(&contents, None) {
|
||||
Ok(python_cst) => {
|
||||
println!("{:#?}", python_cst);
|
||||
println!("{python_cst:#?}");
|
||||
Ok(())
|
||||
}
|
||||
Err(_) => Err(anyhow::anyhow!("Failed to parse CST")),
|
||||
|
||||
@@ -17,7 +17,7 @@ pub struct Cli {
|
||||
pub fn main(cli: &Cli) -> Result<()> {
|
||||
let contents = fs::read_to_string(&cli.file)?;
|
||||
for (_, tok, _) in lexer::make_tokenizer(&contents).flatten() {
|
||||
println!("{:#?}", tok);
|
||||
println!("{tok:#?}");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
use fnv::{FnvHashMap, FnvHashSet};
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use rustpython_ast::{Excepthandler, ExcepthandlerKind, Expr, ExprKind, Location, Stmt, StmtKind};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use rustpython_ast::{
|
||||
Arguments, Excepthandler, ExcepthandlerKind, Expr, ExprKind, Location, Stmt, StmtKind,
|
||||
};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::SourceCodeLocator;
|
||||
|
||||
#[inline(always)]
|
||||
fn collect_call_path_inner<'a>(expr: &'a Expr, parts: &mut Vec<&'a str>) {
|
||||
match &expr.node {
|
||||
ExprKind::Call { func, .. } => {
|
||||
@@ -24,7 +25,6 @@ fn collect_call_path_inner<'a>(expr: &'a Expr, parts: &mut Vec<&'a str>) {
|
||||
}
|
||||
|
||||
/// Convert an `Expr` to its call path (like `List`, or `typing.List`).
|
||||
#[inline(always)]
|
||||
pub fn compose_call_path(expr: &Expr) -> Option<String> {
|
||||
let segments = collect_call_paths(expr);
|
||||
if segments.is_empty() {
|
||||
@@ -35,7 +35,6 @@ pub fn compose_call_path(expr: &Expr) -> Option<String> {
|
||||
}
|
||||
|
||||
/// Convert an `Expr` to its call path segments (like ["typing", "List"]).
|
||||
#[inline(always)]
|
||||
pub fn collect_call_paths(expr: &Expr) -> Vec<&str> {
|
||||
let mut segments = vec![];
|
||||
collect_call_path_inner(expr, &mut segments);
|
||||
@@ -45,7 +44,7 @@ pub fn collect_call_paths(expr: &Expr) -> Vec<&str> {
|
||||
/// Rewrite any import aliases on a call path.
|
||||
pub fn dealias_call_path<'a>(
|
||||
call_path: Vec<&'a str>,
|
||||
import_aliases: &FnvHashMap<&str, &'a str>,
|
||||
import_aliases: &FxHashMap<&str, &'a str>,
|
||||
) -> Vec<&'a str> {
|
||||
if let Some(head) = call_path.first() {
|
||||
if let Some(origin) = import_aliases.get(head) {
|
||||
@@ -79,8 +78,8 @@ pub fn match_module_member(
|
||||
expr: &Expr,
|
||||
module: &str,
|
||||
member: &str,
|
||||
from_imports: &FnvHashMap<&str, FnvHashSet<&str>>,
|
||||
import_aliases: &FnvHashMap<&str, &str>,
|
||||
from_imports: &FxHashMap<&str, FxHashSet<&str>>,
|
||||
import_aliases: &FxHashMap<&str, &str>,
|
||||
) -> bool {
|
||||
match_call_path(
|
||||
&dealias_call_path(collect_call_paths(expr), import_aliases),
|
||||
@@ -97,7 +96,7 @@ pub fn match_call_path(
|
||||
call_path: &[&str],
|
||||
module: &str,
|
||||
member: &str,
|
||||
from_imports: &FnvHashMap<&str, FnvHashSet<&str>>,
|
||||
from_imports: &FxHashMap<&str, FxHashSet<&str>>,
|
||||
) -> bool {
|
||||
// If we have no segments, we can't ever match.
|
||||
let num_segments = call_path.len();
|
||||
@@ -121,10 +120,9 @@ pub fn match_call_path(
|
||||
// `Match`).
|
||||
if num_segments == 0 {
|
||||
module.is_empty()
|
||||
|| from_imports
|
||||
.get(module)
|
||||
.map(|imports| imports.contains(member) || imports.contains("*"))
|
||||
.unwrap_or(false)
|
||||
|| from_imports.get(module).map_or(false, |imports| {
|
||||
imports.contains(member) || imports.contains("*")
|
||||
})
|
||||
} else {
|
||||
let components: Vec<&str> = module.split('.').collect();
|
||||
|
||||
@@ -148,8 +146,7 @@ pub fn match_call_path(
|
||||
let member = components[cut];
|
||||
if from_imports
|
||||
.get(&module.as_str())
|
||||
.map(|imports| imports.contains(member))
|
||||
.unwrap_or(false)
|
||||
.map_or(false, |imports| imports.contains(member))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -218,6 +215,27 @@ pub fn extract_handler_names(handlers: &[Excepthandler]) -> Vec<Vec<&str>> {
|
||||
handler_names
|
||||
}
|
||||
|
||||
/// Return the set of all bound argument names.
|
||||
pub fn collect_arg_names<'a>(arguments: &'a Arguments) -> FxHashSet<&'a str> {
|
||||
let mut arg_names: FxHashSet<&'a str> = FxHashSet::default();
|
||||
for arg in &arguments.posonlyargs {
|
||||
arg_names.insert(arg.node.arg.as_str());
|
||||
}
|
||||
for arg in &arguments.args {
|
||||
arg_names.insert(arg.node.arg.as_str());
|
||||
}
|
||||
if let Some(arg) = &arguments.vararg {
|
||||
arg_names.insert(arg.node.arg.as_str());
|
||||
}
|
||||
for arg in &arguments.kwonlyargs {
|
||||
arg_names.insert(arg.node.arg.as_str());
|
||||
}
|
||||
if let Some(arg) = &arguments.kwarg {
|
||||
arg_names.insert(arg.node.arg.as_str());
|
||||
}
|
||||
arg_names
|
||||
}
|
||||
|
||||
/// Returns `true` if a call is an argumented `super` invocation.
|
||||
pub fn is_super_call_with_arguments(func: &Expr, args: &[Expr]) -> bool {
|
||||
// Check: is this a `super` call?
|
||||
@@ -253,7 +271,7 @@ pub fn to_module_and_member(target: &str) -> (&str, &str) {
|
||||
|
||||
/// Convert a location within a file (relative to `base`) to an absolute
|
||||
/// position.
|
||||
pub fn to_absolute(relative: &Location, base: &Location) -> Location {
|
||||
pub fn to_absolute(relative: Location, base: Location) -> Location {
|
||||
if relative.row() == 1 {
|
||||
Location::new(
|
||||
relative.row() + base.row() - 1,
|
||||
@@ -295,7 +313,7 @@ pub fn match_trailing_content(stmt: &Stmt, locator: &SourceCodeLocator) -> bool
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use anyhow::Result;
|
||||
use fnv::{FnvHashMap, FnvHashSet};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use rustpython_parser::parser;
|
||||
|
||||
use crate::ast::helpers::match_module_member;
|
||||
@@ -307,8 +325,8 @@ mod tests {
|
||||
&expr,
|
||||
"",
|
||||
"list",
|
||||
&FnvHashMap::default(),
|
||||
&FnvHashMap::default(),
|
||||
&FxHashMap::default(),
|
||||
&FxHashMap::default(),
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
@@ -320,8 +338,8 @@ mod tests {
|
||||
&expr,
|
||||
"typing.re",
|
||||
"Match",
|
||||
&FnvHashMap::default(),
|
||||
&FnvHashMap::default(),
|
||||
&FxHashMap::default(),
|
||||
&FxHashMap::default(),
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
@@ -333,16 +351,16 @@ mod tests {
|
||||
&expr,
|
||||
"typing.re",
|
||||
"Match",
|
||||
&FnvHashMap::default(),
|
||||
&FnvHashMap::default(),
|
||||
&FxHashMap::default(),
|
||||
&FxHashMap::default(),
|
||||
));
|
||||
let expr = parser::parse_expression("re.Match", "<filename>")?;
|
||||
assert!(!match_module_member(
|
||||
&expr,
|
||||
"typing.re",
|
||||
"Match",
|
||||
&FnvHashMap::default(),
|
||||
&FnvHashMap::default(),
|
||||
&FxHashMap::default(),
|
||||
&FxHashMap::default(),
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
@@ -354,8 +372,8 @@ mod tests {
|
||||
&expr,
|
||||
"typing.re",
|
||||
"Match",
|
||||
&FnvHashMap::from_iter([("typing.re", FnvHashSet::from_iter(["*"]))]),
|
||||
&FnvHashMap::default()
|
||||
&FxHashMap::from_iter([("typing.re", FxHashSet::from_iter(["*"]))]),
|
||||
&FxHashMap::default()
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
@@ -367,8 +385,8 @@ mod tests {
|
||||
&expr,
|
||||
"typing.re",
|
||||
"Match",
|
||||
&FnvHashMap::from_iter([("typing.re", FnvHashSet::from_iter(["Match"]))]),
|
||||
&FnvHashMap::default()
|
||||
&FxHashMap::from_iter([("typing.re", FxHashSet::from_iter(["Match"]))]),
|
||||
&FxHashMap::default()
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
@@ -380,8 +398,8 @@ mod tests {
|
||||
&expr,
|
||||
"typing.re",
|
||||
"Match",
|
||||
&FnvHashMap::from_iter([("typing", FnvHashSet::from_iter(["re"]))]),
|
||||
&FnvHashMap::default()
|
||||
&FxHashMap::from_iter([("typing", FxHashSet::from_iter(["re"]))]),
|
||||
&FxHashMap::default()
|
||||
));
|
||||
|
||||
let expr = parser::parse_expression("match.Match", "<filename>")?;
|
||||
@@ -389,8 +407,8 @@ mod tests {
|
||||
&expr,
|
||||
"typing.re.match",
|
||||
"Match",
|
||||
&FnvHashMap::from_iter([("typing.re", FnvHashSet::from_iter(["match"]))]),
|
||||
&FnvHashMap::default()
|
||||
&FxHashMap::from_iter([("typing.re", FxHashSet::from_iter(["match"]))]),
|
||||
&FxHashMap::default()
|
||||
));
|
||||
|
||||
let expr = parser::parse_expression("re.match.Match", "<filename>")?;
|
||||
@@ -398,8 +416,8 @@ mod tests {
|
||||
&expr,
|
||||
"typing.re.match",
|
||||
"Match",
|
||||
&FnvHashMap::from_iter([("typing", FnvHashSet::from_iter(["re"]))]),
|
||||
&FnvHashMap::default()
|
||||
&FxHashMap::from_iter([("typing", FxHashSet::from_iter(["re"]))]),
|
||||
&FxHashMap::default()
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
@@ -411,8 +429,8 @@ mod tests {
|
||||
&expr,
|
||||
"typing.re",
|
||||
"Match",
|
||||
&FnvHashMap::from_iter([("typing.re", FnvHashSet::from_iter(["Match"]))]),
|
||||
&FnvHashMap::from_iter([("IMatch", "Match")]),
|
||||
&FxHashMap::from_iter([("typing.re", FxHashSet::from_iter(["Match"]))]),
|
||||
&FxHashMap::from_iter([("IMatch", "Match")]),
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
@@ -424,8 +442,8 @@ mod tests {
|
||||
&expr,
|
||||
"typing.re",
|
||||
"Match",
|
||||
&FnvHashMap::default(),
|
||||
&FnvHashMap::from_iter([("t", "typing.re")]),
|
||||
&FxHashMap::default(),
|
||||
&FxHashMap::from_iter([("t", "typing.re")]),
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
@@ -437,8 +455,8 @@ mod tests {
|
||||
&expr,
|
||||
"typing.re",
|
||||
"Match",
|
||||
&FnvHashMap::default(),
|
||||
&FnvHashMap::from_iter([("t", "typing")]),
|
||||
&FxHashMap::default(),
|
||||
&FxHashMap::from_iter([("t", "typing")]),
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@ use crate::ast::types::{BindingKind, Scope};
|
||||
|
||||
/// Extract the names bound to a given __all__ assignment.
|
||||
pub fn extract_all_names(stmt: &Stmt, scope: &Scope) -> Vec<String> {
|
||||
let mut names: Vec<String> = vec![];
|
||||
|
||||
fn add_to_names(names: &mut Vec<String>, elts: &[Expr]) {
|
||||
for elt in elts {
|
||||
if let ExprKind::Constant {
|
||||
@@ -13,11 +11,13 @@ pub fn extract_all_names(stmt: &Stmt, scope: &Scope) -> Vec<String> {
|
||||
..
|
||||
} = &elt.node
|
||||
{
|
||||
names.push(value.to_string())
|
||||
names.push(value.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut names: Vec<String> = vec![];
|
||||
|
||||
// Grab the existing bound __all__ values.
|
||||
if let StmtKind::AugAssign { .. } = &stmt.node {
|
||||
if let Some(binding) = scope.values.get("__all__") {
|
||||
@@ -35,7 +35,7 @@ pub fn extract_all_names(stmt: &Stmt, scope: &Scope) -> Vec<String> {
|
||||
} {
|
||||
match &value.node {
|
||||
ExprKind::List { elts, .. } | ExprKind::Tuple { elts, .. } => {
|
||||
add_to_names(&mut names, elts)
|
||||
add_to_names(&mut names, elts);
|
||||
}
|
||||
ExprKind::BinOp { left, right, .. } => {
|
||||
let mut current_left = left;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
use fnv::FnvHashMap;
|
||||
use rustpython_ast::{Expr, Keyword};
|
||||
use rustc_hash::FxHashMap;
|
||||
use rustpython_ast::{Expr, Keyword, Stmt};
|
||||
use rustpython_parser::ast::{Located, Location};
|
||||
|
||||
fn id() -> usize {
|
||||
@@ -9,6 +9,12 @@ fn id() -> usize {
|
||||
COUNTER.fetch_add(1, Ordering::Relaxed)
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Node<'a> {
|
||||
Stmt(&'a Stmt),
|
||||
Expr(&'a Expr),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Range {
|
||||
pub location: Location,
|
||||
@@ -52,7 +58,7 @@ pub struct Scope<'a> {
|
||||
pub id: usize,
|
||||
pub kind: ScopeKind<'a>,
|
||||
pub import_starred: bool,
|
||||
pub values: FnvHashMap<&'a str, Binding>,
|
||||
pub values: FxHashMap<&'a str, Binding>,
|
||||
}
|
||||
|
||||
impl<'a> Scope<'a> {
|
||||
@@ -61,7 +67,7 @@ impl<'a> Scope<'a> {
|
||||
id: id(),
|
||||
kind,
|
||||
import_starred: false,
|
||||
values: FnvHashMap::default(),
|
||||
values: FxHashMap::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -101,9 +107,3 @@ pub struct Binding {
|
||||
/// the binding was last used.
|
||||
pub used: Option<(usize, Range)>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum ImportKind {
|
||||
Import,
|
||||
ImportFrom,
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ pub trait Visitor<'a> {
|
||||
fn visit_constant(&mut self, constant: &'a Constant) {
|
||||
walk_constant(self, constant);
|
||||
}
|
||||
fn visit_expr_context(&mut self, expr_content: &'a ExprContext) {
|
||||
walk_expr_context(self, expr_content);
|
||||
fn visit_expr_context(&mut self, expr_context: &'a ExprContext) {
|
||||
walk_expr_context(self, expr_context);
|
||||
}
|
||||
fn visit_boolop(&mut self, boolop: &'a Boolop) {
|
||||
walk_boolop(self, boolop);
|
||||
@@ -249,7 +249,7 @@ pub fn walk_stmt<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, stmt: &'a Stmt) {
|
||||
visitor.visit_stmt(stmt);
|
||||
}
|
||||
for excepthandler in handlers {
|
||||
visitor.visit_excepthandler(excepthandler)
|
||||
visitor.visit_excepthandler(excepthandler);
|
||||
}
|
||||
for stmt in orelse {
|
||||
visitor.visit_stmt(stmt);
|
||||
@@ -447,7 +447,7 @@ pub fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) {
|
||||
pub fn walk_constant<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, constant: &'a Constant) {
|
||||
if let Constant::Tuple(constants) = constant {
|
||||
for constant in constants {
|
||||
visitor.visit_constant(constant)
|
||||
visitor.visit_constant(constant);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -456,8 +456,8 @@ pub fn walk_comprehension<'a, V: Visitor<'a> + ?Sized>(
|
||||
visitor: &mut V,
|
||||
comprehension: &'a Comprehension,
|
||||
) {
|
||||
visitor.visit_expr(&comprehension.target);
|
||||
visitor.visit_expr(&comprehension.iter);
|
||||
visitor.visit_expr(&comprehension.target);
|
||||
for expr in &comprehension.ifs {
|
||||
visitor.visit_expr(expr);
|
||||
}
|
||||
@@ -577,7 +577,6 @@ pub fn walk_pattern<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, pattern: &'a P
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
#[inline(always)]
|
||||
pub fn walk_expr_context<'a, V: Visitor<'a> + ?Sized>(
|
||||
visitor: &mut V,
|
||||
expr_context: &'a ExprContext,
|
||||
@@ -585,21 +584,16 @@ pub fn walk_expr_context<'a, V: Visitor<'a> + ?Sized>(
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
#[inline(always)]
|
||||
pub fn walk_boolop<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, boolop: &'a Boolop) {}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
#[inline(always)]
|
||||
pub fn walk_operator<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, operator: &'a Operator) {}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
#[inline(always)]
|
||||
pub fn walk_unaryop<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, unaryop: &'a Unaryop) {}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
#[inline(always)]
|
||||
pub fn walk_cmpop<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, cmpop: &'a Cmpop) {}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
#[inline(always)]
|
||||
pub fn walk_alias<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, alias: &'a Alias) {}
|
||||
|
||||
@@ -19,7 +19,7 @@ pub fn leading_space(line: &str) -> String {
|
||||
}
|
||||
|
||||
/// Extract the leading indentation from a line.
|
||||
pub fn indentation<'a, T>(checker: &'a Checker, located: &Located<T>) -> String {
|
||||
pub fn indentation<T>(checker: &Checker, located: &Located<T>) -> String {
|
||||
let range = Range::from_located(located);
|
||||
checker
|
||||
.locator
|
||||
|
||||
@@ -10,8 +10,6 @@ use crate::autofix::{Fix, Patch};
|
||||
use crate::checks::Check;
|
||||
use crate::source_code_locator::SourceCodeLocator;
|
||||
|
||||
// TODO(charlie): The model here is awkward because `Apply` is only relevant at
|
||||
// higher levels in the execution flow.
|
||||
#[derive(Hash)]
|
||||
pub enum Mode {
|
||||
Generate,
|
||||
@@ -19,55 +17,55 @@ pub enum Mode {
|
||||
None,
|
||||
}
|
||||
|
||||
impl Mode {
|
||||
/// Return `true` if a patch should be generated under the given `Mode`.
|
||||
pub fn patch(&self) -> bool {
|
||||
match &self {
|
||||
Mode::Generate => true,
|
||||
Mode::Apply => true,
|
||||
Mode::None => false,
|
||||
impl From<bool> for Mode {
|
||||
fn from(value: bool) -> Self {
|
||||
if value {
|
||||
Mode::Apply
|
||||
} else {
|
||||
Mode::None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for Mode {
|
||||
fn from(value: bool) -> Self {
|
||||
impl From<&Mode> for bool {
|
||||
fn from(value: &Mode) -> Self {
|
||||
match value {
|
||||
true => Mode::Apply,
|
||||
false => Mode::None,
|
||||
Mode::Generate | Mode::Apply => true,
|
||||
Mode::None => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Auto-fix errors in a file, and write the fixed source code to disk.
|
||||
pub fn fix_file<'a>(
|
||||
checks: &'a mut [Check],
|
||||
checks: &'a [Check],
|
||||
locator: &'a SourceCodeLocator<'a>,
|
||||
) -> Option<Cow<'a, str>> {
|
||||
) -> Option<(Cow<'a, str>, usize)> {
|
||||
if checks.iter().all(|check| check.fix.is_none()) {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(apply_fixes(
|
||||
checks.iter_mut().filter_map(|check| check.fix.as_mut()),
|
||||
checks.iter().filter_map(|check| check.fix.as_ref()),
|
||||
locator,
|
||||
))
|
||||
}
|
||||
|
||||
/// Apply a series of fixes.
|
||||
fn apply_fixes<'a>(
|
||||
fixes: impl Iterator<Item = &'a mut Fix>,
|
||||
fixes: impl Iterator<Item = &'a Fix>,
|
||||
locator: &'a SourceCodeLocator<'a>,
|
||||
) -> Cow<'a, str> {
|
||||
) -> (Cow<'a, str>, usize) {
|
||||
let mut output = RopeBuilder::new();
|
||||
let mut last_pos: Location = Location::new(1, 0);
|
||||
let mut applied: BTreeSet<&Patch> = BTreeSet::default();
|
||||
let mut num_fixed: usize = 0;
|
||||
|
||||
for fix in fixes.sorted_by_key(|fix| fix.patch.location) {
|
||||
// If we already applied an identical fix as part of another correction, skip
|
||||
// any re-application.
|
||||
if applied.contains(&fix.patch) {
|
||||
fix.applied = true;
|
||||
num_fixed += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -90,19 +88,18 @@ fn apply_fixes<'a>(
|
||||
// Track that the fix was applied.
|
||||
last_pos = fix.patch.end_location;
|
||||
applied.insert(&fix.patch);
|
||||
fix.applied = true;
|
||||
num_fixed += 1;
|
||||
}
|
||||
|
||||
// Add the remaining content.
|
||||
let slice = locator.slice_source_code_at(&last_pos);
|
||||
let slice = locator.slice_source_code_at(last_pos);
|
||||
output.append(&slice);
|
||||
|
||||
Cow::from(output.finish())
|
||||
(Cow::from(output.finish()), num_fixed)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use anyhow::Result;
|
||||
use rustpython_parser::ast::Location;
|
||||
|
||||
use crate::autofix::fixer::apply_fixes;
|
||||
@@ -110,115 +107,117 @@ mod tests {
|
||||
use crate::SourceCodeLocator;
|
||||
|
||||
#[test]
|
||||
fn empty_file() -> Result<()> {
|
||||
let mut fixes = vec![];
|
||||
let locator = SourceCodeLocator::new("");
|
||||
let actual = apply_fixes(fixes.iter_mut(), &locator);
|
||||
let expected = "";
|
||||
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
Ok(())
|
||||
fn empty_file() {
|
||||
let fixes = vec![];
|
||||
let locator = SourceCodeLocator::new(r#""#);
|
||||
let (contents, fixed) = apply_fixes(fixes.iter(), &locator);
|
||||
assert_eq!(contents, "");
|
||||
assert_eq!(fixed, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn apply_single_replacement() -> Result<()> {
|
||||
let mut fixes = vec![Fix {
|
||||
fn apply_single_replacement() {
|
||||
let fixes = vec![Fix {
|
||||
patch: Patch {
|
||||
content: "Bar".to_string(),
|
||||
location: Location::new(1, 8),
|
||||
end_location: Location::new(1, 14),
|
||||
},
|
||||
applied: false,
|
||||
}];
|
||||
let locator = SourceCodeLocator::new(
|
||||
"class A(object):
|
||||
...
|
||||
",
|
||||
r#"
|
||||
class A(object):
|
||||
...
|
||||
"#
|
||||
.trim(),
|
||||
);
|
||||
let actual = apply_fixes(fixes.iter_mut(), &locator);
|
||||
|
||||
let expected = "class A(Bar):
|
||||
...
|
||||
";
|
||||
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
Ok(())
|
||||
let (contents, fixed) = apply_fixes(fixes.iter(), &locator);
|
||||
assert_eq!(
|
||||
contents,
|
||||
r#"
|
||||
class A(Bar):
|
||||
...
|
||||
"#
|
||||
.trim(),
|
||||
);
|
||||
assert_eq!(fixed, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn apply_single_removal() -> Result<()> {
|
||||
let mut fixes = vec![Fix {
|
||||
fn apply_single_removal() {
|
||||
let fixes = vec![Fix {
|
||||
patch: Patch {
|
||||
content: "".to_string(),
|
||||
content: String::new(),
|
||||
location: Location::new(1, 7),
|
||||
end_location: Location::new(1, 15),
|
||||
},
|
||||
applied: false,
|
||||
}];
|
||||
let locator = SourceCodeLocator::new(
|
||||
"class A(object):
|
||||
...
|
||||
",
|
||||
r#"
|
||||
class A(object):
|
||||
...
|
||||
"#
|
||||
.trim(),
|
||||
);
|
||||
let actual = apply_fixes(fixes.iter_mut(), &locator);
|
||||
|
||||
let expected = "class A:
|
||||
...
|
||||
";
|
||||
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
Ok(())
|
||||
let (contents, fixed) = apply_fixes(fixes.iter(), &locator);
|
||||
assert_eq!(
|
||||
contents,
|
||||
r#"
|
||||
class A:
|
||||
...
|
||||
"#
|
||||
.trim()
|
||||
);
|
||||
assert_eq!(fixed, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn apply_double_removal() -> Result<()> {
|
||||
let mut fixes = vec![
|
||||
fn apply_double_removal() {
|
||||
let fixes = vec![
|
||||
Fix {
|
||||
patch: Patch {
|
||||
content: "".to_string(),
|
||||
content: String::new(),
|
||||
location: Location::new(1, 7),
|
||||
end_location: Location::new(1, 16),
|
||||
},
|
||||
applied: false,
|
||||
},
|
||||
Fix {
|
||||
patch: Patch {
|
||||
content: "".to_string(),
|
||||
content: String::new(),
|
||||
location: Location::new(1, 16),
|
||||
end_location: Location::new(1, 23),
|
||||
},
|
||||
applied: false,
|
||||
},
|
||||
];
|
||||
let locator = SourceCodeLocator::new(
|
||||
"class A(object, object):
|
||||
...
|
||||
",
|
||||
r#"
|
||||
class A(object, object):
|
||||
...
|
||||
"#
|
||||
.trim(),
|
||||
);
|
||||
let actual = apply_fixes(fixes.iter_mut(), &locator);
|
||||
let (contents, fixed) = apply_fixes(fixes.iter(), &locator);
|
||||
|
||||
let expected = "class A:
|
||||
...
|
||||
";
|
||||
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
Ok(())
|
||||
assert_eq!(
|
||||
contents,
|
||||
r#"
|
||||
class A:
|
||||
...
|
||||
"#
|
||||
.trim()
|
||||
);
|
||||
assert_eq!(fixed, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ignore_overlapping_fixes() -> Result<()> {
|
||||
let mut fixes = vec![
|
||||
fn ignore_overlapping_fixes() {
|
||||
let fixes = vec![
|
||||
Fix {
|
||||
patch: Patch {
|
||||
content: "".to_string(),
|
||||
content: String::new(),
|
||||
location: Location::new(1, 7),
|
||||
end_location: Location::new(1, 15),
|
||||
},
|
||||
applied: false,
|
||||
},
|
||||
Fix {
|
||||
patch: Patch {
|
||||
@@ -226,22 +225,24 @@ mod tests {
|
||||
location: Location::new(1, 9),
|
||||
end_location: Location::new(1, 11),
|
||||
},
|
||||
applied: false,
|
||||
},
|
||||
];
|
||||
let locator = SourceCodeLocator::new(
|
||||
"class A(object):
|
||||
r#"
|
||||
class A(object):
|
||||
...
|
||||
",
|
||||
"#
|
||||
.trim(),
|
||||
);
|
||||
let actual = apply_fixes(fixes.iter_mut(), &locator);
|
||||
|
||||
let expected = "class A:
|
||||
let (contents, fixed) = apply_fixes(fixes.iter(), &locator);
|
||||
assert_eq!(
|
||||
contents,
|
||||
r#"
|
||||
class A:
|
||||
...
|
||||
";
|
||||
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
Ok(())
|
||||
"#
|
||||
.trim(),
|
||||
);
|
||||
assert_eq!(fixed, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,28 +4,26 @@ use serde::{Deserialize, Serialize};
|
||||
pub mod fixer;
|
||||
pub mod helpers;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct Patch {
|
||||
pub content: String,
|
||||
pub location: Location,
|
||||
pub end_location: Location,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Fix {
|
||||
pub patch: Patch,
|
||||
pub applied: bool,
|
||||
}
|
||||
|
||||
impl Fix {
|
||||
pub fn deletion(start: Location, end: Location) -> Self {
|
||||
Self {
|
||||
patch: Patch {
|
||||
content: "".to_string(),
|
||||
content: String::new(),
|
||||
location: start,
|
||||
end_location: end,
|
||||
},
|
||||
applied: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +34,6 @@ impl Fix {
|
||||
location: start,
|
||||
end_location: end,
|
||||
},
|
||||
applied: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,18 +44,16 @@ impl Fix {
|
||||
location: at,
|
||||
end_location: at,
|
||||
},
|
||||
applied: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dummy(location: Location) -> Self {
|
||||
Self {
|
||||
patch: Patch {
|
||||
content: "".to_string(),
|
||||
content: String::new(),
|
||||
location,
|
||||
end_location: location,
|
||||
},
|
||||
applied: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
17
src/cache.rs
17
src/cache.rs
@@ -63,9 +63,10 @@ impl Mode {
|
||||
|
||||
impl From<bool> for Mode {
|
||||
fn from(value: bool) -> Self {
|
||||
match value {
|
||||
true => Mode::ReadWrite,
|
||||
false => Mode::None,
|
||||
if value {
|
||||
Mode::ReadWrite
|
||||
} else {
|
||||
Mode::None
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -109,7 +110,7 @@ pub fn init() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_sync(key: &u64, value: &[u8]) -> Result<(), std::io::Error> {
|
||||
fn write_sync(key: u64, value: &[u8]) -> Result<(), std::io::Error> {
|
||||
fs::write(
|
||||
Path::new(cache_dir())
|
||||
.join(content_dir())
|
||||
@@ -118,7 +119,7 @@ fn write_sync(key: &u64, value: &[u8]) -> Result<(), std::io::Error> {
|
||||
)
|
||||
}
|
||||
|
||||
fn read_sync(key: &u64) -> Result<Vec<u8>, std::io::Error> {
|
||||
fn read_sync(key: u64) -> Result<Vec<u8>, std::io::Error> {
|
||||
fs::read(
|
||||
Path::new(cache_dir())
|
||||
.join(content_dir())
|
||||
@@ -138,7 +139,7 @@ pub fn get(
|
||||
return None;
|
||||
};
|
||||
|
||||
if let Ok(encoded) = read_sync(&cache_key(path, settings, autofix)) {
|
||||
if let Ok(encoded) = read_sync(cache_key(path, settings, autofix)) {
|
||||
match bincode::deserialize::<CheckResult>(&encoded[..]) {
|
||||
Ok(CheckResult {
|
||||
metadata: CacheMetadata { mtime },
|
||||
@@ -174,9 +175,9 @@ pub fn set(
|
||||
messages,
|
||||
};
|
||||
if let Err(e) = write_sync(
|
||||
&cache_key(path, settings, autofix),
|
||||
cache_key(path, settings, autofix),
|
||||
&bincode::serialize(&check_result).unwrap(),
|
||||
) {
|
||||
error!("Failed to write to cache: {e:?}")
|
||||
error!("Failed to write to cache: {e:?}");
|
||||
}
|
||||
}
|
||||
|
||||
607
src/check_ast.rs
607
src/check_ast.rs
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,6 @@ use nohash_hasher::IntSet;
|
||||
use rustpython_parser::ast::Suite;
|
||||
|
||||
use crate::ast::visitor::Visitor;
|
||||
use crate::autofix::fixer;
|
||||
use crate::checks::Check;
|
||||
use crate::isort;
|
||||
use crate::isort::track::ImportTracker;
|
||||
@@ -15,12 +14,12 @@ fn check_import_blocks(
|
||||
tracker: ImportTracker,
|
||||
locator: &SourceCodeLocator,
|
||||
settings: &Settings,
|
||||
autofix: &fixer::Mode,
|
||||
autofix: bool,
|
||||
) -> Vec<Check> {
|
||||
let mut checks = vec![];
|
||||
for block in tracker.into_iter() {
|
||||
if !block.is_empty() {
|
||||
if let Some(check) = isort::plugins::check_imports(block, locator, settings, autofix) {
|
||||
if let Some(check) = isort::plugins::check_imports(&block, locator, settings, autofix) {
|
||||
checks.push(check);
|
||||
}
|
||||
}
|
||||
@@ -33,7 +32,7 @@ pub fn check_imports(
|
||||
locator: &SourceCodeLocator,
|
||||
exclusions: &IntSet<usize>,
|
||||
settings: &Settings,
|
||||
autofix: &fixer::Mode,
|
||||
autofix: bool,
|
||||
) -> Vec<Check> {
|
||||
let mut tracker = ImportTracker::new(exclusions);
|
||||
for stmt in python_ast {
|
||||
|
||||
@@ -6,7 +6,7 @@ use regex::Regex;
|
||||
use rustpython_parser::ast::Location;
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::autofix::{fixer, Fix};
|
||||
use crate::autofix::Fix;
|
||||
use crate::checks::{Check, CheckCode, CheckKind};
|
||||
use crate::noqa;
|
||||
use crate::noqa::Directive;
|
||||
@@ -14,15 +14,18 @@ use crate::settings::Settings;
|
||||
|
||||
// Regex from PEP263
|
||||
static CODING_COMMENT_REGEX: Lazy<Regex> =
|
||||
Lazy::new(|| Regex::new(r"^[ \t\f]*#.*?coding[:=][ \t]*utf-?8").expect("Invalid regex"));
|
||||
Lazy::new(|| Regex::new(r"^[ \t\f]*#.*?coding[:=][ \t]*utf-?8").unwrap());
|
||||
|
||||
static URL_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"^https?://\S+$").unwrap());
|
||||
|
||||
/// Whether the given line is too long and should be reported.
|
||||
fn should_enforce_line_length(line: &str, length: usize, limit: usize) -> bool {
|
||||
if length > limit {
|
||||
let mut chunks = line.split_whitespace();
|
||||
if let (Some(first), Some(_)) = (chunks.next(), chunks.next()) {
|
||||
// Do not enforce the line length for commented lines with a single word
|
||||
!(first == "#" && chunks.next().is_none())
|
||||
// Do not enforce the line length for commented lines that end with a URL
|
||||
// or contain only a single word.
|
||||
!(first == "#" && chunks.last().map_or(true, |c| URL_REGEX.is_match(c)))
|
||||
} else {
|
||||
// Single word / no printable chars - no way to make the line shorter
|
||||
false
|
||||
@@ -37,7 +40,8 @@ pub fn check_lines(
|
||||
contents: &str,
|
||||
noqa_line_for: &IntMap<usize, usize>,
|
||||
settings: &Settings,
|
||||
autofix: &fixer::Mode,
|
||||
autofix: bool,
|
||||
ignore_noqa: bool,
|
||||
) {
|
||||
let enforce_unnecessary_coding_comment = settings.enabled.contains(&CheckCode::U009);
|
||||
let enforce_line_too_long = settings.enabled.contains(&CheckCode::E501);
|
||||
@@ -53,6 +57,30 @@ pub fn check_lines(
|
||||
assert!(check.location.row() >= 1);
|
||||
}
|
||||
|
||||
macro_rules! add_if {
|
||||
($check:expr, $noqa:expr) => {{
|
||||
match $noqa {
|
||||
(Directive::All(..), matches) => {
|
||||
matches.push($check.kind.code().as_ref());
|
||||
if ignore_noqa {
|
||||
line_checks.push($check);
|
||||
}
|
||||
}
|
||||
(Directive::Codes(.., codes), matches) => {
|
||||
if codes.contains(&$check.kind.code().as_ref()) {
|
||||
matches.push($check.kind.code().as_ref());
|
||||
if ignore_noqa {
|
||||
line_checks.push($check);
|
||||
}
|
||||
} else {
|
||||
line_checks.push($check);
|
||||
}
|
||||
}
|
||||
(Directive::None, ..) => line_checks.push($check),
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
let lines: Vec<&str> = contents.lines().collect();
|
||||
for (lineno, line) in lines.iter().enumerate() {
|
||||
// Grab the noqa (logical) line number for the current (physical) line.
|
||||
@@ -65,21 +93,24 @@ pub fn check_lines(
|
||||
if lineno < 2 {
|
||||
// PEP3120 makes utf-8 the default encoding.
|
||||
if CODING_COMMENT_REGEX.is_match(line) {
|
||||
let line_length = line.len();
|
||||
let mut check = Check::new(
|
||||
CheckKind::PEP3120UnnecessaryCodingComment,
|
||||
Range {
|
||||
location: Location::new(lineno + 1, 0),
|
||||
end_location: Location::new(lineno + 1, line_length + 1),
|
||||
end_location: Location::new(lineno + 2, 0),
|
||||
},
|
||||
);
|
||||
if autofix.patch() && settings.fixable.contains(check.kind.code()) {
|
||||
if autofix && settings.fixable.contains(check.kind.code()) {
|
||||
check.amend(Fix::deletion(
|
||||
Location::new(lineno + 1, 0),
|
||||
Location::new(lineno + 1, line_length + 1),
|
||||
Location::new(lineno + 2, 0),
|
||||
));
|
||||
}
|
||||
line_checks.push(check);
|
||||
|
||||
let noqa = noqa_directives.entry(noqa_lineno).or_insert_with(|| {
|
||||
(noqa::extract_noqa_directive(lines[noqa_lineno]), vec![])
|
||||
});
|
||||
add_if!(check, noqa);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -101,7 +132,7 @@ pub fn check_lines(
|
||||
match noqa {
|
||||
(Directive::All(..), matches) => {
|
||||
matches.push(check.kind.code().as_ref());
|
||||
ignored.push(index)
|
||||
ignored.push(index);
|
||||
}
|
||||
(Directive::Codes(.., codes), matches) => {
|
||||
if codes.contains(&check.kind.code().as_ref()) {
|
||||
@@ -109,7 +140,7 @@ pub fn check_lines(
|
||||
ignored.push(index);
|
||||
}
|
||||
}
|
||||
(Directive::None, _) => {}
|
||||
(Directive::None, ..) => {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,10 +148,6 @@ pub fn check_lines(
|
||||
if enforce_line_too_long {
|
||||
let line_length = line.chars().count();
|
||||
if should_enforce_line_length(line, line_length, settings.line_length) {
|
||||
let noqa = noqa_directives
|
||||
.entry(noqa_lineno)
|
||||
.or_insert_with(|| (noqa::extract_noqa_directive(lines[noqa_lineno]), vec![]));
|
||||
|
||||
let check = Check::new(
|
||||
CheckKind::LineTooLong(line_length, settings.line_length),
|
||||
Range {
|
||||
@@ -129,35 +156,19 @@ pub fn check_lines(
|
||||
},
|
||||
);
|
||||
|
||||
match noqa {
|
||||
(Directive::All(..), matches) => {
|
||||
matches.push(check.kind.code().as_ref());
|
||||
}
|
||||
(Directive::Codes(.., codes), matches) => {
|
||||
if codes.contains(&check.kind.code().as_ref()) {
|
||||
matches.push(check.kind.code().as_ref());
|
||||
} else {
|
||||
line_checks.push(check);
|
||||
}
|
||||
}
|
||||
(Directive::None, _) => line_checks.push(check),
|
||||
}
|
||||
let noqa = noqa_directives
|
||||
.entry(noqa_lineno)
|
||||
.or_insert_with(|| (noqa::extract_noqa_directive(lines[noqa_lineno]), vec![]));
|
||||
add_if!(check, noqa);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Enforce newlines at end of files.
|
||||
// Enforce newlines at end of files (W292).
|
||||
if settings.enabled.contains(&CheckCode::W292) && !contents.ends_with('\n') {
|
||||
// Note: if `lines.last()` is `None`, then `contents` is empty (and so we don't
|
||||
// want to raise W292 anyway).
|
||||
if let Some(line) = lines.last() {
|
||||
let lineno = lines.len() - 1;
|
||||
let noqa_lineno = noqa_line_for.get(&(lineno + 1)).unwrap_or(&(lineno + 1)) - 1;
|
||||
|
||||
let noqa = noqa_directives
|
||||
.entry(noqa_lineno)
|
||||
.or_insert_with(|| (noqa::extract_noqa_directive(lines[noqa_lineno]), vec![]));
|
||||
|
||||
let check = Check::new(
|
||||
CheckKind::NoNewLineAtEndOfFile,
|
||||
Range {
|
||||
@@ -166,23 +177,16 @@ pub fn check_lines(
|
||||
},
|
||||
);
|
||||
|
||||
match noqa {
|
||||
(Directive::All(..), matches) => {
|
||||
matches.push(check.kind.code().as_ref());
|
||||
}
|
||||
(Directive::Codes(.., codes), matches) => {
|
||||
if codes.contains(&check.kind.code().as_ref()) {
|
||||
matches.push(check.kind.code().as_ref());
|
||||
} else {
|
||||
line_checks.push(check);
|
||||
}
|
||||
}
|
||||
(Directive::None, _) => line_checks.push(check),
|
||||
}
|
||||
let lineno = lines.len() - 1;
|
||||
let noqa_lineno = noqa_line_for.get(&(lineno + 1)).unwrap_or(&(lineno + 1)) - 1;
|
||||
let noqa = noqa_directives
|
||||
.entry(noqa_lineno)
|
||||
.or_insert_with(|| (noqa::extract_noqa_directive(lines[noqa_lineno]), vec![]));
|
||||
add_if!(check, noqa);
|
||||
}
|
||||
}
|
||||
|
||||
// Enforce that the noqa directive was actually used.
|
||||
// Enforce that the noqa directive was actually used (M001).
|
||||
if enforce_noqa {
|
||||
for (row, (directive, matches)) in noqa_directives {
|
||||
match directive {
|
||||
@@ -195,7 +199,7 @@ pub fn check_lines(
|
||||
end_location: Location::new(row + 1, end),
|
||||
},
|
||||
);
|
||||
if autofix.patch() && settings.fixable.contains(check.kind.code()) {
|
||||
if autofix && settings.fixable.contains(check.kind.code()) {
|
||||
check.amend(Fix::deletion(
|
||||
Location::new(row + 1, start - spaces),
|
||||
Location::new(row + 1, lines[row].chars().count()),
|
||||
@@ -208,10 +212,10 @@ pub fn check_lines(
|
||||
let mut invalid_codes = vec![];
|
||||
let mut valid_codes = vec![];
|
||||
for code in codes {
|
||||
if !matches.contains(&code) {
|
||||
invalid_codes.push(code.to_string());
|
||||
} else {
|
||||
if matches.contains(&code) || settings.external.contains(code) {
|
||||
valid_codes.push(code.to_string());
|
||||
} else {
|
||||
invalid_codes.push(code.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,7 +227,7 @@ pub fn check_lines(
|
||||
end_location: Location::new(row + 1, end),
|
||||
},
|
||||
);
|
||||
if autofix.patch() && settings.fixable.contains(check.kind.code()) {
|
||||
if autofix && settings.fixable.contains(check.kind.code()) {
|
||||
if valid_codes.is_empty() {
|
||||
check.amend(Fix::deletion(
|
||||
Location::new(row + 1, start - spaces),
|
||||
@@ -245,9 +249,11 @@ pub fn check_lines(
|
||||
}
|
||||
}
|
||||
|
||||
ignored.sort();
|
||||
for index in ignored.iter().rev() {
|
||||
checks.swap_remove(*index);
|
||||
if !ignore_noqa {
|
||||
ignored.sort_unstable();
|
||||
for index in ignored.iter().rev() {
|
||||
checks.swap_remove(*index);
|
||||
}
|
||||
}
|
||||
checks.extend(line_checks);
|
||||
}
|
||||
@@ -257,14 +263,13 @@ mod tests {
|
||||
use nohash_hasher::IntMap;
|
||||
|
||||
use super::check_lines;
|
||||
use crate::autofix::fixer;
|
||||
use crate::checks::{Check, CheckCode};
|
||||
use crate::settings::Settings;
|
||||
|
||||
#[test]
|
||||
fn e501_non_ascii_char() {
|
||||
let line = "'\u{4e9c}' * 2"; // 7 in UTF-32, 9 in UTF-8.
|
||||
let noqa_line_for: IntMap<usize, usize> = Default::default();
|
||||
let noqa_line_for: IntMap<usize, usize> = IntMap::default();
|
||||
let check_with_max_line_length = |line_length: usize| {
|
||||
let mut checks: Vec<Check> = vec![];
|
||||
check_lines(
|
||||
@@ -275,7 +280,8 @@ mod tests {
|
||||
line_length,
|
||||
..Settings::for_rule(CheckCode::E501)
|
||||
},
|
||||
&fixer::Mode::Generate,
|
||||
true,
|
||||
false,
|
||||
);
|
||||
checks
|
||||
};
|
||||
|
||||
@@ -2,20 +2,20 @@
|
||||
|
||||
use rustpython_parser::lexer::{LexResult, Tok};
|
||||
|
||||
use crate::autofix::fixer;
|
||||
use crate::checks::{Check, CheckCode};
|
||||
use crate::lex::docstring_detection::StateMachine;
|
||||
use crate::rules::checks::Context;
|
||||
use crate::source_code_locator::SourceCodeLocator;
|
||||
use crate::{flake8_quotes, pycodestyle, rules, Settings};
|
||||
use crate::{eradicate, flake8_quotes, pycodestyle, rules, Settings};
|
||||
|
||||
pub fn check_tokens(
|
||||
checks: &mut Vec<Check>,
|
||||
locator: &SourceCodeLocator,
|
||||
tokens: &[LexResult],
|
||||
settings: &Settings,
|
||||
autofix: &fixer::Mode,
|
||||
) {
|
||||
autofix: bool,
|
||||
) -> Vec<Check> {
|
||||
let mut checks: Vec<Check> = vec![];
|
||||
|
||||
let enforce_ambiguous_unicode_character = settings.enabled.contains(&CheckCode::RUF001)
|
||||
|| settings.enabled.contains(&CheckCode::RUF002)
|
||||
|| settings.enabled.contains(&CheckCode::RUF003);
|
||||
@@ -23,10 +23,11 @@ pub fn check_tokens(
|
||||
|| settings.enabled.contains(&CheckCode::Q001)
|
||||
|| settings.enabled.contains(&CheckCode::Q002)
|
||||
|| settings.enabled.contains(&CheckCode::Q003);
|
||||
let enforce_commented_out_code = settings.enabled.contains(&CheckCode::ERA001);
|
||||
let enforce_invalid_escape_sequence = settings.enabled.contains(&CheckCode::W605);
|
||||
|
||||
let mut state_machine: StateMachine = Default::default();
|
||||
for (start, tok, end) in tokens.iter().flatten() {
|
||||
let mut state_machine = StateMachine::default();
|
||||
for &(start, ref tok, end) in tokens.iter().flatten() {
|
||||
let is_docstring = if enforce_ambiguous_unicode_character || enforce_quotes {
|
||||
state_machine.consume(tok)
|
||||
} else {
|
||||
@@ -72,6 +73,17 @@ pub fn check_tokens(
|
||||
}
|
||||
}
|
||||
|
||||
// eradicate
|
||||
if enforce_commented_out_code {
|
||||
if matches!(tok, Tok::Comment) {
|
||||
if let Some(check) =
|
||||
eradicate::checks::commented_out_code(locator, start, end, settings, autofix)
|
||||
{
|
||||
checks.push(check);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// W605
|
||||
if enforce_invalid_escape_sequence {
|
||||
if matches!(tok, Tok::String { .. }) {
|
||||
@@ -81,4 +93,6 @@ pub fn check_tokens(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checks
|
||||
}
|
||||
|
||||
596
src/checks.rs
596
src/checks.rs
@@ -7,6 +7,7 @@ use strum_macros::{AsRefStr, EnumIter, EnumString};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::autofix::Fix;
|
||||
use crate::flake8_debugger::types::DebuggerUsingType;
|
||||
use crate::flake8_quotes::settings::Quote;
|
||||
use crate::flake8_tidy_imports::settings::Strictness;
|
||||
use crate::pyupgrade::types::Primitive;
|
||||
@@ -52,6 +53,20 @@ pub enum CheckCode {
|
||||
F405,
|
||||
F406,
|
||||
F407,
|
||||
F501,
|
||||
F502,
|
||||
F503,
|
||||
F504,
|
||||
F505,
|
||||
F506,
|
||||
F507,
|
||||
F508,
|
||||
F509,
|
||||
F521,
|
||||
F522,
|
||||
F523,
|
||||
F524,
|
||||
F525,
|
||||
F541,
|
||||
F601,
|
||||
F602,
|
||||
@@ -99,10 +114,12 @@ pub enum CheckCode {
|
||||
B020,
|
||||
B021,
|
||||
B022,
|
||||
B023,
|
||||
B024,
|
||||
B025,
|
||||
B026,
|
||||
B027,
|
||||
B904,
|
||||
// flake8-blind-except
|
||||
BLE001,
|
||||
// flake8-comprehensions
|
||||
@@ -122,6 +139,8 @@ pub enum CheckCode {
|
||||
C415,
|
||||
C416,
|
||||
C417,
|
||||
// flake8-debugger
|
||||
T100,
|
||||
// mccabe
|
||||
C901,
|
||||
// flake8-tidy-imports
|
||||
@@ -171,6 +190,7 @@ pub enum CheckCode {
|
||||
U012,
|
||||
U013,
|
||||
U014,
|
||||
U015,
|
||||
// pydocstyle
|
||||
D100,
|
||||
D101,
|
||||
@@ -234,6 +254,8 @@ pub enum CheckCode {
|
||||
N818,
|
||||
// isort
|
||||
I001,
|
||||
// eradicate
|
||||
ERA001,
|
||||
// flake8-bandit
|
||||
S101,
|
||||
S102,
|
||||
@@ -249,6 +271,7 @@ pub enum CheckCode {
|
||||
RUF001,
|
||||
RUF002,
|
||||
RUF003,
|
||||
RUF101,
|
||||
// Meta
|
||||
M001,
|
||||
}
|
||||
@@ -261,8 +284,10 @@ pub enum CheckCategory {
|
||||
Pydocstyle,
|
||||
Pyupgrade,
|
||||
PEP8Naming,
|
||||
Eradicate,
|
||||
Flake8Bandit,
|
||||
Flake8Comprehensions,
|
||||
Flake8Debugger,
|
||||
Flake8BooleanTrap,
|
||||
Flake8Bugbear,
|
||||
Flake8Builtins,
|
||||
@@ -280,65 +305,71 @@ pub enum CheckCategory {
|
||||
impl CheckCategory {
|
||||
pub fn title(&self) -> &'static str {
|
||||
match self {
|
||||
CheckCategory::Pycodestyle => "pycodestyle",
|
||||
CheckCategory::Pyflakes => "Pyflakes",
|
||||
CheckCategory::Isort => "isort",
|
||||
CheckCategory::Eradicate => "eradicate",
|
||||
CheckCategory::Flake82020 => "flake8-2020",
|
||||
CheckCategory::Flake8Annotations => "flake8-annotations",
|
||||
CheckCategory::Flake8Bandit => "flake8-bandit",
|
||||
CheckCategory::Flake8BlindExcept => "flake8-blind-except",
|
||||
CheckCategory::Flake8BooleanTrap => "flake8-boolean-trap",
|
||||
CheckCategory::Flake8Builtins => "flake8-builtins",
|
||||
CheckCategory::Flake8Bugbear => "flake8-bugbear",
|
||||
CheckCategory::Flake8Builtins => "flake8-builtins",
|
||||
CheckCategory::Flake8Comprehensions => "flake8-comprehensions",
|
||||
CheckCategory::Flake8TidyImports => "flake8-tidy-imports",
|
||||
CheckCategory::Flake8Debugger => "flake8-debugger",
|
||||
CheckCategory::Flake8Print => "flake8-print",
|
||||
CheckCategory::Flake8Quotes => "flake8-quotes",
|
||||
CheckCategory::Flake8Annotations => "flake8-annotations",
|
||||
CheckCategory::Flake82020 => "flake8-2020",
|
||||
CheckCategory::Flake8BlindExcept => "flake8-blind-except",
|
||||
CheckCategory::Pyupgrade => "pyupgrade",
|
||||
CheckCategory::Pydocstyle => "pydocstyle",
|
||||
CheckCategory::PEP8Naming => "pep8-naming",
|
||||
CheckCategory::Flake8TidyImports => "flake8-tidy-imports",
|
||||
CheckCategory::Isort => "isort",
|
||||
CheckCategory::McCabe => "mccabe",
|
||||
CheckCategory::Ruff => "Ruff-specific rules",
|
||||
CheckCategory::Meta => "Meta rules",
|
||||
CheckCategory::PEP8Naming => "pep8-naming",
|
||||
CheckCategory::Pycodestyle => "pycodestyle",
|
||||
CheckCategory::Pydocstyle => "pydocstyle",
|
||||
CheckCategory::Pyflakes => "Pyflakes",
|
||||
CheckCategory::Pyupgrade => "pyupgrade",
|
||||
CheckCategory::Ruff => "Ruff-specific rules",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn url(&self) -> Option<&'static str> {
|
||||
match self {
|
||||
CheckCategory::Pycodestyle => Some("https://pypi.org/project/pycodestyle/2.9.1/"),
|
||||
CheckCategory::Pyflakes => Some("https://pypi.org/project/pyflakes/2.5.0/"),
|
||||
CheckCategory::Isort => Some("https://pypi.org/project/isort/5.10.1/"),
|
||||
CheckCategory::Flake8Builtins => {
|
||||
Some("https://pypi.org/project/flake8-builtins/2.0.1/")
|
||||
}
|
||||
CheckCategory::Flake8Bugbear => {
|
||||
Some("https://pypi.org/project/flake8-bugbear/22.10.27/")
|
||||
}
|
||||
CheckCategory::Flake8Comprehensions => {
|
||||
Some("https://pypi.org/project/flake8-comprehensions/3.10.1/")
|
||||
}
|
||||
CheckCategory::Flake8TidyImports => {
|
||||
Some("https://pypi.org/project/flake8-tidy-imports/4.8.0/")
|
||||
}
|
||||
CheckCategory::Flake8Print => Some("https://pypi.org/project/flake8-print/5.0.0/"),
|
||||
CheckCategory::Flake8Quotes => Some("https://pypi.org/project/flake8-quotes/3.3.1/"),
|
||||
CheckCategory::Eradicate => Some("https://pypi.org/project/eradicate/2.1.0/"),
|
||||
CheckCategory::Flake82020 => Some("https://pypi.org/project/flake8-2020/1.7.0/"),
|
||||
CheckCategory::Flake8Annotations => {
|
||||
Some("https://pypi.org/project/flake8-annotations/2.9.1/")
|
||||
}
|
||||
CheckCategory::Flake82020 => Some("https://pypi.org/project/flake8-2020/1.7.0/"),
|
||||
CheckCategory::Pyupgrade => Some("https://pypi.org/project/pyupgrade/3.2.0/"),
|
||||
CheckCategory::Pydocstyle => Some("https://pypi.org/project/pydocstyle/6.1.1/"),
|
||||
CheckCategory::PEP8Naming => Some("https://pypi.org/project/pep8-naming/0.13.2/"),
|
||||
CheckCategory::Flake8Bandit => Some("https://pypi.org/project/flake8-bandit/4.1.1/"),
|
||||
CheckCategory::Flake8BlindExcept => {
|
||||
Some("https://pypi.org/project/flake8-blind-except/0.2.1/")
|
||||
}
|
||||
CheckCategory::McCabe => Some("https://pypi.org/project/mccabe/0.7.0/"),
|
||||
CheckCategory::Flake8BooleanTrap => {
|
||||
Some("https://pypi.org/project/flake8-boolean-trap/0.1.0/")
|
||||
}
|
||||
CheckCategory::Ruff => None,
|
||||
CheckCategory::Flake8Bugbear => {
|
||||
Some("https://pypi.org/project/flake8-bugbear/22.10.27/")
|
||||
}
|
||||
CheckCategory::Flake8Builtins => {
|
||||
Some("https://pypi.org/project/flake8-builtins/2.0.1/")
|
||||
}
|
||||
CheckCategory::Flake8Comprehensions => {
|
||||
Some("https://pypi.org/project/flake8-comprehensions/3.10.1/")
|
||||
}
|
||||
CheckCategory::Flake8Debugger => {
|
||||
Some("https://pypi.org/project/flake8-debugger/4.1.2/")
|
||||
}
|
||||
CheckCategory::Flake8Print => Some("https://pypi.org/project/flake8-print/5.0.0/"),
|
||||
CheckCategory::Flake8Quotes => Some("https://pypi.org/project/flake8-quotes/3.3.1/"),
|
||||
CheckCategory::Flake8TidyImports => {
|
||||
Some("https://pypi.org/project/flake8-tidy-imports/4.8.0/")
|
||||
}
|
||||
CheckCategory::Isort => Some("https://pypi.org/project/isort/5.10.1/"),
|
||||
CheckCategory::McCabe => Some("https://pypi.org/project/mccabe/0.7.0/"),
|
||||
CheckCategory::Meta => None,
|
||||
CheckCategory::PEP8Naming => Some("https://pypi.org/project/pep8-naming/0.13.2/"),
|
||||
CheckCategory::Pycodestyle => Some("https://pypi.org/project/pycodestyle/2.9.1/"),
|
||||
CheckCategory::Pydocstyle => Some("https://pypi.org/project/pydocstyle/6.1.1/"),
|
||||
CheckCategory::Pyflakes => Some("https://pypi.org/project/pyflakes/2.5.0/"),
|
||||
CheckCategory::Pyupgrade => Some("https://pypi.org/project/pyupgrade/3.2.0/"),
|
||||
CheckCategory::Ruff => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -398,13 +429,27 @@ pub enum CheckKind {
|
||||
LateFutureImport,
|
||||
MultiValueRepeatedKeyLiteral,
|
||||
MultiValueRepeatedKeyVariable(String),
|
||||
PercentFormatExpectedMapping,
|
||||
PercentFormatExpectedSequence,
|
||||
PercentFormatExtraNamedArguments(Vec<String>),
|
||||
PercentFormatInvalidFormat(String),
|
||||
PercentFormatMissingArgument(Vec<String>),
|
||||
PercentFormatMixedPositionalAndNamed,
|
||||
PercentFormatPositionalCountMismatch(usize, usize),
|
||||
PercentFormatStarRequiresSequence,
|
||||
PercentFormatUnsupportedFormatCharacter(char),
|
||||
RaiseNotImplemented,
|
||||
ReturnOutsideFunction,
|
||||
StringDotFormatExtraNamedArguments(Vec<String>),
|
||||
StringDotFormatExtraPositionalArguments(Vec<String>),
|
||||
StringDotFormatInvalidFormat(String),
|
||||
StringDotFormatMissingArguments(Vec<String>),
|
||||
StringDotFormatMixingAutomatic,
|
||||
TwoStarredExpressions,
|
||||
UndefinedExport(String),
|
||||
UndefinedLocal(String),
|
||||
UndefinedName(String),
|
||||
UnusedImport(Vec<String>, bool),
|
||||
UnusedImport(String, bool),
|
||||
UnusedVariable(String),
|
||||
YieldOutsideFunction,
|
||||
// flake8-builtins
|
||||
@@ -414,31 +459,33 @@ pub enum CheckKind {
|
||||
// flake8-blind-except
|
||||
BlindExcept,
|
||||
// flake8-bugbear
|
||||
UnaryPrefixIncrement,
|
||||
AssignmentToOsEnviron,
|
||||
UnreliableCallableCheck,
|
||||
StripWithMultiCharacters,
|
||||
MutableArgumentDefault,
|
||||
UnusedLoopControlVariable(String),
|
||||
FunctionCallArgumentDefault(Option<String>),
|
||||
GetAttrWithConstant,
|
||||
SetAttrWithConstant,
|
||||
DoNotAssertFalse,
|
||||
JumpStatementInFinally(String),
|
||||
RedundantTupleInExceptionHandler(String),
|
||||
DuplicateHandlerException(Vec<String>),
|
||||
UselessComparison,
|
||||
CannotRaiseLiteral,
|
||||
NoAssertRaisesException,
|
||||
UselessExpression,
|
||||
CachedInstanceMethod,
|
||||
LoopVariableOverridesIterator(String),
|
||||
FStringDocstring,
|
||||
UselessContextlibSuppress,
|
||||
AbstractBaseClassWithoutAbstractMethod(String),
|
||||
AssignmentToOsEnviron,
|
||||
CachedInstanceMethod,
|
||||
CannotRaiseLiteral,
|
||||
DoNotAssertFalse,
|
||||
DuplicateHandlerException(Vec<String>),
|
||||
DuplicateTryBlockException(String),
|
||||
StarArgUnpackingAfterKeywordArg,
|
||||
EmptyMethodWithoutAbstractDecorator(String),
|
||||
FStringDocstring,
|
||||
FunctionCallArgumentDefault(Option<String>),
|
||||
FunctionUsesLoopVariable(String),
|
||||
GetAttrWithConstant,
|
||||
JumpStatementInFinally(String),
|
||||
LoopVariableOverridesIterator(String),
|
||||
MutableArgumentDefault,
|
||||
NoAssertRaisesException,
|
||||
RaiseWithoutFromInsideExcept,
|
||||
RedundantTupleInExceptionHandler(String),
|
||||
SetAttrWithConstant,
|
||||
StarArgUnpackingAfterKeywordArg,
|
||||
StripWithMultiCharacters,
|
||||
UnaryPrefixIncrement,
|
||||
UnreliableCallableCheck,
|
||||
UnusedLoopControlVariable(String),
|
||||
UselessComparison,
|
||||
UselessContextlibSuppress,
|
||||
UselessExpression,
|
||||
// flake8-comprehensions
|
||||
UnnecessaryGeneratorList,
|
||||
UnnecessaryGeneratorSet,
|
||||
@@ -456,6 +503,8 @@ pub enum CheckKind {
|
||||
UnnecessarySubscriptReversal(String),
|
||||
UnnecessaryComprehension(String),
|
||||
UnnecessaryMap(String),
|
||||
// flake8-debugger
|
||||
Debugger(DebuggerUsingType),
|
||||
// flake8-tidy-imports
|
||||
BannedRelativeImport(Strictness),
|
||||
// flake8-print
|
||||
@@ -503,6 +552,7 @@ pub enum CheckKind {
|
||||
UnnecessaryEncodeUTF8,
|
||||
ConvertTypedDictFunctionalToClass(String),
|
||||
ConvertNamedTupleFunctionalToClass(String),
|
||||
RedundantOpenModes,
|
||||
// pydocstyle
|
||||
BlankLineAfterLastSection(String),
|
||||
BlankLineAfterSection(String),
|
||||
@@ -566,6 +616,8 @@ pub enum CheckKind {
|
||||
ErrorSuffixOnExceptionName(String),
|
||||
// isort
|
||||
UnsortedImports,
|
||||
// eradicate
|
||||
CommentedOutCode,
|
||||
// flake8-bandit
|
||||
AssertUsed,
|
||||
ExecUsed,
|
||||
@@ -583,6 +635,7 @@ pub enum CheckKind {
|
||||
AmbiguousUnicodeCharacterString(char, char),
|
||||
AmbiguousUnicodeCharacterDocstring(char, char),
|
||||
AmbiguousUnicodeCharacterComment(char, char),
|
||||
ConvertExitToSysExit,
|
||||
// Meta
|
||||
UnusedNOQA(Option<Vec<String>>),
|
||||
}
|
||||
@@ -595,7 +648,8 @@ impl CheckCode {
|
||||
CheckCode::E501 | CheckCode::W292 | CheckCode::M001 | CheckCode::U009 => {
|
||||
&LintSource::Lines
|
||||
}
|
||||
CheckCode::Q000
|
||||
CheckCode::ERA001
|
||||
| CheckCode::Q000
|
||||
| CheckCode::Q001
|
||||
| CheckCode::Q002
|
||||
| CheckCode::Q003
|
||||
@@ -609,7 +663,7 @@ impl CheckCode {
|
||||
}
|
||||
}
|
||||
|
||||
/// A placeholder representation of the CheckKind for the check.
|
||||
/// A placeholder representation of the `CheckKind` for the check.
|
||||
pub fn kind(&self) -> CheckKind {
|
||||
match self {
|
||||
// pycodestyle errors
|
||||
@@ -631,7 +685,7 @@ impl CheckCode {
|
||||
CheckCode::W292 => CheckKind::NoNewLineAtEndOfFile,
|
||||
CheckCode::W605 => CheckKind::InvalidEscapeSequence('c'),
|
||||
// pyflakes
|
||||
CheckCode::F401 => CheckKind::UnusedImport(vec!["...".to_string()], false),
|
||||
CheckCode::F401 => CheckKind::UnusedImport("...".to_string(), false),
|
||||
CheckCode::F402 => CheckKind::ImportShadowedByLoopVar("...".to_string(), 1),
|
||||
CheckCode::F403 => CheckKind::ImportStarUsed("...".to_string()),
|
||||
CheckCode::F404 => CheckKind::LateFutureImport,
|
||||
@@ -640,6 +694,24 @@ impl CheckCode {
|
||||
}
|
||||
CheckCode::F406 => CheckKind::ImportStarNotPermitted("...".to_string()),
|
||||
CheckCode::F407 => CheckKind::FutureFeatureNotDefined("...".to_string()),
|
||||
CheckCode::F501 => CheckKind::PercentFormatInvalidFormat("...".to_string()),
|
||||
CheckCode::F502 => CheckKind::PercentFormatExpectedMapping,
|
||||
CheckCode::F503 => CheckKind::PercentFormatExpectedSequence,
|
||||
CheckCode::F504 => CheckKind::PercentFormatExtraNamedArguments(vec!["...".to_string()]),
|
||||
CheckCode::F505 => CheckKind::PercentFormatMissingArgument(vec!["...".to_string()]),
|
||||
CheckCode::F506 => CheckKind::PercentFormatMixedPositionalAndNamed,
|
||||
CheckCode::F507 => CheckKind::PercentFormatPositionalCountMismatch(4, 2),
|
||||
CheckCode::F508 => CheckKind::PercentFormatStarRequiresSequence,
|
||||
CheckCode::F509 => CheckKind::PercentFormatUnsupportedFormatCharacter('c'),
|
||||
CheckCode::F521 => CheckKind::StringDotFormatInvalidFormat("...".to_string()),
|
||||
CheckCode::F522 => {
|
||||
CheckKind::StringDotFormatExtraNamedArguments(vec!["...".to_string()])
|
||||
}
|
||||
CheckCode::F523 => {
|
||||
CheckKind::StringDotFormatExtraPositionalArguments(vec!["...".to_string()])
|
||||
}
|
||||
CheckCode::F524 => CheckKind::StringDotFormatMissingArguments(vec!["...".to_string()]),
|
||||
CheckCode::F525 => CheckKind::StringDotFormatMixingAutomatic,
|
||||
CheckCode::F541 => CheckKind::FStringMissingPlaceholders,
|
||||
CheckCode::F601 => CheckKind::MultiValueRepeatedKeyLiteral,
|
||||
CheckCode::F602 => CheckKind::MultiValueRepeatedKeyVariable("...".to_string()),
|
||||
@@ -691,10 +763,12 @@ impl CheckCode {
|
||||
CheckCode::B020 => CheckKind::LoopVariableOverridesIterator("...".to_string()),
|
||||
CheckCode::B021 => CheckKind::FStringDocstring,
|
||||
CheckCode::B022 => CheckKind::UselessContextlibSuppress,
|
||||
CheckCode::B023 => CheckKind::FunctionUsesLoopVariable("...".to_string()),
|
||||
CheckCode::B024 => CheckKind::AbstractBaseClassWithoutAbstractMethod("...".to_string()),
|
||||
CheckCode::B025 => CheckKind::DuplicateTryBlockException("Exception".to_string()),
|
||||
CheckCode::B026 => CheckKind::StarArgUnpackingAfterKeywordArg,
|
||||
CheckCode::B027 => CheckKind::EmptyMethodWithoutAbstractDecorator("...".to_string()),
|
||||
CheckCode::B904 => CheckKind::RaiseWithoutFromInsideExcept,
|
||||
// flake8-comprehensions
|
||||
CheckCode::C400 => CheckKind::UnnecessaryGeneratorList,
|
||||
CheckCode::C401 => CheckKind::UnnecessaryGeneratorSet,
|
||||
@@ -725,6 +799,8 @@ impl CheckCode {
|
||||
}
|
||||
CheckCode::C416 => CheckKind::UnnecessaryComprehension("(list|set)".to_string()),
|
||||
CheckCode::C417 => CheckKind::UnnecessaryMap("(list|set|dict)".to_string()),
|
||||
// flake8-debugger
|
||||
CheckCode::T100 => CheckKind::Debugger(DebuggerUsingType::Import("...".to_string())),
|
||||
// flake8-tidy-imports
|
||||
CheckCode::I252 => CheckKind::BannedRelativeImport(Strictness::All),
|
||||
// flake8-print
|
||||
@@ -777,6 +853,7 @@ impl CheckCode {
|
||||
CheckCode::U012 => CheckKind::UnnecessaryEncodeUTF8,
|
||||
CheckCode::U013 => CheckKind::ConvertTypedDictFunctionalToClass("...".to_string()),
|
||||
CheckCode::U014 => CheckKind::ConvertNamedTupleFunctionalToClass("...".to_string()),
|
||||
CheckCode::U015 => CheckKind::RedundantOpenModes,
|
||||
// pydocstyle
|
||||
CheckCode::D100 => CheckKind::PublicModule,
|
||||
CheckCode::D101 => CheckKind::PublicClass,
|
||||
@@ -856,6 +933,8 @@ impl CheckCode {
|
||||
CheckCode::N818 => CheckKind::ErrorSuffixOnExceptionName("...".to_string()),
|
||||
// isort
|
||||
CheckCode::I001 => CheckKind::UnsortedImports,
|
||||
// eradicate
|
||||
CheckCode::ERA001 => CheckKind::CommentedOutCode,
|
||||
// flake8-bandit
|
||||
CheckCode::S101 => CheckKind::AssertUsed,
|
||||
CheckCode::S102 => CheckKind::ExecUsed,
|
||||
@@ -872,60 +951,29 @@ impl CheckCode {
|
||||
CheckCode::RUF001 => CheckKind::AmbiguousUnicodeCharacterString('𝐁', 'B'),
|
||||
CheckCode::RUF002 => CheckKind::AmbiguousUnicodeCharacterDocstring('𝐁', 'B'),
|
||||
CheckCode::RUF003 => CheckKind::AmbiguousUnicodeCharacterComment('𝐁', 'B'),
|
||||
CheckCode::RUF101 => CheckKind::ConvertExitToSysExit,
|
||||
// Meta
|
||||
CheckCode::M001 => CheckKind::UnusedNOQA(None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn category(&self) -> CheckCategory {
|
||||
#[allow(clippy::match_same_arms)]
|
||||
match self {
|
||||
CheckCode::E402 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E501 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E711 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E712 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E713 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E714 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E721 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E722 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E731 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E741 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E742 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E743 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E902 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E999 => CheckCategory::Pycodestyle,
|
||||
CheckCode::W292 => CheckCategory::Pycodestyle,
|
||||
CheckCode::W605 => CheckCategory::Pycodestyle,
|
||||
CheckCode::F401 => CheckCategory::Pyflakes,
|
||||
CheckCode::F402 => CheckCategory::Pyflakes,
|
||||
CheckCode::F403 => CheckCategory::Pyflakes,
|
||||
CheckCode::F404 => CheckCategory::Pyflakes,
|
||||
CheckCode::F405 => CheckCategory::Pyflakes,
|
||||
CheckCode::F406 => CheckCategory::Pyflakes,
|
||||
CheckCode::F407 => CheckCategory::Pyflakes,
|
||||
CheckCode::F541 => CheckCategory::Pyflakes,
|
||||
CheckCode::F601 => CheckCategory::Pyflakes,
|
||||
CheckCode::F602 => CheckCategory::Pyflakes,
|
||||
CheckCode::F621 => CheckCategory::Pyflakes,
|
||||
CheckCode::F622 => CheckCategory::Pyflakes,
|
||||
CheckCode::F631 => CheckCategory::Pyflakes,
|
||||
CheckCode::F632 => CheckCategory::Pyflakes,
|
||||
CheckCode::F633 => CheckCategory::Pyflakes,
|
||||
CheckCode::F634 => CheckCategory::Pyflakes,
|
||||
CheckCode::F701 => CheckCategory::Pyflakes,
|
||||
CheckCode::F702 => CheckCategory::Pyflakes,
|
||||
CheckCode::F704 => CheckCategory::Pyflakes,
|
||||
CheckCode::F706 => CheckCategory::Pyflakes,
|
||||
CheckCode::F707 => CheckCategory::Pyflakes,
|
||||
CheckCode::F722 => CheckCategory::Pyflakes,
|
||||
CheckCode::F821 => CheckCategory::Pyflakes,
|
||||
CheckCode::F822 => CheckCategory::Pyflakes,
|
||||
CheckCode::F823 => CheckCategory::Pyflakes,
|
||||
CheckCode::F831 => CheckCategory::Pyflakes,
|
||||
CheckCode::F841 => CheckCategory::Pyflakes,
|
||||
CheckCode::F901 => CheckCategory::Pyflakes,
|
||||
CheckCode::A001 => CheckCategory::Flake8Builtins,
|
||||
CheckCode::A002 => CheckCategory::Flake8Builtins,
|
||||
CheckCode::A003 => CheckCategory::Flake8Builtins,
|
||||
CheckCode::ANN001 => CheckCategory::Flake8Annotations,
|
||||
CheckCode::ANN002 => CheckCategory::Flake8Annotations,
|
||||
CheckCode::ANN003 => CheckCategory::Flake8Annotations,
|
||||
CheckCode::ANN101 => CheckCategory::Flake8Annotations,
|
||||
CheckCode::ANN102 => CheckCategory::Flake8Annotations,
|
||||
CheckCode::ANN201 => CheckCategory::Flake8Annotations,
|
||||
CheckCode::ANN202 => CheckCategory::Flake8Annotations,
|
||||
CheckCode::ANN204 => CheckCategory::Flake8Annotations,
|
||||
CheckCode::ANN205 => CheckCategory::Flake8Annotations,
|
||||
CheckCode::ANN206 => CheckCategory::Flake8Annotations,
|
||||
CheckCode::ANN401 => CheckCategory::Flake8Annotations,
|
||||
CheckCode::B002 => CheckCategory::Flake8Bugbear,
|
||||
CheckCode::B003 => CheckCategory::Flake8Bugbear,
|
||||
CheckCode::B004 => CheckCategory::Flake8Bugbear,
|
||||
@@ -947,10 +995,12 @@ impl CheckCode {
|
||||
CheckCode::B020 => CheckCategory::Flake8Bugbear,
|
||||
CheckCode::B021 => CheckCategory::Flake8Bugbear,
|
||||
CheckCode::B022 => CheckCategory::Flake8Bugbear,
|
||||
CheckCode::B023 => CheckCategory::Flake8Bugbear,
|
||||
CheckCode::B024 => CheckCategory::Flake8Bugbear,
|
||||
CheckCode::B025 => CheckCategory::Flake8Bugbear,
|
||||
CheckCode::B026 => CheckCategory::Flake8Bugbear,
|
||||
CheckCode::B027 => CheckCategory::Flake8Bugbear,
|
||||
CheckCode::B904 => CheckCategory::Flake8Bugbear,
|
||||
CheckCode::BLE001 => CheckCategory::Flake8BlindExcept,
|
||||
CheckCode::C400 => CheckCategory::Flake8Comprehensions,
|
||||
CheckCode::C401 => CheckCategory::Flake8Comprehensions,
|
||||
@@ -968,47 +1018,7 @@ impl CheckCode {
|
||||
CheckCode::C415 => CheckCategory::Flake8Comprehensions,
|
||||
CheckCode::C416 => CheckCategory::Flake8Comprehensions,
|
||||
CheckCode::C417 => CheckCategory::Flake8Comprehensions,
|
||||
CheckCode::I252 => CheckCategory::Flake8TidyImports,
|
||||
CheckCode::T201 => CheckCategory::Flake8Print,
|
||||
CheckCode::T203 => CheckCategory::Flake8Print,
|
||||
CheckCode::Q000 => CheckCategory::Flake8Quotes,
|
||||
CheckCode::Q001 => CheckCategory::Flake8Quotes,
|
||||
CheckCode::Q002 => CheckCategory::Flake8Quotes,
|
||||
CheckCode::Q003 => CheckCategory::Flake8Quotes,
|
||||
CheckCode::ANN001 => CheckCategory::Flake8Annotations,
|
||||
CheckCode::ANN002 => CheckCategory::Flake8Annotations,
|
||||
CheckCode::ANN003 => CheckCategory::Flake8Annotations,
|
||||
CheckCode::ANN101 => CheckCategory::Flake8Annotations,
|
||||
CheckCode::ANN102 => CheckCategory::Flake8Annotations,
|
||||
CheckCode::ANN201 => CheckCategory::Flake8Annotations,
|
||||
CheckCode::ANN202 => CheckCategory::Flake8Annotations,
|
||||
CheckCode::ANN204 => CheckCategory::Flake8Annotations,
|
||||
CheckCode::ANN205 => CheckCategory::Flake8Annotations,
|
||||
CheckCode::ANN206 => CheckCategory::Flake8Annotations,
|
||||
CheckCode::ANN401 => CheckCategory::Flake8Annotations,
|
||||
CheckCode::YTT101 => CheckCategory::Flake82020,
|
||||
CheckCode::YTT102 => CheckCategory::Flake82020,
|
||||
CheckCode::YTT103 => CheckCategory::Flake82020,
|
||||
CheckCode::YTT201 => CheckCategory::Flake82020,
|
||||
CheckCode::YTT202 => CheckCategory::Flake82020,
|
||||
CheckCode::YTT203 => CheckCategory::Flake82020,
|
||||
CheckCode::YTT204 => CheckCategory::Flake82020,
|
||||
CheckCode::YTT301 => CheckCategory::Flake82020,
|
||||
CheckCode::YTT302 => CheckCategory::Flake82020,
|
||||
CheckCode::YTT303 => CheckCategory::Flake82020,
|
||||
CheckCode::U001 => CheckCategory::Pyupgrade,
|
||||
CheckCode::U003 => CheckCategory::Pyupgrade,
|
||||
CheckCode::U004 => CheckCategory::Pyupgrade,
|
||||
CheckCode::U005 => CheckCategory::Pyupgrade,
|
||||
CheckCode::U006 => CheckCategory::Pyupgrade,
|
||||
CheckCode::U007 => CheckCategory::Pyupgrade,
|
||||
CheckCode::U008 => CheckCategory::Pyupgrade,
|
||||
CheckCode::U009 => CheckCategory::Pyupgrade,
|
||||
CheckCode::U010 => CheckCategory::Pyupgrade,
|
||||
CheckCode::U011 => CheckCategory::Pyupgrade,
|
||||
CheckCode::U012 => CheckCategory::Pyupgrade,
|
||||
CheckCode::U013 => CheckCategory::Pyupgrade,
|
||||
CheckCode::U014 => CheckCategory::Pyupgrade,
|
||||
CheckCode::C901 => CheckCategory::McCabe,
|
||||
CheckCode::D100 => CheckCategory::Pydocstyle,
|
||||
CheckCode::D101 => CheckCategory::Pydocstyle,
|
||||
CheckCode::D102 => CheckCategory::Pydocstyle,
|
||||
@@ -1053,6 +1063,69 @@ impl CheckCode {
|
||||
CheckCode::D417 => CheckCategory::Pydocstyle,
|
||||
CheckCode::D418 => CheckCategory::Pydocstyle,
|
||||
CheckCode::D419 => CheckCategory::Pydocstyle,
|
||||
CheckCode::E402 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E501 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E711 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E712 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E713 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E714 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E721 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E722 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E731 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E741 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E742 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E743 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E902 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E999 => CheckCategory::Pycodestyle,
|
||||
CheckCode::ERA001 => CheckCategory::Eradicate,
|
||||
CheckCode::F401 => CheckCategory::Pyflakes,
|
||||
CheckCode::F402 => CheckCategory::Pyflakes,
|
||||
CheckCode::F403 => CheckCategory::Pyflakes,
|
||||
CheckCode::F404 => CheckCategory::Pyflakes,
|
||||
CheckCode::F405 => CheckCategory::Pyflakes,
|
||||
CheckCode::F406 => CheckCategory::Pyflakes,
|
||||
CheckCode::F407 => CheckCategory::Pyflakes,
|
||||
CheckCode::F501 => CheckCategory::Pyflakes,
|
||||
CheckCode::F502 => CheckCategory::Pyflakes,
|
||||
CheckCode::F503 => CheckCategory::Pyflakes,
|
||||
CheckCode::F504 => CheckCategory::Pyflakes,
|
||||
CheckCode::F505 => CheckCategory::Pyflakes,
|
||||
CheckCode::F506 => CheckCategory::Pyflakes,
|
||||
CheckCode::F507 => CheckCategory::Pyflakes,
|
||||
CheckCode::F508 => CheckCategory::Pyflakes,
|
||||
CheckCode::F509 => CheckCategory::Pyflakes,
|
||||
CheckCode::F521 => CheckCategory::Pyflakes,
|
||||
CheckCode::F522 => CheckCategory::Pyflakes,
|
||||
CheckCode::F523 => CheckCategory::Pyflakes,
|
||||
CheckCode::F524 => CheckCategory::Pyflakes,
|
||||
CheckCode::F525 => CheckCategory::Pyflakes,
|
||||
CheckCode::F541 => CheckCategory::Pyflakes,
|
||||
CheckCode::F601 => CheckCategory::Pyflakes,
|
||||
CheckCode::F602 => CheckCategory::Pyflakes,
|
||||
CheckCode::F621 => CheckCategory::Pyflakes,
|
||||
CheckCode::F622 => CheckCategory::Pyflakes,
|
||||
CheckCode::F631 => CheckCategory::Pyflakes,
|
||||
CheckCode::F632 => CheckCategory::Pyflakes,
|
||||
CheckCode::F633 => CheckCategory::Pyflakes,
|
||||
CheckCode::F634 => CheckCategory::Pyflakes,
|
||||
CheckCode::F701 => CheckCategory::Pyflakes,
|
||||
CheckCode::F702 => CheckCategory::Pyflakes,
|
||||
CheckCode::F704 => CheckCategory::Pyflakes,
|
||||
CheckCode::F706 => CheckCategory::Pyflakes,
|
||||
CheckCode::F707 => CheckCategory::Pyflakes,
|
||||
CheckCode::F722 => CheckCategory::Pyflakes,
|
||||
CheckCode::F821 => CheckCategory::Pyflakes,
|
||||
CheckCode::F822 => CheckCategory::Pyflakes,
|
||||
CheckCode::F823 => CheckCategory::Pyflakes,
|
||||
CheckCode::F831 => CheckCategory::Pyflakes,
|
||||
CheckCode::F841 => CheckCategory::Pyflakes,
|
||||
CheckCode::F901 => CheckCategory::Pyflakes,
|
||||
CheckCode::FBT001 => CheckCategory::Flake8BooleanTrap,
|
||||
CheckCode::FBT002 => CheckCategory::Flake8BooleanTrap,
|
||||
CheckCode::FBT003 => CheckCategory::Flake8BooleanTrap,
|
||||
CheckCode::I001 => CheckCategory::Isort,
|
||||
CheckCode::I252 => CheckCategory::Flake8TidyImports,
|
||||
CheckCode::M001 => CheckCategory::Meta,
|
||||
CheckCode::N801 => CheckCategory::PEP8Naming,
|
||||
CheckCode::N802 => CheckCategory::PEP8Naming,
|
||||
CheckCode::N803 => CheckCategory::PEP8Naming,
|
||||
@@ -1068,21 +1141,49 @@ impl CheckCode {
|
||||
CheckCode::N816 => CheckCategory::PEP8Naming,
|
||||
CheckCode::N817 => CheckCategory::PEP8Naming,
|
||||
CheckCode::N818 => CheckCategory::PEP8Naming,
|
||||
CheckCode::I001 => CheckCategory::Isort,
|
||||
CheckCode::Q000 => CheckCategory::Flake8Quotes,
|
||||
CheckCode::Q001 => CheckCategory::Flake8Quotes,
|
||||
CheckCode::Q002 => CheckCategory::Flake8Quotes,
|
||||
CheckCode::Q003 => CheckCategory::Flake8Quotes,
|
||||
CheckCode::RUF001 => CheckCategory::Ruff,
|
||||
CheckCode::RUF002 => CheckCategory::Ruff,
|
||||
CheckCode::RUF003 => CheckCategory::Ruff,
|
||||
CheckCode::RUF101 => CheckCategory::Ruff,
|
||||
CheckCode::S101 => CheckCategory::Flake8Bandit,
|
||||
CheckCode::S102 => CheckCategory::Flake8Bandit,
|
||||
CheckCode::S104 => CheckCategory::Flake8Bandit,
|
||||
CheckCode::S105 => CheckCategory::Flake8Bandit,
|
||||
CheckCode::S106 => CheckCategory::Flake8Bandit,
|
||||
CheckCode::S107 => CheckCategory::Flake8Bandit,
|
||||
CheckCode::C901 => CheckCategory::McCabe,
|
||||
CheckCode::FBT001 => CheckCategory::Flake8BooleanTrap,
|
||||
CheckCode::FBT002 => CheckCategory::Flake8BooleanTrap,
|
||||
CheckCode::FBT003 => CheckCategory::Flake8BooleanTrap,
|
||||
CheckCode::RUF001 => CheckCategory::Ruff,
|
||||
CheckCode::RUF002 => CheckCategory::Ruff,
|
||||
CheckCode::RUF003 => CheckCategory::Ruff,
|
||||
CheckCode::M001 => CheckCategory::Meta,
|
||||
CheckCode::T100 => CheckCategory::Flake8Debugger,
|
||||
CheckCode::T201 => CheckCategory::Flake8Print,
|
||||
CheckCode::T203 => CheckCategory::Flake8Print,
|
||||
CheckCode::U001 => CheckCategory::Pyupgrade,
|
||||
CheckCode::U003 => CheckCategory::Pyupgrade,
|
||||
CheckCode::U004 => CheckCategory::Pyupgrade,
|
||||
CheckCode::U005 => CheckCategory::Pyupgrade,
|
||||
CheckCode::U006 => CheckCategory::Pyupgrade,
|
||||
CheckCode::U007 => CheckCategory::Pyupgrade,
|
||||
CheckCode::U008 => CheckCategory::Pyupgrade,
|
||||
CheckCode::U009 => CheckCategory::Pyupgrade,
|
||||
CheckCode::U010 => CheckCategory::Pyupgrade,
|
||||
CheckCode::U011 => CheckCategory::Pyupgrade,
|
||||
CheckCode::U012 => CheckCategory::Pyupgrade,
|
||||
CheckCode::U013 => CheckCategory::Pyupgrade,
|
||||
CheckCode::U014 => CheckCategory::Pyupgrade,
|
||||
CheckCode::U015 => CheckCategory::Pyupgrade,
|
||||
CheckCode::W292 => CheckCategory::Pycodestyle,
|
||||
CheckCode::W605 => CheckCategory::Pycodestyle,
|
||||
CheckCode::YTT101 => CheckCategory::Flake82020,
|
||||
CheckCode::YTT102 => CheckCategory::Flake82020,
|
||||
CheckCode::YTT103 => CheckCategory::Flake82020,
|
||||
CheckCode::YTT201 => CheckCategory::Flake82020,
|
||||
CheckCode::YTT202 => CheckCategory::Flake82020,
|
||||
CheckCode::YTT203 => CheckCategory::Flake82020,
|
||||
CheckCode::YTT204 => CheckCategory::Flake82020,
|
||||
CheckCode::YTT301 => CheckCategory::Flake82020,
|
||||
CheckCode::YTT302 => CheckCategory::Flake82020,
|
||||
CheckCode::YTT303 => CheckCategory::Flake82020,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1121,8 +1222,22 @@ impl CheckKind {
|
||||
CheckKind::NoneComparison(_) => &CheckCode::E711,
|
||||
CheckKind::NotInTest => &CheckCode::E713,
|
||||
CheckKind::NotIsTest => &CheckCode::E714,
|
||||
CheckKind::PercentFormatExpectedMapping => &CheckCode::F502,
|
||||
CheckKind::PercentFormatExpectedSequence => &CheckCode::F503,
|
||||
CheckKind::PercentFormatExtraNamedArguments(_) => &CheckCode::F504,
|
||||
CheckKind::PercentFormatInvalidFormat(_) => &CheckCode::F501,
|
||||
CheckKind::PercentFormatMissingArgument(_) => &CheckCode::F505,
|
||||
CheckKind::PercentFormatMixedPositionalAndNamed => &CheckCode::F506,
|
||||
CheckKind::PercentFormatPositionalCountMismatch(..) => &CheckCode::F507,
|
||||
CheckKind::PercentFormatStarRequiresSequence => &CheckCode::F508,
|
||||
CheckKind::PercentFormatUnsupportedFormatCharacter(_) => &CheckCode::F509,
|
||||
CheckKind::RaiseNotImplemented => &CheckCode::F901,
|
||||
CheckKind::ReturnOutsideFunction => &CheckCode::F706,
|
||||
CheckKind::StringDotFormatExtraNamedArguments(_) => &CheckCode::F522,
|
||||
CheckKind::StringDotFormatExtraPositionalArguments(_) => &CheckCode::F523,
|
||||
CheckKind::StringDotFormatInvalidFormat(_) => &CheckCode::F521,
|
||||
CheckKind::StringDotFormatMissingArguments(_) => &CheckCode::F524,
|
||||
CheckKind::StringDotFormatMixingAutomatic => &CheckCode::F525,
|
||||
CheckKind::SyntaxError(_) => &CheckCode::E999,
|
||||
CheckKind::ExpressionsInStarAssignment => &CheckCode::F621,
|
||||
CheckKind::TrueFalseComparison(..) => &CheckCode::E712,
|
||||
@@ -1142,31 +1257,33 @@ impl CheckKind {
|
||||
CheckKind::BuiltinArgumentShadowing(_) => &CheckCode::A002,
|
||||
CheckKind::BuiltinAttributeShadowing(_) => &CheckCode::A003,
|
||||
// flake8-bugbear
|
||||
CheckKind::UnaryPrefixIncrement => &CheckCode::B002,
|
||||
CheckKind::AssignmentToOsEnviron => &CheckCode::B003,
|
||||
CheckKind::UnreliableCallableCheck => &CheckCode::B004,
|
||||
CheckKind::StripWithMultiCharacters => &CheckCode::B005,
|
||||
CheckKind::MutableArgumentDefault => &CheckCode::B006,
|
||||
CheckKind::UnusedLoopControlVariable(_) => &CheckCode::B007,
|
||||
CheckKind::FunctionCallArgumentDefault(_) => &CheckCode::B008,
|
||||
CheckKind::GetAttrWithConstant => &CheckCode::B009,
|
||||
CheckKind::SetAttrWithConstant => &CheckCode::B010,
|
||||
CheckKind::DoNotAssertFalse => &CheckCode::B011,
|
||||
CheckKind::JumpStatementInFinally(_) => &CheckCode::B012,
|
||||
CheckKind::RedundantTupleInExceptionHandler(_) => &CheckCode::B013,
|
||||
CheckKind::DuplicateHandlerException(_) => &CheckCode::B014,
|
||||
CheckKind::UselessComparison => &CheckCode::B015,
|
||||
CheckKind::CannotRaiseLiteral => &CheckCode::B016,
|
||||
CheckKind::NoAssertRaisesException => &CheckCode::B017,
|
||||
CheckKind::UselessExpression => &CheckCode::B018,
|
||||
CheckKind::CachedInstanceMethod => &CheckCode::B019,
|
||||
CheckKind::LoopVariableOverridesIterator(_) => &CheckCode::B020,
|
||||
CheckKind::FStringDocstring => &CheckCode::B021,
|
||||
CheckKind::UselessContextlibSuppress => &CheckCode::B022,
|
||||
CheckKind::AbstractBaseClassWithoutAbstractMethod(_) => &CheckCode::B024,
|
||||
CheckKind::AssignmentToOsEnviron => &CheckCode::B003,
|
||||
CheckKind::CachedInstanceMethod => &CheckCode::B019,
|
||||
CheckKind::CannotRaiseLiteral => &CheckCode::B016,
|
||||
CheckKind::DoNotAssertFalse => &CheckCode::B011,
|
||||
CheckKind::DuplicateHandlerException(_) => &CheckCode::B014,
|
||||
CheckKind::DuplicateTryBlockException(_) => &CheckCode::B025,
|
||||
CheckKind::StarArgUnpackingAfterKeywordArg => &CheckCode::B026,
|
||||
CheckKind::EmptyMethodWithoutAbstractDecorator(_) => &CheckCode::B027,
|
||||
CheckKind::FStringDocstring => &CheckCode::B021,
|
||||
CheckKind::FunctionCallArgumentDefault(_) => &CheckCode::B008,
|
||||
CheckKind::FunctionUsesLoopVariable(_) => &CheckCode::B023,
|
||||
CheckKind::GetAttrWithConstant => &CheckCode::B009,
|
||||
CheckKind::JumpStatementInFinally(_) => &CheckCode::B012,
|
||||
CheckKind::LoopVariableOverridesIterator(_) => &CheckCode::B020,
|
||||
CheckKind::MutableArgumentDefault => &CheckCode::B006,
|
||||
CheckKind::NoAssertRaisesException => &CheckCode::B017,
|
||||
CheckKind::RaiseWithoutFromInsideExcept => &CheckCode::B904,
|
||||
CheckKind::RedundantTupleInExceptionHandler(_) => &CheckCode::B013,
|
||||
CheckKind::SetAttrWithConstant => &CheckCode::B010,
|
||||
CheckKind::StarArgUnpackingAfterKeywordArg => &CheckCode::B026,
|
||||
CheckKind::StripWithMultiCharacters => &CheckCode::B005,
|
||||
CheckKind::UnaryPrefixIncrement => &CheckCode::B002,
|
||||
CheckKind::UnreliableCallableCheck => &CheckCode::B004,
|
||||
CheckKind::UnusedLoopControlVariable(_) => &CheckCode::B007,
|
||||
CheckKind::UselessComparison => &CheckCode::B015,
|
||||
CheckKind::UselessContextlibSuppress => &CheckCode::B022,
|
||||
CheckKind::UselessExpression => &CheckCode::B018,
|
||||
// flake8-blind-except
|
||||
CheckKind::BlindExcept => &CheckCode::BLE001,
|
||||
// flake8-comprehensions
|
||||
@@ -1186,6 +1303,8 @@ impl CheckKind {
|
||||
CheckKind::UnnecessarySubscriptReversal(_) => &CheckCode::C415,
|
||||
CheckKind::UnnecessaryComprehension(..) => &CheckCode::C416,
|
||||
CheckKind::UnnecessaryMap(_) => &CheckCode::C417,
|
||||
// flake8-debugger
|
||||
CheckKind::Debugger(_) => &CheckCode::T100,
|
||||
// flake8-tidy-imports
|
||||
CheckKind::BannedRelativeImport(_) => &CheckCode::I252,
|
||||
// flake8-print
|
||||
@@ -1233,6 +1352,7 @@ impl CheckKind {
|
||||
CheckKind::UnnecessaryEncodeUTF8 => &CheckCode::U012,
|
||||
CheckKind::ConvertTypedDictFunctionalToClass(_) => &CheckCode::U013,
|
||||
CheckKind::ConvertNamedTupleFunctionalToClass(_) => &CheckCode::U014,
|
||||
CheckKind::RedundantOpenModes => &CheckCode::U015,
|
||||
// pydocstyle
|
||||
CheckKind::BlankLineAfterLastSection(_) => &CheckCode::D413,
|
||||
CheckKind::BlankLineAfterSection(_) => &CheckCode::D410,
|
||||
@@ -1296,6 +1416,8 @@ impl CheckKind {
|
||||
CheckKind::ErrorSuffixOnExceptionName(..) => &CheckCode::N818,
|
||||
// isort
|
||||
CheckKind::UnsortedImports => &CheckCode::I001,
|
||||
// eradicate
|
||||
CheckKind::CommentedOutCode => &CheckCode::ERA001,
|
||||
// flake8-bandit
|
||||
CheckKind::AssertUsed => &CheckCode::S101,
|
||||
CheckKind::ExecUsed => &CheckCode::S102,
|
||||
@@ -1313,6 +1435,7 @@ impl CheckKind {
|
||||
CheckKind::AmbiguousUnicodeCharacterString(..) => &CheckCode::RUF001,
|
||||
CheckKind::AmbiguousUnicodeCharacterDocstring(..) => &CheckCode::RUF002,
|
||||
CheckKind::AmbiguousUnicodeCharacterComment(..) => &CheckCode::RUF003,
|
||||
CheckKind::ConvertExitToSysExit => &CheckCode::RUF101,
|
||||
// Meta
|
||||
CheckKind::UnusedNOQA(_) => &CheckCode::M001,
|
||||
}
|
||||
@@ -1323,13 +1446,13 @@ impl CheckKind {
|
||||
match self {
|
||||
// pycodestyle errors
|
||||
CheckKind::AmbiguousClassName(name) => {
|
||||
format!("Ambiguous class name: `{}`", name)
|
||||
format!("Ambiguous class name: `{name}`")
|
||||
}
|
||||
CheckKind::AmbiguousFunctionName(name) => {
|
||||
format!("Ambiguous function name: `{}`", name)
|
||||
format!("Ambiguous function name: `{name}`")
|
||||
}
|
||||
CheckKind::AmbiguousVariableName(name) => {
|
||||
format!("Ambiguous variable name: `{}`", name)
|
||||
format!("Ambiguous variable name: `{name}`")
|
||||
}
|
||||
CheckKind::AssertTuple => {
|
||||
"Assert test is a non-empty tuple, which is always `True`".to_string()
|
||||
@@ -1372,7 +1495,7 @@ impl CheckKind {
|
||||
CheckKind::ImportStarUsage(name, sources) => {
|
||||
let sources = sources
|
||||
.iter()
|
||||
.map(|source| format!("`{}`", source))
|
||||
.map(|source| format!("`{source}`"))
|
||||
.join(", ");
|
||||
format!("`{name}` may be undefined, or defined from star imports: {sources}")
|
||||
}
|
||||
@@ -1400,34 +1523,75 @@ impl CheckKind {
|
||||
},
|
||||
CheckKind::NotInTest => "Test for membership should be `not in`".to_string(),
|
||||
CheckKind::NotIsTest => "Test for object identity should be `is not`".to_string(),
|
||||
CheckKind::PercentFormatInvalidFormat(message) => {
|
||||
format!("'...' % ... has invalid format string: {message}")
|
||||
}
|
||||
CheckKind::PercentFormatUnsupportedFormatCharacter(char) => {
|
||||
format!("'...' % ... has unsupported format character '{char}'")
|
||||
}
|
||||
CheckKind::PercentFormatExpectedMapping => {
|
||||
"'...' % ... expected mapping but got sequence".to_string()
|
||||
}
|
||||
CheckKind::PercentFormatExpectedSequence => {
|
||||
"'...' % ... expected sequence but got mapping".to_string()
|
||||
}
|
||||
CheckKind::PercentFormatExtraNamedArguments(missing) => {
|
||||
let message = missing.join(", ");
|
||||
format!("'...' % ... has unused named argument(s): {message}")
|
||||
}
|
||||
CheckKind::PercentFormatMissingArgument(missing) => {
|
||||
let message = missing.join(", ");
|
||||
format!("'...' % ... is missing argument(s) for placeholder(s): {message}")
|
||||
}
|
||||
CheckKind::PercentFormatMixedPositionalAndNamed => {
|
||||
"'...' % ... has mixed positional and named placeholders".to_string()
|
||||
}
|
||||
CheckKind::PercentFormatPositionalCountMismatch(wanted, got) => {
|
||||
format!("'...' % ... has {wanted} placeholder(s) but {got} substitution(s)")
|
||||
}
|
||||
CheckKind::PercentFormatStarRequiresSequence => {
|
||||
"'...' % ... `*` specifier requires sequence".to_string()
|
||||
}
|
||||
CheckKind::RaiseNotImplemented => {
|
||||
"`raise NotImplemented` should be `raise NotImplementedError`".to_string()
|
||||
}
|
||||
CheckKind::ReturnOutsideFunction => {
|
||||
"`return` statement outside of a function/method".to_string()
|
||||
}
|
||||
CheckKind::StringDotFormatExtraNamedArguments(missing) => {
|
||||
let message = missing.join(", ");
|
||||
format!("'...'.format(...) has unused named argument(s): {message}")
|
||||
}
|
||||
CheckKind::StringDotFormatExtraPositionalArguments(missing) => {
|
||||
let message = missing.join(", ");
|
||||
format!("'...'.format(...) has unused arguments at position(s): {message}")
|
||||
}
|
||||
CheckKind::StringDotFormatInvalidFormat(message) => {
|
||||
format!("'...'.format(...) has invalid format string: {message}")
|
||||
}
|
||||
CheckKind::StringDotFormatMissingArguments(missing) => {
|
||||
let message = missing.join(", ");
|
||||
format!("'...'.format(...) is missing argument(s) for placeholder(s): {message}")
|
||||
}
|
||||
CheckKind::StringDotFormatMixingAutomatic => {
|
||||
"'...'.format(...) mixes automatic and manual numbering".to_string()
|
||||
}
|
||||
CheckKind::SyntaxError(message) => format!("SyntaxError: {message}"),
|
||||
CheckKind::ExpressionsInStarAssignment => {
|
||||
"Too many expressions in star-unpacking assignment".to_string()
|
||||
}
|
||||
CheckKind::TrueFalseComparison(value, op) => match *value {
|
||||
true => match op {
|
||||
RejectedCmpop::Eq => {
|
||||
"Comparison to `True` should be `cond is True`".to_string()
|
||||
}
|
||||
RejectedCmpop::NotEq => {
|
||||
"Comparison to `True` should be `cond is not True`".to_string()
|
||||
}
|
||||
},
|
||||
false => match op {
|
||||
RejectedCmpop::Eq => {
|
||||
"Comparison to `False` should be `cond is False`".to_string()
|
||||
}
|
||||
RejectedCmpop::NotEq => {
|
||||
"Comparison to `False` should be `cond is not False`".to_string()
|
||||
}
|
||||
},
|
||||
},
|
||||
CheckKind::TrueFalseComparison(true, RejectedCmpop::Eq) => {
|
||||
"Comparison to `True` should be `cond is True`".to_string()
|
||||
}
|
||||
CheckKind::TrueFalseComparison(true, RejectedCmpop::NotEq) => {
|
||||
"Comparison to `True` should be `cond is not True`".to_string()
|
||||
}
|
||||
CheckKind::TrueFalseComparison(false, RejectedCmpop::Eq) => {
|
||||
"Comparison to `False` should be `cond is False`".to_string()
|
||||
}
|
||||
CheckKind::TrueFalseComparison(false, RejectedCmpop::NotEq) => {
|
||||
"Comparison to `False` should be `cond is not False`".to_string()
|
||||
}
|
||||
CheckKind::TwoStarredExpressions => "Two starred expressions in assignment".to_string(),
|
||||
CheckKind::TypeComparison => "Do not compare types, use `isinstance()`".to_string(),
|
||||
CheckKind::UndefinedExport(name) => {
|
||||
@@ -1439,12 +1603,11 @@ impl CheckKind {
|
||||
CheckKind::UndefinedName(name) => {
|
||||
format!("Undefined name `{name}`")
|
||||
}
|
||||
CheckKind::UnusedImport(names, in_init_py) => {
|
||||
let names = names.iter().map(|name| format!("`{name}`")).join(", ");
|
||||
CheckKind::UnusedImport(name, in_init_py) => {
|
||||
if *in_init_py {
|
||||
format!("{names} imported but unused and missing from `__all__`")
|
||||
format!("`{name}` imported but unused and missing from `__all__`")
|
||||
} else {
|
||||
format!("{names} imported but unused")
|
||||
format!("`{name}` imported but unused")
|
||||
}
|
||||
}
|
||||
CheckKind::UnusedVariable(name) => {
|
||||
@@ -1497,6 +1660,9 @@ impl CheckKind {
|
||||
"Do not perform function call in argument defaults".to_string()
|
||||
}
|
||||
}
|
||||
CheckKind::FunctionUsesLoopVariable(name) => {
|
||||
format!("Function definition does not bind loop variable `{name}`")
|
||||
}
|
||||
CheckKind::GetAttrWithConstant => "Do not call `getattr` with a constant attribute \
|
||||
value. It is not any safer than normal property \
|
||||
access."
|
||||
@@ -1575,6 +1741,11 @@ impl CheckKind {
|
||||
decorator"
|
||||
)
|
||||
}
|
||||
CheckKind::RaiseWithoutFromInsideExcept => {
|
||||
"Within an except clause, raise exceptions with raise ... from err or raise ... \
|
||||
from None to distinguish them from errors in exception handling"
|
||||
.to_string()
|
||||
}
|
||||
// flake8-comprehensions
|
||||
CheckKind::UnnecessaryGeneratorList => {
|
||||
"Unnecessary generator (rewrite as a `list` comprehension)".to_string()
|
||||
@@ -1648,6 +1819,11 @@ impl CheckKind {
|
||||
format!("Unnecessary `map` usage (rewrite using a `{obj_type}` comprehension)")
|
||||
}
|
||||
}
|
||||
// flake8-debugger
|
||||
CheckKind::Debugger(using_type) => match using_type {
|
||||
DebuggerUsingType::Call(name) => format!("Trace found: `{name}` used"),
|
||||
DebuggerUsingType::Import(name) => format!("Import for `{name}` found"),
|
||||
},
|
||||
// flake8-tidy-imports
|
||||
CheckKind::BannedRelativeImport(strictness) => match strictness {
|
||||
Strictness::Parents => {
|
||||
@@ -1781,6 +1957,7 @@ impl CheckKind {
|
||||
"Unnecessary parameters to `functools.lru_cache`".to_string()
|
||||
}
|
||||
CheckKind::UnnecessaryEncodeUTF8 => "Unnecessary call to `encode` as UTF-8".to_string(),
|
||||
CheckKind::RedundantOpenModes => "Unnecessary open mode parameters".to_string(),
|
||||
CheckKind::ConvertTypedDictFunctionalToClass(name) => {
|
||||
format!("Convert `{name}` from `TypedDict` functional to class syntax")
|
||||
}
|
||||
@@ -1952,6 +2129,8 @@ impl CheckKind {
|
||||
}
|
||||
// isort
|
||||
CheckKind::UnsortedImports => "Import block is un-sorted or un-formatted".to_string(),
|
||||
// eradicate
|
||||
CheckKind::CommentedOutCode => "Found commented-out code".to_string(),
|
||||
// flake8-bandit
|
||||
CheckKind::AssertUsed => "Use of `assert` detected".to_string(),
|
||||
CheckKind::ExecUsed => "Use of `exec` detected".to_string(),
|
||||
@@ -2002,6 +2181,9 @@ impl CheckKind {
|
||||
'{representant}'?)"
|
||||
)
|
||||
}
|
||||
CheckKind::ConvertExitToSysExit => "`exit()` is only available in the interpreter, \
|
||||
use `sys.exit()` instead"
|
||||
.to_string(),
|
||||
// Meta
|
||||
CheckKind::UnusedNOQA(codes) => match codes {
|
||||
None => "Unused `noqa` directive".to_string(),
|
||||
@@ -2053,6 +2235,8 @@ impl CheckKind {
|
||||
| CheckKind::BlankLineAfterSummary
|
||||
| CheckKind::BlankLineBeforeSection(..)
|
||||
| CheckKind::CapitalizeSectionName(..)
|
||||
| CheckKind::CommentedOutCode
|
||||
| CheckKind::ConvertExitToSysExit
|
||||
| CheckKind::ConvertNamedTupleFunctionalToClass(..)
|
||||
| CheckKind::ConvertTypedDictFunctionalToClass(..)
|
||||
| CheckKind::DashedUnderlineAfterSection(..)
|
||||
@@ -2080,6 +2264,7 @@ impl CheckKind {
|
||||
| CheckKind::PPrintFound
|
||||
| CheckKind::PrintFound
|
||||
| CheckKind::RaiseNotImplemented
|
||||
| CheckKind::RedundantTupleInExceptionHandler(..)
|
||||
| CheckKind::SectionNameEndsInColon(..)
|
||||
| CheckKind::SectionNotOverIndented(..)
|
||||
| CheckKind::SectionUnderlineAfterName(..)
|
||||
@@ -2093,6 +2278,7 @@ impl CheckKind {
|
||||
| CheckKind::UnnecessaryComprehension(..)
|
||||
| CheckKind::UnnecessaryEncodeUTF8
|
||||
| CheckKind::UnnecessaryFutureImport(..)
|
||||
| CheckKind::RedundantOpenModes
|
||||
| CheckKind::UnnecessaryGeneratorDict
|
||||
| CheckKind::UnnecessaryGeneratorList
|
||||
| CheckKind::UnnecessaryGeneratorSet
|
||||
@@ -2143,13 +2329,12 @@ impl Check {
|
||||
mod tests {
|
||||
use std::str::FromStr;
|
||||
|
||||
use anyhow::Result;
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use crate::checks::CheckCode;
|
||||
|
||||
#[test]
|
||||
fn check_code_serialization() -> Result<()> {
|
||||
fn check_code_serialization() {
|
||||
for check_code in CheckCode::iter() {
|
||||
assert!(
|
||||
CheckCode::from_str(check_code.as_ref()).is_ok(),
|
||||
@@ -2157,6 +2342,5 @@ mod tests {
|
||||
check_code
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//! File automatically generated by examples/generate_check_code_prefix.rs.
|
||||
//! File automatically generated by `examples/generate_check_code_prefix.rs`.
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum_macros::EnumString;
|
||||
@@ -59,10 +59,14 @@ pub enum CheckCodePrefix {
|
||||
B020,
|
||||
B021,
|
||||
B022,
|
||||
B023,
|
||||
B024,
|
||||
B025,
|
||||
B026,
|
||||
B027,
|
||||
B9,
|
||||
B90,
|
||||
B904,
|
||||
BLE,
|
||||
BLE0,
|
||||
BLE00,
|
||||
@@ -172,6 +176,10 @@ pub enum CheckCodePrefix {
|
||||
E902,
|
||||
E99,
|
||||
E999,
|
||||
ERA,
|
||||
ERA0,
|
||||
ERA00,
|
||||
ERA001,
|
||||
F,
|
||||
F4,
|
||||
F40,
|
||||
@@ -183,6 +191,22 @@ pub enum CheckCodePrefix {
|
||||
F406,
|
||||
F407,
|
||||
F5,
|
||||
F50,
|
||||
F501,
|
||||
F502,
|
||||
F503,
|
||||
F504,
|
||||
F505,
|
||||
F506,
|
||||
F507,
|
||||
F508,
|
||||
F509,
|
||||
F52,
|
||||
F521,
|
||||
F522,
|
||||
F523,
|
||||
F524,
|
||||
F525,
|
||||
F54,
|
||||
F541,
|
||||
F6,
|
||||
@@ -267,6 +291,9 @@ pub enum CheckCodePrefix {
|
||||
RUF001,
|
||||
RUF002,
|
||||
RUF003,
|
||||
RUF1,
|
||||
RUF10,
|
||||
RUF101,
|
||||
S,
|
||||
S1,
|
||||
S10,
|
||||
@@ -277,6 +304,9 @@ pub enum CheckCodePrefix {
|
||||
S106,
|
||||
S107,
|
||||
T,
|
||||
T1,
|
||||
T10,
|
||||
T100,
|
||||
T2,
|
||||
T20,
|
||||
T201,
|
||||
@@ -298,6 +328,7 @@ pub enum CheckCodePrefix {
|
||||
U012,
|
||||
U013,
|
||||
U014,
|
||||
U015,
|
||||
W,
|
||||
W2,
|
||||
W29,
|
||||
@@ -334,6 +365,7 @@ pub enum PrefixSpecificity {
|
||||
|
||||
impl CheckCodePrefix {
|
||||
pub fn codes(&self) -> Vec<CheckCode> {
|
||||
#[allow(clippy::match_same_arms)]
|
||||
match self {
|
||||
CheckCodePrefix::A => vec![CheckCode::A001, CheckCode::A002, CheckCode::A003],
|
||||
CheckCodePrefix::A0 => vec![CheckCode::A001, CheckCode::A002, CheckCode::A003],
|
||||
@@ -407,10 +439,12 @@ impl CheckCodePrefix {
|
||||
CheckCode::B020,
|
||||
CheckCode::B021,
|
||||
CheckCode::B022,
|
||||
CheckCode::B023,
|
||||
CheckCode::B024,
|
||||
CheckCode::B025,
|
||||
CheckCode::B026,
|
||||
CheckCode::B027,
|
||||
CheckCode::B904,
|
||||
],
|
||||
CheckCodePrefix::B0 => vec![
|
||||
CheckCode::B002,
|
||||
@@ -434,6 +468,7 @@ impl CheckCodePrefix {
|
||||
CheckCode::B020,
|
||||
CheckCode::B021,
|
||||
CheckCode::B022,
|
||||
CheckCode::B023,
|
||||
CheckCode::B024,
|
||||
CheckCode::B025,
|
||||
CheckCode::B026,
|
||||
@@ -483,6 +518,7 @@ impl CheckCodePrefix {
|
||||
CheckCode::B020,
|
||||
CheckCode::B021,
|
||||
CheckCode::B022,
|
||||
CheckCode::B023,
|
||||
CheckCode::B024,
|
||||
CheckCode::B025,
|
||||
CheckCode::B026,
|
||||
@@ -491,10 +527,14 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::B020 => vec![CheckCode::B020],
|
||||
CheckCodePrefix::B021 => vec![CheckCode::B021],
|
||||
CheckCodePrefix::B022 => vec![CheckCode::B022],
|
||||
CheckCodePrefix::B023 => vec![CheckCode::B023],
|
||||
CheckCodePrefix::B024 => vec![CheckCode::B024],
|
||||
CheckCodePrefix::B025 => vec![CheckCode::B025],
|
||||
CheckCodePrefix::B026 => vec![CheckCode::B026],
|
||||
CheckCodePrefix::B027 => vec![CheckCode::B027],
|
||||
CheckCodePrefix::B9 => vec![CheckCode::B904],
|
||||
CheckCodePrefix::B90 => vec![CheckCode::B904],
|
||||
CheckCodePrefix::B904 => vec![CheckCode::B904],
|
||||
CheckCodePrefix::BLE => vec![CheckCode::BLE001],
|
||||
CheckCodePrefix::BLE0 => vec![CheckCode::BLE001],
|
||||
CheckCodePrefix::BLE00 => vec![CheckCode::BLE001],
|
||||
@@ -827,6 +867,10 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::E902 => vec![CheckCode::E902],
|
||||
CheckCodePrefix::E99 => vec![CheckCode::E999],
|
||||
CheckCodePrefix::E999 => vec![CheckCode::E999],
|
||||
CheckCodePrefix::ERA => vec![CheckCode::ERA001],
|
||||
CheckCodePrefix::ERA0 => vec![CheckCode::ERA001],
|
||||
CheckCodePrefix::ERA00 => vec![CheckCode::ERA001],
|
||||
CheckCodePrefix::ERA001 => vec![CheckCode::ERA001],
|
||||
CheckCodePrefix::F => vec![
|
||||
CheckCode::F401,
|
||||
CheckCode::F402,
|
||||
@@ -835,6 +879,20 @@ impl CheckCodePrefix {
|
||||
CheckCode::F405,
|
||||
CheckCode::F406,
|
||||
CheckCode::F407,
|
||||
CheckCode::F501,
|
||||
CheckCode::F502,
|
||||
CheckCode::F503,
|
||||
CheckCode::F504,
|
||||
CheckCode::F505,
|
||||
CheckCode::F506,
|
||||
CheckCode::F507,
|
||||
CheckCode::F508,
|
||||
CheckCode::F509,
|
||||
CheckCode::F521,
|
||||
CheckCode::F522,
|
||||
CheckCode::F523,
|
||||
CheckCode::F524,
|
||||
CheckCode::F525,
|
||||
CheckCode::F541,
|
||||
CheckCode::F601,
|
||||
CheckCode::F602,
|
||||
@@ -882,7 +940,55 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::F405 => vec![CheckCode::F405],
|
||||
CheckCodePrefix::F406 => vec![CheckCode::F406],
|
||||
CheckCodePrefix::F407 => vec![CheckCode::F407],
|
||||
CheckCodePrefix::F5 => vec![CheckCode::F541],
|
||||
CheckCodePrefix::F5 => vec![
|
||||
CheckCode::F501,
|
||||
CheckCode::F502,
|
||||
CheckCode::F503,
|
||||
CheckCode::F504,
|
||||
CheckCode::F505,
|
||||
CheckCode::F506,
|
||||
CheckCode::F507,
|
||||
CheckCode::F508,
|
||||
CheckCode::F509,
|
||||
CheckCode::F521,
|
||||
CheckCode::F522,
|
||||
CheckCode::F523,
|
||||
CheckCode::F524,
|
||||
CheckCode::F525,
|
||||
CheckCode::F541,
|
||||
],
|
||||
CheckCodePrefix::F50 => vec![
|
||||
CheckCode::F501,
|
||||
CheckCode::F502,
|
||||
CheckCode::F503,
|
||||
CheckCode::F504,
|
||||
CheckCode::F505,
|
||||
CheckCode::F506,
|
||||
CheckCode::F507,
|
||||
CheckCode::F508,
|
||||
CheckCode::F509,
|
||||
],
|
||||
CheckCodePrefix::F501 => vec![CheckCode::F501],
|
||||
CheckCodePrefix::F502 => vec![CheckCode::F502],
|
||||
CheckCodePrefix::F503 => vec![CheckCode::F503],
|
||||
CheckCodePrefix::F504 => vec![CheckCode::F504],
|
||||
CheckCodePrefix::F505 => vec![CheckCode::F505],
|
||||
CheckCodePrefix::F506 => vec![CheckCode::F506],
|
||||
CheckCodePrefix::F507 => vec![CheckCode::F507],
|
||||
CheckCodePrefix::F508 => vec![CheckCode::F508],
|
||||
CheckCodePrefix::F509 => vec![CheckCode::F509],
|
||||
CheckCodePrefix::F52 => vec![
|
||||
CheckCode::F521,
|
||||
CheckCode::F522,
|
||||
CheckCode::F523,
|
||||
CheckCode::F524,
|
||||
CheckCode::F525,
|
||||
],
|
||||
CheckCodePrefix::F521 => vec![CheckCode::F521],
|
||||
CheckCodePrefix::F522 => vec![CheckCode::F522],
|
||||
CheckCodePrefix::F523 => vec![CheckCode::F523],
|
||||
CheckCodePrefix::F524 => vec![CheckCode::F524],
|
||||
CheckCodePrefix::F525 => vec![CheckCode::F525],
|
||||
CheckCodePrefix::F54 => vec![CheckCode::F541],
|
||||
CheckCodePrefix::F541 => vec![CheckCode::F541],
|
||||
CheckCodePrefix::F6 => vec![
|
||||
@@ -1058,12 +1164,20 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::Q001 => vec![CheckCode::Q001],
|
||||
CheckCodePrefix::Q002 => vec![CheckCode::Q002],
|
||||
CheckCodePrefix::Q003 => vec![CheckCode::Q003],
|
||||
CheckCodePrefix::RUF => vec![CheckCode::RUF001, CheckCode::RUF002, CheckCode::RUF003],
|
||||
CheckCodePrefix::RUF => vec![
|
||||
CheckCode::RUF001,
|
||||
CheckCode::RUF002,
|
||||
CheckCode::RUF003,
|
||||
CheckCode::RUF101,
|
||||
],
|
||||
CheckCodePrefix::RUF0 => vec![CheckCode::RUF001, CheckCode::RUF002, CheckCode::RUF003],
|
||||
CheckCodePrefix::RUF00 => vec![CheckCode::RUF001, CheckCode::RUF002, CheckCode::RUF003],
|
||||
CheckCodePrefix::RUF001 => vec![CheckCode::RUF001],
|
||||
CheckCodePrefix::RUF002 => vec![CheckCode::RUF002],
|
||||
CheckCodePrefix::RUF003 => vec![CheckCode::RUF003],
|
||||
CheckCodePrefix::RUF1 => vec![CheckCode::RUF101],
|
||||
CheckCodePrefix::RUF10 => vec![CheckCode::RUF101],
|
||||
CheckCodePrefix::RUF101 => vec![CheckCode::RUF101],
|
||||
CheckCodePrefix::S => vec![
|
||||
CheckCode::S101,
|
||||
CheckCode::S102,
|
||||
@@ -1094,7 +1208,10 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::S105 => vec![CheckCode::S105],
|
||||
CheckCodePrefix::S106 => vec![CheckCode::S106],
|
||||
CheckCodePrefix::S107 => vec![CheckCode::S107],
|
||||
CheckCodePrefix::T => vec![CheckCode::T201, CheckCode::T203],
|
||||
CheckCodePrefix::T => vec![CheckCode::T100, CheckCode::T201, CheckCode::T203],
|
||||
CheckCodePrefix::T1 => vec![CheckCode::T100],
|
||||
CheckCodePrefix::T10 => vec![CheckCode::T100],
|
||||
CheckCodePrefix::T100 => vec![CheckCode::T100],
|
||||
CheckCodePrefix::T2 => vec![CheckCode::T201, CheckCode::T203],
|
||||
CheckCodePrefix::T20 => vec![CheckCode::T201, CheckCode::T203],
|
||||
CheckCodePrefix::T201 => vec![CheckCode::T201],
|
||||
@@ -1113,6 +1230,7 @@ impl CheckCodePrefix {
|
||||
CheckCode::U012,
|
||||
CheckCode::U013,
|
||||
CheckCode::U014,
|
||||
CheckCode::U015,
|
||||
],
|
||||
CheckCodePrefix::U0 => vec![
|
||||
CheckCode::U001,
|
||||
@@ -1128,6 +1246,7 @@ impl CheckCodePrefix {
|
||||
CheckCode::U012,
|
||||
CheckCode::U013,
|
||||
CheckCode::U014,
|
||||
CheckCode::U015,
|
||||
],
|
||||
CheckCodePrefix::U00 => vec![
|
||||
CheckCode::U001,
|
||||
@@ -1153,12 +1272,14 @@ impl CheckCodePrefix {
|
||||
CheckCode::U012,
|
||||
CheckCode::U013,
|
||||
CheckCode::U014,
|
||||
CheckCode::U015,
|
||||
],
|
||||
CheckCodePrefix::U010 => vec![CheckCode::U010],
|
||||
CheckCodePrefix::U011 => vec![CheckCode::U011],
|
||||
CheckCodePrefix::U012 => vec![CheckCode::U012],
|
||||
CheckCodePrefix::U013 => vec![CheckCode::U013],
|
||||
CheckCodePrefix::U014 => vec![CheckCode::U014],
|
||||
CheckCodePrefix::U015 => vec![CheckCode::U015],
|
||||
CheckCodePrefix::W => vec![CheckCode::W292, CheckCode::W605],
|
||||
CheckCodePrefix::W2 => vec![CheckCode::W292],
|
||||
CheckCodePrefix::W29 => vec![CheckCode::W292],
|
||||
@@ -1210,6 +1331,7 @@ impl CheckCodePrefix {
|
||||
|
||||
impl CheckCodePrefix {
|
||||
pub fn specificity(&self) -> PrefixSpecificity {
|
||||
#[allow(clippy::match_same_arms)]
|
||||
match self {
|
||||
CheckCodePrefix::A => PrefixSpecificity::Category,
|
||||
CheckCodePrefix::A0 => PrefixSpecificity::Hundreds,
|
||||
@@ -1263,10 +1385,14 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::B020 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::B021 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::B022 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::B023 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::B024 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::B025 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::B026 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::B027 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::B9 => PrefixSpecificity::Hundreds,
|
||||
CheckCodePrefix::B90 => PrefixSpecificity::Tens,
|
||||
CheckCodePrefix::B904 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::BLE => PrefixSpecificity::Category,
|
||||
CheckCodePrefix::BLE0 => PrefixSpecificity::Hundreds,
|
||||
CheckCodePrefix::BLE00 => PrefixSpecificity::Tens,
|
||||
@@ -1376,6 +1502,10 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::E902 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::E99 => PrefixSpecificity::Tens,
|
||||
CheckCodePrefix::E999 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::ERA => PrefixSpecificity::Category,
|
||||
CheckCodePrefix::ERA0 => PrefixSpecificity::Hundreds,
|
||||
CheckCodePrefix::ERA00 => PrefixSpecificity::Tens,
|
||||
CheckCodePrefix::ERA001 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::F => PrefixSpecificity::Category,
|
||||
CheckCodePrefix::F4 => PrefixSpecificity::Hundreds,
|
||||
CheckCodePrefix::F40 => PrefixSpecificity::Tens,
|
||||
@@ -1387,6 +1517,22 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::F406 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::F407 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::F5 => PrefixSpecificity::Hundreds,
|
||||
CheckCodePrefix::F50 => PrefixSpecificity::Tens,
|
||||
CheckCodePrefix::F501 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::F502 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::F503 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::F504 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::F505 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::F506 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::F507 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::F508 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::F509 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::F52 => PrefixSpecificity::Tens,
|
||||
CheckCodePrefix::F521 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::F522 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::F523 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::F524 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::F525 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::F54 => PrefixSpecificity::Tens,
|
||||
CheckCodePrefix::F541 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::F6 => PrefixSpecificity::Hundreds,
|
||||
@@ -1471,6 +1617,9 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::RUF001 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::RUF002 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::RUF003 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::RUF1 => PrefixSpecificity::Hundreds,
|
||||
CheckCodePrefix::RUF10 => PrefixSpecificity::Tens,
|
||||
CheckCodePrefix::RUF101 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::S => PrefixSpecificity::Category,
|
||||
CheckCodePrefix::S1 => PrefixSpecificity::Hundreds,
|
||||
CheckCodePrefix::S10 => PrefixSpecificity::Tens,
|
||||
@@ -1481,6 +1630,9 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::S106 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::S107 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::T => PrefixSpecificity::Category,
|
||||
CheckCodePrefix::T1 => PrefixSpecificity::Hundreds,
|
||||
CheckCodePrefix::T10 => PrefixSpecificity::Tens,
|
||||
CheckCodePrefix::T100 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::T2 => PrefixSpecificity::Hundreds,
|
||||
CheckCodePrefix::T20 => PrefixSpecificity::Tens,
|
||||
CheckCodePrefix::T201 => PrefixSpecificity::Explicit,
|
||||
@@ -1502,6 +1654,7 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::U012 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::U013 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::U014 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::U015 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::W => PrefixSpecificity::Category,
|
||||
CheckCodePrefix::W2 => PrefixSpecificity::Hundreds,
|
||||
CheckCodePrefix::W29 => PrefixSpecificity::Tens,
|
||||
@@ -1529,3 +1682,26 @@ impl CheckCodePrefix {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const CATEGORIES: &[CheckCodePrefix] = &[
|
||||
CheckCodePrefix::A,
|
||||
CheckCodePrefix::ANN,
|
||||
CheckCodePrefix::B,
|
||||
CheckCodePrefix::BLE,
|
||||
CheckCodePrefix::C,
|
||||
CheckCodePrefix::D,
|
||||
CheckCodePrefix::E,
|
||||
CheckCodePrefix::ERA,
|
||||
CheckCodePrefix::F,
|
||||
CheckCodePrefix::FBT,
|
||||
CheckCodePrefix::I,
|
||||
CheckCodePrefix::M,
|
||||
CheckCodePrefix::N,
|
||||
CheckCodePrefix::Q,
|
||||
CheckCodePrefix::RUF,
|
||||
CheckCodePrefix::S,
|
||||
CheckCodePrefix::T,
|
||||
CheckCodePrefix::U,
|
||||
CheckCodePrefix::W,
|
||||
CheckCodePrefix::YTT,
|
||||
];
|
||||
|
||||
38
src/cli.rs
38
src/cli.rs
@@ -1,19 +1,22 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use clap::{command, Parser};
|
||||
use fnv::FnvHashMap;
|
||||
use regex::Regex;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::checks::CheckCode;
|
||||
use crate::checks_gen::CheckCodePrefix;
|
||||
use crate::logging::LogLevel;
|
||||
use crate::printer::SerializationFormat;
|
||||
use crate::settings::types::{PatternPrefixPair, PerFileIgnore, PythonVersion};
|
||||
use crate::settings::types::{
|
||||
FilePattern, PatternPrefixPair, PerFileIgnore, PythonVersion, SerializationFormat,
|
||||
};
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[command(author, about = "Ruff: An extremely fast Python linter.")]
|
||||
#[command(version)]
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
pub struct Cli {
|
||||
#[arg(required = true)]
|
||||
#[arg(required_unless_present_any = ["explain", "generate_shell_completion"])]
|
||||
pub files: Vec<PathBuf>,
|
||||
/// Path to the `pyproject.toml` file to use for configuration.
|
||||
#[arg(long)]
|
||||
@@ -58,11 +61,11 @@ pub struct Cli {
|
||||
pub extend_ignore: Vec<CheckCodePrefix>,
|
||||
/// List of paths, used to exclude files and/or directories from checks.
|
||||
#[arg(long, value_delimiter = ',')]
|
||||
pub exclude: Vec<String>,
|
||||
pub exclude: Vec<FilePattern>,
|
||||
/// Like --exclude, but adds additional files and directories on top of the
|
||||
/// excluded ones.
|
||||
#[arg(long, value_delimiter = ',')]
|
||||
pub extend_exclude: Vec<String>,
|
||||
pub extend_exclude: Vec<FilePattern>,
|
||||
/// List of error codes to treat as eligible for autofix. Only applicable
|
||||
/// when autofix itself is enabled (e.g., via `--fix`).
|
||||
#[arg(long, value_delimiter = ',')]
|
||||
@@ -75,8 +78,8 @@ pub struct Cli {
|
||||
#[arg(long, value_delimiter = ',')]
|
||||
pub per_file_ignores: Vec<PatternPrefixPair>,
|
||||
/// Output serialization format for error messages.
|
||||
#[arg(long, value_enum, default_value_t=SerializationFormat::Text)]
|
||||
pub format: SerializationFormat,
|
||||
#[arg(long, value_enum)]
|
||||
pub format: Option<SerializationFormat>,
|
||||
/// Show violations with source code.
|
||||
#[arg(long)]
|
||||
pub show_source: bool,
|
||||
@@ -109,6 +112,12 @@ pub struct Cli {
|
||||
/// The name of the file when passing it through stdin.
|
||||
#[arg(long)]
|
||||
pub stdin_filename: Option<String>,
|
||||
/// Explain a rule.
|
||||
#[arg(long)]
|
||||
pub explain: Option<CheckCode>,
|
||||
/// Generate shell completion
|
||||
#[arg(long, hide = true, value_name = "SHELL")]
|
||||
pub generate_shell_completion: Option<clap_complete_command::Shell>,
|
||||
}
|
||||
|
||||
impl Cli {
|
||||
@@ -135,19 +144,14 @@ pub fn extract_log_level(cli: &Cli) -> LogLevel {
|
||||
LogLevel::Quiet
|
||||
} else if cli.verbose {
|
||||
LogLevel::Verbose
|
||||
} else if matches!(cli.format, SerializationFormat::Json) {
|
||||
LogLevel::Quiet
|
||||
} else {
|
||||
LogLevel::Default
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a list of `PatternPrefixPair` structs to `PerFileIgnore`.
|
||||
pub fn collect_per_file_ignores(
|
||||
pairs: Vec<PatternPrefixPair>,
|
||||
project_root: Option<&PathBuf>,
|
||||
) -> Vec<PerFileIgnore> {
|
||||
let mut per_file_ignores: FnvHashMap<String, Vec<CheckCodePrefix>> = FnvHashMap::default();
|
||||
pub fn collect_per_file_ignores(pairs: Vec<PatternPrefixPair>) -> Vec<PerFileIgnore> {
|
||||
let mut per_file_ignores: FxHashMap<String, Vec<CheckCodePrefix>> = FxHashMap::default();
|
||||
for pair in pairs {
|
||||
per_file_ignores
|
||||
.entry(pair.pattern)
|
||||
@@ -155,7 +159,7 @@ pub fn collect_per_file_ignores(
|
||||
.push(pair.prefix);
|
||||
}
|
||||
per_file_ignores
|
||||
.iter()
|
||||
.map(|(pattern, prefixes)| PerFileIgnore::new(pattern, prefixes, project_root))
|
||||
.into_iter()
|
||||
.map(|(pattern, prefixes)| PerFileIgnore::new(pattern, &prefixes))
|
||||
.collect()
|
||||
}
|
||||
|
||||
677
src/code_gen.rs
677
src/code_gen.rs
File diff suppressed because it is too large
Load Diff
66
src/commands.rs
Normal file
66
src/commands.rs
Normal file
@@ -0,0 +1,66 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use anyhow::Result;
|
||||
use serde::Serialize;
|
||||
use walkdir::DirEntry;
|
||||
|
||||
use crate::checks::CheckCode;
|
||||
use crate::fs::iter_python_files;
|
||||
use crate::settings::types::SerializationFormat;
|
||||
use crate::{Configuration, Settings};
|
||||
|
||||
/// Print the user-facing configuration settings.
|
||||
pub fn show_settings(
|
||||
configuration: &Configuration,
|
||||
project_root: Option<&PathBuf>,
|
||||
pyproject: Option<&PathBuf>,
|
||||
) {
|
||||
println!("Resolved configuration: {configuration:#?}");
|
||||
println!("Found project root at: {project_root:?}");
|
||||
println!("Found pyproject.toml at: {pyproject:?}");
|
||||
}
|
||||
|
||||
/// Show the list of files to be checked based on current settings.
|
||||
pub fn show_files(files: &[PathBuf], settings: &Settings) {
|
||||
let mut entries: Vec<DirEntry> = files
|
||||
.iter()
|
||||
.flat_map(|path| iter_python_files(path, &settings.exclude, &settings.extend_exclude))
|
||||
.flatten()
|
||||
.collect();
|
||||
entries.sort_by(|a, b| a.path().cmp(b.path()));
|
||||
for entry in entries {
|
||||
println!("{}", entry.path().to_string_lossy());
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct Explanation<'a> {
|
||||
code: &'a str,
|
||||
category: &'a str,
|
||||
summary: &'a str,
|
||||
}
|
||||
|
||||
/// Explain a `CheckCode` to the user.
|
||||
pub fn explain(code: &CheckCode, format: SerializationFormat) -> Result<()> {
|
||||
match format {
|
||||
SerializationFormat::Text | SerializationFormat::Grouped => {
|
||||
println!(
|
||||
"{} ({}): {}",
|
||||
code.as_ref(),
|
||||
code.category().title(),
|
||||
code.kind().summary()
|
||||
);
|
||||
}
|
||||
SerializationFormat::Json => {
|
||||
println!(
|
||||
"{}",
|
||||
serde_json::to_string_pretty(&Explanation {
|
||||
code: code.as_ref(),
|
||||
category: code.category().title(),
|
||||
summary: &code.kind().summary(),
|
||||
})?
|
||||
);
|
||||
}
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
@@ -11,8 +11,8 @@ use crate::{Settings, SourceCodeLocator};
|
||||
|
||||
bitflags! {
|
||||
pub struct Flags: u32 {
|
||||
const NOQA = 0b00000001;
|
||||
const ISORT = 0b00000010;
|
||||
const NOQA = 0b0000_0001;
|
||||
const ISORT = 0b0000_0010;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,18 +38,18 @@ pub struct Directives {
|
||||
pub fn extract_directives(
|
||||
lxr: &[LexResult],
|
||||
locator: &SourceCodeLocator,
|
||||
flags: &Flags,
|
||||
flags: Flags,
|
||||
) -> Directives {
|
||||
Directives {
|
||||
noqa_line_for: if flags.contains(Flags::NOQA) {
|
||||
extract_noqa_line_for(lxr)
|
||||
} else {
|
||||
Default::default()
|
||||
IntMap::default()
|
||||
},
|
||||
isort_exclusions: if flags.contains(Flags::ISORT) {
|
||||
extract_isort_exclusions(lxr, locator)
|
||||
} else {
|
||||
Default::default()
|
||||
IntSet::default()
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -75,13 +75,13 @@ pub fn extract_noqa_line_for(lxr: &[LexResult]) -> IntMap<usize, usize> {
|
||||
/// Extract a set of lines over which to disable isort.
|
||||
pub fn extract_isort_exclusions(lxr: &[LexResult], locator: &SourceCodeLocator) -> IntSet<usize> {
|
||||
let mut exclusions: IntSet<usize> = IntSet::default();
|
||||
let mut off: Option<&Location> = None;
|
||||
for (start, tok, end) in lxr.iter().flatten() {
|
||||
let mut off: Option<Location> = None;
|
||||
for &(start, ref tok, end) in lxr.iter().flatten() {
|
||||
// TODO(charlie): Modify RustPython to include the comment text in the token.
|
||||
if matches!(tok, Tok::Comment) {
|
||||
let comment_text = locator.slice_source_code_range(&Range {
|
||||
location: *start,
|
||||
end_location: *end,
|
||||
location: start,
|
||||
end_location: end,
|
||||
});
|
||||
if off.is_some() {
|
||||
if comment_text == "# isort: on" {
|
||||
@@ -113,7 +113,7 @@ pub fn extract_isort_exclusions(lxr: &[LexResult], locator: &SourceCodeLocator)
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use anyhow::Result;
|
||||
|
||||
use nohash_hasher::IntMap;
|
||||
use rustpython_parser::lexer;
|
||||
use rustpython_parser::lexer::LexResult;
|
||||
@@ -121,8 +121,8 @@ mod tests {
|
||||
use crate::directives::extract_noqa_line_for;
|
||||
|
||||
#[test]
|
||||
fn extraction() -> Result<()> {
|
||||
let empty: IntMap<usize, usize> = Default::default();
|
||||
fn extraction() {
|
||||
let empty: IntMap<usize, usize> = IntMap::default();
|
||||
|
||||
let lxr: Vec<LexResult> = lexer::make_tokenizer(
|
||||
"x = 1
|
||||
@@ -200,7 +200,5 @@ z = x + 1",
|
||||
extract_noqa_line_for(&lxr),
|
||||
IntMap::from_iter([(2, 5), (3, 5), (4, 5)])
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
//! Abstractions for Google-style docstrings.
|
||||
|
||||
use fnv::FnvHashSet;
|
||||
use once_cell::sync::Lazy;
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
pub(crate) static GOOGLE_SECTION_NAMES: Lazy<FnvHashSet<&'static str>> = Lazy::new(|| {
|
||||
FnvHashSet::from_iter([
|
||||
pub(crate) static GOOGLE_SECTION_NAMES: Lazy<FxHashSet<&'static str>> = Lazy::new(|| {
|
||||
FxHashSet::from_iter([
|
||||
"Args",
|
||||
"Arguments",
|
||||
"Attention",
|
||||
@@ -36,36 +36,35 @@ pub(crate) static GOOGLE_SECTION_NAMES: Lazy<FnvHashSet<&'static str>> = Lazy::n
|
||||
])
|
||||
});
|
||||
|
||||
pub(crate) static LOWERCASE_GOOGLE_SECTION_NAMES: Lazy<FnvHashSet<&'static str>> =
|
||||
Lazy::new(|| {
|
||||
FnvHashSet::from_iter([
|
||||
"args",
|
||||
"arguments",
|
||||
"attention",
|
||||
"attributes",
|
||||
"caution",
|
||||
"danger",
|
||||
"error",
|
||||
"example",
|
||||
"examples",
|
||||
"hint",
|
||||
"important",
|
||||
"keyword args",
|
||||
"keyword arguments",
|
||||
"methods",
|
||||
"note",
|
||||
"notes",
|
||||
"return",
|
||||
"returns",
|
||||
"raises",
|
||||
"references",
|
||||
"see also",
|
||||
"tip",
|
||||
"todo",
|
||||
"warning",
|
||||
"warnings",
|
||||
"warns",
|
||||
"yield",
|
||||
"yields",
|
||||
])
|
||||
});
|
||||
pub(crate) static LOWERCASE_GOOGLE_SECTION_NAMES: Lazy<FxHashSet<&'static str>> = Lazy::new(|| {
|
||||
FxHashSet::from_iter([
|
||||
"args",
|
||||
"arguments",
|
||||
"attention",
|
||||
"attributes",
|
||||
"caution",
|
||||
"danger",
|
||||
"error",
|
||||
"example",
|
||||
"examples",
|
||||
"hint",
|
||||
"important",
|
||||
"keyword args",
|
||||
"keyword arguments",
|
||||
"methods",
|
||||
"note",
|
||||
"notes",
|
||||
"return",
|
||||
"returns",
|
||||
"raises",
|
||||
"references",
|
||||
"see also",
|
||||
"tip",
|
||||
"todo",
|
||||
"warning",
|
||||
"warnings",
|
||||
"warns",
|
||||
"yield",
|
||||
"yields",
|
||||
])
|
||||
});
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
//! Abstractions for NumPy-style docstrings.
|
||||
|
||||
use fnv::FnvHashSet;
|
||||
use once_cell::sync::Lazy;
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
pub(crate) static LOWERCASE_NUMPY_SECTION_NAMES: Lazy<FnvHashSet<&'static str>> = Lazy::new(|| {
|
||||
FnvHashSet::from_iter([
|
||||
pub(crate) static LOWERCASE_NUMPY_SECTION_NAMES: Lazy<FxHashSet<&'static str>> = Lazy::new(|| {
|
||||
FxHashSet::from_iter([
|
||||
"short summary",
|
||||
"extended summary",
|
||||
"parameters",
|
||||
@@ -21,8 +21,8 @@ pub(crate) static LOWERCASE_NUMPY_SECTION_NAMES: Lazy<FnvHashSet<&'static str>>
|
||||
])
|
||||
});
|
||||
|
||||
pub(crate) static NUMPY_SECTION_NAMES: Lazy<FnvHashSet<&'static str>> = Lazy::new(|| {
|
||||
FnvHashSet::from_iter([
|
||||
pub(crate) static NUMPY_SECTION_NAMES: Lazy<FxHashSet<&'static str>> = Lazy::new(|| {
|
||||
FxHashSet::from_iter([
|
||||
"Short Summary",
|
||||
"Extended Summary",
|
||||
"Parameters",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use fnv::FnvHashSet;
|
||||
use once_cell::sync::Lazy;
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use crate::docstrings::google::{GOOGLE_SECTION_NAMES, LOWERCASE_GOOGLE_SECTION_NAMES};
|
||||
use crate::docstrings::numpy::{LOWERCASE_NUMPY_SECTION_NAMES, NUMPY_SECTION_NAMES};
|
||||
@@ -10,14 +10,14 @@ pub(crate) enum SectionStyle {
|
||||
}
|
||||
|
||||
impl SectionStyle {
|
||||
pub(crate) fn section_names(&self) -> &Lazy<FnvHashSet<&'static str>> {
|
||||
pub(crate) fn section_names(&self) -> &Lazy<FxHashSet<&'static str>> {
|
||||
match self {
|
||||
SectionStyle::NumPy => &NUMPY_SECTION_NAMES,
|
||||
SectionStyle::Google => &GOOGLE_SECTION_NAMES,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn lowercase_section_names(&self) -> &Lazy<FnvHashSet<&'static str>> {
|
||||
pub(crate) fn lowercase_section_names(&self) -> &Lazy<FxHashSet<&'static str>> {
|
||||
match self {
|
||||
SectionStyle::NumPy => &LOWERCASE_NUMPY_SECTION_NAMES,
|
||||
SectionStyle::Google => &LOWERCASE_GOOGLE_SECTION_NAMES,
|
||||
|
||||
51
src/eradicate/checks.rs
Normal file
51
src/eradicate/checks.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
use rustpython_ast::Location;
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::autofix::Fix;
|
||||
use crate::checks::{CheckCode, CheckKind};
|
||||
use crate::eradicate::detection::comment_contains_code;
|
||||
use crate::{Check, Settings, SourceCodeLocator};
|
||||
|
||||
fn is_standalone_comment(line: &str) -> bool {
|
||||
for char in line.chars() {
|
||||
if char == '#' {
|
||||
return true;
|
||||
} else if !char.is_whitespace() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
unreachable!("Comment should contain '#' character")
|
||||
}
|
||||
|
||||
/// ERA001
|
||||
pub fn commented_out_code(
|
||||
locator: &SourceCodeLocator,
|
||||
start: Location,
|
||||
end: Location,
|
||||
settings: &Settings,
|
||||
autofix: bool,
|
||||
) -> Option<Check> {
|
||||
let location = Location::new(start.row(), 0);
|
||||
let end_location = Location::new(end.row() + 1, 0);
|
||||
let line = locator.slice_source_code_range(&Range {
|
||||
location,
|
||||
end_location,
|
||||
});
|
||||
|
||||
// Verify that the comment is on its own line, and that it contains code.
|
||||
if is_standalone_comment(&line) && comment_contains_code(&line) {
|
||||
let mut check = Check::new(
|
||||
CheckKind::CommentedOutCode,
|
||||
Range {
|
||||
location: start,
|
||||
end_location: end,
|
||||
},
|
||||
);
|
||||
if autofix && settings.fixable.contains(&CheckCode::ERA001) {
|
||||
check.amend(Fix::deletion(location, end_location));
|
||||
}
|
||||
Some(check)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
223
src/eradicate/detection.rs
Normal file
223
src/eradicate/detection.rs
Normal file
@@ -0,0 +1,223 @@
|
||||
/// See: [eradicate.py](https://github.com/myint/eradicate/blob/98f199940979c94447a461d50d27862b118b282d/eradicate.py)
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
|
||||
static ALLOWLIST_REGEX: Lazy<Regex> = Lazy::new(|| {
|
||||
Regex::new(
|
||||
r"(?i)pylint|pyright|noqa|nosec|type:\s*ignore|fmt:\s*(on|off)|isort:\s*(on|off|skip|skip_file|split|dont-add-imports(:\s*\[.*?])?)|TODO|FIXME|XXX"
|
||||
).unwrap()
|
||||
});
|
||||
static BRACKET_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"^[()\[\]{}\s]+$").unwrap());
|
||||
static CODE_INDICATORS: &[&str] = &[
|
||||
"(", ")", "[", "]", "{", "}", ":", "=", "%", "print", "return", "break", "continue", "import",
|
||||
];
|
||||
static CODE_KEYWORDS: Lazy<Vec<Regex>> = Lazy::new(|| {
|
||||
vec![
|
||||
Regex::new(r"^\s*elif\s+.*\s*:\s*$").unwrap(),
|
||||
Regex::new(r"^\s*else\s*:\s*$").unwrap(),
|
||||
Regex::new(r"^\s*try\s*:\s*$").unwrap(),
|
||||
Regex::new(r"^\s*finally\s*:\s*$").unwrap(),
|
||||
Regex::new(r"^\s*except\s+.*\s*:\s*$").unwrap(),
|
||||
]
|
||||
});
|
||||
static CODING_COMMENT_REGEX: Lazy<Regex> =
|
||||
Lazy::new(|| Regex::new(r"^.*?coding[:=][ \t]*([-_.a-zA-Z0-9]+)").unwrap());
|
||||
static HASH_NUMBER: Lazy<Regex> = Lazy::new(|| Regex::new(r"#\d").unwrap());
|
||||
static MULTILINE_ASSIGNMENT_REGEX: Lazy<Regex> =
|
||||
Lazy::new(|| Regex::new(r"^\s*\w+\s*=.*[(\[{]$").unwrap());
|
||||
static PARTIAL_DICTIONARY_REGEX: Lazy<Regex> =
|
||||
Lazy::new(|| Regex::new(r#"^\s*['"]\w+['"]\s*:.+[,{]\s*$"#).unwrap());
|
||||
static PRINT_RETURN_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"^(print|return)\b\s*").unwrap());
|
||||
|
||||
/// Returns `true` if a comment contains Python code.
|
||||
pub fn comment_contains_code(line: &str) -> bool {
|
||||
let line = if let Some(line) = line.trim().strip_prefix('#') {
|
||||
line.trim()
|
||||
} else {
|
||||
return false;
|
||||
};
|
||||
|
||||
// Ignore non-comment related hashes (e.g., "# Issue #999").
|
||||
if HASH_NUMBER.is_match(line) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ignore whitelisted comments.
|
||||
if ALLOWLIST_REGEX.is_match(line) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if CODING_COMMENT_REGEX.is_match(line) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that this is possibly code.
|
||||
if CODE_INDICATORS.iter().all(|symbol| !line.contains(symbol)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if multiline_case(line) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if CODE_KEYWORDS.iter().any(|symbol| symbol.is_match(line)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
let line = PRINT_RETURN_REGEX.replace_all(line, "");
|
||||
|
||||
if PARTIAL_DICTIONARY_REGEX.is_match(&line) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Finally, compile the source code.
|
||||
rustpython_parser::parser::parse_program(&line, "<filename>").is_ok()
|
||||
}
|
||||
|
||||
/// Returns `true` if a line is probably part of some multiline code.
|
||||
fn multiline_case(line: &str) -> bool {
|
||||
if line.ends_with('\\') {
|
||||
return true;
|
||||
}
|
||||
|
||||
if MULTILINE_ASSIGNMENT_REGEX.is_match(line) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if BRACKET_REGEX.is_match(line) {
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::eradicate::detection::comment_contains_code;
|
||||
|
||||
#[test]
|
||||
fn comment_contains_code_basic() {
|
||||
assert!(comment_contains_code("# x = 1"));
|
||||
assert!(comment_contains_code("#from foo import eradicate"));
|
||||
assert!(comment_contains_code("#import eradicate"));
|
||||
assert!(comment_contains_code(r#"#"key": value,"#));
|
||||
assert!(comment_contains_code(r#"#"key": "value","#));
|
||||
assert!(comment_contains_code(r#"#"key": 1 + 1,"#));
|
||||
assert!(comment_contains_code("#'key': 1 + 1,"));
|
||||
assert!(comment_contains_code(r#"#"key": {"#));
|
||||
assert!(comment_contains_code("#}"));
|
||||
assert!(comment_contains_code("#} )]"));
|
||||
|
||||
assert!(!comment_contains_code("#"));
|
||||
assert!(!comment_contains_code("# This is a (real) comment."));
|
||||
assert!(!comment_contains_code("# 123"));
|
||||
assert!(!comment_contains_code("# 123.1"));
|
||||
assert!(!comment_contains_code("# 1, 2, 3"));
|
||||
assert!(!comment_contains_code("x = 1 # x = 1"));
|
||||
assert!(!comment_contains_code(
|
||||
"# pylint: disable=redefined-outer-name"
|
||||
));
|
||||
assert!(!comment_contains_code("# Issue #999: This is not code"));
|
||||
|
||||
// TODO(charlie): This should be `true` under aggressive mode.
|
||||
assert!(!comment_contains_code("#},"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn comment_contains_code_with_print() {
|
||||
assert!(comment_contains_code("#print"));
|
||||
assert!(comment_contains_code("#print(1)"));
|
||||
assert!(comment_contains_code("#print 1"));
|
||||
|
||||
assert!(!comment_contains_code("#to print"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn comment_contains_code_with_return() {
|
||||
assert!(comment_contains_code("#return x"));
|
||||
|
||||
assert!(!comment_contains_code("#to print"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn comment_contains_code_with_multiline() {
|
||||
assert!(comment_contains_code("#else:"));
|
||||
assert!(comment_contains_code("# else : "));
|
||||
assert!(comment_contains_code(r#"# "foo %d" % \\"#));
|
||||
assert!(comment_contains_code("#elif True:"));
|
||||
assert!(comment_contains_code("#x = foo("));
|
||||
assert!(comment_contains_code("#except Exception:"));
|
||||
|
||||
assert!(!comment_contains_code("# this is = to that :("));
|
||||
assert!(!comment_contains_code("#else"));
|
||||
assert!(!comment_contains_code("#or else:"));
|
||||
assert!(!comment_contains_code("#else True:"));
|
||||
|
||||
// TODO(charlie): This should be `true` under aggressive mode.
|
||||
assert!(!comment_contains_code("#def foo():"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn comment_contains_code_with_sentences() {
|
||||
assert!(!comment_contains_code("#code is good"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn comment_contains_code_with_encoding() {
|
||||
assert!(comment_contains_code("# codings=utf-8"));
|
||||
|
||||
assert!(!comment_contains_code("# coding=utf-8"));
|
||||
assert!(!comment_contains_code("#coding= utf-8"));
|
||||
assert!(!comment_contains_code("# coding: utf-8"));
|
||||
assert!(!comment_contains_code("# encoding: utf8"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn comment_contains_code_with_default_allowlist() {
|
||||
assert!(!comment_contains_code("# pylint: disable=A0123"));
|
||||
assert!(!comment_contains_code("# pylint:disable=A0123"));
|
||||
assert!(!comment_contains_code("# pylint: disable = A0123"));
|
||||
assert!(!comment_contains_code("# pylint:disable = A0123"));
|
||||
assert!(!comment_contains_code("# pyright: reportErrorName=true"));
|
||||
assert!(!comment_contains_code("# noqa"));
|
||||
assert!(!comment_contains_code("# NOQA"));
|
||||
assert!(!comment_contains_code("# noqa: A123"));
|
||||
assert!(!comment_contains_code("# noqa:A123"));
|
||||
assert!(!comment_contains_code("# nosec"));
|
||||
assert!(!comment_contains_code("# fmt: on"));
|
||||
assert!(!comment_contains_code("# fmt: off"));
|
||||
assert!(!comment_contains_code("# fmt:on"));
|
||||
assert!(!comment_contains_code("# fmt:off"));
|
||||
assert!(!comment_contains_code("# isort: on"));
|
||||
assert!(!comment_contains_code("# isort:on"));
|
||||
assert!(!comment_contains_code("# isort: off"));
|
||||
assert!(!comment_contains_code("# isort:off"));
|
||||
assert!(!comment_contains_code("# isort: skip"));
|
||||
assert!(!comment_contains_code("# isort:skip"));
|
||||
assert!(!comment_contains_code("# isort: skip_file"));
|
||||
assert!(!comment_contains_code("# isort:skip_file"));
|
||||
assert!(!comment_contains_code("# isort: split"));
|
||||
assert!(!comment_contains_code("# isort:split"));
|
||||
assert!(!comment_contains_code("# isort: dont-add-imports"));
|
||||
assert!(!comment_contains_code("# isort:dont-add-imports"));
|
||||
assert!(!comment_contains_code(
|
||||
"# isort: dont-add-imports: [\"import os\"]"
|
||||
));
|
||||
assert!(!comment_contains_code(
|
||||
"# isort:dont-add-imports: [\"import os\"]"
|
||||
));
|
||||
assert!(!comment_contains_code(
|
||||
"# isort: dont-add-imports:[\"import os\"]"
|
||||
));
|
||||
assert!(!comment_contains_code(
|
||||
"# isort:dont-add-imports:[\"import os\"]"
|
||||
));
|
||||
assert!(!comment_contains_code("# type: ignore"));
|
||||
assert!(!comment_contains_code("# type:ignore"));
|
||||
assert!(!comment_contains_code("# type: ignore[import]"));
|
||||
assert!(!comment_contains_code("# type:ignore[import]"));
|
||||
assert!(!comment_contains_code("# TODO: Do that"));
|
||||
assert!(!comment_contains_code("# FIXME: Fix that"));
|
||||
assert!(!comment_contains_code("# XXX: What ever"));
|
||||
}
|
||||
}
|
||||
2
src/eradicate/mod.rs
Normal file
2
src/eradicate/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub mod checks;
|
||||
pub mod detection;
|
||||
@@ -7,7 +7,6 @@ mod tests {
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::autofix::fixer;
|
||||
use crate::checks::CheckCode;
|
||||
use crate::linter::test_path;
|
||||
use crate::{flake8_annotations, Settings};
|
||||
@@ -31,7 +30,7 @@ mod tests {
|
||||
CheckCode::ANN401,
|
||||
])
|
||||
},
|
||||
&fixer::Mode::Generate,
|
||||
true,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(checks);
|
||||
@@ -57,7 +56,7 @@ mod tests {
|
||||
CheckCode::ANN102,
|
||||
])
|
||||
},
|
||||
&fixer::Mode::Generate,
|
||||
true,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(checks);
|
||||
@@ -83,7 +82,7 @@ mod tests {
|
||||
CheckCode::ANN206,
|
||||
])
|
||||
},
|
||||
&fixer::Mode::Generate,
|
||||
true,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(checks);
|
||||
@@ -109,7 +108,7 @@ mod tests {
|
||||
CheckCode::ANN206,
|
||||
])
|
||||
},
|
||||
&fixer::Mode::Generate,
|
||||
true,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(checks);
|
||||
@@ -129,7 +128,7 @@ mod tests {
|
||||
},
|
||||
..Settings::for_rules(vec![CheckCode::ANN401])
|
||||
},
|
||||
&fixer::Mode::Generate,
|
||||
true,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(checks);
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
use std::ops::Deref;
|
||||
|
||||
use rustpython_ast::{Arguments, Constant, Expr, ExprKind, Stmt, StmtKind};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
@@ -23,18 +21,16 @@ where
|
||||
fn visit_stmt(&mut self, stmt: &'b Stmt) {
|
||||
match &stmt.node {
|
||||
StmtKind::FunctionDef { .. } | StmtKind::AsyncFunctionDef { .. } => {
|
||||
// No recurse.
|
||||
}
|
||||
StmtKind::Return { value } => {
|
||||
self.returns.push(value.as_ref().map(|expr| expr.deref()))
|
||||
// Don't recurse.
|
||||
}
|
||||
StmtKind::Return { value } => self.returns.push(value.as_ref().map(|expr| &**expr)),
|
||||
_ => visitor::walk_stmt(self, stmt),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_none_returning(body: &[Stmt]) -> bool {
|
||||
let mut visitor: ReturnStatementVisitor = Default::default();
|
||||
let mut visitor = ReturnStatementVisitor::default();
|
||||
for stmt in body {
|
||||
visitor.visit_stmt(stmt);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ pub struct Options {
|
||||
}
|
||||
|
||||
#[derive(Debug, Hash, Default)]
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
pub struct Settings {
|
||||
pub mypy_init_return: bool,
|
||||
pub suppress_dummy_args: bool,
|
||||
@@ -29,6 +30,7 @@ pub struct Settings {
|
||||
}
|
||||
|
||||
impl Settings {
|
||||
#[allow(clippy::needless_pass_by_value)]
|
||||
pub fn from_options(options: Options) -> Self {
|
||||
Self {
|
||||
mypy_init_return: options.mypy_init_return.unwrap_or_default(),
|
||||
|
||||
@@ -5,6 +5,19 @@ use crate::ast::types::Range;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
|
||||
const FUNC_NAME_ALLOWLIST: &[&str] = &["get", "setdefault", "pop", "fromkeys"];
|
||||
|
||||
/// Returns `true` if an argument is allowed to use a boolean trap. To return
|
||||
/// `true`, the function name must be explicitly allowed, and the argument must
|
||||
/// be either the first or second argument in the call.
|
||||
fn allow_boolean_trap(func: &Expr) -> bool {
|
||||
if let ExprKind::Attribute { attr, .. } = &func.node {
|
||||
FUNC_NAME_ALLOWLIST.contains(&attr.as_ref())
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn is_boolean_arg(arg: &Expr) -> bool {
|
||||
matches!(
|
||||
&arg.node,
|
||||
@@ -51,7 +64,7 @@ pub fn check_boolean_default_value_in_function_definition(
|
||||
checker: &mut Checker,
|
||||
arguments: &Arguments,
|
||||
) {
|
||||
for arg in arguments.defaults.iter() {
|
||||
for arg in &arguments.defaults {
|
||||
add_if_boolean(
|
||||
checker,
|
||||
arg,
|
||||
@@ -60,8 +73,15 @@ pub fn check_boolean_default_value_in_function_definition(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_boolean_positional_value_in_function_call(checker: &mut Checker, args: &[Expr]) {
|
||||
for arg in args {
|
||||
pub fn check_boolean_positional_value_in_function_call(
|
||||
checker: &mut Checker,
|
||||
args: &[Expr],
|
||||
func: &Expr,
|
||||
) {
|
||||
for (index, arg) in args.iter().enumerate() {
|
||||
if index < 2 && allow_boolean_trap(func) {
|
||||
continue;
|
||||
}
|
||||
add_if_boolean(
|
||||
checker,
|
||||
arg,
|
||||
|
||||
@@ -7,7 +7,6 @@ mod tests {
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::autofix::fixer;
|
||||
use crate::checks::CheckCode;
|
||||
use crate::linter::test_path;
|
||||
use crate::{flake8_bugbear, Settings};
|
||||
@@ -26,7 +25,7 @@ mod tests {
|
||||
},
|
||||
..Settings::for_rules(vec![CheckCode::B008])
|
||||
},
|
||||
&fixer::Mode::Generate,
|
||||
true,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(snapshot, checks);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use fnv::{FnvHashMap, FnvHashSet};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use rustpython_ast::{Constant, Expr, ExprKind, Keyword, Stmt, StmtKind};
|
||||
|
||||
use crate::ast::helpers::match_module_member;
|
||||
@@ -9,16 +9,15 @@ use crate::checks::{Check, CheckCode, CheckKind};
|
||||
fn is_abc_class(
|
||||
bases: &[Expr],
|
||||
keywords: &[Keyword],
|
||||
from_imports: &FnvHashMap<&str, FnvHashSet<&str>>,
|
||||
import_aliases: &FnvHashMap<&str, &str>,
|
||||
from_imports: &FxHashMap<&str, FxHashSet<&str>>,
|
||||
import_aliases: &FxHashMap<&str, &str>,
|
||||
) -> bool {
|
||||
keywords.iter().any(|keyword| {
|
||||
keyword
|
||||
.node
|
||||
.arg
|
||||
.as_ref()
|
||||
.map(|a| a == "metaclass")
|
||||
.unwrap_or(false)
|
||||
.map_or(false, |a| a == "metaclass")
|
||||
&& match_module_member(
|
||||
&keyword.node.value,
|
||||
"abc",
|
||||
@@ -46,16 +45,16 @@ fn is_empty_body(body: &[Stmt]) -> bool {
|
||||
|
||||
fn is_abstractmethod(
|
||||
expr: &Expr,
|
||||
from_imports: &FnvHashMap<&str, FnvHashSet<&str>>,
|
||||
import_aliases: &FnvHashMap<&str, &str>,
|
||||
from_imports: &FxHashMap<&str, FxHashSet<&str>>,
|
||||
import_aliases: &FxHashMap<&str, &str>,
|
||||
) -> bool {
|
||||
match_module_member(expr, "abc", "abstractmethod", from_imports, import_aliases)
|
||||
}
|
||||
|
||||
fn is_overload(
|
||||
expr: &Expr,
|
||||
from_imports: &FnvHashMap<&str, FnvHashSet<&str>>,
|
||||
import_aliases: &FnvHashMap<&str, &str>,
|
||||
from_imports: &FxHashMap<&str, FxHashSet<&str>>,
|
||||
import_aliases: &FxHashMap<&str, &str>,
|
||||
) -> bool {
|
||||
match_module_member(expr, "typing", "overload", from_imports, import_aliases)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use rustpython_ast::{Constant, Expr, ExprContext, ExprKind, Stmt, StmtKind};
|
||||
use rustpython_ast::{Constant, Expr, ExprContext, ExprKind, Location, Stmt, StmtKind};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::autofix::Fix;
|
||||
@@ -8,16 +8,16 @@ use crate::code_gen::SourceGenerator;
|
||||
|
||||
fn assertion_error(msg: Option<&Expr>) -> Stmt {
|
||||
Stmt::new(
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
Location::default(),
|
||||
Location::default(),
|
||||
StmtKind::Raise {
|
||||
exc: Some(Box::new(Expr::new(
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
Location::default(),
|
||||
Location::default(),
|
||||
ExprKind::Call {
|
||||
func: Box::new(Expr::new(
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
Location::default(),
|
||||
Location::default(),
|
||||
ExprKind::Name {
|
||||
id: "AssertionError".to_string(),
|
||||
ctx: ExprContext::Load,
|
||||
@@ -46,14 +46,13 @@ pub fn assert_false(checker: &mut Checker, stmt: &Stmt, test: &Expr, msg: Option
|
||||
let mut check = Check::new(CheckKind::DoNotAssertFalse, Range::from_located(test));
|
||||
if checker.patch(check.kind.code()) {
|
||||
let mut generator = SourceGenerator::new();
|
||||
if let Ok(()) = generator.unparse_stmt(&assertion_error(msg)) {
|
||||
if let Ok(content) = generator.generate() {
|
||||
check.amend(Fix::replacement(
|
||||
content,
|
||||
stmt.location,
|
||||
stmt.end_location.unwrap(),
|
||||
));
|
||||
}
|
||||
generator.unparse_stmt(&assertion_error(msg));
|
||||
if let Ok(content) = generator.generate() {
|
||||
check.amend(Fix::replacement(
|
||||
content,
|
||||
stmt.location,
|
||||
stmt.end_location.unwrap(),
|
||||
));
|
||||
}
|
||||
}
|
||||
checker.add_check(check);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user