Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9161b866b5 | ||
|
|
38141a6f14 | ||
|
|
aa5402fc0e | ||
|
|
99f077aa4e | ||
|
|
7f25d1ec70 | ||
|
|
360b033e04 | ||
|
|
247dcc9f9c |
9
.github/workflows/ci.yaml
vendored
9
.github/workflows/ci.yaml
vendored
@@ -20,6 +20,9 @@ jobs:
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly-2022-11-01
|
||||
override: true
|
||||
components: rustfmt
|
||||
- uses: actions/cache@v3
|
||||
env:
|
||||
cache-name: cache-cargo
|
||||
@@ -33,6 +36,12 @@ jobs:
|
||||
${{ runner.os }}-build-
|
||||
${{ runner.os }}-
|
||||
- run: cargo build --all --release
|
||||
- run: ./target/release/ruff_dev generate-rules-table
|
||||
- run: ./target/release/ruff_dev generate-options
|
||||
- run: git diff --quiet README.md || echo "::error file=README.md::This file is outdated. You may have to rerun 'cargo dev generate-options' and/or 'cargo dev generate-rules-table'."
|
||||
- run: ./target/release/ruff_dev generate-check-code-prefix && cargo fmt -- src/checks_gen.rs
|
||||
- run: git diff --quiet src/checks_gen.rs || echo "::error file=src/checks_gen.rs::This file is outdated. You may have to rerun 'cargo dev generate-check-code-prefix'."
|
||||
- run: git diff --exit-code -- README.md src/checks_gen.rs
|
||||
|
||||
cargo_fmt:
|
||||
name: "cargo fmt"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
repos:
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
rev: v0.0.175
|
||||
rev: v0.0.176
|
||||
hooks:
|
||||
- id: ruff
|
||||
|
||||
|
||||
8
Cargo.lock
generated
8
Cargo.lock
generated
@@ -724,7 +724,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.175-dev.0"
|
||||
version = "0.0.176-dev.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.0.29",
|
||||
@@ -1821,7 +1821,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.175"
|
||||
version = "0.0.176"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.9.1",
|
||||
"anyhow",
|
||||
@@ -1874,7 +1874,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_dev"
|
||||
version = "0.0.175"
|
||||
version = "0.0.176"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.0.29",
|
||||
@@ -1892,7 +1892,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_macros"
|
||||
version = "0.0.175"
|
||||
version = "0.0.176"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
||||
@@ -6,7 +6,7 @@ members = [
|
||||
|
||||
[package]
|
||||
name = "ruff"
|
||||
version = "0.0.175"
|
||||
version = "0.0.176"
|
||||
edition = "2021"
|
||||
rust-version = "1.65.0"
|
||||
|
||||
@@ -41,7 +41,7 @@ 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 }
|
||||
ruff_macros = { version = "0.0.175", path = "ruff_macros" }
|
||||
ruff_macros = { version = "0.0.176", path = "ruff_macros" }
|
||||
rustc-hash = { version = "1.1.0" }
|
||||
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "2edd0d264c50c7807bcff03a52a6509e8b7f187f" }
|
||||
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "2edd0d264c50c7807bcff03a52a6509e8b7f187f" }
|
||||
|
||||
25
LICENSE
25
LICENSE
@@ -438,6 +438,31 @@ are:
|
||||
SOFTWARE.
|
||||
"""
|
||||
|
||||
- flake8-simplify, licensed as follows:
|
||||
"""
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 Martin Thoma
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
- isort, licensed as follows:
|
||||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
15
README.md
15
README.md
@@ -90,6 +90,7 @@ of [Conda](https://docs.conda.io/en/latest/):
|
||||
1. [flake8-print (T20)](#flake8-print-t20)
|
||||
1. [flake8-quotes (Q)](#flake8-quotes-q)
|
||||
1. [flake8-return (RET)](#flake8-return-ret)
|
||||
1. [flake8-simplify (SIM)](#flake8-simplify-sim)
|
||||
1. [flake8-tidy-imports (TID)](#flake8-tidy-imports-tid)
|
||||
1. [flake8-unused-arguments (ARG)](#flake8-unused-arguments-arg)
|
||||
1. [eradicate (ERA)](#eradicate-era)
|
||||
@@ -154,7 +155,7 @@ Ruff also works with [pre-commit](https://pre-commit.com):
|
||||
```yaml
|
||||
repos:
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
rev: v0.0.175
|
||||
rev: v0.0.176
|
||||
hooks:
|
||||
- id: ruff
|
||||
```
|
||||
@@ -369,7 +370,7 @@ For targeted exclusions across entire files (e.g., "Ignore all F841 violations i
|
||||
### "Action Comments"
|
||||
|
||||
Ruff respects `isort`'s ["Action Comments"](https://pycqa.github.io/isort/docs/configuration/action_comments.html)
|
||||
(`# isort: skip_file`, `# isort: on`, `# isort: off`, `# isort: skip`, and `isort: split`), which
|
||||
(`# isort: skip_file`, `# isort: on`, `# isort: off`, `# isort: skip`, and `# isort: split`), which
|
||||
enable selectively enabling and disabling import sorting for blocks of code and other inline
|
||||
configuration.
|
||||
|
||||
@@ -716,7 +717,7 @@ For more, see [flake8-comprehensions](https://pypi.org/project/flake8-comprehens
|
||||
| C409 | UnnecessaryLiteralWithinTupleCall | Unnecessary `(list\|tuple)` literal passed to `tuple()` (remove the outer call to `tuple()`) | 🛠 |
|
||||
| C410 | UnnecessaryLiteralWithinListCall | Unnecessary `(list\|tuple)` literal passed to `list()` (rewrite as a `list` literal) | 🛠 |
|
||||
| C411 | UnnecessaryListCall | Unnecessary `list` call (remove the outer call to `list()`) | 🛠 |
|
||||
| C413 | UnnecessaryCallAroundSorted | Unnecessary `(list\|reversed)` call around `sorted()` | |
|
||||
| C413 | UnnecessaryCallAroundSorted | Unnecessary `(list\|reversed)` call around `sorted()` | 🛠 |
|
||||
| C414 | UnnecessaryDoubleCastOrProcess | Unnecessary `(list\|reversed\|set\|sorted\|tuple)` call within `(list\|set\|sorted\|tuple)()` | |
|
||||
| C415 | UnnecessarySubscriptReversal | Unnecessary subscript reversal of iterable within `(reversed\|set\|sorted)()` | |
|
||||
| C416 | UnnecessaryComprehension | Unnecessary `(list\|set)` comprehension (rewrite using `(list\|set)()`) | 🛠 |
|
||||
@@ -771,6 +772,14 @@ For more, see [flake8-return](https://pypi.org/project/flake8-return/1.2.0/) on
|
||||
| RET507 | SuperfluousElseContinue | Unnecessary `else` after `continue` statement | |
|
||||
| RET508 | SuperfluousElseBreak | Unnecessary `else` after `break` statement | |
|
||||
|
||||
### flake8-simplify (SIM)
|
||||
|
||||
For more, see [flake8-simplify](https://pypi.org/project/flake8-simplify/0.19.3/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| SIM118 | KeyInDict | Use 'key in dict' instead of 'key in dict.keys() | 🛠 |
|
||||
|
||||
### flake8-tidy-imports (TID)
|
||||
|
||||
For more, see [flake8-tidy-imports](https://pypi.org/project/flake8-tidy-imports/4.8.0/) on PyPI.
|
||||
|
||||
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.175"
|
||||
version = "0.0.176"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@@ -1975,7 +1975,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.175"
|
||||
version = "0.0.176"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.175-dev.0"
|
||||
version = "0.0.176-dev.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
|
||||
@@ -18,6 +18,7 @@ pub enum Plugin {
|
||||
Flake8Print,
|
||||
Flake8Quotes,
|
||||
Flake8Return,
|
||||
Flake8Simplify,
|
||||
Flake8TidyImports,
|
||||
McCabe,
|
||||
PEP8Naming,
|
||||
@@ -41,6 +42,7 @@ impl FromStr for Plugin {
|
||||
"flake8-print" => Ok(Plugin::Flake8Print),
|
||||
"flake8-quotes" => Ok(Plugin::Flake8Quotes),
|
||||
"flake8-return" => Ok(Plugin::Flake8Return),
|
||||
"flake8-simplify" => Ok(Plugin::Flake8Simplify),
|
||||
"flake8-tidy-imports" => Ok(Plugin::Flake8TidyImports),
|
||||
"mccabe" => Ok(Plugin::McCabe),
|
||||
"pep8-naming" => Ok(Plugin::PEP8Naming),
|
||||
@@ -65,6 +67,7 @@ impl Plugin {
|
||||
Plugin::Flake8Print => CheckCodePrefix::T2,
|
||||
Plugin::Flake8Quotes => CheckCodePrefix::Q,
|
||||
Plugin::Flake8Return => CheckCodePrefix::RET,
|
||||
Plugin::Flake8Simplify => CheckCodePrefix::SIM,
|
||||
Plugin::Flake8TidyImports => CheckCodePrefix::I25,
|
||||
Plugin::McCabe => CheckCodePrefix::C9,
|
||||
Plugin::PEP8Naming => CheckCodePrefix::N,
|
||||
@@ -101,6 +104,7 @@ impl Plugin {
|
||||
Plugin::Flake8Print => vec![CheckCodePrefix::T2],
|
||||
Plugin::Flake8Quotes => vec![CheckCodePrefix::Q],
|
||||
Plugin::Flake8Return => vec![CheckCodePrefix::RET],
|
||||
Plugin::Flake8Simplify => vec![CheckCodePrefix::SIM],
|
||||
Plugin::Flake8TidyImports => vec![CheckCodePrefix::I25],
|
||||
Plugin::McCabe => vec![CheckCodePrefix::C9],
|
||||
Plugin::PEP8Naming => vec![CheckCodePrefix::N],
|
||||
@@ -397,6 +401,7 @@ pub fn infer_plugins_from_codes(codes: &BTreeSet<CheckCodePrefix>) -> Vec<Plugin
|
||||
Plugin::Flake8Print,
|
||||
Plugin::Flake8Quotes,
|
||||
Plugin::Flake8Return,
|
||||
Plugin::Flake8Simplify,
|
||||
Plugin::Flake8TidyImports,
|
||||
Plugin::PEP8Naming,
|
||||
Plugin::Pyupgrade,
|
||||
|
||||
12
resources/test/fixtures/flake8_simplify/SIM118.py
vendored
Normal file
12
resources/test/fixtures/flake8_simplify/SIM118.py
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
key in dict.keys() # SIM118
|
||||
|
||||
foo["bar"] in dict.keys() # SIM118
|
||||
|
||||
foo() in dict.keys() # SIM118
|
||||
|
||||
for key in dict.keys(): # SIM118
|
||||
pass
|
||||
|
||||
for key in list(dict.keys()):
|
||||
if some_property(key):
|
||||
del dict[key]
|
||||
17
resources/test/fixtures/pyflakes/F821_6.py
vendored
Normal file
17
resources/test/fixtures/pyflakes/F821_6.py
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
"""Test: annotated global."""
|
||||
|
||||
|
||||
n: int
|
||||
|
||||
|
||||
def f():
|
||||
print(n)
|
||||
|
||||
|
||||
def g():
|
||||
global n
|
||||
n = 1
|
||||
|
||||
|
||||
g()
|
||||
f()
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff_dev"
|
||||
version = "0.0.175"
|
||||
version = "0.0.176"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff_macros"
|
||||
version = "0.0.175"
|
||||
version = "0.0.176"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
|
||||
@@ -37,7 +37,7 @@ use crate::visibility::{module_visibility, transition_scope, Modifier, Visibilit
|
||||
use crate::{
|
||||
docstrings, flake8_2020, flake8_annotations, flake8_bandit, flake8_blind_except,
|
||||
flake8_boolean_trap, flake8_bugbear, flake8_builtins, flake8_comprehensions, flake8_debugger,
|
||||
flake8_import_conventions, flake8_print, flake8_return, flake8_tidy_imports,
|
||||
flake8_import_conventions, flake8_print, flake8_return, flake8_simplify, flake8_tidy_imports,
|
||||
flake8_unused_arguments, mccabe, pep8_naming, pycodestyle, pydocstyle, pyflakes, pygrep_hooks,
|
||||
pylint, pyupgrade, visibility,
|
||||
};
|
||||
@@ -1059,6 +1059,9 @@ where
|
||||
if self.settings.enabled.contains(&CheckCode::PLW0120) {
|
||||
pylint::plugins::useless_else_on_loop(self, stmt, body, orelse);
|
||||
}
|
||||
if self.settings.enabled.contains(&CheckCode::SIM118) {
|
||||
flake8_simplify::plugins::key_in_dict_for(self, target, iter);
|
||||
}
|
||||
}
|
||||
StmtKind::Try { handlers, .. } => {
|
||||
if self.settings.enabled.contains(&CheckCode::F707) {
|
||||
@@ -1155,7 +1158,13 @@ where
|
||||
// If any global bindings don't already exist in the global scope, add it.
|
||||
let globals = operations::extract_globals(body);
|
||||
for (name, stmt) in operations::extract_globals(body) {
|
||||
if !self.scopes[GLOBAL_SCOPE_INDEX].values.contains_key(name) {
|
||||
if self.scopes[GLOBAL_SCOPE_INDEX]
|
||||
.values
|
||||
.get(name)
|
||||
.map_or(true, |index| {
|
||||
matches!(self.bindings[*index].kind, BindingKind::Annotation)
|
||||
})
|
||||
{
|
||||
let index = self.bindings.len();
|
||||
self.bindings.push(Binding {
|
||||
kind: BindingKind::Assignment,
|
||||
@@ -1207,7 +1216,13 @@ where
|
||||
// If any global bindings don't already exist in the global scope, add it.
|
||||
let globals = operations::extract_globals(body);
|
||||
for (name, stmt) in &globals {
|
||||
if !self.scopes[GLOBAL_SCOPE_INDEX].values.contains_key(name) {
|
||||
if self.scopes[GLOBAL_SCOPE_INDEX]
|
||||
.values
|
||||
.get(name)
|
||||
.map_or(true, |index| {
|
||||
matches!(self.bindings[*index].kind, BindingKind::Annotation)
|
||||
})
|
||||
{
|
||||
let index = self.bindings.len();
|
||||
self.bindings.push(Binding {
|
||||
kind: BindingKind::Assignment,
|
||||
@@ -2078,6 +2093,16 @@ where
|
||||
comparators,
|
||||
);
|
||||
}
|
||||
|
||||
if self.settings.enabled.contains(&CheckCode::SIM118) {
|
||||
flake8_simplify::plugins::key_in_dict_compare(
|
||||
self,
|
||||
expr,
|
||||
left,
|
||||
ops,
|
||||
comparators,
|
||||
);
|
||||
}
|
||||
}
|
||||
ExprKind::Constant {
|
||||
value: Constant::Str(value),
|
||||
@@ -2717,6 +2742,7 @@ impl<'a> Checker<'a> {
|
||||
let mut first_iter = true;
|
||||
let mut in_generator = false;
|
||||
let mut import_starred = false;
|
||||
|
||||
for scope_index in self.scope_stack.iter().rev() {
|
||||
let scope = &self.scopes[*scope_index];
|
||||
|
||||
|
||||
@@ -206,6 +206,8 @@ pub enum CheckCode {
|
||||
YTT301,
|
||||
YTT302,
|
||||
YTT303,
|
||||
// flake8-simplify
|
||||
SIM118,
|
||||
// pyupgrade
|
||||
UP001,
|
||||
UP003,
|
||||
@@ -337,6 +339,7 @@ pub enum CheckCategory {
|
||||
Flake8Print,
|
||||
Flake8Quotes,
|
||||
Flake8Return,
|
||||
Flake8Simplify,
|
||||
Flake8TidyImports,
|
||||
Flake8UnusedArguments,
|
||||
Eradicate,
|
||||
@@ -377,6 +380,7 @@ impl CheckCategory {
|
||||
CheckCategory::Flake8Quotes => "flake8-quotes",
|
||||
CheckCategory::Flake8Return => "flake8-return",
|
||||
CheckCategory::Flake8TidyImports => "flake8-tidy-imports",
|
||||
CheckCategory::Flake8Simplify => "flake8-simplify",
|
||||
CheckCategory::Flake8UnusedArguments => "flake8-unused-arguments",
|
||||
CheckCategory::Isort => "isort",
|
||||
CheckCategory::McCabe => "mccabe",
|
||||
@@ -406,6 +410,7 @@ impl CheckCategory {
|
||||
CheckCategory::Flake8Print => vec![CheckCodePrefix::T20],
|
||||
CheckCategory::Flake8Quotes => vec![CheckCodePrefix::Q],
|
||||
CheckCategory::Flake8Return => vec![CheckCodePrefix::RET],
|
||||
CheckCategory::Flake8Simplify => vec![CheckCodePrefix::SIM],
|
||||
CheckCategory::Flake8TidyImports => vec![CheckCodePrefix::TID],
|
||||
CheckCategory::Flake8UnusedArguments => vec![CheckCodePrefix::ARG],
|
||||
CheckCategory::Isort => vec![CheckCodePrefix::I],
|
||||
@@ -481,6 +486,10 @@ impl CheckCategory {
|
||||
"https://pypi.org/project/flake8-return/1.2.0/",
|
||||
&Platform::PyPI,
|
||||
)),
|
||||
CheckCategory::Flake8Simplify => Some((
|
||||
"https://pypi.org/project/flake8-simplify/0.19.3/",
|
||||
&Platform::PyPI,
|
||||
)),
|
||||
CheckCategory::Flake8TidyImports => Some((
|
||||
"https://pypi.org/project/flake8-tidy-imports/4.8.0/",
|
||||
&Platform::PyPI,
|
||||
@@ -746,6 +755,8 @@ pub enum CheckKind {
|
||||
SysVersion0Referenced,
|
||||
SysVersionCmpStr10,
|
||||
SysVersionSlice1Referenced,
|
||||
// flake8-simplify
|
||||
KeyInDict(String, String),
|
||||
// pyupgrade
|
||||
TypeOfPrimitive(Primitive),
|
||||
UselessMetaclassType,
|
||||
@@ -1082,6 +1093,8 @@ impl CheckCode {
|
||||
CheckCode::YTT303 => CheckKind::SysVersionSlice1Referenced,
|
||||
// flake8-blind-except
|
||||
CheckCode::BLE001 => CheckKind::BlindExcept("Exception".to_string()),
|
||||
// flake8-simplify
|
||||
CheckCode::SIM118 => CheckKind::KeyInDict("key".to_string(), "dict".to_string()),
|
||||
// pyupgrade
|
||||
CheckCode::UP001 => CheckKind::UselessMetaclassType,
|
||||
CheckCode::UP003 => CheckKind::TypeOfPrimitive(Primitive::Str),
|
||||
@@ -1442,6 +1455,7 @@ impl CheckCode {
|
||||
CheckCode::S105 => CheckCategory::Flake8Bandit,
|
||||
CheckCode::S106 => CheckCategory::Flake8Bandit,
|
||||
CheckCode::S107 => CheckCategory::Flake8Bandit,
|
||||
CheckCode::SIM118 => CheckCategory::Flake8Simplify,
|
||||
CheckCode::T100 => CheckCategory::Flake8Debugger,
|
||||
CheckCode::T201 => CheckCategory::Flake8Print,
|
||||
CheckCode::T203 => CheckCategory::Flake8Print,
|
||||
@@ -1650,6 +1664,8 @@ impl CheckKind {
|
||||
CheckKind::SysVersion0Referenced => &CheckCode::YTT301,
|
||||
CheckKind::SysVersionCmpStr10 => &CheckCode::YTT302,
|
||||
CheckKind::SysVersionSlice1Referenced => &CheckCode::YTT303,
|
||||
// flake8-simplify
|
||||
CheckKind::KeyInDict(..) => &CheckCode::SIM118,
|
||||
// pyupgrade
|
||||
CheckKind::TypeOfPrimitive(_) => &CheckCode::UP003,
|
||||
CheckKind::UselessMetaclassType => &CheckCode::UP001,
|
||||
@@ -2316,6 +2332,10 @@ impl CheckKind {
|
||||
CheckKind::SysVersionSlice1Referenced => {
|
||||
"`sys.version[:1]` referenced (python10), use `sys.version_info`".to_string()
|
||||
}
|
||||
// flake8-simplify
|
||||
CheckKind::KeyInDict(key, dict) => {
|
||||
format!("Use '{key} in {dict}' instead of '{key} in {dict}.keys()")
|
||||
}
|
||||
// pyupgrade
|
||||
CheckKind::TypeOfPrimitive(primitive) => {
|
||||
format!("Use `{}` instead of `type(...)`", primitive.builtin())
|
||||
@@ -2660,6 +2680,7 @@ impl CheckKind {
|
||||
| CheckKind::ImplicitReturn
|
||||
| CheckKind::ImplicitReturnValue
|
||||
| CheckKind::IsLiteral
|
||||
| CheckKind::KeyInDict(..)
|
||||
| CheckKind::MisplacedComparisonConstant(..)
|
||||
| CheckKind::NewLineAfterLastParagraph
|
||||
| CheckKind::NewLineAfterSectionName(..)
|
||||
@@ -2692,6 +2713,7 @@ impl CheckKind {
|
||||
| CheckKind::SuperCallWithParameters
|
||||
| CheckKind::TrueFalseComparison(..)
|
||||
| CheckKind::TypeOfPrimitive(..)
|
||||
| CheckKind::UnnecessaryCallAroundSorted(..)
|
||||
| CheckKind::UnnecessaryCollectionCall(..)
|
||||
| CheckKind::UnnecessaryComprehension(..)
|
||||
| CheckKind::UnnecessaryEncodeUTF8
|
||||
|
||||
@@ -382,6 +382,10 @@ pub enum CheckCodePrefix {
|
||||
S105,
|
||||
S106,
|
||||
S107,
|
||||
SIM,
|
||||
SIM1,
|
||||
SIM11,
|
||||
SIM118,
|
||||
T,
|
||||
T1,
|
||||
T10,
|
||||
@@ -1494,6 +1498,10 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::S105 => vec![CheckCode::S105],
|
||||
CheckCodePrefix::S106 => vec![CheckCode::S106],
|
||||
CheckCodePrefix::S107 => vec![CheckCode::S107],
|
||||
CheckCodePrefix::SIM => vec![CheckCode::SIM118],
|
||||
CheckCodePrefix::SIM1 => vec![CheckCode::SIM118],
|
||||
CheckCodePrefix::SIM11 => vec![CheckCode::SIM118],
|
||||
CheckCodePrefix::SIM118 => vec![CheckCode::SIM118],
|
||||
CheckCodePrefix::T => vec![CheckCode::T100, CheckCode::T201, CheckCode::T203],
|
||||
CheckCodePrefix::T1 => vec![CheckCode::T100],
|
||||
CheckCodePrefix::T10 => vec![CheckCode::T100],
|
||||
@@ -2203,6 +2211,10 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::S105 => SuffixLength::Three,
|
||||
CheckCodePrefix::S106 => SuffixLength::Three,
|
||||
CheckCodePrefix::S107 => SuffixLength::Three,
|
||||
CheckCodePrefix::SIM => SuffixLength::Zero,
|
||||
CheckCodePrefix::SIM1 => SuffixLength::One,
|
||||
CheckCodePrefix::SIM11 => SuffixLength::Two,
|
||||
CheckCodePrefix::SIM118 => SuffixLength::Three,
|
||||
CheckCodePrefix::T => SuffixLength::Zero,
|
||||
CheckCodePrefix::T1 => SuffixLength::One,
|
||||
CheckCodePrefix::T10 => SuffixLength::Two,
|
||||
@@ -2303,6 +2315,7 @@ pub const CATEGORIES: &[CheckCodePrefix] = &[
|
||||
CheckCodePrefix::RET,
|
||||
CheckCodePrefix::RUF,
|
||||
CheckCodePrefix::S,
|
||||
CheckCodePrefix::SIM,
|
||||
CheckCodePrefix::T,
|
||||
CheckCodePrefix::TID,
|
||||
CheckCodePrefix::UP,
|
||||
|
||||
29
src/flake8_simplify/mod.rs
Normal file
29
src/flake8_simplify/mod.rs
Normal file
@@ -0,0 +1,29 @@
|
||||
pub mod plugins;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::convert::AsRef;
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::Result;
|
||||
use test_case::test_case;
|
||||
|
||||
use crate::checks::CheckCode;
|
||||
use crate::linter::test_path;
|
||||
use crate::settings;
|
||||
|
||||
#[test_case(CheckCode::SIM118, Path::new("SIM118.py"); "SIM118")]
|
||||
fn checks(check_code: CheckCode, path: &Path) -> Result<()> {
|
||||
let snapshot = format!("{}_{}", check_code.as_ref(), path.to_string_lossy());
|
||||
let mut checks = test_path(
|
||||
Path::new("./resources/test/fixtures/flake8_simplify")
|
||||
.join(path)
|
||||
.as_path(),
|
||||
&settings::Settings::for_rule(check_code),
|
||||
true,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(snapshot, checks);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
74
src/flake8_simplify/plugins/key_in_dict.rs
Normal file
74
src/flake8_simplify/plugins/key_in_dict.rs
Normal file
@@ -0,0 +1,74 @@
|
||||
use rustpython_ast::{Cmpop, Expr, ExprKind};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::autofix::Fix;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checks::{Check, CheckCode, CheckKind};
|
||||
|
||||
/// SIM118
|
||||
fn key_in_dict(checker: &mut Checker, left: &Expr, right: &Expr, range: Range) {
|
||||
let ExprKind::Call {
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
} = &right.node else {
|
||||
return;
|
||||
};
|
||||
if !(args.is_empty() && keywords.is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
let ExprKind::Attribute { attr, value, .. } = &func.node else {
|
||||
return;
|
||||
};
|
||||
if attr != "keys" {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut check = Check::new(
|
||||
CheckKind::KeyInDict(left.to_string(), value.to_string()),
|
||||
range,
|
||||
);
|
||||
if checker.patch(&CheckCode::SIM118) {
|
||||
let content = right.to_string().replace(".keys()", "");
|
||||
check.amend(Fix::replacement(
|
||||
content,
|
||||
right.location,
|
||||
right.end_location.unwrap(),
|
||||
));
|
||||
}
|
||||
checker.add_check(check);
|
||||
}
|
||||
|
||||
/// SIM118 in a for loop
|
||||
pub fn key_in_dict_for(checker: &mut Checker, target: &Expr, iter: &Expr) {
|
||||
key_in_dict(
|
||||
checker,
|
||||
target,
|
||||
iter,
|
||||
Range {
|
||||
location: target.location,
|
||||
end_location: iter.end_location.unwrap(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// SIM118 in a comparison
|
||||
pub fn key_in_dict_compare(
|
||||
checker: &mut Checker,
|
||||
expr: &Expr,
|
||||
left: &Expr,
|
||||
ops: &[Cmpop],
|
||||
comparators: &[Expr],
|
||||
) {
|
||||
if !matches!(ops[..], [Cmpop::In]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if comparators.len() != 1 {
|
||||
return;
|
||||
}
|
||||
let right = comparators.first().unwrap();
|
||||
|
||||
key_in_dict(checker, left, right, Range::from_located(expr));
|
||||
}
|
||||
3
src/flake8_simplify/plugins/mod.rs
Normal file
3
src/flake8_simplify/plugins/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
pub use key_in_dict::{key_in_dict_compare, key_in_dict_for};
|
||||
|
||||
mod key_in_dict;
|
||||
@@ -0,0 +1,77 @@
|
||||
---
|
||||
source: src/flake8_simplify/mod.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind:
|
||||
KeyInDict:
|
||||
- key
|
||||
- dict
|
||||
location:
|
||||
row: 1
|
||||
column: 0
|
||||
end_location:
|
||||
row: 1
|
||||
column: 18
|
||||
fix:
|
||||
content: dict
|
||||
location:
|
||||
row: 1
|
||||
column: 7
|
||||
end_location:
|
||||
row: 1
|
||||
column: 18
|
||||
- kind:
|
||||
KeyInDict:
|
||||
- "foo['bar']"
|
||||
- dict
|
||||
location:
|
||||
row: 3
|
||||
column: 0
|
||||
end_location:
|
||||
row: 3
|
||||
column: 25
|
||||
fix:
|
||||
content: dict
|
||||
location:
|
||||
row: 3
|
||||
column: 14
|
||||
end_location:
|
||||
row: 3
|
||||
column: 25
|
||||
- kind:
|
||||
KeyInDict:
|
||||
- foo()
|
||||
- dict
|
||||
location:
|
||||
row: 5
|
||||
column: 0
|
||||
end_location:
|
||||
row: 5
|
||||
column: 20
|
||||
fix:
|
||||
content: dict
|
||||
location:
|
||||
row: 5
|
||||
column: 9
|
||||
end_location:
|
||||
row: 5
|
||||
column: 20
|
||||
- kind:
|
||||
KeyInDict:
|
||||
- key
|
||||
- dict
|
||||
location:
|
||||
row: 7
|
||||
column: 4
|
||||
end_location:
|
||||
row: 7
|
||||
column: 22
|
||||
fix:
|
||||
content: dict
|
||||
location:
|
||||
row: 7
|
||||
column: 11
|
||||
end_location:
|
||||
row: 7
|
||||
column: 22
|
||||
|
||||
@@ -53,6 +53,7 @@ mod flake8_import_conventions;
|
||||
mod flake8_print;
|
||||
pub mod flake8_quotes;
|
||||
mod flake8_return;
|
||||
mod flake8_simplify;
|
||||
pub mod flake8_tidy_imports;
|
||||
mod flake8_unused_arguments;
|
||||
pub mod fs;
|
||||
|
||||
@@ -93,6 +93,7 @@ mod tests {
|
||||
#[test_case(CheckCode::F821, Path::new("F821_3.py"); "F821_3")]
|
||||
#[test_case(CheckCode::F821, Path::new("F821_4.py"); "F821_4")]
|
||||
#[test_case(CheckCode::F821, Path::new("F821_5.py"); "F821_5")]
|
||||
#[test_case(CheckCode::F821, Path::new("F821_6.py"); "F821_6")]
|
||||
#[test_case(CheckCode::F822, Path::new("F822.py"); "F822")]
|
||||
#[test_case(CheckCode::F823, Path::new("F823.py"); "F823")]
|
||||
#[test_case(CheckCode::F831, Path::new("F831.py"); "F831")]
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
source: src/pyflakes/mod.rs
|
||||
expression: checks
|
||||
---
|
||||
[]
|
||||
|
||||
@@ -20,7 +20,7 @@ pub struct Options {
|
||||
`RUF002`, and `RUF003`.
|
||||
"#,
|
||||
default = r#"[]"#,
|
||||
value_type = "Vec<char>",
|
||||
value_type = "Vec<a test>",
|
||||
example = r#"
|
||||
# Allow minus-sign (U+2212), greek-small-letter-rho (U+03C1), and the asterisk-operator (U+2217),
|
||||
# which could be confused for "-", "p", and "*", respectively.
|
||||
|
||||
Reference in New Issue
Block a user