Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5e9a8fcf53 | ||
|
|
76439235af | ||
|
|
0c9c6a1c1c | ||
|
|
46a99243cd | ||
|
|
d06dc4c72d | ||
|
|
8f6b2fb32b | ||
|
|
1d61db5b62 | ||
|
|
e15c0c68cb | ||
|
|
abb2adc4d8 | ||
|
|
e070166409 | ||
|
|
0ae6890094 | ||
|
|
21cace0973 | ||
|
|
4994b72ba2 | ||
|
|
dbb1a6e44b |
@@ -1,6 +1,6 @@
|
||||
repos:
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
rev: v0.0.155
|
||||
rev: v0.0.157
|
||||
hooks:
|
||||
- id: ruff
|
||||
|
||||
|
||||
6
Cargo.lock
generated
6
Cargo.lock
generated
@@ -703,7 +703,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.155-dev.0"
|
||||
version = "0.0.157-dev.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.0.22",
|
||||
@@ -1837,7 +1837,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.155"
|
||||
version = "0.0.157"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.9.1",
|
||||
"anyhow",
|
||||
@@ -1889,7 +1889,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_dev"
|
||||
version = "0.0.155"
|
||||
version = "0.0.157"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.0.22",
|
||||
|
||||
@@ -6,7 +6,7 @@ members = [
|
||||
|
||||
[package]
|
||||
name = "ruff"
|
||||
version = "0.0.155"
|
||||
version = "0.0.157"
|
||||
edition = "2021"
|
||||
rust-version = "1.65.0"
|
||||
|
||||
|
||||
76
README.md
76
README.md
@@ -87,13 +87,12 @@ of [Conda](https://docs.conda.io/en/latest/):
|
||||
1. [flake8-debugger (T10)](#flake8-debugger)
|
||||
1. [flake8-print (T20)](#flake8-print)
|
||||
1. [flake8-quotes (Q)](#flake8-quotes)
|
||||
1. [flake8-return (ET)](#flake8-return)
|
||||
1. [flake8-return (RET)](#flake8-return)
|
||||
1. [flake8-tidy-imports (I25)](#flake8-tidy-imports)
|
||||
1. [eradicate (ERA)](#eradicate)
|
||||
1. [pygrep-hooks (PGH)](#pygrep-hooks)
|
||||
1. [Pylint (PL)](#pylint)
|
||||
1. [Ruff-specific rules (RUF)](#ruff-specific-rules)
|
||||
1. [Meta rules (M)](#meta-rules)
|
||||
1. [Editor Integrations](#editor-integrations)
|
||||
1. [FAQ](#faq)
|
||||
1. [Development](#development)
|
||||
@@ -146,7 +145,7 @@ Ruff also works with [pre-commit](https://pre-commit.com):
|
||||
```yaml
|
||||
repos:
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
rev: v0.0.155
|
||||
rev: v0.0.157
|
||||
hooks:
|
||||
- id: ruff
|
||||
```
|
||||
@@ -767,12 +766,15 @@ For more, see [Pylint](https://pypi.org/project/pylint/2.15.7/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| PLC0414 | UselessImportAlias | Import alias does not rename original package | 🛠 |
|
||||
| PLC2201 | MisplacedComparisonConstant | Comparison should be ... | 🛠 |
|
||||
| PLC3002 | UnnecessaryDirectLambdaCall | Lambda expression called directly. Execute the expression inline instead. | |
|
||||
| PLE1142 | AwaitOutsideAsync | `await` should be used within an async function | |
|
||||
| PLR0206 | PropertyWithParameters | Cannot have defined parameters for properties | |
|
||||
| PLR0402 | ConsiderUsingFromImport | Consider using `from ... import ...` | |
|
||||
| PLR1701 | ConsiderMergingIsinstance | Consider merging these isinstance calls: `isinstance(..., (...))` | |
|
||||
| PLR1722 | ConsiderUsingSysExit | Consider using `sys.exit()` | 🛠 |
|
||||
| PLW0120 | UselessElseOnLoop | Else clause on loop without a break statement, remove the else and de-indent all the code inside it | |
|
||||
|
||||
### Ruff-specific rules
|
||||
|
||||
@@ -781,7 +783,6 @@ For more, see [Pylint](https://pypi.org/project/pylint/2.15.7/) on PyPI.
|
||||
| RUF001 | AmbiguousUnicodeCharacterString | String contains ambiguous unicode character '𝐁' (did you mean 'B'?) | 🛠 |
|
||||
| RUF002 | AmbiguousUnicodeCharacterDocstring | Docstring contains ambiguous unicode character '𝐁' (did you mean 'B'?) | 🛠 |
|
||||
| RUF003 | AmbiguousUnicodeCharacterComment | Comment contains ambiguous unicode character '𝐁' (did you mean 'B'?) | |
|
||||
| RUF004 | ConvertExitToSysExit | `exit()` is only available in the interpreter, use `sys.exit()` instead | 🛠 |
|
||||
| RUF100 | UnusedNOQA | Unused `noqa` directive | 🛠 |
|
||||
|
||||
<!-- End auto-generated sections. -->
|
||||
@@ -1269,25 +1270,6 @@ Summary
|
||||
|
||||
### Options
|
||||
|
||||
#### [`dummy_variable_rgx`](#dummy_variable_rgx)
|
||||
|
||||
A regular expression used to identify "dummy" variables, or those which should be ignored when evaluating
|
||||
(e.g.) unused-variable checks.
|
||||
|
||||
**Default value**: `"^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"` (matches `_`, `__`, and `_var`, but not `_var_`)
|
||||
|
||||
**Type**: `Regex`
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```toml
|
||||
[tool.ruff]
|
||||
# Only ignore variables named "_".
|
||||
dummy_variable_rgx = "^_$"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### [`exclude`](#exclude)
|
||||
|
||||
A list of file patterns to exclude from linting.
|
||||
@@ -1301,7 +1283,7 @@ Exclusions are based on globs, and can be either:
|
||||
(to exclude any Python files in `directory`). Note that these paths are relative to the
|
||||
project root (e.g., the directory containing your `pyproject.toml`).
|
||||
|
||||
Note that you'll typically want to use [`extend_exclude`](#extend-exclude) to modify the excluded
|
||||
Note that you'll typically want to use [`extend-exclude`](#extend-exclude) to modify the excluded
|
||||
paths.
|
||||
|
||||
**Default value**: `[".bzr", ".direnv", ".eggs", ".git", ".hg", ".mypy_cache", ".nox", ".pants.d", ".ruff_cache", ".svn", ".tox", ".venv", "__pypackages__", "_build", "buck-out", "build", "dist", "node_modules", "venv"]`
|
||||
@@ -1508,6 +1490,44 @@ line-length = 120
|
||||
|
||||
---
|
||||
|
||||
#### [`dummy-variable-rgx`](#dummy-variable-rgx)
|
||||
|
||||
A regular expression used to identify "dummy" variables, or those which should be ignored when evaluating
|
||||
(e.g.) unused-variable checks.
|
||||
|
||||
**Default value**: `"^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"` (matches `_`, `__`, and `_var`, but not `_var_`)
|
||||
|
||||
**Type**: `Regex`
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```toml
|
||||
[tool.ruff]
|
||||
# Only ignore variables named "_".
|
||||
dummy-variable-rgx = "^_$"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### [`ignore-init-module-imports`](#ignore-init-module-imports)
|
||||
|
||||
Avoid automatically removing unused imports in `__init__.py` files. Such imports will still be
|
||||
flagged, but with a dedicated message suggesting that the import is either added to the module's
|
||||
`__all__` symbol, or re-exported with a redundant alias (e.g., `import os as os`).
|
||||
|
||||
**Default value**: `false`
|
||||
|
||||
**Type**: `bool`
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```toml
|
||||
[tool.ruff]
|
||||
ignore-init-module-imports = true
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### [`format`](#format)
|
||||
|
||||
The style in which violation messages should be formatted: `"text"` (default), `"grouped"`
|
||||
@@ -1787,7 +1807,7 @@ ban-relative-imports = "all"
|
||||
|
||||
### `isort`
|
||||
|
||||
#### [`combine-as-imports`](combine-as-imports)
|
||||
#### [`combine-as-imports`](#combine-as-imports)
|
||||
|
||||
Combines as imports on the same line. See isort's [`combine-as-imports`](https://pycqa.github.io/isort/docs/configuration/options.html#combine-as-imports)
|
||||
option.
|
||||
@@ -1805,7 +1825,7 @@ combine-as-imports = true
|
||||
|
||||
---
|
||||
|
||||
#### [`known-first-party`](known-first-party)
|
||||
#### [`known-first-party`](#known-first-party)
|
||||
|
||||
A list of modules to consider first-party, regardless of whether they can be identified as such
|
||||
via introspection of the local filesystem.
|
||||
@@ -1823,7 +1843,7 @@ known-first-party = ["src"]
|
||||
|
||||
---
|
||||
|
||||
#### [`known-third-party`](known-third-party)
|
||||
#### [`known-third-party`](#known-third-party)
|
||||
|
||||
A list of modules to consider third-party, regardless of whether they can be identified as such
|
||||
via introspection of the local filesystem.
|
||||
@@ -1841,7 +1861,7 @@ known-third-party = ["fastapi"]
|
||||
|
||||
---
|
||||
|
||||
#### [`extra-standard-library`](extra-standard-library)
|
||||
#### [`extra-standard-library`](#extra-standard-library)
|
||||
|
||||
A list of modules to consider standard-library, in addition to those known to Ruff in advance.
|
||||
|
||||
|
||||
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.155"
|
||||
version = "0.0.157"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@@ -1975,7 +1975,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.155"
|
||||
version = "0.0.157"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.155-dev.0"
|
||||
version = "0.0.157-dev.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
|
||||
@@ -253,6 +253,7 @@ mod tests {
|
||||
fixable: None,
|
||||
format: None,
|
||||
ignore: Some(vec![]),
|
||||
ignore_init_module_imports: None,
|
||||
line_length: None,
|
||||
per_file_ignores: None,
|
||||
select: Some(vec![
|
||||
@@ -295,6 +296,7 @@ mod tests {
|
||||
fixable: None,
|
||||
format: None,
|
||||
ignore: Some(vec![]),
|
||||
ignore_init_module_imports: None,
|
||||
line_length: Some(100),
|
||||
per_file_ignores: None,
|
||||
select: Some(vec![
|
||||
@@ -337,6 +339,7 @@ mod tests {
|
||||
fixable: None,
|
||||
format: None,
|
||||
ignore: Some(vec![]),
|
||||
ignore_init_module_imports: None,
|
||||
line_length: Some(100),
|
||||
per_file_ignores: None,
|
||||
select: Some(vec![
|
||||
@@ -379,6 +382,7 @@ mod tests {
|
||||
fixable: None,
|
||||
format: None,
|
||||
ignore: Some(vec![]),
|
||||
ignore_init_module_imports: None,
|
||||
line_length: None,
|
||||
per_file_ignores: None,
|
||||
select: Some(vec![
|
||||
@@ -421,6 +425,7 @@ mod tests {
|
||||
fixable: None,
|
||||
format: None,
|
||||
ignore: Some(vec![]),
|
||||
ignore_init_module_imports: None,
|
||||
line_length: None,
|
||||
per_file_ignores: None,
|
||||
select: Some(vec![
|
||||
@@ -471,6 +476,7 @@ mod tests {
|
||||
fixable: None,
|
||||
format: None,
|
||||
ignore: Some(vec![]),
|
||||
ignore_init_module_imports: None,
|
||||
line_length: None,
|
||||
per_file_ignores: None,
|
||||
select: Some(vec![
|
||||
@@ -548,6 +554,7 @@ mod tests {
|
||||
fixable: None,
|
||||
format: None,
|
||||
ignore: Some(vec![]),
|
||||
ignore_init_module_imports: None,
|
||||
line_length: None,
|
||||
per_file_ignores: None,
|
||||
select: Some(vec![
|
||||
|
||||
1
resources/test/fixtures/flake8_print/T100.py
vendored
1
resources/test/fixtures/flake8_print/T100.py
vendored
@@ -2,6 +2,7 @@ breakpoint()
|
||||
|
||||
|
||||
import pdb
|
||||
import builtins
|
||||
from builtins import breakpoint
|
||||
from pdb import set_trace as st
|
||||
from celery.contrib.rdb import set_trace
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
exit(0)
|
||||
quit(0)
|
||||
|
||||
|
||||
def main():
|
||||
exit(2)
|
||||
quit(2)
|
||||
@@ -1,10 +1,12 @@
|
||||
import sys
|
||||
|
||||
exit(0)
|
||||
quit(0)
|
||||
|
||||
|
||||
def main():
|
||||
exit(1)
|
||||
quit(1)
|
||||
|
||||
|
||||
sys.exit(2)
|
||||
@@ -1,7 +1,9 @@
|
||||
import sys as sys2
|
||||
|
||||
exit(0)
|
||||
quit(0)
|
||||
|
||||
|
||||
def main():
|
||||
exit(1)
|
||||
quit(1)
|
||||
@@ -1,7 +1,9 @@
|
||||
from sys import exit
|
||||
|
||||
exit(0)
|
||||
quit(0)
|
||||
|
||||
|
||||
def main():
|
||||
exit(1)
|
||||
quit(1)
|
||||
@@ -1,7 +1,9 @@
|
||||
from sys import exit as exit2
|
||||
|
||||
exit(0)
|
||||
quit(0)
|
||||
|
||||
|
||||
def main():
|
||||
exit(1)
|
||||
quit(1)
|
||||
@@ -1,7 +1,9 @@
|
||||
from sys import *
|
||||
|
||||
exit(0)
|
||||
quit(0)
|
||||
|
||||
|
||||
def main():
|
||||
exit(1)
|
||||
quit(1)
|
||||
@@ -1,12 +1,19 @@
|
||||
exit(0)
|
||||
quit(0)
|
||||
|
||||
|
||||
def exit(e):
|
||||
pass
|
||||
|
||||
|
||||
def quit(e):
|
||||
pass
|
||||
|
||||
|
||||
exit(1)
|
||||
quit(1)
|
||||
|
||||
|
||||
def main():
|
||||
exit(2)
|
||||
quit(2)
|
||||
@@ -3,6 +3,7 @@
|
||||
# 1. useless-import-alias
|
||||
# 2. consider-using-from-import
|
||||
|
||||
import collections as collections # [useless-import-alias]
|
||||
from collections import OrderedDict as OrderedDict # [useless-import-alias]
|
||||
from collections import OrderedDict as o_dict
|
||||
import os.path as path # [consider-using-from-import]
|
||||
|
||||
103
resources/test/fixtures/pylint/useless_else_on_loop.py
vendored
Normal file
103
resources/test/fixtures/pylint/useless_else_on_loop.py
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
"""Check for else branches on loops with break and return only."""
|
||||
|
||||
|
||||
def test_return_for():
|
||||
"""else + return is not acceptable."""
|
||||
for i in range(10):
|
||||
if i % 2:
|
||||
return i
|
||||
else: # [useless-else-on-loop]
|
||||
print("math is broken")
|
||||
return None
|
||||
|
||||
|
||||
def test_return_while():
|
||||
"""else + return is not acceptable."""
|
||||
while True:
|
||||
return 1
|
||||
else: # [useless-else-on-loop]
|
||||
print("math is broken")
|
||||
return None
|
||||
|
||||
|
||||
while True:
|
||||
|
||||
def short_fun():
|
||||
"""A function with a loop."""
|
||||
for _ in range(10):
|
||||
break
|
||||
|
||||
else: # [useless-else-on-loop]
|
||||
print("or else!")
|
||||
|
||||
|
||||
while True:
|
||||
while False:
|
||||
break
|
||||
else: # [useless-else-on-loop]
|
||||
print("or else!")
|
||||
|
||||
for j in range(10):
|
||||
pass
|
||||
else: # [useless-else-on-loop]
|
||||
print("fat chance")
|
||||
for j in range(10):
|
||||
break
|
||||
|
||||
|
||||
def test_return_for2():
|
||||
"""no false positive for break in else
|
||||
|
||||
https://bitbucket.org/logilab/pylint/issue/117/useless-else-on-loop-false-positives
|
||||
"""
|
||||
for i in range(10):
|
||||
for _ in range(i):
|
||||
if i % 2:
|
||||
break
|
||||
else:
|
||||
break
|
||||
else:
|
||||
print("great math")
|
||||
|
||||
|
||||
def test_break_in_orelse_deep():
|
||||
"""no false positive for break in else deeply nested"""
|
||||
for _ in range(10):
|
||||
if 1 < 2: # pylint: disable=comparison-of-constants
|
||||
for _ in range(3):
|
||||
if 3 < 2: # pylint: disable=comparison-of-constants
|
||||
break
|
||||
else:
|
||||
break
|
||||
else:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def test_break_in_orelse_deep2():
|
||||
"""should rise a useless-else-on-loop message, as the break statement is only
|
||||
for the inner for loop
|
||||
"""
|
||||
for _ in range(10):
|
||||
if 1 < 2: # pylint: disable=comparison-of-constants
|
||||
for _ in range(3):
|
||||
if 3 < 2: # pylint: disable=comparison-of-constants
|
||||
break
|
||||
else:
|
||||
print("all right")
|
||||
else: # [useless-else-on-loop]
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def test_break_in_orelse_deep3():
|
||||
"""no false positive for break deeply nested in else"""
|
||||
for _ in range(10):
|
||||
for _ in range(3):
|
||||
pass
|
||||
else:
|
||||
if 1 < 2: # pylint: disable=comparison-of-constants
|
||||
break
|
||||
else:
|
||||
return True
|
||||
return False
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff_dev"
|
||||
version = "0.0.155"
|
||||
version = "0.0.157"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -61,15 +61,6 @@ pub fn dealias_call_path<'a>(
|
||||
}
|
||||
}
|
||||
|
||||
/// Return `true` if the `Expr` is a name or attribute reference to `${target}`.
|
||||
pub fn match_name_or_attr(expr: &Expr, target: &str) -> bool {
|
||||
match &expr.node {
|
||||
ExprKind::Attribute { attr, .. } => target == attr,
|
||||
ExprKind::Name { id, .. } => target == id,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return `true` if the `Expr` is a reference to `${module}.${target}`.
|
||||
///
|
||||
/// Useful for, e.g., ensuring that a `Union` reference represents
|
||||
|
||||
@@ -37,7 +37,7 @@ use crate::{
|
||||
docstrings, flake8_2020, flake8_annotations, flake8_bandit, flake8_blind_except,
|
||||
flake8_boolean_trap, flake8_bugbear, flake8_builtins, flake8_comprehensions, flake8_debugger,
|
||||
flake8_print, flake8_return, flake8_tidy_imports, mccabe, pep8_naming, pycodestyle, pydocstyle,
|
||||
pyflakes, pygrep_hooks, pylint, pyupgrade, rules,
|
||||
pyflakes, pygrep_hooks, pylint, pyupgrade,
|
||||
};
|
||||
|
||||
const GLOBAL_SCOPE_INDEX: usize = 0;
|
||||
@@ -669,6 +669,9 @@ where
|
||||
}
|
||||
|
||||
// pylint
|
||||
if self.settings.enabled.contains(&CheckCode::PLC0414) {
|
||||
pylint::plugins::useless_import_alias(self, alias);
|
||||
}
|
||||
if self.settings.enabled.contains(&CheckCode::PLR0402) {
|
||||
pylint::plugins::consider_using_from_import(self, alias);
|
||||
}
|
||||
@@ -965,6 +968,11 @@ where
|
||||
self.add_check(check);
|
||||
}
|
||||
}
|
||||
|
||||
// pylint
|
||||
if self.settings.enabled.contains(&CheckCode::PLC0414) {
|
||||
pylint::plugins::useless_import_alias(self, alias);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1009,16 +1017,27 @@ where
|
||||
flake8_bugbear::plugins::assert_raises_exception(self, stmt, items);
|
||||
}
|
||||
}
|
||||
StmtKind::While { .. } => {
|
||||
StmtKind::While { body, orelse, .. } => {
|
||||
if self.settings.enabled.contains(&CheckCode::B023) {
|
||||
flake8_bugbear::plugins::function_uses_loop_variable(self, &Node::Stmt(stmt));
|
||||
}
|
||||
if self.settings.enabled.contains(&CheckCode::PLW0120) {
|
||||
pylint::plugins::useless_else_on_loop(self, stmt, body, orelse);
|
||||
}
|
||||
}
|
||||
StmtKind::For {
|
||||
target, body, iter, ..
|
||||
target,
|
||||
body,
|
||||
iter,
|
||||
orelse,
|
||||
..
|
||||
}
|
||||
| StmtKind::AsyncFor {
|
||||
target, body, iter, ..
|
||||
target,
|
||||
body,
|
||||
iter,
|
||||
orelse,
|
||||
..
|
||||
} => {
|
||||
if self.settings.enabled.contains(&CheckCode::B007) {
|
||||
flake8_bugbear::plugins::unused_loop_control_variable(self, target, body);
|
||||
@@ -1029,6 +1048,9 @@ where
|
||||
if self.settings.enabled.contains(&CheckCode::B023) {
|
||||
flake8_bugbear::plugins::function_uses_loop_variable(self, &Node::Stmt(stmt));
|
||||
}
|
||||
if self.settings.enabled.contains(&CheckCode::PLW0120) {
|
||||
pylint::plugins::useless_else_on_loop(self, stmt, body, orelse);
|
||||
}
|
||||
}
|
||||
StmtKind::Try { handlers, .. } => {
|
||||
if self.settings.enabled.contains(&CheckCode::F707) {
|
||||
@@ -1735,10 +1757,8 @@ where
|
||||
if self.settings.enabled.contains(&CheckCode::PLC3002) {
|
||||
pylint::plugins::unnecessary_direct_lambda_call(self, expr, func);
|
||||
}
|
||||
|
||||
// Ruff
|
||||
if self.settings.enabled.contains(&CheckCode::RUF004) {
|
||||
rules::plugins::convert_exit_to_sys_exit(self, func);
|
||||
if self.settings.enabled.contains(&CheckCode::PLR1722) {
|
||||
pylint::plugins::consider_using_sys_exit(self, func);
|
||||
}
|
||||
}
|
||||
ExprKind::Dict { keys, .. } => {
|
||||
@@ -3075,8 +3095,9 @@ impl<'a> Checker<'a> {
|
||||
let child = self.parents[defined_by];
|
||||
let parent = defined_in.map(|defined_in| self.parents[defined_in]);
|
||||
|
||||
let in_init_py = self.path.ends_with("__init__.py");
|
||||
let fix = if !in_init_py && self.patch(&CheckCode::F401) {
|
||||
let ignore_init = self.settings.ignore_init_module_imports
|
||||
&& self.path.ends_with("__init__.py");
|
||||
let fix = if !ignore_init && self.patch(&CheckCode::F401) {
|
||||
let deleted: Vec<&Stmt> = self
|
||||
.deletions
|
||||
.iter()
|
||||
@@ -3106,7 +3127,7 @@ impl<'a> Checker<'a> {
|
||||
|
||||
for (full_name, range) in unused_imports {
|
||||
let mut check = Check::new(
|
||||
CheckKind::UnusedImport(full_name.clone(), in_init_py),
|
||||
CheckKind::UnusedImport(full_name.clone(), ignore_init),
|
||||
*range,
|
||||
);
|
||||
if let Some(fix) = fix.as_ref() {
|
||||
|
||||
@@ -93,12 +93,15 @@ pub enum CheckCode {
|
||||
F841,
|
||||
F901,
|
||||
// pylint
|
||||
PLC0414,
|
||||
PLC2201,
|
||||
PLC3002,
|
||||
PLE1142,
|
||||
PLR0206,
|
||||
PLR0402,
|
||||
PLR1701,
|
||||
PLR1722,
|
||||
PLW0120,
|
||||
// flake8-builtins
|
||||
A001,
|
||||
A002,
|
||||
@@ -291,7 +294,6 @@ pub enum CheckCode {
|
||||
RUF001,
|
||||
RUF002,
|
||||
RUF003,
|
||||
RUF004,
|
||||
RUF100,
|
||||
// pygrep-hooks
|
||||
PGH001,
|
||||
@@ -574,11 +576,14 @@ pub enum CheckKind {
|
||||
YieldOutsideFunction(DeferralKeyword),
|
||||
// pylint
|
||||
ConsiderMergingIsinstance(String, Vec<String>),
|
||||
UselessImportAlias,
|
||||
MisplacedComparisonConstant(String),
|
||||
UnnecessaryDirectLambdaCall,
|
||||
PropertyWithParameters,
|
||||
ConsiderUsingFromImport(String, String),
|
||||
AwaitOutsideAsync,
|
||||
UselessElseOnLoop,
|
||||
ConsiderUsingSysExit,
|
||||
// flake8-builtins
|
||||
BuiltinVariableShadowing(String),
|
||||
BuiltinArgumentShadowing(String),
|
||||
@@ -773,7 +778,6 @@ pub enum CheckKind {
|
||||
AmbiguousUnicodeCharacterString(char, char),
|
||||
AmbiguousUnicodeCharacterDocstring(char, char),
|
||||
AmbiguousUnicodeCharacterComment(char, char),
|
||||
ConvertExitToSysExit,
|
||||
UnusedNOQA(Option<Vec<String>>),
|
||||
}
|
||||
|
||||
@@ -871,6 +875,7 @@ impl CheckCode {
|
||||
CheckCode::F841 => CheckKind::UnusedVariable("...".to_string()),
|
||||
CheckCode::F901 => CheckKind::RaiseNotImplemented,
|
||||
// pylint
|
||||
CheckCode::PLC0414 => CheckKind::UselessImportAlias,
|
||||
CheckCode::PLC2201 => CheckKind::MisplacedComparisonConstant("...".to_string()),
|
||||
CheckCode::PLC3002 => CheckKind::UnnecessaryDirectLambdaCall,
|
||||
CheckCode::PLE1142 => CheckKind::AwaitOutsideAsync,
|
||||
@@ -881,6 +886,8 @@ impl CheckCode {
|
||||
CheckCode::PLR1701 => {
|
||||
CheckKind::ConsiderMergingIsinstance("...".to_string(), vec!["...".to_string()])
|
||||
}
|
||||
CheckCode::PLR1722 => CheckKind::ConsiderUsingSysExit,
|
||||
CheckCode::PLW0120 => CheckKind::UselessElseOnLoop,
|
||||
// flake8-builtins
|
||||
CheckCode::A001 => CheckKind::BuiltinVariableShadowing("...".to_string()),
|
||||
CheckCode::A002 => CheckKind::BuiltinArgumentShadowing("...".to_string()),
|
||||
@@ -1110,7 +1117,6 @@ impl CheckCode {
|
||||
CheckCode::RUF001 => CheckKind::AmbiguousUnicodeCharacterString('𝐁', 'B'),
|
||||
CheckCode::RUF002 => CheckKind::AmbiguousUnicodeCharacterDocstring('𝐁', 'B'),
|
||||
CheckCode::RUF003 => CheckKind::AmbiguousUnicodeCharacterComment('𝐁', 'B'),
|
||||
CheckCode::RUF004 => CheckKind::ConvertExitToSysExit,
|
||||
CheckCode::RUF100 => CheckKind::UnusedNOQA(None),
|
||||
}
|
||||
}
|
||||
@@ -1299,12 +1305,15 @@ impl CheckCode {
|
||||
CheckCode::N817 => CheckCategory::PEP8Naming,
|
||||
CheckCode::N818 => CheckCategory::PEP8Naming,
|
||||
CheckCode::PGH001 => CheckCategory::PygrepHooks,
|
||||
CheckCode::PLC0414 => CheckCategory::Pylint,
|
||||
CheckCode::PLC2201 => CheckCategory::Pylint,
|
||||
CheckCode::PLC3002 => CheckCategory::Pylint,
|
||||
CheckCode::PLE1142 => CheckCategory::Pylint,
|
||||
CheckCode::PLR0206 => CheckCategory::Pylint,
|
||||
CheckCode::PLR0402 => CheckCategory::Pylint,
|
||||
CheckCode::PLR1701 => CheckCategory::Pylint,
|
||||
CheckCode::PLR1722 => CheckCategory::Pylint,
|
||||
CheckCode::PLW0120 => CheckCategory::Pylint,
|
||||
CheckCode::Q000 => CheckCategory::Flake8Quotes,
|
||||
CheckCode::Q001 => CheckCategory::Flake8Quotes,
|
||||
CheckCode::Q002 => CheckCategory::Flake8Quotes,
|
||||
@@ -1320,7 +1329,6 @@ impl CheckCode {
|
||||
CheckCode::RUF001 => CheckCategory::Ruff,
|
||||
CheckCode::RUF002 => CheckCategory::Ruff,
|
||||
CheckCode::RUF003 => CheckCategory::Ruff,
|
||||
CheckCode::RUF004 => CheckCategory::Ruff,
|
||||
CheckCode::RUF100 => CheckCategory::Ruff,
|
||||
CheckCode::S101 => CheckCategory::Flake8Bandit,
|
||||
CheckCode::S102 => CheckCategory::Flake8Bandit,
|
||||
@@ -1426,12 +1434,15 @@ impl CheckKind {
|
||||
CheckKind::NoNewLineAtEndOfFile => &CheckCode::W292,
|
||||
CheckKind::InvalidEscapeSequence(_) => &CheckCode::W605,
|
||||
// pylint
|
||||
CheckKind::UselessImportAlias => &CheckCode::PLC0414,
|
||||
CheckKind::MisplacedComparisonConstant(..) => &CheckCode::PLC2201,
|
||||
CheckKind::UnnecessaryDirectLambdaCall => &CheckCode::PLC3002,
|
||||
CheckKind::AwaitOutsideAsync => &CheckCode::PLE1142,
|
||||
CheckKind::ConsiderMergingIsinstance(..) => &CheckCode::PLR1701,
|
||||
CheckKind::PropertyWithParameters => &CheckCode::PLR0206,
|
||||
CheckKind::ConsiderUsingFromImport(..) => &CheckCode::PLR0402,
|
||||
CheckKind::ConsiderUsingSysExit => &CheckCode::PLR1722,
|
||||
CheckKind::UselessElseOnLoop => &CheckCode::PLW0120,
|
||||
// flake8-builtins
|
||||
CheckKind::BuiltinVariableShadowing(_) => &CheckCode::A001,
|
||||
CheckKind::BuiltinArgumentShadowing(_) => &CheckCode::A002,
|
||||
@@ -1626,7 +1637,6 @@ impl CheckKind {
|
||||
CheckKind::AmbiguousUnicodeCharacterString(..) => &CheckCode::RUF001,
|
||||
CheckKind::AmbiguousUnicodeCharacterDocstring(..) => &CheckCode::RUF002,
|
||||
CheckKind::AmbiguousUnicodeCharacterComment(..) => &CheckCode::RUF003,
|
||||
CheckKind::ConvertExitToSysExit => &CheckCode::RUF004,
|
||||
CheckKind::UnusedNOQA(_) => &CheckCode::RUF100,
|
||||
}
|
||||
}
|
||||
@@ -1793,9 +1803,12 @@ impl CheckKind {
|
||||
CheckKind::UndefinedName(name) => {
|
||||
format!("Undefined name `{name}`")
|
||||
}
|
||||
CheckKind::UnusedImport(name, in_init_py) => {
|
||||
if *in_init_py {
|
||||
format!("`{name}` imported but unused and missing from `__all__`")
|
||||
CheckKind::UnusedImport(name, ignore_init) => {
|
||||
if *ignore_init {
|
||||
format!(
|
||||
"`{name}` imported but unused; consider adding to `__all__` or using a \
|
||||
redundant alias"
|
||||
)
|
||||
} else {
|
||||
format!("`{name}` imported but unused")
|
||||
}
|
||||
@@ -1812,6 +1825,9 @@ impl CheckKind {
|
||||
format!("Invalid escape sequence: '\\{char}'")
|
||||
}
|
||||
// pylint
|
||||
CheckKind::UselessImportAlias => {
|
||||
"Import alias does not rename original package".to_string()
|
||||
}
|
||||
CheckKind::ConsiderMergingIsinstance(obj, types) => {
|
||||
let types = types.join(", ");
|
||||
format!("Consider merging these isinstance calls: `isinstance({obj}, ({types}))`")
|
||||
@@ -1831,6 +1847,10 @@ impl CheckKind {
|
||||
CheckKind::AwaitOutsideAsync => {
|
||||
"`await` should be used within an async function".to_string()
|
||||
}
|
||||
CheckKind::UselessElseOnLoop => "Else clause on loop without a break statement, \
|
||||
remove the else and de-indent all the code inside it"
|
||||
.to_string(),
|
||||
CheckKind::ConsiderUsingSysExit => "Consider using `sys.exit()`".to_string(),
|
||||
// flake8-builtins
|
||||
CheckKind::BuiltinVariableShadowing(name) => {
|
||||
format!("Variable `{name}` is shadowing a python builtin")
|
||||
@@ -2418,9 +2438,6 @@ impl CheckKind {
|
||||
'{representant}'?)"
|
||||
)
|
||||
}
|
||||
CheckKind::ConvertExitToSysExit => "`exit()` is only available in the interpreter, \
|
||||
use `sys.exit()` instead"
|
||||
.to_string(),
|
||||
CheckKind::UnusedNOQA(codes) => match codes {
|
||||
None => "Unused `noqa` directive".to_string(),
|
||||
Some(codes) => {
|
||||
@@ -2472,7 +2489,7 @@ impl CheckKind {
|
||||
| CheckKind::BlankLineBeforeSection(..)
|
||||
| CheckKind::CapitalizeSectionName(..)
|
||||
| CheckKind::CommentedOutCode
|
||||
| CheckKind::ConvertExitToSysExit
|
||||
| CheckKind::ConsiderUsingSysExit
|
||||
| CheckKind::ConvertNamedTupleFunctionalToClass(..)
|
||||
| CheckKind::ConvertTypedDictFunctionalToClass(..)
|
||||
| CheckKind::DashedUnderlineAfterSection(..)
|
||||
@@ -2536,6 +2553,7 @@ impl CheckKind {
|
||||
| CheckKind::UnusedNOQA(..)
|
||||
| CheckKind::UsePEP585Annotation(..)
|
||||
| CheckKind::UsePEP604Annotation
|
||||
| CheckKind::UselessImportAlias
|
||||
| CheckKind::UselessMetaclassType
|
||||
| CheckKind::UselessObjectInheritance(..)
|
||||
)
|
||||
|
||||
@@ -280,6 +280,10 @@ pub enum CheckCodePrefix {
|
||||
PGH00,
|
||||
PGH001,
|
||||
PLC,
|
||||
PLC0,
|
||||
PLC04,
|
||||
PLC041,
|
||||
PLC0414,
|
||||
PLC2,
|
||||
PLC22,
|
||||
PLC220,
|
||||
@@ -305,6 +309,13 @@ pub enum CheckCodePrefix {
|
||||
PLR17,
|
||||
PLR170,
|
||||
PLR1701,
|
||||
PLR172,
|
||||
PLR1722,
|
||||
PLW,
|
||||
PLW0,
|
||||
PLW01,
|
||||
PLW012,
|
||||
PLW0120,
|
||||
Q,
|
||||
Q0,
|
||||
Q00,
|
||||
@@ -329,7 +340,6 @@ pub enum CheckCodePrefix {
|
||||
RUF001,
|
||||
RUF002,
|
||||
RUF003,
|
||||
RUF004,
|
||||
RUF1,
|
||||
RUF10,
|
||||
RUF100,
|
||||
@@ -1200,7 +1210,13 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::PGH0 => vec![CheckCode::PGH001],
|
||||
CheckCodePrefix::PGH00 => vec![CheckCode::PGH001],
|
||||
CheckCodePrefix::PGH001 => vec![CheckCode::PGH001],
|
||||
CheckCodePrefix::PLC => vec![CheckCode::PLC2201, CheckCode::PLC3002],
|
||||
CheckCodePrefix::PLC => {
|
||||
vec![CheckCode::PLC0414, CheckCode::PLC2201, CheckCode::PLC3002]
|
||||
}
|
||||
CheckCodePrefix::PLC0 => vec![CheckCode::PLC0414],
|
||||
CheckCodePrefix::PLC04 => vec![CheckCode::PLC0414],
|
||||
CheckCodePrefix::PLC041 => vec![CheckCode::PLC0414],
|
||||
CheckCodePrefix::PLC0414 => vec![CheckCode::PLC0414],
|
||||
CheckCodePrefix::PLC2 => vec![CheckCode::PLC2201],
|
||||
CheckCodePrefix::PLC22 => vec![CheckCode::PLC2201],
|
||||
CheckCodePrefix::PLC220 => vec![CheckCode::PLC2201],
|
||||
@@ -1214,9 +1230,12 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::PLE11 => vec![CheckCode::PLE1142],
|
||||
CheckCodePrefix::PLE114 => vec![CheckCode::PLE1142],
|
||||
CheckCodePrefix::PLE1142 => vec![CheckCode::PLE1142],
|
||||
CheckCodePrefix::PLR => {
|
||||
vec![CheckCode::PLR0206, CheckCode::PLR0402, CheckCode::PLR1701]
|
||||
}
|
||||
CheckCodePrefix::PLR => vec![
|
||||
CheckCode::PLR0206,
|
||||
CheckCode::PLR0402,
|
||||
CheckCode::PLR1701,
|
||||
CheckCode::PLR1722,
|
||||
],
|
||||
CheckCodePrefix::PLR0 => vec![CheckCode::PLR0206, CheckCode::PLR0402],
|
||||
CheckCodePrefix::PLR02 => vec![CheckCode::PLR0206],
|
||||
CheckCodePrefix::PLR020 => vec![CheckCode::PLR0206],
|
||||
@@ -1224,10 +1243,17 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::PLR04 => vec![CheckCode::PLR0402],
|
||||
CheckCodePrefix::PLR040 => vec![CheckCode::PLR0402],
|
||||
CheckCodePrefix::PLR0402 => vec![CheckCode::PLR0402],
|
||||
CheckCodePrefix::PLR1 => vec![CheckCode::PLR1701],
|
||||
CheckCodePrefix::PLR17 => vec![CheckCode::PLR1701],
|
||||
CheckCodePrefix::PLR1 => vec![CheckCode::PLR1701, CheckCode::PLR1722],
|
||||
CheckCodePrefix::PLR17 => vec![CheckCode::PLR1701, CheckCode::PLR1722],
|
||||
CheckCodePrefix::PLR170 => vec![CheckCode::PLR1701],
|
||||
CheckCodePrefix::PLR1701 => vec![CheckCode::PLR1701],
|
||||
CheckCodePrefix::PLR172 => vec![CheckCode::PLR1722],
|
||||
CheckCodePrefix::PLR1722 => vec![CheckCode::PLR1722],
|
||||
CheckCodePrefix::PLW => vec![CheckCode::PLW0120],
|
||||
CheckCodePrefix::PLW0 => vec![CheckCode::PLW0120],
|
||||
CheckCodePrefix::PLW01 => vec![CheckCode::PLW0120],
|
||||
CheckCodePrefix::PLW012 => vec![CheckCode::PLW0120],
|
||||
CheckCodePrefix::PLW0120 => vec![CheckCode::PLW0120],
|
||||
CheckCodePrefix::Q => vec![
|
||||
CheckCode::Q000,
|
||||
CheckCode::Q001,
|
||||
@@ -1292,25 +1318,13 @@ impl CheckCodePrefix {
|
||||
CheckCode::RUF001,
|
||||
CheckCode::RUF002,
|
||||
CheckCode::RUF003,
|
||||
CheckCode::RUF004,
|
||||
CheckCode::RUF100,
|
||||
],
|
||||
CheckCodePrefix::RUF0 => vec![
|
||||
CheckCode::RUF001,
|
||||
CheckCode::RUF002,
|
||||
CheckCode::RUF003,
|
||||
CheckCode::RUF004,
|
||||
],
|
||||
CheckCodePrefix::RUF00 => vec![
|
||||
CheckCode::RUF001,
|
||||
CheckCode::RUF002,
|
||||
CheckCode::RUF003,
|
||||
CheckCode::RUF004,
|
||||
],
|
||||
CheckCodePrefix::RUF0 => vec![CheckCode::RUF001, CheckCode::RUF002, CheckCode::RUF003],
|
||||
CheckCodePrefix::RUF00 => vec![CheckCode::RUF001, CheckCode::RUF002, CheckCode::RUF003],
|
||||
CheckCodePrefix::RUF001 => vec![CheckCode::RUF001],
|
||||
CheckCodePrefix::RUF002 => vec![CheckCode::RUF002],
|
||||
CheckCodePrefix::RUF003 => vec![CheckCode::RUF003],
|
||||
CheckCodePrefix::RUF004 => vec![CheckCode::RUF004],
|
||||
CheckCodePrefix::RUF1 => vec![CheckCode::RUF100],
|
||||
CheckCodePrefix::RUF10 => vec![CheckCode::RUF100],
|
||||
CheckCodePrefix::RUF100 => vec![CheckCode::RUF100],
|
||||
@@ -1917,6 +1931,10 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::PGH00 => SuffixLength::Two,
|
||||
CheckCodePrefix::PGH001 => SuffixLength::Three,
|
||||
CheckCodePrefix::PLC => SuffixLength::Zero,
|
||||
CheckCodePrefix::PLC0 => SuffixLength::One,
|
||||
CheckCodePrefix::PLC04 => SuffixLength::Two,
|
||||
CheckCodePrefix::PLC041 => SuffixLength::Three,
|
||||
CheckCodePrefix::PLC0414 => SuffixLength::Four,
|
||||
CheckCodePrefix::PLC2 => SuffixLength::One,
|
||||
CheckCodePrefix::PLC22 => SuffixLength::Two,
|
||||
CheckCodePrefix::PLC220 => SuffixLength::Three,
|
||||
@@ -1942,6 +1960,13 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::PLR17 => SuffixLength::Two,
|
||||
CheckCodePrefix::PLR170 => SuffixLength::Three,
|
||||
CheckCodePrefix::PLR1701 => SuffixLength::Four,
|
||||
CheckCodePrefix::PLR172 => SuffixLength::Three,
|
||||
CheckCodePrefix::PLR1722 => SuffixLength::Four,
|
||||
CheckCodePrefix::PLW => SuffixLength::Zero,
|
||||
CheckCodePrefix::PLW0 => SuffixLength::One,
|
||||
CheckCodePrefix::PLW01 => SuffixLength::Two,
|
||||
CheckCodePrefix::PLW012 => SuffixLength::Three,
|
||||
CheckCodePrefix::PLW0120 => SuffixLength::Four,
|
||||
CheckCodePrefix::Q => SuffixLength::Zero,
|
||||
CheckCodePrefix::Q0 => SuffixLength::One,
|
||||
CheckCodePrefix::Q00 => SuffixLength::Two,
|
||||
@@ -1966,7 +1991,6 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::RUF001 => SuffixLength::Three,
|
||||
CheckCodePrefix::RUF002 => SuffixLength::Three,
|
||||
CheckCodePrefix::RUF003 => SuffixLength::Three,
|
||||
CheckCodePrefix::RUF004 => SuffixLength::Three,
|
||||
CheckCodePrefix::RUF1 => SuffixLength::One,
|
||||
CheckCodePrefix::RUF10 => SuffixLength::Two,
|
||||
CheckCodePrefix::RUF100 => SuffixLength::Three,
|
||||
@@ -2068,6 +2092,7 @@ pub const CATEGORIES: &[CheckCodePrefix] = &[
|
||||
CheckCodePrefix::PLC,
|
||||
CheckCodePrefix::PLE,
|
||||
CheckCodePrefix::PLR,
|
||||
CheckCodePrefix::PLW,
|
||||
CheckCodePrefix::Q,
|
||||
CheckCodePrefix::RET,
|
||||
CheckCodePrefix::RUF,
|
||||
|
||||
@@ -211,7 +211,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
.chain(args.kwonlyargs.iter())
|
||||
.skip(
|
||||
// If this is a non-static method, skip `cls` or `self`.
|
||||
usize::from(!visibility::is_staticmethod(stmt)),
|
||||
usize::from(!visibility::is_staticmethod(checker, stmt)),
|
||||
)
|
||||
{
|
||||
// ANN401 for dynamically typed arguments
|
||||
@@ -283,10 +283,10 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
}
|
||||
|
||||
// ANN101, ANN102
|
||||
if !visibility::is_staticmethod(stmt) {
|
||||
if !visibility::is_staticmethod(checker, stmt) {
|
||||
if let Some(arg) = args.args.first() {
|
||||
if arg.node.annotation.is_none() {
|
||||
if visibility::is_classmethod(stmt) {
|
||||
if visibility::is_classmethod(checker, stmt) {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN102) {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingTypeCls(arg.node.arg.to_string()),
|
||||
@@ -319,14 +319,14 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
|
||||
return;
|
||||
}
|
||||
|
||||
if visibility::is_classmethod(stmt) {
|
||||
if visibility::is_classmethod(checker, stmt) {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN206) {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingReturnTypeClassMethod(name.to_string()),
|
||||
Range::from_located(stmt),
|
||||
));
|
||||
}
|
||||
} else if visibility::is_staticmethod(stmt) {
|
||||
} else if visibility::is_staticmethod(checker, stmt) {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN205) {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingReturnTypeStaticMethod(name.to_string()),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use rustpython_ast::{ExprKind, Stmt, Withitem};
|
||||
|
||||
use crate::ast::helpers::match_name_or_attr;
|
||||
use crate::ast::helpers::match_module_member;
|
||||
use crate::ast::types::Range;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checks::{Check, CheckKind};
|
||||
@@ -12,8 +12,14 @@ pub fn assert_raises_exception(checker: &mut Checker, stmt: &Stmt, items: &[With
|
||||
if let ExprKind::Call { func, args, .. } = &item_context.node {
|
||||
if args.len() == 1
|
||||
&& item.optional_vars.is_none()
|
||||
&& match_name_or_attr(func, "assertRaises")
|
||||
&& match_name_or_attr(args.first().unwrap(), "Exception")
|
||||
&& matches!(&func.node, ExprKind::Attribute { attr, .. } if attr == "assertRaises")
|
||||
&& match_module_member(
|
||||
args.first().unwrap(),
|
||||
"",
|
||||
"Exception",
|
||||
&checker.from_imports,
|
||||
&checker.import_aliases,
|
||||
)
|
||||
{
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::NoAssertRaisesException,
|
||||
|
||||
@@ -41,6 +41,12 @@ pub fn debugger_call(
|
||||
|
||||
/// Checks for the presence of a debugger import.
|
||||
pub fn debugger_import(stmt: &Stmt, module: Option<&str>, name: &str) -> Option<Check> {
|
||||
// Special-case: allow `import builtins`, which is far more general than (e.g.)
|
||||
// `import celery.contrib.rdb`).
|
||||
if module.is_none() && name == "builtins" {
|
||||
return None;
|
||||
}
|
||||
|
||||
if let Some(module) = module {
|
||||
if let Some((module_name, member)) = DEBUGGERS
|
||||
.iter()
|
||||
|
||||
@@ -26,70 +26,70 @@ expression: checks
|
||||
Debugger:
|
||||
Import: builtins.breakpoint
|
||||
location:
|
||||
row: 5
|
||||
row: 6
|
||||
column: 0
|
||||
end_location:
|
||||
row: 5
|
||||
row: 6
|
||||
column: 31
|
||||
fix: ~
|
||||
- kind:
|
||||
Debugger:
|
||||
Import: pdb.set_trace
|
||||
location:
|
||||
row: 6
|
||||
row: 7
|
||||
column: 0
|
||||
end_location:
|
||||
row: 6
|
||||
row: 7
|
||||
column: 31
|
||||
fix: ~
|
||||
- kind:
|
||||
Debugger:
|
||||
Import: celery.contrib.rdb.set_trace
|
||||
location:
|
||||
row: 7
|
||||
row: 8
|
||||
column: 0
|
||||
end_location:
|
||||
row: 7
|
||||
row: 8
|
||||
column: 40
|
||||
fix: ~
|
||||
- kind:
|
||||
Debugger:
|
||||
Import: celery.contrib.rdb
|
||||
location:
|
||||
row: 9
|
||||
row: 10
|
||||
column: 0
|
||||
end_location:
|
||||
row: 9
|
||||
row: 10
|
||||
column: 25
|
||||
fix: ~
|
||||
- kind:
|
||||
Debugger:
|
||||
Call: breakpoint
|
||||
location:
|
||||
row: 12
|
||||
row: 13
|
||||
column: 0
|
||||
end_location:
|
||||
row: 12
|
||||
row: 13
|
||||
column: 12
|
||||
fix: ~
|
||||
- kind:
|
||||
Debugger:
|
||||
Call: set_trace
|
||||
location:
|
||||
row: 13
|
||||
row: 14
|
||||
column: 0
|
||||
end_location:
|
||||
row: 13
|
||||
row: 14
|
||||
column: 4
|
||||
fix: ~
|
||||
- kind:
|
||||
Debugger:
|
||||
Call: set_trace
|
||||
location:
|
||||
row: 14
|
||||
row: 15
|
||||
column: 0
|
||||
end_location:
|
||||
row: 14
|
||||
row: 15
|
||||
column: 11
|
||||
fix: ~
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ pub fn not_missing(
|
||||
false
|
||||
}
|
||||
DefinitionKind::Function(stmt) | DefinitionKind::NestedFunction(stmt) => {
|
||||
if is_overload(stmt) {
|
||||
if is_overload(checker, stmt) {
|
||||
true
|
||||
} else {
|
||||
if checker.settings.enabled.contains(&CheckCode::D103) {
|
||||
@@ -89,7 +89,7 @@ pub fn not_missing(
|
||||
}
|
||||
}
|
||||
DefinitionKind::Method(stmt) => {
|
||||
if is_overload(stmt) || is_override(stmt) {
|
||||
if is_overload(checker, stmt) || is_override(checker, stmt) {
|
||||
true
|
||||
} else if is_magic(stmt) {
|
||||
if checker.settings.enabled.contains(&CheckCode::D105) {
|
||||
@@ -367,11 +367,24 @@ pub fn blank_after_summary(checker: &mut Checker, definition: &Definition) {
|
||||
Range::from_located(docstring),
|
||||
);
|
||||
if checker.patch(check.kind.code()) {
|
||||
// Find the "summary" line (defined as the first non-blank line).
|
||||
let mut summary_line = 0;
|
||||
for line in string.lines() {
|
||||
if line.trim().is_empty() {
|
||||
summary_line += 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Insert one blank line after the summary (replacing any existing lines).
|
||||
check.amend(Fix::replacement(
|
||||
"\n".to_string(),
|
||||
Location::new(docstring.location.row() + 1, 0),
|
||||
Location::new(docstring.location.row() + 1 + blanks_count, 0),
|
||||
Location::new(docstring.location.row() + summary_line + 1, 0),
|
||||
Location::new(
|
||||
docstring.location.row() + summary_line + 1 + blanks_count,
|
||||
0,
|
||||
),
|
||||
));
|
||||
}
|
||||
checker.add_check(check);
|
||||
@@ -835,7 +848,7 @@ pub fn if_needed(checker: &mut Checker, definition: &Definition) {
|
||||
| DefinitionKind::NestedFunction(stmt)
|
||||
| DefinitionKind::Method(stmt) = definition.kind
|
||||
{
|
||||
if is_overload(stmt) {
|
||||
if is_overload(checker, stmt) {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::SkipDocstring,
|
||||
Range::from_located(stmt),
|
||||
@@ -1319,7 +1332,7 @@ fn missing_args(checker: &mut Checker, definition: &Definition, docstrings_args:
|
||||
// If this is a non-static method, skip `cls` or `self`.
|
||||
usize::from(
|
||||
matches!(definition.kind, DefinitionKind::Method(_))
|
||||
&& !is_staticmethod(parent),
|
||||
&& !is_staticmethod(checker, parent),
|
||||
),
|
||||
)
|
||||
{
|
||||
|
||||
@@ -11,14 +11,23 @@ mod tests {
|
||||
use crate::linter::test_path;
|
||||
use crate::Settings;
|
||||
|
||||
#[test_case(CheckCode::PLC0414, Path::new("import_aliasing.py"); "PLC0414")]
|
||||
#[test_case(CheckCode::PLC2201, Path::new("misplaced_comparison_constant.py"); "PLC2201")]
|
||||
#[test_case(CheckCode::PLC3002, Path::new("unnecessary_direct_lambda_call.py"); "PLC3002")]
|
||||
#[test_case(CheckCode::PLE1142, Path::new("await_outside_async.py"); "PLE1142")]
|
||||
#[test_case(CheckCode::PLR0206, Path::new("property_with_parameters.py"); "PLR0206")]
|
||||
#[test_case(CheckCode::PLR0402, Path::new("import_aliasing.py"); "PLR0402")]
|
||||
#[test_case(CheckCode::PLR1701, Path::new("consider_merging_isinstance.py"); "PLR1701")]
|
||||
#[test_case(CheckCode::PLR1722, Path::new("consider_using_sys_exit_0.py"); "PLR1722_0")]
|
||||
#[test_case(CheckCode::PLR1722, Path::new("consider_using_sys_exit_1.py"); "PLR1722_1")]
|
||||
#[test_case(CheckCode::PLR1722, Path::new("consider_using_sys_exit_2.py"); "PLR1722_2")]
|
||||
#[test_case(CheckCode::PLR1722, Path::new("consider_using_sys_exit_3.py"); "PLR1722_3")]
|
||||
#[test_case(CheckCode::PLR1722, Path::new("consider_using_sys_exit_4.py"); "PLR1722_4")]
|
||||
#[test_case(CheckCode::PLR1722, Path::new("consider_using_sys_exit_5.py"); "PLR1722_5")]
|
||||
#[test_case(CheckCode::PLR1722, Path::new("consider_using_sys_exit_6.py"); "PLR1722_6")]
|
||||
#[test_case(CheckCode::PLW0120, Path::new("useless_else_on_loop.py"); "PLW0120")]
|
||||
fn checks(check_code: CheckCode, path: &Path) -> Result<()> {
|
||||
let snapshot = format!("{}", path.to_string_lossy());
|
||||
let snapshot = format!("{}_{}", check_code.as_ref(), path.to_string_lossy());
|
||||
let mut checks = test_path(
|
||||
Path::new("./resources/test/fixtures/pylint")
|
||||
.join(path)
|
||||
|
||||
@@ -1,164 +0,0 @@
|
||||
use itertools::Itertools;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use rustpython_ast::{Alias, Arguments, Boolop, Cmpop, Expr, ExprKind, Stmt};
|
||||
|
||||
use crate::ast::types::{FunctionScope, Range, ScopeKind};
|
||||
use crate::autofix::Fix;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checks::CheckKind;
|
||||
use crate::Check;
|
||||
|
||||
/// PLC2201
|
||||
pub fn misplaced_comparison_constant(
|
||||
checker: &mut Checker,
|
||||
expr: &Expr,
|
||||
left: &Expr,
|
||||
ops: &[Cmpop],
|
||||
comparators: &[Expr],
|
||||
) {
|
||||
if let ([op], [right]) = (ops, comparators) {
|
||||
if matches!(
|
||||
op,
|
||||
Cmpop::Eq | Cmpop::NotEq | Cmpop::Lt | Cmpop::LtE | Cmpop::Gt | Cmpop::GtE,
|
||||
) && matches!(&left.node, &ExprKind::Constant { .. })
|
||||
&& !matches!(&right.node, &ExprKind::Constant { .. })
|
||||
{
|
||||
let reversed_op = match op {
|
||||
Cmpop::Eq => "==",
|
||||
Cmpop::NotEq => "!=",
|
||||
Cmpop::Lt => ">",
|
||||
Cmpop::LtE => ">=",
|
||||
Cmpop::Gt => "<",
|
||||
Cmpop::GtE => "<=",
|
||||
_ => unreachable!("Expected comparison operator"),
|
||||
};
|
||||
let suggestion = format!("{right} {reversed_op} {left}");
|
||||
let mut check = Check::new(
|
||||
CheckKind::MisplacedComparisonConstant(suggestion.clone()),
|
||||
Range::from_located(expr),
|
||||
);
|
||||
if checker.patch(check.kind.code()) {
|
||||
check.amend(Fix::replacement(
|
||||
suggestion,
|
||||
expr.location,
|
||||
expr.end_location.unwrap(),
|
||||
));
|
||||
}
|
||||
checker.add_check(check);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// PLC3002
|
||||
pub fn unnecessary_direct_lambda_call(checker: &mut Checker, expr: &Expr, func: &Expr) {
|
||||
if let ExprKind::Lambda { .. } = &func.node {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::UnnecessaryDirectLambdaCall,
|
||||
Range::from_located(expr),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// PLE1142
|
||||
pub fn await_outside_async(checker: &mut Checker, expr: &Expr) {
|
||||
if !checker
|
||||
.current_scopes()
|
||||
.find_map(|scope| {
|
||||
if let ScopeKind::Function(FunctionScope { async_, .. }) = &scope.kind {
|
||||
Some(*async_)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap_or(true)
|
||||
{
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::AwaitOutsideAsync,
|
||||
Range::from_located(expr),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// PLR0206
|
||||
pub fn property_with_parameters(
|
||||
checker: &mut Checker,
|
||||
stmt: &Stmt,
|
||||
decorator_list: &[Expr],
|
||||
args: &Arguments,
|
||||
) {
|
||||
if decorator_list
|
||||
.iter()
|
||||
.any(|d| matches!(&d.node, ExprKind::Name { id, .. } if id == "property"))
|
||||
{
|
||||
if checker.is_builtin("property")
|
||||
&& args
|
||||
.args
|
||||
.iter()
|
||||
.chain(args.posonlyargs.iter())
|
||||
.chain(args.kwonlyargs.iter())
|
||||
.count()
|
||||
> 1
|
||||
{
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::PropertyWithParameters,
|
||||
Range::from_located(stmt),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// PLR0402
|
||||
pub fn consider_using_from_import(checker: &mut Checker, alias: &Alias) {
|
||||
if let Some(asname) = &alias.node.asname {
|
||||
if let Some((_, module)) = alias.node.name.rsplit_once('.') {
|
||||
if module == asname {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::ConsiderUsingFromImport(module.to_string(), asname.to_string()),
|
||||
Range::from_located(alias),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// PLR1701
|
||||
pub fn consider_merging_isinstance(
|
||||
checker: &mut Checker,
|
||||
expr: &Expr,
|
||||
op: &Boolop,
|
||||
values: &[Expr],
|
||||
) {
|
||||
if !matches!(op, Boolop::Or) || !checker.is_builtin("isinstance") {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut obj_to_types: FxHashMap<String, FxHashSet<String>> = FxHashMap::default();
|
||||
for value in values {
|
||||
if let ExprKind::Call { func, args, .. } = &value.node {
|
||||
if matches!(&func.node, ExprKind::Name { id, .. } if id == "isinstance") {
|
||||
if let [obj, types] = &args[..] {
|
||||
obj_to_types
|
||||
.entry(obj.to_string())
|
||||
.or_insert_with(FxHashSet::default)
|
||||
.extend(match &types.node {
|
||||
ExprKind::Tuple { elts, .. } => {
|
||||
elts.iter().map(std::string::ToString::to_string).collect()
|
||||
}
|
||||
_ => {
|
||||
vec![types.to_string()]
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (obj, types) in obj_to_types {
|
||||
if types.len() > 1 {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::ConsiderMergingIsinstance(obj, types.into_iter().sorted().collect()),
|
||||
Range::from_located(expr),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
26
src/pylint/plugins/await_outside_async.rs
Normal file
26
src/pylint/plugins/await_outside_async.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
use rustpython_ast::Expr;
|
||||
|
||||
use crate::ast::types::{FunctionScope, Range, ScopeKind};
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checks::CheckKind;
|
||||
use crate::Check;
|
||||
|
||||
/// PLE1142
|
||||
pub fn await_outside_async(checker: &mut Checker, expr: &Expr) {
|
||||
if !checker
|
||||
.current_scopes()
|
||||
.find_map(|scope| {
|
||||
if let ScopeKind::Function(FunctionScope { async_, .. }) = &scope.kind {
|
||||
Some(*async_)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap_or(true)
|
||||
{
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::AwaitOutsideAsync,
|
||||
Range::from_located(expr),
|
||||
));
|
||||
}
|
||||
}
|
||||
50
src/pylint/plugins/consider_merging_isinstance.rs
Normal file
50
src/pylint/plugins/consider_merging_isinstance.rs
Normal file
@@ -0,0 +1,50 @@
|
||||
use itertools::Itertools;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use rustpython_ast::{Boolop, Expr, ExprKind};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checks::CheckKind;
|
||||
use crate::Check;
|
||||
|
||||
/// PLR1701
|
||||
pub fn consider_merging_isinstance(
|
||||
checker: &mut Checker,
|
||||
expr: &Expr,
|
||||
op: &Boolop,
|
||||
values: &[Expr],
|
||||
) {
|
||||
if !matches!(op, Boolop::Or) || !checker.is_builtin("isinstance") {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut obj_to_types: FxHashMap<String, FxHashSet<String>> = FxHashMap::default();
|
||||
for value in values {
|
||||
if let ExprKind::Call { func, args, .. } = &value.node {
|
||||
if matches!(&func.node, ExprKind::Name { id, .. } if id == "isinstance") {
|
||||
if let [obj, types] = &args[..] {
|
||||
obj_to_types
|
||||
.entry(obj.to_string())
|
||||
.or_insert_with(FxHashSet::default)
|
||||
.extend(match &types.node {
|
||||
ExprKind::Tuple { elts, .. } => {
|
||||
elts.iter().map(std::string::ToString::to_string).collect()
|
||||
}
|
||||
_ => {
|
||||
vec![types.to_string()]
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (obj, types) in obj_to_types {
|
||||
if types.len() > 1 {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::ConsiderMergingIsinstance(obj, types.into_iter().sorted().collect()),
|
||||
Range::from_located(expr),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
20
src/pylint/plugins/consider_using_from_import.rs
Normal file
20
src/pylint/plugins/consider_using_from_import.rs
Normal file
@@ -0,0 +1,20 @@
|
||||
use rustpython_ast::Alias;
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checks::CheckKind;
|
||||
use crate::Check;
|
||||
|
||||
/// PLR0402
|
||||
pub fn consider_using_from_import(checker: &mut Checker, alias: &Alias) {
|
||||
if let Some(asname) = &alias.node.asname {
|
||||
if let Some((module, name)) = alias.node.name.rsplit_once('.') {
|
||||
if name == asname {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::ConsiderUsingFromImport(module.to_string(), name.to_string()),
|
||||
Range::from_located(alias),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,11 +19,6 @@ fn is_module_star_imported(checker: &Checker, module: &str) -> bool {
|
||||
})
|
||||
}
|
||||
|
||||
/// Return `true` if `exit` is (still) bound as a built-in in the current scope.
|
||||
fn has_builtin_exit_in_scope(checker: &Checker) -> bool {
|
||||
!is_module_star_imported(checker, "sys") && checker.is_builtin("exit")
|
||||
}
|
||||
|
||||
/// Return the appropriate `sys.exit` reference based on the current set of
|
||||
/// imports, or `None` is `sys.exit` hasn't been imported.
|
||||
fn get_member_import_name_alias(checker: &Checker, module: &str, member: &str) -> Option<String> {
|
||||
@@ -65,22 +60,27 @@ fn get_member_import_name_alias(checker: &Checker, module: &str, member: &str) -
|
||||
}
|
||||
|
||||
/// RUF004
|
||||
pub fn convert_exit_to_sys_exit(checker: &mut Checker, func: &Expr) {
|
||||
pub fn consider_using_sys_exit(checker: &mut Checker, func: &Expr) {
|
||||
if let ExprKind::Name { id, .. } = &func.node {
|
||||
if id == "exit" {
|
||||
if has_builtin_exit_in_scope(checker) {
|
||||
let mut check =
|
||||
Check::new(CheckKind::ConvertExitToSysExit, Range::from_located(func));
|
||||
if checker.patch(check.kind.code()) {
|
||||
if let Some(content) = get_member_import_name_alias(checker, "sys", "exit") {
|
||||
check.amend(Fix::replacement(
|
||||
content,
|
||||
func.location,
|
||||
func.end_location.unwrap(),
|
||||
));
|
||||
for name in ["exit", "quit"] {
|
||||
if id == name {
|
||||
if !(name == "exit" && is_module_star_imported(checker, "sys"))
|
||||
&& checker.is_builtin(name)
|
||||
{
|
||||
let mut check =
|
||||
Check::new(CheckKind::ConsiderUsingSysExit, Range::from_located(func));
|
||||
if checker.patch(check.kind.code()) {
|
||||
if let Some(content) = get_member_import_name_alias(checker, "sys", "exit")
|
||||
{
|
||||
check.amend(Fix::replacement(
|
||||
content,
|
||||
func.location,
|
||||
func.end_location.unwrap(),
|
||||
));
|
||||
}
|
||||
}
|
||||
checker.add_check(check);
|
||||
}
|
||||
checker.add_check(check);
|
||||
}
|
||||
}
|
||||
}
|
||||
48
src/pylint/plugins/misplaced_comparison_constant.rs
Normal file
48
src/pylint/plugins/misplaced_comparison_constant.rs
Normal file
@@ -0,0 +1,48 @@
|
||||
use rustpython_ast::{Cmpop, Expr, ExprKind};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::autofix::Fix;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checks::CheckKind;
|
||||
use crate::Check;
|
||||
|
||||
/// PLC2201
|
||||
pub fn misplaced_comparison_constant(
|
||||
checker: &mut Checker,
|
||||
expr: &Expr,
|
||||
left: &Expr,
|
||||
ops: &[Cmpop],
|
||||
comparators: &[Expr],
|
||||
) {
|
||||
if let ([op], [right]) = (ops, comparators) {
|
||||
if matches!(
|
||||
op,
|
||||
Cmpop::Eq | Cmpop::NotEq | Cmpop::Lt | Cmpop::LtE | Cmpop::Gt | Cmpop::GtE,
|
||||
) && matches!(&left.node, &ExprKind::Constant { .. })
|
||||
&& !matches!(&right.node, &ExprKind::Constant { .. })
|
||||
{
|
||||
let reversed_op = match op {
|
||||
Cmpop::Eq => "==",
|
||||
Cmpop::NotEq => "!=",
|
||||
Cmpop::Lt => ">",
|
||||
Cmpop::LtE => ">=",
|
||||
Cmpop::Gt => "<",
|
||||
Cmpop::GtE => "<=",
|
||||
_ => unreachable!("Expected comparison operator"),
|
||||
};
|
||||
let suggestion = format!("{right} {reversed_op} {left}");
|
||||
let mut check = Check::new(
|
||||
CheckKind::MisplacedComparisonConstant(suggestion.clone()),
|
||||
Range::from_located(expr),
|
||||
);
|
||||
if checker.patch(check.kind.code()) {
|
||||
check.amend(Fix::replacement(
|
||||
suggestion,
|
||||
expr.location,
|
||||
expr.end_location.unwrap(),
|
||||
));
|
||||
}
|
||||
checker.add_check(check);
|
||||
}
|
||||
}
|
||||
}
|
||||
19
src/pylint/plugins/mod.rs
Normal file
19
src/pylint/plugins/mod.rs
Normal file
@@ -0,0 +1,19 @@
|
||||
pub use await_outside_async::await_outside_async;
|
||||
pub use consider_merging_isinstance::consider_merging_isinstance;
|
||||
pub use consider_using_from_import::consider_using_from_import;
|
||||
pub use consider_using_sys_exit::consider_using_sys_exit;
|
||||
pub use misplaced_comparison_constant::misplaced_comparison_constant;
|
||||
pub use property_with_parameters::property_with_parameters;
|
||||
pub use unnecessary_direct_lambda_call::unnecessary_direct_lambda_call;
|
||||
pub use useless_else_on_loop::useless_else_on_loop;
|
||||
pub use useless_import_alias::useless_import_alias;
|
||||
|
||||
mod await_outside_async;
|
||||
mod consider_merging_isinstance;
|
||||
mod consider_using_from_import;
|
||||
mod consider_using_sys_exit;
|
||||
mod misplaced_comparison_constant;
|
||||
mod property_with_parameters;
|
||||
mod unnecessary_direct_lambda_call;
|
||||
mod useless_else_on_loop;
|
||||
mod useless_import_alias;
|
||||
34
src/pylint/plugins/property_with_parameters.rs
Normal file
34
src/pylint/plugins/property_with_parameters.rs
Normal file
@@ -0,0 +1,34 @@
|
||||
use rustpython_ast::{Arguments, Expr, ExprKind, Stmt};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checks::CheckKind;
|
||||
use crate::Check;
|
||||
|
||||
/// PLR0206
|
||||
pub fn property_with_parameters(
|
||||
checker: &mut Checker,
|
||||
stmt: &Stmt,
|
||||
decorator_list: &[Expr],
|
||||
args: &Arguments,
|
||||
) {
|
||||
if decorator_list
|
||||
.iter()
|
||||
.any(|d| matches!(&d.node, ExprKind::Name { id, .. } if id == "property"))
|
||||
{
|
||||
if checker.is_builtin("property")
|
||||
&& args
|
||||
.args
|
||||
.iter()
|
||||
.chain(args.posonlyargs.iter())
|
||||
.chain(args.kwonlyargs.iter())
|
||||
.count()
|
||||
> 1
|
||||
{
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::PropertyWithParameters,
|
||||
Range::from_located(stmt),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
16
src/pylint/plugins/unnecessary_direct_lambda_call.rs
Normal file
16
src/pylint/plugins/unnecessary_direct_lambda_call.rs
Normal file
@@ -0,0 +1,16 @@
|
||||
use rustpython_ast::{Expr, ExprKind};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checks::CheckKind;
|
||||
use crate::Check;
|
||||
|
||||
/// PLC3002
|
||||
pub fn unnecessary_direct_lambda_call(checker: &mut Checker, expr: &Expr, func: &Expr) {
|
||||
if let ExprKind::Lambda { .. } = &func.node {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::UnnecessaryDirectLambdaCall,
|
||||
Range::from_located(expr),
|
||||
));
|
||||
}
|
||||
}
|
||||
41
src/pylint/plugins/useless_else_on_loop.rs
Normal file
41
src/pylint/plugins/useless_else_on_loop.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
use rustpython_ast::{ExcepthandlerKind, Stmt, StmtKind};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checks::CheckKind;
|
||||
use crate::Check;
|
||||
|
||||
fn loop_exits_early(body: &[Stmt]) -> bool {
|
||||
body.iter().any(|stmt| match &stmt.node {
|
||||
StmtKind::If { body, .. } => loop_exits_early(body),
|
||||
StmtKind::Try {
|
||||
body,
|
||||
handlers,
|
||||
orelse,
|
||||
finalbody,
|
||||
..
|
||||
} => {
|
||||
loop_exits_early(body)
|
||||
|| handlers.iter().any(|handler| match &handler.node {
|
||||
ExcepthandlerKind::ExceptHandler { body, .. } => loop_exits_early(body),
|
||||
})
|
||||
|| loop_exits_early(orelse)
|
||||
|| loop_exits_early(finalbody)
|
||||
}
|
||||
StmtKind::For { orelse, .. }
|
||||
| StmtKind::AsyncFor { orelse, .. }
|
||||
| StmtKind::While { orelse, .. } => loop_exits_early(orelse),
|
||||
StmtKind::Break { .. } => true,
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
||||
/// PLW0120
|
||||
pub fn useless_else_on_loop(checker: &mut Checker, stmt: &Stmt, body: &[Stmt], orelse: &[Stmt]) {
|
||||
if !orelse.is_empty() && !loop_exits_early(body) {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::UselessElseOnLoop,
|
||||
Range::from_located(stmt),
|
||||
));
|
||||
}
|
||||
}
|
||||
24
src/pylint/plugins/useless_import_alias.rs
Normal file
24
src/pylint/plugins/useless_import_alias.rs
Normal file
@@ -0,0 +1,24 @@
|
||||
use rustpython_ast::Alias;
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::autofix::Fix;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checks::CheckKind;
|
||||
use crate::Check;
|
||||
|
||||
/// PLC0414
|
||||
pub fn useless_import_alias(checker: &mut Checker, alias: &Alias) {
|
||||
if let Some(asname) = &alias.node.asname {
|
||||
if !alias.node.name.contains('.') && &alias.node.name == asname {
|
||||
let mut check = Check::new(CheckKind::UselessImportAlias, Range::from_located(alias));
|
||||
if checker.patch(check.kind.code()) {
|
||||
check.amend(Fix::replacement(
|
||||
asname.to_string(),
|
||||
alias.location,
|
||||
alias.end_location.unwrap(),
|
||||
));
|
||||
}
|
||||
checker.add_check(check);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
---
|
||||
source: src/pylint/mod.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind: UselessImportAlias
|
||||
location:
|
||||
row: 6
|
||||
column: 7
|
||||
end_location:
|
||||
row: 6
|
||||
column: 33
|
||||
fix:
|
||||
content: collections
|
||||
location:
|
||||
row: 6
|
||||
column: 7
|
||||
end_location:
|
||||
row: 6
|
||||
column: 33
|
||||
- kind: UselessImportAlias
|
||||
location:
|
||||
row: 7
|
||||
column: 24
|
||||
end_location:
|
||||
row: 7
|
||||
column: 50
|
||||
fix:
|
||||
content: OrderedDict
|
||||
location:
|
||||
row: 7
|
||||
column: 24
|
||||
end_location:
|
||||
row: 7
|
||||
column: 50
|
||||
- kind: UselessImportAlias
|
||||
location:
|
||||
row: 15
|
||||
column: 14
|
||||
end_location:
|
||||
row: 15
|
||||
column: 24
|
||||
fix:
|
||||
content: bar
|
||||
location:
|
||||
row: 15
|
||||
column: 14
|
||||
end_location:
|
||||
row: 15
|
||||
column: 24
|
||||
- kind: UselessImportAlias
|
||||
location:
|
||||
row: 18
|
||||
column: 18
|
||||
end_location:
|
||||
row: 18
|
||||
column: 28
|
||||
fix:
|
||||
content: bar
|
||||
location:
|
||||
row: 18
|
||||
column: 18
|
||||
end_location:
|
||||
row: 18
|
||||
column: 28
|
||||
- kind: UselessImportAlias
|
||||
location:
|
||||
row: 19
|
||||
column: 22
|
||||
end_location:
|
||||
row: 19
|
||||
column: 38
|
||||
fix:
|
||||
content: foobar
|
||||
location:
|
||||
row: 19
|
||||
column: 22
|
||||
end_location:
|
||||
row: 19
|
||||
column: 38
|
||||
- kind: UselessImportAlias
|
||||
location:
|
||||
row: 21
|
||||
column: 14
|
||||
end_location:
|
||||
row: 21
|
||||
column: 24
|
||||
fix:
|
||||
content: foo
|
||||
location:
|
||||
row: 21
|
||||
column: 14
|
||||
end_location:
|
||||
row: 21
|
||||
column: 24
|
||||
- kind: UselessImportAlias
|
||||
location:
|
||||
row: 22
|
||||
column: 26
|
||||
end_location:
|
||||
row: 22
|
||||
column: 38
|
||||
fix:
|
||||
content: foo2
|
||||
location:
|
||||
row: 22
|
||||
column: 26
|
||||
end_location:
|
||||
row: 22
|
||||
column: 38
|
||||
- kind: UselessImportAlias
|
||||
location:
|
||||
row: 24
|
||||
column: 20
|
||||
end_location:
|
||||
row: 24
|
||||
column: 36
|
||||
fix:
|
||||
content: foobar
|
||||
location:
|
||||
row: 24
|
||||
column: 20
|
||||
end_location:
|
||||
row: 24
|
||||
column: 36
|
||||
|
||||
@@ -4,24 +4,24 @@ expression: checks
|
||||
---
|
||||
- kind:
|
||||
ConsiderUsingFromImport:
|
||||
- path
|
||||
- os
|
||||
- path
|
||||
location:
|
||||
row: 8
|
||||
row: 9
|
||||
column: 7
|
||||
end_location:
|
||||
row: 8
|
||||
row: 9
|
||||
column: 22
|
||||
fix: ~
|
||||
- kind:
|
||||
ConsiderUsingFromImport:
|
||||
- foobar
|
||||
- foo.bar
|
||||
- foobar
|
||||
location:
|
||||
row: 10
|
||||
row: 11
|
||||
column: 7
|
||||
end_location:
|
||||
row: 10
|
||||
row: 11
|
||||
column: 31
|
||||
fix: ~
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
---
|
||||
source: src/pylint/mod.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind: ConsiderUsingSysExit
|
||||
location:
|
||||
row: 1
|
||||
column: 0
|
||||
end_location:
|
||||
row: 1
|
||||
column: 4
|
||||
fix: ~
|
||||
- kind: ConsiderUsingSysExit
|
||||
location:
|
||||
row: 2
|
||||
column: 0
|
||||
end_location:
|
||||
row: 2
|
||||
column: 4
|
||||
fix: ~
|
||||
- kind: ConsiderUsingSysExit
|
||||
location:
|
||||
row: 6
|
||||
column: 4
|
||||
end_location:
|
||||
row: 6
|
||||
column: 8
|
||||
fix: ~
|
||||
- kind: ConsiderUsingSysExit
|
||||
location:
|
||||
row: 7
|
||||
column: 4
|
||||
end_location:
|
||||
row: 7
|
||||
column: 8
|
||||
fix: ~
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
---
|
||||
source: src/pylint/mod.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind: ConsiderUsingSysExit
|
||||
location:
|
||||
row: 3
|
||||
column: 0
|
||||
end_location:
|
||||
row: 3
|
||||
column: 4
|
||||
fix:
|
||||
content: sys.exit
|
||||
location:
|
||||
row: 3
|
||||
column: 0
|
||||
end_location:
|
||||
row: 3
|
||||
column: 4
|
||||
- kind: ConsiderUsingSysExit
|
||||
location:
|
||||
row: 4
|
||||
column: 0
|
||||
end_location:
|
||||
row: 4
|
||||
column: 4
|
||||
fix:
|
||||
content: sys.exit
|
||||
location:
|
||||
row: 4
|
||||
column: 0
|
||||
end_location:
|
||||
row: 4
|
||||
column: 4
|
||||
- kind: ConsiderUsingSysExit
|
||||
location:
|
||||
row: 8
|
||||
column: 4
|
||||
end_location:
|
||||
row: 8
|
||||
column: 8
|
||||
fix:
|
||||
content: sys.exit
|
||||
location:
|
||||
row: 8
|
||||
column: 4
|
||||
end_location:
|
||||
row: 8
|
||||
column: 8
|
||||
- kind: ConsiderUsingSysExit
|
||||
location:
|
||||
row: 9
|
||||
column: 4
|
||||
end_location:
|
||||
row: 9
|
||||
column: 8
|
||||
fix:
|
||||
content: sys.exit
|
||||
location:
|
||||
row: 9
|
||||
column: 4
|
||||
end_location:
|
||||
row: 9
|
||||
column: 8
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
---
|
||||
source: src/pylint/mod.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind: ConsiderUsingSysExit
|
||||
location:
|
||||
row: 3
|
||||
column: 0
|
||||
end_location:
|
||||
row: 3
|
||||
column: 4
|
||||
fix:
|
||||
content: sys2.exit
|
||||
location:
|
||||
row: 3
|
||||
column: 0
|
||||
end_location:
|
||||
row: 3
|
||||
column: 4
|
||||
- kind: ConsiderUsingSysExit
|
||||
location:
|
||||
row: 4
|
||||
column: 0
|
||||
end_location:
|
||||
row: 4
|
||||
column: 4
|
||||
fix:
|
||||
content: sys2.exit
|
||||
location:
|
||||
row: 4
|
||||
column: 0
|
||||
end_location:
|
||||
row: 4
|
||||
column: 4
|
||||
- kind: ConsiderUsingSysExit
|
||||
location:
|
||||
row: 8
|
||||
column: 4
|
||||
end_location:
|
||||
row: 8
|
||||
column: 8
|
||||
fix:
|
||||
content: sys2.exit
|
||||
location:
|
||||
row: 8
|
||||
column: 4
|
||||
end_location:
|
||||
row: 8
|
||||
column: 8
|
||||
- kind: ConsiderUsingSysExit
|
||||
location:
|
||||
row: 9
|
||||
column: 4
|
||||
end_location:
|
||||
row: 9
|
||||
column: 8
|
||||
fix:
|
||||
content: sys2.exit
|
||||
location:
|
||||
row: 9
|
||||
column: 4
|
||||
end_location:
|
||||
row: 9
|
||||
column: 8
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
---
|
||||
source: src/rules/mod.rs
|
||||
source: src/pylint/mod.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind: ConvertExitToSysExit
|
||||
- kind: ConsiderUsingSysExit
|
||||
location:
|
||||
row: 3
|
||||
row: 4
|
||||
column: 0
|
||||
end_location:
|
||||
row: 3
|
||||
row: 4
|
||||
column: 4
|
||||
fix:
|
||||
content: exit2
|
||||
content: exit
|
||||
location:
|
||||
row: 3
|
||||
row: 4
|
||||
column: 0
|
||||
end_location:
|
||||
row: 3
|
||||
row: 4
|
||||
column: 4
|
||||
- kind: ConvertExitToSysExit
|
||||
- kind: ConsiderUsingSysExit
|
||||
location:
|
||||
row: 7
|
||||
row: 9
|
||||
column: 4
|
||||
end_location:
|
||||
row: 7
|
||||
row: 9
|
||||
column: 8
|
||||
fix:
|
||||
content: exit2
|
||||
content: exit
|
||||
location:
|
||||
row: 7
|
||||
row: 9
|
||||
column: 4
|
||||
end_location:
|
||||
row: 7
|
||||
row: 9
|
||||
column: 8
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
---
|
||||
source: src/pylint/mod.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind: ConsiderUsingSysExit
|
||||
location:
|
||||
row: 3
|
||||
column: 0
|
||||
end_location:
|
||||
row: 3
|
||||
column: 4
|
||||
fix:
|
||||
content: exit2
|
||||
location:
|
||||
row: 3
|
||||
column: 0
|
||||
end_location:
|
||||
row: 3
|
||||
column: 4
|
||||
- kind: ConsiderUsingSysExit
|
||||
location:
|
||||
row: 4
|
||||
column: 0
|
||||
end_location:
|
||||
row: 4
|
||||
column: 4
|
||||
fix:
|
||||
content: exit2
|
||||
location:
|
||||
row: 4
|
||||
column: 0
|
||||
end_location:
|
||||
row: 4
|
||||
column: 4
|
||||
- kind: ConsiderUsingSysExit
|
||||
location:
|
||||
row: 8
|
||||
column: 4
|
||||
end_location:
|
||||
row: 8
|
||||
column: 8
|
||||
fix:
|
||||
content: exit2
|
||||
location:
|
||||
row: 8
|
||||
column: 4
|
||||
end_location:
|
||||
row: 8
|
||||
column: 8
|
||||
- kind: ConsiderUsingSysExit
|
||||
location:
|
||||
row: 9
|
||||
column: 4
|
||||
end_location:
|
||||
row: 9
|
||||
column: 8
|
||||
fix:
|
||||
content: exit2
|
||||
location:
|
||||
row: 9
|
||||
column: 4
|
||||
end_location:
|
||||
row: 9
|
||||
column: 8
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
---
|
||||
source: src/rules/mod.rs
|
||||
source: src/pylint/mod.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind: ConvertExitToSysExit
|
||||
- kind: ConsiderUsingSysExit
|
||||
location:
|
||||
row: 3
|
||||
row: 4
|
||||
column: 0
|
||||
end_location:
|
||||
row: 3
|
||||
row: 4
|
||||
column: 4
|
||||
fix:
|
||||
content: sys.exit
|
||||
content: exit
|
||||
location:
|
||||
row: 3
|
||||
row: 4
|
||||
column: 0
|
||||
end_location:
|
||||
row: 3
|
||||
row: 4
|
||||
column: 4
|
||||
- kind: ConvertExitToSysExit
|
||||
- kind: ConsiderUsingSysExit
|
||||
location:
|
||||
row: 7
|
||||
row: 9
|
||||
column: 4
|
||||
end_location:
|
||||
row: 7
|
||||
row: 9
|
||||
column: 8
|
||||
fix:
|
||||
content: sys.exit
|
||||
content: exit
|
||||
location:
|
||||
row: 7
|
||||
row: 9
|
||||
column: 4
|
||||
end_location:
|
||||
row: 7
|
||||
row: 9
|
||||
column: 8
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
source: src/rules/mod.rs
|
||||
source: src/pylint/mod.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind: ConvertExitToSysExit
|
||||
- kind: ConsiderUsingSysExit
|
||||
location:
|
||||
row: 1
|
||||
column: 0
|
||||
@@ -10,12 +10,12 @@ expression: checks
|
||||
row: 1
|
||||
column: 4
|
||||
fix: ~
|
||||
- kind: ConvertExitToSysExit
|
||||
- kind: ConsiderUsingSysExit
|
||||
location:
|
||||
row: 5
|
||||
column: 4
|
||||
row: 2
|
||||
column: 0
|
||||
end_location:
|
||||
row: 5
|
||||
column: 8
|
||||
row: 2
|
||||
column: 4
|
||||
fix: ~
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
---
|
||||
source: src/pylint/mod.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind: UselessElseOnLoop
|
||||
location:
|
||||
row: 6
|
||||
column: 4
|
||||
end_location:
|
||||
row: 11
|
||||
column: 4
|
||||
fix: ~
|
||||
- kind: UselessElseOnLoop
|
||||
location:
|
||||
row: 16
|
||||
column: 4
|
||||
end_location:
|
||||
row: 20
|
||||
column: 4
|
||||
fix: ~
|
||||
- kind: UselessElseOnLoop
|
||||
location:
|
||||
row: 23
|
||||
column: 0
|
||||
end_location:
|
||||
row: 34
|
||||
column: 0
|
||||
fix: ~
|
||||
- kind: UselessElseOnLoop
|
||||
location:
|
||||
row: 34
|
||||
column: 0
|
||||
end_location:
|
||||
row: 40
|
||||
column: 0
|
||||
fix: ~
|
||||
- kind: UselessElseOnLoop
|
||||
location:
|
||||
row: 40
|
||||
column: 0
|
||||
end_location:
|
||||
row: 48
|
||||
column: 0
|
||||
fix: ~
|
||||
- kind: UselessElseOnLoop
|
||||
location:
|
||||
row: 81
|
||||
column: 4
|
||||
end_location:
|
||||
row: 90
|
||||
column: 4
|
||||
fix: ~
|
||||
- kind: UselessElseOnLoop
|
||||
location:
|
||||
row: 96
|
||||
column: 8
|
||||
end_location:
|
||||
row: 101
|
||||
column: 4
|
||||
fix: ~
|
||||
|
||||
@@ -55,6 +55,7 @@ static TYPING_EXTENSIONS: Lazy<FxHashSet<&'static str>> = Lazy::new(|| {
|
||||
"get_overloads",
|
||||
"is_typeddict",
|
||||
"overload",
|
||||
"override",
|
||||
"reveal_type",
|
||||
"runtime_checkable",
|
||||
])
|
||||
|
||||
@@ -6,7 +6,7 @@ use rustpython_ast::{Constant, Expr, ExprKind, Keyword, KeywordData, Location};
|
||||
use rustpython_parser::lexer;
|
||||
use rustpython_parser::token::Tok;
|
||||
|
||||
use crate::ast::helpers::{self, match_name_or_attr};
|
||||
use crate::ast::helpers;
|
||||
use crate::ast::types::Range;
|
||||
use crate::autofix::Fix;
|
||||
use crate::check_ast::Checker;
|
||||
@@ -64,7 +64,7 @@ fn match_open(expr: &Expr) -> (Option<&Expr>, Vec<Keyword>) {
|
||||
keywords,
|
||||
} = &expr.node
|
||||
{
|
||||
if match_name_or_attr(func, OPEN_FUNC_NAME) {
|
||||
if matches!(&func.node, ExprKind::Name {id, ..} if id == OPEN_FUNC_NAME) {
|
||||
// Return the "open mode" parameter and keywords.
|
||||
return (args.get(1), keywords.clone());
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
//! Module for Ruff-specific rules.
|
||||
|
||||
pub mod checks;
|
||||
pub mod plugins;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
@@ -18,13 +17,6 @@ mod tests {
|
||||
#[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::RUF004, Path::new("RUF004_0.py"); "RUF004_0")]
|
||||
#[test_case(CheckCode::RUF004, Path::new("RUF004_1.py"); "RUF004_1")]
|
||||
#[test_case(CheckCode::RUF004, Path::new("RUF004_2.py"); "RUF004_2")]
|
||||
#[test_case(CheckCode::RUF004, Path::new("RUF004_3.py"); "RUF004_3")]
|
||||
#[test_case(CheckCode::RUF004, Path::new("RUF004_4.py"); "RUF004_4")]
|
||||
#[test_case(CheckCode::RUF004, Path::new("RUF004_5.py"); "RUF004_5")]
|
||||
#[test_case(CheckCode::RUF004, Path::new("RUF004_6.py"); "RUF004_6")]
|
||||
fn checks(check_code: CheckCode, path: &Path) -> Result<()> {
|
||||
let snapshot = format!("{}_{}", check_code.as_ref(), path.to_string_lossy());
|
||||
let mut checks = test_path(
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
pub use convert_exit_to_sys_exit::convert_exit_to_sys_exit;
|
||||
|
||||
mod convert_exit_to_sys_exit;
|
||||
@@ -1,35 +0,0 @@
|
||||
---
|
||||
source: src/rules/mod.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind: ConvertExitToSysExit
|
||||
location:
|
||||
row: 3
|
||||
column: 0
|
||||
end_location:
|
||||
row: 3
|
||||
column: 4
|
||||
fix:
|
||||
content: sys2.exit
|
||||
location:
|
||||
row: 3
|
||||
column: 0
|
||||
end_location:
|
||||
row: 3
|
||||
column: 4
|
||||
- kind: ConvertExitToSysExit
|
||||
location:
|
||||
row: 7
|
||||
column: 4
|
||||
end_location:
|
||||
row: 7
|
||||
column: 8
|
||||
fix:
|
||||
content: sys2.exit
|
||||
location:
|
||||
row: 7
|
||||
column: 4
|
||||
end_location:
|
||||
row: 7
|
||||
column: 8
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
source: src/rules/mod.rs
|
||||
expression: checks
|
||||
---
|
||||
[]
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
source: src/rules/mod.rs
|
||||
expression: checks
|
||||
---
|
||||
[]
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
---
|
||||
source: src/rules/mod.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind: ConvertExitToSysExit
|
||||
location:
|
||||
row: 1
|
||||
column: 0
|
||||
end_location:
|
||||
row: 1
|
||||
column: 4
|
||||
fix: ~
|
||||
|
||||
@@ -29,6 +29,7 @@ pub struct Configuration {
|
||||
pub fixable: Vec<CheckCodePrefix>,
|
||||
pub format: SerializationFormat,
|
||||
pub ignore: Vec<CheckCodePrefix>,
|
||||
pub ignore_init_module_imports: bool,
|
||||
pub line_length: usize,
|
||||
pub per_file_ignores: Vec<PerFileIgnore>,
|
||||
pub select: Vec<CheckCodePrefix>,
|
||||
@@ -125,6 +126,7 @@ impl Configuration {
|
||||
unfixable: options.unfixable.unwrap_or_default(),
|
||||
format: options.format.unwrap_or_default(),
|
||||
ignore: options.ignore.unwrap_or_default(),
|
||||
ignore_init_module_imports: options.ignore_init_module_imports.unwrap_or_default(),
|
||||
line_length: options.line_length.unwrap_or(88),
|
||||
per_file_ignores: options
|
||||
.per_file_ignores
|
||||
|
||||
@@ -35,6 +35,7 @@ pub struct Settings {
|
||||
pub external: BTreeSet<String>,
|
||||
pub fixable: FxHashSet<CheckCode>,
|
||||
pub format: SerializationFormat,
|
||||
pub ignore_init_module_imports: bool,
|
||||
pub line_length: usize,
|
||||
pub per_file_ignores: Vec<(GlobMatcher, GlobMatcher, BTreeSet<CheckCode>)>,
|
||||
pub show_source: bool,
|
||||
@@ -79,6 +80,7 @@ impl Settings {
|
||||
flake8_bugbear: config.flake8_bugbear,
|
||||
flake8_quotes: config.flake8_quotes,
|
||||
flake8_tidy_imports: config.flake8_tidy_imports,
|
||||
ignore_init_module_imports: config.ignore_init_module_imports,
|
||||
isort: config.isort,
|
||||
mccabe: config.mccabe,
|
||||
line_length: config.line_length,
|
||||
@@ -100,6 +102,7 @@ impl Settings {
|
||||
external: BTreeSet::default(),
|
||||
fixable: FxHashSet::from_iter([check_code]),
|
||||
format: SerializationFormat::Text,
|
||||
ignore_init_module_imports: false,
|
||||
line_length: 88,
|
||||
per_file_ignores: vec![],
|
||||
show_source: false,
|
||||
@@ -125,6 +128,7 @@ impl Settings {
|
||||
external: BTreeSet::default(),
|
||||
fixable: FxHashSet::from_iter(check_codes),
|
||||
format: SerializationFormat::Text,
|
||||
ignore_init_module_imports: false,
|
||||
line_length: 88,
|
||||
per_file_ignores: vec![],
|
||||
show_source: false,
|
||||
|
||||
@@ -23,6 +23,7 @@ pub struct Options {
|
||||
pub fixable: Option<Vec<CheckCodePrefix>>,
|
||||
pub format: Option<SerializationFormat>,
|
||||
pub ignore: Option<Vec<CheckCodePrefix>>,
|
||||
pub ignore_init_module_imports: Option<bool>,
|
||||
pub line_length: Option<usize>,
|
||||
pub select: Option<Vec<CheckCodePrefix>>,
|
||||
pub show_source: Option<bool>,
|
||||
|
||||
@@ -142,6 +142,7 @@ mod tests {
|
||||
fix: None,
|
||||
fixable: None,
|
||||
ignore: None,
|
||||
ignore_init_module_imports: None,
|
||||
line_length: None,
|
||||
per_file_ignores: None,
|
||||
select: None,
|
||||
@@ -182,6 +183,7 @@ line-length = 79
|
||||
fix: None,
|
||||
fixable: None,
|
||||
ignore: None,
|
||||
ignore_init_module_imports: None,
|
||||
line_length: Some(79),
|
||||
per_file_ignores: None,
|
||||
select: None,
|
||||
@@ -221,6 +223,7 @@ exclude = ["foo.py"]
|
||||
extend_select: None,
|
||||
external: None,
|
||||
ignore: None,
|
||||
ignore_init_module_imports: None,
|
||||
extend_ignore: None,
|
||||
fixable: None,
|
||||
format: None,
|
||||
@@ -262,6 +265,7 @@ select = ["E501"]
|
||||
fix: None,
|
||||
fixable: None,
|
||||
ignore: None,
|
||||
ignore_init_module_imports: None,
|
||||
line_length: None,
|
||||
per_file_ignores: None,
|
||||
select: Some(vec![CheckCodePrefix::E501]),
|
||||
@@ -303,6 +307,7 @@ ignore = ["E501"]
|
||||
fix: None,
|
||||
fixable: None,
|
||||
ignore: Some(vec![CheckCodePrefix::E501]),
|
||||
ignore_init_module_imports: None,
|
||||
line_length: None,
|
||||
per_file_ignores: None,
|
||||
select: None,
|
||||
@@ -381,6 +386,7 @@ other-attribute = 1
|
||||
extend_select: None,
|
||||
external: Some(vec!["V101".to_string()]),
|
||||
ignore: None,
|
||||
ignore_init_module_imports: None,
|
||||
extend_ignore: None,
|
||||
fixable: None,
|
||||
format: None,
|
||||
|
||||
@@ -5,7 +5,8 @@ use std::path::Path;
|
||||
|
||||
use rustpython_ast::{Stmt, StmtKind};
|
||||
|
||||
use crate::ast::helpers::match_name_or_attr;
|
||||
use crate::ast::helpers::match_module_member;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::docstrings::definition::Documentable;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -28,45 +29,57 @@ pub struct VisibleScope {
|
||||
}
|
||||
|
||||
/// Returns `true` if a function is a "static method".
|
||||
pub fn is_staticmethod(stmt: &Stmt) -> bool {
|
||||
pub fn is_staticmethod(checker: &Checker, stmt: &Stmt) -> bool {
|
||||
match &stmt.node {
|
||||
StmtKind::FunctionDef { decorator_list, .. }
|
||||
| StmtKind::AsyncFunctionDef { decorator_list, .. } => decorator_list
|
||||
.iter()
|
||||
.any(|expr| match_name_or_attr(expr, "staticmethod")),
|
||||
| StmtKind::AsyncFunctionDef { decorator_list, .. } => decorator_list.iter().any(|expr| {
|
||||
match_module_member(
|
||||
expr,
|
||||
"",
|
||||
"staticmethod",
|
||||
&checker.from_imports,
|
||||
&checker.import_aliases,
|
||||
)
|
||||
}),
|
||||
_ => panic!("Found non-FunctionDef in is_staticmethod"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if a function is a "class method".
|
||||
pub fn is_classmethod(stmt: &Stmt) -> bool {
|
||||
pub fn is_classmethod(checker: &Checker, stmt: &Stmt) -> bool {
|
||||
match &stmt.node {
|
||||
StmtKind::FunctionDef { decorator_list, .. }
|
||||
| StmtKind::AsyncFunctionDef { decorator_list, .. } => decorator_list
|
||||
.iter()
|
||||
.any(|expr| match_name_or_attr(expr, "classmethod")),
|
||||
| StmtKind::AsyncFunctionDef { decorator_list, .. } => decorator_list.iter().any(|expr| {
|
||||
match_module_member(
|
||||
expr,
|
||||
"",
|
||||
"classmethod",
|
||||
&checker.from_imports,
|
||||
&checker.import_aliases,
|
||||
)
|
||||
}),
|
||||
_ => panic!("Found non-FunctionDef in is_classmethod"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if a function definition is an `@overload`.
|
||||
pub fn is_overload(stmt: &Stmt) -> bool {
|
||||
pub fn is_overload(checker: &Checker, stmt: &Stmt) -> bool {
|
||||
match &stmt.node {
|
||||
StmtKind::FunctionDef { decorator_list, .. }
|
||||
| StmtKind::AsyncFunctionDef { decorator_list, .. } => decorator_list
|
||||
.iter()
|
||||
.any(|expr| match_name_or_attr(expr, "overload")),
|
||||
.any(|expr| checker.match_typing_expr(expr, "overload")),
|
||||
_ => panic!("Found non-FunctionDef in is_overload"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if a function definition is an `@override` (PEP 698).
|
||||
pub fn is_override(stmt: &Stmt) -> bool {
|
||||
pub fn is_override(checker: &Checker, stmt: &Stmt) -> bool {
|
||||
match &stmt.node {
|
||||
StmtKind::FunctionDef { decorator_list, .. }
|
||||
| StmtKind::AsyncFunctionDef { decorator_list, .. } => decorator_list
|
||||
.iter()
|
||||
.any(|expr| match_name_or_attr(expr, "override")),
|
||||
.any(|expr| checker.match_typing_expr(expr, "override")),
|
||||
_ => panic!("Found non-FunctionDef in is_override"),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user