Compare commits
1 Commits
v0.0.59
...
charlie/no
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6f317fc3e7 |
@@ -14,12 +14,6 @@ your proposed change.
|
||||
ruff is written in Rust (1.63.0). You'll need to install the
|
||||
[Rust toolchain](https://www.rust-lang.org/tools/install) for development.
|
||||
|
||||
You'll also need [Insta](https://insta.rs/docs/) to update snapshot tests:
|
||||
|
||||
```shell
|
||||
cargo install cargo-insta
|
||||
```
|
||||
|
||||
### Development
|
||||
|
||||
After cloning the repository, run ruff locally with:
|
||||
@@ -64,7 +58,7 @@ similar rules are implemented.
|
||||
To add a test fixture, create a file under `resources/test/fixtures`, named to match the `CheckCode`
|
||||
you defined earlier (e.g., `E402.py`). This file should contain a variety of violations and
|
||||
non-violations designed to evaluate and demonstrate the behavior of your lint rule. Run ruff locally
|
||||
with (e.g.) `cargo run resources/test/fixtures/E402.py`. Once you're satisfied with the output,
|
||||
with (e.g.) `cargo run resources/test/fixtures/E402.py`. Once you're satisified with the output,
|
||||
codify the behavior as a snapshot test by adding a new function to the `mod tests` section of
|
||||
`src/linter.rs`, like so:
|
||||
|
||||
|
||||
106
Cargo.lock
generated
106
Cargo.lock
generated
@@ -16,7 +16,7 @@ checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
|
||||
dependencies = [
|
||||
"getrandom 0.2.7",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"version_check 0.9.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -319,6 +319,12 @@ version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
|
||||
|
||||
[[package]]
|
||||
name = "bytecount"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f861d9ce359f56dbcb6e0c2a1cb84e52ad732cadb57b806adeb3c7668caccbd8"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.3"
|
||||
@@ -907,7 +913,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
"version_check 0.9.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1137,7 +1143,7 @@ dependencies = [
|
||||
"string_cache",
|
||||
"term",
|
||||
"tiny-keccak",
|
||||
"unicode-xid",
|
||||
"unicode-xid 0.2.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1366,6 +1372,16 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "4.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"version_check 0.1.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "5.1.2"
|
||||
@@ -1373,7 +1389,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"version_check",
|
||||
"version_check 0.9.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom_locate"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a47c112b3861d81f7fbf73892b9271af933af32bd5dee6889aa3c3fa9caed7e"
|
||||
dependencies = [
|
||||
"bytecount",
|
||||
"memchr",
|
||||
"nom 4.2.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1394,6 +1421,17 @@ dependencies = [
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.3"
|
||||
@@ -1695,7 +1733,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"version_check",
|
||||
"version_check 0.9.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1706,7 +1744,7 @@ checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"version_check",
|
||||
"version_check 0.9.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1718,6 +1756,21 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "python-parser"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "683594d14f9c4db9e899643108918ad9db99aedad77121b5179aa205343c10de"
|
||||
dependencies = [
|
||||
"nom 4.2.3",
|
||||
"nom_locate",
|
||||
"num-bigint 0.2.6",
|
||||
"num-traits",
|
||||
"unicode-xid 0.1.0",
|
||||
"unicode_names2 0.2.2",
|
||||
"wtf8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.21"
|
||||
@@ -1907,7 +1960,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.59"
|
||||
version = "0.0.56"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
@@ -1928,6 +1981,7 @@ dependencies = [
|
||||
"notify",
|
||||
"once_cell",
|
||||
"path-absolutize",
|
||||
"python-parser",
|
||||
"rayon",
|
||||
"regex",
|
||||
"rustpython-ast",
|
||||
@@ -1957,7 +2011,7 @@ name = "rustpython-ast"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/charliermarsh/RustPython.git?rev=4f457893efc381ad5c432576b24bcc7e4a08c641#4f457893efc381ad5c432576b24bcc7e4a08c641"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-bigint 0.4.3",
|
||||
"rustpython-common",
|
||||
"rustpython-compiler-core",
|
||||
]
|
||||
@@ -1973,7 +2027,7 @@ dependencies = [
|
||||
"lexical-parse-float",
|
||||
"libc",
|
||||
"lock_api",
|
||||
"num-bigint",
|
||||
"num-bigint 0.4.3",
|
||||
"num-complex",
|
||||
"num-traits",
|
||||
"once_cell",
|
||||
@@ -1995,7 +2049,7 @@ dependencies = [
|
||||
"bstr",
|
||||
"itertools",
|
||||
"lz4_flex",
|
||||
"num-bigint",
|
||||
"num-bigint 0.4.3",
|
||||
"num-complex",
|
||||
"serde",
|
||||
"static_assertions",
|
||||
@@ -2013,7 +2067,7 @@ dependencies = [
|
||||
"lalrpop",
|
||||
"lalrpop-util",
|
||||
"log",
|
||||
"num-bigint",
|
||||
"num-bigint 0.4.3",
|
||||
"num-traits",
|
||||
"phf 0.10.1",
|
||||
"phf_codegen 0.10.0",
|
||||
@@ -2023,7 +2077,7 @@ dependencies = [
|
||||
"tiny-keccak",
|
||||
"unic-emoji-char",
|
||||
"unic-ucd-ident",
|
||||
"unicode_names2",
|
||||
"unicode_names2 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2315,7 +2369,7 @@ checksum = "76971977e6121664ec1b960d1313aacfa75642adc93b9d4d53b247bd4cb1747e"
|
||||
dependencies = [
|
||||
"dirs 2.0.2",
|
||||
"fnv",
|
||||
"nom",
|
||||
"nom 5.1.2",
|
||||
"phf 0.8.0",
|
||||
"phf_codegen 0.8.0",
|
||||
]
|
||||
@@ -2485,12 +2539,24 @@ dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
||||
|
||||
[[package]]
|
||||
name = "unicode_names2"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0dc6c5da0c8d7200f9488cc346bd30ba62bcd9f79ef937ea6573132e3d507df9"
|
||||
|
||||
[[package]]
|
||||
name = "unicode_names2"
|
||||
version = "0.5.1"
|
||||
@@ -2553,9 +2619,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2209b78d1249f7e6f3293657c9779fe31ced465df091bbd433a1cf88e916ec55"
|
||||
dependencies = [
|
||||
"ctor",
|
||||
"version_check",
|
||||
"version_check 0.9.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
@@ -2820,6 +2892,12 @@ dependencies = [
|
||||
"winapi-build",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wtf8"
|
||||
version = "0.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6b9309a86639c488a8eb2b5331cb5127cc9feb0a94a0db4b5d1ab5b84977956"
|
||||
|
||||
[[package]]
|
||||
name = "yaml-rust"
|
||||
version = "0.4.5"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff"
|
||||
version = "0.0.59"
|
||||
version = "0.0.56"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
@@ -35,6 +35,7 @@ serde_json = { version = "1.0.83" }
|
||||
toml = { version = "0.5.9" }
|
||||
update-informer = { version = "0.5.0", default_features = false, features = ["pypi"], optional = true }
|
||||
walkdir = { version = "2.3.2" }
|
||||
python-parser = "0.2.0"
|
||||
|
||||
[dev-dependencies]
|
||||
insta = { version = "1.19.1", features = ["yaml"] }
|
||||
|
||||
@@ -130,8 +130,6 @@ Options:
|
||||
Enable automatic additions of noqa directives to failing lines
|
||||
--dummy-variable-rgx <DUMMY_VARIABLE_RGX>
|
||||
Regular expression matching the name of dummy variables
|
||||
--target-version <TARGET_VERSION>
|
||||
The minimum Python version that should be supported
|
||||
-h, --help
|
||||
Print help information
|
||||
-V, --version
|
||||
@@ -215,7 +213,6 @@ ruff also implements some of the most popular Flake8 plugins natively, including
|
||||
- [`flake8-builtins`](https://pypi.org/project/flake8-builtins/)
|
||||
- [`flake8-super`](https://pypi.org/project/flake8-super/)
|
||||
- [`flake8-print`](https://pypi.org/project/flake8-print/)
|
||||
- [`flake8-comprehensions`](https://pypi.org/project/flake8-comprehensions/) (partial)
|
||||
- [`pyupgrade`](https://pypi.org/project/pyupgrade/) (partial)
|
||||
|
||||
Beyond rule-set parity, ruff suffers from the following limitations vis-à-vis Flake8:
|
||||
@@ -277,15 +274,10 @@ The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` com
|
||||
| A001 | BuiltinVariableShadowing | Variable `...` is shadowing a python builtin | | |
|
||||
| A002 | BuiltinArgumentShadowing | Argument `...` is shadowing a python builtin | | |
|
||||
| A003 | BuiltinAttributeShadowing | Class attribute `...` is shadowing a python builtin | | |
|
||||
| C400 | UnnecessaryGeneratorList | Unnecessary generator - rewrite as a list comprehension | | |
|
||||
| C401 | UnnecessaryGeneratorSet | Unnecessary generator - rewrite as a set comprehension | | |
|
||||
| C403 | UnnecessaryListComprehensionSet | Unnecessary list comprehension - rewrite as a set comprehension | | |
|
||||
| C404 | UnnecessaryListComprehensionDict | Unnecessary list comprehension - rewrite as a dict comprehension | | |
|
||||
| SPR001 | SuperCallWithParameters | Use `super()` instead of `super(__class__, self)` | | 🛠 |
|
||||
| T201 | PrintFound | `print` found | | 🛠 |
|
||||
| T203 | PPrintFound | `pprint` found | | 🛠 |
|
||||
| U001 | UselessMetaclassType | `__metaclass__ = type` is implied | | 🛠 |
|
||||
| U002 | UnnecessaryAbspath | `abspath(__file__)` is unnecessary in Python 3.9 and later | | 🛠 |
|
||||
| R001 | UselessObjectInheritance | Class `...` inherits from object | | 🛠 |
|
||||
| R002 | NoAssertEquals | `assertEquals` is deprecated, use `assertEqual` instead | | 🛠 |
|
||||
| M001 | UnusedNOQA | Unused `noqa` directive | | 🛠 |
|
||||
|
||||
23
examples/parse_python.rs
Normal file
23
examples/parse_python.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
/// Print the AST for a given Python file.
|
||||
use std::path::PathBuf;
|
||||
|
||||
use anyhow::Result;
|
||||
use clap::Parser;
|
||||
|
||||
use ruff::fs;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
struct Cli {
|
||||
#[arg(required = true)]
|
||||
file: PathBuf,
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let cli = Cli::parse();
|
||||
|
||||
let contents = fs::read_file(&cli.file)?;
|
||||
let ast = python_parser::file_input(python_parser::make_strspan(&contents))?.1;
|
||||
println!("{:?}", ast);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
1
resources/test/fixtures/C400.py
vendored
1
resources/test/fixtures/C400.py
vendored
@@ -1 +0,0 @@
|
||||
x = list(x for x in range(3))
|
||||
1
resources/test/fixtures/C401.py
vendored
1
resources/test/fixtures/C401.py
vendored
@@ -1 +0,0 @@
|
||||
x = set(x for x in range(3))
|
||||
1
resources/test/fixtures/C403.py
vendored
1
resources/test/fixtures/C403.py
vendored
@@ -1 +0,0 @@
|
||||
s = set([x for x in range(3)])
|
||||
1
resources/test/fixtures/C404.py
vendored
1
resources/test/fixtures/C404.py
vendored
@@ -1 +0,0 @@
|
||||
d = dict([(i, i) for i in range(3)])
|
||||
33
resources/test/fixtures/F821.py
vendored
33
resources/test/fixtures/F821.py
vendored
@@ -89,36 +89,3 @@ A = (
|
||||
f'B'
|
||||
f'{B}'
|
||||
)
|
||||
|
||||
|
||||
from typing import Annotated, Literal
|
||||
|
||||
|
||||
def arbitrary_callable() -> None:
|
||||
...
|
||||
|
||||
|
||||
class PEP593Test:
|
||||
field: Annotated[
|
||||
int,
|
||||
"base64",
|
||||
arbitrary_callable(),
|
||||
123,
|
||||
(1, 2, 3),
|
||||
]
|
||||
field_with_stringified_type: Annotated[
|
||||
"PEP593Test",
|
||||
123,
|
||||
]
|
||||
field_with_undefined_stringified_type: Annotated[
|
||||
"PEP593Test123",
|
||||
123,
|
||||
]
|
||||
field_with_nested_subscript: Annotated[
|
||||
dict[Literal["foo"], str],
|
||||
123,
|
||||
]
|
||||
field_with_undefined_nested_subscript: Annotated[
|
||||
dict["foo", "bar"], # Expected to fail as undefined.
|
||||
123,
|
||||
]
|
||||
|
||||
15
resources/test/fixtures/U002.py
vendored
15
resources/test/fixtures/U002.py
vendored
@@ -1,15 +0,0 @@
|
||||
from os.path import abspath
|
||||
|
||||
x = abspath(__file__)
|
||||
|
||||
|
||||
import os
|
||||
|
||||
|
||||
y = os.path.abspath(__file__)
|
||||
|
||||
|
||||
from os import path
|
||||
|
||||
|
||||
z = path.abspath(__file__)
|
||||
@@ -134,27 +134,6 @@ pub fn check_useless_metaclass_type(
|
||||
None
|
||||
}
|
||||
|
||||
/// Check UnnecessaryAbspath compliance.
|
||||
pub fn check_unnecessary_abspath(func: &Expr, args: &Vec<Expr>, location: Range) -> Option<Check> {
|
||||
// Validate the arguments.
|
||||
if args.len() == 1 {
|
||||
if let ExprKind::Name { id, .. } = &args[0].node {
|
||||
if id == "__file__" {
|
||||
match &func.node {
|
||||
ExprKind::Attribute { attr: id, .. } | ExprKind::Name { id, .. } => {
|
||||
if id == "abspath" {
|
||||
return Some(Check::new(CheckKind::UnnecessaryAbspath, location));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn is_ambiguous_name(name: &str) -> bool {
|
||||
name == "l" || name == "I" || name == "O"
|
||||
}
|
||||
@@ -713,88 +692,6 @@ pub fn is_super_call_with_arguments(func: &Expr, args: &Vec<Expr>) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
// flakes8-comprehensions
|
||||
/// Check `list(generator)` compliance.
|
||||
pub fn unnecessary_generator_list(expr: &Expr, func: &Expr, args: &Vec<Expr>) -> Option<Check> {
|
||||
if args.len() == 1 {
|
||||
if let ExprKind::Name { id, .. } = &func.node {
|
||||
if id == "list" {
|
||||
if let ExprKind::GeneratorExp { .. } = &args[0].node {
|
||||
return Some(Check::new(
|
||||
CheckKind::UnnecessaryGeneratorList,
|
||||
Range::from_located(expr),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Check `set(generator)` compliance.
|
||||
pub fn unnecessary_generator_set(expr: &Expr, func: &Expr, args: &Vec<Expr>) -> Option<Check> {
|
||||
if args.len() == 1 {
|
||||
if let ExprKind::Name { id, .. } = &func.node {
|
||||
if id == "set" {
|
||||
if let ExprKind::GeneratorExp { .. } = &args[0].node {
|
||||
return Some(Check::new(
|
||||
CheckKind::UnnecessaryGeneratorList,
|
||||
Range::from_located(expr),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Check `set([...])` compliance.
|
||||
pub fn unnecessary_list_comprehension_set(
|
||||
expr: &Expr,
|
||||
func: &Expr,
|
||||
args: &Vec<Expr>,
|
||||
) -> Option<Check> {
|
||||
if args.len() == 1 {
|
||||
if let ExprKind::Name { id, .. } = &func.node {
|
||||
if id == "set" {
|
||||
if let ExprKind::ListComp { .. } = &args[0].node {
|
||||
return Some(Check::new(
|
||||
CheckKind::UnnecessaryListComprehensionSet,
|
||||
Range::from_located(expr),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Check `dict([...])` compliance.
|
||||
pub fn unnecessary_list_comprehension_dict(
|
||||
expr: &Expr,
|
||||
func: &Expr,
|
||||
args: &Vec<Expr>,
|
||||
) -> Option<Check> {
|
||||
if args.len() == 1 {
|
||||
if let ExprKind::Name { id, .. } = &func.node {
|
||||
if id == "dict" {
|
||||
if let ExprKind::ListComp { elt, .. } = &args[0].node {
|
||||
match &elt.node {
|
||||
ExprKind::Tuple { elts, .. } if elts.len() == 2 => {
|
||||
return Some(Check::new(
|
||||
CheckKind::UnnecessaryListComprehensionDict,
|
||||
Range::from_located(expr),
|
||||
));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
// flake8-super
|
||||
/// Check that `super()` has no args
|
||||
pub fn check_super_args(
|
||||
|
||||
110
src/check_ast.rs
110
src/check_ast.rs
@@ -25,7 +25,7 @@ use crate::plugins;
|
||||
use crate::python::builtins::{BUILTINS, MAGIC_GLOBALS};
|
||||
use crate::python::future::ALL_FEATURE_NAMES;
|
||||
use crate::python::typing;
|
||||
use crate::settings::{PythonVersion, Settings};
|
||||
use crate::settings::Settings;
|
||||
|
||||
pub const GLOBAL_SCOPE_INDEX: usize = 0;
|
||||
|
||||
@@ -108,32 +108,11 @@ fn match_name_or_attr(expr: &Expr, target: &str) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
enum SubscriptKind {
|
||||
AnnotatedSubscript,
|
||||
PEP593AnnotatedSubscript,
|
||||
}
|
||||
|
||||
fn match_annotated_subscript(expr: &Expr) -> Option<SubscriptKind> {
|
||||
fn is_annotated_subscript(expr: &Expr) -> bool {
|
||||
match &expr.node {
|
||||
ExprKind::Attribute { attr, .. } => {
|
||||
if typing::is_annotated_subscript(attr) {
|
||||
Some(SubscriptKind::AnnotatedSubscript)
|
||||
} else if typing::is_pep593_annotated_subscript(attr) {
|
||||
Some(SubscriptKind::PEP593AnnotatedSubscript)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
ExprKind::Name { id, .. } => {
|
||||
if typing::is_annotated_subscript(id) {
|
||||
Some(SubscriptKind::AnnotatedSubscript)
|
||||
} else if typing::is_pep593_annotated_subscript(id) {
|
||||
Some(SubscriptKind::PEP593AnnotatedSubscript)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
ExprKind::Attribute { attr, .. } => typing::is_annotated_subscript(attr),
|
||||
ExprKind::Name { id, .. } => typing::is_annotated_subscript(id),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -765,42 +744,6 @@ where
|
||||
plugins::print_call(self, expr, func);
|
||||
}
|
||||
|
||||
// flake8-comprehensions
|
||||
if self.settings.enabled.contains(&CheckCode::C400) {
|
||||
if let Some(check) = checks::unnecessary_generator_list(expr, func, args) {
|
||||
self.checks.push(check);
|
||||
};
|
||||
}
|
||||
|
||||
if self.settings.enabled.contains(&CheckCode::C401) {
|
||||
if let Some(check) = checks::unnecessary_generator_set(expr, func, args) {
|
||||
self.checks.push(check);
|
||||
};
|
||||
}
|
||||
|
||||
if self.settings.enabled.contains(&CheckCode::C403) {
|
||||
if let Some(check) =
|
||||
checks::unnecessary_list_comprehension_set(expr, func, args)
|
||||
{
|
||||
self.checks.push(check);
|
||||
};
|
||||
}
|
||||
|
||||
if self.settings.enabled.contains(&CheckCode::C404) {
|
||||
if let Some(check) =
|
||||
checks::unnecessary_list_comprehension_dict(expr, func, args)
|
||||
{
|
||||
self.checks.push(check);
|
||||
};
|
||||
}
|
||||
|
||||
// pyupgrade
|
||||
if self.settings.enabled.contains(&CheckCode::U002)
|
||||
&& self.settings.target_version >= PythonVersion::Py310
|
||||
{
|
||||
plugins::unnecessary_abspath(self, expr, func, args);
|
||||
}
|
||||
|
||||
if let ExprKind::Name { id, ctx } = &func.node {
|
||||
if id == "locals" && matches!(ctx, ExprContext::Load) {
|
||||
let scope = &mut self.scopes[*(self
|
||||
@@ -919,11 +862,9 @@ where
|
||||
ExprKind::Constant {
|
||||
value: Constant::Str(value),
|
||||
..
|
||||
} => {
|
||||
if self.in_annotation && !self.in_literal {
|
||||
self.deferred_string_annotations
|
||||
.push((Range::from_located(expr), value));
|
||||
}
|
||||
} if self.in_annotation && !self.in_literal => {
|
||||
self.deferred_string_annotations
|
||||
.push((Range::from_located(expr), value));
|
||||
}
|
||||
ExprKind::Lambda { args, .. } => {
|
||||
// Visit the arguments, but avoid the body, which will be deferred.
|
||||
@@ -1074,35 +1015,12 @@ where
|
||||
}
|
||||
}
|
||||
ExprKind::Subscript { value, slice, ctx } => {
|
||||
match match_annotated_subscript(value) {
|
||||
Some(subscript) => match subscript {
|
||||
// Ex) Optional[int]
|
||||
SubscriptKind::AnnotatedSubscript => {
|
||||
self.visit_expr(value);
|
||||
self.visit_annotation(slice);
|
||||
self.visit_expr_context(ctx);
|
||||
}
|
||||
// Ex) Annotated[int, "Hello, world!"]
|
||||
SubscriptKind::PEP593AnnotatedSubscript => {
|
||||
// First argument is a type (including forward references); the rest are
|
||||
// arbitrary Python objects.
|
||||
self.visit_expr(value);
|
||||
if let ExprKind::Tuple { elts, ctx } = &slice.node {
|
||||
if let Some(expr) = elts.first() {
|
||||
self.visit_expr(expr);
|
||||
self.in_annotation = false;
|
||||
for expr in elts.iter().skip(1) {
|
||||
self.visit_expr(expr);
|
||||
}
|
||||
self.in_annotation = true;
|
||||
self.visit_expr_context(ctx);
|
||||
}
|
||||
} else {
|
||||
error!("Found non-ExprKind::Tuple argument to PEP 593 Annotation.")
|
||||
}
|
||||
}
|
||||
},
|
||||
None => visitor::walk_expr(self, expr),
|
||||
if is_annotated_subscript(value) {
|
||||
self.visit_expr(value);
|
||||
self.visit_annotation(slice);
|
||||
self.visit_expr_context(ctx);
|
||||
} else {
|
||||
visitor::walk_expr(self, expr);
|
||||
}
|
||||
}
|
||||
_ => visitor::walk_expr(self, expr),
|
||||
|
||||
@@ -53,7 +53,7 @@ pub const DEFAULT_CHECK_CODES: [CheckCode; 42] = [
|
||||
CheckCode::F901,
|
||||
];
|
||||
|
||||
pub const ALL_CHECK_CODES: [CheckCode; 57] = [
|
||||
pub const ALL_CHECK_CODES: [CheckCode; 52] = [
|
||||
// pycodestyle
|
||||
CheckCode::E402,
|
||||
CheckCode::E501,
|
||||
@@ -102,11 +102,6 @@ pub const ALL_CHECK_CODES: [CheckCode; 57] = [
|
||||
CheckCode::A001,
|
||||
CheckCode::A002,
|
||||
CheckCode::A003,
|
||||
// flake8-comprehensions
|
||||
CheckCode::C400,
|
||||
CheckCode::C401,
|
||||
CheckCode::C403,
|
||||
CheckCode::C404,
|
||||
// flake8-super
|
||||
CheckCode::SPR001,
|
||||
// flake8-print
|
||||
@@ -114,7 +109,6 @@ pub const ALL_CHECK_CODES: [CheckCode; 57] = [
|
||||
CheckCode::T203,
|
||||
// pyupgrade
|
||||
CheckCode::U001,
|
||||
CheckCode::U002,
|
||||
// Refactor
|
||||
CheckCode::R001,
|
||||
CheckCode::R002,
|
||||
@@ -172,11 +166,6 @@ pub enum CheckCode {
|
||||
A001,
|
||||
A002,
|
||||
A003,
|
||||
// flake8-comprehensions
|
||||
C400,
|
||||
C401,
|
||||
C403,
|
||||
C404,
|
||||
// flake8-super
|
||||
SPR001,
|
||||
// flake8-print
|
||||
@@ -184,7 +173,6 @@ pub enum CheckCode {
|
||||
T203,
|
||||
// pyupgrade
|
||||
U001,
|
||||
U002,
|
||||
// Refactor
|
||||
R001,
|
||||
R002,
|
||||
@@ -245,9 +233,6 @@ impl FromStr for CheckCode {
|
||||
"A001" => Ok(CheckCode::A001),
|
||||
"A002" => Ok(CheckCode::A002),
|
||||
"A003" => Ok(CheckCode::A003),
|
||||
// flake8-comprehensions
|
||||
"C403" => Ok(CheckCode::C403),
|
||||
"C404" => Ok(CheckCode::C404),
|
||||
// flake8-super
|
||||
"SPR001" => Ok(CheckCode::SPR001),
|
||||
// flake8-print
|
||||
@@ -255,7 +240,6 @@ impl FromStr for CheckCode {
|
||||
"T203" => Ok(CheckCode::T203),
|
||||
// pyupgrade
|
||||
"U001" => Ok(CheckCode::U001),
|
||||
"U002" => Ok(CheckCode::U002),
|
||||
// Refactor
|
||||
"R001" => Ok(CheckCode::R001),
|
||||
"R002" => Ok(CheckCode::R002),
|
||||
@@ -317,11 +301,6 @@ impl CheckCode {
|
||||
CheckCode::A001 => "A001",
|
||||
CheckCode::A002 => "A002",
|
||||
CheckCode::A003 => "A003",
|
||||
// flake8-comprehensions
|
||||
CheckCode::C400 => "C400",
|
||||
CheckCode::C401 => "C401",
|
||||
CheckCode::C403 => "C403",
|
||||
CheckCode::C404 => "C404",
|
||||
// flake8-super
|
||||
CheckCode::SPR001 => "SPR001",
|
||||
// flake8-print
|
||||
@@ -329,7 +308,6 @@ impl CheckCode {
|
||||
CheckCode::T203 => "T203",
|
||||
// pyupgrade
|
||||
CheckCode::U001 => "U001",
|
||||
CheckCode::U002 => "U002",
|
||||
// Refactor
|
||||
CheckCode::R001 => "R001",
|
||||
CheckCode::R002 => "R002",
|
||||
@@ -400,11 +378,6 @@ impl CheckCode {
|
||||
CheckCode::A001 => CheckKind::BuiltinVariableShadowing("...".to_string()),
|
||||
CheckCode::A002 => CheckKind::BuiltinArgumentShadowing("...".to_string()),
|
||||
CheckCode::A003 => CheckKind::BuiltinAttributeShadowing("...".to_string()),
|
||||
// flake8-comprehensions
|
||||
CheckCode::C400 => CheckKind::UnnecessaryGeneratorList,
|
||||
CheckCode::C401 => CheckKind::UnnecessaryGeneratorSet,
|
||||
CheckCode::C403 => CheckKind::UnnecessaryListComprehensionSet,
|
||||
CheckCode::C404 => CheckKind::UnnecessaryListComprehensionDict,
|
||||
// flake8-super
|
||||
CheckCode::SPR001 => CheckKind::SuperCallWithParameters,
|
||||
// flake8-print
|
||||
@@ -412,7 +385,6 @@ impl CheckCode {
|
||||
CheckCode::T203 => CheckKind::PPrintFound,
|
||||
// pyupgrade
|
||||
CheckCode::U001 => CheckKind::UselessMetaclassType,
|
||||
CheckCode::U002 => CheckKind::UnnecessaryAbspath,
|
||||
// Refactor
|
||||
CheckCode::R001 => CheckKind::UselessObjectInheritance("...".to_string()),
|
||||
CheckCode::R002 => CheckKind::NoAssertEquals,
|
||||
@@ -464,6 +436,7 @@ pub enum CheckKind {
|
||||
ModuleImportNotAtTopOfFile,
|
||||
MultiValueRepeatedKeyLiteral,
|
||||
MultiValueRepeatedKeyVariable(String),
|
||||
NoAssertEquals,
|
||||
NoneComparison(RejectedCmpop),
|
||||
NotInTest,
|
||||
NotIsTest,
|
||||
@@ -477,30 +450,20 @@ pub enum CheckKind {
|
||||
UndefinedLocal(String),
|
||||
UndefinedName(String),
|
||||
UnusedImport(String),
|
||||
UnusedNOQA(Option<String>),
|
||||
UnusedVariable(String),
|
||||
UselessMetaclassType,
|
||||
UselessObjectInheritance(String),
|
||||
YieldOutsideFunction,
|
||||
// flake8-builtin
|
||||
BuiltinVariableShadowing(String),
|
||||
BuiltinArgumentShadowing(String),
|
||||
BuiltinAttributeShadowing(String),
|
||||
// flakes8-comprehensions
|
||||
UnnecessaryGeneratorList,
|
||||
UnnecessaryGeneratorSet,
|
||||
UnnecessaryListComprehensionSet,
|
||||
UnnecessaryListComprehensionDict,
|
||||
// flake8-super
|
||||
SuperCallWithParameters,
|
||||
// flake8-print
|
||||
PrintFound,
|
||||
PPrintFound,
|
||||
// pyupgrade
|
||||
UnnecessaryAbspath,
|
||||
UselessMetaclassType,
|
||||
// Refactor
|
||||
NoAssertEquals,
|
||||
UselessObjectInheritance(String),
|
||||
// Meta
|
||||
UnusedNOQA(Option<String>),
|
||||
}
|
||||
|
||||
impl CheckKind {
|
||||
@@ -553,18 +516,12 @@ impl CheckKind {
|
||||
CheckKind::BuiltinVariableShadowing(_) => "BuiltinVariableShadowing",
|
||||
CheckKind::BuiltinArgumentShadowing(_) => "BuiltinArgumentShadowing",
|
||||
CheckKind::BuiltinAttributeShadowing(_) => "BuiltinAttributeShadowing",
|
||||
// flake8-comprehensions
|
||||
CheckKind::UnnecessaryGeneratorList => "UnnecessaryGeneratorList",
|
||||
CheckKind::UnnecessaryGeneratorSet => "UnnecessaryGeneratorSet",
|
||||
CheckKind::UnnecessaryListComprehensionSet => "UnnecessaryListComprehensionSet",
|
||||
CheckKind::UnnecessaryListComprehensionDict => "UnnecessaryListComprehensionDict",
|
||||
// flake8-super
|
||||
CheckKind::SuperCallWithParameters => "SuperCallWithParameters",
|
||||
// flake8-print
|
||||
CheckKind::PrintFound => "PrintFound",
|
||||
CheckKind::PPrintFound => "PPrintFound",
|
||||
// pyupgrade
|
||||
CheckKind::UnnecessaryAbspath => "UnnecessaryAbspath",
|
||||
CheckKind::UselessMetaclassType => "UselessMetaclassType",
|
||||
// Refactor
|
||||
CheckKind::NoAssertEquals => "NoAssertEquals",
|
||||
@@ -623,18 +580,12 @@ impl CheckKind {
|
||||
CheckKind::BuiltinVariableShadowing(_) => &CheckCode::A001,
|
||||
CheckKind::BuiltinArgumentShadowing(_) => &CheckCode::A002,
|
||||
CheckKind::BuiltinAttributeShadowing(_) => &CheckCode::A003,
|
||||
// flake8-comprehensions
|
||||
CheckKind::UnnecessaryGeneratorList => &CheckCode::C400,
|
||||
CheckKind::UnnecessaryGeneratorSet => &CheckCode::C401,
|
||||
CheckKind::UnnecessaryListComprehensionSet => &CheckCode::C403,
|
||||
CheckKind::UnnecessaryListComprehensionDict => &CheckCode::C404,
|
||||
// flake8-super
|
||||
CheckKind::SuperCallWithParameters => &CheckCode::SPR001,
|
||||
// flake8-print
|
||||
CheckKind::PrintFound => &CheckCode::T201,
|
||||
CheckKind::PPrintFound => &CheckCode::T203,
|
||||
// pyupgrade
|
||||
CheckKind::UnnecessaryAbspath => &CheckCode::U002,
|
||||
CheckKind::UselessMetaclassType => &CheckCode::U001,
|
||||
// Refactor
|
||||
CheckKind::NoAssertEquals => &CheckCode::R002,
|
||||
@@ -782,19 +733,6 @@ impl CheckKind {
|
||||
CheckKind::BuiltinAttributeShadowing(name) => {
|
||||
format!("Class attribute `{name}` is shadowing a python builtin")
|
||||
}
|
||||
// flake8-comprehensions
|
||||
CheckKind::UnnecessaryGeneratorList => {
|
||||
"Unnecessary generator - rewrite as a list comprehension".to_string()
|
||||
}
|
||||
CheckKind::UnnecessaryGeneratorSet => {
|
||||
"Unnecessary generator - rewrite as a set comprehension".to_string()
|
||||
}
|
||||
CheckKind::UnnecessaryListComprehensionSet => {
|
||||
"Unnecessary list comprehension - rewrite as a set comprehension".to_string()
|
||||
}
|
||||
CheckKind::UnnecessaryListComprehensionDict => {
|
||||
"Unnecessary list comprehension - rewrite as a dict comprehension".to_string()
|
||||
}
|
||||
// flake8-super
|
||||
CheckKind::SuperCallWithParameters => {
|
||||
"Use `super()` instead of `super(__class__, self)`".to_string()
|
||||
@@ -803,9 +741,6 @@ impl CheckKind {
|
||||
CheckKind::PrintFound => "`print` found".to_string(),
|
||||
CheckKind::PPrintFound => "`pprint` found".to_string(),
|
||||
// pyupgrade
|
||||
CheckKind::UnnecessaryAbspath => {
|
||||
"`abspath(__file__)` is unnecessary in Python 3.9 and later".to_string()
|
||||
}
|
||||
CheckKind::UselessMetaclassType => "`__metaclass__ = type` is implied".to_string(),
|
||||
// Refactor
|
||||
CheckKind::NoAssertEquals => {
|
||||
@@ -830,7 +765,6 @@ impl CheckKind {
|
||||
| CheckKind::PPrintFound
|
||||
| CheckKind::PrintFound
|
||||
| CheckKind::SuperCallWithParameters
|
||||
| CheckKind::UnnecessaryAbspath
|
||||
| CheckKind::UnusedImport(_)
|
||||
| CheckKind::UnusedNOQA(_)
|
||||
| CheckKind::UselessMetaclassType
|
||||
|
||||
@@ -8,7 +8,6 @@ use rustpython_parser::{lexer, parser};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::autofix::fixer;
|
||||
use crate::autofix::fixer::fix_file;
|
||||
use crate::check_ast::check_ast;
|
||||
use crate::check_lines::check_lines;
|
||||
use crate::checks::{Check, CheckCode, CheckKind, LintSource};
|
||||
@@ -101,33 +100,19 @@ pub fn lint_path(
|
||||
let contents = fs::read_file(path)?;
|
||||
|
||||
// Tokenize once.
|
||||
let tokens: Vec<LexResult> = tokenize(&contents);
|
||||
// let tokens: Vec<LexResult> = tokenize(&contents);
|
||||
|
||||
// Determine the noqa line for every line in the source.
|
||||
let noqa_line_for = noqa::extract_noqa_line_for(&tokens);
|
||||
// let noqa_line_for = noqa::extract_noqa_line_for(&tokens);
|
||||
|
||||
// Generate checks.
|
||||
let mut checks = check_path(path, &contents, tokens, &noqa_line_for, settings, autofix)?;
|
||||
match python_parser::file_input(python_parser::make_strspan(&contents)) {
|
||||
Ok(x) => {}
|
||||
Err(e) => return Err(anyhow::anyhow!("Err: failed")),
|
||||
}
|
||||
|
||||
// Apply autofix.
|
||||
if matches!(autofix, fixer::Mode::Apply) {
|
||||
fix_file(&mut checks, &contents, path)?;
|
||||
};
|
||||
// let _ = parser::parse_program_tokens(tokens, "<filename>")?;
|
||||
|
||||
// Convert to messages.
|
||||
let messages: Vec<Message> = checks
|
||||
.into_iter()
|
||||
.map(|check| Message {
|
||||
kind: check.kind,
|
||||
fixed: check.fix.map(|fix| fix.applied).unwrap_or_default(),
|
||||
location: check.location,
|
||||
end_location: check.end_location,
|
||||
filename: path.to_string_lossy().to_string(),
|
||||
})
|
||||
.collect();
|
||||
cache::set(path, &metadata, settings, autofix, &messages, mode);
|
||||
|
||||
Ok(messages)
|
||||
Ok(vec![])
|
||||
}
|
||||
|
||||
pub fn add_noqa_to_path(path: &Path, settings: &Settings) -> Result<usize> {
|
||||
@@ -786,54 +771,6 @@ mod tests {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn c400() -> Result<()> {
|
||||
let mut checks = check_path(
|
||||
Path::new("./resources/test/fixtures/C400.py"),
|
||||
&settings::Settings::for_rule(CheckCode::C400),
|
||||
&fixer::Mode::Generate,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(checks);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn c401() -> Result<()> {
|
||||
let mut checks = check_path(
|
||||
Path::new("./resources/test/fixtures/C401.py"),
|
||||
&settings::Settings::for_rule(CheckCode::C401),
|
||||
&fixer::Mode::Generate,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(checks);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn c403() -> Result<()> {
|
||||
let mut checks = check_path(
|
||||
Path::new("./resources/test/fixtures/C403.py"),
|
||||
&settings::Settings::for_rule(CheckCode::C403),
|
||||
&fixer::Mode::Generate,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(checks);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn c404() -> Result<()> {
|
||||
let mut checks = check_path(
|
||||
Path::new("./resources/test/fixtures/C404.py"),
|
||||
&settings::Settings::for_rule(CheckCode::C404),
|
||||
&fixer::Mode::Generate,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(checks);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn spr001() -> Result<()> {
|
||||
let mut checks = check_path(
|
||||
@@ -881,16 +818,4 @@ mod tests {
|
||||
insta::assert_yaml_snapshot!(checks);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn u002() -> Result<()> {
|
||||
let mut checks = check_path(
|
||||
Path::new("./resources/test/fixtures/U002.py"),
|
||||
&settings::Settings::for_rule(CheckCode::U002),
|
||||
&fixer::Mode::Generate,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(checks);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
41
src/main.rs
41
src/main.rs
@@ -13,21 +13,21 @@ use rayon::prelude::*;
|
||||
use regex::Regex;
|
||||
use walkdir::DirEntry;
|
||||
|
||||
use ruff::cache;
|
||||
use ruff::checks::CheckCode;
|
||||
use ruff::checks::CheckKind;
|
||||
use ruff::fs::iter_python_files;
|
||||
use ruff::linter::add_noqa_to_path;
|
||||
use ::ruff::cache;
|
||||
use ::ruff::checks::CheckCode;
|
||||
use ::ruff::checks::CheckKind;
|
||||
use ::ruff::fs::iter_python_files;
|
||||
use ::ruff::linter::add_noqa_to_path;
|
||||
use ::ruff::linter::lint_path;
|
||||
use ::ruff::logging::set_up_logging;
|
||||
use ::ruff::message::Message;
|
||||
use ::ruff::printer::{Printer, SerializationFormat};
|
||||
use ::ruff::pyproject::{self, StrCheckCodePair};
|
||||
use ::ruff::settings::CurrentSettings;
|
||||
use ::ruff::settings::{FilePattern, PerFileIgnore, Settings};
|
||||
use ::ruff::tell_user;
|
||||
use ruff::linter::autoformat_path;
|
||||
use ruff::linter::lint_path;
|
||||
use ruff::logging::set_up_logging;
|
||||
use ruff::message::Message;
|
||||
use ruff::printer::{Printer, SerializationFormat};
|
||||
use ruff::pyproject::{self, StrCheckCodePair};
|
||||
use ruff::settings::RawSettings;
|
||||
use ruff::settings::{CurrentSettings, PythonVersion};
|
||||
use ruff::settings::{FilePattern, PerFileIgnore, Settings};
|
||||
use ruff::tell_user;
|
||||
|
||||
const CARGO_PKG_NAME: &str = env!("CARGO_PKG_NAME");
|
||||
const CARGO_PKG_VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
@@ -89,16 +89,12 @@ struct Cli {
|
||||
/// Enable automatic additions of noqa directives to failing lines.
|
||||
#[arg(long)]
|
||||
add_noqa: bool,
|
||||
/// Enable automatic formatting.
|
||||
#[arg(long)]
|
||||
autoformat: bool,
|
||||
/// Regular expression matching the name of dummy variables.
|
||||
#[arg(long)]
|
||||
dummy_variable_rgx: Option<Regex>,
|
||||
/// The minimum Python version that should be supported.
|
||||
#[arg(long)]
|
||||
target_version: Option<PythonVersion>,
|
||||
/// Round-trip auto-formatting.
|
||||
// TODO(charlie): This should be a sub-command.
|
||||
#[arg(long, hide = true)]
|
||||
autoformat: bool,
|
||||
}
|
||||
|
||||
#[cfg(feature = "update-informer")]
|
||||
@@ -314,9 +310,6 @@ fn inner_main() -> Result<ExitCode> {
|
||||
if !cli.extend_ignore.is_empty() {
|
||||
settings.extend_ignore = cli.extend_ignore;
|
||||
}
|
||||
if let Some(target_version) = cli.target_version {
|
||||
settings.target_version = target_version;
|
||||
}
|
||||
if let Some(dummy_variable_rgx) = cli.dummy_variable_rgx {
|
||||
settings.dummy_variable_rgx = dummy_variable_rgx;
|
||||
}
|
||||
@@ -410,7 +403,7 @@ fn inner_main() -> Result<ExitCode> {
|
||||
#[cfg(feature = "update-informer")]
|
||||
check_for_updates();
|
||||
|
||||
if messages.iter().any(|message| !message.fixed) && !cli.exit_zero {
|
||||
if !messages.is_empty() && !cli.exit_zero {
|
||||
return Ok(ExitCode::FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ mod if_tuple;
|
||||
mod invalid_print_syntax;
|
||||
mod print_call;
|
||||
mod super_call_with_parameters;
|
||||
mod unnecessary_abspath;
|
||||
mod useless_metaclass_type;
|
||||
mod useless_object_inheritance;
|
||||
|
||||
@@ -14,6 +13,5 @@ pub use if_tuple::if_tuple;
|
||||
pub use invalid_print_syntax::invalid_print_syntax;
|
||||
pub use print_call::print_call;
|
||||
pub use super_call_with_parameters::super_call_with_parameters;
|
||||
pub use unnecessary_abspath::unnecessary_abspath;
|
||||
pub use useless_metaclass_type::useless_metaclass_type;
|
||||
pub use useless_object_inheritance::useless_object_inheritance;
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
use rustpython_ast::Expr;
|
||||
|
||||
use crate::ast::checks;
|
||||
use crate::ast::types::{CheckLocator, Range};
|
||||
use crate::autofix::fixer;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checks::Fix;
|
||||
|
||||
pub fn unnecessary_abspath(checker: &mut Checker, expr: &Expr, func: &Expr, args: &Vec<Expr>) {
|
||||
if let Some(mut check) = checks::check_unnecessary_abspath(
|
||||
func,
|
||||
args,
|
||||
checker.locate_check(Range::from_located(expr)),
|
||||
) {
|
||||
if matches!(checker.autofix, fixer::Mode::Generate | fixer::Mode::Apply) {
|
||||
check.amend(Fix {
|
||||
content: "__file__".to_string(),
|
||||
location: expr.location,
|
||||
end_location: expr.end_location,
|
||||
applied: false,
|
||||
});
|
||||
}
|
||||
checker.add_check(check);
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,6 @@ use serde::{Deserialize, Deserializer};
|
||||
|
||||
use crate::checks::CheckCode;
|
||||
use crate::fs;
|
||||
use crate::settings::PythonVersion;
|
||||
|
||||
pub fn load_config(pyproject: &Option<PathBuf>) -> Result<Config> {
|
||||
match pyproject {
|
||||
@@ -42,7 +41,6 @@ pub struct Config {
|
||||
#[serde(default)]
|
||||
pub per_file_ignores: Vec<StrCheckCodePair>,
|
||||
pub dummy_variable_rgx: Option<String>,
|
||||
pub target_version: Option<PythonVersion>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
@@ -191,7 +189,6 @@ mod tests {
|
||||
extend_ignore: vec![],
|
||||
per_file_ignores: vec![],
|
||||
dummy_variable_rgx: None,
|
||||
target_version: None,
|
||||
})
|
||||
})
|
||||
);
|
||||
@@ -216,7 +213,6 @@ line-length = 79
|
||||
extend_ignore: vec![],
|
||||
per_file_ignores: vec![],
|
||||
dummy_variable_rgx: None,
|
||||
target_version: None,
|
||||
})
|
||||
})
|
||||
);
|
||||
@@ -241,7 +237,6 @@ exclude = ["foo.py"]
|
||||
extend_ignore: vec![],
|
||||
per_file_ignores: vec![],
|
||||
dummy_variable_rgx: None,
|
||||
target_version: None,
|
||||
})
|
||||
})
|
||||
);
|
||||
@@ -266,7 +261,6 @@ select = ["E501"]
|
||||
extend_ignore: vec![],
|
||||
per_file_ignores: vec![],
|
||||
dummy_variable_rgx: None,
|
||||
target_version: None,
|
||||
})
|
||||
})
|
||||
);
|
||||
@@ -292,7 +286,6 @@ ignore = ["E501"]
|
||||
extend_ignore: vec![],
|
||||
per_file_ignores: vec![],
|
||||
dummy_variable_rgx: None,
|
||||
target_version: None,
|
||||
})
|
||||
})
|
||||
);
|
||||
@@ -361,7 +354,6 @@ other-attribute = 1
|
||||
extend_ignore: vec![],
|
||||
per_file_ignores: vec![],
|
||||
dummy_variable_rgx: None,
|
||||
target_version: None,
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ static ANNOTATED_SUBSCRIPTS: Lazy<BTreeSet<&'static str>> = Lazy::new(|| {
|
||||
"AbstractAsyncContextManager",
|
||||
"AbstractContextManager",
|
||||
"AbstractSet",
|
||||
// "Annotated",
|
||||
"AsyncContextManager",
|
||||
"AsyncGenerator",
|
||||
"AsyncIterable",
|
||||
@@ -88,7 +87,3 @@ static ANNOTATED_SUBSCRIPTS: Lazy<BTreeSet<&'static str>> = Lazy::new(|| {
|
||||
pub fn is_annotated_subscript(name: &str) -> bool {
|
||||
ANNOTATED_SUBSCRIPTS.contains(name)
|
||||
}
|
||||
|
||||
pub fn is_pep593_annotated_subscript(name: &str) -> bool {
|
||||
name == "Annotated"
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::BTreeSet;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use glob::Pattern;
|
||||
@@ -13,38 +11,6 @@ use crate::checks::{CheckCode, DEFAULT_CHECK_CODES};
|
||||
use crate::fs;
|
||||
use crate::pyproject::{load_config, StrCheckCodePair};
|
||||
|
||||
#[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum PythonVersion {
|
||||
Py33,
|
||||
Py34,
|
||||
Py35,
|
||||
Py36,
|
||||
Py37,
|
||||
Py38,
|
||||
Py39,
|
||||
Py310,
|
||||
Py311,
|
||||
}
|
||||
|
||||
impl FromStr for PythonVersion {
|
||||
type Err = anyhow::Error;
|
||||
|
||||
fn from_str(string: &str) -> Result<Self, Self::Err> {
|
||||
match string {
|
||||
"py33" => Ok(PythonVersion::Py33),
|
||||
"py34" => Ok(PythonVersion::Py34),
|
||||
"py35" => Ok(PythonVersion::Py35),
|
||||
"py36" => Ok(PythonVersion::Py36),
|
||||
"py37" => Ok(PythonVersion::Py37),
|
||||
"py38" => Ok(PythonVersion::Py38),
|
||||
"py39" => Ok(PythonVersion::Py39),
|
||||
"py310" => Ok(PythonVersion::Py310),
|
||||
"py311" => Ok(PythonVersion::Py311),
|
||||
_ => Err(anyhow!("Unknown version: {}", string)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Hash)]
|
||||
pub enum FilePattern {
|
||||
Simple(&'static str),
|
||||
@@ -97,7 +63,6 @@ pub struct RawSettings {
|
||||
pub project_root: Option<PathBuf>,
|
||||
pub pyproject: Option<PathBuf>,
|
||||
pub select: Vec<CheckCode>,
|
||||
pub target_version: PythonVersion,
|
||||
}
|
||||
|
||||
static DEFAULT_EXCLUDE: Lazy<Vec<FilePattern>> = Lazy::new(|| {
|
||||
@@ -139,7 +104,6 @@ impl RawSettings {
|
||||
.map_err(|e| anyhow!("Invalid dummy-variable-rgx value: {e}"))?,
|
||||
None => DEFAULT_DUMMY_VARIABLE_RGX.clone(),
|
||||
},
|
||||
target_version: config.target_version.unwrap_or(PythonVersion::Py310),
|
||||
exclude: config
|
||||
.exclude
|
||||
.map(|paths| {
|
||||
@@ -155,9 +119,6 @@ impl RawSettings {
|
||||
.map(|path| FilePattern::from_user(path, &project_root))
|
||||
.collect(),
|
||||
extend_ignore: config.extend_ignore,
|
||||
select: config
|
||||
.select
|
||||
.unwrap_or_else(|| DEFAULT_CHECK_CODES.to_vec()),
|
||||
extend_select: config.extend_select,
|
||||
ignore: config.ignore,
|
||||
line_length: config.line_length.unwrap_or(88),
|
||||
@@ -168,6 +129,9 @@ impl RawSettings {
|
||||
.collect(),
|
||||
project_root,
|
||||
pyproject,
|
||||
select: config
|
||||
.select
|
||||
.unwrap_or_else(|| DEFAULT_CHECK_CODES.to_vec()),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -180,7 +144,6 @@ pub struct Settings {
|
||||
pub extend_exclude: Vec<FilePattern>,
|
||||
pub line_length: usize,
|
||||
pub per_file_ignores: Vec<PerFileIgnore>,
|
||||
pub target_version: PythonVersion,
|
||||
}
|
||||
|
||||
impl Settings {
|
||||
@@ -202,7 +165,6 @@ impl Settings {
|
||||
extend_exclude: settings.extend_exclude,
|
||||
line_length: settings.line_length,
|
||||
per_file_ignores: settings.per_file_ignores,
|
||||
target_version: PythonVersion::Py310,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,7 +176,6 @@ impl Settings {
|
||||
extend_exclude: vec![],
|
||||
line_length: 88,
|
||||
per_file_ignores: vec![],
|
||||
target_version: PythonVersion::Py310,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,7 +187,6 @@ impl Settings {
|
||||
extend_exclude: vec![],
|
||||
line_length: 88,
|
||||
per_file_ignores: vec![],
|
||||
target_version: PythonVersion::Py310,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -281,7 +241,6 @@ pub struct CurrentSettings {
|
||||
pub project_root: Option<PathBuf>,
|
||||
pub pyproject: Option<PathBuf>,
|
||||
pub select: Vec<CheckCode>,
|
||||
pub target_version: PythonVersion,
|
||||
}
|
||||
|
||||
impl CurrentSettings {
|
||||
@@ -306,7 +265,6 @@ impl CurrentSettings {
|
||||
project_root: settings.project_root,
|
||||
pyproject: settings.pyproject,
|
||||
select: settings.select,
|
||||
target_version: settings.target_version,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
---
|
||||
source: src/linter.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind: UnnecessaryGeneratorList
|
||||
location:
|
||||
row: 1
|
||||
column: 5
|
||||
end_location:
|
||||
row: 1
|
||||
column: 30
|
||||
fix: ~
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
---
|
||||
source: src/linter.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind: UnnecessaryGeneratorList
|
||||
location:
|
||||
row: 1
|
||||
column: 5
|
||||
end_location:
|
||||
row: 1
|
||||
column: 29
|
||||
fix: ~
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
---
|
||||
source: src/linter.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind: UnnecessaryListComprehensionSet
|
||||
location:
|
||||
row: 1
|
||||
column: 5
|
||||
end_location:
|
||||
row: 1
|
||||
column: 31
|
||||
fix: ~
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
---
|
||||
source: src/linter.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind: UnnecessaryListComprehensionDict
|
||||
location:
|
||||
row: 1
|
||||
column: 5
|
||||
end_location:
|
||||
row: 1
|
||||
column: 37
|
||||
fix: ~
|
||||
|
||||
@@ -74,31 +74,4 @@ expression: checks
|
||||
row: 89
|
||||
column: 9
|
||||
fix: ~
|
||||
- kind:
|
||||
UndefinedName: PEP593Test123
|
||||
location:
|
||||
row: 114
|
||||
column: 10
|
||||
end_location:
|
||||
row: 114
|
||||
column: 24
|
||||
fix: ~
|
||||
- kind:
|
||||
UndefinedName: foo
|
||||
location:
|
||||
row: 122
|
||||
column: 15
|
||||
end_location:
|
||||
row: 122
|
||||
column: 19
|
||||
fix: ~
|
||||
- kind:
|
||||
UndefinedName: bar
|
||||
location:
|
||||
row: 122
|
||||
column: 22
|
||||
end_location:
|
||||
row: 122
|
||||
column: 26
|
||||
fix: ~
|
||||
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
---
|
||||
source: src/linter.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind: UnnecessaryAbspath
|
||||
location:
|
||||
row: 3
|
||||
column: 5
|
||||
end_location:
|
||||
row: 3
|
||||
column: 22
|
||||
fix:
|
||||
content: __file__
|
||||
location:
|
||||
row: 3
|
||||
column: 5
|
||||
end_location:
|
||||
row: 3
|
||||
column: 22
|
||||
applied: false
|
||||
- kind: UnnecessaryAbspath
|
||||
location:
|
||||
row: 9
|
||||
column: 5
|
||||
end_location:
|
||||
row: 9
|
||||
column: 30
|
||||
fix:
|
||||
content: __file__
|
||||
location:
|
||||
row: 9
|
||||
column: 5
|
||||
end_location:
|
||||
row: 9
|
||||
column: 30
|
||||
applied: false
|
||||
- kind: UnnecessaryAbspath
|
||||
location:
|
||||
row: 15
|
||||
column: 5
|
||||
end_location:
|
||||
row: 15
|
||||
column: 27
|
||||
fix:
|
||||
content: __file__
|
||||
location:
|
||||
row: 15
|
||||
column: 5
|
||||
end_location:
|
||||
row: 15
|
||||
column: 27
|
||||
applied: false
|
||||
|
||||
Reference in New Issue
Block a user