Compare commits
49 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6fa0f21227 | ||
|
|
f5466fe720 | ||
|
|
a0202e8eb2 | ||
|
|
30ff4de9a3 | ||
|
|
897b0f06ef | ||
|
|
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 |
@@ -1,6 +1,6 @@
|
||||
repos:
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
rev: v0.0.140
|
||||
rev: v0.0.149
|
||||
hooks:
|
||||
- id: ruff
|
||||
|
||||
|
||||
101
Cargo.lock
generated
101
Cargo.lock
generated
@@ -220,13 +220,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.22"
|
||||
version = "0.4.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1"
|
||||
checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f"
|
||||
dependencies = [
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"time",
|
||||
"wasm-bindgen",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
@@ -290,6 +293,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,7 +703,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.140-dev.0"
|
||||
version = "0.0.149-dev.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.0.22",
|
||||
@@ -853,9 +886,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.1"
|
||||
version = "1.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
|
||||
checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
@@ -1190,6 +1223,12 @@ version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
|
||||
|
||||
[[package]]
|
||||
name = "nextest-workspace-hack"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d906846a98739ed9d73d66e62c2641eef8321f1734b7a1156ab045a0248fb2b3"
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.24.2"
|
||||
@@ -1576,6 +1615,29 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-junit"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05b909fe9bf2abb1e3d6a97c9189a37c8105c61d03dca9ce6aace023e7d682bd"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"indexmap",
|
||||
"nextest-workspace-hack",
|
||||
"quick-xml",
|
||||
"thiserror",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.26.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f50b1c63b38611e7d4d7f68b82d3ad0cc71a2ad2e7f61fc10f1328d917c93cd"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.21"
|
||||
@@ -1775,7 +1837,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.140"
|
||||
version = "0.0.149"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.9.1",
|
||||
"anyhow",
|
||||
@@ -1786,6 +1848,7 @@ dependencies = [
|
||||
"cachedir",
|
||||
"chrono",
|
||||
"clap 4.0.22",
|
||||
"clap_complete_command",
|
||||
"clearscreen",
|
||||
"colored",
|
||||
"common-path",
|
||||
@@ -1804,6 +1867,7 @@ dependencies = [
|
||||
"num-bigint",
|
||||
"once_cell",
|
||||
"path-absolutize",
|
||||
"quick-junit",
|
||||
"rayon",
|
||||
"regex",
|
||||
"ropey",
|
||||
@@ -1825,7 +1889,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_dev"
|
||||
version = "0.0.140"
|
||||
version = "0.0.149"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.0.22",
|
||||
@@ -2232,6 +2296,17 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi 0.10.0+wasi-snapshot-preview1",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiny-keccak"
|
||||
version = "2.0.2"
|
||||
@@ -2458,6 +2533,12 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
@@ -2496,6 +2577,12 @@ version = "0.9.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
|
||||
@@ -6,7 +6,7 @@ members = [
|
||||
|
||||
[package]
|
||||
name = "ruff"
|
||||
version = "0.0.140"
|
||||
version = "0.0.149"
|
||||
edition = "2021"
|
||||
rust-version = "1.65.0"
|
||||
|
||||
@@ -22,12 +22,13 @@ 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" }
|
||||
globset = {version = "0.4.9" }
|
||||
globset = { version = "0.4.9" }
|
||||
itertools = { version = "0.10.5" }
|
||||
libcst = { git = "https://github.com/charliermarsh/LibCST", rev = "f2f0b7a487a8725d161fe8b3ed73a6758b21e177" }
|
||||
log = { version = "0.4.17" }
|
||||
@@ -36,6 +37,7 @@ notify = { version = "4.0.17" }
|
||||
num-bigint = { version = "0.4.3" }
|
||||
once_cell = { version = "1.16.0" }
|
||||
path-absolutize = { version = "3.0.14", features = ["once_cell_cache", "use_unix_paths_on_wasm"] }
|
||||
quick-junit = { version = "0.3.2" }
|
||||
rayon = { version = "1.5.3" }
|
||||
regex = { version = "1.6.0" }
|
||||
ropey = { version = "1.5.0", features = ["cr_lines", "simd"], default-features = false }
|
||||
|
||||
50
LICENSE
50
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
|
||||
|
||||
4
flake8_to_ruff/Cargo.lock
generated
4
flake8_to_ruff/Cargo.lock
generated
@@ -771,7 +771,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8_to_ruff"
|
||||
version = "0.0.140"
|
||||
version = "0.0.149"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@@ -1975,7 +1975,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.140"
|
||||
version = "0.0.149"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.140-dev.0"
|
||||
version = "0.0.149-dev.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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,
|
||||
]
|
||||
|
||||
@@ -31,7 +31,3 @@ build-backend = "maturin"
|
||||
[tool.maturin]
|
||||
bindings = "bin"
|
||||
strip = true
|
||||
|
||||
[tool.isort]
|
||||
profile = "black"
|
||||
known_third_party = ["fastapi", "pydantic", "starlette"]
|
||||
|
||||
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}
|
||||
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
|
||||
|
||||
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()
|
||||
10
resources/test/fixtures/U015.py
vendored
10
resources/test/fixtures/U015.py
vendored
@@ -68,3 +68,13 @@ open(file="foo", mode='Ub', buffering=- 1, encoding=None, errors=None, newline=N
|
||||
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
|
||||
|
||||
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.140"
|
||||
version = "0.0.149"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -107,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,
|
||||
}
|
||||
|
||||
@@ -4,14 +4,14 @@ 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,
|
||||
}
|
||||
|
||||
301
src/check_ast.rs
301
src/check_ast.rs
@@ -3,7 +3,6 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::path::Path;
|
||||
|
||||
use itertools::Itertools;
|
||||
use log::error;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use rustpython_ast::Withitem;
|
||||
@@ -19,8 +18,7 @@ use crate::ast::helpers::{
|
||||
use crate::ast::operations::extract_all_names;
|
||||
use crate::ast::relocate::relocate_expr;
|
||||
use crate::ast::types::{
|
||||
Binding, BindingContext, BindingKind, ClassScope, FunctionScope, ImportKind, Node, Range,
|
||||
Scope, ScopeKind,
|
||||
Binding, BindingContext, BindingKind, ClassScope, FunctionScope, Node, Range, Scope, ScopeKind,
|
||||
};
|
||||
use crate::ast::visitor::{walk_excepthandler, walk_withitem, Visitor};
|
||||
use crate::ast::{helpers, operations, visitor};
|
||||
@@ -33,11 +31,13 @@ use crate::python::typing::SubscriptKind;
|
||||
use crate::settings::types::PythonVersion;
|
||||
use crate::settings::Settings;
|
||||
use crate::source_code_locator::SourceCodeLocator;
|
||||
use crate::vendored::cformat::{CFormatError, CFormatErrorType};
|
||||
use crate::visibility::{module_visibility, transition_scope, Modifier, Visibility, VisibleScope};
|
||||
use crate::{
|
||||
docstrings, flake8_2020, flake8_annotations, flake8_bandit, flake8_blind_except,
|
||||
flake8_boolean_trap, flake8_bugbear, flake8_builtins, flake8_comprehensions, flake8_print,
|
||||
flake8_tidy_imports, mccabe, pep8_naming, pycodestyle, pydocstyle, pyflakes, pyupgrade, rules,
|
||||
flake8_boolean_trap, flake8_bugbear, flake8_builtins, flake8_comprehensions, flake8_debugger,
|
||||
flake8_print, flake8_tidy_imports, mccabe, pep8_naming, pycodestyle, pydocstyle, pyflakes,
|
||||
pyupgrade, rules,
|
||||
};
|
||||
|
||||
const GLOBAL_SCOPE_INDEX: usize = 0;
|
||||
@@ -76,6 +76,7 @@ pub struct Checker<'a> {
|
||||
in_f_string: Option<Range>,
|
||||
in_annotation: bool,
|
||||
in_deferred_string_annotation: bool,
|
||||
in_deferred_annotation: bool,
|
||||
in_literal: bool,
|
||||
in_subscript: bool,
|
||||
in_withitem: bool,
|
||||
@@ -122,6 +123,7 @@ impl<'a> Checker<'a> {
|
||||
in_f_string: None,
|
||||
in_annotation: false,
|
||||
in_deferred_string_annotation: false,
|
||||
in_deferred_annotation: false,
|
||||
in_literal: false,
|
||||
in_subscript: false,
|
||||
in_withitem: false,
|
||||
@@ -590,7 +592,7 @@ where
|
||||
self.binding_context(),
|
||||
),
|
||||
used: None,
|
||||
range: Range::from_located(stmt),
|
||||
range: Range::from_located(alias),
|
||||
},
|
||||
);
|
||||
} else {
|
||||
@@ -625,16 +627,25 @@ where
|
||||
.last()
|
||||
.expect("No current scope found."))]
|
||||
.id,
|
||||
Range::from_located(stmt),
|
||||
Range::from_located(alias),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
range: Range::from_located(stmt),
|
||||
range: Range::from_located(alias),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// flake8-debugger
|
||||
if self.settings.enabled.contains(&CheckCode::T100) {
|
||||
if let Some(check) =
|
||||
flake8_debugger::checks::debugger_import(stmt, None, &alias.node.name)
|
||||
{
|
||||
self.add_check(check);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(asname) = &alias.node.asname {
|
||||
for alias in names {
|
||||
if let Some(asname) = &alias.node.asname {
|
||||
@@ -703,12 +714,7 @@ where
|
||||
self.from_imports
|
||||
.entry(module)
|
||||
.or_insert_with(FxHashSet::default)
|
||||
.extend(
|
||||
names
|
||||
.iter()
|
||||
.filter(|alias| alias.node.asname.is_none())
|
||||
.map(|alias| alias.node.name.as_str()),
|
||||
);
|
||||
.extend(names.iter().map(|alias| alias.node.name.as_str()));
|
||||
}
|
||||
for alias in names {
|
||||
if let Some(asname) = &alias.node.asname {
|
||||
@@ -746,9 +752,9 @@ where
|
||||
.last()
|
||||
.expect("No current scope found."))]
|
||||
.id,
|
||||
Range::from_located(stmt),
|
||||
Range::from_located(alias),
|
||||
)),
|
||||
range: Range::from_located(stmt),
|
||||
range: Range::from_located(alias),
|
||||
},
|
||||
);
|
||||
|
||||
@@ -760,7 +766,7 @@ where
|
||||
if !ALL_FEATURE_NAMES.contains(&&*alias.node.name) {
|
||||
self.add_check(Check::new(
|
||||
CheckKind::FutureFeatureNotDefined(alias.node.name.to_string()),
|
||||
Range::from_located(stmt),
|
||||
Range::from_located(alias),
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -822,6 +828,7 @@ where
|
||||
None => alias.node.name.to_string(),
|
||||
Some(parent) => format!("{parent}.{}", alias.node.name),
|
||||
};
|
||||
let range = Range::from_located(alias);
|
||||
self.add_binding(
|
||||
name,
|
||||
Binding {
|
||||
@@ -844,12 +851,12 @@ where
|
||||
.last()
|
||||
.expect("No current scope found."))]
|
||||
.id,
|
||||
Range::from_located(stmt),
|
||||
range,
|
||||
))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
range: Range::from_located(stmt),
|
||||
range,
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -864,6 +871,17 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
// flake8-debugger
|
||||
if self.settings.enabled.contains(&CheckCode::T100) {
|
||||
if let Some(check) = flake8_debugger::checks::debugger_import(
|
||||
stmt,
|
||||
module.as_ref().map(String::as_str),
|
||||
&alias.node.name,
|
||||
) {
|
||||
self.add_check(check);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(asname) = &alias.node.asname {
|
||||
if self.settings.enabled.contains(&CheckCode::N811) {
|
||||
if let Some(check) =
|
||||
@@ -1174,10 +1192,14 @@ where
|
||||
// Pre-visit.
|
||||
match &expr.node {
|
||||
ExprKind::Subscript { value, slice, .. } => {
|
||||
// Ex) typing.List[...]
|
||||
// Ex) Optional[...]
|
||||
if !self.in_deferred_string_annotation
|
||||
&& self.settings.enabled.contains(&CheckCode::U007)
|
||||
&& self.settings.target_version >= PythonVersion::Py310
|
||||
&& (self.settings.target_version >= PythonVersion::Py310
|
||||
|| (self.settings.target_version >= PythonVersion::Py37
|
||||
&& !self.settings.pyupgrade.keep_runtime_typing
|
||||
&& self.annotations_future_enabled
|
||||
&& self.in_deferred_annotation))
|
||||
{
|
||||
pyupgrade::plugins::use_pep604_annotation(self, expr, value, slice);
|
||||
}
|
||||
@@ -1216,7 +1238,11 @@ where
|
||||
// Ex) List[...]
|
||||
if !self.in_deferred_string_annotation
|
||||
&& self.settings.enabled.contains(&CheckCode::U006)
|
||||
&& self.settings.target_version >= PythonVersion::Py39
|
||||
&& (self.settings.target_version >= PythonVersion::Py39
|
||||
|| (self.settings.target_version >= PythonVersion::Py37
|
||||
&& !self.settings.pyupgrade.keep_runtime_typing
|
||||
&& self.annotations_future_enabled
|
||||
&& self.in_deferred_annotation))
|
||||
&& typing::is_pep585_builtin(
|
||||
expr,
|
||||
&self.from_imports,
|
||||
@@ -1251,8 +1277,12 @@ where
|
||||
}
|
||||
ExprKind::Attribute { attr, .. } => {
|
||||
// Ex) typing.List[...]
|
||||
if self.settings.enabled.contains(&CheckCode::U006)
|
||||
&& self.settings.target_version >= PythonVersion::Py39
|
||||
if !self.in_deferred_string_annotation
|
||||
&& self.settings.enabled.contains(&CheckCode::U006)
|
||||
&& (self.settings.target_version >= PythonVersion::Py39
|
||||
|| (self.settings.target_version >= PythonVersion::Py37
|
||||
&& self.annotations_future_enabled
|
||||
&& self.in_deferred_annotation))
|
||||
&& typing::is_pep585_builtin(expr, &self.from_imports, &self.import_aliases)
|
||||
{
|
||||
pyupgrade::plugins::use_pep585_annotation(self, expr, attr);
|
||||
@@ -1621,7 +1651,7 @@ where
|
||||
// flake8-boolean-trap
|
||||
if self.settings.enabled.contains(&CheckCode::FBT003) {
|
||||
flake8_boolean_trap::plugins::check_boolean_positional_value_in_function_call(
|
||||
self, args,
|
||||
self, args, func,
|
||||
);
|
||||
}
|
||||
if let ExprKind::Name { id, ctx } = &func.node {
|
||||
@@ -1634,6 +1664,18 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
// flake8-debugger
|
||||
if self.settings.enabled.contains(&CheckCode::T100) {
|
||||
if let Some(check) = flake8_debugger::checks::debugger_call(
|
||||
expr,
|
||||
func,
|
||||
&self.from_imports,
|
||||
&self.import_aliases,
|
||||
) {
|
||||
self.add_check(check);
|
||||
}
|
||||
}
|
||||
|
||||
// Ruff
|
||||
if self.settings.enabled.contains(&CheckCode::RUF101) {
|
||||
rules::plugins::convert_exit_to_sys_exit(self, func);
|
||||
@@ -1688,6 +1730,116 @@ where
|
||||
pyflakes::plugins::invalid_print_syntax(self, left);
|
||||
}
|
||||
}
|
||||
ExprKind::BinOp {
|
||||
left,
|
||||
op: Operator::Mod,
|
||||
right,
|
||||
} => {
|
||||
if let ExprKind::Constant {
|
||||
value: Constant::Str(value),
|
||||
..
|
||||
} = &left.node
|
||||
{
|
||||
if self.settings.enabled.contains(&CheckCode::F501)
|
||||
|| self.settings.enabled.contains(&CheckCode::F502)
|
||||
|| self.settings.enabled.contains(&CheckCode::F503)
|
||||
|| self.settings.enabled.contains(&CheckCode::F504)
|
||||
|| self.settings.enabled.contains(&CheckCode::F505)
|
||||
|| self.settings.enabled.contains(&CheckCode::F506)
|
||||
|| self.settings.enabled.contains(&CheckCode::F507)
|
||||
|| self.settings.enabled.contains(&CheckCode::F508)
|
||||
|| self.settings.enabled.contains(&CheckCode::F509)
|
||||
{
|
||||
let location = Range::from_located(expr);
|
||||
match pyflakes::cformat::CFormatSummary::try_from(value.as_ref()) {
|
||||
Err(CFormatError {
|
||||
typ: CFormatErrorType::UnsupportedFormatChar(c),
|
||||
..
|
||||
}) => {
|
||||
if self.settings.enabled.contains(&CheckCode::F509) {
|
||||
self.add_check(Check::new(
|
||||
CheckKind::PercentFormatUnsupportedFormatCharacter(c),
|
||||
location,
|
||||
));
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
if self.settings.enabled.contains(&CheckCode::F501) {
|
||||
self.add_check(Check::new(
|
||||
CheckKind::PercentFormatInvalidFormat(e.to_string()),
|
||||
location,
|
||||
));
|
||||
}
|
||||
}
|
||||
Ok(summary) => {
|
||||
if self.settings.enabled.contains(&CheckCode::F502) {
|
||||
if let Some(check) =
|
||||
pyflakes::checks::percent_format_expected_mapping(
|
||||
&summary, right, location,
|
||||
)
|
||||
{
|
||||
self.add_check(check);
|
||||
}
|
||||
}
|
||||
if self.settings.enabled.contains(&CheckCode::F503) {
|
||||
if let Some(check) =
|
||||
pyflakes::checks::percent_format_expected_sequence(
|
||||
&summary, right, location,
|
||||
)
|
||||
{
|
||||
self.add_check(check);
|
||||
}
|
||||
}
|
||||
if self.settings.enabled.contains(&CheckCode::F504) {
|
||||
if let Some(check) =
|
||||
pyflakes::checks::percent_format_extra_named_arguments(
|
||||
&summary, right, location,
|
||||
)
|
||||
{
|
||||
self.add_check(check);
|
||||
}
|
||||
}
|
||||
if self.settings.enabled.contains(&CheckCode::F505) {
|
||||
if let Some(check) =
|
||||
pyflakes::checks::percent_format_missing_arguments(
|
||||
&summary, right, location,
|
||||
)
|
||||
{
|
||||
self.add_check(check);
|
||||
}
|
||||
}
|
||||
if self.settings.enabled.contains(&CheckCode::F506) {
|
||||
if let Some(check) =
|
||||
pyflakes::checks::percent_format_mixed_positional_and_named(
|
||||
&summary, location,
|
||||
)
|
||||
{
|
||||
self.add_check(check);
|
||||
}
|
||||
}
|
||||
if self.settings.enabled.contains(&CheckCode::F507) {
|
||||
if let Some(check) =
|
||||
pyflakes::checks::percent_format_positional_count_mismatch(
|
||||
&summary, right, location,
|
||||
)
|
||||
{
|
||||
self.add_check(check);
|
||||
}
|
||||
}
|
||||
if self.settings.enabled.contains(&CheckCode::F508) {
|
||||
if let Some(check) =
|
||||
pyflakes::checks::percent_format_star_requires_sequence(
|
||||
&summary, right, location,
|
||||
)
|
||||
{
|
||||
self.add_check(check);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ExprKind::UnaryOp { op, operand } => {
|
||||
let check_not_in = self.settings.enabled.contains(&CheckCode::E713);
|
||||
let check_not_is = self.settings.enabled.contains(&CheckCode::E714);
|
||||
@@ -2604,7 +2756,9 @@ impl<'a> Checker<'a> {
|
||||
while let Some((expr, scopes, parents)) = self.deferred_annotations.pop() {
|
||||
self.scope_stack = scopes;
|
||||
self.parent_stack = parents;
|
||||
self.in_deferred_annotation = true;
|
||||
self.visit_expr(expr);
|
||||
self.in_deferred_annotation = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2630,9 +2784,9 @@ impl<'a> Checker<'a> {
|
||||
}
|
||||
}
|
||||
for (expr, (scopes, parents)) in allocator.iter().zip(stacks) {
|
||||
self.in_deferred_string_annotation = true;
|
||||
self.scope_stack = scopes;
|
||||
self.parent_stack = parents;
|
||||
self.in_deferred_string_annotation = true;
|
||||
self.visit_expr(expr);
|
||||
self.in_deferred_string_annotation = false;
|
||||
}
|
||||
@@ -2763,68 +2917,54 @@ impl<'a> Checker<'a> {
|
||||
if self.settings.enabled.contains(&CheckCode::F401) {
|
||||
// Collect all unused imports by location. (Multiple unused imports at the same
|
||||
// location indicates an `import from`.)
|
||||
let mut unused: BTreeMap<(ImportKind, usize, Option<usize>), Vec<&str>> =
|
||||
type UnusedImport<'a> = (&'a String, &'a Range);
|
||||
|
||||
let mut unused: BTreeMap<(usize, Option<usize>), Vec<UnusedImport>> =
|
||||
BTreeMap::new();
|
||||
|
||||
for (name, binding) in &scope.values {
|
||||
if !matches!(
|
||||
binding.kind,
|
||||
BindingKind::Importation(..)
|
||||
| BindingKind::SubmoduleImportation(..)
|
||||
| BindingKind::FromImportation(..)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
let (full_name, context) = match &binding.kind {
|
||||
BindingKind::Importation(_, full_name, context)
|
||||
| BindingKind::SubmoduleImportation(_, full_name, context)
|
||||
| BindingKind::FromImportation(_, full_name, context) => {
|
||||
(full_name, context)
|
||||
}
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
let used = binding.used.is_some()
|
||||
// Skip used exports from `__all__`
|
||||
if binding.used.is_some()
|
||||
|| all_names
|
||||
.as_ref()
|
||||
.map(|names| names.contains(name))
|
||||
.unwrap_or_default();
|
||||
|
||||
if !used {
|
||||
match &binding.kind {
|
||||
BindingKind::FromImportation(_, full_name, context) => {
|
||||
unused
|
||||
.entry((
|
||||
ImportKind::ImportFrom,
|
||||
context.defined_by,
|
||||
context.defined_in,
|
||||
))
|
||||
.or_default()
|
||||
.push(full_name);
|
||||
}
|
||||
BindingKind::Importation(_, full_name, context)
|
||||
| BindingKind::SubmoduleImportation(_, full_name, context) => {
|
||||
unused
|
||||
.entry((
|
||||
ImportKind::Import,
|
||||
context.defined_by,
|
||||
context.defined_in,
|
||||
))
|
||||
.or_default()
|
||||
.push(full_name);
|
||||
}
|
||||
_ => unreachable!("Already filtered on BindingKind."),
|
||||
}
|
||||
.unwrap_or_default()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
unused
|
||||
.entry((context.defined_by, context.defined_in))
|
||||
.or_default()
|
||||
.push((full_name, &binding.range));
|
||||
}
|
||||
|
||||
for ((kind, defined_by, defined_in), full_names) in unused {
|
||||
for ((defined_by, defined_in), unused_imports) in unused {
|
||||
let child = self.parents[defined_by];
|
||||
let parent = defined_in.map(|defined_in| self.parents[defined_in]);
|
||||
|
||||
let fix = if self.patch(&CheckCode::F401) {
|
||||
let in_init_py = self.path.ends_with("__init__.py");
|
||||
let fix = if !in_init_py && self.patch(&CheckCode::F401) {
|
||||
let deleted: Vec<&Stmt> = self
|
||||
.deletions
|
||||
.iter()
|
||||
.map(|index| self.parents[*index])
|
||||
.collect();
|
||||
match match kind {
|
||||
ImportKind::Import => pyflakes::fixes::remove_unused_imports,
|
||||
ImportKind::ImportFrom => pyflakes::fixes::remove_unused_import_froms,
|
||||
}(
|
||||
self.locator, &full_names, child, parent, &deleted
|
||||
match pyflakes::fixes::remove_unused_imports(
|
||||
self.locator,
|
||||
&unused_imports,
|
||||
child,
|
||||
parent,
|
||||
&deleted,
|
||||
) {
|
||||
Ok(fix) => {
|
||||
if fix.patch.content.is_empty() || fix.patch.content == "pass" {
|
||||
@@ -2841,24 +2981,13 @@ impl<'a> Checker<'a> {
|
||||
None
|
||||
};
|
||||
|
||||
if self.path.ends_with("__init__.py") {
|
||||
checks.push(Check::new(
|
||||
CheckKind::UnusedImport(
|
||||
full_names.into_iter().sorted().map(String::from).collect(),
|
||||
true,
|
||||
),
|
||||
Range::from_located(child),
|
||||
));
|
||||
} else {
|
||||
for (full_name, range) in unused_imports {
|
||||
let mut check = Check::new(
|
||||
CheckKind::UnusedImport(
|
||||
full_names.into_iter().sorted().map(String::from).collect(),
|
||||
false,
|
||||
),
|
||||
Range::from_located(child),
|
||||
CheckKind::UnusedImport(full_name.clone(), in_init_py),
|
||||
*range,
|
||||
);
|
||||
if let Some(fix) = fix {
|
||||
check.amend(fix);
|
||||
if let Some(fix) = fix.as_ref() {
|
||||
check.amend(fix.clone());
|
||||
}
|
||||
checks.push(check);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -209,7 +212,7 @@ pub fn check_lines(
|
||||
let mut invalid_codes = vec![];
|
||||
let mut valid_codes = vec![];
|
||||
for code in codes {
|
||||
if matches.contains(&code) {
|
||||
if matches.contains(&code) || settings.external.contains(code) {
|
||||
valid_codes.push(code.to_string());
|
||||
} else {
|
||||
invalid_codes.push(code.to_string());
|
||||
|
||||
@@ -6,7 +6,7 @@ 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(
|
||||
locator: &SourceCodeLocator,
|
||||
@@ -23,6 +23,7 @@ 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();
|
||||
@@ -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 { .. }) {
|
||||
|
||||
398
src/checks.rs
398
src/checks.rs
@@ -3,10 +3,11 @@ use std::str::FromStr;
|
||||
use itertools::Itertools;
|
||||
use rustpython_parser::ast::Location;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum_macros::{AsRefStr, EnumIter, EnumString};
|
||||
use strum_macros::{AsRefStr, Display, 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;
|
||||
@@ -16,6 +17,7 @@ use crate::pyupgrade::types::Primitive;
|
||||
EnumIter,
|
||||
EnumString,
|
||||
Debug,
|
||||
Display,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Clone,
|
||||
@@ -52,6 +54,15 @@ pub enum CheckCode {
|
||||
F405,
|
||||
F406,
|
||||
F407,
|
||||
F501,
|
||||
F502,
|
||||
F503,
|
||||
F504,
|
||||
F505,
|
||||
F506,
|
||||
F507,
|
||||
F508,
|
||||
F509,
|
||||
F521,
|
||||
F522,
|
||||
F523,
|
||||
@@ -129,6 +140,8 @@ pub enum CheckCode {
|
||||
C415,
|
||||
C416,
|
||||
C417,
|
||||
// flake8-debugger
|
||||
T100,
|
||||
// mccabe
|
||||
C901,
|
||||
// flake8-tidy-imports
|
||||
@@ -242,6 +255,8 @@ pub enum CheckCode {
|
||||
N818,
|
||||
// isort
|
||||
I001,
|
||||
// eradicate
|
||||
ERA001,
|
||||
// flake8-bandit
|
||||
S101,
|
||||
S102,
|
||||
@@ -270,8 +285,10 @@ pub enum CheckCategory {
|
||||
Pydocstyle,
|
||||
Pyupgrade,
|
||||
PEP8Naming,
|
||||
Eradicate,
|
||||
Flake8Bandit,
|
||||
Flake8Comprehensions,
|
||||
Flake8Debugger,
|
||||
Flake8BooleanTrap,
|
||||
Flake8Bugbear,
|
||||
Flake8Builtins,
|
||||
@@ -289,65 +306,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,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -407,6 +430,15 @@ 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>),
|
||||
@@ -418,7 +450,7 @@ pub enum CheckKind {
|
||||
UndefinedExport(String),
|
||||
UndefinedLocal(String),
|
||||
UndefinedName(String),
|
||||
UnusedImport(Vec<String>, bool),
|
||||
UnusedImport(String, bool),
|
||||
UnusedVariable(String),
|
||||
YieldOutsideFunction,
|
||||
// flake8-builtins
|
||||
@@ -472,6 +504,8 @@ pub enum CheckKind {
|
||||
UnnecessarySubscriptReversal(String),
|
||||
UnnecessaryComprehension(String),
|
||||
UnnecessaryMap(String),
|
||||
// flake8-debugger
|
||||
Debugger(DebuggerUsingType),
|
||||
// flake8-tidy-imports
|
||||
BannedRelativeImport(Strictness),
|
||||
// flake8-print
|
||||
@@ -583,6 +617,8 @@ pub enum CheckKind {
|
||||
ErrorSuffixOnExceptionName(String),
|
||||
// isort
|
||||
UnsortedImports,
|
||||
// eradicate
|
||||
CommentedOutCode,
|
||||
// flake8-bandit
|
||||
AssertUsed,
|
||||
ExecUsed,
|
||||
@@ -613,7 +649,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
|
||||
@@ -649,7 +686,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,
|
||||
@@ -658,6 +695,15 @@ 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()])
|
||||
@@ -754,6 +800,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
|
||||
@@ -886,6 +934,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,
|
||||
@@ -911,58 +961,20 @@ impl CheckCode {
|
||||
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::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::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,
|
||||
@@ -1007,48 +1019,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::U015 => CheckCategory::Pyupgrade,
|
||||
CheckCode::C901 => CheckCategory::McCabe,
|
||||
CheckCode::D100 => CheckCategory::Pydocstyle,
|
||||
CheckCode::D101 => CheckCategory::Pydocstyle,
|
||||
CheckCode::D102 => CheckCategory::Pydocstyle,
|
||||
@@ -1093,6 +1064,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,
|
||||
@@ -1108,22 +1142,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::RUF101 => 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1162,6 +1223,15 @@ 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,
|
||||
@@ -1234,6 +1304,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
|
||||
@@ -1345,6 +1417,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,
|
||||
@@ -1450,6 +1524,35 @@ 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()
|
||||
}
|
||||
@@ -1501,12 +1604,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) => {
|
||||
@@ -1718,6 +1820,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 => {
|
||||
@@ -2023,6 +2130,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(),
|
||||
@@ -2127,6 +2236,7 @@ impl CheckKind {
|
||||
| CheckKind::BlankLineAfterSummary
|
||||
| CheckKind::BlankLineBeforeSection(..)
|
||||
| CheckKind::CapitalizeSectionName(..)
|
||||
| CheckKind::CommentedOutCode
|
||||
| CheckKind::ConvertExitToSysExit
|
||||
| CheckKind::ConvertNamedTupleFunctionalToClass(..)
|
||||
| CheckKind::ConvertTypedDictFunctionalToClass(..)
|
||||
|
||||
@@ -176,6 +176,10 @@ pub enum CheckCodePrefix {
|
||||
E902,
|
||||
E99,
|
||||
E999,
|
||||
ERA,
|
||||
ERA0,
|
||||
ERA00,
|
||||
ERA001,
|
||||
F,
|
||||
F4,
|
||||
F40,
|
||||
@@ -187,6 +191,16 @@ pub enum CheckCodePrefix {
|
||||
F406,
|
||||
F407,
|
||||
F5,
|
||||
F50,
|
||||
F501,
|
||||
F502,
|
||||
F503,
|
||||
F504,
|
||||
F505,
|
||||
F506,
|
||||
F507,
|
||||
F508,
|
||||
F509,
|
||||
F52,
|
||||
F521,
|
||||
F522,
|
||||
@@ -290,6 +304,9 @@ pub enum CheckCodePrefix {
|
||||
S106,
|
||||
S107,
|
||||
T,
|
||||
T1,
|
||||
T10,
|
||||
T100,
|
||||
T2,
|
||||
T20,
|
||||
T201,
|
||||
@@ -850,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,
|
||||
@@ -858,6 +879,15 @@ 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,
|
||||
@@ -911,6 +941,15 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::F406 => vec![CheckCode::F406],
|
||||
CheckCodePrefix::F407 => vec![CheckCode::F407],
|
||||
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,
|
||||
@@ -918,6 +957,26 @@ impl CheckCodePrefix {
|
||||
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,
|
||||
@@ -1149,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],
|
||||
@@ -1440,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,
|
||||
@@ -1451,6 +1517,16 @@ 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,
|
||||
@@ -1554,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,
|
||||
@@ -1612,6 +1691,7 @@ pub const CATEGORIES: &[CheckCodePrefix] = &[
|
||||
CheckCodePrefix::C,
|
||||
CheckCodePrefix::D,
|
||||
CheckCodePrefix::E,
|
||||
CheckCodePrefix::ERA,
|
||||
CheckCodePrefix::F,
|
||||
CheckCodePrefix::FBT,
|
||||
CheckCodePrefix::I,
|
||||
|
||||
16
src/cli.rs
16
src/cli.rs
@@ -7,15 +7,16 @@ 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::{FilePattern, 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)]
|
||||
@@ -77,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,
|
||||
@@ -114,6 +115,9 @@ pub struct Cli {
|
||||
/// 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 {
|
||||
@@ -140,8 +144,6 @@ 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
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use anyhow::Result;
|
||||
use anyhow::{bail, Result};
|
||||
use serde::Serialize;
|
||||
use walkdir::DirEntry;
|
||||
|
||||
use crate::checks::CheckCode;
|
||||
use crate::fs::iter_python_files;
|
||||
use crate::printer::SerializationFormat;
|
||||
use crate::settings::types::SerializationFormat;
|
||||
use crate::{Configuration, Settings};
|
||||
|
||||
/// Print the user-facing configuration settings.
|
||||
@@ -43,7 +43,7 @@ struct Explanation<'a> {
|
||||
/// Explain a `CheckCode` to the user.
|
||||
pub fn explain(code: &CheckCode, format: SerializationFormat) -> Result<()> {
|
||||
match format {
|
||||
SerializationFormat::Text => {
|
||||
SerializationFormat::Text | SerializationFormat::Grouped => {
|
||||
println!(
|
||||
"{} ({}): {}",
|
||||
code.as_ref(),
|
||||
@@ -61,6 +61,9 @@ pub fn explain(code: &CheckCode, format: SerializationFormat) -> Result<()> {
|
||||
})?
|
||||
);
|
||||
}
|
||||
SerializationFormat::Junit => {
|
||||
bail!("`--explain` does not support junit format")
|
||||
}
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -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,
|
||||
@@ -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,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//! Settings for the `pep8-naming` plugin.
|
||||
//! Settings for the `flake8-bugbear` plugin.
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
||||
@@ -39,9 +39,7 @@ pub fn fix_unnecessary_generator_list(
|
||||
let call = match_call(body)?;
|
||||
let arg = match_arg(call)?;
|
||||
|
||||
let generator_exp = if let Expression::GeneratorExp(generator_exp) = &arg.value {
|
||||
generator_exp
|
||||
} else {
|
||||
let Expression::GeneratorExp(generator_exp) = &arg.value else {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Expected node to be: Expression::GeneratorExp"
|
||||
));
|
||||
@@ -82,9 +80,7 @@ pub fn fix_unnecessary_generator_set(
|
||||
let call = match_call(body)?;
|
||||
let arg = match_arg(call)?;
|
||||
|
||||
let generator_exp = if let Expression::GeneratorExp(generator_exp) = &arg.value {
|
||||
generator_exp
|
||||
} else {
|
||||
let Expression::GeneratorExp(generator_exp) = &arg.value else {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Expected node to be: Expression::GeneratorExp"
|
||||
));
|
||||
@@ -126,28 +122,20 @@ pub fn fix_unnecessary_generator_dict(
|
||||
let arg = match_arg(call)?;
|
||||
|
||||
// Extract the (k, v) from `(k, v) for ...`.
|
||||
let generator_exp = if let Expression::GeneratorExp(generator_exp) = &arg.value {
|
||||
generator_exp
|
||||
} else {
|
||||
let Expression::GeneratorExp(generator_exp) = &arg.value else {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Expected node to be: Expression::GeneratorExp"
|
||||
));
|
||||
};
|
||||
let tuple = if let Expression::Tuple(tuple) = &generator_exp.elt.as_ref() {
|
||||
tuple
|
||||
} else {
|
||||
let Expression::Tuple(tuple) = &generator_exp.elt.as_ref() else {
|
||||
return Err(anyhow::anyhow!("Expected node to be: Expression::Tuple"));
|
||||
};
|
||||
let key = if let Some(Element::Simple { value, .. }) = &tuple.elements.get(0) {
|
||||
value
|
||||
} else {
|
||||
let Some(Element::Simple { value: key, .. }) = &tuple.elements.get(0) else {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Expected tuple to contain a key as the first element"
|
||||
));
|
||||
};
|
||||
let value = if let Some(Element::Simple { value, .. }) = &tuple.elements.get(1) {
|
||||
value
|
||||
} else {
|
||||
let Some(Element::Simple { value, .. }) = &tuple.elements.get(1) else {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Expected tuple to contain a key as the second element"
|
||||
));
|
||||
@@ -192,9 +180,7 @@ pub fn fix_unnecessary_list_comprehension_set(
|
||||
let call = match_call(body)?;
|
||||
let arg = match_arg(call)?;
|
||||
|
||||
let list_comp = if let Expression::ListComp(list_comp) = &arg.value {
|
||||
list_comp
|
||||
} else {
|
||||
let Expression::ListComp(list_comp) = &arg.value else {
|
||||
return Err(anyhow::anyhow!("Expected node to be: Expression::ListComp"));
|
||||
};
|
||||
|
||||
@@ -233,25 +219,18 @@ pub fn fix_unnecessary_list_comprehension_dict(
|
||||
let call = match_call(body)?;
|
||||
let arg = match_arg(call)?;
|
||||
|
||||
let list_comp = if let Expression::ListComp(list_comp) = &arg.value {
|
||||
list_comp
|
||||
} else {
|
||||
let Expression::ListComp(list_comp) = &arg.value else {
|
||||
return Err(anyhow::anyhow!("Expected node to be: Expression::ListComp"));
|
||||
};
|
||||
|
||||
let tuple = if let Expression::Tuple(tuple) = &*list_comp.elt {
|
||||
tuple
|
||||
} else {
|
||||
let Expression::Tuple(tuple) = &*list_comp.elt else {
|
||||
return Err(anyhow::anyhow!("Expected node to be: Expression::Tuple"));
|
||||
};
|
||||
|
||||
let (key, comma, value) = match &tuple.elements[..] {
|
||||
[Element::Simple {
|
||||
let [Element::Simple {
|
||||
value: key,
|
||||
comma: Some(comma),
|
||||
}, Element::Simple { value, .. }] => (key, comma, value),
|
||||
_ => return Err(anyhow::anyhow!("Expected tuple with two elements")),
|
||||
};
|
||||
}, Element::Simple { value, .. }] = &tuple.elements[..] else { return Err(anyhow::anyhow!("Expected tuple with two elements")) };
|
||||
|
||||
body.value = Expression::DictComp(Box::new(DictComp {
|
||||
key: Box::new(key.clone()),
|
||||
@@ -409,9 +388,7 @@ pub fn fix_unnecessary_collection_call(
|
||||
let mut tree = match_module(&module_text)?;
|
||||
let mut body = match_expr(&mut tree)?;
|
||||
let call = match_call(body)?;
|
||||
let name = if let Expression::Name(name) = &call.func.as_ref() {
|
||||
name
|
||||
} else {
|
||||
let Expression::Name(name) = &call.func.as_ref() else {
|
||||
return Err(anyhow::anyhow!("Expected node to be: Expression::Name"));
|
||||
};
|
||||
|
||||
|
||||
64
src/flake8_debugger/checks.rs
Normal file
64
src/flake8_debugger/checks.rs
Normal file
@@ -0,0 +1,64 @@
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use rustpython_ast::{Expr, Stmt};
|
||||
|
||||
use crate::ast::helpers::{collect_call_paths, dealias_call_path, match_call_path};
|
||||
use crate::ast::types::Range;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
use crate::flake8_debugger::types::DebuggerUsingType;
|
||||
|
||||
const DEBUGGERS: &[(&str, &str)] = &[
|
||||
("pdb", "set_trace"),
|
||||
("pudb", "set_trace"),
|
||||
("ipdb", "set_trace"),
|
||||
("ipdb", "sset_trace"),
|
||||
("IPython.terminal.embed", "InteractiveShellEmbed"),
|
||||
("IPython.frontend.terminal.embed", "InteractiveShellEmbed"),
|
||||
("celery.contrib.rdb", "set_trace"),
|
||||
("builtins", "breakpoint"),
|
||||
("", "breakpoint"),
|
||||
];
|
||||
|
||||
/// Checks for the presence of a debugger call.
|
||||
pub fn debugger_call(
|
||||
expr: &Expr,
|
||||
func: &Expr,
|
||||
from_imports: &FxHashMap<&str, FxHashSet<&str>>,
|
||||
import_aliases: &FxHashMap<&str, &str>,
|
||||
) -> Option<Check> {
|
||||
let call_path = dealias_call_path(collect_call_paths(func), import_aliases);
|
||||
if DEBUGGERS
|
||||
.iter()
|
||||
.any(|(module, member)| match_call_path(&call_path, module, member, from_imports))
|
||||
{
|
||||
Some(Check::new(
|
||||
CheckKind::Debugger(DebuggerUsingType::Call(call_path.join("."))),
|
||||
Range::from_located(expr),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks for the presence of a debugger import.
|
||||
pub fn debugger_import(stmt: &Stmt, module: Option<&str>, name: &str) -> Option<Check> {
|
||||
if let Some(module) = module {
|
||||
if let Some((module_name, member)) = DEBUGGERS
|
||||
.iter()
|
||||
.find(|(module_name, member)| module_name == &module && member == &name)
|
||||
{
|
||||
return Some(Check::new(
|
||||
CheckKind::Debugger(DebuggerUsingType::Import(format!("{module_name}.{member}"))),
|
||||
Range::from_located(stmt),
|
||||
));
|
||||
}
|
||||
} else if DEBUGGERS
|
||||
.iter()
|
||||
.any(|(module_name, ..)| module_name == &name)
|
||||
{
|
||||
return Some(Check::new(
|
||||
CheckKind::Debugger(DebuggerUsingType::Import(name.to_string())),
|
||||
Range::from_located(stmt),
|
||||
));
|
||||
}
|
||||
None
|
||||
}
|
||||
2
src/flake8_debugger/mod.rs
Normal file
2
src/flake8_debugger/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub mod checks;
|
||||
pub mod types;
|
||||
7
src/flake8_debugger/types.rs
Normal file
7
src/flake8_debugger/types.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum DebuggerUsingType {
|
||||
Call(String),
|
||||
Import(String),
|
||||
}
|
||||
@@ -39,6 +39,7 @@ pub mod commands;
|
||||
mod cst;
|
||||
mod directives;
|
||||
mod docstrings;
|
||||
mod eradicate;
|
||||
mod flake8_2020;
|
||||
pub mod flake8_annotations;
|
||||
pub mod flake8_bandit;
|
||||
@@ -47,6 +48,7 @@ pub mod flake8_boolean_trap;
|
||||
pub mod flake8_bugbear;
|
||||
mod flake8_builtins;
|
||||
mod flake8_comprehensions;
|
||||
mod flake8_debugger;
|
||||
mod flake8_print;
|
||||
pub mod flake8_quotes;
|
||||
pub mod flake8_tidy_imports;
|
||||
|
||||
118
src/linter.rs
118
src/linter.rs
@@ -7,6 +7,7 @@ use std::path::Path;
|
||||
use anyhow::Result;
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
use log::debug;
|
||||
use nohash_hasher::IntMap;
|
||||
use rustpython_parser::lexer::LexResult;
|
||||
|
||||
use crate::ast::types::Range;
|
||||
@@ -46,6 +47,7 @@ impl AddAssign for Diagnostics {
|
||||
|
||||
/// Generate a list of `Check` violations from the source code contents at the
|
||||
/// given `Path`.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn check_path(
|
||||
path: &Path,
|
||||
contents: &str,
|
||||
@@ -252,7 +254,7 @@ pub fn add_noqa_to_path(path: &Path, settings: &Settings) -> Result<usize> {
|
||||
tokens,
|
||||
&locator,
|
||||
&Directives {
|
||||
noqa_line_for: Default::default(),
|
||||
noqa_line_for: IntMap::default(),
|
||||
isort_exclusions: directives.isort_exclusions,
|
||||
},
|
||||
settings,
|
||||
@@ -260,7 +262,13 @@ pub fn add_noqa_to_path(path: &Path, settings: &Settings) -> Result<usize> {
|
||||
true,
|
||||
)?;
|
||||
|
||||
add_noqa(&checks, &contents, &directives.noqa_line_for, path)
|
||||
add_noqa(
|
||||
path,
|
||||
&checks,
|
||||
&contents,
|
||||
&directives.noqa_line_for,
|
||||
&settings.external,
|
||||
)
|
||||
}
|
||||
|
||||
/// Apply autoformatting to the source code at the given `Path`.
|
||||
@@ -397,6 +405,7 @@ mod tests {
|
||||
use crate::checks::CheckCode;
|
||||
use crate::linter::test_path;
|
||||
use crate::settings;
|
||||
use crate::settings::types::PythonVersion;
|
||||
|
||||
#[test_case(CheckCode::A001, Path::new("A001.py"); "A001")]
|
||||
#[test_case(CheckCode::A002, Path::new("A002.py"); "A002")]
|
||||
@@ -485,9 +494,9 @@ mod tests {
|
||||
#[test_case(CheckCode::D414, Path::new("sections.py"); "D414")]
|
||||
#[test_case(CheckCode::D415, Path::new("D.py"); "D415")]
|
||||
#[test_case(CheckCode::D416, Path::new("D.py"); "D416")]
|
||||
#[test_case(CheckCode::D417, Path::new("sections.py"); "D417_0")]
|
||||
#[test_case(CheckCode::D417, Path::new("canonical_numpy_examples.py"); "D417_1")]
|
||||
#[test_case(CheckCode::D417, Path::new("canonical_google_examples.py"); "D417_2")]
|
||||
#[test_case(CheckCode::D417, Path::new("canonical_numpy_examples.py"); "D417_1")]
|
||||
#[test_case(CheckCode::D417, Path::new("sections.py"); "D417_0")]
|
||||
#[test_case(CheckCode::D418, Path::new("D.py"); "D418")]
|
||||
#[test_case(CheckCode::D419, Path::new("D.py"); "D419")]
|
||||
#[test_case(CheckCode::E402, Path::new("E402.py"); "E402")]
|
||||
@@ -503,6 +512,7 @@ mod tests {
|
||||
#[test_case(CheckCode::E742, Path::new("E742.py"); "E742")]
|
||||
#[test_case(CheckCode::E743, Path::new("E743.py"); "E743")]
|
||||
#[test_case(CheckCode::E999, Path::new("E999.py"); "E999")]
|
||||
#[test_case(CheckCode::ERA001, Path::new("ERA001.py"); "ERA001")]
|
||||
#[test_case(CheckCode::F401, Path::new("F401_0.py"); "F401_0")]
|
||||
#[test_case(CheckCode::F401, Path::new("F401_1.py"); "F401_1")]
|
||||
#[test_case(CheckCode::F401, Path::new("F401_2.py"); "F401_2")]
|
||||
@@ -516,6 +526,19 @@ mod tests {
|
||||
#[test_case(CheckCode::F405, Path::new("F405.py"); "F405")]
|
||||
#[test_case(CheckCode::F406, Path::new("F406.py"); "F406")]
|
||||
#[test_case(CheckCode::F407, Path::new("F407.py"); "F407")]
|
||||
#[test_case(CheckCode::F501, Path::new("F50x.py"); "F501")]
|
||||
#[test_case(CheckCode::F502, Path::new("F502.py"); "F502_1")]
|
||||
#[test_case(CheckCode::F502, Path::new("F50x.py"); "F502_0")]
|
||||
#[test_case(CheckCode::F503, Path::new("F503.py"); "F503_1")]
|
||||
#[test_case(CheckCode::F503, Path::new("F50x.py"); "F503_0")]
|
||||
#[test_case(CheckCode::F504, Path::new("F504.py"); "F504_1")]
|
||||
#[test_case(CheckCode::F504, Path::new("F50x.py"); "F504_0")]
|
||||
#[test_case(CheckCode::F505, Path::new("F504.py"); "F505_1")]
|
||||
#[test_case(CheckCode::F505, Path::new("F50x.py"); "F505_0")]
|
||||
#[test_case(CheckCode::F506, Path::new("F50x.py"); "F506")]
|
||||
#[test_case(CheckCode::F507, Path::new("F50x.py"); "F507")]
|
||||
#[test_case(CheckCode::F508, Path::new("F50x.py"); "F508")]
|
||||
#[test_case(CheckCode::F509, Path::new("F50x.py"); "F509")]
|
||||
#[test_case(CheckCode::F521, Path::new("F521.py"); "F521")]
|
||||
#[test_case(CheckCode::F522, Path::new("F522.py"); "F522")]
|
||||
#[test_case(CheckCode::F523, Path::new("F523.py"); "F523")]
|
||||
@@ -546,6 +569,9 @@ mod tests {
|
||||
#[test_case(CheckCode::F831, Path::new("F831.py"); "F831")]
|
||||
#[test_case(CheckCode::F841, Path::new("F841.py"); "F841")]
|
||||
#[test_case(CheckCode::F901, Path::new("F901.py"); "F901")]
|
||||
#[test_case(CheckCode::FBT001, Path::new("FBT.py"); "FBT001")]
|
||||
#[test_case(CheckCode::FBT002, Path::new("FBT.py"); "FBT002")]
|
||||
#[test_case(CheckCode::FBT003, Path::new("FBT.py"); "FBT003")]
|
||||
#[test_case(CheckCode::N801, Path::new("N801.py"); "N801")]
|
||||
#[test_case(CheckCode::N802, Path::new("N802.py"); "N802")]
|
||||
#[test_case(CheckCode::N803, Path::new("N803.py"); "N803")]
|
||||
@@ -561,12 +587,23 @@ mod tests {
|
||||
#[test_case(CheckCode::N816, Path::new("N816.py"); "N816")]
|
||||
#[test_case(CheckCode::N817, Path::new("N817.py"); "N817")]
|
||||
#[test_case(CheckCode::N818, Path::new("N818.py"); "N818")]
|
||||
#[test_case(CheckCode::RUF001, Path::new("RUF001.py"); "RUF001")]
|
||||
#[test_case(CheckCode::RUF002, Path::new("RUF002.py"); "RUF002")]
|
||||
#[test_case(CheckCode::RUF003, Path::new("RUF003.py"); "RUF003")]
|
||||
#[test_case(CheckCode::RUF101, Path::new("RUF101_0.py"); "RUF101_0")]
|
||||
#[test_case(CheckCode::RUF101, Path::new("RUF101_1.py"); "RUF101_1")]
|
||||
#[test_case(CheckCode::RUF101, Path::new("RUF101_2.py"); "RUF101_2")]
|
||||
#[test_case(CheckCode::RUF101, Path::new("RUF101_3.py"); "RUF101_3")]
|
||||
#[test_case(CheckCode::RUF101, Path::new("RUF101_4.py"); "RUF101_4")]
|
||||
#[test_case(CheckCode::RUF101, Path::new("RUF101_5.py"); "RUF101_5")]
|
||||
#[test_case(CheckCode::RUF101, Path::new("RUF101_6.py"); "RUF101_6")]
|
||||
#[test_case(CheckCode::S101, Path::new("S101.py"); "S101")]
|
||||
#[test_case(CheckCode::S102, Path::new("S102.py"); "S102")]
|
||||
#[test_case(CheckCode::S104, Path::new("S104.py"); "S104")]
|
||||
#[test_case(CheckCode::S105, Path::new("S105.py"); "S105")]
|
||||
#[test_case(CheckCode::S106, Path::new("S106.py"); "S106")]
|
||||
#[test_case(CheckCode::S107, Path::new("S107.py"); "S107")]
|
||||
#[test_case(CheckCode::T100, Path::new("T100.py"); "T100")]
|
||||
#[test_case(CheckCode::T201, Path::new("T201.py"); "T201")]
|
||||
#[test_case(CheckCode::T203, Path::new("T203.py"); "T203")]
|
||||
#[test_case(CheckCode::U001, Path::new("U001.py"); "U001")]
|
||||
@@ -593,16 +630,6 @@ mod tests {
|
||||
#[test_case(CheckCode::W292, Path::new("W292_2.py"); "W292_2")]
|
||||
#[test_case(CheckCode::W605, Path::new("W605_0.py"); "W605_0")]
|
||||
#[test_case(CheckCode::W605, Path::new("W605_1.py"); "W605_1")]
|
||||
#[test_case(CheckCode::RUF001, Path::new("RUF001.py"); "RUF001")]
|
||||
#[test_case(CheckCode::RUF002, Path::new("RUF002.py"); "RUF002")]
|
||||
#[test_case(CheckCode::RUF003, Path::new("RUF003.py"); "RUF003")]
|
||||
#[test_case(CheckCode::RUF101, Path::new("RUF101_0.py"); "RUF101_0")]
|
||||
#[test_case(CheckCode::RUF101, Path::new("RUF101_1.py"); "RUF101_1")]
|
||||
#[test_case(CheckCode::RUF101, Path::new("RUF101_2.py"); "RUF101_2")]
|
||||
#[test_case(CheckCode::RUF101, Path::new("RUF101_3.py"); "RUF101_3")]
|
||||
#[test_case(CheckCode::RUF101, Path::new("RUF101_4.py"); "RUF101_4")]
|
||||
#[test_case(CheckCode::RUF101, Path::new("RUF101_5.py"); "RUF101_5")]
|
||||
#[test_case(CheckCode::RUF101, Path::new("RUF101_6.py"); "RUF101_6")]
|
||||
#[test_case(CheckCode::YTT101, Path::new("YTT101.py"); "YTT101")]
|
||||
#[test_case(CheckCode::YTT102, Path::new("YTT102.py"); "YTT102")]
|
||||
#[test_case(CheckCode::YTT103, Path::new("YTT103.py"); "YTT103")]
|
||||
@@ -613,9 +640,6 @@ mod tests {
|
||||
#[test_case(CheckCode::YTT301, Path::new("YTT301.py"); "YTT301")]
|
||||
#[test_case(CheckCode::YTT302, Path::new("YTT302.py"); "YTT302")]
|
||||
#[test_case(CheckCode::YTT303, Path::new("YTT303.py"); "YTT303")]
|
||||
#[test_case(CheckCode::FBT001, Path::new("FBT.py"); "FBT001")]
|
||||
#[test_case(CheckCode::FBT002, Path::new("FBT.py"); "FBT002")]
|
||||
#[test_case(CheckCode::FBT003, Path::new("FBT.py"); "FBT003")]
|
||||
fn checks(check_code: CheckCode, path: &Path) -> Result<()> {
|
||||
let snapshot = format!("{}_{}", check_code.as_ref(), path.to_string_lossy());
|
||||
let mut checks = test_path(
|
||||
@@ -678,4 +702,64 @@ mod tests {
|
||||
insta::assert_yaml_snapshot!(checks);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn future_annotations_pep_585_p37() -> Result<()> {
|
||||
let mut checks = test_path(
|
||||
Path::new("./resources/test/fixtures/future_annotations.py"),
|
||||
&settings::Settings {
|
||||
target_version: PythonVersion::Py37,
|
||||
..settings::Settings::for_rule(CheckCode::U006)
|
||||
},
|
||||
true,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(checks);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn future_annotations_pep_585_py310() -> Result<()> {
|
||||
let mut checks = test_path(
|
||||
Path::new("./resources/test/fixtures/future_annotations.py"),
|
||||
&settings::Settings {
|
||||
target_version: PythonVersion::Py310,
|
||||
..settings::Settings::for_rule(CheckCode::U006)
|
||||
},
|
||||
true,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(checks);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn future_annotations_pep_604_p37() -> Result<()> {
|
||||
let mut checks = test_path(
|
||||
Path::new("./resources/test/fixtures/future_annotations.py"),
|
||||
&settings::Settings {
|
||||
target_version: PythonVersion::Py37,
|
||||
..settings::Settings::for_rule(CheckCode::U007)
|
||||
},
|
||||
true,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(checks);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn future_annotations_pep_604_py310() -> Result<()> {
|
||||
let mut checks = test_path(
|
||||
Path::new("./resources/test/fixtures/future_annotations.py"),
|
||||
&settings::Settings {
|
||||
target_version: PythonVersion::Py310,
|
||||
..settings::Settings::for_rule(CheckCode::U007)
|
||||
},
|
||||
true,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(checks);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
63
src/main.rs
63
src/main.rs
@@ -23,14 +23,15 @@ use ::ruff::fs::iter_python_files;
|
||||
use ::ruff::linter::{add_noqa_to_path, autoformat_path, lint_path, lint_stdin, Diagnostics};
|
||||
use ::ruff::logging::{set_up_logging, LogLevel};
|
||||
use ::ruff::message::Message;
|
||||
use ::ruff::printer::{Printer, SerializationFormat};
|
||||
use ::ruff::printer::Printer;
|
||||
use ::ruff::settings::configuration::Configuration;
|
||||
use ::ruff::settings::types::SerializationFormat;
|
||||
use ::ruff::settings::{pyproject, Settings};
|
||||
#[cfg(feature = "update-informer")]
|
||||
use ::ruff::updates;
|
||||
use ::ruff::{cache, commands};
|
||||
use anyhow::Result;
|
||||
use clap::Parser;
|
||||
use clap::{CommandFactory, Parser};
|
||||
use colored::Colorize;
|
||||
use log::{debug, error};
|
||||
use notify::{raw_watcher, RecursiveMode, Watcher};
|
||||
@@ -189,23 +190,18 @@ fn inner_main() -> Result<ExitCode> {
|
||||
// Extract command-line arguments.
|
||||
let cli = Cli::parse();
|
||||
let fix = cli.fix();
|
||||
|
||||
let log_level = extract_log_level(&cli);
|
||||
set_up_logging(&log_level)?;
|
||||
|
||||
if let Some(shell) = cli.generate_shell_completion {
|
||||
shell.generate(&mut Cli::command(), &mut std::io::stdout());
|
||||
return Ok(ExitCode::SUCCESS);
|
||||
}
|
||||
|
||||
// Find the project root and pyproject.toml.
|
||||
let project_root = pyproject::find_project_root(&cli.files);
|
||||
match &project_root {
|
||||
Some(path) => debug!("Found project root at: {:?}", path),
|
||||
None => debug!("Unable to identify project root; assuming current directory..."),
|
||||
};
|
||||
let pyproject = cli
|
||||
.config
|
||||
.or_else(|| pyproject::find_pyproject_toml(project_root.as_ref()));
|
||||
match &pyproject {
|
||||
Some(path) => debug!("Found pyproject.toml at: {:?}", path),
|
||||
None => debug!("Unable to find pyproject.toml; using default settings..."),
|
||||
};
|
||||
|
||||
// Reconcile configuration from pyproject.toml and command-line arguments.
|
||||
let mut configuration =
|
||||
@@ -237,6 +233,9 @@ fn inner_main() -> Result<ExitCode> {
|
||||
if !cli.unfixable.is_empty() {
|
||||
configuration.unfixable = cli.unfixable;
|
||||
}
|
||||
if let Some(format) = cli.format {
|
||||
configuration.format = format;
|
||||
}
|
||||
if let Some(line_length) = cli.line_length {
|
||||
configuration.line_length = line_length;
|
||||
}
|
||||
@@ -256,11 +255,6 @@ fn inner_main() -> Result<ExitCode> {
|
||||
configuration.show_source = true;
|
||||
}
|
||||
|
||||
if let Some(code) = cli.explain {
|
||||
commands::explain(&code, cli.format)?;
|
||||
return Ok(ExitCode::SUCCESS);
|
||||
}
|
||||
|
||||
if cli.show_settings && cli.show_files {
|
||||
eprintln!("Error: specify --show-settings or show-files (not both).");
|
||||
return Ok(ExitCode::FAILURE);
|
||||
@@ -274,6 +268,30 @@ fn inner_main() -> Result<ExitCode> {
|
||||
let fix_enabled: bool = configuration.fix;
|
||||
let settings = Settings::from_configuration(configuration, project_root.as_ref())?;
|
||||
|
||||
// If we're using JSON, override the log level.
|
||||
let log_level = if matches!(settings.format, SerializationFormat::Json) {
|
||||
LogLevel::Quiet
|
||||
} else {
|
||||
log_level
|
||||
};
|
||||
set_up_logging(&log_level)?;
|
||||
|
||||
// Now that we've inferred the appropriate log level, add some debug
|
||||
// information.
|
||||
match &project_root {
|
||||
Some(path) => debug!("Found project root at: {:?}", path),
|
||||
None => debug!("Unable to identify project root; assuming current directory..."),
|
||||
};
|
||||
match &pyproject {
|
||||
Some(path) => debug!("Found pyproject.toml at: {:?}", path),
|
||||
None => debug!("Unable to find pyproject.toml; using default settings..."),
|
||||
};
|
||||
|
||||
if let Some(code) = cli.explain {
|
||||
commands::explain(&code, settings.format)?;
|
||||
return Ok(ExitCode::SUCCESS);
|
||||
}
|
||||
|
||||
if cli.show_files {
|
||||
commands::show_files(&cli.files, &settings);
|
||||
return Ok(ExitCode::SUCCESS);
|
||||
@@ -286,24 +304,21 @@ fn inner_main() -> Result<ExitCode> {
|
||||
cache_enabled = false;
|
||||
}
|
||||
|
||||
let printer = Printer::new(&cli.format, &log_level);
|
||||
let printer = Printer::new(&settings.format, &log_level);
|
||||
if cli.watch {
|
||||
if settings.format != SerializationFormat::Text {
|
||||
eprintln!("Warning: --format 'text' is used in watch mode.");
|
||||
}
|
||||
if fix_enabled {
|
||||
eprintln!("Warning: --fix is not enabled in watch mode.");
|
||||
}
|
||||
|
||||
if cli.add_noqa {
|
||||
eprintln!("Warning: --no-qa is not enabled in watch mode.");
|
||||
}
|
||||
|
||||
if cli.autoformat {
|
||||
eprintln!("Warning: --autoformat is not enabled in watch mode.");
|
||||
}
|
||||
|
||||
if cli.format != SerializationFormat::Text {
|
||||
eprintln!("Warning: --format 'text' is used in watch mode.");
|
||||
}
|
||||
|
||||
// Perform an initial run instantly.
|
||||
printer.clear_screen()?;
|
||||
printer.write_to_user("Starting linter in watch mode...\n");
|
||||
|
||||
@@ -1,16 +1,10 @@
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt;
|
||||
use std::path::Path;
|
||||
|
||||
use annotate_snippets::display_list::{DisplayList, FormatOptions};
|
||||
use annotate_snippets::snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation};
|
||||
use colored::Colorize;
|
||||
use rustpython_parser::ast::Location;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
use crate::fs::relativize_path;
|
||||
use crate::source_code_locator::SourceCodeLocator;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
@@ -50,57 +44,6 @@ impl PartialOrd for Message {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Message {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let label = format!(
|
||||
"{}{}{}{}{}{} {} {}",
|
||||
relativize_path(Path::new(&self.filename)).bold(),
|
||||
":".cyan(),
|
||||
self.location.row(),
|
||||
":".cyan(),
|
||||
self.location.column(),
|
||||
":".cyan(),
|
||||
self.kind.code().as_ref().red().bold(),
|
||||
self.kind.body(),
|
||||
);
|
||||
match &self.source {
|
||||
None => write!(f, "{label}"),
|
||||
Some(source) => {
|
||||
let snippet = Snippet {
|
||||
title: Some(Annotation {
|
||||
label: Some(&label),
|
||||
annotation_type: AnnotationType::Error,
|
||||
// The ID (error number) is already encoded in the `label`.
|
||||
id: None,
|
||||
}),
|
||||
footer: vec![],
|
||||
slices: vec![Slice {
|
||||
source: &source.contents,
|
||||
line_start: self.location.row(),
|
||||
annotations: vec![SourceAnnotation {
|
||||
label: self.kind.code().as_ref(),
|
||||
annotation_type: AnnotationType::Error,
|
||||
range: source.range,
|
||||
}],
|
||||
// The origin (file name, line number, and column number) is already encoded
|
||||
// in the `label`.
|
||||
origin: None,
|
||||
fold: false,
|
||||
}],
|
||||
opt: FormatOptions {
|
||||
color: true,
|
||||
..FormatOptions::default()
|
||||
},
|
||||
};
|
||||
// `split_once(' ')` strips "error: " from `message`.
|
||||
let message = DisplayList::from(snippet).to_string();
|
||||
let (_, message) = message.split_once(' ').unwrap();
|
||||
write!(f, "{message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Source {
|
||||
pub contents: String,
|
||||
|
||||
64
src/noqa.rs
64
src/noqa.rs
@@ -3,6 +3,7 @@ use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::Result;
|
||||
use itertools::Itertools;
|
||||
use nohash_hasher::IntMap;
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
@@ -13,9 +14,9 @@ static NO_QA_REGEX: Lazy<Regex> = Lazy::new(|| {
|
||||
Regex::new(
|
||||
r"(?P<spaces>\s*)(?P<noqa>(?i:# noqa)(?::\s?(?P<codes>([A-Z]+[0-9]+(?:[,\s]+)?)+))?)",
|
||||
)
|
||||
.expect("Invalid regex")
|
||||
.unwrap()
|
||||
});
|
||||
static SPLIT_COMMA_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"[,\s]").expect("Invalid regex"));
|
||||
static SPLIT_COMMA_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"[,\s]").unwrap());
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Directive<'a> {
|
||||
@@ -52,12 +53,13 @@ pub fn extract_noqa_directive(line: &str) -> Directive {
|
||||
}
|
||||
|
||||
pub fn add_noqa(
|
||||
path: &Path,
|
||||
checks: &[Check],
|
||||
contents: &str,
|
||||
noqa_line_for: &IntMap<usize, usize>,
|
||||
path: &Path,
|
||||
external: &BTreeSet<String>,
|
||||
) -> Result<usize> {
|
||||
let (count, output) = add_noqa_inner(checks, contents, noqa_line_for);
|
||||
let (count, output) = add_noqa_inner(checks, contents, noqa_line_for, external);
|
||||
fs::write(path, output)?;
|
||||
Ok(count)
|
||||
}
|
||||
@@ -66,6 +68,7 @@ fn add_noqa_inner(
|
||||
checks: &[Check],
|
||||
contents: &str,
|
||||
noqa_line_for: &IntMap<usize, usize>,
|
||||
external: &BTreeSet<String>,
|
||||
) -> (usize, String) {
|
||||
let lines: Vec<&str> = contents.lines().collect();
|
||||
let mut matches_by_line: BTreeMap<usize, BTreeSet<&CheckCode>> = BTreeMap::new();
|
||||
@@ -112,25 +115,47 @@ fn add_noqa_inner(
|
||||
output.push('\n');
|
||||
count += 1;
|
||||
}
|
||||
Directive::All(_, start, _) | Directive::Codes(_, start, ..) => {
|
||||
let mut new_line = String::new();
|
||||
|
||||
Directive::All(_, start, _) => {
|
||||
// Add existing content.
|
||||
new_line.push_str(&line[..start].trim_end());
|
||||
output.push_str(line[..start].trim_end());
|
||||
|
||||
// Add `noqa` directive.
|
||||
new_line.push_str(" # noqa: ");
|
||||
output.push_str(" # noqa: ");
|
||||
|
||||
// Add codes.
|
||||
let codes: Vec<&str> = codes.iter().map(AsRef::as_ref).collect();
|
||||
let codes: Vec<&str> =
|
||||
codes.iter().map(AsRef::as_ref).sorted_unstable().collect();
|
||||
let suffix = codes.join(", ");
|
||||
new_line.push_str(&suffix);
|
||||
output.push_str(&suffix);
|
||||
output.push('\n');
|
||||
count += 1;
|
||||
}
|
||||
Directive::Codes(_, start, _, existing) => {
|
||||
// Reconstruct the line based on the preserved check codes.
|
||||
// This enables us to tally the number of edits.
|
||||
let mut formatted = String::new();
|
||||
|
||||
output.push_str(&new_line);
|
||||
// Add existing content.
|
||||
formatted.push_str(line[..start].trim_end());
|
||||
|
||||
// Add `noqa` directive.
|
||||
formatted.push_str(" # noqa: ");
|
||||
|
||||
// Add codes.
|
||||
let codes: Vec<&str> = codes
|
||||
.iter()
|
||||
.map(AsRef::as_ref)
|
||||
.chain(existing.into_iter().filter(|code| external.contains(*code)))
|
||||
.sorted_unstable()
|
||||
.collect();
|
||||
let suffix = codes.join(", ");
|
||||
formatted.push_str(&suffix);
|
||||
|
||||
output.push_str(&formatted);
|
||||
output.push('\n');
|
||||
|
||||
// Only count if the new line is an actual edit.
|
||||
if &new_line != line {
|
||||
if &formatted != line {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
@@ -144,6 +169,7 @@ fn add_noqa_inner(
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use nohash_hasher::IntMap;
|
||||
use rustpython_parser::ast::Location;
|
||||
@@ -171,7 +197,8 @@ mod tests {
|
||||
let checks = vec![];
|
||||
let contents = "x = 1";
|
||||
let noqa_line_for = IntMap::default();
|
||||
let (count, output) = add_noqa_inner(&checks, contents, &noqa_line_for);
|
||||
let external = BTreeSet::default();
|
||||
let (count, output) = add_noqa_inner(&checks, contents, &noqa_line_for, &external);
|
||||
assert_eq!(count, 0);
|
||||
assert_eq!(output.trim(), contents.trim());
|
||||
|
||||
@@ -184,7 +211,8 @@ mod tests {
|
||||
)];
|
||||
let contents = "x = 1";
|
||||
let noqa_line_for = IntMap::default();
|
||||
let (count, output) = add_noqa_inner(&checks, contents, &noqa_line_for);
|
||||
let external = BTreeSet::default();
|
||||
let (count, output) = add_noqa_inner(&checks, contents, &noqa_line_for, &external);
|
||||
assert_eq!(count, 1);
|
||||
assert_eq!(output.trim(), "x = 1 # noqa: F841".trim());
|
||||
|
||||
@@ -206,7 +234,8 @@ mod tests {
|
||||
];
|
||||
let contents = "x = 1 # noqa: E741";
|
||||
let noqa_line_for = IntMap::default();
|
||||
let (count, output) = add_noqa_inner(&checks, contents, &noqa_line_for);
|
||||
let external = BTreeSet::default();
|
||||
let (count, output) = add_noqa_inner(&checks, contents, &noqa_line_for, &external);
|
||||
assert_eq!(count, 1);
|
||||
assert_eq!(output.trim(), "x = 1 # noqa: E741, F841".trim());
|
||||
|
||||
@@ -228,7 +257,8 @@ mod tests {
|
||||
];
|
||||
let contents = "x = 1 # noqa";
|
||||
let noqa_line_for = IntMap::default();
|
||||
let (count, output) = add_noqa_inner(&checks, contents, &noqa_line_for);
|
||||
let external = BTreeSet::default();
|
||||
let (count, output) = add_noqa_inner(&checks, contents, &noqa_line_for, &external);
|
||||
assert_eq!(count, 1);
|
||||
assert_eq!(output.trim(), "x = 1 # noqa: E741, F841".trim());
|
||||
}
|
||||
|
||||
249
src/printer.rs
249
src/printer.rs
@@ -1,20 +1,22 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::path::Path;
|
||||
|
||||
use annotate_snippets::display_list::{DisplayList, FormatOptions};
|
||||
use annotate_snippets::snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation};
|
||||
use anyhow::Result;
|
||||
use clap::ValueEnum;
|
||||
use colored::Colorize;
|
||||
use itertools::iterate;
|
||||
use rustpython_parser::ast::Location;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::checks::{CheckCode, CheckKind};
|
||||
use crate::fs::relativize_path;
|
||||
use crate::linter::Diagnostics;
|
||||
use crate::logging::LogLevel;
|
||||
use crate::message::Message;
|
||||
use crate::settings::types::SerializationFormat;
|
||||
use crate::tell_user;
|
||||
|
||||
#[derive(Clone, Copy, ValueEnum, PartialEq, Eq, Debug)]
|
||||
pub enum SerializationFormat {
|
||||
Text,
|
||||
Json,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct ExpandedMessage<'a> {
|
||||
kind: &'a CheckKind,
|
||||
@@ -41,6 +43,28 @@ impl<'a> Printer<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn pre_text(&self, diagnostics: &Diagnostics) {
|
||||
if self.log_level >= &LogLevel::Default {
|
||||
if diagnostics.fixed > 0 {
|
||||
println!(
|
||||
"Found {} error(s) ({} fixed).",
|
||||
diagnostics.messages.len(),
|
||||
diagnostics.fixed,
|
||||
);
|
||||
} else if !diagnostics.messages.is_empty() {
|
||||
println!("Found {} error(s).", diagnostics.messages.len());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn post_text(&self, num_fixable: usize) {
|
||||
if self.log_level >= &LogLevel::Default {
|
||||
if num_fixable > 0 {
|
||||
println!("{num_fixable} potentially fixable with the --fix option.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_once(&self, diagnostics: &Diagnostics) -> Result<()> {
|
||||
if matches!(self.log_level, LogLevel::Silent) {
|
||||
return Ok(());
|
||||
@@ -72,28 +96,101 @@ impl<'a> Printer<'a> {
|
||||
)?
|
||||
);
|
||||
}
|
||||
SerializationFormat::Text => {
|
||||
if self.log_level >= &LogLevel::Default {
|
||||
if diagnostics.fixed > 0 {
|
||||
println!(
|
||||
"Found {} error(s) ({} fixed).",
|
||||
diagnostics.messages.len(),
|
||||
diagnostics.fixed,
|
||||
);
|
||||
} else if !diagnostics.messages.is_empty() {
|
||||
println!("Found {} error(s).", diagnostics.messages.len());
|
||||
}
|
||||
SerializationFormat::Junit => {
|
||||
use quick_junit::{NonSuccessKind, Report, TestCase, TestCaseStatus, TestSuite};
|
||||
|
||||
// Group by filename.
|
||||
let mut grouped_messages = BTreeMap::default();
|
||||
for message in &diagnostics.messages {
|
||||
grouped_messages
|
||||
.entry(&message.filename)
|
||||
.or_insert_with(Vec::new)
|
||||
.push(message);
|
||||
}
|
||||
|
||||
let mut report = Report::new("ruff");
|
||||
for (filename, messages) in grouped_messages {
|
||||
let mut test_suite = TestSuite::new(filename);
|
||||
test_suite
|
||||
.extra
|
||||
.insert("package".to_string(), "org.ruff".to_string());
|
||||
for message in messages {
|
||||
let mut status = TestCaseStatus::non_success(NonSuccessKind::Failure);
|
||||
status.set_message(message.kind.body());
|
||||
status.set_description(format!(
|
||||
"line {}, col {}, {}",
|
||||
message.location.row(),
|
||||
message.location.column(),
|
||||
message.kind.body()
|
||||
));
|
||||
let mut case =
|
||||
TestCase::new(format!("org.ruff.{}", message.kind.code()), status);
|
||||
let file_path = Path::new(filename);
|
||||
let file_stem = file_path.file_stem().unwrap().to_str().unwrap();
|
||||
let classname = file_path.parent().unwrap().join(file_stem);
|
||||
case.set_classname(classname.to_str().unwrap());
|
||||
case.extra
|
||||
.insert("line".to_string(), message.location.row().to_string());
|
||||
case.extra
|
||||
.insert("column".to_string(), message.location.column().to_string());
|
||||
|
||||
test_suite.add_test_case(case);
|
||||
}
|
||||
report.add_test_suite(test_suite);
|
||||
}
|
||||
println!("{}", report.to_string().unwrap());
|
||||
}
|
||||
SerializationFormat::Text => {
|
||||
self.pre_text(diagnostics);
|
||||
|
||||
for message in &diagnostics.messages {
|
||||
println!("{message}");
|
||||
print_message(message);
|
||||
}
|
||||
|
||||
if self.log_level >= &LogLevel::Default {
|
||||
if num_fixable > 0 {
|
||||
println!("{num_fixable} potentially fixable with the --fix option.");
|
||||
}
|
||||
self.post_text(num_fixable);
|
||||
}
|
||||
SerializationFormat::Grouped => {
|
||||
self.pre_text(diagnostics);
|
||||
println!();
|
||||
|
||||
// Group by filename.
|
||||
let mut grouped_messages = BTreeMap::default();
|
||||
for message in &diagnostics.messages {
|
||||
grouped_messages
|
||||
.entry(&message.filename)
|
||||
.or_insert_with(Vec::new)
|
||||
.push(message);
|
||||
}
|
||||
|
||||
for (filename, messages) in grouped_messages {
|
||||
// Compute the maximum number of digits in the row and column, for messages in
|
||||
// this file.
|
||||
let row_length = num_digits(
|
||||
messages
|
||||
.iter()
|
||||
.map(|message| message.location.row())
|
||||
.max()
|
||||
.unwrap(),
|
||||
);
|
||||
let column_length = num_digits(
|
||||
messages
|
||||
.iter()
|
||||
.map(|message| message.location.column())
|
||||
.max()
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
// Print the filename.
|
||||
println!("{}:", relativize_path(Path::new(&filename)).underline());
|
||||
|
||||
// Print each message.
|
||||
for message in messages {
|
||||
print_grouped_message(message, row_length, column_length);
|
||||
}
|
||||
println!();
|
||||
}
|
||||
|
||||
self.post_text(num_fixable);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +214,7 @@ impl<'a> Printer<'a> {
|
||||
println!();
|
||||
}
|
||||
for message in &diagnostics.messages {
|
||||
println!("{message}");
|
||||
print_message(message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,3 +227,107 @@ impl<'a> Printer<'a> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn num_digits(n: usize) -> usize {
|
||||
iterate(n, |&n| n / 10)
|
||||
.take_while(|&n| n > 0)
|
||||
.count()
|
||||
.max(1)
|
||||
}
|
||||
|
||||
/// Print a single `Message` with full details.
|
||||
fn print_message(message: &Message) {
|
||||
let label = format!(
|
||||
"{}{}{}{}{}{} {} {}",
|
||||
relativize_path(Path::new(&message.filename)).bold(),
|
||||
":".cyan(),
|
||||
message.location.row(),
|
||||
":".cyan(),
|
||||
message.location.column(),
|
||||
":".cyan(),
|
||||
message.kind.code().as_ref().red().bold(),
|
||||
message.kind.body(),
|
||||
);
|
||||
println!("{label}");
|
||||
if let Some(source) = &message.source {
|
||||
let snippet = Snippet {
|
||||
title: Some(Annotation {
|
||||
label: None,
|
||||
annotation_type: AnnotationType::Error,
|
||||
// The ID (error number) is already encoded in the `label`.
|
||||
id: None,
|
||||
}),
|
||||
footer: vec![],
|
||||
slices: vec![Slice {
|
||||
source: &source.contents,
|
||||
line_start: message.location.row(),
|
||||
annotations: vec![SourceAnnotation {
|
||||
label: message.kind.code().as_ref(),
|
||||
annotation_type: AnnotationType::Error,
|
||||
range: source.range,
|
||||
}],
|
||||
// The origin (file name, line number, and column number) is already encoded
|
||||
// in the `label`.
|
||||
origin: None,
|
||||
fold: false,
|
||||
}],
|
||||
opt: FormatOptions {
|
||||
color: true,
|
||||
..FormatOptions::default()
|
||||
},
|
||||
};
|
||||
// Skip the first line, since we format the `label` ourselves.
|
||||
let message = DisplayList::from(snippet).to_string();
|
||||
let (_, message) = message.split_once('\n').unwrap();
|
||||
println!("{message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Print a grouped `Message`, assumed to be printed in a group with others from
|
||||
/// the same file.
|
||||
fn print_grouped_message(message: &Message, row_length: usize, column_length: usize) {
|
||||
let label = format!(
|
||||
" {}{}{}{}{} {} {}",
|
||||
" ".repeat(row_length - num_digits(message.location.row())),
|
||||
message.location.row(),
|
||||
":".cyan(),
|
||||
message.location.column(),
|
||||
" ".repeat(column_length - num_digits(message.location.column())),
|
||||
message.kind.code().as_ref().red().bold(),
|
||||
message.kind.body(),
|
||||
);
|
||||
println!("{label}");
|
||||
if let Some(source) = &message.source {
|
||||
let snippet = Snippet {
|
||||
title: Some(Annotation {
|
||||
label: None,
|
||||
annotation_type: AnnotationType::Error,
|
||||
// The ID (error number) is already encoded in the `label`.
|
||||
id: None,
|
||||
}),
|
||||
footer: vec![],
|
||||
slices: vec![Slice {
|
||||
source: &source.contents,
|
||||
line_start: message.location.row(),
|
||||
annotations: vec![SourceAnnotation {
|
||||
label: message.kind.code().as_ref(),
|
||||
annotation_type: AnnotationType::Error,
|
||||
range: source.range,
|
||||
}],
|
||||
// The origin (file name, line number, and column number) is already encoded
|
||||
// in the `label`.
|
||||
origin: None,
|
||||
fold: false,
|
||||
}],
|
||||
opt: FormatOptions {
|
||||
color: true,
|
||||
..FormatOptions::default()
|
||||
},
|
||||
};
|
||||
// Skip the first line, since we format the `label` ourselves.
|
||||
let message = DisplayList::from(snippet).to_string();
|
||||
let (_, message) = message.split_once('\n').unwrap();
|
||||
let message = textwrap::indent(message, " ");
|
||||
println!("{message}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ use itertools::Itertools;
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use rustc_hash::FxHashSet;
|
||||
use rustpython_ast::{Arg, Constant, ExprKind, Location, StmtKind};
|
||||
use rustpython_ast::{Constant, ExprKind, Location, StmtKind};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::ast::whitespace;
|
||||
@@ -15,7 +15,7 @@ use crate::docstrings::constants;
|
||||
use crate::docstrings::definition::{Definition, DefinitionKind};
|
||||
use crate::docstrings::sections::{section_contexts, SectionContext};
|
||||
use crate::docstrings::styles::SectionStyle;
|
||||
use crate::visibility::{is_init, is_magic, is_overload, is_staticmethod, Visibility};
|
||||
use crate::visibility::{is_init, is_magic, is_overload, is_override, is_staticmethod, Visibility};
|
||||
|
||||
/// D100, D101, D102, D103, D104, D105, D106, D107
|
||||
pub fn not_missing(
|
||||
@@ -88,7 +88,7 @@ pub fn not_missing(
|
||||
}
|
||||
}
|
||||
DefinitionKind::Method(stmt) => {
|
||||
if is_overload(stmt) {
|
||||
if is_overload(stmt) || is_override(stmt) {
|
||||
true
|
||||
} else if is_magic(stmt) {
|
||||
if checker.settings.enabled.contains(&CheckCode::D105) {
|
||||
@@ -1303,8 +1303,9 @@ fn missing_args(checker: &mut Checker, definition: &Definition, docstrings_args:
|
||||
args: arguments, ..
|
||||
} = &parent.node
|
||||
{
|
||||
// Collect all the arguments into a single vector.
|
||||
let mut all_arguments: Vec<&Arg> = arguments
|
||||
// Look for arguments that weren't included in the docstring.
|
||||
let mut missing_arg_names: BTreeSet<String> = BTreeSet::default();
|
||||
for arg in arguments
|
||||
.args
|
||||
.iter()
|
||||
.chain(arguments.posonlyargs.iter())
|
||||
@@ -1316,33 +1317,38 @@ fn missing_args(checker: &mut Checker, definition: &Definition, docstrings_args:
|
||||
&& !is_staticmethod(parent),
|
||||
),
|
||||
)
|
||||
.collect();
|
||||
{
|
||||
let arg_name = arg.node.arg.as_str();
|
||||
if !arg_name.starts_with('_') && !docstrings_args.contains(&arg_name) {
|
||||
missing_arg_names.insert(arg_name.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
// Check specifically for `vararg` and `kwarg`, which can be prefixed with a
|
||||
// single or double star, respectively.
|
||||
if let Some(arg) = &arguments.vararg {
|
||||
all_arguments.push(arg);
|
||||
let arg_name = arg.node.arg.as_str();
|
||||
let starred_arg_name = format!("*{arg_name}");
|
||||
if !arg_name.starts_with('_')
|
||||
&& !docstrings_args.contains(&arg_name)
|
||||
&& !docstrings_args.contains(&starred_arg_name.as_str())
|
||||
{
|
||||
missing_arg_names.insert(starred_arg_name);
|
||||
}
|
||||
}
|
||||
if let Some(arg) = &arguments.kwarg {
|
||||
all_arguments.push(arg);
|
||||
}
|
||||
|
||||
// Look for arguments that weren't included in the docstring.
|
||||
let mut missing_args: BTreeSet<&str> = BTreeSet::default();
|
||||
for arg in all_arguments {
|
||||
let arg_name = arg.node.arg.as_str();
|
||||
if arg_name.starts_with('_') {
|
||||
continue;
|
||||
let starred_arg_name = format!("**{arg_name}");
|
||||
if !arg_name.starts_with('_')
|
||||
&& !docstrings_args.contains(&arg_name)
|
||||
&& !docstrings_args.contains(&starred_arg_name.as_str())
|
||||
{
|
||||
missing_arg_names.insert(starred_arg_name);
|
||||
}
|
||||
if docstrings_args.contains(&arg_name) {
|
||||
continue;
|
||||
}
|
||||
missing_args.insert(arg_name);
|
||||
}
|
||||
|
||||
if !missing_args.is_empty() {
|
||||
let names = missing_args
|
||||
.into_iter()
|
||||
.map(String::from)
|
||||
.sorted()
|
||||
.collect();
|
||||
if !missing_arg_names.is_empty() {
|
||||
let names = missing_arg_names.into_iter().sorted().collect();
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::DocumentAllArguments(names),
|
||||
Range::from_located(parent),
|
||||
@@ -1354,7 +1360,7 @@ fn missing_args(checker: &mut Checker, definition: &Definition, docstrings_args:
|
||||
|
||||
// See: `GOOGLE_ARGS_REGEX` in `pydocstyle/checker.py`.
|
||||
static GOOGLE_ARGS_REGEX: Lazy<Regex> =
|
||||
Lazy::new(|| Regex::new(r"^\s*(\w+)\s*(\(.*?\))?\s*:\n?\s*.+").expect("Invalid regex"));
|
||||
Lazy::new(|| Regex::new(r"^\s*(\w+)\s*(\(.*?\))?\s*:\n?\s*.+").unwrap());
|
||||
|
||||
fn args_section(checker: &mut Checker, definition: &Definition, context: &SectionContext) {
|
||||
let mut args_sections: Vec<String> = vec![];
|
||||
|
||||
102
src/pyflakes/cformat.rs
Normal file
102
src/pyflakes/cformat.rs
Normal file
@@ -0,0 +1,102 @@
|
||||
//! Implements helper functions for using vendored/cformat.rs
|
||||
use std::convert::TryFrom;
|
||||
use std::str::FromStr;
|
||||
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use crate::vendored::cformat::{
|
||||
CFormatError, CFormatPart, CFormatQuantity, CFormatSpec, CFormatString,
|
||||
};
|
||||
|
||||
pub(crate) struct CFormatSummary {
|
||||
pub starred: bool,
|
||||
pub num_positional: usize,
|
||||
pub keywords: FxHashSet<String>,
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for CFormatSummary {
|
||||
type Error = CFormatError;
|
||||
|
||||
fn try_from(literal: &str) -> Result<Self, Self::Error> {
|
||||
let format_string = CFormatString::from_str(literal)?;
|
||||
|
||||
let mut starred = false;
|
||||
let mut num_positional = 0;
|
||||
let mut keywords = FxHashSet::default();
|
||||
|
||||
for format_part in format_string.parts {
|
||||
if let CFormatPart::Spec(CFormatSpec {
|
||||
mapping_key,
|
||||
min_field_width,
|
||||
precision,
|
||||
..
|
||||
}) = format_part.1
|
||||
{
|
||||
match mapping_key {
|
||||
Some(k) => {
|
||||
keywords.insert(k);
|
||||
}
|
||||
None => {
|
||||
num_positional += 1;
|
||||
}
|
||||
};
|
||||
if min_field_width == Some(CFormatQuantity::FromValuesTuple) {
|
||||
num_positional += 1;
|
||||
starred = true;
|
||||
}
|
||||
if precision == Some(CFormatQuantity::FromValuesTuple) {
|
||||
num_positional += 1;
|
||||
starred = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(CFormatSummary {
|
||||
starred,
|
||||
num_positional,
|
||||
keywords,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_cformat_summary() {
|
||||
let literal = "%(foo)s %s %d %(bar)x";
|
||||
|
||||
let expected_positional = 2;
|
||||
let expected_keywords = ["foo", "bar"].into_iter().map(String::from).collect();
|
||||
|
||||
let format_summary = CFormatSummary::try_from(literal).unwrap();
|
||||
assert!(!format_summary.starred);
|
||||
assert_eq!(format_summary.num_positional, expected_positional);
|
||||
assert_eq!(format_summary.keywords, expected_keywords);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cformat_summary_starred() {
|
||||
let format_summary1 = CFormatSummary::try_from("%*s %*d").unwrap();
|
||||
assert!(format_summary1.starred);
|
||||
assert_eq!(format_summary1.num_positional, 4);
|
||||
|
||||
let format_summary2 = CFormatSummary::try_from("%s %.*d").unwrap();
|
||||
assert!(format_summary2.starred);
|
||||
assert_eq!(format_summary2.num_positional, 3);
|
||||
|
||||
let format_summary3 = CFormatSummary::try_from("%s %*.*d").unwrap();
|
||||
assert!(format_summary3.starred);
|
||||
assert_eq!(format_summary3.num_positional, 4);
|
||||
|
||||
let format_summary4 = CFormatSummary::try_from("%s %1d").unwrap();
|
||||
assert!(!format_summary4.starred);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cformat_summary_invalid() {
|
||||
assert!(CFormatSummary::try_from("%").is_err());
|
||||
assert!(CFormatSummary::try_from("%(foo).").is_err());
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ use rustpython_parser::ast::{
|
||||
|
||||
use crate::ast::types::{BindingKind, FunctionScope, Range, Scope, ScopeKind};
|
||||
use crate::checks::{Check, CheckKind};
|
||||
use crate::pyflakes::cformat::CFormatSummary;
|
||||
use crate::pyflakes::format::FormatSummary;
|
||||
|
||||
fn has_star_star_kwargs(keywords: &[Keyword]) -> bool {
|
||||
@@ -23,6 +24,216 @@ fn has_star_args(args: &[Expr]) -> bool {
|
||||
.any(|a| matches!(&a.node, ExprKind::Starred { .. }))
|
||||
}
|
||||
|
||||
/// F502
|
||||
pub(crate) fn percent_format_expected_mapping(
|
||||
summary: &CFormatSummary,
|
||||
right: &Expr,
|
||||
location: Range,
|
||||
) -> Option<Check> {
|
||||
if summary.keywords.is_empty() {
|
||||
None
|
||||
} else {
|
||||
// Tuple, List, Set (+comprehensions)
|
||||
match right.node {
|
||||
ExprKind::List { .. }
|
||||
| ExprKind::Tuple { .. }
|
||||
| ExprKind::Set { .. }
|
||||
| ExprKind::ListComp { .. }
|
||||
| ExprKind::SetComp { .. }
|
||||
| ExprKind::GeneratorExp { .. } => Some(Check::new(
|
||||
CheckKind::PercentFormatExpectedMapping,
|
||||
location,
|
||||
)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// F503
|
||||
pub(crate) fn percent_format_expected_sequence(
|
||||
summary: &CFormatSummary,
|
||||
right: &Expr,
|
||||
location: Range,
|
||||
) -> Option<Check> {
|
||||
if summary.num_positional <= 1 {
|
||||
None
|
||||
} else {
|
||||
match right.node {
|
||||
ExprKind::Dict { .. } | ExprKind::DictComp { .. } => Some(Check::new(
|
||||
CheckKind::PercentFormatExpectedSequence,
|
||||
location,
|
||||
)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// F504
|
||||
pub(crate) fn percent_format_extra_named_arguments(
|
||||
summary: &CFormatSummary,
|
||||
right: &Expr,
|
||||
location: Range,
|
||||
) -> Option<Check> {
|
||||
if summary.num_positional > 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
if let ExprKind::Dict { keys, values } = &right.node {
|
||||
if values.len() > keys.len() {
|
||||
return None; // contains **x splat
|
||||
}
|
||||
|
||||
let missing: Vec<&String> = keys
|
||||
.iter()
|
||||
.filter_map(|k| match &k.node {
|
||||
// We can only check that string literals exist
|
||||
ExprKind::Constant {
|
||||
value: Constant::Str(value),
|
||||
..
|
||||
} => {
|
||||
if summary.keywords.contains(value) {
|
||||
None
|
||||
} else {
|
||||
Some(value)
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
|
||||
if missing.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(Check::new(
|
||||
CheckKind::PercentFormatExtraNamedArguments(
|
||||
missing.iter().map(|&s| s.clone()).collect(),
|
||||
),
|
||||
location,
|
||||
))
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// F505
|
||||
pub(crate) fn percent_format_missing_arguments(
|
||||
summary: &CFormatSummary,
|
||||
right: &Expr,
|
||||
location: Range,
|
||||
) -> Option<Check> {
|
||||
if summary.num_positional > 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
if let ExprKind::Dict { keys, values } = &right.node {
|
||||
if values.len() > keys.len() {
|
||||
return None; // contains **x splat
|
||||
}
|
||||
|
||||
let mut keywords = FxHashSet::default();
|
||||
for key in keys {
|
||||
match &key.node {
|
||||
ExprKind::Constant {
|
||||
value: Constant::Str(value),
|
||||
..
|
||||
} => {
|
||||
keywords.insert(value);
|
||||
}
|
||||
_ => {
|
||||
return None; // Dynamic keys present
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let missing: Vec<&String> = summary
|
||||
.keywords
|
||||
.iter()
|
||||
.filter(|k| !keywords.contains(k))
|
||||
.collect();
|
||||
|
||||
if missing.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(Check::new(
|
||||
CheckKind::PercentFormatMissingArgument(
|
||||
missing.iter().map(|&s| s.clone()).collect(),
|
||||
),
|
||||
location,
|
||||
))
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// F506
|
||||
pub(crate) fn percent_format_mixed_positional_and_named(
|
||||
summary: &CFormatSummary,
|
||||
location: Range,
|
||||
) -> Option<Check> {
|
||||
if summary.num_positional == 0 || summary.keywords.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(Check::new(
|
||||
CheckKind::PercentFormatMixedPositionalAndNamed,
|
||||
location,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// F507
|
||||
pub(crate) fn percent_format_positional_count_mismatch(
|
||||
summary: &CFormatSummary,
|
||||
right: &Expr,
|
||||
location: Range,
|
||||
) -> Option<Check> {
|
||||
if !summary.keywords.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
match &right.node {
|
||||
ExprKind::List { elts, .. } | ExprKind::Tuple { elts, .. } | ExprKind::Set { elts, .. } => {
|
||||
let mut found = 0;
|
||||
for elt in elts {
|
||||
if let ExprKind::Starred { .. } = &elt.node {
|
||||
return None;
|
||||
}
|
||||
found += 1;
|
||||
}
|
||||
|
||||
if found == summary.num_positional {
|
||||
None
|
||||
} else {
|
||||
Some(Check::new(
|
||||
CheckKind::PercentFormatPositionalCountMismatch(summary.num_positional, found),
|
||||
location,
|
||||
))
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// F508
|
||||
pub(crate) fn percent_format_star_requires_sequence(
|
||||
summary: &CFormatSummary,
|
||||
right: &Expr,
|
||||
location: Range,
|
||||
) -> Option<Check> {
|
||||
if summary.starred {
|
||||
match &right.node {
|
||||
ExprKind::Dict { .. } | ExprKind::DictComp { .. } => Some(Check::new(
|
||||
CheckKind::PercentFormatStarRequiresSequence,
|
||||
location,
|
||||
)),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// F522
|
||||
pub(crate) fn string_dot_format_extra_named_arguments(
|
||||
summary: &FormatSummary,
|
||||
@@ -38,16 +249,17 @@ pub(crate) fn string_dot_format_extra_named_arguments(
|
||||
arg.as_ref()
|
||||
});
|
||||
|
||||
let missing: Vec<String> = keywords
|
||||
let missing: Vec<&String> = keywords
|
||||
.filter(|&k| !summary.keywords.contains(k))
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
if missing.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(Check::new(
|
||||
CheckKind::StringDotFormatExtraNamedArguments(missing),
|
||||
CheckKind::StringDotFormatExtraNamedArguments(
|
||||
missing.iter().map(|&s| s.clone()).collect(),
|
||||
),
|
||||
location,
|
||||
))
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use anyhow::Result;
|
||||
use libcst_native::{
|
||||
Codegen, CodegenState, CompOp, Comparison, ComparisonTarget, Expr, Expression, ImportNames,
|
||||
NameOrAttribute, SmallStatement, Statement,
|
||||
SmallStatement, Statement,
|
||||
};
|
||||
use rustpython_ast::Stmt;
|
||||
|
||||
@@ -14,7 +14,7 @@ use crate::source_code_locator::SourceCodeLocator;
|
||||
/// Generate a Fix to remove any unused imports from an `import` statement.
|
||||
pub fn remove_unused_imports(
|
||||
locator: &SourceCodeLocator,
|
||||
full_names: &[&str],
|
||||
unused_imports: &Vec<(&String, &Range)>,
|
||||
stmt: &Stmt,
|
||||
parent: Option<&Stmt>,
|
||||
deleted: &[&Stmt],
|
||||
@@ -22,106 +22,43 @@ pub fn remove_unused_imports(
|
||||
let module_text = locator.slice_source_code_range(&Range::from_located(stmt));
|
||||
let mut tree = match_module(&module_text)?;
|
||||
|
||||
let body = if let Some(Statement::Simple(body)) = tree.body.first_mut() {
|
||||
body
|
||||
} else {
|
||||
let Some(Statement::Simple(body)) = tree.body.first_mut() else {
|
||||
return Err(anyhow::anyhow!("Expected node to be: Statement::Simple"));
|
||||
};
|
||||
let body = if let Some(SmallStatement::Import(body)) = body.body.first_mut() {
|
||||
body
|
||||
} else {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Expected node to be: SmallStatement::ImportFrom"
|
||||
));
|
||||
};
|
||||
let aliases = &mut body.names;
|
||||
|
||||
// Preserve the trailing comma (or not) from the last entry.
|
||||
let trailing_comma = aliases.last().and_then(|alias| alias.comma.clone());
|
||||
|
||||
// Identify unused imports from within the `import`.
|
||||
let mut removable = vec![];
|
||||
for (index, alias) in aliases.iter().enumerate() {
|
||||
if full_names.contains(&compose_module_path(&alias.name).as_str()) {
|
||||
removable.push(index);
|
||||
}
|
||||
}
|
||||
// TODO(charlie): This is quadratic.
|
||||
for index in removable.iter().rev() {
|
||||
aliases.remove(*index);
|
||||
}
|
||||
|
||||
if let Some(alias) = aliases.last_mut() {
|
||||
alias.comma = trailing_comma;
|
||||
}
|
||||
|
||||
if aliases.is_empty() {
|
||||
helpers::remove_stmt(stmt, parent, deleted)
|
||||
} else {
|
||||
let mut state = CodegenState::default();
|
||||
tree.codegen(&mut state);
|
||||
|
||||
Ok(Fix::replacement(
|
||||
state.to_string(),
|
||||
stmt.location,
|
||||
stmt.end_location.unwrap(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate a Fix to remove any unused imports from an `import from` statement.
|
||||
pub fn remove_unused_import_froms(
|
||||
locator: &SourceCodeLocator,
|
||||
full_names: &[&str],
|
||||
stmt: &Stmt,
|
||||
parent: Option<&Stmt>,
|
||||
deleted: &[&Stmt],
|
||||
) -> Result<Fix> {
|
||||
let module_text = locator.slice_source_code_range(&Range::from_located(stmt));
|
||||
let mut tree = match_module(&module_text)?;
|
||||
|
||||
let body = if let Some(Statement::Simple(body)) = tree.body.first_mut() {
|
||||
body
|
||||
} else {
|
||||
return Err(anyhow::anyhow!("Expected node to be: Statement::Simple"));
|
||||
};
|
||||
let body = if let Some(SmallStatement::ImportFrom(body)) = body.body.first_mut() {
|
||||
body
|
||||
} else {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Expected node to be: SmallStatement::ImportFrom"
|
||||
));
|
||||
};
|
||||
|
||||
let aliases = if let ImportNames::Aliases(aliases) = &mut body.names {
|
||||
aliases
|
||||
} else {
|
||||
return Err(anyhow::anyhow!("Expected node to be: Aliases"));
|
||||
};
|
||||
|
||||
// Preserve the trailing comma (or not) from the last entry.
|
||||
let trailing_comma = aliases.last().and_then(|alias| alias.comma.clone());
|
||||
|
||||
// Identify unused imports from within the `import from`.
|
||||
let mut removable = vec![];
|
||||
for (index, alias) in aliases.iter().enumerate() {
|
||||
if let NameOrAttribute::N(name) = &alias.name {
|
||||
let import_name = name.value.to_string();
|
||||
let full_name = body
|
||||
.module
|
||||
.as_ref()
|
||||
.map(compose_module_path)
|
||||
.map(|module_name| format!("{module_name}.{import_name}"))
|
||||
.unwrap_or(import_name);
|
||||
|
||||
if full_names.contains(&full_name.as_str()) {
|
||||
removable.push(index);
|
||||
let (aliases, import_module) = match body.body.first_mut() {
|
||||
Some(SmallStatement::Import(import_body)) => Ok((&mut import_body.names, None)),
|
||||
Some(SmallStatement::ImportFrom(import_body)) => {
|
||||
if let ImportNames::Aliases(names) = &mut import_body.names {
|
||||
Ok((names, import_body.module.as_ref()))
|
||||
} else {
|
||||
Err(anyhow::anyhow!("Expected node to be: Aliases"))
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO(charlie): This is quadratic.
|
||||
for index in removable.iter().rev() {
|
||||
aliases.remove(*index);
|
||||
_ => Err(anyhow::anyhow!(
|
||||
"Expected node to be: SmallStatement::ImportFrom or SmallStatement::Import"
|
||||
)),
|
||||
}?;
|
||||
|
||||
// Preserve the trailing comma (or not) from the last entry.
|
||||
let trailing_comma = aliases.last().and_then(|alias| alias.comma.clone());
|
||||
|
||||
for (name_to_remove, _) in unused_imports {
|
||||
let alias_index = aliases.iter().position(|alias| {
|
||||
let full_name = match import_module {
|
||||
Some(module_name) => format!(
|
||||
"{}.{}",
|
||||
compose_module_path(module_name),
|
||||
compose_module_path(&alias.name)
|
||||
),
|
||||
None => compose_module_path(&alias.name),
|
||||
};
|
||||
&full_name.as_str() == name_to_remove
|
||||
});
|
||||
|
||||
if let Some(index) = alias_index {
|
||||
aliases.remove(index);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(alias) = aliases.last_mut() {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod cformat;
|
||||
pub mod checks;
|
||||
pub mod fixes;
|
||||
pub mod format;
|
||||
|
||||
@@ -111,10 +111,7 @@ pub fn remove_super_arguments(locator: &SourceCodeLocator, expr: &Expr) -> Optio
|
||||
let range = Range::from_located(expr);
|
||||
let contents = locator.slice_source_code_range(&range);
|
||||
|
||||
let mut tree = match libcst_native::parse_module(&contents, None) {
|
||||
Ok(m) => m,
|
||||
Err(_) => return None,
|
||||
};
|
||||
let mut tree = libcst_native::parse_module(&contents, None).ok()?;
|
||||
|
||||
if let Some(Statement::Simple(body)) = tree.body.first_mut() {
|
||||
if let Some(SmallStatement::Expr(body)) = body.body.first_mut() {
|
||||
@@ -150,22 +147,16 @@ pub fn remove_unnecessary_future_import(
|
||||
let module_text = locator.slice_source_code_range(&Range::from_located(stmt));
|
||||
let mut tree = match_module(&module_text)?;
|
||||
|
||||
let body = if let Some(Statement::Simple(body)) = tree.body.first_mut() {
|
||||
body
|
||||
} else {
|
||||
let Some(Statement::Simple(body)) = tree.body.first_mut() else {
|
||||
return Err(anyhow::anyhow!("Expected node to be: Statement::Simple"));
|
||||
};
|
||||
let body = if let Some(SmallStatement::ImportFrom(body)) = body.body.first_mut() {
|
||||
body
|
||||
} else {
|
||||
let Some(SmallStatement::ImportFrom(body)) = body.body.first_mut() else {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Expected node to be: SmallStatement::ImportFrom"
|
||||
));
|
||||
};
|
||||
|
||||
let aliases = if let ImportNames::Aliases(aliases) = &mut body.names {
|
||||
aliases
|
||||
} else {
|
||||
let ImportNames::Aliases(aliases) = &mut body.names else {
|
||||
return Err(anyhow::anyhow!("Expected node to be: Aliases"));
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
mod checks;
|
||||
pub mod fixes;
|
||||
pub mod plugins;
|
||||
pub mod settings;
|
||||
pub mod types;
|
||||
|
||||
@@ -64,7 +64,6 @@ fn match_open(expr: &Expr) -> (Option<&Expr>, Vec<Keyword>) {
|
||||
keywords,
|
||||
} = &expr.node
|
||||
{
|
||||
// TODO(andberger): Verify that "open" is still bound to the built-in function.
|
||||
if match_name_or_attr(func, OPEN_FUNC_NAME) {
|
||||
// Return the "open mode" parameter and keywords.
|
||||
return (args.get(1), keywords.clone());
|
||||
@@ -149,6 +148,10 @@ fn create_remove_param_fix(
|
||||
|
||||
/// U015
|
||||
pub fn redundant_open_modes(checker: &mut Checker, expr: &Expr) {
|
||||
// If `open` has been rebound, skip this check entirely.
|
||||
if !checker.is_builtin(OPEN_FUNC_NAME) {
|
||||
return;
|
||||
}
|
||||
let (mode_param, keywords): (Option<&Expr>, Vec<Keyword>) = match_open(expr);
|
||||
if mode_param.is_none() && !keywords.is_empty() {
|
||||
if let Some(value) = keywords.iter().find_map(|keyword| {
|
||||
|
||||
22
src/pyupgrade/settings.rs
Normal file
22
src/pyupgrade/settings.rs
Normal file
@@ -0,0 +1,22 @@
|
||||
//! Settings for the `pyupgrade` plugin.
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
|
||||
pub struct Options {
|
||||
pub keep_runtime_typing: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Hash, Default)]
|
||||
pub struct Settings {
|
||||
pub keep_runtime_typing: bool,
|
||||
}
|
||||
|
||||
impl Settings {
|
||||
pub fn from_options(options: &Options) -> Self {
|
||||
Self {
|
||||
keep_runtime_typing: options.keep_runtime_typing.unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,10 +11,10 @@ use regex::Regex;
|
||||
|
||||
use crate::checks_gen::{CheckCodePrefix, CATEGORIES};
|
||||
use crate::settings::pyproject::load_options;
|
||||
use crate::settings::types::{FilePattern, PerFileIgnore, PythonVersion};
|
||||
use crate::settings::types::{FilePattern, PerFileIgnore, PythonVersion, SerializationFormat};
|
||||
use crate::{
|
||||
flake8_annotations, flake8_bugbear, flake8_quotes, flake8_tidy_imports, fs, isort, mccabe,
|
||||
pep8_naming,
|
||||
pep8_naming, pyupgrade,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -24,8 +24,10 @@ pub struct Configuration {
|
||||
pub extend_exclude: Vec<FilePattern>,
|
||||
pub extend_ignore: Vec<CheckCodePrefix>,
|
||||
pub extend_select: Vec<CheckCodePrefix>,
|
||||
pub external: Vec<String>,
|
||||
pub fix: bool,
|
||||
pub fixable: Vec<CheckCodePrefix>,
|
||||
pub format: SerializationFormat,
|
||||
pub ignore: Vec<CheckCodePrefix>,
|
||||
pub line_length: usize,
|
||||
pub per_file_ignores: Vec<PerFileIgnore>,
|
||||
@@ -42,6 +44,7 @@ pub struct Configuration {
|
||||
pub isort: isort::settings::Settings,
|
||||
pub mccabe: mccabe::settings::Settings,
|
||||
pub pep8_naming: pep8_naming::settings::Settings,
|
||||
pub pyupgrade: pyupgrade::settings::Settings,
|
||||
}
|
||||
|
||||
static DEFAULT_EXCLUDE: Lazy<Vec<FilePattern>> = Lazy::new(|| {
|
||||
@@ -116,9 +119,11 @@ impl Configuration {
|
||||
.select
|
||||
.unwrap_or_else(|| vec![CheckCodePrefix::E, CheckCodePrefix::F]),
|
||||
extend_select: options.extend_select.unwrap_or_default(),
|
||||
external: options.external.unwrap_or_default(),
|
||||
fix: options.fix.unwrap_or_default(),
|
||||
fixable: options.fixable.unwrap_or_else(|| CATEGORIES.to_vec()),
|
||||
unfixable: options.unfixable.unwrap_or_default(),
|
||||
format: options.format.unwrap_or(SerializationFormat::Text),
|
||||
ignore: options.ignore.unwrap_or_default(),
|
||||
line_length: options.line_length.unwrap_or(88),
|
||||
per_file_ignores: options
|
||||
@@ -160,6 +165,11 @@ impl Configuration {
|
||||
.pep8_naming
|
||||
.map(pep8_naming::settings::Settings::from_options)
|
||||
.unwrap_or_default(),
|
||||
pyupgrade: options
|
||||
.pyupgrade
|
||||
.as_ref()
|
||||
.map(pyupgrade::settings::Settings::from_options)
|
||||
.unwrap_or_default(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,10 +15,10 @@ use rustc_hash::FxHashSet;
|
||||
use crate::checks::CheckCode;
|
||||
use crate::checks_gen::{CheckCodePrefix, PrefixSpecificity};
|
||||
use crate::settings::configuration::Configuration;
|
||||
use crate::settings::types::{FilePattern, PerFileIgnore, PythonVersion};
|
||||
use crate::settings::types::{FilePattern, PerFileIgnore, PythonVersion, SerializationFormat};
|
||||
use crate::{
|
||||
flake8_annotations, flake8_bugbear, flake8_quotes, flake8_tidy_imports, fs, isort, mccabe,
|
||||
pep8_naming,
|
||||
pep8_naming, pyupgrade,
|
||||
};
|
||||
|
||||
pub mod configuration;
|
||||
@@ -32,7 +32,9 @@ pub struct Settings {
|
||||
pub enabled: FxHashSet<CheckCode>,
|
||||
pub exclude: GlobSet,
|
||||
pub extend_exclude: GlobSet,
|
||||
pub external: BTreeSet<String>,
|
||||
pub fixable: FxHashSet<CheckCode>,
|
||||
pub format: SerializationFormat,
|
||||
pub line_length: usize,
|
||||
pub per_file_ignores: Vec<(GlobMatcher, GlobMatcher, BTreeSet<CheckCode>)>,
|
||||
pub show_source: bool,
|
||||
@@ -46,6 +48,7 @@ pub struct Settings {
|
||||
pub isort: isort::settings::Settings,
|
||||
pub mccabe: mccabe::settings::Settings,
|
||||
pub pep8_naming: pep8_naming::settings::Settings,
|
||||
pub pyupgrade: pyupgrade::settings::Settings,
|
||||
}
|
||||
|
||||
impl Settings {
|
||||
@@ -69,7 +72,9 @@ impl Settings {
|
||||
),
|
||||
exclude: resolve_globset(config.exclude, project_root)?,
|
||||
extend_exclude: resolve_globset(config.extend_exclude, project_root)?,
|
||||
external: BTreeSet::from_iter(config.external),
|
||||
fixable: resolve_codes(&config.fixable, &config.unfixable),
|
||||
format: config.format,
|
||||
flake8_annotations: config.flake8_annotations,
|
||||
flake8_bugbear: config.flake8_bugbear,
|
||||
flake8_quotes: config.flake8_quotes,
|
||||
@@ -78,6 +83,7 @@ impl Settings {
|
||||
mccabe: config.mccabe,
|
||||
line_length: config.line_length,
|
||||
pep8_naming: config.pep8_naming,
|
||||
pyupgrade: config.pyupgrade,
|
||||
per_file_ignores: resolve_per_file_ignores(config.per_file_ignores, project_root)?,
|
||||
src: config.src,
|
||||
target_version: config.target_version,
|
||||
@@ -89,11 +95,14 @@ impl Settings {
|
||||
Self {
|
||||
dummy_variable_rgx: Regex::new("^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$").unwrap(),
|
||||
enabled: FxHashSet::from_iter([check_code.clone()]),
|
||||
fixable: FxHashSet::from_iter([check_code]),
|
||||
exclude: GlobSet::empty(),
|
||||
extend_exclude: GlobSet::empty(),
|
||||
external: BTreeSet::default(),
|
||||
fixable: FxHashSet::from_iter([check_code]),
|
||||
format: SerializationFormat::Text,
|
||||
line_length: 88,
|
||||
per_file_ignores: vec![],
|
||||
show_source: false,
|
||||
src: vec![path_dedot::CWD.clone()],
|
||||
target_version: PythonVersion::Py310,
|
||||
flake8_annotations: flake8_annotations::settings::Settings::default(),
|
||||
@@ -103,7 +112,7 @@ impl Settings {
|
||||
isort: isort::settings::Settings::default(),
|
||||
mccabe: mccabe::settings::Settings::default(),
|
||||
pep8_naming: pep8_naming::settings::Settings::default(),
|
||||
show_source: false,
|
||||
pyupgrade: pyupgrade::settings::Settings::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,11 +120,14 @@ impl Settings {
|
||||
Self {
|
||||
dummy_variable_rgx: Regex::new("^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$").unwrap(),
|
||||
enabled: FxHashSet::from_iter(check_codes.clone()),
|
||||
fixable: FxHashSet::from_iter(check_codes),
|
||||
exclude: GlobSet::empty(),
|
||||
extend_exclude: GlobSet::empty(),
|
||||
external: BTreeSet::default(),
|
||||
fixable: FxHashSet::from_iter(check_codes),
|
||||
format: SerializationFormat::Text,
|
||||
line_length: 88,
|
||||
per_file_ignores: vec![],
|
||||
show_source: false,
|
||||
src: vec![path_dedot::CWD.clone()],
|
||||
target_version: PythonVersion::Py310,
|
||||
flake8_annotations: flake8_annotations::settings::Settings::default(),
|
||||
@@ -125,7 +137,7 @@ impl Settings {
|
||||
isort: isort::settings::Settings::default(),
|
||||
mccabe: mccabe::settings::Settings::default(),
|
||||
pep8_naming: pep8_naming::settings::Settings::default(),
|
||||
show_source: false,
|
||||
pyupgrade: pyupgrade::settings::Settings::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -137,6 +149,7 @@ impl Hash for Settings {
|
||||
for value in &self.enabled {
|
||||
value.hash(state);
|
||||
}
|
||||
self.external.hash(state);
|
||||
for value in &self.fixable {
|
||||
value.hash(state);
|
||||
}
|
||||
@@ -156,6 +169,7 @@ impl Hash for Settings {
|
||||
self.isort.hash(state);
|
||||
self.mccabe.hash(state);
|
||||
self.pep8_naming.hash(state);
|
||||
self.pyupgrade.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,10 +4,10 @@ use rustc_hash::FxHashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::checks_gen::CheckCodePrefix;
|
||||
use crate::settings::types::PythonVersion;
|
||||
use crate::settings::types::{PythonVersion, SerializationFormat};
|
||||
use crate::{
|
||||
flake8_annotations, flake8_bugbear, flake8_quotes, flake8_tidy_imports, isort, mccabe,
|
||||
pep8_naming,
|
||||
pep8_naming, pyupgrade,
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
@@ -18,8 +18,10 @@ pub struct Options {
|
||||
pub extend_exclude: Option<Vec<String>>,
|
||||
pub extend_ignore: Option<Vec<CheckCodePrefix>>,
|
||||
pub extend_select: Option<Vec<CheckCodePrefix>>,
|
||||
pub external: Option<Vec<String>>,
|
||||
pub fix: Option<bool>,
|
||||
pub fixable: Option<Vec<CheckCodePrefix>>,
|
||||
pub format: Option<SerializationFormat>,
|
||||
pub ignore: Option<Vec<CheckCodePrefix>>,
|
||||
pub line_length: Option<usize>,
|
||||
pub select: Option<Vec<CheckCodePrefix>>,
|
||||
@@ -35,6 +37,7 @@ pub struct Options {
|
||||
pub isort: Option<isort::settings::Options>,
|
||||
pub mccabe: Option<mccabe::settings::Options>,
|
||||
pub pep8_naming: Option<pep8_naming::settings::Options>,
|
||||
pub pyupgrade: Option<pyupgrade::settings::Options>,
|
||||
// Tables are required to go last.
|
||||
pub per_file_ignores: Option<FxHashMap<String, Vec<CheckCodePrefix>>>,
|
||||
}
|
||||
|
||||
@@ -138,6 +138,7 @@ mod tests {
|
||||
extend_exclude: None,
|
||||
extend_ignore: None,
|
||||
extend_select: None,
|
||||
external: None,
|
||||
fix: None,
|
||||
fixable: None,
|
||||
ignore: None,
|
||||
@@ -147,6 +148,7 @@ mod tests {
|
||||
show_source: None,
|
||||
src: None,
|
||||
target_version: None,
|
||||
format: None,
|
||||
unfixable: None,
|
||||
flake8_annotations: None,
|
||||
flake8_bugbear: None,
|
||||
@@ -155,6 +157,7 @@ mod tests {
|
||||
isort: None,
|
||||
mccabe: None,
|
||||
pep8_naming: None,
|
||||
pyupgrade: None,
|
||||
})
|
||||
})
|
||||
);
|
||||
@@ -175,6 +178,7 @@ line-length = 79
|
||||
extend_exclude: None,
|
||||
extend_ignore: None,
|
||||
extend_select: None,
|
||||
external: None,
|
||||
fix: None,
|
||||
fixable: None,
|
||||
ignore: None,
|
||||
@@ -184,6 +188,7 @@ line-length = 79
|
||||
show_source: None,
|
||||
src: None,
|
||||
target_version: None,
|
||||
format: None,
|
||||
unfixable: None,
|
||||
flake8_annotations: None,
|
||||
flake8_bugbear: None,
|
||||
@@ -192,6 +197,7 @@ line-length = 79
|
||||
isort: None,
|
||||
mccabe: None,
|
||||
pep8_naming: None,
|
||||
pyupgrade: None,
|
||||
})
|
||||
})
|
||||
);
|
||||
@@ -213,9 +219,11 @@ exclude = ["foo.py"]
|
||||
extend_exclude: None,
|
||||
select: None,
|
||||
extend_select: None,
|
||||
external: None,
|
||||
ignore: None,
|
||||
extend_ignore: None,
|
||||
fixable: None,
|
||||
format: None,
|
||||
unfixable: None,
|
||||
per_file_ignores: None,
|
||||
dummy_variable_rgx: None,
|
||||
@@ -229,6 +237,7 @@ exclude = ["foo.py"]
|
||||
isort: None,
|
||||
mccabe: None,
|
||||
pep8_naming: None,
|
||||
pyupgrade: None,
|
||||
})
|
||||
})
|
||||
);
|
||||
@@ -249,6 +258,7 @@ select = ["E501"]
|
||||
extend_exclude: None,
|
||||
extend_ignore: None,
|
||||
extend_select: None,
|
||||
external: None,
|
||||
fix: None,
|
||||
fixable: None,
|
||||
ignore: None,
|
||||
@@ -258,6 +268,7 @@ select = ["E501"]
|
||||
show_source: None,
|
||||
src: None,
|
||||
target_version: None,
|
||||
format: None,
|
||||
unfixable: None,
|
||||
flake8_annotations: None,
|
||||
flake8_bugbear: None,
|
||||
@@ -266,6 +277,7 @@ select = ["E501"]
|
||||
isort: None,
|
||||
mccabe: None,
|
||||
pep8_naming: None,
|
||||
pyupgrade: None,
|
||||
})
|
||||
})
|
||||
);
|
||||
@@ -287,6 +299,7 @@ ignore = ["E501"]
|
||||
extend_exclude: None,
|
||||
extend_ignore: None,
|
||||
extend_select: Some(vec![CheckCodePrefix::M001]),
|
||||
external: None,
|
||||
fix: None,
|
||||
fixable: None,
|
||||
ignore: Some(vec![CheckCodePrefix::E501]),
|
||||
@@ -296,6 +309,7 @@ ignore = ["E501"]
|
||||
show_source: None,
|
||||
src: None,
|
||||
target_version: None,
|
||||
format: None,
|
||||
unfixable: None,
|
||||
flake8_annotations: None,
|
||||
flake8_bugbear: None,
|
||||
@@ -304,6 +318,7 @@ ignore = ["E501"]
|
||||
isort: None,
|
||||
mccabe: None,
|
||||
pep8_naming: None,
|
||||
pyupgrade: None,
|
||||
})
|
||||
})
|
||||
);
|
||||
@@ -369,9 +384,11 @@ other-attribute = 1
|
||||
]),
|
||||
select: None,
|
||||
extend_select: None,
|
||||
external: Some(vec!["V101".to_string()]),
|
||||
ignore: None,
|
||||
extend_ignore: None,
|
||||
fixable: None,
|
||||
format: None,
|
||||
unfixable: None,
|
||||
per_file_ignores: Some(FxHashMap::from_iter([(
|
||||
"__init__.py".to_string(),
|
||||
@@ -422,6 +439,7 @@ other-attribute = 1
|
||||
]),
|
||||
staticmethod_decorators: Some(vec!["staticmethod".to_string()]),
|
||||
}),
|
||||
pyupgrade: None,
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use clap::ValueEnum;
|
||||
use globset::{Glob, GlobSetBuilder};
|
||||
use serde::{de, Deserialize, Deserializer, Serialize};
|
||||
|
||||
@@ -141,3 +142,12 @@ impl FromStr for PatternPrefixPair {
|
||||
Ok(Self { pattern, prefix })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, ValueEnum, PartialEq, Eq, Serialize, Deserialize, Debug)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub enum SerializationFormat {
|
||||
Text,
|
||||
Json,
|
||||
Junit,
|
||||
Grouped,
|
||||
}
|
||||
|
||||
@@ -4,10 +4,10 @@ expression: checks
|
||||
---
|
||||
- kind: PublicClass
|
||||
location:
|
||||
row: 14
|
||||
row: 15
|
||||
column: 0
|
||||
end_location:
|
||||
row: 67
|
||||
row: 72
|
||||
column: 0
|
||||
fix: ~
|
||||
|
||||
|
||||
@@ -4,26 +4,26 @@ expression: checks
|
||||
---
|
||||
- kind: PublicMethod
|
||||
location:
|
||||
row: 22
|
||||
row: 23
|
||||
column: 4
|
||||
end_location:
|
||||
row: 25
|
||||
row: 26
|
||||
column: 4
|
||||
fix: ~
|
||||
- kind: PublicMethod
|
||||
location:
|
||||
row: 51
|
||||
row: 56
|
||||
column: 4
|
||||
end_location:
|
||||
row: 54
|
||||
row: 59
|
||||
column: 4
|
||||
fix: ~
|
||||
- kind: PublicMethod
|
||||
location:
|
||||
row: 63
|
||||
row: 68
|
||||
column: 4
|
||||
end_location:
|
||||
row: 67
|
||||
row: 72
|
||||
column: 0
|
||||
fix: ~
|
||||
|
||||
|
||||
@@ -4,10 +4,10 @@ expression: checks
|
||||
---
|
||||
- kind: PublicFunction
|
||||
location:
|
||||
row: 395
|
||||
row: 400
|
||||
column: 0
|
||||
end_location:
|
||||
row: 396
|
||||
row: 401
|
||||
column: 0
|
||||
fix: ~
|
||||
|
||||
|
||||
@@ -4,10 +4,10 @@ expression: checks
|
||||
---
|
||||
- kind: MagicMethod
|
||||
location:
|
||||
row: 59
|
||||
row: 64
|
||||
column: 4
|
||||
end_location:
|
||||
row: 62
|
||||
row: 67
|
||||
column: 4
|
||||
fix: ~
|
||||
|
||||
|
||||
@@ -4,18 +4,18 @@ expression: checks
|
||||
---
|
||||
- kind: PublicInit
|
||||
location:
|
||||
row: 55
|
||||
row: 60
|
||||
column: 4
|
||||
end_location:
|
||||
row: 58
|
||||
row: 63
|
||||
column: 4
|
||||
fix: ~
|
||||
- kind: PublicInit
|
||||
location:
|
||||
row: 529
|
||||
row: 534
|
||||
column: 4
|
||||
end_location:
|
||||
row: 533
|
||||
row: 538
|
||||
column: 0
|
||||
fix: ~
|
||||
|
||||
|
||||
@@ -5,69 +5,69 @@ expression: checks
|
||||
- kind:
|
||||
NoBlankLineBeforeFunction: 1
|
||||
location:
|
||||
row: 132
|
||||
row: 137
|
||||
column: 4
|
||||
end_location:
|
||||
row: 132
|
||||
row: 137
|
||||
column: 24
|
||||
fix:
|
||||
patch:
|
||||
content: ""
|
||||
location:
|
||||
row: 131
|
||||
row: 136
|
||||
column: 0
|
||||
end_location:
|
||||
row: 132
|
||||
row: 137
|
||||
column: 0
|
||||
- kind:
|
||||
NoBlankLineBeforeFunction: 1
|
||||
location:
|
||||
row: 146
|
||||
row: 151
|
||||
column: 4
|
||||
end_location:
|
||||
row: 146
|
||||
row: 151
|
||||
column: 37
|
||||
fix:
|
||||
patch:
|
||||
content: ""
|
||||
location:
|
||||
row: 145
|
||||
row: 150
|
||||
column: 0
|
||||
end_location:
|
||||
row: 146
|
||||
row: 151
|
||||
column: 0
|
||||
- kind:
|
||||
NoBlankLineBeforeFunction: 1
|
||||
location:
|
||||
row: 541
|
||||
row: 546
|
||||
column: 4
|
||||
end_location:
|
||||
row: 544
|
||||
row: 549
|
||||
column: 7
|
||||
fix:
|
||||
patch:
|
||||
content: ""
|
||||
location:
|
||||
row: 540
|
||||
row: 545
|
||||
column: 0
|
||||
end_location:
|
||||
row: 541
|
||||
row: 546
|
||||
column: 0
|
||||
- kind:
|
||||
NoBlankLineBeforeFunction: 1
|
||||
location:
|
||||
row: 563
|
||||
row: 568
|
||||
column: 4
|
||||
end_location:
|
||||
row: 566
|
||||
row: 571
|
||||
column: 7
|
||||
fix:
|
||||
patch:
|
||||
content: ""
|
||||
location:
|
||||
row: 562
|
||||
row: 567
|
||||
column: 0
|
||||
end_location:
|
||||
row: 563
|
||||
row: 568
|
||||
column: 0
|
||||
|
||||
|
||||
@@ -5,69 +5,69 @@ expression: checks
|
||||
- kind:
|
||||
NoBlankLineAfterFunction: 1
|
||||
location:
|
||||
row: 137
|
||||
row: 142
|
||||
column: 4
|
||||
end_location:
|
||||
row: 137
|
||||
row: 142
|
||||
column: 24
|
||||
fix:
|
||||
patch:
|
||||
content: ""
|
||||
location:
|
||||
row: 138
|
||||
row: 143
|
||||
column: 0
|
||||
end_location:
|
||||
row: 139
|
||||
row: 144
|
||||
column: 0
|
||||
- kind:
|
||||
NoBlankLineAfterFunction: 1
|
||||
location:
|
||||
row: 146
|
||||
row: 151
|
||||
column: 4
|
||||
end_location:
|
||||
row: 146
|
||||
row: 151
|
||||
column: 37
|
||||
fix:
|
||||
patch:
|
||||
content: ""
|
||||
location:
|
||||
row: 147
|
||||
row: 152
|
||||
column: 0
|
||||
end_location:
|
||||
row: 148
|
||||
row: 153
|
||||
column: 0
|
||||
- kind:
|
||||
NoBlankLineAfterFunction: 1
|
||||
location:
|
||||
row: 550
|
||||
row: 555
|
||||
column: 4
|
||||
end_location:
|
||||
row: 553
|
||||
row: 558
|
||||
column: 7
|
||||
fix:
|
||||
patch:
|
||||
content: ""
|
||||
location:
|
||||
row: 554
|
||||
row: 559
|
||||
column: 0
|
||||
end_location:
|
||||
row: 555
|
||||
row: 560
|
||||
column: 0
|
||||
- kind:
|
||||
NoBlankLineAfterFunction: 1
|
||||
location:
|
||||
row: 563
|
||||
row: 568
|
||||
column: 4
|
||||
end_location:
|
||||
row: 566
|
||||
row: 571
|
||||
column: 7
|
||||
fix:
|
||||
patch:
|
||||
content: ""
|
||||
location:
|
||||
row: 567
|
||||
row: 572
|
||||
column: 0
|
||||
end_location:
|
||||
row: 568
|
||||
row: 573
|
||||
column: 0
|
||||
|
||||
|
||||
@@ -5,52 +5,52 @@ expression: checks
|
||||
- kind:
|
||||
OneBlankLineBeforeClass: 0
|
||||
location:
|
||||
row: 156
|
||||
row: 161
|
||||
column: 4
|
||||
end_location:
|
||||
row: 156
|
||||
row: 161
|
||||
column: 32
|
||||
fix:
|
||||
patch:
|
||||
content: "\n"
|
||||
location:
|
||||
row: 156
|
||||
row: 161
|
||||
column: 0
|
||||
end_location:
|
||||
row: 156
|
||||
row: 161
|
||||
column: 0
|
||||
- kind:
|
||||
OneBlankLineBeforeClass: 0
|
||||
location:
|
||||
row: 187
|
||||
row: 192
|
||||
column: 4
|
||||
end_location:
|
||||
row: 187
|
||||
row: 192
|
||||
column: 45
|
||||
fix:
|
||||
patch:
|
||||
content: "\n"
|
||||
location:
|
||||
row: 187
|
||||
row: 192
|
||||
column: 0
|
||||
end_location:
|
||||
row: 187
|
||||
row: 192
|
||||
column: 0
|
||||
- kind:
|
||||
OneBlankLineBeforeClass: 0
|
||||
location:
|
||||
row: 521
|
||||
row: 526
|
||||
column: 4
|
||||
end_location:
|
||||
row: 527
|
||||
row: 532
|
||||
column: 7
|
||||
fix:
|
||||
patch:
|
||||
content: "\n"
|
||||
location:
|
||||
row: 521
|
||||
row: 526
|
||||
column: 0
|
||||
end_location:
|
||||
row: 521
|
||||
row: 526
|
||||
column: 0
|
||||
|
||||
|
||||
@@ -5,35 +5,35 @@ expression: checks
|
||||
- kind:
|
||||
OneBlankLineAfterClass: 0
|
||||
location:
|
||||
row: 176
|
||||
row: 181
|
||||
column: 4
|
||||
end_location:
|
||||
row: 176
|
||||
row: 181
|
||||
column: 24
|
||||
fix:
|
||||
patch:
|
||||
content: "\n"
|
||||
location:
|
||||
row: 177
|
||||
row: 182
|
||||
column: 0
|
||||
end_location:
|
||||
row: 177
|
||||
row: 182
|
||||
column: 0
|
||||
- kind:
|
||||
OneBlankLineAfterClass: 0
|
||||
location:
|
||||
row: 187
|
||||
row: 192
|
||||
column: 4
|
||||
end_location:
|
||||
row: 187
|
||||
row: 192
|
||||
column: 45
|
||||
fix:
|
||||
patch:
|
||||
content: "\n"
|
||||
location:
|
||||
row: 188
|
||||
row: 193
|
||||
column: 0
|
||||
end_location:
|
||||
row: 188
|
||||
row: 193
|
||||
column: 0
|
||||
|
||||
|
||||
@@ -4,34 +4,34 @@ expression: checks
|
||||
---
|
||||
- kind: BlankLineAfterSummary
|
||||
location:
|
||||
row: 195
|
||||
row: 200
|
||||
column: 4
|
||||
end_location:
|
||||
row: 198
|
||||
row: 203
|
||||
column: 7
|
||||
fix:
|
||||
patch:
|
||||
content: "\n"
|
||||
location:
|
||||
row: 196
|
||||
row: 201
|
||||
column: 0
|
||||
end_location:
|
||||
row: 196
|
||||
row: 201
|
||||
column: 0
|
||||
- kind: BlankLineAfterSummary
|
||||
location:
|
||||
row: 205
|
||||
row: 210
|
||||
column: 4
|
||||
end_location:
|
||||
row: 210
|
||||
row: 215
|
||||
column: 7
|
||||
fix:
|
||||
patch:
|
||||
content: "\n"
|
||||
location:
|
||||
row: 206
|
||||
row: 211
|
||||
column: 0
|
||||
end_location:
|
||||
row: 208
|
||||
row: 213
|
||||
column: 0
|
||||
|
||||
|
||||
@@ -4,34 +4,34 @@ expression: checks
|
||||
---
|
||||
- kind: NoUnderIndentation
|
||||
location:
|
||||
row: 227
|
||||
row: 232
|
||||
column: 0
|
||||
end_location:
|
||||
row: 227
|
||||
row: 232
|
||||
column: 0
|
||||
fix:
|
||||
patch:
|
||||
content: " "
|
||||
location:
|
||||
row: 227
|
||||
row: 232
|
||||
column: 0
|
||||
end_location:
|
||||
row: 227
|
||||
row: 232
|
||||
column: 0
|
||||
- kind: NoUnderIndentation
|
||||
location:
|
||||
row: 435
|
||||
row: 440
|
||||
column: 0
|
||||
end_location:
|
||||
row: 435
|
||||
row: 440
|
||||
column: 0
|
||||
fix:
|
||||
patch:
|
||||
content: " "
|
||||
location:
|
||||
row: 435
|
||||
row: 440
|
||||
column: 0
|
||||
end_location:
|
||||
row: 435
|
||||
row: 440
|
||||
column: 4
|
||||
|
||||
|
||||
@@ -4,50 +4,50 @@ expression: checks
|
||||
---
|
||||
- kind: NoOverIndentation
|
||||
location:
|
||||
row: 247
|
||||
row: 252
|
||||
column: 0
|
||||
end_location:
|
||||
row: 247
|
||||
row: 252
|
||||
column: 0
|
||||
fix:
|
||||
patch:
|
||||
content: " "
|
||||
location:
|
||||
row: 247
|
||||
row: 252
|
||||
column: 0
|
||||
end_location:
|
||||
row: 247
|
||||
row: 252
|
||||
column: 7
|
||||
- kind: NoOverIndentation
|
||||
location:
|
||||
row: 259
|
||||
row: 264
|
||||
column: 0
|
||||
end_location:
|
||||
row: 259
|
||||
row: 264
|
||||
column: 0
|
||||
fix:
|
||||
patch:
|
||||
content: " "
|
||||
location:
|
||||
row: 259
|
||||
row: 264
|
||||
column: 0
|
||||
end_location:
|
||||
row: 259
|
||||
row: 264
|
||||
column: 8
|
||||
- kind: NoOverIndentation
|
||||
location:
|
||||
row: 267
|
||||
row: 272
|
||||
column: 0
|
||||
end_location:
|
||||
row: 267
|
||||
row: 272
|
||||
column: 0
|
||||
fix:
|
||||
patch:
|
||||
content: " "
|
||||
location:
|
||||
row: 267
|
||||
row: 272
|
||||
column: 0
|
||||
end_location:
|
||||
row: 267
|
||||
row: 272
|
||||
column: 8
|
||||
|
||||
|
||||
@@ -4,18 +4,18 @@ expression: checks
|
||||
---
|
||||
- kind: NewLineAfterLastParagraph
|
||||
location:
|
||||
row: 276
|
||||
row: 281
|
||||
column: 4
|
||||
end_location:
|
||||
row: 278
|
||||
row: 283
|
||||
column: 19
|
||||
fix:
|
||||
patch:
|
||||
content: "\n "
|
||||
location:
|
||||
row: 278
|
||||
row: 283
|
||||
column: 16
|
||||
end_location:
|
||||
row: 278
|
||||
row: 283
|
||||
column: 16
|
||||
|
||||
|
||||
@@ -4,50 +4,50 @@ expression: checks
|
||||
---
|
||||
- kind: NoSurroundingWhitespace
|
||||
location:
|
||||
row: 283
|
||||
row: 288
|
||||
column: 4
|
||||
end_location:
|
||||
row: 283
|
||||
row: 288
|
||||
column: 33
|
||||
fix:
|
||||
patch:
|
||||
content: Whitespace at the end.
|
||||
location:
|
||||
row: 283
|
||||
row: 288
|
||||
column: 7
|
||||
end_location:
|
||||
row: 283
|
||||
row: 288
|
||||
column: 30
|
||||
- kind: NoSurroundingWhitespace
|
||||
location:
|
||||
row: 288
|
||||
row: 293
|
||||
column: 4
|
||||
end_location:
|
||||
row: 288
|
||||
row: 293
|
||||
column: 37
|
||||
fix:
|
||||
patch:
|
||||
content: Whitespace at everywhere.
|
||||
location:
|
||||
row: 288
|
||||
row: 293
|
||||
column: 7
|
||||
end_location:
|
||||
row: 288
|
||||
row: 293
|
||||
column: 34
|
||||
- kind: NoSurroundingWhitespace
|
||||
location:
|
||||
row: 294
|
||||
row: 299
|
||||
column: 4
|
||||
end_location:
|
||||
row: 297
|
||||
row: 302
|
||||
column: 7
|
||||
fix:
|
||||
patch:
|
||||
content: Whitespace at the beginning.
|
||||
location:
|
||||
row: 294
|
||||
row: 299
|
||||
column: 7
|
||||
end_location:
|
||||
row: 294
|
||||
row: 299
|
||||
column: 36
|
||||
|
||||
|
||||
@@ -5,35 +5,35 @@ expression: checks
|
||||
- kind:
|
||||
NoBlankLineBeforeClass: 1
|
||||
location:
|
||||
row: 165
|
||||
row: 170
|
||||
column: 4
|
||||
end_location:
|
||||
row: 165
|
||||
row: 170
|
||||
column: 29
|
||||
fix:
|
||||
patch:
|
||||
content: ""
|
||||
location:
|
||||
row: 164
|
||||
row: 169
|
||||
column: 0
|
||||
end_location:
|
||||
row: 165
|
||||
row: 170
|
||||
column: 0
|
||||
- kind:
|
||||
NoBlankLineBeforeClass: 1
|
||||
location:
|
||||
row: 176
|
||||
row: 181
|
||||
column: 4
|
||||
end_location:
|
||||
row: 176
|
||||
row: 181
|
||||
column: 24
|
||||
fix:
|
||||
patch:
|
||||
content: ""
|
||||
location:
|
||||
row: 175
|
||||
row: 180
|
||||
column: 0
|
||||
end_location:
|
||||
row: 176
|
||||
row: 181
|
||||
column: 0
|
||||
|
||||
|
||||
@@ -4,10 +4,10 @@ expression: checks
|
||||
---
|
||||
- kind: MultiLineSummaryFirstLine
|
||||
location:
|
||||
row: 124
|
||||
row: 129
|
||||
column: 4
|
||||
end_location:
|
||||
row: 126
|
||||
row: 131
|
||||
column: 7
|
||||
fix: ~
|
||||
|
||||
|
||||
@@ -4,154 +4,154 @@ expression: checks
|
||||
---
|
||||
- kind: MultiLineSummarySecondLine
|
||||
location:
|
||||
row: 195
|
||||
row: 200
|
||||
column: 4
|
||||
end_location:
|
||||
row: 198
|
||||
row: 203
|
||||
column: 7
|
||||
fix: ~
|
||||
- kind: MultiLineSummarySecondLine
|
||||
location:
|
||||
row: 205
|
||||
column: 4
|
||||
end_location:
|
||||
row: 210
|
||||
column: 7
|
||||
fix: ~
|
||||
- kind: MultiLineSummarySecondLine
|
||||
location:
|
||||
column: 4
|
||||
end_location:
|
||||
row: 215
|
||||
column: 4
|
||||
end_location:
|
||||
row: 219
|
||||
column: 7
|
||||
fix: ~
|
||||
- kind: MultiLineSummarySecondLine
|
||||
location:
|
||||
row: 225
|
||||
row: 220
|
||||
column: 4
|
||||
end_location:
|
||||
row: 229
|
||||
row: 224
|
||||
column: 7
|
||||
fix: ~
|
||||
- kind: MultiLineSummarySecondLine
|
||||
location:
|
||||
row: 235
|
||||
row: 230
|
||||
column: 4
|
||||
end_location:
|
||||
row: 239
|
||||
row: 234
|
||||
column: 7
|
||||
fix: ~
|
||||
- kind: MultiLineSummarySecondLine
|
||||
location:
|
||||
row: 240
|
||||
column: 4
|
||||
end_location:
|
||||
row: 244
|
||||
column: 3
|
||||
fix: ~
|
||||
- kind: MultiLineSummarySecondLine
|
||||
location:
|
||||
row: 245
|
||||
row: 250
|
||||
column: 4
|
||||
end_location:
|
||||
row: 249
|
||||
row: 254
|
||||
column: 7
|
||||
fix: ~
|
||||
- kind: MultiLineSummarySecondLine
|
||||
location:
|
||||
row: 255
|
||||
row: 260
|
||||
column: 4
|
||||
end_location:
|
||||
row: 259
|
||||
row: 264
|
||||
column: 11
|
||||
fix: ~
|
||||
- kind: MultiLineSummarySecondLine
|
||||
location:
|
||||
row: 265
|
||||
row: 270
|
||||
column: 4
|
||||
end_location:
|
||||
row: 269
|
||||
row: 274
|
||||
column: 7
|
||||
fix: ~
|
||||
- kind: MultiLineSummarySecondLine
|
||||
location:
|
||||
row: 276
|
||||
row: 281
|
||||
column: 4
|
||||
end_location:
|
||||
row: 278
|
||||
row: 283
|
||||
column: 19
|
||||
fix: ~
|
||||
- kind: MultiLineSummarySecondLine
|
||||
location:
|
||||
row: 294
|
||||
row: 299
|
||||
column: 4
|
||||
end_location:
|
||||
row: 297
|
||||
row: 302
|
||||
column: 7
|
||||
fix: ~
|
||||
- kind: MultiLineSummarySecondLine
|
||||
location:
|
||||
row: 338
|
||||
column: 4
|
||||
end_location:
|
||||
row: 343
|
||||
column: 7
|
||||
fix: ~
|
||||
- kind: MultiLineSummarySecondLine
|
||||
location:
|
||||
row: 378
|
||||
column: 4
|
||||
end_location:
|
||||
row: 381
|
||||
row: 348
|
||||
column: 7
|
||||
fix: ~
|
||||
- kind: MultiLineSummarySecondLine
|
||||
location:
|
||||
row: 387
|
||||
row: 383
|
||||
column: 4
|
||||
end_location:
|
||||
row: 391
|
||||
row: 386
|
||||
column: 7
|
||||
fix: ~
|
||||
- kind: MultiLineSummarySecondLine
|
||||
location:
|
||||
row: 433
|
||||
row: 392
|
||||
column: 4
|
||||
end_location:
|
||||
row: 396
|
||||
column: 7
|
||||
fix: ~
|
||||
- kind: MultiLineSummarySecondLine
|
||||
location:
|
||||
row: 438
|
||||
column: 36
|
||||
end_location:
|
||||
row: 436
|
||||
row: 441
|
||||
column: 7
|
||||
fix: ~
|
||||
- kind: MultiLineSummarySecondLine
|
||||
location:
|
||||
row: 445
|
||||
row: 450
|
||||
column: 4
|
||||
end_location:
|
||||
row: 449
|
||||
row: 454
|
||||
column: 7
|
||||
fix: ~
|
||||
- kind: MultiLineSummarySecondLine
|
||||
location:
|
||||
row: 521
|
||||
row: 526
|
||||
column: 4
|
||||
end_location:
|
||||
row: 527
|
||||
row: 532
|
||||
column: 7
|
||||
fix: ~
|
||||
- kind: MultiLineSummarySecondLine
|
||||
location:
|
||||
row: 541
|
||||
row: 546
|
||||
column: 4
|
||||
end_location:
|
||||
row: 544
|
||||
row: 549
|
||||
column: 7
|
||||
fix: ~
|
||||
- kind: MultiLineSummarySecondLine
|
||||
location:
|
||||
row: 550
|
||||
row: 555
|
||||
column: 4
|
||||
end_location:
|
||||
row: 553
|
||||
row: 558
|
||||
column: 7
|
||||
fix: ~
|
||||
- kind: MultiLineSummarySecondLine
|
||||
location:
|
||||
row: 563
|
||||
row: 568
|
||||
column: 4
|
||||
end_location:
|
||||
row: 566
|
||||
row: 571
|
||||
column: 7
|
||||
fix: ~
|
||||
|
||||
|
||||
@@ -2,14 +2,6 @@
|
||||
source: src/linter.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind: UsesTripleQuotes
|
||||
location:
|
||||
row: 302
|
||||
column: 4
|
||||
end_location:
|
||||
row: 302
|
||||
column: 19
|
||||
fix: ~
|
||||
- kind: UsesTripleQuotes
|
||||
location:
|
||||
row: 307
|
||||
@@ -24,7 +16,7 @@ expression: checks
|
||||
column: 4
|
||||
end_location:
|
||||
row: 312
|
||||
column: 15
|
||||
column: 19
|
||||
fix: ~
|
||||
- kind: UsesTripleQuotes
|
||||
location:
|
||||
@@ -36,10 +28,18 @@ expression: checks
|
||||
fix: ~
|
||||
- kind: UsesTripleQuotes
|
||||
location:
|
||||
row: 323
|
||||
row: 322
|
||||
column: 4
|
||||
end_location:
|
||||
row: 323
|
||||
row: 322
|
||||
column: 15
|
||||
fix: ~
|
||||
- kind: UsesTripleQuotes
|
||||
location:
|
||||
row: 328
|
||||
column: 4
|
||||
end_location:
|
||||
row: 328
|
||||
column: 16
|
||||
fix: ~
|
||||
|
||||
|
||||
@@ -4,60 +4,52 @@ expression: checks
|
||||
---
|
||||
- kind: EndsInPeriod
|
||||
location:
|
||||
row: 350
|
||||
row: 355
|
||||
column: 4
|
||||
end_location:
|
||||
row: 350
|
||||
row: 355
|
||||
column: 17
|
||||
fix: ~
|
||||
- kind: EndsInPeriod
|
||||
location:
|
||||
row: 401
|
||||
row: 406
|
||||
column: 24
|
||||
end_location:
|
||||
row: 401
|
||||
row: 406
|
||||
column: 39
|
||||
fix: ~
|
||||
- kind: EndsInPeriod
|
||||
location:
|
||||
row: 405
|
||||
row: 410
|
||||
column: 4
|
||||
end_location:
|
||||
row: 405
|
||||
row: 410
|
||||
column: 24
|
||||
fix: ~
|
||||
- kind: EndsInPeriod
|
||||
location:
|
||||
row: 411
|
||||
row: 416
|
||||
column: 4
|
||||
end_location:
|
||||
row: 411
|
||||
row: 416
|
||||
column: 24
|
||||
fix: ~
|
||||
- kind: EndsInPeriod
|
||||
location:
|
||||
row: 417
|
||||
row: 422
|
||||
column: 34
|
||||
end_location:
|
||||
row: 417
|
||||
row: 422
|
||||
column: 49
|
||||
fix: ~
|
||||
- kind: EndsInPeriod
|
||||
location:
|
||||
row: 424
|
||||
row: 429
|
||||
column: 48
|
||||
end_location:
|
||||
row: 424
|
||||
row: 429
|
||||
column: 63
|
||||
fix: ~
|
||||
- kind: EndsInPeriod
|
||||
location:
|
||||
row: 465
|
||||
column: 4
|
||||
end_location:
|
||||
row: 465
|
||||
column: 24
|
||||
fix: ~
|
||||
- kind: EndsInPeriod
|
||||
location:
|
||||
row: 470
|
||||
@@ -76,34 +68,42 @@ expression: checks
|
||||
fix: ~
|
||||
- kind: EndsInPeriod
|
||||
location:
|
||||
row: 482
|
||||
row: 480
|
||||
column: 4
|
||||
end_location:
|
||||
row: 482
|
||||
row: 480
|
||||
column: 24
|
||||
fix: ~
|
||||
- kind: EndsInPeriod
|
||||
location:
|
||||
row: 504
|
||||
row: 487
|
||||
column: 4
|
||||
end_location:
|
||||
row: 504
|
||||
row: 487
|
||||
column: 24
|
||||
fix: ~
|
||||
- kind: EndsInPeriod
|
||||
location:
|
||||
row: 509
|
||||
column: 4
|
||||
end_location:
|
||||
row: 509
|
||||
column: 34
|
||||
fix: ~
|
||||
- kind: EndsInPeriod
|
||||
location:
|
||||
row: 509
|
||||
row: 514
|
||||
column: 4
|
||||
end_location:
|
||||
row: 509
|
||||
row: 514
|
||||
column: 33
|
||||
fix: ~
|
||||
- kind: EndsInPeriod
|
||||
location:
|
||||
row: 515
|
||||
row: 520
|
||||
column: 4
|
||||
end_location:
|
||||
row: 515
|
||||
row: 520
|
||||
column: 32
|
||||
fix: ~
|
||||
|
||||
|
||||
@@ -4,10 +4,10 @@ expression: checks
|
||||
---
|
||||
- kind: NoSignature
|
||||
location:
|
||||
row: 373
|
||||
row: 378
|
||||
column: 4
|
||||
end_location:
|
||||
row: 373
|
||||
row: 378
|
||||
column: 30
|
||||
fix: ~
|
||||
|
||||
|
||||
@@ -4,60 +4,52 @@ expression: checks
|
||||
---
|
||||
- kind: EndsInPunctuation
|
||||
location:
|
||||
row: 350
|
||||
row: 355
|
||||
column: 4
|
||||
end_location:
|
||||
row: 350
|
||||
row: 355
|
||||
column: 17
|
||||
fix: ~
|
||||
- kind: EndsInPunctuation
|
||||
location:
|
||||
row: 401
|
||||
row: 406
|
||||
column: 24
|
||||
end_location:
|
||||
row: 401
|
||||
row: 406
|
||||
column: 39
|
||||
fix: ~
|
||||
- kind: EndsInPunctuation
|
||||
location:
|
||||
row: 405
|
||||
row: 410
|
||||
column: 4
|
||||
end_location:
|
||||
row: 405
|
||||
row: 410
|
||||
column: 24
|
||||
fix: ~
|
||||
- kind: EndsInPunctuation
|
||||
location:
|
||||
row: 411
|
||||
row: 416
|
||||
column: 4
|
||||
end_location:
|
||||
row: 411
|
||||
row: 416
|
||||
column: 24
|
||||
fix: ~
|
||||
- kind: EndsInPunctuation
|
||||
location:
|
||||
row: 417
|
||||
row: 422
|
||||
column: 34
|
||||
end_location:
|
||||
row: 417
|
||||
row: 422
|
||||
column: 49
|
||||
fix: ~
|
||||
- kind: EndsInPunctuation
|
||||
location:
|
||||
row: 424
|
||||
row: 429
|
||||
column: 48
|
||||
end_location:
|
||||
row: 424
|
||||
row: 429
|
||||
column: 63
|
||||
fix: ~
|
||||
- kind: EndsInPunctuation
|
||||
location:
|
||||
row: 465
|
||||
column: 4
|
||||
end_location:
|
||||
row: 465
|
||||
column: 24
|
||||
fix: ~
|
||||
- kind: EndsInPunctuation
|
||||
location:
|
||||
row: 470
|
||||
@@ -76,26 +68,34 @@ expression: checks
|
||||
fix: ~
|
||||
- kind: EndsInPunctuation
|
||||
location:
|
||||
row: 482
|
||||
row: 480
|
||||
column: 4
|
||||
end_location:
|
||||
row: 482
|
||||
row: 480
|
||||
column: 24
|
||||
fix: ~
|
||||
- kind: EndsInPunctuation
|
||||
location:
|
||||
row: 504
|
||||
row: 487
|
||||
column: 4
|
||||
end_location:
|
||||
row: 504
|
||||
row: 487
|
||||
column: 24
|
||||
fix: ~
|
||||
- kind: EndsInPunctuation
|
||||
location:
|
||||
row: 509
|
||||
column: 4
|
||||
end_location:
|
||||
row: 509
|
||||
column: 34
|
||||
fix: ~
|
||||
- kind: EndsInPunctuation
|
||||
location:
|
||||
row: 515
|
||||
row: 520
|
||||
column: 4
|
||||
end_location:
|
||||
row: 515
|
||||
row: 520
|
||||
column: 32
|
||||
fix: ~
|
||||
|
||||
|
||||
@@ -4,26 +4,26 @@ expression: checks
|
||||
---
|
||||
- kind: SkipDocstring
|
||||
location:
|
||||
row: 33
|
||||
row: 34
|
||||
column: 4
|
||||
end_location:
|
||||
row: 37
|
||||
row: 38
|
||||
column: 4
|
||||
fix: ~
|
||||
- kind: SkipDocstring
|
||||
location:
|
||||
row: 85
|
||||
row: 90
|
||||
column: 4
|
||||
end_location:
|
||||
row: 89
|
||||
row: 94
|
||||
column: 4
|
||||
fix: ~
|
||||
- kind: SkipDocstring
|
||||
location:
|
||||
row: 105
|
||||
row: 110
|
||||
column: 0
|
||||
end_location:
|
||||
row: 110
|
||||
row: 115
|
||||
column: 0
|
||||
fix: ~
|
||||
|
||||
|
||||
@@ -4,26 +4,26 @@ expression: checks
|
||||
---
|
||||
- kind: NonEmpty
|
||||
location:
|
||||
row: 19
|
||||
row: 20
|
||||
column: 8
|
||||
end_location:
|
||||
row: 19
|
||||
row: 20
|
||||
column: 14
|
||||
fix: ~
|
||||
- kind: NonEmpty
|
||||
location:
|
||||
row: 69
|
||||
row: 74
|
||||
column: 4
|
||||
end_location:
|
||||
row: 69
|
||||
row: 74
|
||||
column: 11
|
||||
fix: ~
|
||||
- kind: NonEmpty
|
||||
location:
|
||||
row: 75
|
||||
row: 80
|
||||
column: 8
|
||||
end_location:
|
||||
row: 75
|
||||
row: 80
|
||||
column: 10
|
||||
fix: ~
|
||||
|
||||
|
||||
85
src/snapshots/ruff__linter__tests__ERA001_ERA001.py.snap
Normal file
85
src/snapshots/ruff__linter__tests__ERA001_ERA001.py.snap
Normal file
@@ -0,0 +1,85 @@
|
||||
---
|
||||
source: src/linter.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind: CommentedOutCode
|
||||
location:
|
||||
row: 1
|
||||
column: 0
|
||||
end_location:
|
||||
row: 1
|
||||
column: 10
|
||||
fix:
|
||||
patch:
|
||||
content: ""
|
||||
location:
|
||||
row: 1
|
||||
column: 0
|
||||
end_location:
|
||||
row: 2
|
||||
column: 0
|
||||
- kind: CommentedOutCode
|
||||
location:
|
||||
row: 2
|
||||
column: 0
|
||||
end_location:
|
||||
row: 2
|
||||
column: 22
|
||||
fix:
|
||||
patch:
|
||||
content: ""
|
||||
location:
|
||||
row: 2
|
||||
column: 0
|
||||
end_location:
|
||||
row: 3
|
||||
column: 0
|
||||
- kind: CommentedOutCode
|
||||
location:
|
||||
row: 3
|
||||
column: 0
|
||||
end_location:
|
||||
row: 3
|
||||
column: 6
|
||||
fix:
|
||||
patch:
|
||||
content: ""
|
||||
location:
|
||||
row: 3
|
||||
column: 0
|
||||
end_location:
|
||||
row: 4
|
||||
column: 0
|
||||
- kind: CommentedOutCode
|
||||
location:
|
||||
row: 5
|
||||
column: 0
|
||||
end_location:
|
||||
row: 5
|
||||
column: 13
|
||||
fix:
|
||||
patch:
|
||||
content: ""
|
||||
location:
|
||||
row: 5
|
||||
column: 0
|
||||
end_location:
|
||||
row: 6
|
||||
column: 0
|
||||
- kind: CommentedOutCode
|
||||
location:
|
||||
row: 12
|
||||
column: 4
|
||||
end_location:
|
||||
row: 12
|
||||
column: 16
|
||||
fix:
|
||||
patch:
|
||||
content: ""
|
||||
location:
|
||||
row: 12
|
||||
column: 0
|
||||
end_location:
|
||||
row: 13
|
||||
column: 0
|
||||
|
||||
@@ -4,14 +4,14 @@ expression: checks
|
||||
---
|
||||
- kind:
|
||||
UnusedImport:
|
||||
- - functools
|
||||
- functools
|
||||
- false
|
||||
location:
|
||||
row: 2
|
||||
column: 0
|
||||
column: 7
|
||||
end_location:
|
||||
row: 2
|
||||
column: 20
|
||||
column: 16
|
||||
fix:
|
||||
patch:
|
||||
content: import os
|
||||
@@ -23,14 +23,14 @@ expression: checks
|
||||
column: 20
|
||||
- kind:
|
||||
UnusedImport:
|
||||
- - collections.OrderedDict
|
||||
- collections.OrderedDict
|
||||
- false
|
||||
location:
|
||||
row: 4
|
||||
column: 0
|
||||
row: 6
|
||||
column: 4
|
||||
end_location:
|
||||
row: 8
|
||||
column: 1
|
||||
row: 6
|
||||
column: 15
|
||||
fix:
|
||||
patch:
|
||||
content: "from collections import (\n Counter,\n namedtuple,\n)"
|
||||
@@ -42,11 +42,11 @@ expression: checks
|
||||
column: 1
|
||||
- kind:
|
||||
UnusedImport:
|
||||
- - logging.handlers
|
||||
- logging.handlers
|
||||
- false
|
||||
location:
|
||||
row: 12
|
||||
column: 0
|
||||
column: 7
|
||||
end_location:
|
||||
row: 12
|
||||
column: 23
|
||||
@@ -61,11 +61,11 @@ expression: checks
|
||||
column: 0
|
||||
- kind:
|
||||
UnusedImport:
|
||||
- - shelve
|
||||
- shelve
|
||||
- false
|
||||
location:
|
||||
row: 32
|
||||
column: 4
|
||||
column: 11
|
||||
end_location:
|
||||
row: 32
|
||||
column: 17
|
||||
@@ -80,11 +80,11 @@ expression: checks
|
||||
column: 0
|
||||
- kind:
|
||||
UnusedImport:
|
||||
- - importlib
|
||||
- importlib
|
||||
- false
|
||||
location:
|
||||
row: 33
|
||||
column: 4
|
||||
column: 11
|
||||
end_location:
|
||||
row: 33
|
||||
column: 20
|
||||
@@ -99,11 +99,11 @@ expression: checks
|
||||
column: 20
|
||||
- kind:
|
||||
UnusedImport:
|
||||
- - pathlib
|
||||
- pathlib
|
||||
- false
|
||||
location:
|
||||
row: 37
|
||||
column: 4
|
||||
column: 11
|
||||
end_location:
|
||||
row: 37
|
||||
column: 18
|
||||
@@ -118,11 +118,11 @@ expression: checks
|
||||
column: 0
|
||||
- kind:
|
||||
UnusedImport:
|
||||
- - pickle
|
||||
- pickle
|
||||
- false
|
||||
location:
|
||||
row: 52
|
||||
column: 8
|
||||
column: 15
|
||||
end_location:
|
||||
row: 52
|
||||
column: 21
|
||||
|
||||
@@ -4,11 +4,11 @@ expression: checks
|
||||
---
|
||||
- kind:
|
||||
UnusedImport:
|
||||
- - a.b.c
|
||||
- a.b.c
|
||||
- false
|
||||
location:
|
||||
row: 2
|
||||
column: 0
|
||||
column: 16
|
||||
end_location:
|
||||
row: 2
|
||||
column: 17
|
||||
@@ -23,11 +23,11 @@ expression: checks
|
||||
column: 0
|
||||
- kind:
|
||||
UnusedImport:
|
||||
- - d.e.f
|
||||
- d.e.f
|
||||
- false
|
||||
location:
|
||||
row: 3
|
||||
column: 0
|
||||
column: 16
|
||||
end_location:
|
||||
row: 3
|
||||
column: 22
|
||||
@@ -42,11 +42,11 @@ expression: checks
|
||||
column: 0
|
||||
- kind:
|
||||
UnusedImport:
|
||||
- - h.i
|
||||
- h.i
|
||||
- false
|
||||
location:
|
||||
row: 4
|
||||
column: 0
|
||||
column: 7
|
||||
end_location:
|
||||
row: 4
|
||||
column: 10
|
||||
@@ -61,11 +61,11 @@ expression: checks
|
||||
column: 0
|
||||
- kind:
|
||||
UnusedImport:
|
||||
- - j.k
|
||||
- j.k
|
||||
- false
|
||||
location:
|
||||
row: 5
|
||||
column: 0
|
||||
column: 7
|
||||
end_location:
|
||||
row: 5
|
||||
column: 15
|
||||
|
||||
@@ -4,11 +4,11 @@ expression: checks
|
||||
---
|
||||
- kind:
|
||||
UnusedImport:
|
||||
- - background.BackgroundTasks
|
||||
- background.BackgroundTasks
|
||||
- false
|
||||
location:
|
||||
row: 7
|
||||
column: 0
|
||||
column: 24
|
||||
end_location:
|
||||
row: 7
|
||||
column: 39
|
||||
@@ -23,11 +23,11 @@ expression: checks
|
||||
column: 0
|
||||
- kind:
|
||||
UnusedImport:
|
||||
- - datastructures.UploadFile
|
||||
- datastructures.UploadFile
|
||||
- false
|
||||
location:
|
||||
row: 10
|
||||
column: 0
|
||||
column: 28
|
||||
end_location:
|
||||
row: 10
|
||||
column: 52
|
||||
@@ -42,11 +42,11 @@ expression: checks
|
||||
column: 0
|
||||
- kind:
|
||||
UnusedImport:
|
||||
- - background
|
||||
- background
|
||||
- false
|
||||
location:
|
||||
row: 17
|
||||
column: 0
|
||||
column: 7
|
||||
end_location:
|
||||
row: 17
|
||||
column: 17
|
||||
@@ -61,11 +61,11 @@ expression: checks
|
||||
column: 0
|
||||
- kind:
|
||||
UnusedImport:
|
||||
- - datastructures
|
||||
- datastructures
|
||||
- false
|
||||
location:
|
||||
row: 20
|
||||
column: 0
|
||||
column: 7
|
||||
end_location:
|
||||
row: 20
|
||||
column: 35
|
||||
|
||||
@@ -6,7 +6,7 @@ expression: checks
|
||||
FutureFeatureNotDefined: non_existent_feature
|
||||
location:
|
||||
row: 2
|
||||
column: 0
|
||||
column: 23
|
||||
end_location:
|
||||
row: 2
|
||||
column: 43
|
||||
|
||||
14
src/snapshots/ruff__linter__tests__F501_F50x.py.snap
Normal file
14
src/snapshots/ruff__linter__tests__F501_F50x.py.snap
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
source: src/linter.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind:
|
||||
PercentFormatInvalidFormat: incomplete format
|
||||
location:
|
||||
row: 1
|
||||
column: 9
|
||||
end_location:
|
||||
row: 1
|
||||
column: 25
|
||||
fix: ~
|
||||
|
||||
61
src/snapshots/ruff__linter__tests__F502_F502.py.snap
Normal file
61
src/snapshots/ruff__linter__tests__F502_F502.py.snap
Normal file
@@ -0,0 +1,61 @@
|
||||
---
|
||||
source: src/linter.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind: PercentFormatExpectedMapping
|
||||
location:
|
||||
row: 6
|
||||
column: 10
|
||||
end_location:
|
||||
row: 6
|
||||
column: 19
|
||||
fix: ~
|
||||
- kind: PercentFormatExpectedMapping
|
||||
location:
|
||||
row: 7
|
||||
column: 10
|
||||
end_location:
|
||||
row: 7
|
||||
column: 20
|
||||
fix: ~
|
||||
- kind: PercentFormatExpectedMapping
|
||||
location:
|
||||
row: 8
|
||||
column: 10
|
||||
end_location:
|
||||
row: 8
|
||||
column: 19
|
||||
fix: ~
|
||||
- kind: PercentFormatExpectedMapping
|
||||
location:
|
||||
row: 9
|
||||
column: 10
|
||||
end_location:
|
||||
row: 9
|
||||
column: 22
|
||||
fix: ~
|
||||
- kind: PercentFormatExpectedMapping
|
||||
location:
|
||||
row: 11
|
||||
column: 10
|
||||
end_location:
|
||||
row: 11
|
||||
column: 37
|
||||
fix: ~
|
||||
- kind: PercentFormatExpectedMapping
|
||||
location:
|
||||
row: 12
|
||||
column: 10
|
||||
end_location:
|
||||
row: 12
|
||||
column: 37
|
||||
fix: ~
|
||||
- kind: PercentFormatExpectedMapping
|
||||
location:
|
||||
row: 13
|
||||
column: 10
|
||||
end_location:
|
||||
row: 13
|
||||
column: 37
|
||||
fix: ~
|
||||
|
||||
13
src/snapshots/ruff__linter__tests__F502_F50x.py.snap
Normal file
13
src/snapshots/ruff__linter__tests__F502_F50x.py.snap
Normal file
@@ -0,0 +1,13 @@
|
||||
---
|
||||
source: src/linter.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind: PercentFormatExpectedMapping
|
||||
location:
|
||||
row: 9
|
||||
column: 10
|
||||
end_location:
|
||||
row: 9
|
||||
column: 21
|
||||
fix: ~
|
||||
|
||||
29
src/snapshots/ruff__linter__tests__F503_F503.py.snap
Normal file
29
src/snapshots/ruff__linter__tests__F503_F503.py.snap
Normal file
@@ -0,0 +1,29 @@
|
||||
---
|
||||
source: src/linter.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind: PercentFormatExpectedSequence
|
||||
location:
|
||||
row: 17
|
||||
column: 8
|
||||
end_location:
|
||||
row: 17
|
||||
column: 24
|
||||
fix: ~
|
||||
- kind: PercentFormatExpectedSequence
|
||||
location:
|
||||
row: 18
|
||||
column: 8
|
||||
end_location:
|
||||
row: 18
|
||||
column: 28
|
||||
fix: ~
|
||||
- kind: PercentFormatExpectedSequence
|
||||
location:
|
||||
row: 23
|
||||
column: 8
|
||||
end_location:
|
||||
row: 23
|
||||
column: 42
|
||||
fix: ~
|
||||
|
||||
13
src/snapshots/ruff__linter__tests__F503_F50x.py.snap
Normal file
13
src/snapshots/ruff__linter__tests__F503_F50x.py.snap
Normal file
@@ -0,0 +1,13 @@
|
||||
---
|
||||
source: src/linter.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind: PercentFormatExpectedSequence
|
||||
location:
|
||||
row: 10
|
||||
column: 8
|
||||
end_location:
|
||||
row: 10
|
||||
column: 20
|
||||
fix: ~
|
||||
|
||||
15
src/snapshots/ruff__linter__tests__F504_F504.py.snap
Normal file
15
src/snapshots/ruff__linter__tests__F504_F504.py.snap
Normal file
@@ -0,0 +1,15 @@
|
||||
---
|
||||
source: src/linter.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind:
|
||||
PercentFormatExtraNamedArguments:
|
||||
- b
|
||||
location:
|
||||
row: 3
|
||||
column: 14
|
||||
end_location:
|
||||
row: 3
|
||||
column: 34
|
||||
fix: ~
|
||||
|
||||
15
src/snapshots/ruff__linter__tests__F504_F50x.py.snap
Normal file
15
src/snapshots/ruff__linter__tests__F504_F50x.py.snap
Normal file
@@ -0,0 +1,15 @@
|
||||
---
|
||||
source: src/linter.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind:
|
||||
PercentFormatExtraNamedArguments:
|
||||
- baz
|
||||
location:
|
||||
row: 8
|
||||
column: 10
|
||||
end_location:
|
||||
row: 8
|
||||
column: 32
|
||||
fix: ~
|
||||
|
||||
6
src/snapshots/ruff__linter__tests__F505_F504.py.snap
Normal file
6
src/snapshots/ruff__linter__tests__F505_F504.py.snap
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
source: src/linter.rs
|
||||
expression: checks
|
||||
---
|
||||
[]
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user