Compare commits

..

43 Commits

Author SHA1 Message Date
Charlie Marsh
0e8c237167 Bump version to 0.0.205 2022-12-31 13:44:39 -05:00
Harutaka Kawamura
960c5e2006 Use more precise error ranges for names (#1513) 2022-12-31 13:42:39 -05:00
Charlie Marsh
9ba17fbf92 Avoid flagging nested f-strings (#1516) 2022-12-31 13:41:21 -05:00
Charlie Marsh
bfdf972a5d Add code kind to Quick Fix action 2022-12-31 10:26:47 -05:00
Charlie Marsh
0c215365ae Bump version to 0.0.204 2022-12-31 08:20:09 -05:00
Maksudul Haque
815284f890 Check for Unsupported Files and Display Errors and Warnings (#1509) 2022-12-31 08:12:55 -05:00
Charlie Marsh
6880338a9a Restore pyproject.toml 2022-12-31 08:06:08 -05:00
Charlie Marsh
68b749c67d Remove foo directory 2022-12-31 08:05:04 -05:00
Reiner Gerecke
c0fc55b812 Generate source code with detected line ending (#1487) 2022-12-31 08:02:29 -05:00
Reiner Gerecke
ba9cf70917 Adjust test_path helper to detect round-trip autofix issues (#1501) 2022-12-31 08:02:13 -05:00
Harutaka Kawamura
f73dfbbfd3 Fix E722 and F707 ranges (#1508) 2022-12-31 07:58:46 -05:00
Reiner Gerecke
62c273cd22 Include fix commit message when showing violations together with source (#1505) 2022-12-31 07:54:41 -05:00
Harutaka Kawamura
938ad9a39e Fix N818 range (#1503) 2022-12-31 07:43:03 -05:00
Harutaka Kawamura
14248cb8cb Improve PLW0120 range (#1500) 2022-12-31 07:42:49 -05:00
Harutaka Kawamura
3a280039e1 Improve F811 range for function and class definitions (#1499) 2022-12-31 07:42:18 -05:00
Harutaka Kawamura
4e9e58bdc0 Improve T20X ranges (#1502) 2022-12-31 07:41:53 -05:00
Harutaka Kawamura
926b5494ad Remove unused snapshots (#1497) 2022-12-31 07:40:38 -05:00
Reiner Gerecke
6717b48ca5 Fix detection of changed imports in isort plugin (#1504) 2022-12-31 07:37:27 -05:00
Harutaka Kawamura
f7bb5bc858 Remove F831 (#1495) 2022-12-30 23:57:51 -05:00
Harutaka Kawamura
3e23fd1487 Stop overriding locations for expressions within f-strings (#1494) 2022-12-30 23:43:59 -05:00
Charlie Marsh
01c74e0629 Add a "fix message" to every autofix-able check (#1489) 2022-12-30 23:16:03 -05:00
Charlie Marsh
1e3cf87f67 Escape strings when formatting check messages (#1493) 2022-12-30 22:11:01 -05:00
Charlie Marsh
248447e139 Trim CLI help during generation (#1492) 2022-12-30 22:03:58 -05:00
Charlie Marsh
95f139583a Modify pyproject.toml to meet schema compliance 2022-12-30 15:51:35 -05:00
Charlie Marsh
74903f23d6 Bump version to 0.0.203 2022-12-30 15:33:30 -05:00
Charlie Marsh
3ee20a70d3 Remove lingering ruff_options.ts references 2022-12-30 15:33:09 -05:00
Charlie Marsh
4c2fbb7ac0 Remove hidden autoformat command (#1486) 2022-12-30 15:32:05 -05:00
Charlie Marsh
7a66f98590 Move some argument validation into Clap (#1485) 2022-12-30 15:29:41 -05:00
Charlie Marsh
a2bf3916f3 Make clean a standalone command 2022-12-30 15:20:18 -05:00
Reiner Gerecke
c9aa7b9308 Generate the README's --help output automatically via cargo +nightly dev generate-all (#1483) 2022-12-30 15:06:32 -05:00
Charlie Marsh
d880ca6cc6 Add a command to clear the Ruff cache (#1484) 2022-12-30 13:52:16 -05:00
Reiner Gerecke
080f99b908 Detect line endings and use them during code generation (#1482) 2022-12-30 12:59:40 -05:00
Charlie Marsh
a7dc491ff1 Fix clippy 2022-12-30 12:34:43 -05:00
Charlie Marsh
cdc8f8c91a Remove support for ur prefixes (#1481) 2022-12-30 11:21:05 -05:00
Colin Delahunty
138c46e793 Simplified code for unicode fix (#1475) 2022-12-30 11:18:52 -05:00
Charlie Marsh
a86c57a832 Support multi-line noqa directives for 'import from' (#1479) 2022-12-30 11:16:50 -05:00
Charlie Marsh
818582fe8a Bump version to 0.0.202 2022-12-30 08:16:32 -05:00
Charlie Marsh
90574c1088 Set editor background on top-level component (#1478) 2022-12-30 07:55:54 -05:00
Charlie Marsh
3061a35e7c Use more precise ranges for class and function checks (#1476) 2022-12-30 07:39:20 -05:00
Martin Fischer
87681697ae Improve CLI help for --select (#1471) 2022-12-30 07:16:44 -05:00
Martin Fischer
e9ec2a7b36 Add use test_case::test_case; to CONTRIBUTING.md
I previously tried adding the #[test_case()] attribute macro and got
confused because the Rust compilation suddenly failed with:

    error[E0658]: use of unstable library feature 'custom_test_frameworks': custom test frameworks are an unstable feature

which is a quite confusing error message.  The solution is to just add
`use test_case::test_case;`, so this commit adds that line to the
example in CONTRIBUTING.md to spare others this source of confusion.
2022-12-30 07:13:48 -05:00
Martin Fischer
b0bb75dc1c Add --select to command suggested in CONTRIBUTING.md
By default only E* and F* lints are enabled. I previously followed the
CONTRIBUTING.md instructions to implement a TID* lint and was confused
why my lint wasn't being run.
2022-12-30 07:13:48 -05:00
Martin Fischer
ebca5c2df8 Make banned-api config setting optional (#1465) 2022-12-30 07:09:56 -05:00
523 changed files with 4050 additions and 2126 deletions

View File

@@ -40,8 +40,7 @@ jobs:
- run: git diff --quiet README.md || echo "::error file=README.md::This file is outdated. Run 'cargo +nightly dev generate-all'."
- run: git diff --quiet src/checks_gen.rs || echo "::error file=src/checks_gen.rs::This file is outdated. Run 'cargo +nightly dev generate-all'."
- run: git diff --quiet ruff.schema.json || echo "::error file=ruff.schema.json::This file is outdated. Run 'cargo +nightly dev generate-all'."
- run: git diff --quiet playground/src/ruff_options.ts || echo "::error file=playground/src/ruff_options.ts::This file is outdated. Run 'cargo +nightly dev generate-all'."
- run: git diff --exit-code -- README.md src/checks_gen.rs ruff.schema.json playground/src/ruff_options.ts
- run: git diff --exit-code -- README.md src/checks_gen.rs ruff.schema.json
cargo-fmt:
name: "cargo fmt"
@@ -118,7 +117,17 @@ jobs:
${{ runner.os }}-build-
${{ runner.os }}-
- run: pip install black[d]==22.12.0
- run: cargo test --all
- name: Run tests
run: |
export INSTA_SNAPSHOT_REFERENCES_FILE="$(mktemp)"
cargo test --all
USED_SNAPSHOTS=$(cat $INSTA_SNAPSHOT_REFERENCES_FILE | xargs realpath --relative-to $PWD)
UNUSED_SNAPSHOTS=$(cat <(git ls-files '*.snap') <(echo "$USED_SNAPSHOTS") | sort | uniq -u)
if [ ! -z "$UNUSED_SNAPSHOTS" ]; then
echo "Found unused snapshots:"
echo "$UNUSED_SNAPSHOTS"
exit 1
fi
- run: cargo test --package ruff --test black_compatibility_test -- --ignored
# TODO(charlie): Re-enable the `wasm-pack` tests.

View File

@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.0.201
rev: v0.0.205
hooks:
- id: ruff

View File

@@ -66,11 +66,13 @@ understand how other, 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 --no-cache`. Once you're satisfied with the
with (e.g.) `cargo run resources/test/fixtures/E402.py --no-cache --select E402`. Once you're satisfied with the
output, codify the behavior as a snapshot test by adding a new `testcase` macro to the `mod tests`
section of `src/linter.rs`, like so:
```rust
use test_case::test_case;
#[test_case(CheckCode::A001, Path::new("A001.py"); "A001")]
...
```

16
Cargo.lock generated
View File

@@ -750,7 +750,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]]
name = "flake8-to-ruff"
version = "0.0.201-dev.0"
version = "0.0.205-dev.0"
dependencies = [
"anyhow",
"clap 4.0.32",
@@ -1878,7 +1878,7 @@ dependencies = [
[[package]]
name = "ruff"
version = "0.0.201"
version = "0.0.205"
dependencies = [
"annotate-snippets 0.9.1",
"anyhow",
@@ -1946,7 +1946,7 @@ dependencies = [
[[package]]
name = "ruff_dev"
version = "0.0.201"
version = "0.0.205"
dependencies = [
"anyhow",
"clap 4.0.32",
@@ -1967,7 +1967,7 @@ dependencies = [
[[package]]
name = "ruff_macros"
version = "0.0.201"
version = "0.0.205"
dependencies = [
"proc-macro2",
"quote",
@@ -2010,7 +2010,7 @@ dependencies = [
[[package]]
name = "rustpython-ast"
version = "0.1.0"
source = "git+https://github.com/RustPython/RustPython.git?rev=68d26955b3e24198a150315e7959719b03709dee#68d26955b3e24198a150315e7959719b03709dee"
source = "git+https://github.com/RustPython/RustPython.git?rev=8cb2b8292062adf13bde1b863a9b02c9f0bda3dd#8cb2b8292062adf13bde1b863a9b02c9f0bda3dd"
dependencies = [
"num-bigint",
"rustpython-common",
@@ -2020,7 +2020,7 @@ dependencies = [
[[package]]
name = "rustpython-common"
version = "0.0.0"
source = "git+https://github.com/RustPython/RustPython.git?rev=68d26955b3e24198a150315e7959719b03709dee#68d26955b3e24198a150315e7959719b03709dee"
source = "git+https://github.com/RustPython/RustPython.git?rev=8cb2b8292062adf13bde1b863a9b02c9f0bda3dd#8cb2b8292062adf13bde1b863a9b02c9f0bda3dd"
dependencies = [
"ascii",
"cfg-if 1.0.0",
@@ -2043,7 +2043,7 @@ dependencies = [
[[package]]
name = "rustpython-compiler-core"
version = "0.1.2"
source = "git+https://github.com/RustPython/RustPython.git?rev=68d26955b3e24198a150315e7959719b03709dee#68d26955b3e24198a150315e7959719b03709dee"
source = "git+https://github.com/RustPython/RustPython.git?rev=8cb2b8292062adf13bde1b863a9b02c9f0bda3dd#8cb2b8292062adf13bde1b863a9b02c9f0bda3dd"
dependencies = [
"bincode",
"bitflags",
@@ -2060,7 +2060,7 @@ dependencies = [
[[package]]
name = "rustpython-parser"
version = "0.1.2"
source = "git+https://github.com/RustPython/RustPython.git?rev=68d26955b3e24198a150315e7959719b03709dee#68d26955b3e24198a150315e7959719b03709dee"
source = "git+https://github.com/RustPython/RustPython.git?rev=8cb2b8292062adf13bde1b863a9b02c9f0bda3dd#8cb2b8292062adf13bde1b863a9b02c9f0bda3dd"
dependencies = [
"ahash",
"anyhow",

View File

@@ -6,7 +6,7 @@ members = [
[package]
name = "ruff"
version = "0.0.201"
version = "0.0.205"
authors = ["Charlie Marsh <charlie.r.marsh@gmail.com>"]
edition = "2021"
rust-version = "1.65.0"
@@ -51,11 +51,11 @@ path-absolutize = { version = "3.0.14", features = ["once_cell_cache", "use_unix
quick-junit = { version = "0.3.2" }
regex = { version = "1.6.0" }
ropey = { version = "1.5.0", features = ["cr_lines", "simd"], default-features = false }
ruff_macros = { version = "0.0.201", path = "ruff_macros" }
ruff_macros = { version = "0.0.205", path = "ruff_macros" }
rustc-hash = { version = "1.1.0" }
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "68d26955b3e24198a150315e7959719b03709dee" }
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "68d26955b3e24198a150315e7959719b03709dee" }
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "68d26955b3e24198a150315e7959719b03709dee" }
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "8cb2b8292062adf13bde1b863a9b02c9f0bda3dd" }
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "8cb2b8292062adf13bde1b863a9b02c9f0bda3dd" }
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "8cb2b8292062adf13bde1b863a9b02c9f0bda3dd" }
schemars = { version = "0.8.11" }
semver = { version = "1.0.16" }
serde = { version = "1.0.147", features = ["derive"] }

View File

@@ -169,7 +169,7 @@ Ruff also works with [pre-commit](https://pre-commit.com):
```yaml
- repo: https://github.com/charliermarsh/ruff-pre-commit
# Ruff version.
rev: 'v0.0.201'
rev: 'v0.0.205'
hooks:
- id: ruff
# Respect `exclude` and `extend-exclude` settings.
@@ -300,6 +300,7 @@ ruff path/to/code/ --select F401 --select F403
See `ruff --help` for more:
<!-- Begin auto-generated cli help. -->
```shell
Ruff: An extremely fast Python linter.
@@ -330,11 +331,11 @@ Options:
-n, --no-cache
Disable cache reads
--select <SELECT>
List of error codes to enable
Comma-separated list of error codes to enable (or ALL, to enable all checks)
--extend-select <EXTEND_SELECT>
Like --select, but adds additional error codes on top of the selected ones
--ignore <IGNORE>
List of error codes to ignore
Comma-separated list of error codes to disable
--extend-ignore <EXTEND_IGNORE>
Like --ignore, but adds additional error codes on top of the ignored ones
--exclude <EXCLUDE>
@@ -349,6 +350,10 @@ Options:
List of mappings from file pattern to code to exclude
--format <FORMAT>
Output serialization format for error messages [possible values: text, json, junit, grouped, github, gitlab]
--stdin-filename <STDIN_FILENAME>
The name of the file when passing it through stdin
--cache-dir <CACHE_DIR>
Path to the cache directory
--show-source
Show violations with source code
--respect-gitignore
@@ -357,12 +362,6 @@ Options:
Enforce exclusions, even for paths passed to Ruff directly on the command-line
--update-check
Enable or disable automatic update checks
--show-files
See the files Ruff will be run against with the current settings
--show-settings
See the settings Ruff will use to check a given Python file
--add-noqa
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>
@@ -370,18 +369,23 @@ Options:
--line-length <LINE_LENGTH>
Set the line-length for length-associated checks and automatic formatting
--max-complexity <MAX_COMPLEXITY>
Max McCabe complexity allowed for a function
--stdin-filename <STDIN_FILENAME>
The name of the file when passing it through stdin
Maximum McCabe complexity allowed for a given function
--add-noqa
Enable automatic additions of `noqa` directives to failing lines
--clean
Clear any caches in the current directory or any subdirectories
--explain <EXPLAIN>
Explain a rule
--cache-dir <CACHE_DIR>
Path to the cache directory
--show-files
See the files Ruff will be run against with the current settings
--show-settings
See the settings Ruff will use to check a given Python file
-h, --help
Print help information
-V, --version
Print version information
```
<!-- End auto-generated cli help. -->
### `pyproject.toml` discovery
@@ -541,7 +545,7 @@ For more, see [Pyflakes](https://pypi.org/project/pyflakes/2.5.0/) on PyPI.
| F621 | ExpressionsInStarAssignment | Too many expressions in star-unpacking assignment | |
| F622 | TwoStarredExpressions | Two starred expressions in assignment | |
| F631 | AssertTuple | Assert test is a non-empty tuple, which is always `True` | |
| F632 | IsLiteral | Use `==` and `!=` to compare constant literals | 🛠 |
| F632 | IsLiteral | Use `==` to compare constant literals | 🛠 |
| F633 | InvalidPrintSyntax | Use of `>>` is invalid with `print` function | |
| F634 | IfTuple | If test is a tuple, which is always `True` | |
| F701 | BreakOutsideLoop | `break` outside loop | |
@@ -554,7 +558,6 @@ For more, see [Pyflakes](https://pypi.org/project/pyflakes/2.5.0/) on PyPI.
| F821 | UndefinedName | Undefined name `...` | |
| F822 | UndefinedExport | Undefined name `...` in `__all__` | |
| F823 | UndefinedLocal | Local variable `...` referenced before assignment | |
| F831 | DuplicateArgumentName | Duplicate argument name in function definition | |
| F841 | UnusedVariable | Local variable `...` is assigned to but never used | |
| F842 | UnusedAnnotation | Local variable `...` is annotated but never used | |
| F901 | RaiseNotImplemented | `raise NotImplemented` should be `raise NotImplementedError` | 🛠 |
@@ -574,7 +577,7 @@ For more, see [pycodestyle](https://pypi.org/project/pycodestyle/2.9.1/) on PyPI
| E714 | NotIsTest | Test for object identity should be `is not` | 🛠 |
| E721 | TypeComparison | Do not compare types, use `isinstance()` | |
| E722 | DoNotUseBareExcept | Do not use bare `except` | |
| E731 | DoNotAssignLambda | Do not assign a lambda expression, use a def | 🛠 |
| E731 | DoNotAssignLambda | Do not assign a `lambda` expression, use a `def` | 🛠 |
| E741 | AmbiguousVariableName | Ambiguous variable name: `...` | |
| E742 | AmbiguousClassName | Ambiguous class name: `...` | |
| E743 | AmbiguousFunctionName | Ambiguous function name: `...` | |
@@ -659,7 +662,7 @@ For more, see [pyupgrade](https://pypi.org/project/pyupgrade/3.2.0/) on PyPI.
| ---- | ---- | ------- | --- |
| UP001 | UselessMetaclassType | `__metaclass__ = type` is implied | 🛠 |
| UP003 | TypeOfPrimitive | Use `str` instead of `type(...)` | 🛠 |
| UP004 | UselessObjectInheritance | Class `...` inherits from object | 🛠 |
| UP004 | UselessObjectInheritance | Class `...` inherits from `object` | 🛠 |
| UP005 | DeprecatedUnittestAlias | `assertEquals` is deprecated, use `assertEqual` | 🛠 |
| UP006 | UsePEP585Annotation | Use `list` instead of `List` for type annotations | 🛠 |
| UP007 | UsePEP604Annotation | Use `X \| Y` for type annotations | 🛠 |
@@ -673,7 +676,7 @@ For more, see [pyupgrade](https://pypi.org/project/pyupgrade/3.2.0/) on PyPI.
| UP015 | RedundantOpenModes | Unnecessary open mode parameters | 🛠 |
| UP016 | RemoveSixCompat | Unnecessary `six` compatibility usage | 🛠 |
| UP017 | DatetimeTimezoneUTC | Use `datetime.UTC` alias | 🛠 |
| UP018 | NativeLiterals | Unnecessary call to `str` and `bytes` | 🛠 |
| UP018 | NativeLiterals | Unnecessary call to `str` | 🛠 |
| UP019 | TypingTextStrAlias | `typing.Text` is deprecated, use `str` | 🛠 |
| UP020 | OpenAlias | Use builtin `open` | 🛠 |
| UP021 | ReplaceUniversalNewlines | `universal_newlines` is deprecated, use `text` | 🛠 |
@@ -1014,7 +1017,7 @@ 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'?) | |
| RUF003 | AmbiguousUnicodeCharacterComment | Comment contains ambiguous unicode character '𝐁' (did you mean 'B'?) | 🛠 |
| RUF004 | KeywordArgumentBeforeStarArgument | Keyword argument `...` must come after starred arguments | |
| RUF100 | UnusedNOQA | Unused blanket `noqa` directive | 🛠 |
@@ -1669,7 +1672,6 @@ Summary
<!-- Sections automatically generated by `cargo dev generate-options`. -->
<!-- Begin auto-generated options sections. -->
#### [`allowed-confusables`](#allowed-confusables)
A list of allowed "confusable" Unicode characters to ignore when

View File

@@ -771,7 +771,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]]
name = "flake8_to_ruff"
version = "0.0.201"
version = "0.0.205"
dependencies = [
"anyhow",
"clap",
@@ -1975,7 +1975,7 @@ dependencies = [
[[package]]
name = "ruff"
version = "0.0.201"
version = "0.0.205"
dependencies = [
"anyhow",
"bincode",

View File

@@ -1,6 +1,6 @@
[package]
name = "flake8-to-ruff"
version = "0.0.201-dev.0"
version = "0.0.205-dev.0"
edition = "2021"
[lib]

View File

@@ -98,7 +98,11 @@ export default function Editor() {
}, []);
return (
<main className={"h-full w-full flex flex-auto"}>
<main
className={
"h-full w-full flex flex-auto bg-ayu-background dark:bg-ayu-background-dark"
}
>
<Header
edit={edit}
tab={tab}

View File

@@ -44,8 +44,6 @@ export default function Header({
"border-b",
"border-gray-200",
"dark:border-gray-800",
"bg-ayu-background",
"dark:bg-ayu-background-dark",
)}
>
<div className="flex space-x-5">

View File

@@ -56,7 +56,9 @@ export default function SourceEditor({
.filter((check) => position.startLineNumber === check.location.row)
.filter((check) => check.fix)
.map((check) => ({
title: `Fix ${check.code}`,
title: check.fix
? `${check.code}: ${check.fix.message}` ?? `Fix ${check.code}`
: "Autofix",
id: `fix-${check.code}`,
kind: "quickfix",
edit: check.fix

View File

@@ -1,5 +1,19 @@
[build-system]
requires = ["maturin>=0.14,<0.15"]
build-backend = "maturin"
[project]
name = "ruff"
version = "0.0.205"
description = "An extremely fast Python linter, written in Rust."
authors = [
{ name = "Charlie Marsh", email = "charlie.r.marsh@gmail.com" },
]
maintainers = [
{ name = "Charlie Marsh", email = "charlie.r.marsh@gmail.com" },
]
requires-python = ">=3.7"
license = { file = "LICENSE" }
keywords = ["automation", "flake8", "pycodestyle", "pyflakes", "pylint", "clippy"]
classifiers = [
"Development Status :: 3 - Alpha",
@@ -17,24 +31,14 @@ classifiers = [
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Software Development :: Quality Assurance",
]
author = "Charlie Marsh"
author_email = "charlie.r.marsh@gmail.com"
description = "An extremely fast Python linter, written in Rust."
requires-python = ">=3.7"
[project.urls]
repository = "https://github.com/charliermarsh/ruff"
[build-system]
requires = ["maturin>=0.14,<0.15"]
build-backend = "maturin"
urls = { repository = "https://github.com/charliermarsh/ruff-lsp" }
[tool.maturin]
bindings = "bin"
strip = true
[tool.ruff]
update-check = true
line-length = 88
[tool.ruff.isort]
force-wrap-aliases = true

View File

@@ -51,3 +51,12 @@ secret == "s3cr3t"
token == "s3cr3t"
secrete == "s3cr3t"
password == safe == "s3cr3t"
if token == "1\n2":
pass
if token == "3\t4":
pass
if token == "5\r6":
pass

View File

@@ -0,0 +1 @@
from long_module_name import member_one, member_two, member_three, member_four, member_five

View File

@@ -0,0 +1,2 @@
from long_module_name import member_one, member_two, member_three, member_four, member_five

View File

@@ -0,0 +1,2 @@
from long_module_name import member_one, member_two, member_three, member_four, member_five

View File

@@ -1,16 +1,66 @@
"""Test: noqa directives."""
from module import (
A, # noqa: F401
B,
# This should ignore both errors.
from typing import ( # noqa: F401
List,
Sequence,
)
from module import (
A, # noqa: F401
B, # noqa: F401
# This should ignore both errors.
from typing import ( # noqa
List,
Sequence,
)
from module import (
A,
B,
# This should ignore both errors.
from typing import (
List, # noqa: F401
Sequence, # noqa: F401
)
# This should ignore both errors.
from typing import (
List, # noqa
Sequence, # noqa
)
# This should ignore the first error.
from typing import (
Mapping, # noqa: F401
Union,
)
# This should ignore both errors.
from typing import ( # noqa
List,
Sequence,
)
# This should ignore the error, but the inner noqa should be marked as unused.
from typing import ( # noqa: F401
Optional, # noqa: F401
)
# This should ignore the error, but the inner noqa should be marked as unused.
from typing import ( # noqa
Optional, # noqa: F401
)
# This should ignore the error, but mark F501 as unused.
from typing import ( # noqa: F401
Dict, # noqa: F501
)
# This should ignore the error, but mark F501 as unused.
from typing import ( # noqa: F501
Tuple, # noqa: F401
)
# This should ignore both errors.
from typing import Any, AnyStr # noqa: F401
# This should ignore both errors.
from typing import AsyncIterable, AsyncGenerator # noqa
# This should mark F501 as unused.
from typing import Awaitable, AwaitableGenerator # noqa: F501

View File

@@ -1,6 +1,8 @@
# OK
a = "abc"
b = f"ghi{'jkl'}"
# Errors
c = f"def"
d = f"def" + "ghi"
e = (
@@ -8,5 +10,17 @@ e = (
"ghi"
)
# OK
g = f"ghi{123:{45}}"
# Error
h = "x" "y" f"z"
v = 23.234234
# OK
f"{v:0.2f}"
# OK (false negatives)
f"{v:{f'0.2f'}}"
f"{f''}"

View File

@@ -1,10 +0,0 @@
def foo(x: int, y: int, x: int) -> None:
pass
def bar(x: int, y: int, *, x: int) -> None:
pass
def baz(x: int, y: int, **x: int) -> None:
pass

View File

@@ -0,0 +1,64 @@
# This should ignore both errors.
from typing import ( # noqa: F401
List,
Sequence,
)
# This should ignore both errors.
from typing import ( # noqa
List,
Sequence,
)
# This should ignore both errors.
from typing import (
List, # noqa: F401
Sequence, # noqa: F401
)
# This should ignore both errors.
from typing import (
List, # noqa
Sequence, # noqa
)
# This should ignore the first error.
from typing import (
Mapping, # noqa: F401
Union,
)
# This should ignore both errors.
from typing import ( # noqa
List,
Sequence,
)
# This should ignore the error, but the inner noqa should be marked as unused.
from typing import ( # noqa: F401
Optional, # noqa: F401
)
# This should ignore the error, but the inner noqa should be marked as unused.
from typing import ( # noqa
Optional, # noqa: F401
)
# This should ignore the error, but mark F501 as unused.
from typing import ( # noqa: F401
Dict, # noqa: F501
)
# This should ignore the error, but mark F501 as unused.
from typing import ( # noqa: F501
Tuple, # noqa: F401
)
# This should ignore both errors.
from typing import Any, AnyStr # noqa: F401
# This should ignore both errors.
from typing import AsyncIterable, AsyncGenerator # noqa
# This should mark F501 as unused.
from typing import Awaitable, AwaitableGenerator # noqa: F501

View File

@@ -652,8 +652,6 @@
"F821",
"F822",
"F823",
"F83",
"F831",
"F84",
"F841",
"F842",
@@ -1095,9 +1093,6 @@
},
"Flake8TidyImportsOptions": {
"type": "object",
"required": [
"banned-api"
],
"properties": {
"ban-relative-imports": {
"description": "Whether to ban all relative imports (`\"all\"`), or only those imports that extend into the parent module or beyond (`\"parents\"`).",
@@ -1112,7 +1107,10 @@
},
"banned-api": {
"description": "Specific modules or module members that may not be imported or accessed. Note that this check is only meant to flag accidental uses, and can be circumvented via `eval` or `importlib`.",
"type": "object",
"type": [
"object",
"null"
],
"additionalProperties": {
"$ref": "#/definitions/BannedApi"
}

View File

@@ -1,6 +1,6 @@
[package]
name = "ruff_dev"
version = "0.0.201"
version = "0.0.205"
edition = "2021"
[dependencies]
@@ -11,9 +11,9 @@ itertools = { version = "0.10.5" }
libcst = { git = "https://github.com/charliermarsh/LibCST", rev = "f2f0b7a487a8725d161fe8b3ed73a6758b21e177" }
once_cell = { version = "1.16.0" }
ruff = { path = ".." }
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "68d26955b3e24198a150315e7959719b03709dee" }
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "68d26955b3e24198a150315e7959719b03709dee" }
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "68d26955b3e24198a150315e7959719b03709dee" }
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "8cb2b8292062adf13bde1b863a9b02c9f0bda3dd" }
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "8cb2b8292062adf13bde1b863a9b02c9f0bda3dd" }
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "8cb2b8292062adf13bde1b863a9b02c9f0bda3dd" }
schemars = { version = "0.8.11" }
serde_json = {version="1.0.91"}
strum = { version = "0.24.1", features = ["strum_macros"] }

View File

@@ -4,7 +4,8 @@ use anyhow::Result;
use clap::Args;
use crate::{
generate_check_code_prefix, generate_json_schema, generate_options, generate_rules_table,
generate_check_code_prefix, generate_cli_help, generate_json_schema, generate_options,
generate_rules_table,
};
#[derive(Args)]
@@ -27,5 +28,8 @@ pub fn main(cli: &Cli) -> Result<()> {
generate_options::main(&generate_options::Cli {
dry_run: cli.dry_run,
})?;
generate_cli_help::main(&generate_cli_help::Cli {
dry_run: cli.dry_run,
})?;
Ok(())
}

View File

@@ -0,0 +1,38 @@
//! Generate CLI help.
use anyhow::Result;
use clap::{Args, CommandFactory};
use ruff::cli::Cli as MainCli;
use crate::utils::replace_readme_section;
const HELP_BEGIN_PRAGMA: &str = "<!-- Begin auto-generated cli help. -->";
const HELP_END_PRAGMA: &str = "<!-- End auto-generated cli help. -->";
#[derive(Args)]
pub struct Cli {
/// Write the generated help to stdout (rather than to `README.md`).
#[arg(long)]
pub(crate) dry_run: bool,
}
fn trim_lines(s: &str) -> String {
s.lines().map(str::trim_end).collect::<Vec<_>>().join("\n")
}
pub fn main(cli: &Cli) -> Result<()> {
let mut cmd = MainCli::command();
let output = trim_lines(cmd.render_help().to_string().trim());
if cli.dry_run {
print!("{output}");
} else {
replace_readme_section(
&format!("```shell\n{output}\n```\n"),
HELP_BEGIN_PRAGMA,
HELP_END_PRAGMA,
)?;
}
Ok(())
}

View File

@@ -1,16 +1,13 @@
//! Generate a Markdown-compatible listing of configuration options.
use std::fs;
use std::fs::OpenOptions;
use std::io::Write;
use std::path::PathBuf;
use anyhow::Result;
use clap::Args;
use itertools::Itertools;
use ruff::settings::options::Options;
use ruff::settings::options_base::{ConfigurationOptions, OptionEntry, OptionField};
use crate::utils::replace_readme_section;
const BEGIN_PRAGMA: &str = "<!-- Begin auto-generated options sections. -->";
const END_PRAGMA: &str = "<!-- End auto-generated options sections. -->";
@@ -95,30 +92,7 @@ pub fn main(cli: &Cli) -> Result<()> {
if cli.dry_run {
print!("{output}");
} else {
// Read the existing file.
let file = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.parent()
.expect("Failed to find root directory")
.join("README.md");
let existing = fs::read_to_string(&file)?;
// Extract the prefix.
let index = existing
.find(BEGIN_PRAGMA)
.expect("Unable to find begin pragma");
let prefix = &existing[..index + BEGIN_PRAGMA.len()];
// Extract the suffix.
let index = existing
.find(END_PRAGMA)
.expect("Unable to find end pragma");
let suffix = &existing[index..];
// Write the prefix, new contents, and suffix.
let mut f = OpenOptions::new().write(true).truncate(true).open(&file)?;
write!(f, "{prefix}\n\n")?;
write!(f, "{output}")?;
write!(f, "{suffix}")?;
replace_readme_section(&output, BEGIN_PRAGMA, END_PRAGMA)?;
}
Ok(())

View File

@@ -1,16 +1,13 @@
//! Generate a Markdown-compatible table of supported lint rules.
use std::fs;
use std::fs::OpenOptions;
use std::io::Write;
use std::path::PathBuf;
use anyhow::Result;
use clap::Args;
use itertools::Itertools;
use ruff::checks::{CheckCategory, CheckCode};
use strum::IntoEnumIterator;
use crate::utils::replace_readme_section;
const TABLE_BEGIN_PRAGMA: &str = "<!-- Begin auto-generated sections. -->";
const TABLE_END_PRAGMA: &str = "<!-- End auto-generated sections. -->";
@@ -85,32 +82,3 @@ pub fn main(cli: &Cli) -> Result<()> {
Ok(())
}
fn replace_readme_section(content: &str, begin_pragma: &str, end_pragma: &str) -> Result<()> {
// Read the existing file.
let file = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.parent()
.expect("Failed to find root directory")
.join("README.md");
let existing = fs::read_to_string(&file)?;
// Extract the prefix.
let index = existing
.find(begin_pragma)
.expect("Unable to find begin pragma");
let prefix = &existing[..index + begin_pragma.len()];
// Extract the suffix.
let index = existing
.find(end_pragma)
.expect("Unable to find end pragma");
let suffix = &existing[index..];
// Write the prefix, new contents, and suffix.
let mut f = OpenOptions::new().write(true).truncate(true).open(&file)?;
writeln!(f, "{prefix}")?;
write!(f, "{content}")?;
write!(f, "{suffix}")?;
Ok(())
}

View File

@@ -13,6 +13,7 @@
pub mod generate_all;
pub mod generate_check_code_prefix;
pub mod generate_cli_help;
pub mod generate_json_schema;
pub mod generate_options;
pub mod generate_rules_table;
@@ -20,3 +21,4 @@ pub mod print_ast;
pub mod print_cst;
pub mod print_tokens;
pub mod round_trip;
mod utils;

View File

@@ -14,8 +14,8 @@
use anyhow::Result;
use clap::{Parser, Subcommand};
use ruff_dev::{
generate_all, generate_check_code_prefix, generate_json_schema, generate_options,
generate_rules_table, print_ast, print_cst, print_tokens, round_trip,
generate_all, generate_check_code_prefix, generate_cli_help, generate_json_schema,
generate_options, generate_rules_table, print_ast, print_cst, print_tokens, round_trip,
};
#[derive(Parser)]
@@ -38,6 +38,8 @@ enum Commands {
GenerateRulesTable(generate_rules_table::Cli),
/// Generate a Markdown-compatible listing of configuration options.
GenerateOptions(generate_options::Cli),
/// Generate CLI help.
GenerateCliHelp(generate_cli_help::Cli),
/// Print the AST for a given Python file.
PrintAST(print_ast::Cli),
/// Print the LibCST CST for a given Python file.
@@ -56,6 +58,7 @@ fn main() -> Result<()> {
Commands::GenerateJSONSchema(args) => generate_json_schema::main(args)?,
Commands::GenerateRulesTable(args) => generate_rules_table::main(args)?,
Commands::GenerateOptions(args) => generate_options::main(args)?,
Commands::GenerateCliHelp(args) => generate_cli_help::main(args)?,
Commands::PrintAST(args) => print_ast::main(args)?,
Commands::PrintCST(args) => print_cst::main(args)?,
Commands::PrintTokens(args) => print_tokens::main(args)?,

View File

@@ -22,7 +22,11 @@ pub fn main(cli: &Cli) -> Result<()> {
let python_ast = parser::parse_program(&contents, &cli.file.to_string_lossy())?;
let locator = SourceCodeLocator::new(&contents);
let stylist = SourceCodeStyleDetector::from_contents(&contents, &locator);
let mut generator = SourceCodeGenerator::new(stylist.indentation(), stylist.quote());
let mut generator = SourceCodeGenerator::new(
stylist.indentation(),
stylist.quote(),
stylist.line_ending(),
);
generator.unparse_suite(&python_ast);
println!("{}", generator.generate()?);
Ok(())

35
ruff_dev/src/utils.rs Normal file
View File

@@ -0,0 +1,35 @@
use std::fs;
use std::fs::OpenOptions;
use std::io::Write;
use std::path::PathBuf;
use anyhow::Result;
pub fn replace_readme_section(content: &str, begin_pragma: &str, end_pragma: &str) -> Result<()> {
// Read the existing file.
let file = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.parent()
.expect("Failed to find root directory")
.join("README.md");
let existing = fs::read_to_string(&file)?;
// Extract the prefix.
let index = existing
.find(begin_pragma)
.expect("Unable to find begin pragma");
let prefix = &existing[..index + begin_pragma.len()];
// Extract the suffix.
let index = existing
.find(end_pragma)
.expect("Unable to find end pragma");
let suffix = &existing[index..];
// Write the prefix, new contents, and suffix.
let mut f = OpenOptions::new().write(true).truncate(true).open(&file)?;
writeln!(f, "{prefix}")?;
write!(f, "{content}")?;
write!(f, "{suffix}")?;
Ok(())
}

View File

@@ -1,6 +1,6 @@
[package]
name = "ruff_macros"
version = "0.0.201"
version = "0.0.205"
edition = "2021"
[lib]

View File

@@ -5,7 +5,7 @@ use regex::Regex;
use rustc_hash::{FxHashMap, FxHashSet};
use rustpython_ast::{
Arguments, Constant, Excepthandler, ExcepthandlerKind, Expr, ExprKind, Keyword, KeywordData,
Location, Stmt, StmtKind,
Located, Location, Stmt, StmtKind,
};
use rustpython_parser::lexer;
use rustpython_parser::lexer::Tok;
@@ -395,6 +395,19 @@ pub fn identifier_range(stmt: &Stmt, locator: &SourceCodeLocator) -> Range {
Range::from_located(stmt)
}
// Return the ranges of `Name` tokens within a specified node.
pub fn find_names<T>(located: &Located<T>, locator: &SourceCodeLocator) -> Vec<Range> {
let contents = locator.slice_source_code_range(&Range::from_located(located));
lexer::make_tokenizer_located(&contents, located.location)
.flatten()
.filter(|(_, tok, _)| matches!(tok, Tok::Name { .. }))
.map(|(start, _, end)| Range {
location: start,
end_location: end,
})
.collect()
}
/// Return the `Range` of `name` in `Excepthandler`.
pub fn excepthandler_name_range(
handler: &Excepthandler,
@@ -426,6 +439,64 @@ pub fn excepthandler_name_range(
}
}
/// Return the `Range` of `except` in `Excepthandler`.
pub fn except_range(handler: &Excepthandler, locator: &SourceCodeLocator) -> Range {
let ExcepthandlerKind::ExceptHandler { body, type_, .. } = &handler.node;
let end = if let Some(type_) = type_ {
type_.location
} else {
body.first()
.expect("Expected body to be non-empty")
.location
};
let contents = locator.slice_source_code_range(&Range {
location: handler.location,
end_location: end,
});
let range = lexer::make_tokenizer_located(&contents, handler.location)
.flatten()
.find(|(_, kind, _)| matches!(kind, Tok::Except { .. }))
.map(|(location, _, end_location)| Range {
location,
end_location,
})
.expect("Failed to find `except` range");
range
}
/// Return the `Range` of `else` in `For`, `AsyncFor`, and `While` statements.
pub fn else_range(stmt: &Stmt, locator: &SourceCodeLocator) -> Option<Range> {
match &stmt.node {
StmtKind::For { body, orelse, .. }
| StmtKind::AsyncFor { body, orelse, .. }
| StmtKind::While { body, orelse, .. }
if !orelse.is_empty() =>
{
let body_end = body
.last()
.expect("Expected body to be non-empty")
.end_location
.unwrap();
let contents = locator.slice_source_code_range(&Range {
location: body_end,
end_location: orelse
.first()
.expect("Expected orelse to be non-empty")
.location,
});
let range = lexer::make_tokenizer_located(&contents, body_end)
.flatten()
.find(|(_, kind, _)| matches!(kind, Tok::Else))
.map(|(location, _, end_location)| Range {
location,
end_location,
});
range
}
_ => None,
}
}
/// Return `true` if a `Stmt` appears to be part of a multi-statement line, with
/// other statements preceding it.
pub fn preceded_by_continuation(stmt: &Stmt, locator: &SourceCodeLocator) -> bool {
@@ -466,7 +537,9 @@ mod tests {
use rustpython_ast::Location;
use rustpython_parser::parser;
use crate::ast::helpers::{identifier_range, match_module_member, match_trailing_content};
use crate::ast::helpers::{
else_range, identifier_range, match_module_member, match_trailing_content,
};
use crate::ast::types::Range;
use crate::source_code_locator::SourceCodeLocator;
@@ -738,4 +811,24 @@ class Class():
Ok(())
}
#[test]
fn test_else_range() -> Result<()> {
let contents = r#"
for x in y:
pass
else:
pass
"#
.trim();
let program = parser::parse_program(contents, "<filename>")?;
let stmt = program.first().unwrap();
let locator = SourceCodeLocator::new(contents);
let range = else_range(stmt, &locator).unwrap();
assert_eq!(range.location.row(), 3);
assert_eq!(range.location.column(), 0);
assert_eq!(range.end_location.row(), 3);
assert_eq!(range.end_location.column(), 4);
Ok(())
}
}

View File

@@ -15,8 +15,9 @@ use serde::{Deserialize, Serialize};
use crate::message::Message;
use crate::settings::{flags, Settings};
static CACHE_DIR: Lazy<Option<String>> = Lazy::new(|| std::env::var("RUFF_CACHE_DIR").ok());
const CARGO_PKG_VERSION: &str = env!("CARGO_PKG_VERSION");
static CACHE_DIR: Lazy<Option<String>> = Lazy::new(|| std::env::var("RUFF_CACHE_DIR").ok());
pub const DEFAULT_CACHE_DIR_NAME: &str = ".ruff_cache";
#[derive(Serialize, Deserialize)]
struct CacheMetadata {
@@ -40,7 +41,7 @@ struct CheckResult {
pub fn cache_dir(project_root: &Path) -> PathBuf {
CACHE_DIR
.as_ref()
.map_or_else(|| project_root.join(".ruff_cache"), PathBuf::from)
.map_or_else(|| project_root.join(DEFAULT_CACHE_DIR_NAME), PathBuf::from)
}
fn content_dir() -> &'static Path {

View File

@@ -87,11 +87,11 @@ pub struct Checker<'a> {
deferred_assignments: Vec<DeferralContext<'a>>,
// Internal, derivative state.
visible_scope: VisibleScope,
in_f_string: Option<Range>,
in_annotation: bool,
in_type_definition: bool,
in_deferred_string_type_definition: bool,
in_deferred_type_definition: bool,
in_f_string: bool,
in_literal: bool,
in_subscript: bool,
seen_import_boundary: bool,
@@ -144,11 +144,11 @@ impl<'a> Checker<'a> {
modifier: Modifier::Module,
visibility: module_visibility(path),
},
in_f_string: None,
in_annotation: false,
in_type_definition: false,
in_deferred_string_type_definition: false,
in_deferred_type_definition: false,
in_f_string: false,
in_literal: false,
in_subscript: false,
seen_import_boundary: false,
@@ -161,14 +161,7 @@ impl<'a> Checker<'a> {
}
/// Add a `Check` to the `Checker`.
pub(crate) fn add_check(&mut self, mut check: Check) {
// If we're in an f-string, override the location. RustPython doesn't produce
// reliable locations for expressions within f-strings, so we use the
// span of the f-string itself as a best-effort default.
if let Some(range) = self.in_f_string {
check.location = range.location;
check.end_location = range.end_location;
}
pub(crate) fn add_check(&mut self, check: Check) {
self.checks.push(check);
}
@@ -184,16 +177,7 @@ impl<'a> Checker<'a> {
pub fn patch(&self, code: &CheckCode) -> bool {
// TODO(charlie): We can't fix errors in f-strings until RustPython adds
// location data.
matches!(self.autofix, flags::Autofix::Enabled)
&& self.in_f_string.is_none()
&& self.settings.fixable.contains(code)
}
/// Return the amended `Range` from a `Located`.
pub fn range_for<T>(&self, located: &Located<T>) -> Range {
// If we're in an f-string, override the location.
self.in_f_string
.unwrap_or_else(|| Range::from_located(located))
matches!(self.autofix, flags::Autofix::Enabled) && self.settings.fixable.contains(code)
}
/// Return `true` if the `Expr` is a reference to `typing.${target}`.
@@ -282,16 +266,17 @@ where
match &stmt.node {
StmtKind::Global { names } => {
let scope_index = *self.scope_stack.last().expect("No current scope found");
let ranges = helpers::find_names(stmt, self.locator);
if scope_index != GLOBAL_SCOPE_INDEX {
// Add the binding to the current scope.
let scope = &mut self.scopes[scope_index];
let usage = Some((scope.id, Range::from_located(stmt)));
for name in names {
for (name, range) in names.iter().zip(ranges.iter()) {
let index = self.bindings.len();
self.bindings.push(Binding {
kind: BindingKind::Global,
used: usage,
range: Range::from_located(stmt),
range: *range,
source: Some(RefEquality(stmt)),
});
scope.values.insert(name, index);
@@ -302,8 +287,9 @@ where
self.add_checks(
names
.iter()
.filter_map(|name| {
pycodestyle::checks::ambiguous_variable_name(name, stmt)
.zip(ranges.iter())
.filter_map(|(name, range)| {
pycodestyle::checks::ambiguous_variable_name(name, *range)
})
.into_iter(),
);
@@ -311,16 +297,17 @@ where
}
StmtKind::Nonlocal { names } => {
let scope_index = *self.scope_stack.last().expect("No current scope found");
let ranges = helpers::find_names(stmt, self.locator);
if scope_index != GLOBAL_SCOPE_INDEX {
let scope = &mut self.scopes[scope_index];
let usage = Some((scope.id, Range::from_located(stmt)));
for name in names {
for (name, range) in names.iter().zip(ranges.iter()) {
// Add a binding to the current scope.
let index = self.bindings.len();
self.bindings.push(Binding {
kind: BindingKind::Nonlocal,
used: usage,
range: Range::from_located(stmt),
range: *range,
source: Some(RefEquality(stmt)),
});
scope.values.insert(name, index);
@@ -328,7 +315,7 @@ where
// Mark the binding in the defining scopes as used too. (Skip the global scope
// and the current scope.)
for name in names {
for (name, range) in names.iter().zip(ranges.iter()) {
let mut exists = false;
for index in self.scope_stack.iter().skip(1).rev().skip(1) {
if let Some(index) = self.scopes[*index].values.get(&name.as_str()) {
@@ -342,7 +329,7 @@ where
if self.settings.enabled.contains(&CheckCode::PLE0117) {
self.add_check(Check::new(
CheckKind::NonlocalWithoutBinding(name.to_string()),
Range::from_located(stmt),
*range,
));
}
}
@@ -353,8 +340,9 @@ where
self.add_checks(
names
.iter()
.filter_map(|name| {
pycodestyle::checks::ambiguous_variable_name(name, stmt)
.zip(ranges.iter())
.filter_map(|(name, range)| {
pycodestyle::checks::ambiguous_variable_name(name, *range)
})
.into_iter(),
);
@@ -397,10 +385,9 @@ where
..
} => {
if self.settings.enabled.contains(&CheckCode::E743) {
if let Some(check) = pycodestyle::checks::ambiguous_function_name(
name,
Range::from_located(stmt),
) {
if let Some(check) = pycodestyle::checks::ambiguous_function_name(name, || {
helpers::identifier_range(stmt, self.locator)
}) {
self.add_check(check);
}
}
@@ -551,7 +538,7 @@ where
Binding {
kind: BindingKind::FunctionDefinition,
used: None,
range: Range::from_located(stmt),
range: helpers::identifier_range(stmt, self.locator),
source: Some(self.current_stmt().clone()),
},
);
@@ -585,9 +572,9 @@ where
}
if self.settings.enabled.contains(&CheckCode::E742) {
if let Some(check) =
pycodestyle::checks::ambiguous_class_name(name, Range::from_located(stmt))
{
if let Some(check) = pycodestyle::checks::ambiguous_class_name(name, || {
helpers::identifier_range(stmt, self.locator)
}) {
self.add_check(check);
}
}
@@ -601,9 +588,12 @@ where
}
if self.settings.enabled.contains(&CheckCode::N818) {
if let Some(check) =
pep8_naming::checks::error_suffix_on_exception_name(stmt, bases, name)
{
if let Some(check) = pep8_naming::checks::error_suffix_on_exception_name(
stmt,
bases,
name,
self.locator,
) {
self.add_check(check);
}
}
@@ -1187,7 +1177,9 @@ where
}
StmtKind::Try { handlers, .. } => {
if self.settings.enabled.contains(&CheckCode::F707) {
if let Some(check) = pyflakes::checks::default_except_not_last(handlers) {
if let Some(check) =
pyflakes::checks::default_except_not_last(handlers, self.locator)
{
self.add_check(check);
}
}
@@ -1431,7 +1423,7 @@ where
Binding {
kind: BindingKind::ClassDefinition,
used: None,
range: Range::from_located(stmt),
range: helpers::identifier_range(stmt, self.locator),
source: Some(self.current_stmt().clone()),
},
);
@@ -1555,9 +1547,10 @@ where
}
ExprContext::Store => {
if self.settings.enabled.contains(&CheckCode::E741) {
if let Some(check) =
pycodestyle::checks::ambiguous_variable_name(id, expr)
{
if let Some(check) = pycodestyle::checks::ambiguous_variable_name(
id,
Range::from_located(expr),
) {
self.add_check(check);
}
}
@@ -1728,7 +1721,7 @@ where
if self.settings.enabled.contains(&CheckCode::T201)
|| self.settings.enabled.contains(&CheckCode::T203)
{
flake8_print::plugins::print_call(self, expr, func, keywords);
flake8_print::plugins::print_call(self, func, keywords);
}
// flake8-bugbear
@@ -2166,11 +2159,12 @@ where
}
}
ExprKind::JoinedStr { values } => {
if self.settings.enabled.contains(&CheckCode::F541) {
if self.in_f_string.is_none()
&& !values
.iter()
.any(|value| matches!(value.node, ExprKind::FormattedValue { .. }))
// Conversion flags are parsed as f-strings without placeholders, so skip
// nested f-strings, which would lead to false positives.
if !self.in_f_string && self.settings.enabled.contains(&CheckCode::F541) {
if !values
.iter()
.any(|value| matches!(value.node, ExprKind::FormattedValue { .. }))
{
self.add_check(Check::new(
CheckKind::FStringMissingPlaceholders,
@@ -2178,7 +2172,6 @@ where
));
}
}
self.in_f_string = Some(Range::from_located(expr));
}
ExprKind::BinOp {
left,
@@ -2398,7 +2391,7 @@ where
}
}
if self.settings.enabled.contains(&CheckCode::UP025) {
pyupgrade::plugins::rewrite_unicode_literal(self, expr, value, kind);
pyupgrade::plugins::rewrite_unicode_literal(self, expr, kind);
}
}
ExprKind::Lambda { args, body, .. } => {
@@ -2671,6 +2664,11 @@ where
}
self.in_subscript = prev_in_subscript;
}
ExprKind::JoinedStr { .. } => {
self.in_f_string = true;
visitor::walk_expr(self, expr);
self.in_f_string = prev_in_f_string;
}
_ => visitor::walk_expr(self, expr),
}
@@ -2702,7 +2700,8 @@ where
if let Some(check) = pycodestyle::checks::do_not_use_bare_except(
type_.as_deref(),
body,
Range::from_located(excepthandler),
excepthandler,
self.locator,
) {
self.add_check(check);
}
@@ -2721,9 +2720,11 @@ where
match name {
Some(name) => {
if self.settings.enabled.contains(&CheckCode::E741) {
if let Some(check) =
pycodestyle::checks::ambiguous_variable_name(name, excepthandler)
{
if let Some(check) = pycodestyle::checks::ambiguous_variable_name(
name,
helpers::excepthandler_name_range(excepthandler, self.locator)
.expect("Failed to find `name` range"),
) {
self.add_check(check);
}
}
@@ -2790,10 +2791,6 @@ where
}
fn visit_arguments(&mut self, arguments: &'b Arguments) {
if self.settings.enabled.contains(&CheckCode::F831) {
self.checks
.extend(pyflakes::checks::duplicate_arguments(arguments));
}
if self.settings.enabled.contains(&CheckCode::B006) {
flake8_bugbear::plugins::mutable_argument_default(self, arguments);
}
@@ -2844,7 +2841,10 @@ where
);
if self.settings.enabled.contains(&CheckCode::E741) {
if let Some(check) = pycodestyle::checks::ambiguous_variable_name(&arg.node.arg, arg) {
if let Some(check) = pycodestyle::checks::ambiguous_variable_name(
&arg.node.arg,
Range::from_located(arg),
) {
self.add_check(check);
}
}
@@ -3674,7 +3674,22 @@ impl<'a> Checker<'a> {
let defined_by = binding.source.as_ref().unwrap();
let defined_in = self.child_to_parent.get(defined_by);
if self.is_ignored(&CheckCode::F401, binding.range.location.row()) {
let child = defined_by.0;
let check_lineno = binding.range.location.row();
let parent_lineno = if matches!(child.node, StmtKind::ImportFrom { .. })
&& child.location.row() != check_lineno
{
Some(child.location.row())
} else {
None
};
if self.is_ignored(&CheckCode::F401, check_lineno)
|| parent_lineno.map_or(false, |parent_lineno| {
self.is_ignored(&CheckCode::F401, parent_lineno)
})
{
ignored
.entry((defined_by, defined_in))
.or_default()
@@ -3721,26 +3736,40 @@ impl<'a> Checker<'a> {
None
};
let multiple = unused_imports.len() > 1;
for (full_name, range) in unused_imports {
let mut check = Check::new(
CheckKind::UnusedImport(full_name.clone(), ignore_init),
CheckKind::UnusedImport(full_name.clone(), ignore_init, multiple),
*range,
);
if matches!(child.node, StmtKind::ImportFrom { .. })
&& child.location.row() != range.location.row()
{
check.parent(child.location);
}
if let Some(fix) = fix.as_ref() {
check.amend(fix.clone());
}
checks.push(check);
}
}
for (_, unused_imports) in ignored
for ((defined_by, ..), unused_imports) in ignored
.into_iter()
.sorted_by_key(|((defined_by, _), _)| defined_by.0.location)
{
let child = defined_by.0;
let multiple = unused_imports.len() > 1;
for (full_name, range) in unused_imports {
checks.push(Check::new(
CheckKind::UnusedImport(full_name.clone(), ignore_init),
let mut check = Check::new(
CheckKind::UnusedImport(full_name.clone(), ignore_init, multiple),
*range,
));
);
if matches!(child.node, StmtKind::ImportFrom { .. })
&& child.location.row() != range.location.row()
{
check.parent(child.location);
}
checks.push(check);
}
}
}

View File

@@ -11,11 +11,13 @@ use crate::isort;
use crate::isort::track::ImportTracker;
use crate::settings::{flags, Settings};
use crate::source_code_locator::SourceCodeLocator;
use crate::source_code_style::SourceCodeStyleDetector;
fn check_import_blocks(
tracker: ImportTracker,
locator: &SourceCodeLocator,
settings: &Settings,
stylist: &SourceCodeStyleDetector,
autofix: flags::Autofix,
package: Option<&Path>,
) -> Vec<Check> {
@@ -23,7 +25,7 @@ fn check_import_blocks(
for block in tracker.into_iter() {
if !block.imports.is_empty() {
if let Some(check) =
isort::plugins::check_imports(&block, locator, settings, autofix, package)
isort::plugins::check_imports(&block, locator, settings, stylist, autofix, package)
{
checks.push(check);
}
@@ -32,11 +34,13 @@ fn check_import_blocks(
checks
}
#[allow(clippy::too_many_arguments)]
pub fn check_imports(
python_ast: &Suite,
locator: &SourceCodeLocator,
directives: &IsortDirectives,
settings: &Settings,
stylist: &SourceCodeStyleDetector,
autofix: flags::Autofix,
path: &Path,
package: Option<&Path>,
@@ -45,5 +49,5 @@ pub fn check_imports(
for stmt in python_ast {
tracker.visit_stmt(stmt);
}
check_import_blocks(tracker, locator, settings, autofix, package)
check_import_blocks(tracker, locator, settings, stylist, autofix, package)
}

View File

@@ -25,12 +25,6 @@ pub fn check_noqa(
let enforce_noqa = settings.enabled.contains(&CheckCode::RUF100);
checks.sort_by_key(|check| check.location);
let mut checks_iter = checks.iter().enumerate().peekable();
if let Some((_index, check)) = checks_iter.peek() {
assert!(check.location.row() >= 1);
}
let lines: Vec<&str> = contents.lines().collect();
for lineno in commented_lines {
// If we hit an exemption for the entire file, bail.
@@ -44,20 +38,18 @@ pub fn check_noqa(
.entry(lineno - 1)
.or_insert_with(|| (noqa::extract_noqa_directive(lines[lineno - 1]), vec![]));
}
}
// Remove any ignored checks.
while let Some((index, check)) =
checks_iter.next_if(|(_index, check)| check.location.row() <= *lineno)
{
if check.kind == CheckKind::BlanketNOQA {
continue;
}
// Grab the noqa (logical) line number for the current (physical) line.
// If there are newlines at the end of the file, they won't be represented in
// `noqa_line_for`, so fallback to the current line.
let check_lineno = check.location.row();
let noqa_lineno = noqa_line_for.get(&check_lineno).unwrap_or(&check_lineno);
if noqa_lineno == lineno {
// Remove any ignored checks.
for (index, check) in checks.iter().enumerate() {
if check.kind == CheckKind::BlanketNOQA {
continue;
}
// Is the check ignored by a `noqa` directive on the parent line?
if let Some(parent_lineno) = check.parent.map(|location| location.row()) {
let noqa_lineno = noqa_line_for.get(&parent_lineno).unwrap_or(&parent_lineno);
if commented_lines.contains(noqa_lineno) {
let noqa = noqa_directives.entry(noqa_lineno - 1).or_insert_with(|| {
(noqa::extract_noqa_directive(lines[noqa_lineno - 1]), vec![])
});
@@ -65,17 +57,41 @@ pub fn check_noqa(
(Directive::All(..), matches) => {
matches.push(check.kind.code().as_ref());
ignored.push(index);
continue;
}
(Directive::Codes(.., codes), matches) => {
if noqa::includes(check.kind.code(), codes) {
matches.push(check.kind.code().as_ref());
ignored.push(index);
continue;
}
}
(Directive::None, ..) => {}
}
}
}
// Is the check ignored by a `noqa` directive on the same line?
let check_lineno = check.location.row();
let noqa_lineno = noqa_line_for.get(&check_lineno).unwrap_or(&check_lineno);
if commented_lines.contains(noqa_lineno) {
let noqa = noqa_directives
.entry(noqa_lineno - 1)
.or_insert_with(|| (noqa::extract_noqa_directive(lines[noqa_lineno - 1]), vec![]));
match noqa {
(Directive::All(..), matches) => {
matches.push(check.kind.code().as_ref());
ignored.push(index);
}
(Directive::Codes(.., codes), matches) => {
if noqa::includes(check.kind.code(), codes) {
matches.push(check.kind.code().as_ref());
ignored.push(index);
}
}
(Directive::None, ..) => {}
}
}
}
// Enforce that the noqa directive was actually used (RUF100).

View File

@@ -3,6 +3,7 @@ use std::fmt;
use itertools::Itertools;
use once_cell::sync::Lazy;
use rustc_hash::FxHashMap;
use rustpython_ast::Cmpop;
use rustpython_parser::ast::Location;
use serde::{Deserialize, Serialize};
use strum_macros::{AsRefStr, Display, EnumIter, EnumString};
@@ -91,7 +92,6 @@ pub enum CheckCode {
F821,
F822,
F823,
F831,
F841,
F842,
F901,
@@ -618,11 +618,37 @@ pub enum LintSource {
}
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum RejectedCmpop {
pub enum EqCmpop {
Eq,
NotEq,
}
impl From<&Cmpop> for EqCmpop {
fn from(cmpop: &Cmpop) -> Self {
match cmpop {
Cmpop::Eq => EqCmpop::Eq,
Cmpop::NotEq => EqCmpop::NotEq,
_ => unreachable!("Expected Cmpop::Eq | Cmpop::NotEq"),
}
}
}
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum IsCmpop {
Is,
IsNot,
}
impl From<&Cmpop> for IsCmpop {
fn from(cmpop: &Cmpop) -> Self {
match cmpop {
Cmpop::Is => IsCmpop::Is,
Cmpop::IsNot => IsCmpop::IsNot,
_ => unreachable!("Expected Cmpop::Is | Cmpop::IsNot"),
}
}
}
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum DeferralKeyword {
Yield,
@@ -655,6 +681,21 @@ impl fmt::Display for Branch {
}
}
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum LiteralType {
Str,
Bytes,
}
impl fmt::Display for LiteralType {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match self {
LiteralType::Str => fmt.write_str("str"),
LiteralType::Bytes => fmt.write_str("bytes"),
}
}
}
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct UnusedCodes {
pub unknown: Vec<String>,
@@ -668,17 +709,17 @@ pub enum CheckKind {
AmbiguousClassName(String),
AmbiguousFunctionName(String),
AmbiguousVariableName(String),
DoNotAssignLambda,
DoNotAssignLambda(String),
DoNotUseBareExcept,
IOError(String),
LineTooLong(usize, usize),
ModuleImportNotAtTopOfFile,
MultipleImportsOnOneLine,
NoneComparison(RejectedCmpop),
NoneComparison(EqCmpop),
NotInTest,
NotIsTest,
SyntaxError(String),
TrueFalseComparison(bool, RejectedCmpop),
TrueFalseComparison(bool, EqCmpop),
TypeComparison,
// pycodestyle warnings
NoNewLineAtEndOfFile,
@@ -688,7 +729,6 @@ pub enum CheckKind {
BreakOutsideLoop,
ContinueOutsideLoop,
DefaultExceptNotLast,
DuplicateArgumentName,
ExpressionsInStarAssignment,
FStringMissingPlaceholders,
ForwardAnnotationSyntaxError(String),
@@ -699,7 +739,7 @@ pub enum CheckKind {
ImportStarUsage(String, Vec<String>),
ImportStarUsed(String),
InvalidPrintSyntax,
IsLiteral,
IsLiteral(IsCmpop),
LateFutureImport,
MultiValueRepeatedKeyLiteral,
MultiValueRepeatedKeyVariable(String),
@@ -725,7 +765,7 @@ pub enum CheckKind {
UndefinedLocal(String),
UnusedAnnotation(String),
UndefinedName(String),
UnusedImport(String, bool),
UnusedImport(String, bool, bool),
UnusedVariable(String),
YieldOutsideFunction(DeferralKeyword),
// pylint
@@ -859,10 +899,10 @@ pub enum CheckKind {
UnnecessaryEncodeUTF8,
ConvertTypedDictFunctionalToClass(String),
ConvertNamedTupleFunctionalToClass(String),
RedundantOpenModes,
RedundantOpenModes(Option<String>),
RemoveSixCompat,
DatetimeTimezoneUTC,
NativeLiterals,
NativeLiterals(LiteralType),
OpenAlias,
ReplaceUniversalNewlines,
ReplaceStdoutStderr,
@@ -1030,13 +1070,13 @@ impl CheckCode {
CheckCode::E401 => CheckKind::MultipleImportsOnOneLine,
CheckCode::E402 => CheckKind::ModuleImportNotAtTopOfFile,
CheckCode::E501 => CheckKind::LineTooLong(89, 88),
CheckCode::E711 => CheckKind::NoneComparison(RejectedCmpop::Eq),
CheckCode::E712 => CheckKind::TrueFalseComparison(true, RejectedCmpop::Eq),
CheckCode::E711 => CheckKind::NoneComparison(EqCmpop::Eq),
CheckCode::E712 => CheckKind::TrueFalseComparison(true, EqCmpop::Eq),
CheckCode::E713 => CheckKind::NotInTest,
CheckCode::E714 => CheckKind::NotIsTest,
CheckCode::E721 => CheckKind::TypeComparison,
CheckCode::E722 => CheckKind::DoNotUseBareExcept,
CheckCode::E731 => CheckKind::DoNotAssignLambda,
CheckCode::E731 => CheckKind::DoNotAssignLambda("...".to_string()),
CheckCode::E741 => CheckKind::AmbiguousVariableName("...".to_string()),
CheckCode::E742 => CheckKind::AmbiguousClassName("...".to_string()),
CheckCode::E743 => CheckKind::AmbiguousFunctionName("...".to_string()),
@@ -1046,7 +1086,7 @@ impl CheckCode {
CheckCode::W292 => CheckKind::NoNewLineAtEndOfFile,
CheckCode::W605 => CheckKind::InvalidEscapeSequence('c'),
// pyflakes
CheckCode::F401 => CheckKind::UnusedImport("...".to_string(), false),
CheckCode::F401 => CheckKind::UnusedImport("...".to_string(), false, false),
CheckCode::F402 => CheckKind::ImportShadowedByLoopVar("...".to_string(), 1),
CheckCode::F403 => CheckKind::ImportStarUsed("...".to_string()),
CheckCode::F404 => CheckKind::LateFutureImport,
@@ -1079,7 +1119,7 @@ impl CheckCode {
CheckCode::F621 => CheckKind::ExpressionsInStarAssignment,
CheckCode::F622 => CheckKind::TwoStarredExpressions,
CheckCode::F631 => CheckKind::AssertTuple,
CheckCode::F632 => CheckKind::IsLiteral,
CheckCode::F632 => CheckKind::IsLiteral(IsCmpop::Is),
CheckCode::F633 => CheckKind::InvalidPrintSyntax,
CheckCode::F634 => CheckKind::IfTuple,
CheckCode::F701 => CheckKind::BreakOutsideLoop,
@@ -1092,7 +1132,6 @@ impl CheckCode {
CheckCode::F821 => CheckKind::UndefinedName("...".to_string()),
CheckCode::F822 => CheckKind::UndefinedExport("...".to_string()),
CheckCode::F823 => CheckKind::UndefinedLocal("...".to_string()),
CheckCode::F831 => CheckKind::DuplicateArgumentName,
CheckCode::F841 => CheckKind::UnusedVariable("...".to_string()),
CheckCode::F842 => CheckKind::UnusedAnnotation("...".to_string()),
CheckCode::F901 => CheckKind::RaiseNotImplemented,
@@ -1253,10 +1292,10 @@ impl CheckCode {
CheckCode::UP012 => CheckKind::UnnecessaryEncodeUTF8,
CheckCode::UP013 => CheckKind::ConvertTypedDictFunctionalToClass("...".to_string()),
CheckCode::UP014 => CheckKind::ConvertNamedTupleFunctionalToClass("...".to_string()),
CheckCode::UP015 => CheckKind::RedundantOpenModes,
CheckCode::UP015 => CheckKind::RedundantOpenModes(None),
CheckCode::UP016 => CheckKind::RemoveSixCompat,
CheckCode::UP017 => CheckKind::DatetimeTimezoneUTC,
CheckCode::UP018 => CheckKind::NativeLiterals,
CheckCode::UP018 => CheckKind::NativeLiterals(LiteralType::Str),
CheckCode::UP019 => CheckKind::TypingTextStrAlias,
CheckCode::UP020 => CheckKind::OpenAlias,
CheckCode::UP021 => CheckKind::ReplaceUniversalNewlines,
@@ -1589,7 +1628,6 @@ impl CheckCode {
CheckCode::F821 => CheckCategory::Pyflakes,
CheckCode::F822 => CheckCategory::Pyflakes,
CheckCode::F823 => CheckCategory::Pyflakes,
CheckCode::F831 => CheckCategory::Pyflakes,
CheckCode::F841 => CheckCategory::Pyflakes,
CheckCode::F842 => CheckCategory::Pyflakes,
CheckCode::F901 => CheckCategory::Pyflakes,
@@ -1724,9 +1762,8 @@ impl CheckKind {
CheckKind::BreakOutsideLoop => &CheckCode::F701,
CheckKind::ContinueOutsideLoop => &CheckCode::F702,
CheckKind::DefaultExceptNotLast => &CheckCode::F707,
CheckKind::DoNotAssignLambda => &CheckCode::E731,
CheckKind::DoNotAssignLambda(..) => &CheckCode::E731,
CheckKind::DoNotUseBareExcept => &CheckCode::E722,
CheckKind::DuplicateArgumentName => &CheckCode::F831,
CheckKind::FStringMissingPlaceholders => &CheckCode::F541,
CheckKind::ForwardAnnotationSyntaxError(..) => &CheckCode::F722,
CheckKind::FutureFeatureNotDefined(..) => &CheckCode::F407,
@@ -1737,7 +1774,7 @@ impl CheckKind {
CheckKind::ImportStarUsage(..) => &CheckCode::F405,
CheckKind::ImportStarUsed(..) => &CheckCode::F403,
CheckKind::InvalidPrintSyntax => &CheckCode::F633,
CheckKind::IsLiteral => &CheckCode::F632,
CheckKind::IsLiteral(..) => &CheckCode::F632,
CheckKind::LateFutureImport => &CheckCode::F404,
CheckKind::LineTooLong(..) => &CheckCode::E501,
CheckKind::MultipleImportsOnOneLine => &CheckCode::E401,
@@ -1909,10 +1946,10 @@ impl CheckKind {
CheckKind::UnnecessaryEncodeUTF8 => &CheckCode::UP012,
CheckKind::ConvertTypedDictFunctionalToClass(..) => &CheckCode::UP013,
CheckKind::ConvertNamedTupleFunctionalToClass(..) => &CheckCode::UP014,
CheckKind::RedundantOpenModes => &CheckCode::UP015,
CheckKind::RedundantOpenModes(..) => &CheckCode::UP015,
CheckKind::RemoveSixCompat => &CheckCode::UP016,
CheckKind::DatetimeTimezoneUTC => &CheckCode::UP017,
CheckKind::NativeLiterals => &CheckCode::UP018,
CheckKind::NativeLiterals(..) => &CheckCode::UP018,
CheckKind::TypingTextStrAlias => &CheckCode::UP019,
CheckKind::OpenAlias => &CheckCode::UP020,
CheckKind::ReplaceUniversalNewlines => &CheckCode::UP021,
@@ -2068,13 +2105,10 @@ impl CheckKind {
CheckKind::DefaultExceptNotLast => {
"An `except` block as not the last exception handler".to_string()
}
CheckKind::DoNotAssignLambda => {
"Do not assign a lambda expression, use a def".to_string()
CheckKind::DoNotAssignLambda(..) => {
"Do not assign a `lambda` expression, use a `def`".to_string()
}
CheckKind::DoNotUseBareExcept => "Do not use bare `except`".to_string(),
CheckKind::DuplicateArgumentName => {
"Duplicate argument name in function definition".to_string()
}
CheckKind::ForwardAnnotationSyntaxError(body) => {
format!("Syntax error in forward annotation: `{body}`")
}
@@ -2105,7 +2139,10 @@ impl CheckKind {
.join(", ");
format!("`{name}` may be undefined, or defined from star imports: {sources}")
}
CheckKind::IsLiteral => "Use `==` and `!=` to compare constant literals".to_string(),
CheckKind::IsLiteral(cmpop) => match cmpop {
IsCmpop::Is => "Use `==` to compare constant literals".to_string(),
IsCmpop::IsNot => "Use `!=` to compare constant literals".to_string(),
},
CheckKind::LateFutureImport => {
"`from __future__` imports must occur at the beginning of the file".to_string()
}
@@ -2123,10 +2160,8 @@ impl CheckKind {
format!("Dictionary key `{name}` repeated")
}
CheckKind::NoneComparison(op) => match op {
RejectedCmpop::Eq => "Comparison to `None` should be `cond is None`".to_string(),
RejectedCmpop::NotEq => {
"Comparison to `None` should be `cond is not None`".to_string()
}
EqCmpop::Eq => "Comparison to `None` should be `cond is None`".to_string(),
EqCmpop::NotEq => "Comparison to `None` should be `cond is not None`".to_string(),
},
CheckKind::NotInTest => "Test for membership should be `not in`".to_string(),
CheckKind::NotIsTest => "Test for object identity should be `is not`".to_string(),
@@ -2190,16 +2225,16 @@ impl CheckKind {
CheckKind::ExpressionsInStarAssignment => {
"Too many expressions in star-unpacking assignment".to_string()
}
CheckKind::TrueFalseComparison(true, RejectedCmpop::Eq) => {
CheckKind::TrueFalseComparison(true, EqCmpop::Eq) => {
"Comparison to `True` should be `cond is True`".to_string()
}
CheckKind::TrueFalseComparison(true, RejectedCmpop::NotEq) => {
CheckKind::TrueFalseComparison(true, EqCmpop::NotEq) => {
"Comparison to `True` should be `cond is not True`".to_string()
}
CheckKind::TrueFalseComparison(false, RejectedCmpop::Eq) => {
CheckKind::TrueFalseComparison(false, EqCmpop::Eq) => {
"Comparison to `False` should be `cond is False`".to_string()
}
CheckKind::TrueFalseComparison(false, RejectedCmpop::NotEq) => {
CheckKind::TrueFalseComparison(false, EqCmpop::NotEq) => {
"Comparison to `False` should be `cond is not False`".to_string()
}
CheckKind::TwoStarredExpressions => "Two starred expressions in assignment".to_string(),
@@ -2216,7 +2251,7 @@ impl CheckKind {
CheckKind::UnusedAnnotation(name) => {
format!("Local variable `{name}` is annotated but never used")
}
CheckKind::UnusedImport(name, ignore_init) => {
CheckKind::UnusedImport(name, ignore_init, ..) => {
if *ignore_init {
format!(
"`{name}` imported but unused; consider adding to `__all__` or using a \
@@ -2627,7 +2662,7 @@ impl CheckKind {
format!("`{alias}` is deprecated, use `{target}`")
}
CheckKind::UselessObjectInheritance(name) => {
format!("Class `{name}` inherits from object")
format!("Class `{name}` inherits from `object`")
}
CheckKind::UsePEP585Annotation(name) => {
format!(
@@ -2653,14 +2688,24 @@ impl CheckKind {
"Unnecessary parameters to `functools.lru_cache`".to_string()
}
CheckKind::UnnecessaryEncodeUTF8 => "Unnecessary call to `encode` as UTF-8".to_string(),
CheckKind::RedundantOpenModes => "Unnecessary open mode parameters".to_string(),
CheckKind::RedundantOpenModes(replacement) => match replacement {
None => "Unnecessary open mode parameters".to_string(),
Some(replacement) => {
format!("Unnecessary open mode parameters, use \"{replacement}\"")
}
},
CheckKind::RemoveSixCompat => "Unnecessary `six` compatibility usage".to_string(),
CheckKind::DatetimeTimezoneUTC => "Use `datetime.UTC` alias".to_string(),
CheckKind::NativeLiterals => "Unnecessary call to `str` and `bytes`".to_string(),
CheckKind::NativeLiterals(literal_type) => {
format!("Unnecessary call to `{literal_type}`")
}
CheckKind::OpenAlias => "Use builtin `open`".to_string(),
CheckKind::ConvertTypedDictFunctionalToClass(name) => {
format!("Convert `{name}` from `TypedDict` functional to class syntax")
}
CheckKind::ConvertNamedTupleFunctionalToClass(name) => {
format!("Convert `{name}` from `NamedTuple` functional to class syntax")
}
CheckKind::ReplaceUniversalNewlines => {
"`universal_newlines` is deprecated, use `text`".to_string()
}
@@ -2671,9 +2716,6 @@ impl CheckKind {
"`cElementTree` is deprecated, use `ElementTree`".to_string()
}
CheckKind::RewriteUnicodeLiteral => "Remove unicode literals from strings".to_string(),
CheckKind::ConvertNamedTupleFunctionalToClass(name) => {
format!("Convert `{name}` from `NamedTuple` functional to class syntax")
}
// pydocstyle
CheckKind::FitsOnOneLine => "One-line docstring should fit on one line".to_string(),
CheckKind::BlankLineAfterSummary => {
@@ -2850,14 +2892,13 @@ impl CheckKind {
CheckKind::HardcodedBindAllInterfaces => {
"Possible binding to all interfaces".to_string()
}
CheckKind::HardcodedPasswordString(string) => {
format!("Possible hardcoded password: `\"{string}\"`")
}
CheckKind::HardcodedPasswordFuncArg(string) => {
format!("Possible hardcoded password: `\"{string}\"`")
}
CheckKind::HardcodedPasswordDefault(string) => {
format!("Possible hardcoded password: `\"{string}\"`")
CheckKind::HardcodedPasswordString(string)
| CheckKind::HardcodedPasswordFuncArg(string)
| CheckKind::HardcodedPasswordDefault(string) => {
format!(
"Possible hardcoded password: `\"{}\"`",
string.escape_debug()
)
}
// flake8-blind-except
CheckKind::BlindExcept(name) => format!("Do not catch blind exception: `{name}`"),
@@ -3089,6 +3130,7 @@ impl CheckKind {
self,
CheckKind::AmbiguousUnicodeCharacterString(..)
| CheckKind::AmbiguousUnicodeCharacterDocstring(..)
| CheckKind::AmbiguousUnicodeCharacterComment(..)
| CheckKind::BlankLineAfterLastSection(..)
| CheckKind::BlankLineAfterSection(..)
| CheckKind::BlankLineAfterSummary
@@ -3101,7 +3143,7 @@ impl CheckKind {
| CheckKind::DatetimeTimezoneUTC
| CheckKind::DeprecatedUnittestAlias(..)
| CheckKind::DoNotAssertFalse
| CheckKind::DoNotAssignLambda
| CheckKind::DoNotAssignLambda(..)
| CheckKind::DuplicateHandlerException(..)
| CheckKind::EndsInPeriod
| CheckKind::EndsInPunctuation
@@ -3109,11 +3151,11 @@ impl CheckKind {
| CheckKind::ImplicitReturn
| CheckKind::ImplicitReturnValue
| CheckKind::InvalidEscapeSequence(..)
| CheckKind::IsLiteral
| CheckKind::IsLiteral(..)
| CheckKind::KeyInDict(..)
| CheckKind::MisplacedComparisonConstant(..)
| CheckKind::MissingReturnTypeSpecialMethod(..)
| CheckKind::NativeLiterals
| CheckKind::NativeLiterals(..)
| CheckKind::OpenAlias
| CheckKind::NewLineAfterLastParagraph
| CheckKind::ReplaceUniversalNewlines
@@ -3136,10 +3178,10 @@ impl CheckKind {
| CheckKind::OneBlankLineBeforeClass(..)
| CheckKind::PEP3120UnnecessaryCodingComment
| CheckKind::PPrintFound
| CheckKind::PercentFormatExtraNamedArguments(..)
| CheckKind::PrintFound
| CheckKind::PercentFormatExtraNamedArguments(..)
| CheckKind::RaiseNotImplemented
| CheckKind::RedundantOpenModes
| CheckKind::RedundantOpenModes(..)
| CheckKind::RedundantTupleInExceptionHandler(..)
| CheckKind::RemoveSixCompat
| CheckKind::SectionNameEndsInColon(..)
@@ -3171,7 +3213,7 @@ impl CheckKind {
| CheckKind::UnnecessaryLiteralWithinTupleCall(..)
| CheckKind::UnnecessaryReturnNone
| CheckKind::UnsortedImports
| CheckKind::UnusedImport(_, false)
| CheckKind::UnusedImport(_, false, _)
| CheckKind::UnusedLoopControlVariable(..)
| CheckKind::UnusedNOQA(..)
| CheckKind::UsePEP585Annotation(..)
@@ -3182,6 +3224,235 @@ impl CheckKind {
| CheckKind::UselessObjectInheritance(..)
)
}
/// The message used to describe the fix action for a given `CheckKind`.
pub fn commit(&self) -> Option<String> {
match self {
CheckKind::AmbiguousUnicodeCharacterString(confusable, representant)
| CheckKind::AmbiguousUnicodeCharacterDocstring(confusable, representant)
| CheckKind::AmbiguousUnicodeCharacterComment(confusable, representant) => {
Some(format!("Replace '{confusable}' with '{representant}'"))
}
CheckKind::BlankLineAfterLastSection(name) => {
Some(format!("Add blank line after \"{name}\""))
}
CheckKind::BlankLineAfterSection(name) => {
Some(format!("Add blank line after \"{name}\""))
}
CheckKind::BlankLineAfterSummary => Some("Insert single blank line".to_string()),
CheckKind::BlankLineBeforeSection(name) => {
Some(format!("Add blank line before \"{name}\""))
}
CheckKind::CapitalizeSectionName(name) => Some(format!("Capitalize \"{name}\"")),
CheckKind::CommentedOutCode => Some("Remove commented-out code".to_string()),
CheckKind::ConvertTypedDictFunctionalToClass(name)
| CheckKind::ConvertNamedTupleFunctionalToClass(name) => {
Some(format!("Convert `{name}` to class syntax"))
}
CheckKind::DashedUnderlineAfterSection(name) => {
Some(format!("Add dashed line under \"{name}\""))
}
CheckKind::DatetimeTimezoneUTC => Some("Convert to `datetime.UTC` alias".to_string()),
CheckKind::DeprecatedUnittestAlias(alias, target) => {
Some(format!("Replace `{target}` with `{alias}`"))
}
CheckKind::DoNotAssertFalse => Some("Replace `assert False`".to_string()),
CheckKind::DoNotAssignLambda(name) => Some(format!("Rewrite `{name}` as a `def`")),
CheckKind::DuplicateHandlerException(..) => Some("De-duplicate exceptions".to_string()),
CheckKind::EndsInPeriod => Some("Add period".to_string()),
CheckKind::EndsInPunctuation => Some("Add closing punctuation".to_string()),
CheckKind::GetAttrWithConstant => {
Some("Replace `getattr` with attribute access".to_string())
}
CheckKind::ImplicitReturnValue => Some("Add explicit `None` return value".to_string()),
CheckKind::ImplicitReturn => Some("Add explicit `return` statement".to_string()),
CheckKind::InvalidEscapeSequence(..) => {
Some("Add backslash to escape sequence".to_string())
}
CheckKind::IsLiteral(cmpop) => Some(match cmpop {
IsCmpop::Is => "Replace `is` with `==`".to_string(),
IsCmpop::IsNot => "Replace `is not` with `!=`".to_string(),
}),
CheckKind::KeyInDict(key, dict) => Some(format!("Convert to `{key} in {dict}`")),
CheckKind::MisplacedComparisonConstant(comparison) => {
Some(format!("Replace with {comparison}"))
}
CheckKind::MissingReturnTypeSpecialMethod(..) => {
Some("Add `None` return type".to_string())
}
CheckKind::NativeLiterals(literal_type) => {
Some(format!("Replace with `{literal_type}`"))
}
CheckKind::OpenAlias => Some("Replace with builtin `open`".to_string()),
CheckKind::NewLineAfterLastParagraph => {
Some("Move closing quotes to new line".to_string())
}
CheckKind::ReplaceUniversalNewlines => {
Some("Replace with `text` keyword argument".to_string())
}
CheckKind::ReplaceStdoutStderr => {
Some("Replace with `capture_output` keyword argument".to_string())
}
CheckKind::RewriteCElementTree => Some("Replace with `ElementTree`".to_string()),
CheckKind::RewriteUnicodeLiteral => Some("Remove unicode prefix".to_string()),
CheckKind::NewLineAfterSectionName(name) => {
Some(format!("Add newline after \"{name}\""))
}
CheckKind::NoBlankLineBeforeFunction(..) => {
Some("Remove blank line(s) before function docstring".to_string())
}
CheckKind::NoBlankLineAfterFunction(..) => {
Some("Remove blank line(s) after function docstring".to_string())
}
CheckKind::NoBlankLineBeforeClass(..) => {
Some("Remove blank line(s) before class docstring".to_string())
}
CheckKind::OneBlankLineBeforeClass(..) => {
Some("Insert 1 blank line before class docstring".to_string())
}
CheckKind::OneBlankLineAfterClass(..) => {
Some("Insert 1 blank line after class docstring".to_string())
}
CheckKind::NoBlankLinesBetweenHeaderAndContent(..) => {
Some("Remove blank line(s)".to_string())
}
CheckKind::NoNewLineAtEndOfFile => Some("Add trailing newline".to_string()),
CheckKind::NoOverIndentation => Some("Remove over-indentation".to_string()),
CheckKind::NoSurroundingWhitespace => Some("Trim surrounding whitespace".to_string()),
CheckKind::NoUnderIndentation => Some("Increase indentation".to_string()),
CheckKind::NoneComparison(op) => Some(match op {
EqCmpop::Eq => "Replace with `cond is None`".to_string(),
EqCmpop::NotEq => "Replace with `cond is not None`".to_string(),
}),
CheckKind::NotInTest => Some("Convert to `not in`".to_string()),
CheckKind::NotIsTest => Some("Convert to `is not`".to_string()),
CheckKind::PEP3120UnnecessaryCodingComment => {
Some("Remove unnecessary coding comment".to_string())
}
CheckKind::PPrintFound => Some("Remove `pprint`".to_string()),
CheckKind::PercentFormatExtraNamedArguments(missing)
| CheckKind::StringDotFormatExtraNamedArguments(missing) => {
let message = missing.join(", ");
Some(format!("Remove extra named arguments: {message}"))
}
CheckKind::PrintFound => Some("Remove `print`".to_string()),
CheckKind::RaiseNotImplemented => Some("Use `raise NotImplementedError`".to_string()),
CheckKind::RedundantOpenModes(replacement) => Some(match replacement {
None => "Remove open mode parameters".to_string(),
Some(replacement) => {
format!("Replace with \"{replacement}\"")
}
}),
CheckKind::RedundantTupleInExceptionHandler(name) => {
Some(format!("Replace with `except {name}`"))
}
CheckKind::RemoveSixCompat => Some("Remove `six` usage".to_string()),
CheckKind::SectionNameEndsInColon(name) => Some(format!("Add colon to \"{name}\"")),
CheckKind::SectionNotOverIndented(name) => {
Some(format!("Remove over-indentation from \"{name}\""))
}
CheckKind::SectionUnderlineAfterName(name) => {
Some(format!("Add underline to \"{name}\""))
}
CheckKind::SectionUnderlineMatchesSectionLength(name) => {
Some(format!("Adjust underline length to match \"{name}\""))
}
CheckKind::SectionUnderlineNotOverIndented(name) => {
Some(format!("Remove over-indentation from \"{name}\" underline"))
}
CheckKind::SetAttrWithConstant => Some("Replace `setattr` with assignment".to_string()),
CheckKind::SuperCallWithParameters => Some("Remove `__super__` parameters".to_string()),
CheckKind::TrueFalseComparison(true, EqCmpop::Eq) => {
Some("Replace with `cond is True`".to_string())
}
CheckKind::TrueFalseComparison(true, EqCmpop::NotEq) => {
Some("Replace with `cond is not True`".to_string())
}
CheckKind::TrueFalseComparison(false, EqCmpop::Eq) => {
Some("Replace with `cond is False`".to_string())
}
CheckKind::TrueFalseComparison(false, EqCmpop::NotEq) => {
Some("Replace with `cond is not False`".to_string())
}
CheckKind::TypeOfPrimitive(primitive) => Some(format!(
"Replace `type(...)` with `{}`",
primitive.builtin()
)),
CheckKind::TypingTextStrAlias => Some("Replace with `str`".to_string()),
CheckKind::UnnecessaryCallAroundSorted(func) => {
Some(format!("Remove unnecessary `{func}` call"))
}
CheckKind::UnnecessaryCollectionCall(..) => Some("Rewrite as a literal".to_string()),
CheckKind::UnnecessaryComprehension(obj_type) => {
Some(format!("Rewrite using `{obj_type}()`"))
}
CheckKind::UnnecessaryEncodeUTF8 => Some("Remove unnecessary `encode`".to_string()),
CheckKind::UnnecessaryFutureImport(..) => {
Some("Remove unnecessary `__future__` import".to_string())
}
CheckKind::UnnecessaryGeneratorDict => {
Some("Rewrite as a `dict` comprehension".to_string())
}
CheckKind::UnnecessaryGeneratorList => {
Some("Rewrite as a `list` comprehension".to_string())
}
CheckKind::UnnecessaryGeneratorSet => {
Some("Rewrite as a `set` comprehension".to_string())
}
CheckKind::UnnecessaryLRUCacheParams => {
Some("Remove unnecessary parameters".to_string())
}
CheckKind::UnnecessaryListCall => Some("Remove outer `list` call".to_string()),
CheckKind::UnnecessaryListComprehensionDict => {
Some("Rewrite as a `dict` comprehension".to_string())
}
CheckKind::UnnecessaryListComprehensionSet => {
Some("Rewrite as a `set` comprehension".to_string())
}
CheckKind::UnnecessaryLiteralDict(..) => {
Some("Rewrite as a `dict` literal".to_string())
}
CheckKind::UnnecessaryLiteralSet(..) => Some("Rewrite as a `set` literal".to_string()),
CheckKind::UnnecessaryLiteralWithinTupleCall(literal) => Some({
if literal == "list" {
"Rewrite as a `tuple` literal".to_string()
} else {
"Remove outer `tuple` call".to_string()
}
}),
CheckKind::UnnecessaryLiteralWithinListCall(literal) => Some({
if literal == "list" {
"Remove outer `list` call".to_string()
} else {
"Rewrite as a `list` literal".to_string()
}
}),
CheckKind::UnnecessaryReturnNone => Some("Remove explicit `return None`".to_string()),
CheckKind::UnsortedImports => Some("Organize imports".to_string()),
CheckKind::UnusedImport(name, false, multiple) => {
if *multiple {
Some("Remove unused import".to_string())
} else {
Some(format!("Remove unused import: `{name}`"))
}
}
CheckKind::UnusedLoopControlVariable(name) => {
Some(format!("Rename unused `{name}` to `_{name}`"))
}
CheckKind::UnusedNOQA(..) => Some("Remove unused `noqa` directive".to_string()),
CheckKind::UsePEP585Annotation(name) => {
Some(format!("Replace `{name}` with `{}`", name.to_lowercase(),))
}
CheckKind::UsePEP604Annotation => Some("Convert to `X | Y`".to_string()),
CheckKind::UseSysExit(name) => Some(format!("Replace `{name}` with `sys.exit()`")),
CheckKind::UselessImportAlias => Some("Remove import alias".to_string()),
CheckKind::UselessMetaclassType => Some("Remove `__metaclass__ = type`".to_string()),
CheckKind::UselessObjectInheritance(..) => {
Some("Remove `object` inheritance".to_string())
}
_ => None,
}
}
}
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
@@ -3190,6 +3461,7 @@ pub struct Check {
pub location: Location,
pub end_location: Location,
pub fix: Option<Fix>,
pub parent: Option<Location>,
}
impl Check {
@@ -3199,11 +3471,18 @@ impl Check {
location: range.location,
end_location: range.end_location,
fix: None,
parent: None,
}
}
pub fn amend(&mut self, fix: Fix) {
pub fn amend(&mut self, fix: Fix) -> &mut Self {
self.fix = Some(fix);
self
}
pub fn parent(&mut self, parent: Location) -> &mut Self {
self.parent = Some(parent);
self
}
}
@@ -3354,4 +3633,17 @@ mod tests {
);
}
}
#[test]
fn fixable_codes() {
for check_code in CheckCode::iter() {
let kind = check_code.kind();
if kind.fixable() {
assert!(
kind.commit().is_some(),
"{check_code:?} is fixable but has no commit message."
);
}
}
}
}

View File

@@ -283,8 +283,6 @@ pub enum CheckCodePrefix {
F821,
F822,
F823,
F83,
F831,
F84,
F841,
F842,
@@ -647,7 +645,6 @@ impl CheckCodePrefix {
CheckCode::F821,
CheckCode::F822,
CheckCode::F823,
CheckCode::F831,
CheckCode::F841,
CheckCode::F842,
CheckCode::F901,
@@ -1506,7 +1503,6 @@ impl CheckCodePrefix {
CheckCode::F821,
CheckCode::F822,
CheckCode::F823,
CheckCode::F831,
CheckCode::F841,
CheckCode::F842,
CheckCode::F901,
@@ -1640,7 +1636,6 @@ impl CheckCodePrefix {
CheckCode::F821,
CheckCode::F822,
CheckCode::F823,
CheckCode::F831,
CheckCode::F841,
CheckCode::F842,
],
@@ -1650,8 +1645,6 @@ impl CheckCodePrefix {
CheckCodePrefix::F821 => vec![CheckCode::F821],
CheckCodePrefix::F822 => vec![CheckCode::F822],
CheckCodePrefix::F823 => vec![CheckCode::F823],
CheckCodePrefix::F83 => vec![CheckCode::F831],
CheckCodePrefix::F831 => vec![CheckCode::F831],
CheckCodePrefix::F84 => vec![CheckCode::F841, CheckCode::F842],
CheckCodePrefix::F841 => vec![CheckCode::F841],
CheckCodePrefix::F842 => vec![CheckCode::F842],
@@ -3102,8 +3095,6 @@ impl CheckCodePrefix {
CheckCodePrefix::F821 => SuffixLength::Three,
CheckCodePrefix::F822 => SuffixLength::Three,
CheckCodePrefix::F823 => SuffixLength::Three,
CheckCodePrefix::F83 => SuffixLength::Two,
CheckCodePrefix::F831 => SuffixLength::Three,
CheckCodePrefix::F84 => SuffixLength::Two,
CheckCodePrefix::F841 => SuffixLength::Three,
CheckCodePrefix::F842 => SuffixLength::Three,

View File

@@ -17,7 +17,7 @@ use crate::settings::types::{
#[command(version)]
#[allow(clippy::struct_excessive_bools)]
pub struct Cli {
#[arg(required_unless_present_any = ["explain", "generate_shell_completion"])]
#[arg(required_unless_present_any = ["clean", "explain", "generate_shell_completion"])]
pub files: Vec<PathBuf>,
/// Path to the `pyproject.toml` or `ruff.toml` file to use for
/// configuration.
@@ -57,14 +57,15 @@ pub struct Cli {
/// Disable cache reads.
#[arg(short, long)]
pub no_cache: bool,
/// List of error codes to enable.
/// Comma-separated list of error codes to enable (or ALL, to enable all
/// checks).
#[arg(long, value_delimiter = ',')]
pub select: Option<Vec<CheckCodePrefix>>,
/// Like --select, but adds additional error codes on top of the selected
/// ones.
#[arg(long, value_delimiter = ',')]
pub extend_select: Option<Vec<CheckCodePrefix>>,
/// List of error codes to ignore.
/// Comma-separated list of error codes to disable.
#[arg(long, value_delimiter = ',')]
pub ignore: Option<Vec<CheckCodePrefix>>,
/// Like --ignore, but adds additional error codes on top of the ignored
@@ -92,6 +93,12 @@ pub struct Cli {
/// Output serialization format for error messages.
#[arg(long, value_enum)]
pub format: Option<SerializationFormat>,
/// The name of the file when passing it through stdin.
#[arg(long)]
pub stdin_filename: Option<PathBuf>,
/// Path to the cache directory.
#[arg(long)]
pub cache_dir: Option<PathBuf>,
/// Show violations with source code.
#[arg(long, overrides_with("no_show_source"))]
show_source: bool,
@@ -114,15 +121,6 @@ pub struct Cli {
update_check: bool,
#[clap(long, overrides_with("update_check"), hide = true)]
no_update_check: bool,
/// See the files Ruff will be run against with the current settings.
#[arg(long)]
pub show_files: bool,
/// See the settings Ruff will use to check a given Python file.
#[arg(long)]
pub show_settings: bool,
/// Enable automatic additions of noqa directives to failing lines.
#[arg(long)]
pub add_noqa: bool,
/// Regular expression matching the name of dummy variables.
#[arg(long)]
pub dummy_variable_rgx: Option<Regex>,
@@ -133,25 +131,100 @@ pub struct Cli {
/// formatting.
#[arg(long)]
pub line_length: Option<usize>,
/// Max McCabe complexity allowed for a function.
/// Maximum McCabe complexity allowed for a given function.
#[arg(long)]
pub max_complexity: Option<usize>,
/// Round-trip auto-formatting.
// TODO(charlie): This should be a sub-command.
#[arg(long, hide = true)]
pub autoformat: bool,
/// The name of the file when passing it through stdin.
#[arg(long)]
pub stdin_filename: Option<PathBuf>,
/// Enable automatic additions of `noqa` directives to failing lines.
#[arg(
long,
// conflicts_with = "add_noqa",
conflicts_with = "clean",
conflicts_with = "explain",
conflicts_with = "generate_shell_completion",
conflicts_with = "show_files",
conflicts_with = "show_settings",
// Unsupported default-command arguments.
conflicts_with = "stdin_filename",
conflicts_with = "watch",
)]
pub add_noqa: bool,
/// Clear any caches in the current directory or any subdirectories.
#[arg(
long,
// Fake subcommands.
conflicts_with = "add_noqa",
// conflicts_with = "clean",
conflicts_with = "explain",
conflicts_with = "generate_shell_completion",
conflicts_with = "show_files",
conflicts_with = "show_settings",
// Unsupported default-command arguments.
conflicts_with = "stdin_filename",
conflicts_with = "watch",
)]
pub clean: bool,
/// Explain a rule.
#[arg(long)]
#[arg(
long,
// Fake subcommands.
conflicts_with = "add_noqa",
conflicts_with = "clean",
// conflicts_with = "explain",
conflicts_with = "generate_shell_completion",
conflicts_with = "show_files",
conflicts_with = "show_settings",
// Unsupported default-command arguments.
conflicts_with = "stdin_filename",
conflicts_with = "watch",
)]
pub explain: Option<CheckCode>,
/// Generate shell completion
#[arg(long, hide = true, value_name = "SHELL")]
#[arg(
long,
hide = true,
value_name = "SHELL",
// Fake subcommands.
conflicts_with = "add_noqa",
conflicts_with = "clean",
conflicts_with = "explain",
// conflicts_with = "generate_shell_completion",
conflicts_with = "show_files",
conflicts_with = "show_settings",
// Unsupported default-command arguments.
conflicts_with = "stdin_filename",
conflicts_with = "watch",
)]
pub generate_shell_completion: Option<clap_complete_command::Shell>,
/// Path to the cache directory.
#[arg(long)]
pub cache_dir: Option<PathBuf>,
/// See the files Ruff will be run against with the current settings.
#[arg(
long,
// Fake subcommands.
conflicts_with = "add_noqa",
conflicts_with = "clean",
conflicts_with = "explain",
conflicts_with = "generate_shell_completion",
// conflicts_with = "show_files",
conflicts_with = "show_settings",
// Unsupported default-command arguments.
conflicts_with = "stdin_filename",
conflicts_with = "watch",
)]
pub show_files: bool,
/// See the settings Ruff will use to check a given Python file.
#[arg(
long,
// Fake subcommands.
conflicts_with = "add_noqa",
conflicts_with = "clean",
conflicts_with = "explain",
conflicts_with = "generate_shell_completion",
conflicts_with = "show_files",
// conflicts_with = "show_settings",
// Unsupported default-command arguments.
conflicts_with = "stdin_filename",
conflicts_with = "watch",
)]
pub show_settings: bool,
}
impl Cli {
@@ -161,7 +234,7 @@ impl Cli {
(
Arguments {
add_noqa: self.add_noqa,
autoformat: self.autoformat,
clean: self.clean,
config: self.config,
diff: self.diff,
exit_zero: self.exit_zero,
@@ -222,7 +295,7 @@ fn resolve_bool_arg(yes: bool, no: bool) -> Option<bool> {
#[allow(clippy::struct_excessive_bools)]
pub struct Arguments {
pub add_noqa: bool,
pub autoformat: bool,
pub clean: bool,
pub config: Option<PathBuf>,
pub diff: bool,
pub exit_zero: bool,

View File

@@ -1,26 +1,32 @@
use std::fs::remove_dir_all;
use std::io::{self, Read};
use std::path::{Path, PathBuf};
use std::time::Instant;
use anyhow::{bail, Result};
use colored::Colorize;
use ignore::Error;
use itertools::Itertools;
use log::{debug, error};
use path_absolutize::path_dedot;
#[cfg(not(target_family = "wasm"))]
use rayon::prelude::*;
use rustpython_ast::Location;
use serde::Serialize;
use walkdir::WalkDir;
use crate::autofix::fixer;
use crate::cache::DEFAULT_CACHE_DIR_NAME;
use crate::checks::{CheckCode, CheckKind};
use crate::cli::Overrides;
use crate::iterators::par_iter;
use crate::linter::{add_noqa_to_path, autoformat_path, lint_path, lint_stdin, Diagnostics};
use crate::linter::{add_noqa_to_path, lint_path, lint_stdin, Diagnostics};
use crate::logging::LogLevel;
use crate::message::Message;
use crate::resolver::{FileDiscovery, PyprojectDiscovery};
use crate::settings::flags;
use crate::settings::types::SerializationFormat;
use crate::{cache, packages, resolver};
use crate::{cache, fs, one_time_warning, packages, resolver};
/// Run the linter over a collection of files.
pub fn run(
@@ -38,6 +44,15 @@ pub fn run(
let duration = start.elapsed();
debug!("Identified files to lint in: {:?}", duration);
if paths.is_empty() {
one_time_warning!(
"{} {}",
"warning:".yellow().bold(),
"No Python files found under the given path(s)"
);
return Ok(Diagnostics::default());
}
// Validate the `Settings` and return any errors.
resolver.validate(pyproject_strategy)?;
@@ -179,6 +194,15 @@ pub fn add_noqa(
let duration = start.elapsed();
debug!("Identified files to lint in: {:?}", duration);
if paths.is_empty() {
one_time_warning!(
"{} {}",
"warning:".yellow().bold(),
"No Python files found under the given path(s)"
);
return Ok(0);
}
// Validate the `Settings` and return any errors.
resolver.validate(pyproject_strategy)?;
@@ -204,45 +228,6 @@ pub fn add_noqa(
Ok(modifications)
}
/// Automatically format a collection of files.
pub fn autoformat(
files: &[PathBuf],
pyproject_strategy: &PyprojectDiscovery,
file_strategy: &FileDiscovery,
overrides: &Overrides,
) -> Result<usize> {
// Collect all the files to format.
let start = Instant::now();
let (paths, resolver) =
resolver::python_files_in_path(files, pyproject_strategy, file_strategy, overrides)?;
let duration = start.elapsed();
debug!("Identified files to lint in: {:?}", duration);
// Validate the `Settings` and return any errors.
resolver.validate(pyproject_strategy)?;
let start = Instant::now();
let modifications = par_iter(&paths)
.flatten()
.filter_map(|entry| {
let path = entry.path();
let settings = resolver.resolve(path, pyproject_strategy);
match autoformat_path(path, settings) {
Ok(()) => Some(()),
Err(e) => {
error!("Failed to autoformat {}: {e}", path.to_string_lossy());
None
}
}
})
.count();
let duration = start.elapsed();
debug!("Auto-formatted files in: {:?}", duration);
Ok(modifications)
}
/// Print the user-facing configuration settings.
pub fn show_settings(
files: &[PathBuf],
@@ -283,6 +268,15 @@ pub fn show_files(
let (paths, resolver) =
resolver::python_files_in_path(files, pyproject_strategy, file_strategy, overrides)?;
if paths.is_empty() {
one_time_warning!(
"{} {}",
"warning:".yellow().bold(),
"No Python files found under the given path(s)"
);
return Ok(());
}
// Validate the `Settings` and return any errors.
resolver.validate(pyproject_strategy)?;
@@ -338,3 +332,21 @@ pub fn explain(code: &CheckCode, format: &SerializationFormat) -> Result<()> {
};
Ok(())
}
/// Clear any caches in the current directory or any subdirectories.
pub fn clean(level: &LogLevel) -> Result<()> {
for entry in WalkDir::new(&*path_dedot::CWD)
.into_iter()
.filter_map(std::result::Result::ok)
.filter(|entry| entry.file_type().is_dir())
{
let cache = entry.path().join(DEFAULT_CACHE_DIR_NAME);
if cache.is_dir() {
if level >= &LogLevel::Default {
eprintln!("Removing cache at: {}", fs::relativize_path(&cache).bold());
}
remove_dir_all(&cache)?;
}
}
Ok(())
}

View File

@@ -1,9 +1,9 @@
// See: https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals.
pub const TRIPLE_QUOTE_PREFIXES: &[&str] = &[
"ur\"\"\"", "ur'''", "u\"\"\"", "u'''", "r\"\"\"", "r'''", "UR\"\"\"", "UR'''", "Ur\"\"\"",
"Ur'''", "U\"\"\"", "U'''", "uR\"\"\"", "uR'''", "R\"\"\"", "R'''", "\"\"\"", "'''",
"u\"\"\"", "u'''", "r\"\"\"", "r'''", "U\"\"\"", "U'''", "R\"\"\"", "R'''", "\"\"\"", "'''",
];
pub const SINGLE_QUOTE_PREFIXES: &[&str] = &[
"ur\"", "ur'", "u\"", "u'", "r\"", "r'", "ur\"", "ur'", "u\"", "u'", "r\"", "r'", "UR\"",
"UR'", "Ur\"", "Ur'", "U\"", "U'", "uR\"", "uR'", "R\"", "R'", "\"", "'",
"u\"", "u'", "r\"", "r'", "u\"", "u'", "r\"", "r'", "U\"", "U'", "R\"", "R'", "\"", "'",
];

View File

@@ -16,13 +16,12 @@ mod tests {
#[test_case(CheckCode::ERA001, Path::new("ERA001.py"); "ERA001")]
fn checks(check_code: CheckCode, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", check_code.as_ref(), path.to_string_lossy());
let mut checks = test_path(
let checks = test_path(
Path::new("./resources/test/fixtures/eradicate")
.join(path)
.as_path(),
&settings::Settings::for_rule(check_code),
)?;
checks.sort_by_key(|check| check.location);
insta::assert_yaml_snapshot!(snapshot, checks);
Ok(())
}

View File

@@ -17,6 +17,7 @@ expression: checks
end_location:
row: 2
column: 0
parent: ~
- kind: CommentedOutCode
location:
row: 2
@@ -32,6 +33,7 @@ expression: checks
end_location:
row: 3
column: 0
parent: ~
- kind: CommentedOutCode
location:
row: 3
@@ -47,6 +49,7 @@ expression: checks
end_location:
row: 4
column: 0
parent: ~
- kind: CommentedOutCode
location:
row: 5
@@ -62,6 +65,7 @@ expression: checks
end_location:
row: 6
column: 0
parent: ~
- kind: CommentedOutCode
location:
row: 12
@@ -77,4 +81,5 @@ expression: checks
end_location:
row: 13
column: 0
parent: ~

View File

@@ -24,13 +24,12 @@ mod tests {
#[test_case(CheckCode::YTT303, Path::new("YTT303.py"); "YTT303")]
fn checks(check_code: CheckCode, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", check_code.as_ref(), path.to_string_lossy());
let mut checks = test_path(
let checks = test_path(
Path::new("./resources/test/fixtures/flake8_2020")
.join(path)
.as_path(),
&settings::Settings::for_rule(check_code),
)?;
checks.sort_by_key(|check| check.location);
insta::assert_yaml_snapshot!(snapshot, checks);
Ok(())
}

View File

@@ -10,6 +10,7 @@ expression: checks
row: 6
column: 17
fix: ~
parent: ~
- kind: SysVersionSlice3Referenced
location:
row: 7
@@ -18,6 +19,7 @@ expression: checks
row: 7
column: 13
fix: ~
parent: ~
- kind: SysVersionSlice3Referenced
location:
row: 8
@@ -26,4 +28,5 @@ expression: checks
row: 8
column: 7
fix: ~
parent: ~

View File

@@ -10,6 +10,7 @@ expression: checks
row: 4
column: 22
fix: ~
parent: ~
- kind: SysVersion2Referenced
location:
row: 5
@@ -18,4 +19,5 @@ expression: checks
row: 5
column: 18
fix: ~
parent: ~

View File

@@ -10,6 +10,7 @@ expression: checks
row: 4
column: 7
fix: ~
parent: ~
- kind: SysVersionCmpStr3
location:
row: 5
@@ -18,6 +19,7 @@ expression: checks
row: 5
column: 11
fix: ~
parent: ~
- kind: SysVersionCmpStr3
location:
row: 6
@@ -26,6 +28,7 @@ expression: checks
row: 6
column: 11
fix: ~
parent: ~
- kind: SysVersionCmpStr3
location:
row: 7
@@ -34,6 +37,7 @@ expression: checks
row: 7
column: 11
fix: ~
parent: ~
- kind: SysVersionCmpStr3
location:
row: 8
@@ -42,4 +46,5 @@ expression: checks
row: 8
column: 11
fix: ~
parent: ~

View File

@@ -10,6 +10,7 @@ expression: checks
row: 7
column: 25
fix: ~
parent: ~
- kind: SysVersionInfo0Eq3Referenced
location:
row: 8
@@ -18,6 +19,7 @@ expression: checks
row: 8
column: 21
fix: ~
parent: ~
- kind: SysVersionInfo0Eq3Referenced
location:
row: 9
@@ -26,6 +28,7 @@ expression: checks
row: 9
column: 25
fix: ~
parent: ~
- kind: SysVersionInfo0Eq3Referenced
location:
row: 10
@@ -34,4 +37,5 @@ expression: checks
row: 10
column: 21
fix: ~
parent: ~

View File

@@ -10,6 +10,7 @@ expression: checks
row: 4
column: 10
fix: ~
parent: ~
- kind: SixPY3Referenced
location:
row: 6
@@ -18,4 +19,5 @@ expression: checks
row: 6
column: 6
fix: ~
parent: ~

View File

@@ -10,6 +10,7 @@ expression: checks
row: 4
column: 19
fix: ~
parent: ~
- kind: SysVersionInfo1CmpInt
location:
row: 5
@@ -18,4 +19,5 @@ expression: checks
row: 5
column: 15
fix: ~
parent: ~

View File

@@ -10,6 +10,7 @@ expression: checks
row: 4
column: 22
fix: ~
parent: ~
- kind: SysVersionInfoMinorCmpInt
location:
row: 5
@@ -18,4 +19,5 @@ expression: checks
row: 5
column: 18
fix: ~
parent: ~

View File

@@ -10,6 +10,7 @@ expression: checks
row: 4
column: 22
fix: ~
parent: ~
- kind: SysVersion0Referenced
location:
row: 5
@@ -18,4 +19,5 @@ expression: checks
row: 5
column: 18
fix: ~
parent: ~

View File

@@ -10,6 +10,7 @@ expression: checks
row: 4
column: 7
fix: ~
parent: ~
- kind: SysVersionCmpStr10
location:
row: 5
@@ -18,6 +19,7 @@ expression: checks
row: 5
column: 11
fix: ~
parent: ~
- kind: SysVersionCmpStr10
location:
row: 6
@@ -26,6 +28,7 @@ expression: checks
row: 6
column: 11
fix: ~
parent: ~
- kind: SysVersionCmpStr10
location:
row: 7
@@ -34,6 +37,7 @@ expression: checks
row: 7
column: 11
fix: ~
parent: ~
- kind: SysVersionCmpStr10
location:
row: 8
@@ -42,4 +46,5 @@ expression: checks
row: 8
column: 11
fix: ~
parent: ~

View File

@@ -10,6 +10,7 @@ expression: checks
row: 4
column: 17
fix: ~
parent: ~
- kind: SysVersionSlice1Referenced
location:
row: 5
@@ -18,4 +19,5 @@ expression: checks
row: 5
column: 13
fix: ~
parent: ~

View File

@@ -15,7 +15,7 @@ mod tests {
#[test]
fn defaults() -> Result<()> {
let mut checks = test_path(
let checks = test_path(
Path::new("./resources/test/fixtures/flake8_annotations/annotation_presence.py"),
&Settings {
..Settings::for_rules(vec![
@@ -33,14 +33,13 @@ mod tests {
])
},
)?;
checks.sort_by_key(|check| check.location);
insta::assert_yaml_snapshot!(checks);
Ok(())
}
#[test]
fn suppress_dummy_args() -> Result<()> {
let mut checks = test_path(
let checks = test_path(
Path::new("./resources/test/fixtures/flake8_annotations/suppress_dummy_args.py"),
&Settings {
flake8_annotations: flake8_annotations::settings::Settings {
@@ -58,14 +57,13 @@ mod tests {
])
},
)?;
checks.sort_by_key(|check| check.location);
insta::assert_yaml_snapshot!(checks);
Ok(())
}
#[test]
fn mypy_init_return() -> Result<()> {
let mut checks = test_path(
let checks = test_path(
Path::new("./resources/test/fixtures/flake8_annotations/mypy_init_return.py"),
&Settings {
flake8_annotations: flake8_annotations::settings::Settings {
@@ -83,14 +81,13 @@ mod tests {
])
},
)?;
checks.sort_by_key(|check| check.location);
insta::assert_yaml_snapshot!(checks);
Ok(())
}
#[test]
fn suppress_none_returning() -> Result<()> {
let mut checks = test_path(
let checks = test_path(
Path::new("./resources/test/fixtures/flake8_annotations/suppress_none_returning.py"),
&Settings {
flake8_annotations: flake8_annotations::settings::Settings {
@@ -108,14 +105,13 @@ mod tests {
])
},
)?;
checks.sort_by_key(|check| check.location);
insta::assert_yaml_snapshot!(checks);
Ok(())
}
#[test]
fn allow_star_arg_any() -> Result<()> {
let mut checks = test_path(
let checks = test_path(
Path::new("./resources/test/fixtures/flake8_annotations/allow_star_arg_any.py"),
&Settings {
flake8_annotations: flake8_annotations::settings::Settings {
@@ -127,14 +123,13 @@ mod tests {
..Settings::for_rules(vec![CheckCode::ANN401])
},
)?;
checks.sort_by_key(|check| check.location);
insta::assert_yaml_snapshot!(checks);
Ok(())
}
#[test]
fn allow_overload() -> Result<()> {
let mut checks = test_path(
let checks = test_path(
Path::new("./resources/test/fixtures/flake8_annotations/allow_overload.py"),
&Settings {
..Settings::for_rules(vec![
@@ -146,7 +141,6 @@ mod tests {
])
},
)?;
checks.sort_by_key(|check| check.location);
insta::assert_yaml_snapshot!(checks);
Ok(())
}

View File

@@ -3,7 +3,7 @@ use rustpython_ast::{Constant, Expr, ExprKind, Stmt, StmtKind};
use crate::ast::types::Range;
use crate::ast::visitor::Visitor;
use crate::ast::{cast, visitor};
use crate::ast::{cast, helpers, visitor};
use crate::checkers::ast::Checker;
use crate::checks::{CheckCode, CheckKind};
use crate::docstrings::definition::{Definition, DefinitionKind};
@@ -167,7 +167,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
if checker.settings.enabled.contains(&CheckCode::ANN201) {
checker.add_check(Check::new(
CheckKind::MissingReturnTypePublicFunction(name.to_string()),
Range::from_located(stmt),
helpers::identifier_range(stmt, checker.locator),
));
}
}
@@ -175,7 +175,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
if checker.settings.enabled.contains(&CheckCode::ANN202) {
checker.add_check(Check::new(
CheckKind::MissingReturnTypePrivateFunction(name.to_string()),
Range::from_located(stmt),
helpers::identifier_range(stmt, checker.locator),
));
}
}
@@ -309,14 +309,14 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
if checker.settings.enabled.contains(&CheckCode::ANN206) {
checker.add_check(Check::new(
CheckKind::MissingReturnTypeClassMethod(name.to_string()),
Range::from_located(stmt),
helpers::identifier_range(stmt, checker.locator),
));
}
} else if visibility::is_staticmethod(checker, cast::decorator_list(stmt)) {
if checker.settings.enabled.contains(&CheckCode::ANN205) {
checker.add_check(Check::new(
CheckKind::MissingReturnTypeStaticMethod(name.to_string()),
Range::from_located(stmt),
helpers::identifier_range(stmt, checker.locator),
));
}
} else if visibility::is_init(stmt) {
@@ -328,11 +328,13 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
{
let mut check = Check::new(
CheckKind::MissingReturnTypeSpecialMethod(name.to_string()),
Range::from_located(stmt),
helpers::identifier_range(stmt, checker.locator),
);
if checker.patch(check.kind.code()) {
match fixes::add_return_none_annotation(checker.locator, stmt) {
Ok(fix) => check.amend(fix),
Ok(fix) => {
check.amend(fix);
}
Err(e) => error!("Failed to generate fix: {e}"),
}
}
@@ -343,7 +345,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
if checker.settings.enabled.contains(&CheckCode::ANN204) {
checker.add_check(Check::new(
CheckKind::MissingReturnTypeSpecialMethod(name.to_string()),
Range::from_located(stmt),
helpers::identifier_range(stmt, checker.locator),
));
}
} else {
@@ -352,7 +354,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
if checker.settings.enabled.contains(&CheckCode::ANN201) {
checker.add_check(Check::new(
CheckKind::MissingReturnTypePublicFunction(name.to_string()),
Range::from_located(stmt),
helpers::identifier_range(stmt, checker.locator),
));
}
}
@@ -360,7 +362,7 @@ pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &V
if checker.settings.enabled.contains(&CheckCode::ANN202) {
checker.add_check(Check::new(
CheckKind::MissingReturnTypePrivateFunction(name.to_string()),
Range::from_located(stmt),
helpers::identifier_range(stmt, checker.locator),
));
}
}

View File

@@ -6,9 +6,10 @@ expression: checks
MissingReturnTypePublicFunction: bar
location:
row: 29
column: 4
column: 8
end_location:
row: 30
column: 16
row: 29
column: 11
fix: ~
parent: ~

View File

@@ -11,6 +11,7 @@ expression: checks
row: 10
column: 14
fix: ~
parent: ~
- kind:
DynamicallyTypedExpression: foo
location:
@@ -20,6 +21,7 @@ expression: checks
row: 15
column: 49
fix: ~
parent: ~
- kind:
DynamicallyTypedExpression: a
location:
@@ -29,6 +31,7 @@ expression: checks
row: 40
column: 31
fix: ~
parent: ~
- kind:
DynamicallyTypedExpression: foo_method
location:
@@ -38,4 +41,5 @@ expression: checks
row: 44
column: 69
fix: ~
parent: ~

View File

@@ -6,11 +6,12 @@ expression: checks
MissingReturnTypePublicFunction: foo
location:
row: 4
column: 0
column: 4
end_location:
row: 5
column: 8
row: 4
column: 7
fix: ~
parent: ~
- kind:
MissingTypeFunctionArgument: a
location:
@@ -20,6 +21,7 @@ expression: checks
row: 4
column: 9
fix: ~
parent: ~
- kind:
MissingTypeFunctionArgument: b
location:
@@ -29,15 +31,17 @@ expression: checks
row: 4
column: 12
fix: ~
parent: ~
- kind:
MissingReturnTypePublicFunction: foo
location:
row: 9
column: 0
column: 4
end_location:
row: 10
column: 8
row: 9
column: 7
fix: ~
parent: ~
- kind:
MissingTypeFunctionArgument: b
location:
@@ -47,6 +51,7 @@ expression: checks
row: 9
column: 17
fix: ~
parent: ~
- kind:
MissingTypeFunctionArgument: b
location:
@@ -56,24 +61,27 @@ expression: checks
row: 14
column: 17
fix: ~
parent: ~
- kind:
MissingReturnTypePublicFunction: foo
location:
row: 19
column: 0
column: 4
end_location:
row: 20
column: 8
row: 19
column: 7
fix: ~
parent: ~
- kind:
MissingReturnTypePublicFunction: foo
location:
row: 24
column: 0
column: 4
end_location:
row: 25
column: 8
row: 24
column: 7
fix: ~
parent: ~
- kind:
DynamicallyTypedExpression: a
location:
@@ -83,6 +91,7 @@ expression: checks
row: 44
column: 14
fix: ~
parent: ~
- kind:
DynamicallyTypedExpression: foo
location:
@@ -92,6 +101,7 @@ expression: checks
row: 49
column: 49
fix: ~
parent: ~
- kind:
DynamicallyTypedExpression: "*args"
location:
@@ -101,6 +111,7 @@ expression: checks
row: 54
column: 26
fix: ~
parent: ~
- kind:
DynamicallyTypedExpression: "**kwargs"
location:
@@ -110,6 +121,7 @@ expression: checks
row: 54
column: 41
fix: ~
parent: ~
- kind:
DynamicallyTypedExpression: "*args"
location:
@@ -119,6 +131,7 @@ expression: checks
row: 59
column: 26
fix: ~
parent: ~
- kind:
DynamicallyTypedExpression: "**kwargs"
location:
@@ -128,6 +141,7 @@ expression: checks
row: 64
column: 41
fix: ~
parent: ~
- kind:
MissingTypeSelf: self
location:
@@ -137,6 +151,7 @@ expression: checks
row: 74
column: 16
fix: ~
parent: ~
- kind:
DynamicallyTypedExpression: a
location:
@@ -146,6 +161,7 @@ expression: checks
row: 78
column: 31
fix: ~
parent: ~
- kind:
DynamicallyTypedExpression: foo
location:
@@ -155,6 +171,7 @@ expression: checks
row: 82
column: 69
fix: ~
parent: ~
- kind:
DynamicallyTypedExpression: "*params"
location:
@@ -164,6 +181,7 @@ expression: checks
row: 86
column: 45
fix: ~
parent: ~
- kind:
DynamicallyTypedExpression: "**options"
location:
@@ -173,6 +191,7 @@ expression: checks
row: 86
column: 61
fix: ~
parent: ~
- kind:
DynamicallyTypedExpression: "*params"
location:
@@ -182,6 +201,7 @@ expression: checks
row: 90
column: 45
fix: ~
parent: ~
- kind:
DynamicallyTypedExpression: "**options"
location:
@@ -191,6 +211,7 @@ expression: checks
row: 94
column: 61
fix: ~
parent: ~
- kind:
MissingTypeCls: cls
location:
@@ -200,4 +221,5 @@ expression: checks
row: 104
column: 15
fix: ~
parent: ~

View File

@@ -6,10 +6,10 @@ expression: checks
MissingReturnTypeSpecialMethod: __init__
location:
row: 5
column: 4
column: 8
end_location:
row: 6
column: 11
row: 5
column: 16
fix:
content: " -> None"
location:
@@ -18,14 +18,15 @@ expression: checks
end_location:
row: 5
column: 22
parent: ~
- kind:
MissingReturnTypeSpecialMethod: __init__
location:
row: 11
column: 4
column: 8
end_location:
row: 12
column: 11
row: 11
column: 16
fix:
content: " -> None"
location:
@@ -34,13 +35,15 @@ expression: checks
end_location:
row: 11
column: 27
parent: ~
- kind:
MissingReturnTypePrivateFunction: __init__
location:
row: 40
column: 0
column: 4
end_location:
row: 41
column: 7
row: 40
column: 12
fix: ~
parent: ~

View File

@@ -6,18 +6,20 @@ expression: checks
MissingReturnTypePublicFunction: foo
location:
row: 45
column: 0
column: 4
end_location:
row: 46
column: 15
row: 45
column: 7
fix: ~
parent: ~
- kind:
MissingReturnTypePublicFunction: foo
location:
row: 50
column: 0
column: 4
end_location:
row: 55
column: 14
row: 50
column: 7
fix: ~
parent: ~

View File

@@ -21,13 +21,12 @@ mod tests {
#[test_case(CheckCode::S107, Path::new("S107.py"); "S107")]
fn checks(check_code: CheckCode, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", check_code.as_ref(), path.to_string_lossy());
let mut checks = test_path(
let checks = test_path(
Path::new("./resources/test/fixtures/flake8_bandit")
.join(path)
.as_path(),
&settings::Settings::for_rule(check_code),
)?;
checks.sort_by_key(|check| check.location);
insta::assert_yaml_snapshot!(snapshot, checks);
Ok(())
}

View File

@@ -10,6 +10,7 @@ expression: checks
row: 2
column: 11
fix: ~
parent: ~
- kind: AssertUsed
location:
row: 8
@@ -18,6 +19,7 @@ expression: checks
row: 8
column: 17
fix: ~
parent: ~
- kind: AssertUsed
location:
row: 11
@@ -26,4 +28,5 @@ expression: checks
row: 11
column: 17
fix: ~
parent: ~

View File

@@ -10,6 +10,7 @@ expression: checks
row: 3
column: 17
fix: ~
parent: ~
- kind: ExecUsed
location:
row: 5
@@ -18,4 +19,5 @@ expression: checks
row: 5
column: 13
fix: ~
parent: ~

View File

@@ -10,6 +10,7 @@ expression: checks
row: 9
column: 9
fix: ~
parent: ~
- kind: HardcodedBindAllInterfaces
location:
row: 10
@@ -18,6 +19,7 @@ expression: checks
row: 10
column: 9
fix: ~
parent: ~
- kind: HardcodedBindAllInterfaces
location:
row: 14
@@ -26,6 +28,7 @@ expression: checks
row: 14
column: 14
fix: ~
parent: ~
- kind: HardcodedBindAllInterfaces
location:
row: 18
@@ -34,4 +37,5 @@ expression: checks
row: 18
column: 17
fix: ~
parent: ~

View File

@@ -11,6 +11,7 @@ expression: checks
row: 12
column: 19
fix: ~
parent: ~
- kind:
HardcodedPasswordString: s3cr3t
location:
@@ -20,6 +21,7 @@ expression: checks
row: 13
column: 16
fix: ~
parent: ~
- kind:
HardcodedPasswordString: s3cr3t
location:
@@ -29,6 +31,7 @@ expression: checks
row: 14
column: 17
fix: ~
parent: ~
- kind:
HardcodedPasswordString: s3cr3t
location:
@@ -38,6 +41,7 @@ expression: checks
row: 15
column: 14
fix: ~
parent: ~
- kind:
HardcodedPasswordString: s3cr3t
location:
@@ -47,6 +51,7 @@ expression: checks
row: 16
column: 17
fix: ~
parent: ~
- kind:
HardcodedPasswordString: s3cr3t
location:
@@ -56,6 +61,7 @@ expression: checks
row: 17
column: 16
fix: ~
parent: ~
- kind:
HardcodedPasswordString: s3cr3t
location:
@@ -65,6 +71,7 @@ expression: checks
row: 18
column: 18
fix: ~
parent: ~
- kind:
HardcodedPasswordString: s3cr3t
location:
@@ -74,6 +81,7 @@ expression: checks
row: 19
column: 26
fix: ~
parent: ~
- kind:
HardcodedPasswordString: s3cr3t
location:
@@ -83,6 +91,7 @@ expression: checks
row: 20
column: 26
fix: ~
parent: ~
- kind:
HardcodedPasswordString: s3cr3t
location:
@@ -92,6 +101,7 @@ expression: checks
row: 22
column: 24
fix: ~
parent: ~
- kind:
HardcodedPasswordString: s3cr3t
location:
@@ -101,6 +111,7 @@ expression: checks
row: 23
column: 20
fix: ~
parent: ~
- kind:
HardcodedPasswordString: s3cr3t
location:
@@ -110,6 +121,7 @@ expression: checks
row: 24
column: 22
fix: ~
parent: ~
- kind:
HardcodedPasswordString: s3cr3t
location:
@@ -119,6 +131,7 @@ expression: checks
row: 25
column: 19
fix: ~
parent: ~
- kind:
HardcodedPasswordString: s3cr3t
location:
@@ -128,6 +141,7 @@ expression: checks
row: 26
column: 22
fix: ~
parent: ~
- kind:
HardcodedPasswordString: s3cr3t
location:
@@ -137,6 +151,7 @@ expression: checks
row: 27
column: 21
fix: ~
parent: ~
- kind:
HardcodedPasswordString: s3cr3t
location:
@@ -146,6 +161,7 @@ expression: checks
row: 28
column: 23
fix: ~
parent: ~
- kind:
HardcodedPasswordString: s3cr3t
location:
@@ -155,6 +171,7 @@ expression: checks
row: 29
column: 31
fix: ~
parent: ~
- kind:
HardcodedPasswordString: s3cr3t
location:
@@ -164,6 +181,7 @@ expression: checks
row: 30
column: 31
fix: ~
parent: ~
- kind:
HardcodedPasswordString: s3cr3t
location:
@@ -173,6 +191,7 @@ expression: checks
row: 34
column: 23
fix: ~
parent: ~
- kind:
HardcodedPasswordString: s3cr3t
location:
@@ -182,6 +201,7 @@ expression: checks
row: 38
column: 27
fix: ~
parent: ~
- kind:
HardcodedPasswordString: s3cr3t
location:
@@ -191,6 +211,7 @@ expression: checks
row: 39
column: 24
fix: ~
parent: ~
- kind:
HardcodedPasswordString: s3cr3t
location:
@@ -200,6 +221,7 @@ expression: checks
row: 40
column: 25
fix: ~
parent: ~
- kind:
HardcodedPasswordString: s3cr3t
location:
@@ -209,6 +231,7 @@ expression: checks
row: 41
column: 22
fix: ~
parent: ~
- kind:
HardcodedPasswordString: s3cr3t
location:
@@ -218,6 +241,7 @@ expression: checks
row: 42
column: 25
fix: ~
parent: ~
- kind:
HardcodedPasswordString: s3cr3t
location:
@@ -227,6 +251,7 @@ expression: checks
row: 43
column: 24
fix: ~
parent: ~
- kind:
HardcodedPasswordString: s3cr3t
location:
@@ -236,6 +261,7 @@ expression: checks
row: 44
column: 26
fix: ~
parent: ~
- kind:
HardcodedPasswordString: s3cr3t
location:
@@ -245,6 +271,7 @@ expression: checks
row: 46
column: 20
fix: ~
parent: ~
- kind:
HardcodedPasswordString: s3cr3t
location:
@@ -254,6 +281,7 @@ expression: checks
row: 47
column: 17
fix: ~
parent: ~
- kind:
HardcodedPasswordString: s3cr3t
location:
@@ -263,6 +291,7 @@ expression: checks
row: 48
column: 18
fix: ~
parent: ~
- kind:
HardcodedPasswordString: s3cr3t
location:
@@ -272,6 +301,7 @@ expression: checks
row: 49
column: 15
fix: ~
parent: ~
- kind:
HardcodedPasswordString: s3cr3t
location:
@@ -281,6 +311,7 @@ expression: checks
row: 50
column: 18
fix: ~
parent: ~
- kind:
HardcodedPasswordString: s3cr3t
location:
@@ -290,6 +321,7 @@ expression: checks
row: 51
column: 17
fix: ~
parent: ~
- kind:
HardcodedPasswordString: s3cr3t
location:
@@ -299,6 +331,7 @@ expression: checks
row: 52
column: 19
fix: ~
parent: ~
- kind:
HardcodedPasswordString: s3cr3t
location:
@@ -308,4 +341,35 @@ expression: checks
row: 53
column: 28
fix: ~
parent: ~
- kind:
HardcodedPasswordString: "1\n2"
location:
row: 55
column: 12
end_location:
row: 55
column: 18
fix: ~
parent: ~
- kind:
HardcodedPasswordString: "3\t4"
location:
row: 58
column: 12
end_location:
row: 58
column: 18
fix: ~
parent: ~
- kind:
HardcodedPasswordString: "5\r6"
location:
row: 61
column: 12
end_location:
row: 61
column: 18
fix: ~
parent: ~

View File

@@ -11,4 +11,5 @@ expression: checks
row: 13
column: 25
fix: ~
parent: ~

View File

@@ -11,6 +11,7 @@ expression: checks
row: 5
column: 37
fix: ~
parent: ~
- kind:
HardcodedPasswordDefault: posonly
location:
@@ -20,6 +21,7 @@ expression: checks
row: 13
column: 53
fix: ~
parent: ~
- kind:
HardcodedPasswordDefault: kwonly
location:
@@ -29,6 +31,7 @@ expression: checks
row: 21
column: 46
fix: ~
parent: ~
- kind:
HardcodedPasswordDefault: posonly
location:
@@ -38,6 +41,7 @@ expression: checks
row: 29
column: 47
fix: ~
parent: ~
- kind:
HardcodedPasswordDefault: kwonly
location:
@@ -47,4 +51,5 @@ expression: checks
row: 29
column: 69
fix: ~
parent: ~

View File

@@ -15,13 +15,12 @@ mod tests {
#[test_case(CheckCode::BLE001, Path::new("BLE.py"); "BLE001")]
fn checks(check_code: CheckCode, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", check_code.as_ref(), path.to_string_lossy());
let mut checks = test_path(
let checks = test_path(
Path::new("./resources/test/fixtures/flake8_blind_except")
.join(path)
.as_path(),
&settings::Settings::for_rule(check_code),
)?;
checks.sort_by_key(|check| check.location);
insta::assert_yaml_snapshot!(snapshot, checks);
Ok(())
}

View File

@@ -11,6 +11,7 @@ expression: checks
row: 25
column: 20
fix: ~
parent: ~
- kind:
BlindExcept: Exception
location:
@@ -20,6 +21,7 @@ expression: checks
row: 31
column: 16
fix: ~
parent: ~
- kind:
BlindExcept: Exception
location:
@@ -29,6 +31,7 @@ expression: checks
row: 42
column: 16
fix: ~
parent: ~
- kind:
BlindExcept: BaseException
location:
@@ -38,6 +41,7 @@ expression: checks
row: 45
column: 24
fix: ~
parent: ~
- kind:
BlindExcept: Exception
location:
@@ -47,6 +51,7 @@ expression: checks
row: 54
column: 16
fix: ~
parent: ~
- kind:
BlindExcept: Exception
location:
@@ -56,6 +61,7 @@ expression: checks
row: 60
column: 16
fix: ~
parent: ~
- kind:
BlindExcept: BaseException
location:
@@ -65,4 +71,5 @@ expression: checks
row: 62
column: 20
fix: ~
parent: ~

View File

@@ -17,13 +17,12 @@ mod tests {
#[test_case(CheckCode::FBT003, Path::new("FBT.py"); "FBT003")]
fn checks(check_code: CheckCode, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", check_code.as_ref(), path.to_string_lossy());
let mut checks = test_path(
let checks = test_path(
Path::new("./resources/test/fixtures/flake8_boolean_trap")
.join(path)
.as_path(),
&settings::Settings::for_rule(check_code),
)?;
checks.sort_by_key(|check| check.location);
insta::assert_yaml_snapshot!(snapshot, checks);
Ok(())
}

View File

@@ -10,6 +10,7 @@ expression: checks
row: 4
column: 26
fix: ~
parent: ~
- kind: BooleanPositionalArgInFunctionDefinition
location:
row: 5
@@ -18,6 +19,7 @@ expression: checks
row: 5
column: 31
fix: ~
parent: ~
- kind: BooleanPositionalArgInFunctionDefinition
location:
row: 10
@@ -26,6 +28,7 @@ expression: checks
row: 10
column: 36
fix: ~
parent: ~
- kind: BooleanPositionalArgInFunctionDefinition
location:
row: 11
@@ -34,6 +37,7 @@ expression: checks
row: 11
column: 41
fix: ~
parent: ~
- kind: BooleanPositionalArgInFunctionDefinition
location:
row: 14
@@ -42,6 +46,7 @@ expression: checks
row: 14
column: 37
fix: ~
parent: ~
- kind: BooleanPositionalArgInFunctionDefinition
location:
row: 15
@@ -50,6 +55,7 @@ expression: checks
row: 15
column: 42
fix: ~
parent: ~
- kind: BooleanPositionalArgInFunctionDefinition
location:
row: 18
@@ -58,6 +64,7 @@ expression: checks
row: 18
column: 40
fix: ~
parent: ~
- kind: BooleanPositionalArgInFunctionDefinition
location:
row: 19
@@ -66,4 +73,5 @@ expression: checks
row: 19
column: 45
fix: ~
parent: ~

View File

@@ -10,6 +10,7 @@ expression: checks
row: 12
column: 34
fix: ~
parent: ~
- kind: BooleanDefaultValueInFunctionDefinition
location:
row: 13
@@ -18,6 +19,7 @@ expression: checks
row: 13
column: 46
fix: ~
parent: ~
- kind: BooleanDefaultValueInFunctionDefinition
location:
row: 14
@@ -26,6 +28,7 @@ expression: checks
row: 14
column: 44
fix: ~
parent: ~
- kind: BooleanDefaultValueInFunctionDefinition
location:
row: 15
@@ -34,4 +37,5 @@ expression: checks
row: 15
column: 49
fix: ~
parent: ~

View File

@@ -10,6 +10,7 @@ expression: checks
row: 42
column: 14
fix: ~
parent: ~
- kind: BooleanPositionalValueInFunctionCall
location:
row: 57
@@ -18,6 +19,7 @@ expression: checks
row: 57
column: 14
fix: ~
parent: ~
- kind: BooleanPositionalValueInFunctionCall
location:
row: 57
@@ -26,4 +28,5 @@ expression: checks
row: 57
column: 21
fix: ~
parent: ~

View File

@@ -42,13 +42,12 @@ mod tests {
#[test_case(CheckCode::B905, Path::new("B905.py"); "B905")]
fn checks(check_code: CheckCode, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", check_code.as_ref(), path.to_string_lossy());
let mut checks = test_path(
let checks = test_path(
Path::new("./resources/test/fixtures/flake8_bugbear")
.join(path)
.as_path(),
&Settings::for_rule(check_code),
)?;
checks.sort_by_key(|check| check.location);
insta::assert_yaml_snapshot!(snapshot, checks);
Ok(())
}
@@ -56,7 +55,7 @@ mod tests {
#[test]
fn extend_immutable_calls() -> Result<()> {
let snapshot = "extend_immutable_calls".to_string();
let mut checks = test_path(
let checks = test_path(
Path::new("./resources/test/fixtures/flake8_bugbear/B008_extended.py"),
&Settings {
flake8_bugbear: flake8_bugbear::settings::Settings {
@@ -68,7 +67,6 @@ mod tests {
..Settings::for_rules(vec![CheckCode::B008])
},
)?;
checks.sort_by_key(|check| check.location);
insta::assert_yaml_snapshot!(snapshot, checks);
Ok(())
}

View File

@@ -47,8 +47,11 @@ pub fn assert_false(checker: &mut Checker, stmt: &Stmt, test: &Expr, msg: Option
let mut check = Check::new(CheckKind::DoNotAssertFalse, Range::from_located(test));
if checker.patch(check.kind.code()) {
let mut generator =
SourceCodeGenerator::new(checker.style.indentation(), checker.style.quote());
let mut generator = SourceCodeGenerator::new(
checker.style.indentation(),
checker.style.quote(),
checker.style.line_ending(),
);
generator.unparse_stmt(&assertion_error(msg));
if let Ok(content) = generator.generate() {
check.amend(Fix::replacement(

View File

@@ -54,8 +54,11 @@ fn duplicate_handler_exceptions<'a>(
Range::from_located(expr),
);
if checker.patch(check.kind.code()) {
let mut generator =
SourceCodeGenerator::new(checker.style.indentation(), checker.style.quote());
let mut generator = SourceCodeGenerator::new(
checker.style.indentation(),
checker.style.quote(),
checker.style.line_ending(),
);
if unique_elts.len() == 1 {
generator.unparse_expr(unique_elts[0], 0);
} else {

View File

@@ -1,6 +1,6 @@
use rustpython_ast::{ExprKind, Stmt, StmtKind};
use crate::ast::types::Range;
use crate::ast::helpers;
use crate::checkers::ast::Checker;
use crate::checks::{Check, CheckKind};
@@ -17,6 +17,6 @@ pub fn f_string_docstring(checker: &mut Checker, body: &[Stmt]) {
};
checker.add_check(Check::new(
CheckKind::FStringDocstring,
Range::from_located(stmt),
helpers::identifier_range(stmt, checker.locator),
));
}

View File

@@ -12,8 +12,6 @@ use crate::checks::{Check, CheckKind};
struct LoadedNamesVisitor<'a> {
// Tuple of: name, defining expression, and defining range.
names: Vec<(&'a str, &'a Expr, Range)>,
// If we're in an f-string, the range of the defining expression.
in_f_string: Option<Range>,
}
/// `Visitor` to collect all used identifiers in a statement.
@@ -24,18 +22,10 @@ where
fn visit_expr(&mut self, expr: &'b Expr) {
match &expr.node {
ExprKind::JoinedStr { .. } => {
let prev_in_f_string = self.in_f_string;
self.in_f_string = Some(Range::from_located(expr));
visitor::walk_expr(self, expr);
self.in_f_string = prev_in_f_string;
}
ExprKind::Name { id, ctx } if matches!(ctx, ExprContext::Load) => {
self.names.push((
id,
expr,
self.in_f_string
.unwrap_or_else(|| Range::from_located(expr)),
));
self.names.push((id, expr, Range::from_located(expr)));
}
_ => visitor::walk_expr(self, expr),
}

View File

@@ -46,8 +46,11 @@ pub fn getattr_with_constant(checker: &mut Checker, expr: &Expr, func: &Expr, ar
let mut check = Check::new(CheckKind::GetAttrWithConstant, Range::from_located(expr));
if checker.patch(check.kind.code()) {
let mut generator =
SourceCodeGenerator::new(checker.style.indentation(), checker.style.quote());
let mut generator = SourceCodeGenerator::new(
checker.style.indentation(),
checker.style.quote(),
checker.style.line_ending(),
);
generator.unparse_expr(&attribute(obj, value), 0);
if let Ok(content) = generator.generate() {
check.amend(Fix::replacement(

View File

@@ -23,8 +23,11 @@ pub fn redundant_tuple_in_exception_handler(checker: &mut Checker, handlers: &[E
Range::from_located(type_),
);
if checker.patch(check.kind.code()) {
let mut generator =
SourceCodeGenerator::new(checker.style.indentation(), checker.style.quote());
let mut generator = SourceCodeGenerator::new(
checker.style.indentation(),
checker.style.quote(),
checker.style.line_ending(),
);
generator.unparse_expr(elt, 0);
if let Ok(content) = generator.generate() {
check.amend(Fix::replacement(

View File

@@ -34,7 +34,11 @@ fn assignment(
type_comment: None,
},
);
let mut generator = SourceCodeGenerator::new(stylist.indentation(), stylist.quote());
let mut generator = SourceCodeGenerator::new(
stylist.indentation(),
stylist.quote(),
stylist.line_ending(),
);
generator.unparse_stmt(&stmt);
generator.generate().map_err(std::convert::Into::into)
}
@@ -70,11 +74,13 @@ pub fn setattr_with_constant(checker: &mut Checker, expr: &Expr, func: &Expr, ar
let mut check = Check::new(CheckKind::SetAttrWithConstant, Range::from_located(expr));
if checker.patch(check.kind.code()) {
match assignment(obj, name, value, checker.style) {
Ok(content) => check.amend(Fix::replacement(
content,
expr.location,
expr.end_location.unwrap(),
)),
Ok(content) => {
check.amend(Fix::replacement(
content,
expr.location,
expr.end_location.unwrap(),
));
}
Err(e) => error!("Failed to fix invalid comparison: {e}"),
};
}

View File

@@ -10,6 +10,7 @@ expression: checks
row: 15
column: 11
fix: ~
parent: ~
- kind: UnaryPrefixIncrement
location:
row: 20
@@ -18,4 +19,5 @@ expression: checks
row: 20
column: 14
fix: ~
parent: ~

View File

@@ -10,4 +10,5 @@ expression: checks
row: 9
column: 10
fix: ~
parent: ~

View File

@@ -10,6 +10,7 @@ expression: checks
row: 3
column: 29
fix: ~
parent: ~
- kind: UnreliableCallableCheck
location:
row: 5
@@ -18,4 +19,5 @@ expression: checks
row: 5
column: 36
fix: ~
parent: ~

View File

@@ -10,6 +10,7 @@ expression: checks
row: 4
column: 24
fix: ~
parent: ~
- kind: StripWithMultiCharacters
location:
row: 7
@@ -18,6 +19,7 @@ expression: checks
row: 7
column: 17
fix: ~
parent: ~
- kind: StripWithMultiCharacters
location:
row: 10
@@ -26,6 +28,7 @@ expression: checks
row: 10
column: 25
fix: ~
parent: ~
- kind: StripWithMultiCharacters
location:
row: 13
@@ -34,6 +37,7 @@ expression: checks
row: 13
column: 18
fix: ~
parent: ~
- kind: StripWithMultiCharacters
location:
row: 16
@@ -42,6 +46,7 @@ expression: checks
row: 16
column: 25
fix: ~
parent: ~
- kind: StripWithMultiCharacters
location:
row: 19
@@ -50,4 +55,5 @@ expression: checks
row: 19
column: 18
fix: ~
parent: ~

View File

@@ -10,6 +10,7 @@ expression: checks
row: 60
column: 33
fix: ~
parent: ~
- kind: MutableArgumentDefault
location:
row: 64
@@ -18,6 +19,7 @@ expression: checks
row: 64
column: 31
fix: ~
parent: ~
- kind: MutableArgumentDefault
location:
row: 68
@@ -26,6 +28,7 @@ expression: checks
row: 68
column: 24
fix: ~
parent: ~
- kind: MutableArgumentDefault
location:
row: 72
@@ -34,6 +37,7 @@ expression: checks
row: 72
column: 44
fix: ~
parent: ~
- kind: MutableArgumentDefault
location:
row: 76
@@ -42,6 +46,7 @@ expression: checks
row: 76
column: 56
fix: ~
parent: ~
- kind: MutableArgumentDefault
location:
row: 80
@@ -50,6 +55,7 @@ expression: checks
row: 80
column: 44
fix: ~
parent: ~
- kind: MutableArgumentDefault
location:
row: 85
@@ -58,6 +64,7 @@ expression: checks
row: 85
column: 69
fix: ~
parent: ~
- kind: MutableArgumentDefault
location:
row: 89
@@ -66,6 +73,7 @@ expression: checks
row: 89
column: 72
fix: ~
parent: ~
- kind: MutableArgumentDefault
location:
row: 93
@@ -74,6 +82,7 @@ expression: checks
row: 93
column: 68
fix: ~
parent: ~
- kind: MutableArgumentDefault
location:
row: 97
@@ -82,6 +91,7 @@ expression: checks
row: 97
column: 34
fix: ~
parent: ~
- kind: MutableArgumentDefault
location:
row: 170
@@ -90,6 +100,7 @@ expression: checks
row: 170
column: 48
fix: ~
parent: ~
- kind: MutableArgumentDefault
location:
row: 203
@@ -98,6 +109,7 @@ expression: checks
row: 203
column: 28
fix: ~
parent: ~
- kind: MutableArgumentDefault
location:
row: 204
@@ -106,6 +118,7 @@ expression: checks
row: 204
column: 36
fix: ~
parent: ~
- kind: MutableArgumentDefault
location:
row: 205
@@ -114,4 +127,5 @@ expression: checks
row: 205
column: 66
fix: ~
parent: ~

View File

@@ -18,6 +18,7 @@ expression: checks
end_location:
row: 6
column: 5
parent: ~
- kind:
UnusedLoopControlVariable: k
location:
@@ -34,6 +35,7 @@ expression: checks
end_location:
row: 18
column: 13
parent: ~
- kind:
UnusedLoopControlVariable: i
location:
@@ -50,6 +52,7 @@ expression: checks
end_location:
row: 30
column: 5
parent: ~
- kind:
UnusedLoopControlVariable: k
location:
@@ -66,4 +69,5 @@ expression: checks
end_location:
row: 30
column: 13
parent: ~

View File

@@ -11,6 +11,7 @@ expression: checks
row: 85
column: 68
fix: ~
parent: ~
- kind:
FunctionCallArgumentDefault: range
location:
@@ -20,6 +21,7 @@ expression: checks
row: 89
column: 71
fix: ~
parent: ~
- kind:
FunctionCallArgumentDefault: range
location:
@@ -29,6 +31,7 @@ expression: checks
row: 93
column: 67
fix: ~
parent: ~
- kind:
FunctionCallArgumentDefault: time.time
location:
@@ -38,6 +41,7 @@ expression: checks
row: 109
column: 49
fix: ~
parent: ~
- kind:
FunctionCallArgumentDefault: dt.datetime.now
location:
@@ -47,6 +51,7 @@ expression: checks
row: 113
column: 28
fix: ~
parent: ~
- kind:
FunctionCallArgumentDefault: dt.timedelta
location:
@@ -56,6 +61,7 @@ expression: checks
row: 113
column: 51
fix: ~
parent: ~
- kind:
FunctionCallArgumentDefault: ~
location:
@@ -65,6 +71,7 @@ expression: checks
row: 117
column: 44
fix: ~
parent: ~
- kind:
FunctionCallArgumentDefault: float
location:
@@ -74,6 +81,7 @@ expression: checks
row: 155
column: 47
fix: ~
parent: ~
- kind:
FunctionCallArgumentDefault: float
location:
@@ -83,6 +91,7 @@ expression: checks
row: 160
column: 37
fix: ~
parent: ~
- kind:
FunctionCallArgumentDefault: float
location:
@@ -92,6 +101,7 @@ expression: checks
row: 164
column: 57
fix: ~
parent: ~
- kind:
FunctionCallArgumentDefault: float
location:
@@ -101,6 +111,7 @@ expression: checks
row: 170
column: 28
fix: ~
parent: ~
- kind:
FunctionCallArgumentDefault: dt.datetime.now
location:
@@ -110,6 +121,7 @@ expression: checks
row: 170
column: 47
fix: ~
parent: ~
- kind:
FunctionCallArgumentDefault: map
location:
@@ -119,6 +131,7 @@ expression: checks
row: 176
column: 62
fix: ~
parent: ~
- kind:
FunctionCallArgumentDefault: random.randint
location:
@@ -128,6 +141,7 @@ expression: checks
row: 181
column: 59
fix: ~
parent: ~
- kind:
FunctionCallArgumentDefault: dt.datetime.now
location:
@@ -137,4 +151,5 @@ expression: checks
row: 181
column: 53
fix: ~
parent: ~

View File

@@ -17,6 +17,7 @@ expression: checks
end_location:
row: 18
column: 19
parent: ~
- kind: GetAttrWithConstant
location:
row: 19
@@ -32,6 +33,7 @@ expression: checks
end_location:
row: 19
column: 23
parent: ~
- kind: GetAttrWithConstant
location:
row: 20
@@ -47,6 +49,7 @@ expression: checks
end_location:
row: 20
column: 22
parent: ~
- kind: GetAttrWithConstant
location:
row: 21
@@ -62,6 +65,7 @@ expression: checks
end_location:
row: 21
column: 23
parent: ~
- kind: GetAttrWithConstant
location:
row: 22
@@ -77,6 +81,7 @@ expression: checks
end_location:
row: 22
column: 31
parent: ~
- kind: GetAttrWithConstant
location:
row: 23
@@ -92,4 +97,5 @@ expression: checks
end_location:
row: 23
column: 20
parent: ~

View File

@@ -17,6 +17,7 @@ expression: checks
end_location:
row: 37
column: 25
parent: ~
- kind: SetAttrWithConstant
location:
row: 38
@@ -32,6 +33,7 @@ expression: checks
end_location:
row: 38
column: 29
parent: ~
- kind: SetAttrWithConstant
location:
row: 39
@@ -47,6 +49,7 @@ expression: checks
end_location:
row: 39
column: 28
parent: ~
- kind: SetAttrWithConstant
location:
row: 40
@@ -62,6 +65,7 @@ expression: checks
end_location:
row: 40
column: 29
parent: ~
- kind: SetAttrWithConstant
location:
row: 41
@@ -77,4 +81,5 @@ expression: checks
end_location:
row: 41
column: 30
parent: ~

View File

@@ -17,6 +17,7 @@ expression: checks
end_location:
row: 8
column: 12
parent: ~
- kind: DoNotAssertFalse
location:
row: 10
@@ -32,4 +33,5 @@ expression: checks
end_location:
row: 10
column: 23
parent: ~

View File

@@ -11,6 +11,7 @@ expression: checks
row: 5
column: 14
fix: ~
parent: ~
- kind:
JumpStatementInFinally: return
location:
@@ -20,6 +21,7 @@ expression: checks
row: 13
column: 18
fix: ~
parent: ~
- kind:
JumpStatementInFinally: return
location:
@@ -29,6 +31,7 @@ expression: checks
row: 21
column: 18
fix: ~
parent: ~
- kind:
JumpStatementInFinally: return
location:
@@ -38,6 +41,7 @@ expression: checks
row: 31
column: 18
fix: ~
parent: ~
- kind:
JumpStatementInFinally: return
location:
@@ -47,6 +51,7 @@ expression: checks
row: 44
column: 26
fix: ~
parent: ~
- kind:
JumpStatementInFinally: break
location:
@@ -56,6 +61,7 @@ expression: checks
row: 66
column: 17
fix: ~
parent: ~
- kind:
JumpStatementInFinally: continue
location:
@@ -65,6 +71,7 @@ expression: checks
row: 78
column: 20
fix: ~
parent: ~
- kind:
JumpStatementInFinally: return
location:
@@ -74,6 +81,7 @@ expression: checks
row: 94
column: 18
fix: ~
parent: ~
- kind:
JumpStatementInFinally: continue
location:
@@ -83,6 +91,7 @@ expression: checks
row: 101
column: 16
fix: ~
parent: ~
- kind:
JumpStatementInFinally: break
location:
@@ -92,4 +101,5 @@ expression: checks
row: 107
column: 13
fix: ~
parent: ~

View File

@@ -18,4 +18,5 @@ expression: checks
end_location:
row: 3
column: 20
parent: ~

View File

@@ -19,6 +19,7 @@ expression: checks
end_location:
row: 17
column: 25
parent: ~
- kind:
DuplicateHandlerException:
- MyError
@@ -36,6 +37,7 @@ expression: checks
end_location:
row: 28
column: 25
parent: ~
- kind:
DuplicateHandlerException:
- re.error
@@ -53,4 +55,5 @@ expression: checks
end_location:
row: 49
column: 27
parent: ~

View File

@@ -10,6 +10,7 @@ expression: checks
row: 3
column: 6
fix: ~
parent: ~
- kind: UselessComparison
location:
row: 7
@@ -18,6 +19,7 @@ expression: checks
row: 7
column: 11
fix: ~
parent: ~
- kind: UselessComparison
location:
row: 17
@@ -26,6 +28,7 @@ expression: checks
row: 17
column: 15
fix: ~
parent: ~
- kind: UselessComparison
location:
row: 24
@@ -34,4 +37,5 @@ expression: checks
row: 24
column: 10
fix: ~
parent: ~

View File

@@ -10,6 +10,7 @@ expression: checks
row: 6
column: 11
fix: ~
parent: ~
- kind: CannotRaiseLiteral
location:
row: 7
@@ -18,6 +19,7 @@ expression: checks
row: 7
column: 7
fix: ~
parent: ~
- kind: CannotRaiseLiteral
location:
row: 8
@@ -26,4 +28,5 @@ expression: checks
row: 8
column: 14
fix: ~
parent: ~

View File

@@ -10,4 +10,5 @@ expression: checks
row: 23
column: 42
fix: ~
parent: ~

View File

@@ -10,6 +10,7 @@ expression: checks
row: 11
column: 6
fix: ~
parent: ~
- kind: UselessExpression
location:
row: 12
@@ -18,6 +19,7 @@ expression: checks
row: 12
column: 5
fix: ~
parent: ~
- kind: UselessExpression
location:
row: 13
@@ -26,6 +28,7 @@ expression: checks
row: 13
column: 7
fix: ~
parent: ~
- kind: UselessExpression
location:
row: 14
@@ -34,6 +37,7 @@ expression: checks
row: 14
column: 10
fix: ~
parent: ~
- kind: UselessExpression
location:
row: 15
@@ -42,6 +46,7 @@ expression: checks
row: 15
column: 8
fix: ~
parent: ~
- kind: UselessExpression
location:
row: 16
@@ -50,6 +55,7 @@ expression: checks
row: 16
column: 9
fix: ~
parent: ~
- kind: UselessExpression
location:
row: 17
@@ -58,6 +64,7 @@ expression: checks
row: 17
column: 8
fix: ~
parent: ~
- kind: UselessExpression
location:
row: 18
@@ -66,6 +73,7 @@ expression: checks
row: 18
column: 10
fix: ~
parent: ~
- kind: UselessExpression
location:
row: 19
@@ -74,6 +82,7 @@ expression: checks
row: 19
column: 10
fix: ~
parent: ~
- kind: UselessExpression
location:
row: 20
@@ -82,6 +91,7 @@ expression: checks
row: 20
column: 18
fix: ~
parent: ~
- kind: UselessExpression
location:
row: 24
@@ -90,6 +100,7 @@ expression: checks
row: 24
column: 7
fix: ~
parent: ~
- kind: UselessExpression
location:
row: 27
@@ -98,6 +109,7 @@ expression: checks
row: 27
column: 5
fix: ~
parent: ~
- kind: UselessExpression
location:
row: 39
@@ -106,6 +118,7 @@ expression: checks
row: 39
column: 6
fix: ~
parent: ~
- kind: UselessExpression
location:
row: 40
@@ -114,6 +127,7 @@ expression: checks
row: 40
column: 5
fix: ~
parent: ~
- kind: UselessExpression
location:
row: 41
@@ -122,6 +136,7 @@ expression: checks
row: 41
column: 7
fix: ~
parent: ~
- kind: UselessExpression
location:
row: 42
@@ -130,6 +145,7 @@ expression: checks
row: 42
column: 10
fix: ~
parent: ~
- kind: UselessExpression
location:
row: 43
@@ -138,6 +154,7 @@ expression: checks
row: 43
column: 8
fix: ~
parent: ~
- kind: UselessExpression
location:
row: 44
@@ -146,6 +163,7 @@ expression: checks
row: 44
column: 9
fix: ~
parent: ~
- kind: UselessExpression
location:
row: 45
@@ -154,6 +172,7 @@ expression: checks
row: 45
column: 8
fix: ~
parent: ~
- kind: UselessExpression
location:
row: 46
@@ -162,6 +181,7 @@ expression: checks
row: 46
column: 10
fix: ~
parent: ~
- kind: UselessExpression
location:
row: 47
@@ -170,6 +190,7 @@ expression: checks
row: 47
column: 10
fix: ~
parent: ~
- kind: UselessExpression
location:
row: 48
@@ -178,6 +199,7 @@ expression: checks
row: 48
column: 18
fix: ~
parent: ~
- kind: UselessExpression
location:
row: 52
@@ -186,6 +208,7 @@ expression: checks
row: 52
column: 7
fix: ~
parent: ~
- kind: UselessExpression
location:
row: 55
@@ -194,4 +217,5 @@ expression: checks
row: 55
column: 5
fix: ~
parent: ~

Some files were not shown because too many files have changed in this diff Show More