Compare commits
90 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8cf745045f | ||
|
|
f6992cc98c | ||
|
|
3cc74c0564 | ||
|
|
887b9aa840 | ||
|
|
faf8556a5c | ||
|
|
1888f6d41b | ||
|
|
9d8cd2d2fe | ||
|
|
05c19f0091 | ||
|
|
8213b64ad5 | ||
|
|
ff0f5968fa | ||
|
|
6c17670aa5 | ||
|
|
1347b7ebb6 | ||
|
|
f40609f524 | ||
|
|
f572acab30 | ||
|
|
1eb5f3ea75 | ||
|
|
24aa177912 | ||
|
|
2ddc768412 | ||
|
|
0f9508f549 | ||
|
|
7c3d387abd | ||
|
|
d600650214 | ||
|
|
43383bb696 | ||
|
|
ff83f356af | ||
|
|
89622425d4 | ||
|
|
1aafe31c00 | ||
|
|
16c5ac1e91 | ||
|
|
da39cddccb | ||
|
|
de6435f41d | ||
|
|
589ae48f8c | ||
|
|
35cc3094b5 | ||
|
|
07c9fc55f6 | ||
|
|
7773e9728b | ||
|
|
8fc435bad9 | ||
|
|
dd20b23576 | ||
|
|
da8ee1df3e | ||
|
|
7f77ed0f86 | ||
|
|
1b33cfb9cb | ||
|
|
dbc64f1faa | ||
|
|
f4b5f0d259 | ||
|
|
85b882fc54 | ||
|
|
99d9aa61bf | ||
|
|
050f34dd25 | ||
|
|
1cd82d588b | ||
|
|
cea9e34942 | ||
|
|
1ede377402 | ||
|
|
82eff641fb | ||
|
|
eb1bc9f092 | ||
|
|
df88504dea | ||
|
|
b9ec3e9137 | ||
|
|
b067b665ff | ||
|
|
22cfd03b13 | ||
|
|
3ae408a364 | ||
|
|
95073b1586 | ||
|
|
3597a94818 | ||
|
|
2727e5f3b7 | ||
|
|
de53b567f5 | ||
|
|
21479a151d | ||
|
|
d822458d97 | ||
|
|
6741ea9790 | ||
|
|
2e1799dd80 | ||
|
|
c48c7669a8 | ||
|
|
d5fbcd708d | ||
|
|
b335a6a5ec | ||
|
|
f5cbee452a | ||
|
|
5d1ea4410a | ||
|
|
f27163d2c7 | ||
|
|
62c126f70e | ||
|
|
8344d5151c | ||
|
|
f7780eb720 | ||
|
|
c544d84b46 | ||
|
|
fbdc075e5c | ||
|
|
d3472104d0 | ||
|
|
0c8b981216 | ||
|
|
0e3f08aa68 | ||
|
|
a75b1c85ee | ||
|
|
726e6c68cf | ||
|
|
34c91224d7 | ||
|
|
50c4bbc52b | ||
|
|
f0239de559 | ||
|
|
2be632f3cc | ||
|
|
ec3fed5a61 | ||
|
|
1da44485d5 | ||
|
|
e5f30ff5a8 | ||
|
|
c92f5c14a3 | ||
|
|
2f92399f4e | ||
|
|
83dfb5fe8b | ||
|
|
cc915371ca | ||
|
|
5576db3d5a | ||
|
|
f26f38d023 | ||
|
|
578ec4d843 | ||
|
|
2f3bebe5a2 |
2
.cargo/config.toml
Normal file
2
.cargo/config.toml
Normal file
@@ -0,0 +1,2 @@
|
||||
[alias]
|
||||
dev = "run --package ruff_dev --bin ruff_dev"
|
||||
@@ -1,6 +1,6 @@
|
||||
repos:
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
rev: v0.0.98
|
||||
rev: v0.0.110
|
||||
hooks:
|
||||
- id: ruff
|
||||
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
# Contributing to ruff
|
||||
# Contributing to Ruff
|
||||
|
||||
Welcome! We're happy to have you here. Thank you in advance for your contribution to ruff.
|
||||
Welcome! We're happy to have you here. Thank you in advance for your contribution to Ruff.
|
||||
|
||||
## The basics
|
||||
|
||||
ruff welcomes contributions in the form of Pull Requests. For small changes (e.g., bug fixes), feel
|
||||
Ruff welcomes contributions in the form of Pull Requests. For small changes (e.g., bug fixes), feel
|
||||
free to submit a PR. For larger changes (e.g., new lint rules, new functionality, new configuration
|
||||
options), consider submitting an [Issue](https://github.com/charliermarsh/ruff/issues) outlining
|
||||
your proposed change.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
ruff is written in Rust (1.63.0). You'll need to install the
|
||||
Ruff is written in Rust. You'll need to install the
|
||||
[Rust toolchain](https://www.rust-lang.org/tools/install) for development.
|
||||
|
||||
You'll also need [Insta](https://insta.rs/docs/) to update snapshot tests:
|
||||
@@ -22,7 +22,7 @@ cargo install cargo-insta
|
||||
|
||||
### Development
|
||||
|
||||
After cloning the repository, run ruff locally with:
|
||||
After cloning the repository, run Ruff locally with:
|
||||
|
||||
```shell
|
||||
cargo run resources/test/fixtures --no-cache
|
||||
@@ -32,9 +32,9 @@ Prior to opening a pull request, ensure that your code has been auto-formatted,
|
||||
both the lint and test validation checks:
|
||||
|
||||
```shell
|
||||
cargo fmt # Auto-formatting...
|
||||
cargo clippy # Linting...
|
||||
cargo test # Testing...
|
||||
cargo +nightly fmt --all # Auto-formatting...
|
||||
cargo +nightly clippy --all # Linting...
|
||||
cargo +nightly test --all # Testing...
|
||||
```
|
||||
|
||||
These checks will run on GitHub Actions when you open your Pull Request, but running them locally
|
||||
@@ -45,12 +45,13 @@ prior to merging.
|
||||
|
||||
### Example: Adding a new lint rule
|
||||
|
||||
There are three phases to adding a new lint rule:
|
||||
There are four phases to adding a new lint rule:
|
||||
|
||||
1. Define the rule in `src/checks.rs`.
|
||||
2. Define the _logic_ for triggering the rule in `src/check_ast.rs` (for AST-based checks)
|
||||
or `src/check_lines.rs` (for text-based checks).
|
||||
2. Define the _logic_ for triggering the rule in `src/check_ast.rs` (for AST-based checks),
|
||||
`src/check_tokens.rs` (for token-based checks), or `src/check_lines.rs` (for text-based checks).
|
||||
3. Add a test fixture.
|
||||
4. Update the generated files (documentation and generated code).
|
||||
|
||||
To define the rule, open up `src/checks.rs`. You'll need to define both a `CheckCode` and
|
||||
`CheckKind`. As an example, you can grep for `E402` and `ModuleImportNotAtTopOfFile`, and follow the
|
||||
@@ -58,37 +59,33 @@ pattern implemented therein.
|
||||
|
||||
To trigger the rule, you'll likely want to augment the logic in `src/check_ast.rs`, which defines
|
||||
the Python AST visitor, responsible for iterating over the abstract syntax tree and collecting
|
||||
lint-rule violations as it goes. Grep for the `Check::new` invocations to understand how other,
|
||||
similar rules are implemented.
|
||||
lint-rule violations as it goes. If you need to inspect the AST, you can run `cargo dev print-ast`
|
||||
with a Python file. Grep for the `Check::new` invocations to 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`. Once you're satisfied with the output,
|
||||
codify the behavior as a snapshot test by adding a new function to the `mod tests` section of
|
||||
`src/linter.rs`, like so:
|
||||
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
|
||||
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
|
||||
#[test]
|
||||
fn e402() -> Result<()> {
|
||||
let mut checks = check_path(
|
||||
Path::new("./resources/test/fixtures/E402.py"),
|
||||
&settings::Settings::for_rule(CheckCode::E402),
|
||||
&fixer::Mode::Generate,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(checks);
|
||||
Ok(())
|
||||
}
|
||||
#[test_case(CheckCode::A001, Path::new("A001.py"); "A001")]
|
||||
...
|
||||
```
|
||||
|
||||
Then, run `cargo test`. Your test will fail, but you'll be prompted to follow-up with
|
||||
`cargo insta review`. Accept the generated snapshot, then commit the snapshot file alongside the
|
||||
rest of your changes.
|
||||
|
||||
Finally, to update the documentation, run `cargo dev generate-rules-table` from the repo root. To
|
||||
update the generated prefix map, run `cargo dev generate-check-code-prefix`. Both of these commands
|
||||
should be run whenever a new check is added to the codebase.
|
||||
|
||||
### Example: Adding a new configuration option
|
||||
|
||||
ruff's user-facing settings live in two places: first, the command-line options defined with
|
||||
Ruff's user-facing settings live in two places: first, the command-line options defined with
|
||||
[clap](https://docs.rs/clap/latest/clap/) via the `Cli` struct in `src/main.rs`; and second, the
|
||||
`Config` struct defined `src/pyproject.rs`, which is responsible for extracting user-defined
|
||||
settings from a `pyproject.toml` file.
|
||||
@@ -103,9 +100,9 @@ acceptable unused variables (e.g., `_`).
|
||||
|
||||
## Release process
|
||||
|
||||
As of now, ruff has an ad hoc release process: releases are cut with high frequency via GitHub
|
||||
As of now, Ruff has an ad hoc release process: releases are cut with high frequency via GitHub
|
||||
Actions, which automatically generates the appropriate wheels across architectures and publishes
|
||||
them to [PyPI](https://pypi.org/project/ruff/).
|
||||
|
||||
ruff follows the [semver](https://semver.org/) versioning standard. However, as pre-1.0 software,
|
||||
Ruff follows the [semver](https://semver.org/) versioning standard. However, as pre-1.0 software,
|
||||
even patch releases may contain [non-backwards-compatible changes](https://semver.org/#spec-item-4).
|
||||
|
||||
332
Cargo.lock
generated
332
Cargo.lock
generated
@@ -14,7 +14,7 @@ version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
|
||||
dependencies = [
|
||||
"getrandom 0.2.7",
|
||||
"getrandom 0.2.8",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
]
|
||||
@@ -51,9 +51,9 @@ checksum = "c7021ce4924a3f25f802b2cccd1af585e39ea1a363a1aa2e72afe54b67a3a7a7"
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.65"
|
||||
version = "1.0.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602"
|
||||
checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6"
|
||||
|
||||
[[package]]
|
||||
name = "ascii"
|
||||
@@ -72,11 +72,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "assert_cmd"
|
||||
version = "2.0.4"
|
||||
version = "2.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93ae1ddd39efd67689deb1979d80bad3bf7f2b09c6e6117c8d1f2443b5e2f83e"
|
||||
checksum = "ba45b8163c49ab5f972e59a8a5a03b6d2972619d486e19ec9fe744f7c2753d3c"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"bstr 1.0.1",
|
||||
"doc-comment",
|
||||
"predicates",
|
||||
"predicates-core",
|
||||
@@ -111,9 +111,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "async-global-executor"
|
||||
version = "2.3.0"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0da5b41ee986eed3f524c380e6d64965aea573882a8907682ad100f7859305ca"
|
||||
checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"async-executor",
|
||||
@@ -126,16 +126,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "async-io"
|
||||
version = "1.9.0"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83e21f3a490c72b3b0cf44962180e60045de2925d8dff97918f7ee43c8f637c7"
|
||||
checksum = "e8121296a9f05be7f34aa4196b1747243b3b62e048bb7906f644f3fbfc490cf7"
|
||||
dependencies = [
|
||||
"async-lock",
|
||||
"autocfg",
|
||||
"concurrent-queue",
|
||||
"futures-lite",
|
||||
"libc",
|
||||
"log",
|
||||
"once_cell",
|
||||
"parking",
|
||||
"polling",
|
||||
"slab",
|
||||
@@ -146,11 +146,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "async-lock"
|
||||
version = "2.5.0"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e97a171d191782fba31bb902b14ad94e24a68145032b7eedf871ab0bc0d077b6"
|
||||
checksum = "c8101efe8695a6c17e02911402145357e718ac92d3ff88ae8419e84b1707b685"
|
||||
dependencies = [
|
||||
"event-listener",
|
||||
"futures-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -238,9 +239,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.13.0"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
||||
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
@@ -328,10 +329,22 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.11.0"
|
||||
name = "bstr"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d"
|
||||
checksum = "fca0852af221f458706eb0725c03e4ed6c46af9ac98e6a689d5e634215d594dd"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"once_cell",
|
||||
"regex-automata",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba"
|
||||
|
||||
[[package]]
|
||||
name = "byte-tools"
|
||||
@@ -382,9 +395,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.73"
|
||||
version = "1.0.75"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
|
||||
checksum = "41ca34107f97baef6cfb231b32f36115781856b8f8208e8c580e0bcaea374842"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
@@ -464,14 +477,14 @@ dependencies = [
|
||||
"bitflags",
|
||||
"clap_lex 0.2.4",
|
||||
"indexmap",
|
||||
"textwrap 0.16.0",
|
||||
"textwrap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.0.15"
|
||||
version = "4.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6bf8832993da70a4c6d13c581f4463c2bdda27b9bf1c5498dc4365543abe6d6f"
|
||||
checksum = "91b9970d7505127a162fdaa9b96428d28a479ba78c9ec7550a63a5d9863db682"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"bitflags",
|
||||
@@ -484,9 +497,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.0.13"
|
||||
version = "4.0.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c42f169caba89a7d512b5418b09864543eeb4d497416c917d7137863bd2076ad"
|
||||
checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error",
|
||||
@@ -701,9 +714,9 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
|
||||
|
||||
[[package]]
|
||||
name = "ctor"
|
||||
version = "0.1.23"
|
||||
version = "0.1.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdffe87e1d521a10f9696f833fe502293ea446d7f256c06128293a4119bdf4cb"
|
||||
checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
@@ -711,9 +724,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cxx"
|
||||
version = "1.0.78"
|
||||
version = "1.0.81"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19f39818dcfc97d45b03953c1292efc4e80954e1583c4aa770bac1383e2310a4"
|
||||
checksum = "97abf9f0eca9e52b7f81b945524e76710e6cb2366aead23b7d4fbf72e281f888"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cxxbridge-flags",
|
||||
@@ -723,9 +736,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cxx-build"
|
||||
version = "1.0.78"
|
||||
version = "1.0.81"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e580d70777c116df50c390d1211993f62d40302881e54d4b79727acb83d0199"
|
||||
checksum = "7cc32cc5fea1d894b77d269ddb9f192110069a8a9c1f1d441195fba90553dea3"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"codespan-reporting",
|
||||
@@ -738,15 +751,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-flags"
|
||||
version = "1.0.78"
|
||||
version = "1.0.81"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56a46460b88d1cec95112c8c363f0e2c39afdb237f60583b0b36343bf627ea9c"
|
||||
checksum = "8ca220e4794c934dc6b1207c3b42856ad4c302f2df1712e9f8d2eec5afaacf1f"
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-macro"
|
||||
version = "1.0.78"
|
||||
version = "1.0.81"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "747b608fecf06b0d72d440f27acc99288207324b793be2c17991839f3d4995ea"
|
||||
checksum = "b846f081361125bfc8dc9d3940c84e1fd83ba54bbca7b17cd29483c828be0704"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -902,9 +915,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.17"
|
||||
version = "0.2.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e94a7bbaa59354bc20dd75b67f23e2797b4490e9d6928203fb105c79e448c86c"
|
||||
checksum = "4b9663d381d07ae25dc88dbdf27df458faa83a9b25336bcac83d5e452b5fc9d3"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
@@ -920,10 +933,10 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.98-dev.0"
|
||||
version = "0.0.110-dev.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.0.15",
|
||||
"clap 4.0.22",
|
||||
"configparser",
|
||||
"once_cell",
|
||||
"regex",
|
||||
@@ -995,9 +1008,9 @@ checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.24"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f21eda599937fba36daeb58a22e8f5cee2d14c4a17b5b7739c7c8e5e3b8230c"
|
||||
checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
@@ -1010,9 +1023,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.24"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30bdd20c28fadd505d0fd6712cdfcb0d4b5648baf45faef7f852afb2399bb050"
|
||||
checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
@@ -1020,15 +1033,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.24"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e5aa3de05362c3fb88de6531e6296e85cde7739cccad4b9dfeeb7f6ebce56bf"
|
||||
checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.24"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ff63c23854bee61b6e9cd331d523909f238fc7636290b96826e9cfa5faa00ab"
|
||||
checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
@@ -1037,9 +1050,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.24"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbf4d2a7a308fd4578637c0b17c7e1c7ba127b8f6ba00b29f717e9655d85eb68"
|
||||
checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb"
|
||||
|
||||
[[package]]
|
||||
name = "futures-lite"
|
||||
@@ -1058,9 +1071,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.24"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42cd15d1c7456c04dbdf7e88bcd69760d74f3a798d6444e16974b505b0e62f17"
|
||||
checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1069,21 +1082,21 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.24"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21b20ba5a92e727ba30e72834706623d94ac93a725410b6a6b6fbc1b07f7ba56"
|
||||
checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.24"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6508c467c73851293f390476d4491cf4d227dbabcd4170f3bb6044959b294f1"
|
||||
checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.24"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44fb6cb1be61cc1d2e43b262516aafcf63b241cffdb1d3fa115f91d9c7b09c90"
|
||||
checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
@@ -1129,9 +1142,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.7"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
|
||||
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"js-sys",
|
||||
@@ -1208,9 +1221,9 @@ checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.51"
|
||||
version = "0.1.53"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f5a6ef98976b22b3b7f2f3a806f858cb862044cfa66805aa3ad84cb3d3b785ed"
|
||||
checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
@@ -1222,9 +1235,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone-haiku"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fde6edd6cef363e9359ed3c98ba64590ba9eecba2293eb5a723ab32aee8926aa"
|
||||
checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca"
|
||||
dependencies = [
|
||||
"cxx",
|
||||
"cxx-build",
|
||||
@@ -1427,14 +1440,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.135"
|
||||
version = "0.2.137"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c"
|
||||
checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
|
||||
|
||||
[[package]]
|
||||
name = "libcst"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/charliermarsh/LibCST?rev=32a044c127668df44582f85699358e67803b0d73#32a044c127668df44582f85699358e67803b0d73"
|
||||
source = "git+https://github.com/charliermarsh/LibCST?rev=a13ec97dd4eb925bde4d426c6e422582793b260c#a13ec97dd4eb925bde4d426c6e422582793b260c"
|
||||
dependencies = [
|
||||
"chic",
|
||||
"itertools",
|
||||
@@ -1449,7 +1462,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "libcst_derive"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/charliermarsh/LibCST?rev=32a044c127668df44582f85699358e67803b0d73#32a044c127668df44582f85699358e67803b0d73"
|
||||
source = "git+https://github.com/charliermarsh/LibCST?rev=a13ec97dd4eb925bde4d426c6e422582793b260c#a13ec97dd4eb925bde4d426c6e422582793b260c"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
@@ -1583,9 +1596,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "net2"
|
||||
version = "0.2.37"
|
||||
version = "0.2.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae"
|
||||
checksum = "74d0df99cfcd2530b2e694f6e17e7f37b8e26bb23983ac530c0c97408837c631"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10",
|
||||
"libc",
|
||||
@@ -1680,9 +1693,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.13.1"
|
||||
version = "1.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
|
||||
checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
@@ -1690,9 +1703,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.15.0"
|
||||
version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1"
|
||||
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
|
||||
|
||||
[[package]]
|
||||
name = "oorandom"
|
||||
@@ -1714,9 +1727,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
version = "6.3.0"
|
||||
version = "6.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff"
|
||||
checksum = "3baf96e39c5359d2eb0dd6ccb42c62b91d9678aa68160d261b9e0ccbf9e9dea9"
|
||||
|
||||
[[package]]
|
||||
name = "parking"
|
||||
@@ -1736,9 +1749,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.9.3"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929"
|
||||
checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
@@ -1938,9 +1951,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "polling"
|
||||
version = "2.3.0"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "899b00b9c8ab553c743b3e11e87c5c7d423b2a2de229ba95b24a756344748011"
|
||||
checksum = "ab4609a838d88b73d8238967b60dd115cc08d38e2bbaf51ee1e4b695f89122e2"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if 1.0.0",
|
||||
@@ -1952,9 +1965,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.16"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
|
||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "precomputed-hash"
|
||||
@@ -1964,9 +1977,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
|
||||
|
||||
[[package]]
|
||||
name = "predicates"
|
||||
version = "2.1.1"
|
||||
version = "2.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5aab5be6e4732b473071984b3164dbbfb7a3674d30ea5ff44410b6bcd960c3c"
|
||||
checksum = "ab68289ded120dcbf9d571afcf70163233229052aec9b08ab09532f698d0e1e6"
|
||||
dependencies = [
|
||||
"difflib",
|
||||
"itertools",
|
||||
@@ -1975,15 +1988,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "predicates-core"
|
||||
version = "1.0.3"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da1c2388b1513e1b605fcec39a95e0a9e8ef088f71443ef37099fa9ae6673fcb"
|
||||
checksum = "a6e7125585d872860e9955ca571650b27a4979c5823084168c5ed5bbfb016b56"
|
||||
|
||||
[[package]]
|
||||
name = "predicates-tree"
|
||||
version = "1.0.5"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d86de6de25020a36c6d3643a86d9a6a9f552107c0559c60ea03551b5e16c032"
|
||||
checksum = "ad3f7fa8d61e139cbc7c3edfebf3b6678883a53f5ffac65d1259329a93ee43a5"
|
||||
dependencies = [
|
||||
"predicates-core",
|
||||
"termtree",
|
||||
@@ -2015,9 +2028,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.46"
|
||||
version = "1.0.47"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94e2ef8dbfc347b10c094890f778ee2e36ca9bb4262e86dc99cd217e35f3470b"
|
||||
checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -2097,7 +2110,7 @@ version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom 0.2.7",
|
||||
"getrandom 0.2.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2157,16 +2170,16 @@ version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
|
||||
dependencies = [
|
||||
"getrandom 0.2.7",
|
||||
"getrandom 0.2.8",
|
||||
"redox_syscall",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.6.0"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
|
||||
checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
@@ -2181,9 +2194,9 @@ checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.27"
|
||||
version = "0.6.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
|
||||
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
|
||||
|
||||
[[package]]
|
||||
name = "remove_dir_all"
|
||||
@@ -2209,25 +2222,34 @@ dependencies = [
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ropey"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbd22239fafefc42138ca5da064f3c17726a80d2379d817a3521240e78dd0064"
|
||||
dependencies = [
|
||||
"smallvec",
|
||||
"str_indices",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.98"
|
||||
version = "0.0.110"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"assert_cmd",
|
||||
"bincode",
|
||||
"cacache",
|
||||
"chrono",
|
||||
"clap 4.0.15",
|
||||
"clap 4.0.22",
|
||||
"clearscreen",
|
||||
"codegen",
|
||||
"colored",
|
||||
"common-path",
|
||||
"criterion",
|
||||
"dirs 4.0.0",
|
||||
"fern",
|
||||
"filetime",
|
||||
"getrandom 0.2.7",
|
||||
"getrandom 0.2.8",
|
||||
"glob",
|
||||
"insta",
|
||||
"itertools",
|
||||
@@ -2239,6 +2261,7 @@ dependencies = [
|
||||
"path-absolutize",
|
||||
"rayon",
|
||||
"regex",
|
||||
"ropey",
|
||||
"rustpython-ast",
|
||||
"rustpython-common",
|
||||
"rustpython-parser",
|
||||
@@ -2247,18 +2270,35 @@ dependencies = [
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"test-case",
|
||||
"textwrap 0.15.1",
|
||||
"textwrap",
|
||||
"titlecase",
|
||||
"toml",
|
||||
"update-informer",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff_dev"
|
||||
version = "0.0.110"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.0.22",
|
||||
"codegen",
|
||||
"itertools",
|
||||
"libcst",
|
||||
"ruff",
|
||||
"rustpython-ast",
|
||||
"rustpython-common",
|
||||
"rustpython-parser",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.20.6"
|
||||
version = "0.20.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5aab8ee6c7097ed6057f43c187a62418d0c05a4bd5f18b3571db50ee0f9ce033"
|
||||
checksum = "539a2bfe908f471bfa933876bd1eb6a19cf2176d375f82ef7f99530a40e48c2c"
|
||||
dependencies = [
|
||||
"log",
|
||||
"ring",
|
||||
@@ -2269,7 +2309,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-ast"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=77b821a1941019fe34f73ce17cea013ae1b98fd0#77b821a1941019fe34f73ce17cea013ae1b98fd0"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb#27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"rustpython-common",
|
||||
@@ -2279,7 +2319,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-common"
|
||||
version = "0.0.0"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=77b821a1941019fe34f73ce17cea013ae1b98fd0#77b821a1941019fe34f73ce17cea013ae1b98fd0"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb#27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb"
|
||||
dependencies = [
|
||||
"ascii",
|
||||
"cfg-if 1.0.0",
|
||||
@@ -2302,11 +2342,11 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-compiler-core"
|
||||
version = "0.1.2"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=77b821a1941019fe34f73ce17cea013ae1b98fd0#77b821a1941019fe34f73ce17cea013ae1b98fd0"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb#27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"bitflags",
|
||||
"bstr",
|
||||
"bstr 0.2.17",
|
||||
"itertools",
|
||||
"lz4_flex",
|
||||
"num-bigint",
|
||||
@@ -2319,7 +2359,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-parser"
|
||||
version = "0.1.2"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=77b821a1941019fe34f73ce17cea013ae1b98fd0#77b821a1941019fe34f73ce17cea013ae1b98fd0"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb#27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"anyhow",
|
||||
@@ -2391,18 +2431,18 @@ checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.145"
|
||||
version = "1.0.147"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b"
|
||||
checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.145"
|
||||
version = "1.0.147"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c"
|
||||
checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -2411,9 +2451,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.86"
|
||||
version = "1.0.87"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41feea4228a6f1cd09ec7a3593a682276702cd67b5273544757dae23c096f074"
|
||||
checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
@@ -2559,6 +2599,12 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "str_indices"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d9199fa80c817e074620be84374a520062ebac833f358d74b37060ce4a0f2c0"
|
||||
|
||||
[[package]]
|
||||
name = "string_cache"
|
||||
version = "0.8.4"
|
||||
@@ -2602,9 +2648,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.102"
|
||||
version = "1.0.103"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1"
|
||||
checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -2670,9 +2716,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "termtree"
|
||||
version = "0.2.4"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "507e9898683b6c43a9aa55b64259b721b52ba226e0f3779137e50ad114a4c90b"
|
||||
checksum = "95059e91184749cb66be6dc994f67f182b6d897cb3df74a5bf66b5e709295fd8"
|
||||
|
||||
[[package]]
|
||||
name = "test-case"
|
||||
@@ -2698,21 +2744,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.15.1"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "949517c0cf1bf4ee812e2e07e08ab448e3ae0d23472aee8a06c985f0c8815b16"
|
||||
checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
|
||||
dependencies = [
|
||||
"smawk",
|
||||
"unicode-linebreak",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.37"
|
||||
@@ -2952,7 +2992,7 @@ version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b97acb4c28a254fd7a4aeec976c46a7fa404eac4d7c134b30c75144846d7cb8f"
|
||||
dependencies = [
|
||||
"base64 0.13.0",
|
||||
"base64 0.13.1",
|
||||
"chunked_transfer",
|
||||
"flate2",
|
||||
"log",
|
||||
@@ -3208,46 +3248,60 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.36.1"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
|
||||
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.36.1"
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
|
||||
checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.36.1"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
|
||||
checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.36.1"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
|
||||
checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.36.1"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
|
||||
checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.36.1"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
|
||||
checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
|
||||
|
||||
[[package]]
|
||||
name = "ws2_32-sys"
|
||||
|
||||
27
Cargo.toml
27
Cargo.toml
@@ -1,18 +1,19 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"flake8_to_ruff",
|
||||
"flake8_to_ruff",
|
||||
"ruff_dev",
|
||||
]
|
||||
|
||||
[package]
|
||||
name = "ruff"
|
||||
version = "0.0.98"
|
||||
version = "0.0.110"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
name = "ruff"
|
||||
|
||||
[dependencies]
|
||||
anyhow = { version = "1.0.60" }
|
||||
anyhow = { version = "1.0.66" }
|
||||
bincode = { version = "1.3.3" }
|
||||
chrono = { version = "0.4.21" }
|
||||
clap = { version = "4.0.1", features = ["derive"] }
|
||||
@@ -23,25 +24,26 @@ fern = { version = "0.6.1" }
|
||||
filetime = { version = "0.2.17" }
|
||||
glob = { version = "0.3.0" }
|
||||
itertools = { version = "0.10.5" }
|
||||
libcst = { git = "https://github.com/charliermarsh/LibCST", rev = "32a044c127668df44582f85699358e67803b0d73" }
|
||||
libcst = { git = "https://github.com/charliermarsh/LibCST", rev = "a13ec97dd4eb925bde4d426c6e422582793b260c" }
|
||||
log = { version = "0.4.17" }
|
||||
notify = { version = "4.0.17" }
|
||||
num-bigint = { version = "0.4.3" }
|
||||
once_cell = { version = "1.13.1" }
|
||||
once_cell = { version = "1.16.0" }
|
||||
path-absolutize = { version = "3.0.14", features = ["once_cell_cache", "use_unix_paths_on_wasm"] }
|
||||
rayon = { version = "1.5.3" }
|
||||
regex = { version = "1.6.0" }
|
||||
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "77b821a1941019fe34f73ce17cea013ae1b98fd0" }
|
||||
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "77b821a1941019fe34f73ce17cea013ae1b98fd0" }
|
||||
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "77b821a1941019fe34f73ce17cea013ae1b98fd0" }
|
||||
serde = { version = "1.0.143", features = ["derive"] }
|
||||
serde_json = { version = "1.0.83" }
|
||||
ropey = { version = "1.5.0", features = ["cr_lines", "simd"], default-features = false }
|
||||
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb" }
|
||||
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb" }
|
||||
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb" }
|
||||
serde = { version = "1.0.147", features = ["derive"] }
|
||||
serde_json = { version = "1.0.87" }
|
||||
strum = { version = "0.24.1", features = ["strum_macros"] }
|
||||
strum_macros = { version = "0.24.3" }
|
||||
textwrap = { version = "0.15.1" }
|
||||
textwrap = { version = "0.16.0" }
|
||||
titlecase = { version = "2.2.1" }
|
||||
toml = { version = "0.5.9" }
|
||||
update-informer = { version = "0.5.0", default_features = false, features = ["pypi"], optional = true }
|
||||
update-informer = { version = "0.5.0", default-features = false, features = ["pypi"], optional = true }
|
||||
walkdir = { version = "2.3.2" }
|
||||
|
||||
[target.'cfg(not(target_family = "wasm"))'.dependencies]
|
||||
@@ -55,7 +57,6 @@ getrandom = { version = "0.2.7", features = ["js"] }
|
||||
|
||||
[dev-dependencies]
|
||||
assert_cmd = { version = "2.0.4" }
|
||||
codegen = { version = "0.2.0" }
|
||||
criterion = { version = "0.4.0" }
|
||||
insta = { version = "1.19.1", features = ["yaml"] }
|
||||
test-case = { version = "2.2.2" }
|
||||
|
||||
220
README.md
220
README.md
@@ -15,21 +15,29 @@ An extremely fast Python linter, written in Rust.
|
||||
<i>Linting the CPython codebase from scratch.</i>
|
||||
</p>
|
||||
|
||||
- ⚡️ 10-100x faster than existing linters
|
||||
- 🐍 Installable via `pip`
|
||||
- 🤝 Python 3.10 compatibility
|
||||
- 🛠️ `pyproject.toml` support
|
||||
- 📦 [ESLint](https://eslint.org/docs/latest/user-guide/command-line-interface#caching)-inspired cache support
|
||||
- 🔧 [ESLint](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix)-inspired autofix support (e.g., automatically remove unused imports)
|
||||
- 👀 [TypeScript](https://www.typescriptlang.org/docs/handbook/configuring-watch.html)-inspired `--watch` support, for continuous file monitoring
|
||||
- ⚖️ [Near-parity](#how-does-ruff-compare-to-flake8) with the built-in Flake8 rule set
|
||||
- 🔌 Native re-implementations of popular Flake8 plugins, like [`flake8-docstrings`](https://pypi.org/project/flake8-docstrings/) ([`pydocstyle`](https://pypi.org/project/pydocstyle/))
|
||||
- ⚡️ 10-100x faster than existing linters
|
||||
- 🐍 Installable via `pip`
|
||||
- 🤝 Python 3.10 compatibility
|
||||
- 🛠️ `pyproject.toml` support
|
||||
- 📦 Built-in caching, to avoid re-analyzing unchanged files
|
||||
- 🔧 `--fix` support, for automatic error correction (e.g., automatically remove unused imports)
|
||||
- 👀 `--watch` support, for continuous file monitoring
|
||||
- ⚖️ [Near-parity](#how-does-ruff-compare-to-flake8) with the built-in Flake8 rule set
|
||||
- 🔌 Native re-implementations of popular Flake8 plugins, like [`flake8-docstrings`](https://pypi.org/project/flake8-docstrings/) ([`pydocstyle`](https://pypi.org/project/pydocstyle/))
|
||||
|
||||
Ruff aims to be orders of magnitude faster than alternative tools while integrating more
|
||||
functionality behind a single, common interface. Ruff can be used to replace Flake8 (plus a variety
|
||||
of plugins), [`pydocstyle`](https://pypi.org/project/pydocstyle/), [`yesqa`](https://github.com/asottile/yesqa),
|
||||
and even a subset of [`pyupgrade`](https://pypi.org/project/pyupgrade/) and [`autoflake`](https://pypi.org/project/autoflake/)
|
||||
all while executing tens or hundreds of times faster than any individual tool.
|
||||
of plugins), [`isort`](https://pypi.org/project/isort/), [`pydocstyle`](https://pypi.org/project/pydocstyle/),
|
||||
[`yesqa`](https://github.com/asottile/yesqa), and even a subset of [`pyupgrade`](https://pypi.org/project/pyupgrade/)
|
||||
and [`autoflake`](https://pypi.org/project/autoflake/) all while executing tens or hundreds of times
|
||||
faster than any individual tool.
|
||||
|
||||
(Coming from Flake8? Try [`flake8-to-ruff`](https://pypi.org/project/flake8-to-ruff/) to
|
||||
automatically convert your existing configuration.)
|
||||
|
||||
Ruff is actively developed and used in major open-source projects
|
||||
like [Zulip](https://github.com/zulip/zulip), [pydantic](https://github.com/pydantic/pydantic),
|
||||
and [Saleor](https://github.com/saleor/saleor).
|
||||
|
||||
Read the [launch blog post](https://notes.crmarsh.com/python-tooling-could-be-much-much-faster).
|
||||
|
||||
@@ -39,17 +47,18 @@ Read the [launch blog post](https://notes.crmarsh.com/python-tooling-could-be-mu
|
||||
2. [Configuration](#configuration)
|
||||
3. [Supported Rules](#supported-rules)
|
||||
1. [Pyflakes](#pyflakes)
|
||||
2. [pycodestyle (error)](#pycodestyle-error)
|
||||
3. [pycodestyle (warning)](#pycodestyle-warning)
|
||||
4. [pydocstyle](#pydocstyle)
|
||||
5. [pyupgrade](#pyupgrade)
|
||||
6. [pep8-naming](#pep8-naming)
|
||||
7. [flake8-comprehensions](#flake8-comprehensions)
|
||||
8. [flake8-bugbear](#flake8-bugbear)
|
||||
9. [flake8-builtins](#flake8-builtins)
|
||||
10. [flake8-print](#flake8-print)
|
||||
11. [flake8-quotes](#flake8-quotes)
|
||||
12. [Meta rules](#meta-rules)
|
||||
2. [pycodestyle](#pycodestyle)
|
||||
3. [pydocstyle](#pydocstyle)
|
||||
4. [pyupgrade](#pyupgrade)
|
||||
5. [pep8-naming](#pep8-naming)
|
||||
6. [flake8-comprehensions](#flake8-comprehensions)
|
||||
7. [flake8-bugbear](#flake8-bugbear)
|
||||
8. [flake8-builtins](#flake8-builtins)
|
||||
9. [flake8-print](#flake8-print)
|
||||
10. [flake8-quotes](#flake8-quotes)
|
||||
11. [flake8-annotations](#flake8-annotations)
|
||||
12. [Ruff-specific rules](#ruff-specific-rules)
|
||||
13. [Meta rules](#meta-rules)
|
||||
5. [Editor Integrations](#editor-integrations)
|
||||
6. [FAQ](#faq)
|
||||
7. [Development](#development)
|
||||
@@ -89,7 +98,7 @@ Ruff also works with [pre-commit](https://pre-commit.com):
|
||||
```yaml
|
||||
repos:
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
rev: v0.0.98
|
||||
rev: v0.0.110
|
||||
hooks:
|
||||
- id: ruff
|
||||
```
|
||||
@@ -195,7 +204,7 @@ Options:
|
||||
Exit with status code "0", even upon detecting errors
|
||||
-w, --watch
|
||||
Run in watch mode by re-running whenever files change
|
||||
-f, --fix
|
||||
--fix
|
||||
Attempt to automatically fix lint errors
|
||||
-n, --no-cache
|
||||
Disable cache reads
|
||||
@@ -277,25 +286,32 @@ Ruff supports several workflows to aid in `noqa` management.
|
||||
|
||||
First, Ruff provides a special error code, `M001`, to enforce that your `noqa` directives are
|
||||
"valid", in that the errors they _say_ they ignore are actually being triggered on that line (and
|
||||
thus suppressed). **You can run `ruff /path/to/file.py --extend-select M001` to flag unused `noqa`
|
||||
directives.**
|
||||
thus suppressed). You can run `ruff /path/to/file.py --extend-select M001` to flag unused `noqa`
|
||||
directives.
|
||||
|
||||
Second, Ruff can _automatically remove_ unused `noqa` directives via its autofix functionality.
|
||||
**You can run `ruff /path/to/file.py --extend-select M001 --fix` to automatically remove unused
|
||||
`noqa` directives.**
|
||||
You can run `ruff /path/to/file.py --extend-select M001 --fix` to automatically remove unused
|
||||
`noqa` directives.
|
||||
|
||||
Third, Ruff can _automatically add_ `noqa` directives to all failing lines. This is useful when
|
||||
migrating a new codebase to Ruff. **You can run `ruff /path/to/file.py --add-noqa` to automatically
|
||||
add `noqa` directives to all failing lines, with the appropriate error codes.**
|
||||
migrating a new codebase to Ruff. You can run `ruff /path/to/file.py --add-noqa` to automatically
|
||||
add `noqa` directives to all failing lines, with the appropriate error codes.
|
||||
|
||||
## Supported Rules
|
||||
|
||||
Regardless of the rule's origin, Ruff re-implements every rule in Rust as a first-party feature.
|
||||
|
||||
By default, Ruff enables all `E` and `F` error codes, which correspond to those built-in to Flake8.
|
||||
|
||||
The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` command-line option.
|
||||
|
||||
<!-- Sections automatically generated by `cargo dev generate-rules-table`. -->
|
||||
<!-- Begin auto-generated sections. -->
|
||||
|
||||
### Pyflakes
|
||||
|
||||
For more, see [Pyflakes](https://pypi.org/project/pyflakes/2.5.0/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| F401 | UnusedImport | `...` imported but unused | 🛠 |
|
||||
@@ -311,7 +327,7 @@ The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` com
|
||||
| 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 `==` and `!=` 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 | |
|
||||
@@ -325,9 +341,11 @@ The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` com
|
||||
| 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 | |
|
||||
| F901 | RaiseNotImplemented | `raise NotImplemented` should be `raise NotImplementedError` | |
|
||||
| F901 | RaiseNotImplemented | `raise NotImplemented` should be `raise NotImplementedError` | 🛠 |
|
||||
|
||||
### pycodestyle (error)
|
||||
### pycodestyle
|
||||
|
||||
For more, see [pycodestyle](https://pypi.org/project/pycodestyle/2.9.1/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
@@ -345,16 +363,21 @@ The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` com
|
||||
| E743 | AmbiguousFunctionName | Ambiguous function name: `...` | |
|
||||
| E902 | IOError | IOError: `...` | |
|
||||
| E999 | SyntaxError | SyntaxError: `...` | |
|
||||
|
||||
### pycodestyle (warning)
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| W292 | NoNewLineAtEndOfFile | No newline at end of file | |
|
||||
| W605 | InvalidEscapeSequence | Invalid escape sequence: '\c' | |
|
||||
|
||||
### isort
|
||||
|
||||
For more, see [isort](https://pypi.org/project/isort/5.10.1/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| I001 | UnsortedImports | Import block is un-sorted or un-formatted | 🛠 |
|
||||
|
||||
### pydocstyle
|
||||
|
||||
For more, see [pydocstyle](https://pypi.org/project/pydocstyle/6.1.1/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| D100 | PublicModule | Missing docstring in public module | |
|
||||
@@ -404,6 +427,8 @@ The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` com
|
||||
|
||||
### pyupgrade
|
||||
|
||||
For more, see [pyupgrade](https://pypi.org/project/pyupgrade/3.2.0/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| U001 | UselessMetaclassType | `__metaclass__ = type` is implied | 🛠 |
|
||||
@@ -414,9 +439,14 @@ The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` com
|
||||
| U006 | UsePEP585Annotation | Use `list` instead of `List` for type annotations | 🛠 |
|
||||
| U007 | UsePEP604Annotation | Use `X \| Y` for type annotations | 🛠 |
|
||||
| U008 | SuperCallWithParameters | Use `super()` instead of `super(__class__, self)` | 🛠 |
|
||||
| U009 | PEP3120UnnecessaryCodingComment | utf-8 encoding declaration is unnecessary | 🛠 |
|
||||
| U010 | UnnecessaryFutureImport | Unnessary __future__ import `...` for target Python version | |
|
||||
| U011 | UnnecessaryLRUCacheParams | Unnessary parameters to functools.lru_cache | 🛠 |
|
||||
|
||||
### pep8-naming
|
||||
|
||||
For more, see [pep8-naming](https://pypi.org/project/pep8-naming/0.13.2/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| N801 | InvalidClassName | Class name `...` should use CapWords convention | |
|
||||
@@ -437,15 +467,17 @@ The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` com
|
||||
|
||||
### flake8-comprehensions
|
||||
|
||||
For more, see [flake8-comprehensions](https://pypi.org/project/flake8-comprehensions/3.10.1/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| C400 | UnnecessaryGeneratorList | Unnecessary generator (rewrite as a `list` comprehension) | 🛠 |
|
||||
| C401 | UnnecessaryGeneratorSet | Unnecessary generator (rewrite as a `set` comprehension) | 🛠 |
|
||||
| C402 | UnnecessaryGeneratorDict | Unnecessary generator (rewrite as a `dict` comprehension) | 🛠 |
|
||||
| C403 | UnnecessaryListComprehensionSet | Unnecessary `list` comprehension (rewrite as a `set` comprehension) | 🛠 |
|
||||
| C404 | UnnecessaryListComprehensionDict | Unnecessary `list` comprehension (rewrite as a `dict` comprehension) | |
|
||||
| C404 | UnnecessaryListComprehensionDict | Unnecessary `list` comprehension (rewrite as a `dict` comprehension) | 🛠 |
|
||||
| C405 | UnnecessaryLiteralSet | Unnecessary `(list\|tuple)` literal (rewrite as a `set` literal) | 🛠 |
|
||||
| C406 | UnnecessaryLiteralDict | Unnecessary `(list\|tuple)` literal (rewrite as a `dict` literal) | |
|
||||
| C406 | UnnecessaryLiteralDict | Unnecessary `(list\|tuple)` literal (rewrite as a `dict` literal) | 🛠 |
|
||||
| C408 | UnnecessaryCollectionCall | Unnecessary `(dict\|list\|tuple)` call (rewrite as a literal) | 🛠 |
|
||||
| C409 | UnnecessaryLiteralWithinTupleCall | Unnecessary `(list\|tuple)` literal passed to `tuple()` (remove the outer call to `tuple()`) | 🛠 |
|
||||
| C410 | UnnecessaryLiteralWithinListCall | Unnecessary `(list\|tuple)` literal passed to `list()` (rewrite as a `list` literal) | 🛠 |
|
||||
@@ -453,24 +485,37 @@ The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` com
|
||||
| C413 | UnnecessaryCallAroundSorted | Unnecessary `(list\|reversed)` call around `sorted()` | |
|
||||
| C414 | UnnecessaryDoubleCastOrProcess | Unnecessary `(list\|reversed\|set\|sorted\|tuple)` call within `(list\|set\|sorted\|tuple)()` | |
|
||||
| C415 | UnnecessarySubscriptReversal | Unnecessary subscript reversal of iterable within `(reversed\|set\|sorted)()` | |
|
||||
| C416 | UnnecessaryComprehension | Unnecessary `(list\|set)` comprehension (rewrite using `(list\|set)()`) | |
|
||||
| C416 | UnnecessaryComprehension | Unnecessary `(list\|set)` comprehension (rewrite using `(list\|set)()`) | 🛠 |
|
||||
| C417 | UnnecessaryMap | Unnecessary `map` usage (rewrite using a `(list\|set\|dict)` comprehension) | |
|
||||
|
||||
### flake8-bugbear
|
||||
|
||||
For more, see [flake8-bugbear](https://pypi.org/project/flake8-bugbear/22.10.27/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| B002 | UnaryPrefixIncrement | Python does not support the unary prefix increment. | |
|
||||
| B003 | AssignmentToOsEnviron | Assigning to `os.environ` doesn't clear the environment. | |
|
||||
| B004 | UnreliableCallableCheck | Using `hasattr(x, '__call__')` to test if x is callable is unreliable. Use `callable(x)` for consistent results. | |
|
||||
| B005 | StripWithMultiCharacters | Using `.strip()` with multi-character strings is misleading the reader. | |
|
||||
| B006 | MutableArgumentDefault | Do not use mutable data structures for argument defaults. | |
|
||||
| B007 | UnusedLoopControlVariable | Loop control variable `i` not used within the loop body. | 🛠 |
|
||||
| B008 | FunctionCallArgumentDefault | Do not perform function calls in argument defaults. | |
|
||||
| B009 | GetAttrWithConstant | Do not call `getattr` with a constant attribute value, it is not any safer than normal property access. | |
|
||||
| B011 | DoNotAssertFalse | Do not `assert False` (`python -O` removes these calls), raise `AssertionError()` | 🛠 |
|
||||
| B013 | RedundantTupleInExceptionHandler | A length-one tuple literal is redundant. Write `except ValueError:` instead of `except (ValueError,):`. | |
|
||||
| B014 | DuplicateHandlerException | Exception handler with duplicate exception: `ValueError` | 🛠 |
|
||||
| B015 | UselessComparison | Pointless comparison. This comparison does nothing but waste CPU instructions. Either prepend `assert` or remove it. | |
|
||||
| B016 | CannotRaiseLiteral | Cannot raise a literal. Did you intend to return it or raise an Exception? | |
|
||||
| B017 | NoAssertRaisesException | `assertRaises(Exception):` should be considered evil. | |
|
||||
| B018 | UselessExpression | Found useless expression. Either assign it to a variable or remove it. | |
|
||||
| B025 | DuplicateTryBlockException | try-except block with duplicate exception `Exception` | |
|
||||
| B026 | StarArgUnpackingAfterKeywordArg | Star-arg unpacking after a keyword argument is strongly discouraged. | |
|
||||
|
||||
### flake8-builtins
|
||||
|
||||
For more, see [flake8-builtins](https://pypi.org/project/flake8-builtins/2.0.1/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| A001 | BuiltinVariableShadowing | Variable `...` is shadowing a python builtin | |
|
||||
@@ -479,6 +524,8 @@ The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` com
|
||||
|
||||
### flake8-print
|
||||
|
||||
For more, see [flake8-print](https://pypi.org/project/flake8-print/5.0.0/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| T201 | PrintFound | `print` found | 🛠 |
|
||||
@@ -486,6 +533,8 @@ The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` com
|
||||
|
||||
### flake8-quotes
|
||||
|
||||
For more, see [flake8-quotes](https://pypi.org/project/flake8-quotes/3.3.1/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| Q000 | BadQuotesInlineString | Single quotes found but double quotes preferred | |
|
||||
@@ -493,14 +542,46 @@ The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` com
|
||||
| Q002 | BadQuotesDocstring | Single quote docstring found but double quotes preferred | |
|
||||
| Q003 | AvoidQuoteEscape | Change outer quotes to avoid escaping inner quotes | |
|
||||
|
||||
### flake8-annotations
|
||||
|
||||
For more, see [flake8-annotations](https://pypi.org/project/flake8-annotations/2.9.1/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| ANN001 | MissingTypeFunctionArgument | Missing type annotation for function argument `...` | |
|
||||
| ANN002 | MissingTypeArgs | Missing type annotation for `*...` | |
|
||||
| ANN003 | MissingTypeKwargs | Missing type annotation for `**...` | |
|
||||
| ANN101 | MissingTypeSelf | Missing type annotation for `...` in method | |
|
||||
| ANN102 | MissingTypeCls | Missing type annotation for `...` in classmethod | |
|
||||
| ANN201 | MissingReturnTypePublicFunction | Missing return type annotation for public function `...` | |
|
||||
| ANN202 | MissingReturnTypePrivateFunction | Missing return type annotation for private function `...` | |
|
||||
| ANN204 | MissingReturnTypeMagicMethod | Missing return type annotation for magic method `...` | |
|
||||
| ANN205 | MissingReturnTypeStaticMethod | Missing return type annotation for staticmethod `...` | |
|
||||
| ANN206 | MissingReturnTypeClassMethod | Missing return type annotation for classmethod `...` | |
|
||||
| ANN401 | DynamicallyTypedExpression | Dynamically typed expressions (typing.Any) are disallowed in `...` | |
|
||||
|
||||
### Ruff-specific rules
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| 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'?) | |
|
||||
|
||||
### Meta rules
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| M001 | UnusedNOQA | Unused `noqa` directive | 🛠 |
|
||||
|
||||
<!-- End auto-generated sections. -->
|
||||
|
||||
## Editor Integrations
|
||||
|
||||
### VS Code (Official)
|
||||
|
||||
Download the [Ruff VS Code extension](https://marketplace.visualstudio.com/items?itemName=charliermarsh.ruff).
|
||||
|
||||
### PyCharm
|
||||
|
||||
Ruff can be installed as an [External Tool](https://www.jetbrains.com/help/pycharm/configuring-third-party-tools.html)
|
||||
@@ -513,6 +594,19 @@ Ruff should then appear as a runnable action:
|
||||
|
||||

|
||||
|
||||
### Vim & Neovim (Unofficial)
|
||||
|
||||
Ruff is available as part of the [coc-pyright](https://github.com/fannheyward/coc-pyright) extension
|
||||
for coc.nvim.
|
||||
|
||||
Ruff can also be integrated via [efm](https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md#efm)
|
||||
in just a [few lines](https://github.com/JafarAbdi/myconfigs/blob/6f0b6b2450e92ec8fc50422928cd22005b919110/efm-langserver/config.yaml#L14-L20).
|
||||
|
||||
### Language Server Protocol (Unofficial)
|
||||
|
||||
[`ruffd`](https://github.com/Seamooo/ruffd) is a Rust-based language server for Ruff that implements
|
||||
the Language Server Protocol (LSP).
|
||||
|
||||
### GitHub Actions
|
||||
|
||||
GitHub Actions has everything you need to run Ruff out-of-the-box:
|
||||
@@ -549,6 +643,9 @@ stylistic lint rules that are obviated by autoformatting.
|
||||
|
||||
### How does Ruff compare to Flake8?
|
||||
|
||||
(Coming from Flake8? Try [`flake8-to-ruff`](https://pypi.org/project/flake8-to-ruff/) to
|
||||
automatically convert your existing configuration.)
|
||||
|
||||
Ruff can be used as a (near) drop-in replacement for Flake8 when used (1) without or with a small
|
||||
number of plugins, (2) alongside Black, and (3) on Python 3 code.
|
||||
|
||||
@@ -566,9 +663,10 @@ including:
|
||||
- [`flake8-super`](https://pypi.org/project/flake8-super/)
|
||||
- [`flake8-print`](https://pypi.org/project/flake8-print/)
|
||||
- [`flake8-quotes`](https://pypi.org/project/flake8-quotes/)
|
||||
- [`flake8-annotations`](https://pypi.org/project/flake8-annotations/)
|
||||
- [`flake8-comprehensions`](https://pypi.org/project/flake8-comprehensions/)
|
||||
- [`flake8-bugbear`](https://pypi.org/project/flake8-bugbear/) (10/32)
|
||||
- [`pyupgrade`](https://pypi.org/project/pyupgrade/) (10/34)
|
||||
- [`flake8-bugbear`](https://pypi.org/project/flake8-bugbear/) (19/32)
|
||||
- [`pyupgrade`](https://pypi.org/project/pyupgrade/) (14/34)
|
||||
- [`autoflake`](https://pypi.org/project/autoflake/) (1/7)
|
||||
|
||||
Beyond rule-set parity, Ruff suffers from the following limitations vis-à-vis Flake8:
|
||||
@@ -588,11 +686,12 @@ Today, Ruff can be used to replace Flake8 when used with any of the following pl
|
||||
- [`flake8-super`](https://pypi.org/project/flake8-super/)
|
||||
- [`flake8-print`](https://pypi.org/project/flake8-print/)
|
||||
- [`flake8-quotes`](https://pypi.org/project/flake8-quotes/)
|
||||
- [`flake8-annotations`](https://pypi.org/project/flake8-annotations/)
|
||||
- [`flake8-comprehensions`](https://pypi.org/project/flake8-comprehensions/)
|
||||
- [`flake8-bugbear`](https://pypi.org/project/flake8-bugbear/) (10/32)
|
||||
- [`flake8-bugbear`](https://pypi.org/project/flake8-bugbear/) (19/32)
|
||||
|
||||
Ruff also implements the functionality that you get from [`yesqa`](https://github.com/asottile/yesqa),
|
||||
and a subset of the rules implemented in [`pyupgrade`](https://pypi.org/project/pyupgrade/) (10/34).
|
||||
Ruff can also replace [`isort`](https://pypi.org/project/isort/), [`yesqa`](https://github.com/asottile/yesqa),
|
||||
and a subset of the rules implemented in [`pyupgrade`](https://pypi.org/project/pyupgrade/) (14/34).
|
||||
|
||||
If you're looking to use Ruff, but rely on an unsupported Flake8 plugin, free to file an Issue.
|
||||
|
||||
@@ -612,6 +711,31 @@ on Rust at all.
|
||||
Ruff does not yet support third-party plugins, though a plugin system is within-scope for the
|
||||
project. See [#283](https://github.com/charliermarsh/ruff/issues/283) for more.
|
||||
|
||||
### How does Ruff's import sorting compare to [`isort`](https://pypi.org/project/isort/)?
|
||||
|
||||
Ruff's import sorting is intended to be equivalent to `isort` when used `profile = "black"` and
|
||||
`combine_as_imports = true`. Like `isort`, Ruff's import sorting is compatible with Black.
|
||||
|
||||
Ruff is less configurable than `isort`, but supports the `known-first-party`, `known-third-party`,
|
||||
`extra-standard-library`, and `src` settings, like so:
|
||||
|
||||
```toml
|
||||
[tool.ruff]
|
||||
select = [
|
||||
# Pyflakes
|
||||
"F",
|
||||
# Pycodestyle
|
||||
"E",
|
||||
"W",
|
||||
# isort
|
||||
"I"
|
||||
]
|
||||
src = ["src", "tests"]
|
||||
|
||||
[tool.ruff.isort]
|
||||
known-first-party = ["my_module1", "my_module2"]
|
||||
```
|
||||
|
||||
### Does Ruff support NumPy- or Google-style docstrings?
|
||||
|
||||
Yes! To enable a specific docstring convention, start by enabling all `pydocstyle` error codes, and
|
||||
@@ -684,7 +808,7 @@ extend-ignore = [
|
||||
|
||||
## Development
|
||||
|
||||
Ruff is written in Rust (1.64.0). You'll need to install the [Rust toolchain](https://www.rust-lang.org/tools/install)
|
||||
Ruff is written in Rust (1.65.0). You'll need to install the [Rust toolchain](https://www.rust-lang.org/tools/install)
|
||||
for development.
|
||||
|
||||
Assuming you have `cargo` installed, you can run:
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
use std::path::Path;
|
||||
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
use ropey::Rope;
|
||||
use ruff::fs;
|
||||
use ruff::source_code_locator::compute_offsets;
|
||||
|
||||
fn criterion_benchmark(c: &mut Criterion) {
|
||||
let contents = fs::read_file(Path::new("resources/test/fixtures/D.py")).unwrap();
|
||||
c.bench_function("compute_offsets", |b| {
|
||||
b.iter(|| compute_offsets(black_box(&contents)))
|
||||
c.bench_function("rope", |b| {
|
||||
b.iter(|| {
|
||||
let rope = Rope::from_str(black_box(&contents));
|
||||
rope.line_to_char(black_box(4));
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
//! Generate a Markdown-compatible table of supported lint rules.
|
||||
|
||||
use ruff::checks::{CheckCategory, CheckCode};
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
fn main() {
|
||||
for check_category in CheckCategory::iter() {
|
||||
println!("### {}", check_category.title());
|
||||
println!();
|
||||
|
||||
println!("| Code | Name | Message | Fix |");
|
||||
println!("| ---- | ---- | ------- | --- |");
|
||||
for check_code in CheckCode::iter() {
|
||||
if check_code.category() == check_category {
|
||||
let check_kind = check_code.kind();
|
||||
let fix_token = if check_kind.fixable() { "🛠" } else { "" };
|
||||
println!(
|
||||
"| {} | {} | {} | {} |",
|
||||
check_kind.code().as_ref(),
|
||||
check_kind.as_ref(),
|
||||
check_kind.summary().replace("|", r"\|"),
|
||||
fix_token
|
||||
);
|
||||
}
|
||||
}
|
||||
println!();
|
||||
}
|
||||
}
|
||||
18
flake8_to_ruff/Cargo.lock
generated
18
flake8_to_ruff/Cargo.lock
generated
@@ -771,7 +771,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8_to_ruff"
|
||||
version = "0.0.98"
|
||||
version = "0.0.110"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@@ -1265,7 +1265,7 @@ checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
|
||||
[[package]]
|
||||
name = "libcst"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/charliermarsh/LibCST?rev=32a044c127668df44582f85699358e67803b0d73#32a044c127668df44582f85699358e67803b0d73"
|
||||
source = "git+https://github.com/charliermarsh/LibCST?rev=a13ec97dd4eb925bde4d426c6e422582793b260c#a13ec97dd4eb925bde4d426c6e422582793b260c"
|
||||
dependencies = [
|
||||
"chic",
|
||||
"itertools",
|
||||
@@ -1280,7 +1280,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "libcst_derive"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/charliermarsh/LibCST?rev=32a044c127668df44582f85699358e67803b0d73#32a044c127668df44582f85699358e67803b0d73"
|
||||
source = "git+https://github.com/charliermarsh/LibCST?rev=a13ec97dd4eb925bde4d426c6e422582793b260c#a13ec97dd4eb925bde4d426c6e422582793b260c"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
@@ -1505,7 +1505,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.13.1"
|
||||
version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
|
||||
dependencies = [
|
||||
@@ -1975,7 +1975,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.98"
|
||||
version = "0.0.110"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
@@ -2028,7 +2028,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-ast"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=77b821a1941019fe34f73ce17cea013ae1b98fd0#77b821a1941019fe34f73ce17cea013ae1b98fd0"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb#27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"rustpython-common",
|
||||
@@ -2038,7 +2038,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-common"
|
||||
version = "0.0.0"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=77b821a1941019fe34f73ce17cea013ae1b98fd0#77b821a1941019fe34f73ce17cea013ae1b98fd0"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb#27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb"
|
||||
dependencies = [
|
||||
"ascii",
|
||||
"cfg-if 1.0.0",
|
||||
@@ -2061,7 +2061,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-compiler-core"
|
||||
version = "0.1.2"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=77b821a1941019fe34f73ce17cea013ae1b98fd0#77b821a1941019fe34f73ce17cea013ae1b98fd0"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb#27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"bitflags",
|
||||
@@ -2078,7 +2078,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-parser"
|
||||
version = "0.1.2"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=77b821a1941019fe34f73ce17cea013ae1b98fd0#77b821a1941019fe34f73ce17cea013ae1b98fd0"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb#27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"anyhow",
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
[package]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.98-dev.0"
|
||||
version = "0.0.110-dev.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
name = "flake8_to_ruff"
|
||||
|
||||
[dependencies]
|
||||
anyhow = { version = "1.0.60" }
|
||||
anyhow = { version = "1.0.66" }
|
||||
clap = { version = "4.0.1", features = ["derive"] }
|
||||
configparser = { version = "3.0.2" }
|
||||
once_cell = { version = "1.13.1" }
|
||||
once_cell = { version = "1.16.0" }
|
||||
regex = { version = "1.6.0" }
|
||||
ruff = { path = "..", default-features = false }
|
||||
serde = { version = "1.0.143", features = ["derive"] }
|
||||
serde_json = { version = "1.0.83" }
|
||||
serde = { version = "1.0.147", features = ["derive"] }
|
||||
serde_json = { version = "1.0.87" }
|
||||
toml = { version = "0.5.9" }
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -17,7 +17,7 @@ pip install flake8-to-ruff
|
||||
|
||||
### Usage
|
||||
|
||||
To run Ruff, try any of the following:
|
||||
To run `flake8-to-ruff`:
|
||||
|
||||
```shell
|
||||
flake8-to-ruff path/to/setup.cfg
|
||||
@@ -25,6 +25,60 @@ flake8-to-ruff path/to/tox.ini
|
||||
flake8-to-ruff path/to/.flake8
|
||||
```
|
||||
|
||||
`flake8-to-ruff` will print the relevant `pyproject.toml` sections to standard output, like so:
|
||||
|
||||
```toml
|
||||
[tool.ruff]
|
||||
exclude = [
|
||||
'.svn',
|
||||
'CVS',
|
||||
'.bzr',
|
||||
'.hg',
|
||||
'.git',
|
||||
'__pycache__',
|
||||
'.tox',
|
||||
'.idea',
|
||||
'.mypy_cache',
|
||||
'.venv',
|
||||
'node_modules',
|
||||
'_state_machine.py',
|
||||
'test_fstring.py',
|
||||
'bad_coding2.py',
|
||||
'badsyntax_*.py',
|
||||
]
|
||||
select = [
|
||||
'A',
|
||||
'E',
|
||||
'F',
|
||||
'Q',
|
||||
]
|
||||
ignore = []
|
||||
|
||||
[tool.ruff.flake8-quotes]
|
||||
inline-quotes = 'single'
|
||||
|
||||
[tool.ruff.pep8-naming]
|
||||
ignore-names = [
|
||||
'foo',
|
||||
'bar',
|
||||
]
|
||||
```
|
||||
|
||||
### Plugins
|
||||
|
||||
`flake8-to-ruff` will attempt to infer any activated plugins based on the settings provided in your
|
||||
configuration file.
|
||||
|
||||
For example, if your `.flake8` file includes a `docstring-convention` property, `flake8-to-ruff`
|
||||
will enable the appropriate [`flake8-docstrings`](https://pypi.org/project/flake8-docstrings/)
|
||||
checks.
|
||||
|
||||
Alternatively, you can manually specify plugins on the command-line:
|
||||
|
||||
```shell
|
||||
flake8-to-ruff path/to/.flake8 --plugin flake8-builtins --plugin flake8-quotes
|
||||
```
|
||||
|
||||
## Limitations
|
||||
|
||||
1. Ruff only supports a subset of the Flake configuration options. `flake8-to-ruff` will warn on and
|
||||
@@ -33,9 +87,6 @@ flake8-to-ruff path/to/.flake8
|
||||
2. Ruff will omit any error codes that are unimplemented or unsupported by Ruff, including error
|
||||
codes from unsupported plugins. (See the [Ruff README](https://github.com/charliermarsh/ruff#user-content-how-does-ruff-compare-to-flake8)
|
||||
for the complete list of supported plugins.)
|
||||
3. `flake8-to-ruff` does not auto-detect your Flake8 plugins, so any reliance on Flake8 plugins that
|
||||
implicitly enable third-party checks will be ignored. Instead, add those error codes to your
|
||||
`select` or `extend-select` fields, so that `flake8-to-ruff` can pick them up.
|
||||
|
||||
## License
|
||||
|
||||
|
||||
36
flake8_to_ruff/examples/poetry.ini
Normal file
36
flake8_to_ruff/examples/poetry.ini
Normal file
@@ -0,0 +1,36 @@
|
||||
[flake8]
|
||||
min_python_version = 3.7.0
|
||||
max-line-length = 88
|
||||
ban-relative-imports = true
|
||||
# flake8-use-fstring: https://github.com/MichaelKim0407/flake8-use-fstring#--percent-greedy-and---format-greedy
|
||||
format-greedy = 1
|
||||
inline-quotes = double
|
||||
enable-extensions = TC, TC1
|
||||
type-checking-strict = true
|
||||
eradicate-whitelist-extend = ^-.*;
|
||||
extend-ignore =
|
||||
# E203: Whitespace before ':' (pycqa/pycodestyle#373)
|
||||
E203,
|
||||
# SIM106: Handle error-cases first
|
||||
SIM106,
|
||||
# ANN101: Missing type annotation for self in method
|
||||
ANN101,
|
||||
# ANN102: Missing type annotation for cls in classmethod
|
||||
ANN102,
|
||||
# PIE781: assign-and-return
|
||||
PIE781,
|
||||
# PIE798 no-unnecessary-class: Consider using a module for namespacing instead
|
||||
PIE798,
|
||||
per-file-ignores =
|
||||
# TC002: Move third-party import '...' into a type-checking block
|
||||
__init__.py:TC002,
|
||||
# ANN201: Missing return type annotation for public function
|
||||
tests/test_*:ANN201
|
||||
tests/**/test_*:ANN201
|
||||
extend-exclude =
|
||||
# Frozen and not subject to change in this repo:
|
||||
get-poetry.py,
|
||||
install-poetry.py,
|
||||
# External to the project's coding standards:
|
||||
tests/fixtures/*,
|
||||
tests/**/fixtures/*,
|
||||
19
flake8_to_ruff/examples/python-discord.ini
Normal file
19
flake8_to_ruff/examples/python-discord.ini
Normal file
@@ -0,0 +1,19 @@
|
||||
[flake8]
|
||||
max-line-length=120
|
||||
docstring-convention=all
|
||||
import-order-style=pycharm
|
||||
application_import_names=bot,tests
|
||||
exclude=.cache,.venv,.git,constants.py
|
||||
extend-ignore=
|
||||
B311,W503,E226,S311,T000,E731
|
||||
# Missing Docstrings
|
||||
D100,D104,D105,D107,
|
||||
# Docstring Whitespace
|
||||
D203,D212,D214,D215,
|
||||
# Docstring Quotes
|
||||
D301,D302,
|
||||
# Docstring Content
|
||||
D400,D401,D402,D404,D405,D406,D407,D408,D409,D410,D411,D412,D413,D414,D416,D417
|
||||
# Type Annotations
|
||||
ANN002,ANN003,ANN101,ANN102,ANN204,ANN206,ANN401
|
||||
per-file-ignores=tests/*:D,ANN
|
||||
6
flake8_to_ruff/examples/requests.ini
Normal file
6
flake8_to_ruff/examples/requests.ini
Normal file
@@ -0,0 +1,6 @@
|
||||
[flake8]
|
||||
ignore = E203, E501, W503
|
||||
per-file-ignores =
|
||||
requests/__init__.py:E402, F401
|
||||
requests/compat.py:E402, F401
|
||||
tests/compat.py:F401
|
||||
@@ -1,21 +1,74 @@
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{BTreeSet, HashMap};
|
||||
|
||||
use anyhow::Result;
|
||||
use ruff::checks_gen::CheckCodePrefix;
|
||||
use ruff::flake8_quotes::settings::Quote;
|
||||
use ruff::settings::options::Options;
|
||||
use ruff::settings::pyproject::Pyproject;
|
||||
use ruff::{flake8_quotes, pep8_naming};
|
||||
use ruff::{flake8_annotations, flake8_quotes, pep8_naming};
|
||||
|
||||
use crate::parser;
|
||||
use crate::plugin::Plugin;
|
||||
use crate::{parser, plugin};
|
||||
|
||||
pub fn convert(config: HashMap<String, HashMap<String, Option<String>>>) -> Result<Pyproject> {
|
||||
// Extract the Flake8 section.
|
||||
let flake8 = config
|
||||
.get("flake8")
|
||||
.expect("Unable to find flake8 section in INI file.");
|
||||
pub fn convert(
|
||||
flake8: &HashMap<String, Option<String>>,
|
||||
plugins: Option<Vec<Plugin>>,
|
||||
) -> Result<Pyproject> {
|
||||
// Extract all referenced check code prefixes, to power plugin inference.
|
||||
let mut referenced_codes: BTreeSet<CheckCodePrefix> = Default::default();
|
||||
for (key, value) in flake8 {
|
||||
if let Some(value) = value {
|
||||
match key.as_str() {
|
||||
"select" | "ignore" | "extend-select" | "extend_select" | "extend-ignore"
|
||||
| "extend_ignore" => {
|
||||
referenced_codes.extend(parser::parse_prefix_codes(value.as_ref()));
|
||||
}
|
||||
"per-file-ignores" | "per_file_ignores" => {
|
||||
if let Ok(per_file_ignores) =
|
||||
parser::parse_files_to_codes_mapping(value.as_ref())
|
||||
{
|
||||
for (_, codes) in parser::collect_per_file_ignores(per_file_ignores) {
|
||||
referenced_codes.extend(codes);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the user has specified a `select`. If not, we'll add our own
|
||||
// default `select`, and populate it based on user plugins.
|
||||
let mut select = flake8
|
||||
.get("select")
|
||||
.and_then(|value| {
|
||||
value
|
||||
.as_ref()
|
||||
.map(|value| BTreeSet::from_iter(parser::parse_prefix_codes(value)))
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
plugin::resolve_select(
|
||||
flake8,
|
||||
&plugins.unwrap_or_else(|| {
|
||||
plugin::infer_plugins_from_options(flake8)
|
||||
.into_iter()
|
||||
.chain(plugin::infer_plugins_from_codes(&referenced_codes))
|
||||
.collect()
|
||||
}),
|
||||
)
|
||||
});
|
||||
let mut ignore = flake8
|
||||
.get("ignore")
|
||||
.and_then(|value| {
|
||||
value
|
||||
.as_ref()
|
||||
.map(|value| BTreeSet::from_iter(parser::parse_prefix_codes(value)))
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
// Parse each supported option.
|
||||
let mut options: Options = Default::default();
|
||||
let mut flake8_annotations: flake8_annotations::settings::Options = Default::default();
|
||||
let mut flake8_quotes: flake8_quotes::settings::Options = Default::default();
|
||||
let mut pep8_naming: pep8_naming::settings::Options = Default::default();
|
||||
for (key, value) in flake8 {
|
||||
@@ -27,16 +80,19 @@ pub fn convert(config: HashMap<String, HashMap<String, Option<String>>>) -> Resu
|
||||
Err(e) => eprintln!("Unable to parse '{key}' property: {e}"),
|
||||
},
|
||||
"select" => {
|
||||
options.select = Some(parser::parse_prefix_codes(value.as_ref()));
|
||||
}
|
||||
"extend-select" | "extend_select" => {
|
||||
options.extend_select = Some(parser::parse_prefix_codes(value.as_ref()));
|
||||
// No-op (handled above).
|
||||
select.extend(parser::parse_prefix_codes(value.as_ref()));
|
||||
}
|
||||
"ignore" => {
|
||||
options.ignore = Some(parser::parse_prefix_codes(value.as_ref()));
|
||||
// No-op (handled above).
|
||||
}
|
||||
"extend-select" | "extend_select" => {
|
||||
// Unlike Flake8, use a single explicit `select`.
|
||||
select.extend(parser::parse_prefix_codes(value.as_ref()));
|
||||
}
|
||||
"extend-ignore" | "extend_ignore" => {
|
||||
options.extend_ignore = Some(parser::parse_prefix_codes(value.as_ref()));
|
||||
// Unlike Flake8, use a single explicit `ignore`.
|
||||
ignore.extend(parser::parse_prefix_codes(value.as_ref()));
|
||||
}
|
||||
"exclude" => {
|
||||
options.exclude = Some(parser::parse_strings(value.as_ref()));
|
||||
@@ -53,6 +109,31 @@ pub fn convert(config: HashMap<String, HashMap<String, Option<String>>>) -> Resu
|
||||
Err(e) => eprintln!("Unable to parse '{key}' property: {e}"),
|
||||
}
|
||||
}
|
||||
// flake8-annotations
|
||||
"suppress-none-returning" | "suppress_none_returning" => {
|
||||
match parser::parse_bool(value.as_ref()) {
|
||||
Ok(bool) => flake8_annotations.suppress_none_returning = Some(bool),
|
||||
Err(e) => eprintln!("Unable to parse '{key}' property: {e}"),
|
||||
}
|
||||
}
|
||||
"suppress-dummy-args" | "suppress_dummy_args" => {
|
||||
match parser::parse_bool(value.as_ref()) {
|
||||
Ok(bool) => flake8_annotations.suppress_dummy_args = Some(bool),
|
||||
Err(e) => eprintln!("Unable to parse '{key}' property: {e}"),
|
||||
}
|
||||
}
|
||||
"mypy-init-return" | "mypy_init_return" => {
|
||||
match parser::parse_bool(value.as_ref()) {
|
||||
Ok(bool) => flake8_annotations.mypy_init_return = Some(bool),
|
||||
Err(e) => eprintln!("Unable to parse '{key}' property: {e}"),
|
||||
}
|
||||
}
|
||||
"allow-star-arg-any" | "allow_star_arg_any" => {
|
||||
match parser::parse_bool(value.as_ref()) {
|
||||
Ok(bool) => flake8_annotations.allow_star_arg_any = Some(bool),
|
||||
Err(e) => eprintln!("Unable to parse '{key}' property: {e}"),
|
||||
}
|
||||
}
|
||||
// flake8-quotes
|
||||
"quotes" | "inline-quotes" | "inline_quotes" => match value.trim() {
|
||||
"'" | "single" => flake8_quotes.inline_quotes = Some(Quote::Single),
|
||||
@@ -69,10 +150,9 @@ pub fn convert(config: HashMap<String, HashMap<String, Option<String>>>) -> Resu
|
||||
"\"" | "double" => flake8_quotes.docstring_quotes = Some(Quote::Single),
|
||||
_ => eprintln!("Unexpected '{key}' value: {value}"),
|
||||
},
|
||||
"avoid-escape" | "avoid_escape" => match value.trim() {
|
||||
"true" => flake8_quotes.avoid_escape = Some(true),
|
||||
"false" => flake8_quotes.avoid_escape = Some(false),
|
||||
_ => eprintln!("Unexpected '{key}' value: {value}"),
|
||||
"avoid-escape" | "avoid_escape" => match parser::parse_bool(value.as_ref()) {
|
||||
Ok(bool) => flake8_quotes.avoid_escape = Some(bool),
|
||||
Err(e) => eprintln!("Unable to parse '{key}' property: {e}"),
|
||||
},
|
||||
// pep8-naming
|
||||
"ignore-names" | "ignore_names" => {
|
||||
@@ -86,12 +166,19 @@ pub fn convert(config: HashMap<String, HashMap<String, Option<String>>>) -> Resu
|
||||
pep8_naming.staticmethod_decorators =
|
||||
Some(parser::parse_strings(value.as_ref()));
|
||||
}
|
||||
// flake8-docstrings
|
||||
"docstring-convention" => {
|
||||
// No-op (handled above).
|
||||
}
|
||||
// Unknown
|
||||
_ => eprintln!("Skipping unsupported property: {key}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Deduplicate and sort.
|
||||
options.select = Some(Vec::from_iter(select));
|
||||
options.ignore = Some(Vec::from_iter(ignore));
|
||||
if flake8_quotes != Default::default() {
|
||||
options.flake8_quotes = Some(flake8_quotes);
|
||||
}
|
||||
@@ -108,27 +195,37 @@ mod tests {
|
||||
use std::collections::HashMap;
|
||||
|
||||
use anyhow::Result;
|
||||
use ruff::checks_gen::CheckCodePrefix;
|
||||
use ruff::flake8_quotes;
|
||||
use ruff::settings::options::Options;
|
||||
use ruff::settings::pyproject::Pyproject;
|
||||
|
||||
use crate::converter::convert;
|
||||
use crate::plugin::Plugin;
|
||||
|
||||
#[test]
|
||||
fn it_converts_empty() -> Result<()> {
|
||||
let actual = convert(HashMap::from([("flake8".to_string(), HashMap::from([]))]))?;
|
||||
let actual = convert(&HashMap::from([]), None)?;
|
||||
let expected = Pyproject::new(Options {
|
||||
line_length: None,
|
||||
src: None,
|
||||
fix: None,
|
||||
exclude: None,
|
||||
extend_exclude: None,
|
||||
select: None,
|
||||
select: Some(vec![
|
||||
CheckCodePrefix::E,
|
||||
CheckCodePrefix::F,
|
||||
CheckCodePrefix::W,
|
||||
]),
|
||||
extend_select: None,
|
||||
ignore: None,
|
||||
ignore: Some(vec![]),
|
||||
extend_ignore: None,
|
||||
per_file_ignores: None,
|
||||
dummy_variable_rgx: None,
|
||||
target_version: None,
|
||||
flake8_annotations: None,
|
||||
flake8_quotes: None,
|
||||
isort: None,
|
||||
pep8_naming: None,
|
||||
});
|
||||
assert_eq!(actual, expected);
|
||||
@@ -138,22 +235,30 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn it_converts_dashes() -> Result<()> {
|
||||
let actual = convert(HashMap::from([(
|
||||
"flake8".to_string(),
|
||||
HashMap::from([("max-line-length".to_string(), Some("100".to_string()))]),
|
||||
)]))?;
|
||||
let actual = convert(
|
||||
&HashMap::from([("max-line-length".to_string(), Some("100".to_string()))]),
|
||||
Some(vec![]),
|
||||
)?;
|
||||
let expected = Pyproject::new(Options {
|
||||
line_length: Some(100),
|
||||
src: None,
|
||||
fix: None,
|
||||
exclude: None,
|
||||
extend_exclude: None,
|
||||
select: None,
|
||||
select: Some(vec![
|
||||
CheckCodePrefix::E,
|
||||
CheckCodePrefix::F,
|
||||
CheckCodePrefix::W,
|
||||
]),
|
||||
extend_select: None,
|
||||
ignore: None,
|
||||
ignore: Some(vec![]),
|
||||
extend_ignore: None,
|
||||
per_file_ignores: None,
|
||||
dummy_variable_rgx: None,
|
||||
target_version: None,
|
||||
flake8_annotations: None,
|
||||
flake8_quotes: None,
|
||||
isort: None,
|
||||
pep8_naming: None,
|
||||
});
|
||||
assert_eq!(actual, expected);
|
||||
@@ -163,22 +268,30 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn it_converts_underscores() -> Result<()> {
|
||||
let actual = convert(HashMap::from([(
|
||||
"flake8".to_string(),
|
||||
HashMap::from([("max_line_length".to_string(), Some("100".to_string()))]),
|
||||
)]))?;
|
||||
let actual = convert(
|
||||
&HashMap::from([("max_line_length".to_string(), Some("100".to_string()))]),
|
||||
Some(vec![]),
|
||||
)?;
|
||||
let expected = Pyproject::new(Options {
|
||||
line_length: Some(100),
|
||||
src: None,
|
||||
fix: None,
|
||||
exclude: None,
|
||||
extend_exclude: None,
|
||||
select: None,
|
||||
select: Some(vec![
|
||||
CheckCodePrefix::E,
|
||||
CheckCodePrefix::F,
|
||||
CheckCodePrefix::W,
|
||||
]),
|
||||
extend_select: None,
|
||||
ignore: None,
|
||||
ignore: Some(vec![]),
|
||||
extend_ignore: None,
|
||||
per_file_ignores: None,
|
||||
dummy_variable_rgx: None,
|
||||
target_version: None,
|
||||
flake8_annotations: None,
|
||||
flake8_quotes: None,
|
||||
isort: None,
|
||||
pep8_naming: None,
|
||||
});
|
||||
assert_eq!(actual, expected);
|
||||
@@ -188,22 +301,30 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn it_ignores_parse_errors() -> Result<()> {
|
||||
let actual = convert(HashMap::from([(
|
||||
"flake8".to_string(),
|
||||
HashMap::from([("max_line_length".to_string(), Some("abc".to_string()))]),
|
||||
)]))?;
|
||||
let actual = convert(
|
||||
&HashMap::from([("max_line_length".to_string(), Some("abc".to_string()))]),
|
||||
Some(vec![]),
|
||||
)?;
|
||||
let expected = Pyproject::new(Options {
|
||||
line_length: None,
|
||||
src: None,
|
||||
fix: None,
|
||||
exclude: None,
|
||||
extend_exclude: None,
|
||||
select: None,
|
||||
select: Some(vec![
|
||||
CheckCodePrefix::E,
|
||||
CheckCodePrefix::F,
|
||||
CheckCodePrefix::W,
|
||||
]),
|
||||
extend_select: None,
|
||||
ignore: None,
|
||||
ignore: Some(vec![]),
|
||||
extend_ignore: None,
|
||||
per_file_ignores: None,
|
||||
dummy_variable_rgx: None,
|
||||
target_version: None,
|
||||
flake8_annotations: None,
|
||||
flake8_quotes: None,
|
||||
isort: None,
|
||||
pep8_naming: None,
|
||||
});
|
||||
assert_eq!(actual, expected);
|
||||
@@ -212,28 +333,146 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_converts_extensions() -> Result<()> {
|
||||
let actual = convert(HashMap::from([(
|
||||
"flake8".to_string(),
|
||||
HashMap::from([("inline-quotes".to_string(), Some("single".to_string()))]),
|
||||
)]))?;
|
||||
fn it_converts_plugin_options() -> Result<()> {
|
||||
let actual = convert(
|
||||
&HashMap::from([("inline-quotes".to_string(), Some("single".to_string()))]),
|
||||
Some(vec![]),
|
||||
)?;
|
||||
let expected = Pyproject::new(Options {
|
||||
line_length: None,
|
||||
src: None,
|
||||
fix: None,
|
||||
exclude: None,
|
||||
extend_exclude: None,
|
||||
select: None,
|
||||
select: Some(vec![
|
||||
CheckCodePrefix::E,
|
||||
CheckCodePrefix::F,
|
||||
CheckCodePrefix::W,
|
||||
]),
|
||||
extend_select: None,
|
||||
ignore: None,
|
||||
ignore: Some(vec![]),
|
||||
extend_ignore: None,
|
||||
per_file_ignores: None,
|
||||
dummy_variable_rgx: None,
|
||||
target_version: None,
|
||||
flake8_annotations: None,
|
||||
flake8_quotes: Some(flake8_quotes::settings::Options {
|
||||
inline_quotes: Some(flake8_quotes::settings::Quote::Single),
|
||||
multiline_quotes: None,
|
||||
docstring_quotes: None,
|
||||
avoid_escape: None,
|
||||
}),
|
||||
isort: None,
|
||||
pep8_naming: None,
|
||||
});
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_converts_docstring_conventions() -> Result<()> {
|
||||
let actual = convert(
|
||||
&HashMap::from([(
|
||||
"docstring-convention".to_string(),
|
||||
Some("numpy".to_string()),
|
||||
)]),
|
||||
Some(vec![Plugin::Flake8Docstrings]),
|
||||
)?;
|
||||
let expected = Pyproject::new(Options {
|
||||
line_length: None,
|
||||
src: None,
|
||||
fix: None,
|
||||
exclude: None,
|
||||
extend_exclude: None,
|
||||
select: Some(vec![
|
||||
CheckCodePrefix::D100,
|
||||
CheckCodePrefix::D101,
|
||||
CheckCodePrefix::D102,
|
||||
CheckCodePrefix::D103,
|
||||
CheckCodePrefix::D104,
|
||||
CheckCodePrefix::D105,
|
||||
CheckCodePrefix::D106,
|
||||
CheckCodePrefix::D200,
|
||||
CheckCodePrefix::D201,
|
||||
CheckCodePrefix::D202,
|
||||
CheckCodePrefix::D204,
|
||||
CheckCodePrefix::D205,
|
||||
CheckCodePrefix::D206,
|
||||
CheckCodePrefix::D207,
|
||||
CheckCodePrefix::D208,
|
||||
CheckCodePrefix::D209,
|
||||
CheckCodePrefix::D210,
|
||||
CheckCodePrefix::D211,
|
||||
CheckCodePrefix::D214,
|
||||
CheckCodePrefix::D215,
|
||||
CheckCodePrefix::D300,
|
||||
CheckCodePrefix::D400,
|
||||
CheckCodePrefix::D403,
|
||||
CheckCodePrefix::D404,
|
||||
CheckCodePrefix::D405,
|
||||
CheckCodePrefix::D406,
|
||||
CheckCodePrefix::D407,
|
||||
CheckCodePrefix::D408,
|
||||
CheckCodePrefix::D409,
|
||||
CheckCodePrefix::D410,
|
||||
CheckCodePrefix::D411,
|
||||
CheckCodePrefix::D412,
|
||||
CheckCodePrefix::D414,
|
||||
CheckCodePrefix::D418,
|
||||
CheckCodePrefix::D419,
|
||||
CheckCodePrefix::E,
|
||||
CheckCodePrefix::F,
|
||||
CheckCodePrefix::W,
|
||||
]),
|
||||
extend_select: None,
|
||||
ignore: Some(vec![]),
|
||||
extend_ignore: None,
|
||||
per_file_ignores: None,
|
||||
dummy_variable_rgx: None,
|
||||
target_version: None,
|
||||
flake8_annotations: None,
|
||||
flake8_quotes: None,
|
||||
isort: None,
|
||||
pep8_naming: None,
|
||||
});
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_infers_plugins_if_omitted() -> Result<()> {
|
||||
let actual = convert(
|
||||
&HashMap::from([("inline-quotes".to_string(), Some("single".to_string()))]),
|
||||
None,
|
||||
)?;
|
||||
let expected = Pyproject::new(Options {
|
||||
line_length: None,
|
||||
src: None,
|
||||
fix: None,
|
||||
exclude: None,
|
||||
extend_exclude: None,
|
||||
select: Some(vec![
|
||||
CheckCodePrefix::E,
|
||||
CheckCodePrefix::F,
|
||||
CheckCodePrefix::Q,
|
||||
CheckCodePrefix::W,
|
||||
]),
|
||||
extend_select: None,
|
||||
ignore: Some(vec![]),
|
||||
extend_ignore: None,
|
||||
per_file_ignores: None,
|
||||
dummy_variable_rgx: None,
|
||||
target_version: None,
|
||||
flake8_annotations: None,
|
||||
flake8_quotes: Some(flake8_quotes::settings::Options {
|
||||
inline_quotes: Some(flake8_quotes::settings::Quote::Single),
|
||||
multiline_quotes: None,
|
||||
docstring_quotes: None,
|
||||
avoid_escape: None,
|
||||
}),
|
||||
isort: None,
|
||||
pep8_naming: None,
|
||||
});
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
@@ -2,3 +2,4 @@
|
||||
|
||||
pub mod converter;
|
||||
mod parser;
|
||||
pub mod plugin;
|
||||
|
||||
@@ -6,6 +6,7 @@ use anyhow::Result;
|
||||
use clap::Parser;
|
||||
use configparser::ini::Ini;
|
||||
use flake8_to_ruff::converter;
|
||||
use flake8_to_ruff::plugin::Plugin;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(
|
||||
@@ -17,6 +18,9 @@ struct Cli {
|
||||
/// '.flake8').
|
||||
#[arg(required = true)]
|
||||
file: PathBuf,
|
||||
/// List of plugins to enable.
|
||||
#[arg(long, value_delimiter = ',')]
|
||||
plugin: Option<Vec<Plugin>>,
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
@@ -27,8 +31,13 @@ fn main() -> Result<()> {
|
||||
ini.set_multiline(true);
|
||||
let config = ini.load(cli.file).map_err(|msg| anyhow::anyhow!(msg))?;
|
||||
|
||||
// Extract the Flake8 section.
|
||||
let flake8 = config
|
||||
.get("flake8")
|
||||
.expect("Unable to find flake8 section in INI file.");
|
||||
|
||||
// Create the pyproject.toml.
|
||||
let pyproject = converter::convert(config)?;
|
||||
let pyproject = converter::convert(flake8, cli.plugin)?;
|
||||
println!("{}", toml::to_string_pretty(&pyproject)?);
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -37,6 +37,15 @@ pub fn parse_strings(value: &str) -> Vec<String> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Parse a boolean.
|
||||
pub fn parse_bool(value: &str) -> Result<bool> {
|
||||
match value.trim() {
|
||||
"true" => Ok(true),
|
||||
"false" => Ok(false),
|
||||
_ => Err(anyhow::anyhow!("Unexpected boolean value: {value}")),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Token {
|
||||
token_name: TokenType,
|
||||
|
||||
396
flake8_to_ruff/src/plugin.rs
Normal file
396
flake8_to_ruff/src/plugin.rs
Normal file
@@ -0,0 +1,396 @@
|
||||
use std::collections::{BTreeSet, HashMap};
|
||||
use std::str::FromStr;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use ruff::checks_gen::CheckCodePrefix;
|
||||
|
||||
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
|
||||
pub enum Plugin {
|
||||
Flake8Bugbear,
|
||||
Flake8Builtins,
|
||||
Flake8Comprehensions,
|
||||
Flake8Docstrings,
|
||||
Flake8Print,
|
||||
Flake8Quotes,
|
||||
Flake8Annotations,
|
||||
PEP8Naming,
|
||||
Pyupgrade,
|
||||
}
|
||||
|
||||
impl FromStr for Plugin {
|
||||
type Err = anyhow::Error;
|
||||
|
||||
fn from_str(string: &str) -> Result<Self, Self::Err> {
|
||||
match string {
|
||||
"flake8-bugbear" => Ok(Plugin::Flake8Bugbear),
|
||||
"flake8-builtins" => Ok(Plugin::Flake8Builtins),
|
||||
"flake8-comprehensions" => Ok(Plugin::Flake8Comprehensions),
|
||||
"flake8-docstrings" => Ok(Plugin::Flake8Docstrings),
|
||||
"flake8-print" => Ok(Plugin::Flake8Print),
|
||||
"flake8-quotes" => Ok(Plugin::Flake8Quotes),
|
||||
"flake8-annotations" => Ok(Plugin::Flake8Annotations),
|
||||
"pep8-naming" => Ok(Plugin::PEP8Naming),
|
||||
"pyupgrade" => Ok(Plugin::Pyupgrade),
|
||||
_ => Err(anyhow!("Unknown plugin: {}", string)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Plugin {
|
||||
pub fn default(&self) -> CheckCodePrefix {
|
||||
match self {
|
||||
Plugin::Flake8Bugbear => CheckCodePrefix::B,
|
||||
Plugin::Flake8Builtins => CheckCodePrefix::A,
|
||||
Plugin::Flake8Comprehensions => CheckCodePrefix::C,
|
||||
Plugin::Flake8Docstrings => CheckCodePrefix::D,
|
||||
Plugin::Flake8Print => CheckCodePrefix::T,
|
||||
Plugin::Flake8Quotes => CheckCodePrefix::Q,
|
||||
Plugin::Flake8Annotations => CheckCodePrefix::ANN,
|
||||
Plugin::PEP8Naming => CheckCodePrefix::N,
|
||||
Plugin::Pyupgrade => CheckCodePrefix::U,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn select(&self, flake8: &HashMap<String, Option<String>>) -> Vec<CheckCodePrefix> {
|
||||
match self {
|
||||
Plugin::Flake8Bugbear => vec![CheckCodePrefix::B],
|
||||
Plugin::Flake8Builtins => vec![CheckCodePrefix::A],
|
||||
Plugin::Flake8Comprehensions => vec![CheckCodePrefix::C],
|
||||
Plugin::Flake8Docstrings => {
|
||||
// Use the user-provided docstring.
|
||||
for key in ["docstring-convention", "docstring_convention"] {
|
||||
if let Some(Some(value)) = flake8.get(key) {
|
||||
match DocstringConvention::from_str(value) {
|
||||
Ok(convention) => return convention.select(),
|
||||
Err(e) => {
|
||||
eprintln!("Unexpected '{key}' value: {value} ({e}");
|
||||
return vec![];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Default to PEP8.
|
||||
DocstringConvention::PEP8.select()
|
||||
}
|
||||
Plugin::Flake8Print => vec![CheckCodePrefix::T],
|
||||
Plugin::Flake8Quotes => vec![CheckCodePrefix::Q],
|
||||
Plugin::Flake8Annotations => vec![CheckCodePrefix::ANN],
|
||||
Plugin::PEP8Naming => vec![CheckCodePrefix::N],
|
||||
Plugin::Pyupgrade => vec![CheckCodePrefix::U],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum DocstringConvention {
|
||||
All,
|
||||
PEP8,
|
||||
NumPy,
|
||||
Google,
|
||||
}
|
||||
|
||||
impl FromStr for DocstringConvention {
|
||||
type Err = anyhow::Error;
|
||||
|
||||
fn from_str(string: &str) -> Result<Self, Self::Err> {
|
||||
match string {
|
||||
"all" => Ok(DocstringConvention::All),
|
||||
"pep8" => Ok(DocstringConvention::PEP8),
|
||||
"numpy" => Ok(DocstringConvention::NumPy),
|
||||
"google" => Ok(DocstringConvention::Google),
|
||||
_ => Err(anyhow!("Unknown docstring convention: {}", string)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DocstringConvention {
|
||||
fn select(&self) -> Vec<CheckCodePrefix> {
|
||||
match self {
|
||||
DocstringConvention::All => vec![CheckCodePrefix::D],
|
||||
DocstringConvention::PEP8 => vec![
|
||||
// All errors except D203, D212, D213, D214, D215, D404, D405, D406, D407, D408,
|
||||
// D409, D410, D411, D413, D415, D416 and D417.
|
||||
CheckCodePrefix::D100,
|
||||
CheckCodePrefix::D101,
|
||||
CheckCodePrefix::D102,
|
||||
CheckCodePrefix::D103,
|
||||
CheckCodePrefix::D104,
|
||||
CheckCodePrefix::D105,
|
||||
CheckCodePrefix::D106,
|
||||
CheckCodePrefix::D107,
|
||||
CheckCodePrefix::D200,
|
||||
CheckCodePrefix::D201,
|
||||
CheckCodePrefix::D202,
|
||||
// CheckCodePrefix::D203,
|
||||
CheckCodePrefix::D204,
|
||||
CheckCodePrefix::D205,
|
||||
CheckCodePrefix::D206,
|
||||
CheckCodePrefix::D207,
|
||||
CheckCodePrefix::D208,
|
||||
CheckCodePrefix::D209,
|
||||
CheckCodePrefix::D210,
|
||||
CheckCodePrefix::D211,
|
||||
// CheckCodePrefix::D212,
|
||||
// CheckCodePrefix::D213,
|
||||
// CheckCodePrefix::D214,
|
||||
// CheckCodePrefix::D215,
|
||||
CheckCodePrefix::D300,
|
||||
CheckCodePrefix::D400,
|
||||
CheckCodePrefix::D402,
|
||||
CheckCodePrefix::D403,
|
||||
// CheckCodePrefix::D404,
|
||||
// CheckCodePrefix::D405,
|
||||
// CheckCodePrefix::D406,
|
||||
// CheckCodePrefix::D407,
|
||||
// CheckCodePrefix::D408,
|
||||
// CheckCodePrefix::D409,
|
||||
// CheckCodePrefix::D410,
|
||||
// CheckCodePrefix::D411,
|
||||
CheckCodePrefix::D412,
|
||||
// CheckCodePrefix::D413,
|
||||
CheckCodePrefix::D414,
|
||||
// CheckCodePrefix::D415,
|
||||
// CheckCodePrefix::D416,
|
||||
// CheckCodePrefix::D417,
|
||||
CheckCodePrefix::D418,
|
||||
CheckCodePrefix::D419,
|
||||
],
|
||||
DocstringConvention::NumPy => vec![
|
||||
// All errors except D107, D203, D212, D213, D402, D413, D415, D416, and D417.
|
||||
CheckCodePrefix::D100,
|
||||
CheckCodePrefix::D101,
|
||||
CheckCodePrefix::D102,
|
||||
CheckCodePrefix::D103,
|
||||
CheckCodePrefix::D104,
|
||||
CheckCodePrefix::D105,
|
||||
CheckCodePrefix::D106,
|
||||
// CheckCodePrefix::D107,
|
||||
CheckCodePrefix::D200,
|
||||
CheckCodePrefix::D201,
|
||||
CheckCodePrefix::D202,
|
||||
// CheckCodePrefix::D203,
|
||||
CheckCodePrefix::D204,
|
||||
CheckCodePrefix::D205,
|
||||
CheckCodePrefix::D206,
|
||||
CheckCodePrefix::D207,
|
||||
CheckCodePrefix::D208,
|
||||
CheckCodePrefix::D209,
|
||||
CheckCodePrefix::D210,
|
||||
CheckCodePrefix::D211,
|
||||
// CheckCodePrefix::D212,
|
||||
// CheckCodePrefix::D213,
|
||||
CheckCodePrefix::D214,
|
||||
CheckCodePrefix::D215,
|
||||
CheckCodePrefix::D300,
|
||||
CheckCodePrefix::D400,
|
||||
// CheckCodePrefix::D402,
|
||||
CheckCodePrefix::D403,
|
||||
CheckCodePrefix::D404,
|
||||
CheckCodePrefix::D405,
|
||||
CheckCodePrefix::D406,
|
||||
CheckCodePrefix::D407,
|
||||
CheckCodePrefix::D408,
|
||||
CheckCodePrefix::D409,
|
||||
CheckCodePrefix::D410,
|
||||
CheckCodePrefix::D411,
|
||||
CheckCodePrefix::D412,
|
||||
// CheckCodePrefix::D413,
|
||||
CheckCodePrefix::D414,
|
||||
// CheckCodePrefix::D415,
|
||||
// CheckCodePrefix::D416,
|
||||
// CheckCodePrefix::D417,
|
||||
CheckCodePrefix::D418,
|
||||
CheckCodePrefix::D419,
|
||||
],
|
||||
DocstringConvention::Google => vec![
|
||||
// All errors except D203, D204, D213, D215, D400, D401, D404, D406, D407, D408,
|
||||
// D409 and D413.
|
||||
CheckCodePrefix::D100,
|
||||
CheckCodePrefix::D101,
|
||||
CheckCodePrefix::D102,
|
||||
CheckCodePrefix::D103,
|
||||
CheckCodePrefix::D104,
|
||||
CheckCodePrefix::D105,
|
||||
CheckCodePrefix::D106,
|
||||
CheckCodePrefix::D107,
|
||||
CheckCodePrefix::D200,
|
||||
CheckCodePrefix::D201,
|
||||
CheckCodePrefix::D202,
|
||||
// CheckCodePrefix::D203,
|
||||
// CheckCodePrefix::D204,
|
||||
CheckCodePrefix::D205,
|
||||
CheckCodePrefix::D206,
|
||||
CheckCodePrefix::D207,
|
||||
CheckCodePrefix::D208,
|
||||
CheckCodePrefix::D209,
|
||||
CheckCodePrefix::D210,
|
||||
CheckCodePrefix::D211,
|
||||
CheckCodePrefix::D212,
|
||||
// CheckCodePrefix::D213,
|
||||
CheckCodePrefix::D214,
|
||||
// CheckCodePrefix::D215,
|
||||
CheckCodePrefix::D300,
|
||||
// CheckCodePrefix::D400,
|
||||
CheckCodePrefix::D402,
|
||||
CheckCodePrefix::D403,
|
||||
// CheckCodePrefix::D404,
|
||||
CheckCodePrefix::D405,
|
||||
// CheckCodePrefix::D406,
|
||||
// CheckCodePrefix::D407,
|
||||
// CheckCodePrefix::D408,
|
||||
// CheckCodePrefix::D409,
|
||||
CheckCodePrefix::D410,
|
||||
CheckCodePrefix::D411,
|
||||
CheckCodePrefix::D412,
|
||||
// CheckCodePrefix::D413,
|
||||
CheckCodePrefix::D414,
|
||||
CheckCodePrefix::D415,
|
||||
CheckCodePrefix::D416,
|
||||
CheckCodePrefix::D417,
|
||||
CheckCodePrefix::D418,
|
||||
CheckCodePrefix::D419,
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Infer the enabled plugins based on user-provided options.
|
||||
///
|
||||
/// For example, if the user specified a `mypy-init-return` setting, we should
|
||||
/// infer that `flake8-annotations` is active.
|
||||
pub fn infer_plugins_from_options(flake8: &HashMap<String, Option<String>>) -> Vec<Plugin> {
|
||||
let mut plugins = BTreeSet::new();
|
||||
for key in flake8.keys() {
|
||||
match key.as_str() {
|
||||
// flake8-docstrings
|
||||
"docstring-convention" | "docstring_convention" => {
|
||||
plugins.insert(Plugin::Flake8Docstrings);
|
||||
}
|
||||
// flake8-builtins
|
||||
"builtins-ignorelist" | "builtins_ignorelist" => {
|
||||
plugins.insert(Plugin::Flake8Builtins);
|
||||
}
|
||||
// flake8-quotes
|
||||
"quotes" | "inline-quotes" | "inline_quotes" => {
|
||||
plugins.insert(Plugin::Flake8Quotes);
|
||||
}
|
||||
"multiline-quotes" | "multiline_quotes" => {
|
||||
plugins.insert(Plugin::Flake8Quotes);
|
||||
}
|
||||
"docstring-quotes" | "docstring_quotes" => {
|
||||
plugins.insert(Plugin::Flake8Quotes);
|
||||
}
|
||||
"avoid-escape" | "avoid_escape" => {
|
||||
plugins.insert(Plugin::Flake8Quotes);
|
||||
}
|
||||
// flake8-annotations
|
||||
"suppress-none-returning" | "suppress_none_returning" => {
|
||||
plugins.insert(Plugin::Flake8Annotations);
|
||||
}
|
||||
"suppress-dummy-args" | "suppress_dummy_args" => {
|
||||
plugins.insert(Plugin::Flake8Annotations);
|
||||
}
|
||||
"allow-untyped-defs" | "allow_untyped_defs" => {
|
||||
plugins.insert(Plugin::Flake8Annotations);
|
||||
}
|
||||
"allow-untyped-nested" | "allow_untyped_nested" => {
|
||||
plugins.insert(Plugin::Flake8Annotations);
|
||||
}
|
||||
"mypy-init-return" | "mypy_init_return" => {
|
||||
plugins.insert(Plugin::Flake8Annotations);
|
||||
}
|
||||
"dispatch-decorators" | "dispatch_decorators" => {
|
||||
plugins.insert(Plugin::Flake8Annotations);
|
||||
}
|
||||
"overload-decorators" | "overload_decorators" => {
|
||||
plugins.insert(Plugin::Flake8Annotations);
|
||||
}
|
||||
"allow-star-arg-any" | "allow_star_arg_any" => {
|
||||
plugins.insert(Plugin::Flake8Annotations);
|
||||
}
|
||||
// pep8-naming
|
||||
"ignore-names" | "ignore_names" => {
|
||||
plugins.insert(Plugin::PEP8Naming);
|
||||
}
|
||||
"classmethod-decorators" | "classmethod_decorators" => {
|
||||
plugins.insert(Plugin::PEP8Naming);
|
||||
}
|
||||
"staticmethod-decorators" | "staticmethod_decorators" => {
|
||||
plugins.insert(Plugin::PEP8Naming);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Vec::from_iter(plugins)
|
||||
}
|
||||
|
||||
/// Infer the enabled plugins based on the referenced prefixes.
|
||||
///
|
||||
/// For example, if the user ignores `ANN101`, we should infer that
|
||||
/// `flake8-annotations` is active.
|
||||
pub fn infer_plugins_from_codes(codes: &BTreeSet<CheckCodePrefix>) -> Vec<Plugin> {
|
||||
[
|
||||
Plugin::Flake8Bugbear,
|
||||
Plugin::Flake8Builtins,
|
||||
Plugin::Flake8Comprehensions,
|
||||
Plugin::Flake8Docstrings,
|
||||
Plugin::Flake8Print,
|
||||
Plugin::Flake8Quotes,
|
||||
Plugin::Flake8Annotations,
|
||||
Plugin::PEP8Naming,
|
||||
Plugin::Pyupgrade,
|
||||
]
|
||||
.into_iter()
|
||||
.filter(|plugin| {
|
||||
for prefix in codes {
|
||||
if prefix
|
||||
.codes()
|
||||
.iter()
|
||||
.any(|code| plugin.default().codes().contains(code))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Resolve the set of enabled `CheckCodePrefix` values for the given plugins.
|
||||
pub fn resolve_select(
|
||||
flake8: &HashMap<String, Option<String>>,
|
||||
plugins: &[Plugin],
|
||||
) -> BTreeSet<CheckCodePrefix> {
|
||||
// Include default Pyflakes and pycodestyle checks.
|
||||
let mut select = BTreeSet::from([CheckCodePrefix::E, CheckCodePrefix::F, CheckCodePrefix::W]);
|
||||
|
||||
// Add prefix codes for every plugin.
|
||||
for plugin in plugins {
|
||||
select.extend(plugin.select(flake8));
|
||||
}
|
||||
|
||||
select
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::plugin::{infer_plugins_from_options, Plugin};
|
||||
|
||||
#[test]
|
||||
fn it_infers_plugins() {
|
||||
let actual = infer_plugins_from_options(&HashMap::from([(
|
||||
"inline-quotes".to_string(),
|
||||
Some("single".to_string()),
|
||||
)]));
|
||||
let expected = vec![Plugin::Flake8Quotes];
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
let actual = infer_plugins_from_options(&HashMap::from([(
|
||||
"staticmethod-decorators".to_string(),
|
||||
Some("[]".to_string()),
|
||||
)]));
|
||||
let expected = vec![Plugin::PEP8Naming];
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
}
|
||||
@@ -32,3 +32,7 @@ build-backend = "maturin"
|
||||
bindings = "bin"
|
||||
sdist-include = ["Cargo.lock"]
|
||||
strip = true
|
||||
|
||||
[tool.isort]
|
||||
profile = "black"
|
||||
known_third_party = ["fastapi", "pydantic", "starlette"]
|
||||
|
||||
18
resources/test/fixtures/B003.py
vendored
Normal file
18
resources/test/fixtures/B003.py
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
"""
|
||||
Should emit:
|
||||
B003 - on line 9
|
||||
"""
|
||||
|
||||
import os
|
||||
from os import environ
|
||||
|
||||
os.environ = {}
|
||||
environ = {} # that's fine, assigning a new meaning to the module-level name
|
||||
|
||||
|
||||
class Object:
|
||||
os = None
|
||||
|
||||
|
||||
o = Object()
|
||||
o.os.environ = {}
|
||||
12
resources/test/fixtures/B004.py
vendored
Normal file
12
resources/test/fixtures/B004.py
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
def this_is_a_bug():
|
||||
o = object()
|
||||
if hasattr(o, "__call__"):
|
||||
print("Ooh, callable! Or is it?")
|
||||
if getattr(o, "__call__", False):
|
||||
print("Ooh, callable! Or is it?")
|
||||
|
||||
|
||||
def this_is_fine():
|
||||
o = object()
|
||||
if callable(o):
|
||||
print("Ooh, this is actually callable.")
|
||||
26
resources/test/fixtures/B005.py
vendored
Normal file
26
resources/test/fixtures/B005.py
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
s = "qwe"
|
||||
s.strip(s) # no warning
|
||||
s.strip("we") # no warning
|
||||
s.strip(".facebook.com") # warning
|
||||
s.strip("e") # no warning
|
||||
s.strip("\n\t ") # no warning
|
||||
s.strip(r"\n\t ") # warning
|
||||
s.lstrip(s) # no warning
|
||||
s.lstrip("we") # no warning
|
||||
s.lstrip(".facebook.com") # warning
|
||||
s.lstrip("e") # no warning
|
||||
s.lstrip("\n\t ") # no warning
|
||||
s.lstrip(r"\n\t ") # warning
|
||||
s.rstrip(s) # no warning
|
||||
s.rstrip("we") # warning
|
||||
s.rstrip(".facebook.com") # warning
|
||||
s.rstrip("e") # no warning
|
||||
s.rstrip("\n\t ") # no warning
|
||||
s.rstrip(r"\n\t ") # warning
|
||||
|
||||
from somewhere import other_type, strip
|
||||
|
||||
strip("we") # no warning
|
||||
other_type().lstrip() # no warning
|
||||
other_type().rstrip(["a", "b", "c"]) # no warning
|
||||
other_type().strip("a", "b") # no warning
|
||||
47
resources/test/fixtures/B009_B010.py
vendored
Normal file
47
resources/test/fixtures/B009_B010.py
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
"""
|
||||
Should emit:
|
||||
B009 - Line 17, 18, 19, 44
|
||||
B010 - Line 28, 29, 30
|
||||
"""
|
||||
|
||||
# Valid getattr usage
|
||||
getattr(foo, bar)
|
||||
getattr(foo, "bar", None)
|
||||
getattr(foo, "bar{foo}".format(foo="a"), None)
|
||||
getattr(foo, "bar{foo}".format(foo="a"))
|
||||
getattr(foo, bar, None)
|
||||
getattr(foo, "123abc")
|
||||
getattr(foo, "except")
|
||||
|
||||
# Invalid usage
|
||||
getattr(foo, "bar")
|
||||
getattr(foo, "_123abc")
|
||||
getattr(foo, "abc123")
|
||||
|
||||
# Valid setattr usage
|
||||
setattr(foo, bar, None)
|
||||
setattr(foo, "bar{foo}".format(foo="a"), None)
|
||||
setattr(foo, "123abc", None)
|
||||
setattr(foo, "except", None)
|
||||
|
||||
# Invalid usage
|
||||
setattr(foo, "bar", None)
|
||||
setattr(foo, "_123abc", None)
|
||||
setattr(foo, "abc123", None)
|
||||
|
||||
# Allow use of setattr within lambda expression
|
||||
# since assignment is not valid in this context.
|
||||
c = lambda x: setattr(x, "some_attr", 1)
|
||||
|
||||
|
||||
class FakeCookieStore:
|
||||
def __init__(self, has_setter):
|
||||
self.cookie_filter = None
|
||||
if has_setter:
|
||||
self.setCookieFilter = lambda func: setattr(self, "cookie_filter", func)
|
||||
|
||||
|
||||
# getattr is still flagged within lambda though
|
||||
c = lambda x: getattr(x, "some_attr")
|
||||
# should be replaced with
|
||||
c = lambda x: x.some_attr
|
||||
27
resources/test/fixtures/B015.py
vendored
Normal file
27
resources/test/fixtures/B015.py
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
assert 1 == 1
|
||||
|
||||
1 == 1
|
||||
|
||||
assert 1 in (1, 2)
|
||||
|
||||
1 in (1, 2)
|
||||
|
||||
|
||||
if 1 == 2:
|
||||
pass
|
||||
|
||||
|
||||
def test():
|
||||
assert 1 in (1, 2)
|
||||
|
||||
1 in (1, 2)
|
||||
|
||||
|
||||
data = [x for x in [1, 2, 3] if x in (1, 2)]
|
||||
|
||||
|
||||
class TestClass:
|
||||
1 == 1
|
||||
|
||||
|
||||
print(1 == 1)
|
||||
11
resources/test/fixtures/B016.py
vendored
Normal file
11
resources/test/fixtures/B016.py
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
"""
|
||||
Should emit:
|
||||
B016 - on lines 6, 7, and 8
|
||||
"""
|
||||
|
||||
raise False
|
||||
raise 1
|
||||
raise "string"
|
||||
raise Exception(False)
|
||||
raise Exception(1)
|
||||
raise Exception("string")
|
||||
59
resources/test/fixtures/B018.py
vendored
Normal file
59
resources/test/fixtures/B018.py
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
class Foo1:
|
||||
"""abc"""
|
||||
|
||||
|
||||
class Foo2:
|
||||
"""abc"""
|
||||
|
||||
a = 2
|
||||
"str" # Str (no raise)
|
||||
f"{int}" # JoinedStr (no raise)
|
||||
1j # Number (complex)
|
||||
1 # Number (int)
|
||||
1.0 # Number (float)
|
||||
b"foo" # Binary
|
||||
True # NameConstant (True)
|
||||
False # NameConstant (False)
|
||||
None # NameConstant (None)
|
||||
[1, 2] # list
|
||||
{1, 2} # set
|
||||
{"foo": "bar"} # dict
|
||||
|
||||
|
||||
class Foo3:
|
||||
123
|
||||
a = 2
|
||||
"str"
|
||||
1
|
||||
|
||||
|
||||
def foo1():
|
||||
"""my docstring"""
|
||||
|
||||
|
||||
def foo2():
|
||||
"""my docstring"""
|
||||
a = 2
|
||||
"str" # Str (no raise)
|
||||
f"{int}" # JoinedStr (no raise)
|
||||
1j # Number (complex)
|
||||
1 # Number (int)
|
||||
1.0 # Number (float)
|
||||
b"foo" # Binary
|
||||
True # NameConstant (True)
|
||||
False # NameConstant (False)
|
||||
None # NameConstant (None)
|
||||
[1, 2] # list
|
||||
{1, 2} # set
|
||||
{"foo": "bar"} # dict
|
||||
|
||||
|
||||
def foo3():
|
||||
123
|
||||
a = 2
|
||||
"str"
|
||||
3
|
||||
|
||||
|
||||
def foo4():
|
||||
...
|
||||
21
resources/test/fixtures/B026.py
vendored
Normal file
21
resources/test/fixtures/B026.py
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
"""
|
||||
Should emit:
|
||||
B026 - on lines 16, 17, 18, 19, 20, 21
|
||||
"""
|
||||
|
||||
|
||||
def foo(bar, baz, bam):
|
||||
print(bar, baz, bam)
|
||||
|
||||
|
||||
bar_baz = ["bar", "baz"]
|
||||
|
||||
foo("bar", "baz", bam="bam")
|
||||
foo("bar", baz="baz", bam="bam")
|
||||
foo(bar="bar", baz="baz", bam="bam")
|
||||
foo(bam="bam", *["bar", "baz"])
|
||||
foo(bam="bam", *bar_baz)
|
||||
foo(baz="baz", bam="bam", *["bar"])
|
||||
foo(bar="bar", baz="baz", bam="bam", *[])
|
||||
foo(bam="bam", *["bar"], *["baz"])
|
||||
foo(*["bar"], bam="bam", *["baz"])
|
||||
2
resources/test/fixtures/C413.py
vendored
2
resources/test/fixtures/C413.py
vendored
@@ -1,4 +1,6 @@
|
||||
x = [2, 3, 1]
|
||||
list(x)
|
||||
list(sorted(x))
|
||||
reversed(sorted(x))
|
||||
reversed(sorted(x, key=lambda e: e))
|
||||
reversed(sorted(x, reverse=True))
|
||||
|
||||
35
resources/test/fixtures/E501.py
vendored
35
resources/test/fixtures/E501.py
vendored
@@ -14,3 +14,38 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor i
|
||||
|
||||
_ = "---------------------------------------------------------------------------AAAAAAA"
|
||||
_ = "---------------------------------------------------------------------------亜亜亜亜亜亜亜"
|
||||
|
||||
|
||||
def caller(string: str) -> None:
|
||||
assert string is not None
|
||||
|
||||
|
||||
caller(
|
||||
"""
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
||||
""",
|
||||
)
|
||||
|
||||
|
||||
caller(
|
||||
"""
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
||||
""", # noqa: E501
|
||||
)
|
||||
|
||||
multiple_strings_per_line = {
|
||||
# OK
|
||||
"Lorem ipsum dolor": "sit amet",
|
||||
# E501 Line too long
|
||||
"Lorem ipsum dolor": "sit amet consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
|
||||
# E501 Line too long
|
||||
"Lorem ipsum dolor": """
|
||||
sit amet consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
||||
""",
|
||||
# OK
|
||||
"Lorem ipsum dolor": "sit amet consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", # noqa: E501
|
||||
# OK
|
||||
"Lorem ipsum dolor": """
|
||||
sit amet consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
||||
""", # noqa: E501
|
||||
}
|
||||
|
||||
3
resources/test/fixtures/F632.py
vendored
3
resources/test/fixtures/F632.py
vendored
@@ -3,3 +3,6 @@ if x is "abc":
|
||||
|
||||
if 123 is not y:
|
||||
pass
|
||||
|
||||
if "123" is x < 3:
|
||||
pass
|
||||
|
||||
14
resources/test/fixtures/F821_3.py
vendored
Normal file
14
resources/test/fixtures/F821_3.py
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
"""Test (edge case): accesses of object named `dict`."""
|
||||
|
||||
# OK
|
||||
dict = {"parameters": {}}
|
||||
dict["parameters"]["userId"] = "userId"
|
||||
dict["parameters"]["itemId"] = "itemId"
|
||||
del dict["parameters"]["itemId"]
|
||||
|
||||
# F821 Undefined name `key`
|
||||
# F821 Undefined name `value`
|
||||
x: dict["key", "value"]
|
||||
|
||||
# OK
|
||||
x: dict[str, str]
|
||||
8
resources/test/fixtures/N803.py
vendored
8
resources/test/fixtures/N803.py
vendored
@@ -1,7 +1,7 @@
|
||||
def func(a, A):
|
||||
return a, A
|
||||
def func(_, a, A):
|
||||
return _, a, A
|
||||
|
||||
|
||||
class Class:
|
||||
def method(self, a, A):
|
||||
return a, A
|
||||
def method(self, _, a, A):
|
||||
return _, a, A
|
||||
|
||||
36
resources/test/fixtures/N804.py
vendored
36
resources/test/fixtures/N804.py
vendored
@@ -1,19 +1,43 @@
|
||||
from abc import ABCMeta
|
||||
|
||||
|
||||
class Class:
|
||||
@classmethod
|
||||
def bad_class_method(this):
|
||||
def bad_method(this):
|
||||
pass
|
||||
|
||||
if False:
|
||||
|
||||
def extra_bad_method(this):
|
||||
pass
|
||||
|
||||
def good_method(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def good_class_method(cls):
|
||||
pass
|
||||
|
||||
def method(self):
|
||||
def class_method(cls):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def static_method(x):
|
||||
return x
|
||||
|
||||
def __init__(self):
|
||||
...
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
...
|
||||
|
||||
def __init_subclass__(self, default_name, **kwargs):
|
||||
...
|
||||
|
||||
|
||||
class MetaClass(ABCMeta):
|
||||
def bad_method(self):
|
||||
pass
|
||||
|
||||
def good_method(cls):
|
||||
pass
|
||||
|
||||
|
||||
def func(x):
|
||||
return x
|
||||
|
||||
21
resources/test/fixtures/N805.py
vendored
21
resources/test/fixtures/N805.py
vendored
@@ -1,11 +1,11 @@
|
||||
import random
|
||||
from abc import ABCMeta
|
||||
|
||||
|
||||
class Class:
|
||||
def bad_method(this):
|
||||
pass
|
||||
|
||||
if random.random(0, 2) == 0:
|
||||
if False:
|
||||
|
||||
def extra_bad_method(this):
|
||||
pass
|
||||
@@ -21,6 +21,23 @@ class Class:
|
||||
def static_method(x):
|
||||
return x
|
||||
|
||||
def __init__(self):
|
||||
...
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
...
|
||||
|
||||
def __init_subclass__(self, default_name, **kwargs):
|
||||
...
|
||||
|
||||
|
||||
class MetaClass(ABCMeta):
|
||||
def bad_method(self):
|
||||
pass
|
||||
|
||||
def good_method(cls):
|
||||
pass
|
||||
|
||||
|
||||
def func(x):
|
||||
return x
|
||||
|
||||
7
resources/test/fixtures/RUF001.py
vendored
Normal file
7
resources/test/fixtures/RUF001.py
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
x = "𝐁ad string"
|
||||
|
||||
|
||||
def f():
|
||||
"""Here's a docstring with an unusual parenthesis: )"""
|
||||
# And here's a comment with an unusual punctuation mark: ᜵
|
||||
...
|
||||
7
resources/test/fixtures/RUF002.py
vendored
Normal file
7
resources/test/fixtures/RUF002.py
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
x = "𝐁ad string"
|
||||
|
||||
|
||||
def f():
|
||||
"""Here's a docstring with an unusual parenthesis: )"""
|
||||
# And here's a comment with an unusual punctuation mark: ᜵
|
||||
...
|
||||
7
resources/test/fixtures/RUF003.py
vendored
Normal file
7
resources/test/fixtures/RUF003.py
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
x = "𝐁ad string"
|
||||
|
||||
|
||||
def f():
|
||||
"""Here's a docstring with an unusual parenthesis: )"""
|
||||
# And here's a comment with an unusual punctuation mark: ᜵
|
||||
...
|
||||
3
resources/test/fixtures/U009_0.py
vendored
Normal file
3
resources/test/fixtures/U009_0.py
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# coding=utf8
|
||||
|
||||
print('Hello world')
|
||||
4
resources/test/fixtures/U009_1.py
vendored
Normal file
4
resources/test/fixtures/U009_1.py
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
print('Hello world')
|
||||
5
resources/test/fixtures/U009_2.py
vendored
Normal file
5
resources/test/fixtures/U009_2.py
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
#!/usr/bin/python
|
||||
# A coding comment is only valid in the first two lines, so this one is not checked.
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
print('Hello world')
|
||||
4
resources/test/fixtures/U009_3.py
vendored
Normal file
4
resources/test/fixtures/U009_3.py
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: something-else -*-
|
||||
|
||||
print('Hello world')
|
||||
5
resources/test/fixtures/U010.py
vendored
Normal file
5
resources/test/fixtures/U010.py
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
from __future__ import annotations, nested_scopes, generators
|
||||
|
||||
from __future__ import absolute_import, division
|
||||
|
||||
from __future__ import generator_stop
|
||||
103
resources/test/fixtures/U011_0.py
vendored
Normal file
103
resources/test/fixtures/U011_0.py
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
import functools
|
||||
from functools import lru_cache
|
||||
|
||||
|
||||
@lru_cache()
|
||||
def fixme1():
|
||||
pass
|
||||
|
||||
|
||||
@other_deco_after
|
||||
@functools.lru_cache()
|
||||
def fixme2():
|
||||
pass
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def fixme3():
|
||||
pass
|
||||
|
||||
|
||||
@functools.lru_cache(maxsize=None)
|
||||
@other_deco_before
|
||||
def fixme4():
|
||||
pass
|
||||
|
||||
|
||||
@lru_cache( # A
|
||||
) # B
|
||||
def fixme5():
|
||||
pass
|
||||
|
||||
|
||||
@lru_cache(
|
||||
# A
|
||||
) # B
|
||||
def fixme6():
|
||||
pass
|
||||
|
||||
|
||||
@functools.lru_cache(
|
||||
# A
|
||||
maxsize = None) # B
|
||||
def fixme7():
|
||||
pass
|
||||
|
||||
|
||||
@functools.lru_cache(
|
||||
# A1
|
||||
maxsize = None
|
||||
# A2
|
||||
) # B
|
||||
def fixme8():
|
||||
pass
|
||||
|
||||
|
||||
@functools.lru_cache(
|
||||
# A1
|
||||
maxsize =
|
||||
None
|
||||
# A2
|
||||
|
||||
)
|
||||
def fixme9():
|
||||
pass
|
||||
|
||||
|
||||
@functools.lru_cache(
|
||||
# A1
|
||||
maxsize =
|
||||
None
|
||||
# A2
|
||||
)
|
||||
def fixme10():
|
||||
pass
|
||||
|
||||
|
||||
@lru_cache
|
||||
def correct1():
|
||||
pass
|
||||
|
||||
|
||||
@functools.lru_cache
|
||||
def correct2():
|
||||
pass
|
||||
|
||||
|
||||
@functoools.lru_cache(maxsize=64)
|
||||
def correct3():
|
||||
pass
|
||||
|
||||
|
||||
def user_func():
|
||||
pass
|
||||
|
||||
|
||||
@lru_cache(user_func)
|
||||
def correct4():
|
||||
pass
|
||||
|
||||
|
||||
@lru_cache(user_func, maxsize=None)
|
||||
def correct5():
|
||||
pass
|
||||
15
resources/test/fixtures/U011_1.py
vendored
Normal file
15
resources/test/fixtures/U011_1.py
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
import functools
|
||||
|
||||
|
||||
def lru_cache(maxsize=None):
|
||||
pass
|
||||
|
||||
|
||||
@lru_cache()
|
||||
def dont_fixme():
|
||||
pass
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def dont_fixme():
|
||||
pass
|
||||
35
resources/test/fixtures/W605_1.py
vendored
Normal file
35
resources/test/fixtures/W605_1.py
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
#: W605:1:10
|
||||
regex = '\.png$'
|
||||
|
||||
#: W605:2:1
|
||||
regex = '''
|
||||
\.png$
|
||||
'''
|
||||
|
||||
#: W605:2:6
|
||||
f(
|
||||
'\_'
|
||||
)
|
||||
|
||||
#: W605:4:6
|
||||
"""
|
||||
multi-line
|
||||
literal
|
||||
with \_ somewhere
|
||||
in the middle
|
||||
"""
|
||||
|
||||
#: Okay
|
||||
regex = r'\.png$'
|
||||
regex = '\\.png$'
|
||||
regex = r'''
|
||||
\.png$
|
||||
'''
|
||||
regex = r'''
|
||||
\\.png$
|
||||
'''
|
||||
s = '\\'
|
||||
regex = '\w' # noqa
|
||||
regex = '''
|
||||
\w
|
||||
''' # noqa
|
||||
9
resources/test/fixtures/excluded.py
vendored
9
resources/test/fixtures/excluded.py
vendored
@@ -1,9 +0,0 @@
|
||||
a = "abc"
|
||||
b = f"ghi{'jkl'}"
|
||||
|
||||
c = f"def"
|
||||
d = f"def" + "ghi"
|
||||
e = (
|
||||
f"def" +
|
||||
"ghi"
|
||||
)
|
||||
57
resources/test/fixtures/flake8_annotations/allow_star_arg_any.py
vendored
Normal file
57
resources/test/fixtures/flake8_annotations/allow_star_arg_any.py
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
from typing import Any
|
||||
|
||||
|
||||
# OK
|
||||
def foo(a: int, *args: str, **kwargs: str) -> int:
|
||||
pass
|
||||
|
||||
|
||||
# ANN401
|
||||
def foo(a: Any, *args: str, **kwargs: str) -> int:
|
||||
pass
|
||||
|
||||
|
||||
# ANN401
|
||||
def foo(a: int, *args: str, **kwargs: str) -> Any:
|
||||
pass
|
||||
|
||||
|
||||
# OK
|
||||
def foo(a: int, *args: Any, **kwargs: Any) -> int:
|
||||
pass
|
||||
|
||||
|
||||
# OK
|
||||
def foo(a: int, *args: Any, **kwargs: str) -> int:
|
||||
pass
|
||||
|
||||
|
||||
# ANN401
|
||||
def foo(a: int, *args: str, **kwargs: Any) -> int:
|
||||
pass
|
||||
|
||||
|
||||
class Bar:
|
||||
# OK
|
||||
def foo_method(self, a: int, *params: str, **options: str) -> int:
|
||||
pass
|
||||
|
||||
# ANN401
|
||||
def foo_method(self, a: Any, *params: str, **options: str) -> int:
|
||||
pass
|
||||
|
||||
# ANN401
|
||||
def foo_method(self, a: int, *params: str, **options: str) -> Any:
|
||||
pass
|
||||
|
||||
# OK
|
||||
def foo_method(self, a: int, *params: Any, **options: Any) -> int:
|
||||
pass
|
||||
|
||||
# OK
|
||||
def foo_method(self, a: int, *params: Any, **options: str) -> int:
|
||||
pass
|
||||
|
||||
# OK
|
||||
def foo_method(self, a: int, *params: str, **options: Any) -> int:
|
||||
pass
|
||||
105
resources/test/fixtures/flake8_annotations/annotation_presence.py
vendored
Normal file
105
resources/test/fixtures/flake8_annotations/annotation_presence.py
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
from typing import Any, Type
|
||||
|
||||
# Error
|
||||
def foo(a, b):
|
||||
pass
|
||||
|
||||
|
||||
# Error
|
||||
def foo(a: int, b):
|
||||
pass
|
||||
|
||||
|
||||
# Error
|
||||
def foo(a: int, b) -> int:
|
||||
pass
|
||||
|
||||
|
||||
# Error
|
||||
def foo(a: int, b: int):
|
||||
pass
|
||||
|
||||
|
||||
# Error
|
||||
def foo():
|
||||
pass
|
||||
|
||||
|
||||
# OK
|
||||
def foo(a: int, b: int) -> int:
|
||||
pass
|
||||
|
||||
|
||||
# OK
|
||||
def foo() -> int:
|
||||
pass
|
||||
|
||||
|
||||
# OK
|
||||
def foo(a: int, *args: str, **kwargs: str) -> int:
|
||||
pass
|
||||
|
||||
|
||||
# ANN401
|
||||
def foo(a: Any, *args: str, **kwargs: str) -> int:
|
||||
pass
|
||||
|
||||
|
||||
# ANN401
|
||||
def foo(a: int, *args: str, **kwargs: str) -> Any:
|
||||
pass
|
||||
|
||||
|
||||
# ANN401
|
||||
def foo(a: int, *args: Any, **kwargs: Any) -> int:
|
||||
pass
|
||||
|
||||
|
||||
# ANN401
|
||||
def foo(a: int, *args: Any, **kwargs: str) -> int:
|
||||
pass
|
||||
|
||||
|
||||
# ANN401
|
||||
def foo(a: int, *args: str, **kwargs: Any) -> int:
|
||||
pass
|
||||
|
||||
|
||||
class Foo:
|
||||
# OK
|
||||
def foo(self: "Foo", a: int, b: int) -> int:
|
||||
pass
|
||||
|
||||
# ANN101
|
||||
def foo(self, a: int, b: int) -> int:
|
||||
pass
|
||||
|
||||
# ANN401
|
||||
def foo(self: "Foo", a: Any, *params: str, **options: str) -> int:
|
||||
pass
|
||||
|
||||
# ANN401
|
||||
def foo(self: "Foo", a: int, *params: str, **options: str) -> Any:
|
||||
pass
|
||||
|
||||
# ANN401
|
||||
def foo(self: "Foo", a: int, *params: Any, **options: Any) -> int:
|
||||
pass
|
||||
|
||||
# ANN401
|
||||
def foo(self: "Foo", a: int, *params: Any, **options: str) -> int:
|
||||
pass
|
||||
|
||||
# ANN401
|
||||
def foo(self: "Foo", a: int, *params: str, **options: Any) -> int:
|
||||
pass
|
||||
|
||||
# OK
|
||||
@classmethod
|
||||
def foo(cls: Type["Foo"], a: int, b: int) -> int:
|
||||
pass
|
||||
|
||||
# ANN102
|
||||
@classmethod
|
||||
def foo(cls, a: int, b: int) -> int:
|
||||
pass
|
||||
41
resources/test/fixtures/flake8_annotations/mypy_init_return.py
vendored
Normal file
41
resources/test/fixtures/flake8_annotations/mypy_init_return.py
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
"""Test case expected to be run with `mypy_init_return = True`."""
|
||||
|
||||
# Error
|
||||
class Foo:
|
||||
def __init__(self):
|
||||
...
|
||||
|
||||
|
||||
# Error
|
||||
class Foo:
|
||||
def __init__(self, foo):
|
||||
...
|
||||
|
||||
|
||||
# OK
|
||||
class Foo:
|
||||
def __init__(self, foo) -> None:
|
||||
...
|
||||
|
||||
|
||||
# OK
|
||||
class Foo:
|
||||
def __init__(self) -> None:
|
||||
...
|
||||
|
||||
|
||||
# OK
|
||||
class Foo:
|
||||
def __init__(self, foo: int):
|
||||
...
|
||||
|
||||
|
||||
# OK
|
||||
class Foo:
|
||||
def __init__(self, foo: int) -> None:
|
||||
...
|
||||
|
||||
|
||||
# Error
|
||||
def __init__(self, foo: int):
|
||||
...
|
||||
26
resources/test/fixtures/flake8_annotations/suppress_dummy_args.py
vendored
Normal file
26
resources/test/fixtures/flake8_annotations/suppress_dummy_args.py
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
"""Test case expected to be run with `suppress_dummy_args = True`."""
|
||||
|
||||
# OK
|
||||
def foo(_) -> None:
|
||||
...
|
||||
|
||||
|
||||
# OK
|
||||
def foo(*_) -> None:
|
||||
...
|
||||
|
||||
|
||||
# OK
|
||||
def foo(**_) -> None:
|
||||
...
|
||||
|
||||
|
||||
# OK
|
||||
def foo(a: int, _) -> None:
|
||||
...
|
||||
|
||||
|
||||
# OK
|
||||
def foo() -> None:
|
||||
def bar(_) -> None:
|
||||
...
|
||||
55
resources/test/fixtures/flake8_annotations/suppress_none_returning.py
vendored
Normal file
55
resources/test/fixtures/flake8_annotations/suppress_none_returning.py
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
"""Test case expected to be run with `suppress_none_returning = True`."""
|
||||
|
||||
# OK
|
||||
def foo():
|
||||
a = 2 + 2
|
||||
|
||||
|
||||
# OK
|
||||
def foo():
|
||||
return
|
||||
|
||||
|
||||
# OK
|
||||
def foo():
|
||||
return None
|
||||
|
||||
|
||||
# OK
|
||||
def foo():
|
||||
a = 2 + 2
|
||||
if a == 4:
|
||||
return
|
||||
else:
|
||||
return
|
||||
|
||||
|
||||
# OK
|
||||
def foo():
|
||||
a = 2 + 2
|
||||
if a == 4:
|
||||
return None
|
||||
else:
|
||||
return
|
||||
|
||||
|
||||
# OK
|
||||
def foo():
|
||||
def bar() -> bool:
|
||||
return True
|
||||
|
||||
bar()
|
||||
|
||||
|
||||
# Error
|
||||
def foo():
|
||||
return True
|
||||
|
||||
|
||||
# Error
|
||||
def foo():
|
||||
a = 2 + 2
|
||||
if a == 4:
|
||||
return True
|
||||
else:
|
||||
return
|
||||
0
resources/test/fixtures/foo/__init__.py
vendored
0
resources/test/fixtures/foo/__init__.py
vendored
5
resources/test/fixtures/isort/combine_import_froms.py
vendored
Normal file
5
resources/test/fixtures/isort/combine_import_froms.py
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
from collections import Awaitable
|
||||
from collections import AsyncIterable
|
||||
from collections import Collection
|
||||
from collections import ChainMap
|
||||
from collections import MutableSequence, MutableMapping
|
||||
4
resources/test/fixtures/isort/deduplicate_imports.py
vendored
Normal file
4
resources/test/fixtures/isort/deduplicate_imports.py
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import os
|
||||
import os
|
||||
import os as os1
|
||||
import os as os2
|
||||
1
resources/test/fixtures/isort/fit_line_length.py
vendored
Normal file
1
resources/test/fixtures/isort/fit_line_length.py
vendored
Normal file
@@ -0,0 +1 @@
|
||||
from collections import Collection
|
||||
2
resources/test/fixtures/isort/import_from_after_import.py
vendored
Normal file
2
resources/test/fixtures/isort/import_from_after_import.py
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
from collections import Collection
|
||||
import os
|
||||
6
resources/test/fixtures/isort/leading_prefix.py
vendored
Normal file
6
resources/test/fixtures/isort/leading_prefix.py
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
x = 1; import sys
|
||||
import os
|
||||
|
||||
if True:
|
||||
x = 1; import sys
|
||||
import os
|
||||
3
resources/test/fixtures/isort/no_reorder_within_section.py
vendored
Normal file
3
resources/test/fixtures/isort/no_reorder_within_section.py
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# OK
|
||||
import os
|
||||
import sys
|
||||
6
resources/test/fixtures/isort/preserve_indentation.py
vendored
Normal file
6
resources/test/fixtures/isort/preserve_indentation.py
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
if True:
|
||||
import sys
|
||||
import os
|
||||
else:
|
||||
import sys
|
||||
import os
|
||||
2
resources/test/fixtures/isort/reorder_within_section.py
vendored
Normal file
2
resources/test/fixtures/isort/reorder_within_section.py
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
import sys
|
||||
import os
|
||||
5
resources/test/fixtures/isort/separate_first_party_imports.py
vendored
Normal file
5
resources/test/fixtures/isort/separate_first_party_imports.py
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
import sys
|
||||
import leading_prefix
|
||||
import numpy as np
|
||||
import os
|
||||
from leading_prefix import Class
|
||||
3
resources/test/fixtures/isort/separate_future_imports.py
vendored
Normal file
3
resources/test/fixtures/isort/separate_future_imports.py
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
import sys
|
||||
import os
|
||||
from __future__ import annotations
|
||||
4
resources/test/fixtures/isort/separate_third_party_imports.py
vendored
Normal file
4
resources/test/fixtures/isort/separate_third_party_imports.py
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import pandas as pd
|
||||
import sys
|
||||
import numpy as np
|
||||
import os
|
||||
6
resources/test/fixtures/isort/trailing_suffix.py
vendored
Normal file
6
resources/test/fixtures/isort/trailing_suffix.py
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
import sys
|
||||
import os; x = 1
|
||||
|
||||
if True:
|
||||
import sys
|
||||
import os; x = 1
|
||||
4
resources/test/fixtures/pyproject.toml
vendored
4
resources/test/fixtures/pyproject.toml
vendored
@@ -1,9 +1,9 @@
|
||||
[tool.ruff]
|
||||
line-length = 88
|
||||
extend-exclude = [
|
||||
"excluded.py",
|
||||
"excluded_file.py",
|
||||
"migrations",
|
||||
"directory/also_excluded.py",
|
||||
"with_excluded_file/other_excluded_file.py",
|
||||
]
|
||||
per-file-ignores = { "__init__.py" = ["F401"] }
|
||||
|
||||
|
||||
17
ruff_dev/Cargo.toml
Normal file
17
ruff_dev/Cargo.toml
Normal file
@@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "ruff_dev"
|
||||
version = "0.0.110"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
anyhow = { version = "1.0.66" }
|
||||
clap = { version = "4.0.1", features = ["derive"] }
|
||||
codegen = { version = "0.2.0" }
|
||||
itertools = { version = "0.10.5" }
|
||||
libcst = { git = "https://github.com/charliermarsh/LibCST", rev = "a13ec97dd4eb925bde4d426c6e422582793b260c" }
|
||||
ruff = { path = ".." }
|
||||
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb" }
|
||||
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb" }
|
||||
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "27bf82a2251d7e6ac6cd75e6ad51be12a53d84bb" }
|
||||
strum = { version = "0.24.1", features = ["strum_macros"] }
|
||||
strum_macros = { version = "0.24.3" }
|
||||
@@ -1,22 +1,39 @@
|
||||
//! Generate the CheckCodePrefix enum.
|
||||
//! Generate the `CheckCodePrefix` enum.
|
||||
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::Write;
|
||||
|
||||
use anyhow::Result;
|
||||
use clap::Parser;
|
||||
use codegen::{Scope, Type, Variant};
|
||||
use itertools::Itertools;
|
||||
use ruff::checks::CheckCode;
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
fn main() {
|
||||
const FILE: &str = "src/checks_gen.rs";
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
pub struct Cli {
|
||||
/// Write the generated source code to stdout (rather than to
|
||||
/// `src/checks_gen.rs`).
|
||||
#[arg(long)]
|
||||
dry_run: bool,
|
||||
}
|
||||
|
||||
pub fn main(cli: &Cli) -> Result<()> {
|
||||
// Build up a map from prefix to matching CheckCodes.
|
||||
let mut prefix_to_codes: BTreeMap<String, BTreeSet<CheckCode>> = Default::default();
|
||||
for check_code in CheckCode::iter() {
|
||||
let as_ref = check_code.as_ref().to_string();
|
||||
for i in 1..=as_ref.len() {
|
||||
let as_ref: String = check_code.as_ref().to_string();
|
||||
let prefix_len = as_ref
|
||||
.chars()
|
||||
.take_while(|char| char.is_alphabetic())
|
||||
.count();
|
||||
for i in prefix_len..=as_ref.len() {
|
||||
let prefix = as_ref[..i].to_string();
|
||||
let entry = prefix_to_codes
|
||||
.entry(prefix)
|
||||
.or_insert_with(|| Default::default());
|
||||
let entry = prefix_to_codes.entry(prefix).or_default();
|
||||
entry.insert(check_code.clone());
|
||||
}
|
||||
}
|
||||
@@ -31,10 +48,12 @@ fn main() {
|
||||
.derive("Debug")
|
||||
.derive("PartialEq")
|
||||
.derive("Eq")
|
||||
.derive("PartialOrd")
|
||||
.derive("Ord")
|
||||
.derive("Clone")
|
||||
.derive("Serialize")
|
||||
.derive("Deserialize");
|
||||
for (prefix, _) in &prefix_to_codes {
|
||||
for prefix in prefix_to_codes.keys() {
|
||||
gen = gen.push_variant(Variant::new(prefix.to_string()));
|
||||
}
|
||||
|
||||
@@ -78,12 +97,13 @@ fn main() {
|
||||
.ret(Type::new("PrefixSpecificity"))
|
||||
.vis("pub")
|
||||
.line("match self {");
|
||||
for (prefix, _) in &prefix_to_codes {
|
||||
let specificity = match prefix.len() {
|
||||
4 => "Explicit",
|
||||
3 => "Tens",
|
||||
2 => "Hundreds",
|
||||
1 => "Category",
|
||||
for prefix in prefix_to_codes.keys() {
|
||||
let num_numeric = prefix.chars().filter(|char| char.is_numeric()).count();
|
||||
let specificity = match num_numeric {
|
||||
3 => "Explicit",
|
||||
2 => "Tens",
|
||||
1 => "Hundreds",
|
||||
0 => "Category",
|
||||
_ => panic!("Invalid prefix: {}", prefix),
|
||||
};
|
||||
gen = gen.line(format!(
|
||||
@@ -93,12 +113,28 @@ fn main() {
|
||||
}
|
||||
gen.line("}");
|
||||
|
||||
println!("//! File automatically generated by examples/generate_check_code_prefix.rs.");
|
||||
println!();
|
||||
println!("use serde::{{Serialize, Deserialize}};");
|
||||
println!("use strum_macros::EnumString;");
|
||||
println!();
|
||||
println!("use crate::checks::CheckCode;");
|
||||
println!();
|
||||
println!("{}", scope.to_string());
|
||||
// Construct the output contents.
|
||||
let mut output = String::new();
|
||||
output.push_str("//! File automatically generated by examples/generate_check_code_prefix.rs.");
|
||||
output.push('\n');
|
||||
output.push('\n');
|
||||
output.push_str("use serde::{{Serialize, Deserialize}};");
|
||||
output.push('\n');
|
||||
output.push_str("use strum_macros::EnumString;");
|
||||
output.push('\n');
|
||||
output.push('\n');
|
||||
output.push_str("use crate::checks::CheckCode;");
|
||||
output.push('\n');
|
||||
output.push('\n');
|
||||
output.push_str(&scope.to_string());
|
||||
|
||||
// Write the output to `src/checks_gen.rs` (or stdout).
|
||||
if cli.dry_run {
|
||||
println!("{}", output);
|
||||
} else {
|
||||
let mut f = OpenOptions::new().write(true).truncate(true).open(FILE)?;
|
||||
write!(f, "{}", output)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
93
ruff_dev/src/generate_rules_table.rs
Normal file
93
ruff_dev/src/generate_rules_table.rs
Normal file
@@ -0,0 +1,93 @@
|
||||
//! 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 ruff::checks::{CheckCategory, CheckCode};
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
const BEGIN_PRAGMA: &str = "<!-- Begin auto-generated sections. -->";
|
||||
const END_PRAGMA: &str = "<!-- End auto-generated sections. -->";
|
||||
|
||||
#[derive(Args)]
|
||||
pub struct Cli {
|
||||
/// Write the generated table to stdout (rather than to `README.md`).
|
||||
#[arg(long)]
|
||||
dry_run: bool,
|
||||
}
|
||||
|
||||
pub fn main(cli: &Cli) -> Result<()> {
|
||||
// Generate the table string.
|
||||
let mut output = String::new();
|
||||
for check_category in CheckCategory::iter() {
|
||||
output.push_str(&format!("### {}", check_category.title()));
|
||||
output.push('\n');
|
||||
output.push('\n');
|
||||
|
||||
if let Some(url) = check_category.url() {
|
||||
output.push_str(&format!(
|
||||
"For more, see [{}]({}) on PyPI.",
|
||||
check_category.title(),
|
||||
url
|
||||
));
|
||||
output.push('\n');
|
||||
output.push('\n');
|
||||
}
|
||||
|
||||
output.push_str("| Code | Name | Message | Fix |");
|
||||
output.push('\n');
|
||||
output.push_str("| ---- | ---- | ------- | --- |");
|
||||
output.push('\n');
|
||||
|
||||
for check_code in CheckCode::iter() {
|
||||
if check_code.category() == check_category {
|
||||
let check_kind = check_code.kind();
|
||||
let fix_token = if check_kind.fixable() { "🛠" } else { "" };
|
||||
output.push_str(&format!(
|
||||
"| {} | {} | {} | {} |",
|
||||
check_kind.code().as_ref(),
|
||||
check_kind.as_ref(),
|
||||
check_kind.summary().replace('|', r"\|"),
|
||||
fix_token
|
||||
));
|
||||
output.push('\n');
|
||||
}
|
||||
}
|
||||
output.push('\n');
|
||||
}
|
||||
|
||||
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, "{}\n\n", prefix)?;
|
||||
write!(f, "{}", output)?;
|
||||
write!(f, "{}", suffix)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,25 +1,25 @@
|
||||
//! Run round-trip source code generation on a given Python file.
|
||||
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use anyhow::Result;
|
||||
use clap::Parser;
|
||||
use clap::Args;
|
||||
use ruff::code_gen::SourceGenerator;
|
||||
use ruff::fs;
|
||||
use rustpython_parser::parser;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
struct Cli {
|
||||
#[derive(Args)]
|
||||
pub struct Cli {
|
||||
/// Python file to round-trip.
|
||||
#[arg(required = true)]
|
||||
file: PathBuf,
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let cli = Cli::parse();
|
||||
|
||||
let contents = fs::read_file(&cli.file)?;
|
||||
pub fn main(cli: &Cli) -> Result<()> {
|
||||
let contents = fs::read_to_string(&cli.file)?;
|
||||
let python_ast = parser::parse_program(&contents, &cli.file.to_string_lossy())?;
|
||||
let mut generator = SourceGenerator::new();
|
||||
generator.unparse_suite(&python_ast)?;
|
||||
println!("{}", generator.generate()?);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
6
ruff_dev/src/lib.rs
Normal file
6
ruff_dev/src/lib.rs
Normal file
@@ -0,0 +1,6 @@
|
||||
pub mod generate_check_code_prefix;
|
||||
pub mod generate_rules_table;
|
||||
pub mod generate_source_code;
|
||||
pub mod print_ast;
|
||||
pub mod print_cst;
|
||||
pub mod print_tokens;
|
||||
43
ruff_dev/src/main.rs
Normal file
43
ruff_dev/src/main.rs
Normal file
@@ -0,0 +1,43 @@
|
||||
use anyhow::Result;
|
||||
use clap::{Parser, Subcommand};
|
||||
use ruff_dev::{
|
||||
generate_check_code_prefix, generate_rules_table, generate_source_code, print_ast, print_cst,
|
||||
print_tokens,
|
||||
};
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
#[command(propagate_version = true)]
|
||||
struct Cli {
|
||||
#[command(subcommand)]
|
||||
command: Commands,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
enum Commands {
|
||||
/// Generate the `CheckCodePrefix` enum.
|
||||
GenerateCheckCodePrefix(generate_check_code_prefix::Cli),
|
||||
/// Generate a Markdown-compatible table of supported lint rules.
|
||||
GenerateRulesTable(generate_rules_table::Cli),
|
||||
/// Run round-trip source code generation on a given Python file.
|
||||
GenerateSourceCode(generate_source_code::Cli),
|
||||
/// Print the AST for a given Python file.
|
||||
PrintAST(print_ast::Cli),
|
||||
/// Print the LibCST CST for a given Python file.
|
||||
PrintCST(print_cst::Cli),
|
||||
/// Print the token stream for a given Python file.
|
||||
PrintTokens(print_tokens::Cli),
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let cli = Cli::parse();
|
||||
match &cli.command {
|
||||
Commands::GenerateCheckCodePrefix(args) => generate_check_code_prefix::main(args)?,
|
||||
Commands::GenerateRulesTable(args) => generate_rules_table::main(args)?,
|
||||
Commands::GenerateSourceCode(args) => generate_source_code::main(args)?,
|
||||
Commands::PrintAST(args) => print_ast::main(args)?,
|
||||
Commands::PrintCST(args) => print_cst::main(args)?,
|
||||
Commands::PrintTokens(args) => print_tokens::main(args)?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,25 +1,22 @@
|
||||
//! Print the AST for a given Python file.
|
||||
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use anyhow::Result;
|
||||
use clap::Parser;
|
||||
use ruff::fs;
|
||||
use clap::Args;
|
||||
use rustpython_parser::parser;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
struct Cli {
|
||||
#[derive(Args)]
|
||||
pub struct Cli {
|
||||
/// Python file for which to generate the AST.
|
||||
#[arg(required = true)]
|
||||
file: PathBuf,
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let cli = Cli::parse();
|
||||
|
||||
let contents = fs::read_file(&cli.file)?;
|
||||
pub fn main(cli: &Cli) -> Result<()> {
|
||||
let contents = fs::read_to_string(&cli.file)?;
|
||||
let python_ast = parser::parse_program(&contents, &cli.file.to_string_lossy())?;
|
||||
|
||||
println!("{:#?}", python_ast);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
25
ruff_dev/src/print_cst.rs
Normal file
25
ruff_dev/src/print_cst.rs
Normal file
@@ -0,0 +1,25 @@
|
||||
//! Print the LibCST CST for a given Python file.
|
||||
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use anyhow::Result;
|
||||
use clap::Args;
|
||||
|
||||
#[derive(Args)]
|
||||
pub struct Cli {
|
||||
/// Python file for which to generate the CST.
|
||||
#[arg(required = true)]
|
||||
file: PathBuf,
|
||||
}
|
||||
|
||||
pub fn main(cli: &Cli) -> Result<()> {
|
||||
let contents = fs::read_to_string(&cli.file)?;
|
||||
match libcst_native::parse_module(&contents, None) {
|
||||
Ok(python_cst) => {
|
||||
println!("{:#?}", python_cst);
|
||||
Ok(())
|
||||
}
|
||||
Err(_) => Err(anyhow::anyhow!("Failed to parse CST")),
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,23 @@
|
||||
//! Print the token stream for a given Python file.
|
||||
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use anyhow::Result;
|
||||
use clap::Parser;
|
||||
use ruff::fs;
|
||||
use clap::Args;
|
||||
use rustpython_parser::lexer;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
struct Cli {
|
||||
#[derive(Args)]
|
||||
pub struct Cli {
|
||||
/// Python file for which to generate the AST.
|
||||
#[arg(required = true)]
|
||||
file: PathBuf,
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let cli = Cli::parse();
|
||||
|
||||
let contents = fs::read_file(&cli.file)?;
|
||||
pub fn main(cli: &Cli) -> Result<()> {
|
||||
let contents = fs::read_to_string(&cli.file)?;
|
||||
for (_, tok, _) in lexer::make_tokenizer(&contents).flatten() {
|
||||
println!("{:#?}", tok);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
1.64.0
|
||||
1.65.0
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
use rustpython_ast::{Expr, Keyword};
|
||||
use rustpython_parser::ast::{Located, Location};
|
||||
|
||||
fn id() -> usize {
|
||||
@@ -30,24 +31,33 @@ pub struct FunctionScope {
|
||||
pub uses_locals: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ScopeKind {
|
||||
Class,
|
||||
Function(FunctionScope),
|
||||
Generator,
|
||||
Module,
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct ClassScope<'a> {
|
||||
pub name: &'a str,
|
||||
pub bases: &'a [Expr],
|
||||
pub keywords: &'a [Keyword],
|
||||
pub decorator_list: &'a [Expr],
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Scope {
|
||||
pub enum ScopeKind<'a> {
|
||||
Class(ClassScope<'a>),
|
||||
Function(FunctionScope),
|
||||
Generator,
|
||||
Module,
|
||||
Arg,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Scope<'a> {
|
||||
pub id: usize,
|
||||
pub kind: ScopeKind,
|
||||
pub kind: ScopeKind<'a>,
|
||||
pub import_starred: bool,
|
||||
pub values: BTreeMap<String, Binding>,
|
||||
}
|
||||
|
||||
impl Scope {
|
||||
pub fn new(kind: ScopeKind) -> Self {
|
||||
impl<'a> Scope<'a> {
|
||||
pub fn new(kind: ScopeKind<'a>) -> Self {
|
||||
Scope {
|
||||
id: id(),
|
||||
kind,
|
||||
@@ -90,10 +100,6 @@ pub struct Binding {
|
||||
pub used: Option<(usize, Range)>,
|
||||
}
|
||||
|
||||
pub trait CheckLocator {
|
||||
fn locate_check(&self, default: Range) -> Range;
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum ImportKind {
|
||||
Import,
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
use std::borrow::Cow;
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use itertools::Itertools;
|
||||
use ropey::RopeBuilder;
|
||||
use rustpython_parser::ast::Location;
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::autofix::{Fix, Patch};
|
||||
use crate::checks::Check;
|
||||
use crate::source_code_locator::SourceCodeLocator;
|
||||
|
||||
// TODO(charlie): The model here is awkward because `Apply` is only relevant at
|
||||
// higher levels in the execution flow.
|
||||
@@ -36,24 +40,28 @@ impl From<bool> for Mode {
|
||||
}
|
||||
|
||||
/// Auto-fix errors in a file, and write the fixed source code to disk.
|
||||
pub fn fix_file(checks: &mut [Check], contents: &str) -> Option<String> {
|
||||
pub fn fix_file<'a>(
|
||||
checks: &'a mut [Check],
|
||||
locator: &'a SourceCodeLocator<'a>,
|
||||
) -> Option<Cow<'a, str>> {
|
||||
if checks.iter().all(|check| check.fix.is_none()) {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(apply_fixes(
|
||||
checks.iter_mut().filter_map(|check| check.fix.as_mut()),
|
||||
contents,
|
||||
locator,
|
||||
))
|
||||
}
|
||||
|
||||
/// Apply a series of fixes.
|
||||
fn apply_fixes<'a>(fixes: impl Iterator<Item = &'a mut Fix>, contents: &str) -> String {
|
||||
let lines: Vec<&str> = contents.lines().collect();
|
||||
|
||||
let mut output: String = Default::default();
|
||||
let mut last_pos: Location = Default::default();
|
||||
let mut applied: BTreeSet<&Patch> = Default::default();
|
||||
fn apply_fixes<'a>(
|
||||
fixes: impl Iterator<Item = &'a mut Fix>,
|
||||
locator: &'a SourceCodeLocator<'a>,
|
||||
) -> Cow<'a, str> {
|
||||
let mut output = RopeBuilder::new();
|
||||
let mut last_pos: Location = Location::new(1, 0);
|
||||
let mut applied: BTreeSet<&Patch> = BTreeSet::new();
|
||||
|
||||
for fix in fixes.sorted_by_key(|fix| fix.patch.location) {
|
||||
// If we already applied an identical fix as part of another correction, skip
|
||||
@@ -69,44 +77,27 @@ fn apply_fixes<'a>(fixes: impl Iterator<Item = &'a mut Fix>, contents: &str) ->
|
||||
continue;
|
||||
}
|
||||
|
||||
if fix.patch.location.row() > last_pos.row() {
|
||||
if last_pos.row() > 0 || last_pos.column() > 0 {
|
||||
output.push_str(&lines[last_pos.row() - 1][last_pos.column()..]);
|
||||
output.push('\n');
|
||||
}
|
||||
for line in &lines[last_pos.row()..fix.patch.location.row() - 1] {
|
||||
output.push_str(line);
|
||||
output.push('\n');
|
||||
}
|
||||
output.push_str(&lines[fix.patch.location.row() - 1][..fix.patch.location.column()]);
|
||||
output.push_str(&fix.patch.content);
|
||||
} else {
|
||||
output.push_str(
|
||||
&lines[last_pos.row() - 1][last_pos.column()..fix.patch.location.column()],
|
||||
);
|
||||
output.push_str(&fix.patch.content);
|
||||
}
|
||||
last_pos = fix.patch.end_location;
|
||||
// Add all contents from `last_pos` to `fix.patch.location`.
|
||||
let slice = locator.slice_source_code_range(&Range {
|
||||
location: last_pos,
|
||||
end_location: fix.patch.location,
|
||||
});
|
||||
output.append(&slice);
|
||||
|
||||
// Add the patch itself.
|
||||
output.append(&fix.patch.content);
|
||||
|
||||
// Track that the fix was applied.
|
||||
last_pos = fix.patch.end_location;
|
||||
applied.insert(&fix.patch);
|
||||
fix.applied = true;
|
||||
}
|
||||
|
||||
if last_pos.row() > 0
|
||||
&& (last_pos.row() - 1) < lines.len()
|
||||
&& (last_pos.row() > 0 || last_pos.column() > 0)
|
||||
{
|
||||
output.push_str(&lines[last_pos.row() - 1][last_pos.column()..]);
|
||||
output.push('\n');
|
||||
}
|
||||
if last_pos.row() < lines.len() {
|
||||
for line in &lines[last_pos.row()..] {
|
||||
output.push_str(line);
|
||||
output.push('\n');
|
||||
}
|
||||
}
|
||||
// Add the remaining content.
|
||||
let slice = locator.slice_source_code_at(&last_pos);
|
||||
output.append(&slice);
|
||||
|
||||
output
|
||||
Cow::from(output.finish())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -116,11 +107,13 @@ mod tests {
|
||||
|
||||
use crate::autofix::fixer::apply_fixes;
|
||||
use crate::autofix::{Fix, Patch};
|
||||
use crate::SourceCodeLocator;
|
||||
|
||||
#[test]
|
||||
fn empty_file() -> Result<()> {
|
||||
let mut fixes = vec![];
|
||||
let actual = apply_fixes(fixes.iter_mut(), "");
|
||||
let locator = SourceCodeLocator::new("");
|
||||
let actual = apply_fixes(fixes.iter_mut(), &locator);
|
||||
let expected = "";
|
||||
|
||||
assert_eq!(actual, expected);
|
||||
@@ -138,12 +131,12 @@ mod tests {
|
||||
},
|
||||
applied: false,
|
||||
}];
|
||||
let actual = apply_fixes(
|
||||
fixes.iter_mut(),
|
||||
let locator = SourceCodeLocator::new(
|
||||
"class A(object):
|
||||
...
|
||||
",
|
||||
);
|
||||
let actual = apply_fixes(fixes.iter_mut(), &locator);
|
||||
|
||||
let expected = "class A(Bar):
|
||||
...
|
||||
@@ -164,12 +157,12 @@ mod tests {
|
||||
},
|
||||
applied: false,
|
||||
}];
|
||||
let actual = apply_fixes(
|
||||
fixes.iter_mut(),
|
||||
let locator = SourceCodeLocator::new(
|
||||
"class A(object):
|
||||
...
|
||||
",
|
||||
);
|
||||
let actual = apply_fixes(fixes.iter_mut(), &locator);
|
||||
|
||||
let expected = "class A:
|
||||
...
|
||||
@@ -200,12 +193,12 @@ mod tests {
|
||||
applied: false,
|
||||
},
|
||||
];
|
||||
let actual = apply_fixes(
|
||||
fixes.iter_mut(),
|
||||
let locator = SourceCodeLocator::new(
|
||||
"class A(object, object):
|
||||
...
|
||||
",
|
||||
);
|
||||
let actual = apply_fixes(fixes.iter_mut(), &locator);
|
||||
|
||||
let expected = "class A:
|
||||
...
|
||||
@@ -236,12 +229,12 @@ mod tests {
|
||||
applied: false,
|
||||
},
|
||||
];
|
||||
let actual = apply_fixes(
|
||||
fixes.iter_mut(),
|
||||
let locator = SourceCodeLocator::new(
|
||||
"class A(object):
|
||||
...
|
||||
",
|
||||
);
|
||||
let actual = apply_fixes(fixes.iter_mut(), &locator);
|
||||
|
||||
let expected = "class A:
|
||||
...
|
||||
|
||||
777
src/check_ast.rs
777
src/check_ast.rs
File diff suppressed because it is too large
Load Diff
41
src/check_imports.rs
Normal file
41
src/check_imports.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
//! Lint rules based on import analysis.
|
||||
|
||||
use rustpython_parser::ast::Suite;
|
||||
|
||||
use crate::ast::visitor::Visitor;
|
||||
use crate::autofix::fixer;
|
||||
use crate::checks::Check;
|
||||
use crate::isort;
|
||||
use crate::isort::track::ImportTracker;
|
||||
use crate::settings::Settings;
|
||||
use crate::source_code_locator::SourceCodeLocator;
|
||||
|
||||
fn check_import_blocks(
|
||||
tracker: ImportTracker,
|
||||
locator: &SourceCodeLocator,
|
||||
settings: &Settings,
|
||||
autofix: &fixer::Mode,
|
||||
) -> Vec<Check> {
|
||||
let mut checks = vec![];
|
||||
for block in tracker.into_iter() {
|
||||
if !block.is_empty() {
|
||||
if let Some(check) = isort::plugins::check_imports(block, locator, settings, autofix) {
|
||||
checks.push(check);
|
||||
}
|
||||
}
|
||||
}
|
||||
checks
|
||||
}
|
||||
|
||||
pub fn check_imports(
|
||||
python_ast: &Suite,
|
||||
locator: &SourceCodeLocator,
|
||||
settings: &Settings,
|
||||
autofix: &fixer::Mode,
|
||||
) -> Vec<Check> {
|
||||
let mut tracker = ImportTracker::new();
|
||||
for stmt in python_ast {
|
||||
tracker.visit_stmt(stmt);
|
||||
}
|
||||
check_import_blocks(tracker, locator, settings, autofix)
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use rustpython_parser::ast::Location;
|
||||
|
||||
use crate::ast::types::Range;
|
||||
@@ -11,6 +13,10 @@ use crate::noqa;
|
||||
use crate::noqa::Directive;
|
||||
use crate::settings::Settings;
|
||||
|
||||
// Regex from PEP263
|
||||
static CODING_COMMENT_REGEX: Lazy<Regex> =
|
||||
Lazy::new(|| Regex::new(r"^[ \t\f]*#.*?coding[:=][ \t]*utf-?8").expect("Invalid regex"));
|
||||
|
||||
/// Whether the given line is too long and should be reported.
|
||||
fn should_enforce_line_length(line: &str, length: usize, limit: usize) -> bool {
|
||||
if length > limit {
|
||||
@@ -34,6 +40,7 @@ pub fn check_lines(
|
||||
settings: &Settings,
|
||||
autofix: &fixer::Mode,
|
||||
) {
|
||||
let enforce_unnecessary_coding_comment = settings.enabled.contains(&CheckCode::U009);
|
||||
let enforce_line_too_long = settings.enabled.contains(&CheckCode::E501);
|
||||
let enforce_noqa = settings.enabled.contains(&CheckCode::M001);
|
||||
|
||||
@@ -52,6 +59,30 @@ pub fn check_lines(
|
||||
.map(|lineno| lineno - 1)
|
||||
.unwrap_or(lineno);
|
||||
|
||||
// Enforce unnecessary coding comments (U009).
|
||||
if enforce_unnecessary_coding_comment {
|
||||
if lineno < 2 {
|
||||
// PEP3120 makes utf-8 the default encoding.
|
||||
if CODING_COMMENT_REGEX.is_match(line) {
|
||||
let line_length = line.len();
|
||||
let mut check = Check::new(
|
||||
CheckKind::PEP3120UnnecessaryCodingComment,
|
||||
Range {
|
||||
location: Location::new(lineno + 1, 0),
|
||||
end_location: Location::new(lineno + 1, line_length + 1),
|
||||
},
|
||||
);
|
||||
if autofix.patch() {
|
||||
check.amend(Fix::deletion(
|
||||
Location::new(lineno + 1, 0),
|
||||
Location::new(lineno + 1, line_length + 1),
|
||||
));
|
||||
}
|
||||
line_checks.push(check);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if enforce_noqa {
|
||||
noqa_directives
|
||||
.entry(noqa_lineno)
|
||||
@@ -82,7 +113,7 @@ pub fn check_lines(
|
||||
}
|
||||
}
|
||||
|
||||
// Enforce line length.
|
||||
// Enforce line length violations (E501).
|
||||
if enforce_line_too_long {
|
||||
let line_length = line.chars().count();
|
||||
if should_enforce_line_length(line, line_length, settings.line_length) {
|
||||
|
||||
@@ -2,37 +2,64 @@
|
||||
|
||||
use rustpython_parser::lexer::{LexResult, Tok};
|
||||
|
||||
use crate::autofix::fixer;
|
||||
use crate::checks::{Check, CheckCode};
|
||||
use crate::flake8_quotes::docstring_detection::StateMachine;
|
||||
use crate::lex::docstring_detection::StateMachine;
|
||||
use crate::rules::checks::Context;
|
||||
use crate::source_code_locator::SourceCodeLocator;
|
||||
use crate::{flake8_quotes, pycodestyle, Settings};
|
||||
use crate::{flake8_quotes, pycodestyle, rules, Settings};
|
||||
|
||||
pub fn check_tokens(
|
||||
checks: &mut Vec<Check>,
|
||||
locator: &SourceCodeLocator,
|
||||
tokens: &[LexResult],
|
||||
settings: &Settings,
|
||||
autofix: &fixer::Mode,
|
||||
) {
|
||||
let enforce_invalid_escape_sequence = settings.enabled.contains(&CheckCode::W605);
|
||||
let enforce_ambiguous_unicode_character = settings.enabled.contains(&CheckCode::RUF001)
|
||||
|| settings.enabled.contains(&CheckCode::RUF002)
|
||||
|| settings.enabled.contains(&CheckCode::RUF003);
|
||||
let enforce_quotes = settings.enabled.contains(&CheckCode::Q000)
|
||||
| settings.enabled.contains(&CheckCode::Q001)
|
||||
| settings.enabled.contains(&CheckCode::Q002)
|
||||
| settings.enabled.contains(&CheckCode::Q003);
|
||||
|| settings.enabled.contains(&CheckCode::Q001)
|
||||
|| settings.enabled.contains(&CheckCode::Q002)
|
||||
|| settings.enabled.contains(&CheckCode::Q003);
|
||||
let enforce_invalid_escape_sequence = settings.enabled.contains(&CheckCode::W605);
|
||||
|
||||
let mut state_machine: StateMachine = Default::default();
|
||||
for (start, tok, end) in tokens.iter().flatten() {
|
||||
// W605
|
||||
if enforce_invalid_escape_sequence {
|
||||
if matches!(tok, Tok::String { .. }) {
|
||||
checks.extend(pycodestyle::checks::invalid_escape_sequence(
|
||||
locator, start, end,
|
||||
));
|
||||
let is_docstring = if enforce_ambiguous_unicode_character || enforce_quotes {
|
||||
state_machine.consume(tok)
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
// RUF001, RUF002, RUF003
|
||||
if enforce_ambiguous_unicode_character {
|
||||
if matches!(tok, Tok::String { .. } | Tok::Comment) {
|
||||
for check in rules::checks::ambiguous_unicode_character(
|
||||
locator,
|
||||
start,
|
||||
end,
|
||||
if matches!(tok, Tok::String { .. }) {
|
||||
if is_docstring {
|
||||
Context::Docstring
|
||||
} else {
|
||||
Context::String
|
||||
}
|
||||
} else {
|
||||
Context::Comment
|
||||
},
|
||||
autofix.patch(),
|
||||
) {
|
||||
if settings.enabled.contains(check.kind.code()) {
|
||||
checks.push(check);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// flake8-quotes
|
||||
if enforce_quotes {
|
||||
let is_docstring = state_machine.consume(tok);
|
||||
if matches!(tok, Tok::String { .. }) {
|
||||
if let Some(check) = flake8_quotes::checks::quotes(
|
||||
locator,
|
||||
@@ -47,5 +74,14 @@ pub fn check_tokens(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// W605
|
||||
if enforce_invalid_escape_sequence {
|
||||
if matches!(tok, Tok::String { .. }) {
|
||||
checks.extend(pycodestyle::checks::invalid_escape_sequence(
|
||||
locator, start, end,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
344
src/checks.rs
344
src/checks.rs
@@ -78,13 +78,22 @@ pub enum CheckCode {
|
||||
A003,
|
||||
// flake8-bugbear
|
||||
B002,
|
||||
B003,
|
||||
B004,
|
||||
B005,
|
||||
B006,
|
||||
B007,
|
||||
B008,
|
||||
B009,
|
||||
B011,
|
||||
B013,
|
||||
B014,
|
||||
B015,
|
||||
B016,
|
||||
B017,
|
||||
B018,
|
||||
B025,
|
||||
B026,
|
||||
// flake8-comprehensions
|
||||
C400,
|
||||
C401,
|
||||
@@ -110,6 +119,18 @@ pub enum CheckCode {
|
||||
Q001,
|
||||
Q002,
|
||||
Q003,
|
||||
// flake8-annotations
|
||||
ANN001,
|
||||
ANN002,
|
||||
ANN003,
|
||||
ANN101,
|
||||
ANN102,
|
||||
ANN201,
|
||||
ANN202,
|
||||
ANN204,
|
||||
ANN205,
|
||||
ANN206,
|
||||
ANN401,
|
||||
// pyupgrade
|
||||
U001,
|
||||
U002,
|
||||
@@ -119,6 +140,9 @@ pub enum CheckCode {
|
||||
U006,
|
||||
U007,
|
||||
U008,
|
||||
U009,
|
||||
U010,
|
||||
U011,
|
||||
// pydocstyle
|
||||
D100,
|
||||
D101,
|
||||
@@ -180,6 +204,12 @@ pub enum CheckCode {
|
||||
N816,
|
||||
N817,
|
||||
N818,
|
||||
// isort
|
||||
I001,
|
||||
// Ruff
|
||||
RUF001,
|
||||
RUF002,
|
||||
RUF003,
|
||||
// Meta
|
||||
M001,
|
||||
}
|
||||
@@ -187,8 +217,8 @@ pub enum CheckCode {
|
||||
#[derive(EnumIter, Debug, PartialEq, Eq)]
|
||||
pub enum CheckCategory {
|
||||
Pyflakes,
|
||||
PycodestyleError,
|
||||
PycodestyleWarning,
|
||||
Pycodestyle,
|
||||
Isort,
|
||||
Pydocstyle,
|
||||
Pyupgrade,
|
||||
PEP8Naming,
|
||||
@@ -197,26 +227,57 @@ pub enum CheckCategory {
|
||||
Flake8Builtins,
|
||||
Flake8Print,
|
||||
Flake8Quotes,
|
||||
Flake8Annotations,
|
||||
Ruff,
|
||||
Meta,
|
||||
}
|
||||
|
||||
impl CheckCategory {
|
||||
pub fn title(&self) -> &'static str {
|
||||
match self {
|
||||
CheckCategory::PycodestyleError => "pycodestyle (error)",
|
||||
CheckCategory::PycodestyleWarning => "pycodestyle (warning)",
|
||||
CheckCategory::Pycodestyle => "pycodestyle",
|
||||
CheckCategory::Pyflakes => "Pyflakes",
|
||||
CheckCategory::Isort => "isort",
|
||||
CheckCategory::Flake8Builtins => "flake8-builtins",
|
||||
CheckCategory::Flake8Bugbear => "flake8-bugbear",
|
||||
CheckCategory::Flake8Comprehensions => "flake8-comprehensions",
|
||||
CheckCategory::Flake8Print => "flake8-print",
|
||||
CheckCategory::Flake8Quotes => "flake8-quotes",
|
||||
CheckCategory::Flake8Annotations => "flake8-annotations",
|
||||
CheckCategory::Pyupgrade => "pyupgrade",
|
||||
CheckCategory::Pydocstyle => "pydocstyle",
|
||||
CheckCategory::PEP8Naming => "pep8-naming",
|
||||
CheckCategory::Ruff => "Ruff-specific rules",
|
||||
CheckCategory::Meta => "Meta rules",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn url(&self) -> Option<&'static str> {
|
||||
match self {
|
||||
CheckCategory::Pycodestyle => Some("https://pypi.org/project/pycodestyle/2.9.1/"),
|
||||
CheckCategory::Pyflakes => Some("https://pypi.org/project/pyflakes/2.5.0/"),
|
||||
CheckCategory::Isort => Some("https://pypi.org/project/isort/5.10.1/"),
|
||||
CheckCategory::Flake8Builtins => {
|
||||
Some("https://pypi.org/project/flake8-builtins/2.0.1/")
|
||||
}
|
||||
CheckCategory::Flake8Bugbear => {
|
||||
Some("https://pypi.org/project/flake8-bugbear/22.10.27/")
|
||||
}
|
||||
CheckCategory::Flake8Comprehensions => {
|
||||
Some("https://pypi.org/project/flake8-comprehensions/3.10.1/")
|
||||
}
|
||||
CheckCategory::Flake8Print => Some("https://pypi.org/project/flake8-print/5.0.0/"),
|
||||
CheckCategory::Flake8Quotes => Some("https://pypi.org/project/flake8-quotes/3.3.1/"),
|
||||
CheckCategory::Flake8Annotations => {
|
||||
Some("https://pypi.org/project/flake8-annotations/2.9.1/")
|
||||
}
|
||||
CheckCategory::Pyupgrade => Some("https://pypi.org/project/pyupgrade/3.2.0/"),
|
||||
CheckCategory::Pydocstyle => Some("https://pypi.org/project/pydocstyle/6.1.1/"),
|
||||
CheckCategory::PEP8Naming => Some("https://pypi.org/project/pep8-naming/0.13.2/"),
|
||||
CheckCategory::Ruff => None,
|
||||
CheckCategory::Meta => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
@@ -225,6 +286,7 @@ pub enum LintSource {
|
||||
FileSystem,
|
||||
Lines,
|
||||
Tokens,
|
||||
Imports,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
@@ -288,13 +350,22 @@ pub enum CheckKind {
|
||||
BuiltinAttributeShadowing(String),
|
||||
// flake8-bugbear
|
||||
UnaryPrefixIncrement,
|
||||
AssignmentToOsEnviron,
|
||||
UnreliableCallableCheck,
|
||||
StripWithMultiCharacters,
|
||||
MutableArgumentDefault,
|
||||
UnusedLoopControlVariable(String),
|
||||
FunctionCallArgumentDefault,
|
||||
GetAttrWithConstant,
|
||||
DoNotAssertFalse,
|
||||
RedundantTupleInExceptionHandler(String),
|
||||
DuplicateHandlerException(Vec<String>),
|
||||
UselessComparison,
|
||||
CannotRaiseLiteral,
|
||||
NoAssertRaisesException,
|
||||
UselessExpression,
|
||||
DuplicateTryBlockException(String),
|
||||
StarArgUnpackingAfterKeywordArg,
|
||||
// flake8-comprehensions
|
||||
UnnecessaryGeneratorList,
|
||||
UnnecessaryGeneratorSet,
|
||||
@@ -320,6 +391,18 @@ pub enum CheckKind {
|
||||
BadQuotesMultilineString(Quote),
|
||||
BadQuotesDocstring(Quote),
|
||||
AvoidQuoteEscape,
|
||||
// flake8-annotations
|
||||
MissingTypeFunctionArgument(String),
|
||||
MissingTypeArgs(String),
|
||||
MissingTypeKwargs(String),
|
||||
MissingTypeSelf(String),
|
||||
MissingTypeCls(String),
|
||||
MissingReturnTypePublicFunction(String),
|
||||
MissingReturnTypePrivateFunction(String),
|
||||
MissingReturnTypeMagicMethod(String),
|
||||
MissingReturnTypeStaticMethod(String),
|
||||
MissingReturnTypeClassMethod(String),
|
||||
DynamicallyTypedExpression(String),
|
||||
// pyupgrade
|
||||
TypeOfPrimitive(Primitive),
|
||||
UnnecessaryAbspath,
|
||||
@@ -329,6 +412,9 @@ pub enum CheckKind {
|
||||
UsePEP585Annotation(String),
|
||||
UsePEP604Annotation,
|
||||
SuperCallWithParameters,
|
||||
PEP3120UnnecessaryCodingComment,
|
||||
UnnecessaryFutureImport(String),
|
||||
UnnecessaryLRUCacheParams,
|
||||
// pydocstyle
|
||||
BlankLineAfterLastSection(String),
|
||||
BlankLineAfterSection(String),
|
||||
@@ -390,6 +476,12 @@ pub enum CheckKind {
|
||||
MixedCaseVariableInGlobalScope(String),
|
||||
CamelcaseImportedAsAcronym(String, String),
|
||||
ErrorSuffixOnExceptionName(String),
|
||||
// isort
|
||||
UnsortedImports,
|
||||
// Ruff
|
||||
AmbiguousUnicodeCharacterString(char, char),
|
||||
AmbiguousUnicodeCharacterDocstring(char, char),
|
||||
AmbiguousUnicodeCharacterComment(char, char),
|
||||
// Meta
|
||||
UnusedNOQA(Option<Vec<String>>),
|
||||
}
|
||||
@@ -399,13 +491,19 @@ impl CheckCode {
|
||||
/// physical lines).
|
||||
pub fn lint_source(&self) -> &'static LintSource {
|
||||
match self {
|
||||
CheckCode::E501 | CheckCode::W292 | CheckCode::M001 => &LintSource::Lines,
|
||||
CheckCode::W605
|
||||
| CheckCode::Q000
|
||||
CheckCode::E501 | CheckCode::W292 | CheckCode::M001 | CheckCode::U009 => {
|
||||
&LintSource::Lines
|
||||
}
|
||||
CheckCode::Q000
|
||||
| CheckCode::Q001
|
||||
| CheckCode::Q002
|
||||
| CheckCode::Q003 => &LintSource::Tokens,
|
||||
| CheckCode::Q003
|
||||
| CheckCode::W605
|
||||
| CheckCode::RUF001
|
||||
| CheckCode::RUF002
|
||||
| CheckCode::RUF003 => &LintSource::Tokens,
|
||||
CheckCode::E902 => &LintSource::FileSystem,
|
||||
CheckCode::I001 => &LintSource::Imports,
|
||||
_ => &LintSource::AST,
|
||||
}
|
||||
}
|
||||
@@ -468,15 +566,24 @@ impl CheckCode {
|
||||
CheckCode::A003 => CheckKind::BuiltinAttributeShadowing("...".to_string()),
|
||||
// flake8-bugbear
|
||||
CheckCode::B002 => CheckKind::UnaryPrefixIncrement,
|
||||
CheckCode::B003 => CheckKind::AssignmentToOsEnviron,
|
||||
CheckCode::B004 => CheckKind::UnreliableCallableCheck,
|
||||
CheckCode::B005 => CheckKind::StripWithMultiCharacters,
|
||||
CheckCode::B006 => CheckKind::MutableArgumentDefault,
|
||||
CheckCode::B007 => CheckKind::UnusedLoopControlVariable("i".to_string()),
|
||||
CheckCode::B008 => CheckKind::FunctionCallArgumentDefault,
|
||||
CheckCode::B009 => CheckKind::GetAttrWithConstant,
|
||||
CheckCode::B011 => CheckKind::DoNotAssertFalse,
|
||||
CheckCode::B013 => {
|
||||
CheckKind::RedundantTupleInExceptionHandler("ValueError".to_string())
|
||||
}
|
||||
CheckCode::B014 => CheckKind::DuplicateHandlerException(vec!["ValueError".to_string()]),
|
||||
CheckCode::B015 => CheckKind::UselessComparison,
|
||||
CheckCode::B016 => CheckKind::CannotRaiseLiteral,
|
||||
CheckCode::B017 => CheckKind::NoAssertRaisesException,
|
||||
CheckCode::B018 => CheckKind::UselessExpression,
|
||||
CheckCode::B025 => CheckKind::DuplicateTryBlockException("Exception".to_string()),
|
||||
CheckCode::B026 => CheckKind::StarArgUnpackingAfterKeywordArg,
|
||||
// flake8-comprehensions
|
||||
CheckCode::C400 => CheckKind::UnnecessaryGeneratorList,
|
||||
CheckCode::C401 => CheckKind::UnnecessaryGeneratorSet,
|
||||
@@ -515,6 +622,18 @@ impl CheckCode {
|
||||
CheckCode::Q001 => CheckKind::BadQuotesMultilineString(Quote::Double),
|
||||
CheckCode::Q002 => CheckKind::BadQuotesDocstring(Quote::Double),
|
||||
CheckCode::Q003 => CheckKind::AvoidQuoteEscape,
|
||||
// flake8-annotations
|
||||
CheckCode::ANN001 => CheckKind::MissingTypeFunctionArgument("...".to_string()),
|
||||
CheckCode::ANN002 => CheckKind::MissingTypeArgs("...".to_string()),
|
||||
CheckCode::ANN003 => CheckKind::MissingTypeKwargs("...".to_string()),
|
||||
CheckCode::ANN101 => CheckKind::MissingTypeSelf("...".to_string()),
|
||||
CheckCode::ANN102 => CheckKind::MissingTypeCls("...".to_string()),
|
||||
CheckCode::ANN201 => CheckKind::MissingReturnTypePublicFunction("...".to_string()),
|
||||
CheckCode::ANN202 => CheckKind::MissingReturnTypePrivateFunction("...".to_string()),
|
||||
CheckCode::ANN204 => CheckKind::MissingReturnTypeMagicMethod("...".to_string()),
|
||||
CheckCode::ANN205 => CheckKind::MissingReturnTypeStaticMethod("...".to_string()),
|
||||
CheckCode::ANN206 => CheckKind::MissingReturnTypeClassMethod("...".to_string()),
|
||||
CheckCode::ANN401 => CheckKind::DynamicallyTypedExpression("...".to_string()),
|
||||
// pyupgrade
|
||||
CheckCode::U001 => CheckKind::UselessMetaclassType,
|
||||
CheckCode::U002 => CheckKind::UnnecessaryAbspath,
|
||||
@@ -527,6 +646,9 @@ impl CheckCode {
|
||||
CheckCode::U006 => CheckKind::UsePEP585Annotation("List".to_string()),
|
||||
CheckCode::U007 => CheckKind::UsePEP604Annotation,
|
||||
CheckCode::U008 => CheckKind::SuperCallWithParameters,
|
||||
CheckCode::U009 => CheckKind::PEP3120UnnecessaryCodingComment,
|
||||
CheckCode::U010 => CheckKind::UnnecessaryFutureImport("...".to_string()),
|
||||
CheckCode::U011 => CheckKind::UnnecessaryLRUCacheParams,
|
||||
// pydocstyle
|
||||
CheckCode::D100 => CheckKind::PublicModule,
|
||||
CheckCode::D101 => CheckKind::PublicClass,
|
||||
@@ -604,6 +726,12 @@ impl CheckCode {
|
||||
CheckKind::CamelcaseImportedAsAcronym("...".to_string(), "...".to_string())
|
||||
}
|
||||
CheckCode::N818 => CheckKind::ErrorSuffixOnExceptionName("...".to_string()),
|
||||
// isort
|
||||
CheckCode::I001 => CheckKind::UnsortedImports,
|
||||
// Ruff
|
||||
CheckCode::RUF001 => CheckKind::AmbiguousUnicodeCharacterString('𝐁', 'B'),
|
||||
CheckCode::RUF002 => CheckKind::AmbiguousUnicodeCharacterDocstring('𝐁', 'B'),
|
||||
CheckCode::RUF003 => CheckKind::AmbiguousUnicodeCharacterComment('𝐁', 'B'),
|
||||
// Meta
|
||||
CheckCode::M001 => CheckKind::UnusedNOQA(None),
|
||||
}
|
||||
@@ -611,22 +739,22 @@ impl CheckCode {
|
||||
|
||||
pub fn category(&self) -> CheckCategory {
|
||||
match self {
|
||||
CheckCode::E402 => CheckCategory::PycodestyleError,
|
||||
CheckCode::E501 => CheckCategory::PycodestyleError,
|
||||
CheckCode::E711 => CheckCategory::PycodestyleError,
|
||||
CheckCode::E712 => CheckCategory::PycodestyleError,
|
||||
CheckCode::E713 => CheckCategory::PycodestyleError,
|
||||
CheckCode::E714 => CheckCategory::PycodestyleError,
|
||||
CheckCode::E721 => CheckCategory::PycodestyleError,
|
||||
CheckCode::E722 => CheckCategory::PycodestyleError,
|
||||
CheckCode::E731 => CheckCategory::PycodestyleError,
|
||||
CheckCode::E741 => CheckCategory::PycodestyleError,
|
||||
CheckCode::E742 => CheckCategory::PycodestyleError,
|
||||
CheckCode::E743 => CheckCategory::PycodestyleError,
|
||||
CheckCode::E902 => CheckCategory::PycodestyleError,
|
||||
CheckCode::E999 => CheckCategory::PycodestyleError,
|
||||
CheckCode::W292 => CheckCategory::PycodestyleWarning,
|
||||
CheckCode::W605 => CheckCategory::PycodestyleWarning,
|
||||
CheckCode::E402 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E501 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E711 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E712 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E713 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E714 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E721 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E722 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E731 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E741 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E742 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E743 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E902 => CheckCategory::Pycodestyle,
|
||||
CheckCode::E999 => CheckCategory::Pycodestyle,
|
||||
CheckCode::W292 => CheckCategory::Pycodestyle,
|
||||
CheckCode::W605 => CheckCategory::Pycodestyle,
|
||||
CheckCode::F401 => CheckCategory::Pyflakes,
|
||||
CheckCode::F402 => CheckCategory::Pyflakes,
|
||||
CheckCode::F403 => CheckCategory::Pyflakes,
|
||||
@@ -659,13 +787,22 @@ impl CheckCode {
|
||||
CheckCode::A002 => CheckCategory::Flake8Builtins,
|
||||
CheckCode::A003 => CheckCategory::Flake8Builtins,
|
||||
CheckCode::B002 => CheckCategory::Flake8Bugbear,
|
||||
CheckCode::B003 => CheckCategory::Flake8Bugbear,
|
||||
CheckCode::B004 => CheckCategory::Flake8Bugbear,
|
||||
CheckCode::B005 => CheckCategory::Flake8Bugbear,
|
||||
CheckCode::B006 => CheckCategory::Flake8Bugbear,
|
||||
CheckCode::B007 => CheckCategory::Flake8Bugbear,
|
||||
CheckCode::B008 => CheckCategory::Flake8Bugbear,
|
||||
CheckCode::B009 => CheckCategory::Flake8Bugbear,
|
||||
CheckCode::B011 => CheckCategory::Flake8Bugbear,
|
||||
CheckCode::B013 => CheckCategory::Flake8Bugbear,
|
||||
CheckCode::B014 => CheckCategory::Flake8Bugbear,
|
||||
CheckCode::B015 => CheckCategory::Flake8Bugbear,
|
||||
CheckCode::B016 => CheckCategory::Flake8Bugbear,
|
||||
CheckCode::B017 => CheckCategory::Flake8Bugbear,
|
||||
CheckCode::B018 => CheckCategory::Flake8Bugbear,
|
||||
CheckCode::B025 => CheckCategory::Flake8Bugbear,
|
||||
CheckCode::B026 => CheckCategory::Flake8Bugbear,
|
||||
CheckCode::C400 => CheckCategory::Flake8Comprehensions,
|
||||
CheckCode::C401 => CheckCategory::Flake8Comprehensions,
|
||||
CheckCode::C402 => CheckCategory::Flake8Comprehensions,
|
||||
@@ -688,6 +825,17 @@ impl CheckCode {
|
||||
CheckCode::Q001 => CheckCategory::Flake8Quotes,
|
||||
CheckCode::Q002 => CheckCategory::Flake8Quotes,
|
||||
CheckCode::Q003 => CheckCategory::Flake8Quotes,
|
||||
CheckCode::ANN001 => CheckCategory::Flake8Annotations,
|
||||
CheckCode::ANN002 => CheckCategory::Flake8Annotations,
|
||||
CheckCode::ANN003 => CheckCategory::Flake8Annotations,
|
||||
CheckCode::ANN101 => CheckCategory::Flake8Annotations,
|
||||
CheckCode::ANN102 => CheckCategory::Flake8Annotations,
|
||||
CheckCode::ANN201 => CheckCategory::Flake8Annotations,
|
||||
CheckCode::ANN202 => CheckCategory::Flake8Annotations,
|
||||
CheckCode::ANN204 => CheckCategory::Flake8Annotations,
|
||||
CheckCode::ANN205 => CheckCategory::Flake8Annotations,
|
||||
CheckCode::ANN206 => CheckCategory::Flake8Annotations,
|
||||
CheckCode::ANN401 => CheckCategory::Flake8Annotations,
|
||||
CheckCode::U001 => CheckCategory::Pyupgrade,
|
||||
CheckCode::U002 => CheckCategory::Pyupgrade,
|
||||
CheckCode::U003 => CheckCategory::Pyupgrade,
|
||||
@@ -696,6 +844,9 @@ impl CheckCode {
|
||||
CheckCode::U006 => CheckCategory::Pyupgrade,
|
||||
CheckCode::U007 => CheckCategory::Pyupgrade,
|
||||
CheckCode::U008 => CheckCategory::Pyupgrade,
|
||||
CheckCode::U009 => CheckCategory::Pyupgrade,
|
||||
CheckCode::U010 => CheckCategory::Pyupgrade,
|
||||
CheckCode::U011 => CheckCategory::Pyupgrade,
|
||||
CheckCode::D100 => CheckCategory::Pydocstyle,
|
||||
CheckCode::D101 => CheckCategory::Pydocstyle,
|
||||
CheckCode::D102 => CheckCategory::Pydocstyle,
|
||||
@@ -755,6 +906,10 @@ impl CheckCode {
|
||||
CheckCode::N816 => CheckCategory::PEP8Naming,
|
||||
CheckCode::N817 => CheckCategory::PEP8Naming,
|
||||
CheckCode::N818 => CheckCategory::PEP8Naming,
|
||||
CheckCode::I001 => CheckCategory::Isort,
|
||||
CheckCode::RUF001 => CheckCategory::Ruff,
|
||||
CheckCode::RUF002 => CheckCategory::Ruff,
|
||||
CheckCode::RUF003 => CheckCategory::Ruff,
|
||||
CheckCode::M001 => CheckCategory::Meta,
|
||||
}
|
||||
}
|
||||
@@ -816,13 +971,22 @@ impl CheckKind {
|
||||
CheckKind::BuiltinAttributeShadowing(_) => &CheckCode::A003,
|
||||
// flake8-bugbear
|
||||
CheckKind::UnaryPrefixIncrement => &CheckCode::B002,
|
||||
CheckKind::AssignmentToOsEnviron => &CheckCode::B003,
|
||||
CheckKind::UnreliableCallableCheck => &CheckCode::B004,
|
||||
CheckKind::StripWithMultiCharacters => &CheckCode::B005,
|
||||
CheckKind::MutableArgumentDefault => &CheckCode::B006,
|
||||
CheckKind::UnusedLoopControlVariable(_) => &CheckCode::B007,
|
||||
CheckKind::FunctionCallArgumentDefault => &CheckCode::B008,
|
||||
CheckKind::GetAttrWithConstant => &CheckCode::B009,
|
||||
CheckKind::DoNotAssertFalse => &CheckCode::B011,
|
||||
CheckKind::RedundantTupleInExceptionHandler(_) => &CheckCode::B013,
|
||||
CheckKind::DuplicateHandlerException(_) => &CheckCode::B014,
|
||||
CheckKind::UselessComparison => &CheckCode::B015,
|
||||
CheckKind::CannotRaiseLiteral => &CheckCode::B016,
|
||||
CheckKind::NoAssertRaisesException => &CheckCode::B017,
|
||||
CheckKind::UselessExpression => &CheckCode::B018,
|
||||
CheckKind::DuplicateTryBlockException(_) => &CheckCode::B025,
|
||||
CheckKind::StarArgUnpackingAfterKeywordArg => &CheckCode::B026,
|
||||
// flake8-comprehensions
|
||||
CheckKind::UnnecessaryGeneratorList => &CheckCode::C400,
|
||||
CheckKind::UnnecessaryGeneratorSet => &CheckCode::C401,
|
||||
@@ -848,6 +1012,18 @@ impl CheckKind {
|
||||
CheckKind::BadQuotesMultilineString(_) => &CheckCode::Q001,
|
||||
CheckKind::BadQuotesDocstring(_) => &CheckCode::Q002,
|
||||
CheckKind::AvoidQuoteEscape => &CheckCode::Q003,
|
||||
// flake8-annotations
|
||||
CheckKind::MissingTypeFunctionArgument(_) => &CheckCode::ANN001,
|
||||
CheckKind::MissingTypeArgs(_) => &CheckCode::ANN002,
|
||||
CheckKind::MissingTypeKwargs(_) => &CheckCode::ANN003,
|
||||
CheckKind::MissingTypeSelf(_) => &CheckCode::ANN101,
|
||||
CheckKind::MissingTypeCls(_) => &CheckCode::ANN102,
|
||||
CheckKind::MissingReturnTypePublicFunction(_) => &CheckCode::ANN201,
|
||||
CheckKind::MissingReturnTypePrivateFunction(_) => &CheckCode::ANN202,
|
||||
CheckKind::MissingReturnTypeMagicMethod(_) => &CheckCode::ANN204,
|
||||
CheckKind::MissingReturnTypeStaticMethod(_) => &CheckCode::ANN205,
|
||||
CheckKind::MissingReturnTypeClassMethod(_) => &CheckCode::ANN206,
|
||||
CheckKind::DynamicallyTypedExpression(_) => &CheckCode::ANN401,
|
||||
// pyupgrade
|
||||
CheckKind::TypeOfPrimitive(_) => &CheckCode::U003,
|
||||
CheckKind::UnnecessaryAbspath => &CheckCode::U002,
|
||||
@@ -857,6 +1033,9 @@ impl CheckKind {
|
||||
CheckKind::UsePEP604Annotation => &CheckCode::U007,
|
||||
CheckKind::UselessObjectInheritance(_) => &CheckCode::U004,
|
||||
CheckKind::SuperCallWithParameters => &CheckCode::U008,
|
||||
CheckKind::PEP3120UnnecessaryCodingComment => &CheckCode::U009,
|
||||
CheckKind::UnnecessaryFutureImport(_) => &CheckCode::U010,
|
||||
CheckKind::UnnecessaryLRUCacheParams => &CheckCode::U011,
|
||||
// pydocstyle
|
||||
CheckKind::BlankLineAfterLastSection(_) => &CheckCode::D413,
|
||||
CheckKind::BlankLineAfterSection(_) => &CheckCode::D410,
|
||||
@@ -918,6 +1097,12 @@ impl CheckKind {
|
||||
CheckKind::MixedCaseVariableInGlobalScope(..) => &CheckCode::N816,
|
||||
CheckKind::CamelcaseImportedAsAcronym(..) => &CheckCode::N817,
|
||||
CheckKind::ErrorSuffixOnExceptionName(..) => &CheckCode::N818,
|
||||
// isort
|
||||
CheckKind::UnsortedImports => &CheckCode::I001,
|
||||
// Ruff
|
||||
CheckKind::AmbiguousUnicodeCharacterString(..) => &CheckCode::RUF001,
|
||||
CheckKind::AmbiguousUnicodeCharacterDocstring(..) => &CheckCode::RUF002,
|
||||
CheckKind::AmbiguousUnicodeCharacterComment(..) => &CheckCode::RUF003,
|
||||
// Meta
|
||||
CheckKind::UnusedNOQA(_) => &CheckCode::M001,
|
||||
}
|
||||
@@ -1078,6 +1263,16 @@ impl CheckKind {
|
||||
increment. Writing `++n` is equivalent to \
|
||||
`+(+(n))`, which equals `n`. You meant `n += 1`."
|
||||
.to_string(),
|
||||
CheckKind::AssignmentToOsEnviron => {
|
||||
"Assigning to `os.environ` doesn't clear the environment.".to_string()
|
||||
}
|
||||
CheckKind::UnreliableCallableCheck => " Using `hasattr(x, '__call__')` to test if x \
|
||||
is callable is unreliable. Use `callable(x)` \
|
||||
for consistent results."
|
||||
.to_string(),
|
||||
CheckKind::StripWithMultiCharacters => "Using `.strip()` with multi-character strings \
|
||||
is misleading the reader."
|
||||
.to_string(),
|
||||
CheckKind::MutableArgumentDefault => {
|
||||
"Do not use mutable data structures for argument defaults.".to_string()
|
||||
}
|
||||
@@ -1085,6 +1280,13 @@ impl CheckKind {
|
||||
"Loop control variable `{name}` not used within the loop body. If this is \
|
||||
intended, start the name with an underscore."
|
||||
),
|
||||
CheckKind::FunctionCallArgumentDefault => {
|
||||
"Do not perform function calls in argument defaults.".to_string()
|
||||
}
|
||||
CheckKind::GetAttrWithConstant => "Do not call `getattr` with a constant attribute \
|
||||
value, it is not any safer than normal property \
|
||||
access."
|
||||
.to_string(),
|
||||
CheckKind::DoNotAssertFalse => "Do not `assert False` (`python -O` removes these \
|
||||
calls), raise `AssertionError()`"
|
||||
.to_string(),
|
||||
@@ -1094,6 +1296,13 @@ impl CheckKind {
|
||||
`except ({name},):`."
|
||||
)
|
||||
}
|
||||
CheckKind::UselessComparison => "Pointless comparison. This comparison does nothing \
|
||||
but waste CPU instructions. Either prepend `assert` \
|
||||
or remove it."
|
||||
.to_string(),
|
||||
CheckKind::CannotRaiseLiteral => "Cannot raise a literal. Did you intend to return it \
|
||||
or raise an Exception?"
|
||||
.to_string(),
|
||||
CheckKind::DuplicateHandlerException(names) => {
|
||||
if names.len() == 1 {
|
||||
let name = &names[0];
|
||||
@@ -1110,9 +1319,19 @@ impl CheckKind {
|
||||
`assertRaisesRegex`, or use the context manager form of `assertRaises`."
|
||||
.to_string()
|
||||
}
|
||||
CheckKind::UselessExpression => {
|
||||
"Found useless expression. Either assign it to a variable or remove it.".to_string()
|
||||
}
|
||||
CheckKind::DuplicateTryBlockException(name) => {
|
||||
format!("try-except block with duplicate exception `{name}`")
|
||||
}
|
||||
CheckKind::StarArgUnpackingAfterKeywordArg => {
|
||||
"Star-arg unpacking after a keyword argument is strongly discouraged, because it \
|
||||
only works when the keyword parameter is declared after all parameters supplied \
|
||||
by the unpacked sequence, and this change of ordering can surprise and mislead \
|
||||
readers."
|
||||
.to_string()
|
||||
}
|
||||
// flake8-comprehensions
|
||||
CheckKind::UnnecessaryGeneratorList => {
|
||||
"Unnecessary generator (rewrite as a `list` comprehension)".to_string()
|
||||
@@ -1213,6 +1432,38 @@ impl CheckKind {
|
||||
CheckKind::AvoidQuoteEscape => {
|
||||
"Change outer quotes to avoid escaping inner quotes".to_string()
|
||||
}
|
||||
// flake8-annotations
|
||||
CheckKind::MissingTypeFunctionArgument(name) => {
|
||||
format!("Missing type annotation for function argument `{name}`")
|
||||
}
|
||||
CheckKind::MissingTypeArgs(name) => format!("Missing type annotation for `*{name}`"),
|
||||
CheckKind::MissingTypeKwargs(name) => {
|
||||
format!("Missing type annotation for `**{name}`")
|
||||
}
|
||||
CheckKind::MissingTypeSelf(name) => {
|
||||
format!("Missing type annotation for `{name}` in method")
|
||||
}
|
||||
CheckKind::MissingTypeCls(name) => {
|
||||
format!("Missing type annotation for `{name}` in classmethod")
|
||||
}
|
||||
CheckKind::MissingReturnTypePublicFunction(name) => {
|
||||
format!("Missing return type annotation for public function `{name}`")
|
||||
}
|
||||
CheckKind::MissingReturnTypePrivateFunction(name) => {
|
||||
format!("Missing return type annotation for private function `{name}`")
|
||||
}
|
||||
CheckKind::MissingReturnTypeMagicMethod(name) => {
|
||||
format!("Missing return type annotation for magic method `{name}`")
|
||||
}
|
||||
CheckKind::MissingReturnTypeStaticMethod(name) => {
|
||||
format!("Missing return type annotation for staticmethod `{name}`")
|
||||
}
|
||||
CheckKind::MissingReturnTypeClassMethod(name) => {
|
||||
format!("Missing return type annotation for classmethod `{name}`")
|
||||
}
|
||||
CheckKind::DynamicallyTypedExpression(name) => {
|
||||
format!("Dynamically typed expressions (typing.Any) are disallowed in `{name}`")
|
||||
}
|
||||
// pyupgrade
|
||||
CheckKind::TypeOfPrimitive(primitive) => {
|
||||
format!("Use `{}` instead of `type(...)`", primitive.builtin())
|
||||
@@ -1238,6 +1489,12 @@ impl CheckKind {
|
||||
CheckKind::SuperCallWithParameters => {
|
||||
"Use `super()` instead of `super(__class__, self)`".to_string()
|
||||
}
|
||||
CheckKind::UnnecessaryFutureImport(name) => {
|
||||
format!("Unnessary __future__ import `{name}` for target Python version")
|
||||
}
|
||||
CheckKind::UnnecessaryLRUCacheParams => {
|
||||
"Unnessary parameters to functools.lru_cache".to_string()
|
||||
}
|
||||
// pydocstyle
|
||||
CheckKind::FitsOnOneLine => "One-line docstring should fit on one line".to_string(),
|
||||
CheckKind::BlankLineAfterSummary => {
|
||||
@@ -1398,6 +1655,30 @@ impl CheckKind {
|
||||
CheckKind::ErrorSuffixOnExceptionName(name) => {
|
||||
format!("Exception name `{name}` should be named with an Error suffix")
|
||||
}
|
||||
CheckKind::PEP3120UnnecessaryCodingComment => {
|
||||
"utf-8 encoding declaration is unnecessary".to_string()
|
||||
}
|
||||
// isort
|
||||
CheckKind::UnsortedImports => "Import block is un-sorted or un-formatted".to_string(),
|
||||
// Ruff
|
||||
CheckKind::AmbiguousUnicodeCharacterString(confusable, representant) => {
|
||||
format!(
|
||||
"String contains ambiguous unicode character '{confusable}' (did you mean \
|
||||
'{representant}'?)"
|
||||
)
|
||||
}
|
||||
CheckKind::AmbiguousUnicodeCharacterDocstring(confusable, representant) => {
|
||||
format!(
|
||||
"Docstring contains ambiguous unicode character '{confusable}' (did you mean \
|
||||
'{representant}'?)"
|
||||
)
|
||||
}
|
||||
CheckKind::AmbiguousUnicodeCharacterComment(confusable, representant) => {
|
||||
format!(
|
||||
"Comment contains ambiguous unicode character '{confusable}' (did you mean \
|
||||
'{representant}'?)"
|
||||
)
|
||||
}
|
||||
// Meta
|
||||
CheckKind::UnusedNOQA(codes) => match codes {
|
||||
None => "Unused `noqa` directive".to_string(),
|
||||
@@ -1431,6 +1712,9 @@ impl CheckKind {
|
||||
CheckKind::NoAssertRaisesException => {
|
||||
"`assertRaises(Exception):` should be considered evil.".to_string()
|
||||
}
|
||||
CheckKind::StarArgUnpackingAfterKeywordArg => {
|
||||
"Star-arg unpacking after a keyword argument is strongly discouraged.".to_string()
|
||||
}
|
||||
_ => self.body(),
|
||||
}
|
||||
}
|
||||
@@ -1439,7 +1723,9 @@ impl CheckKind {
|
||||
pub fn fixable(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
CheckKind::BlankLineAfterLastSection(_)
|
||||
CheckKind::AmbiguousUnicodeCharacterString(_, _)
|
||||
| CheckKind::AmbiguousUnicodeCharacterDocstring(_, _)
|
||||
| CheckKind::BlankLineAfterLastSection(_)
|
||||
| CheckKind::BlankLineAfterSection(_)
|
||||
| CheckKind::BlankLineAfterSummary
|
||||
| CheckKind::BlankLineBeforeSection(_)
|
||||
@@ -1448,6 +1734,7 @@ impl CheckKind {
|
||||
| CheckKind::DeprecatedUnittestAlias(_, _)
|
||||
| CheckKind::DoNotAssertFalse
|
||||
| CheckKind::DuplicateHandlerException(_)
|
||||
| CheckKind::IsLiteral
|
||||
| CheckKind::NewLineAfterLastParagraph
|
||||
| CheckKind::NewLineAfterSectionName(_)
|
||||
| CheckKind::NoBlankLineAfterFunction(_)
|
||||
@@ -1459,8 +1746,10 @@ impl CheckKind {
|
||||
| CheckKind::NoUnderIndentation
|
||||
| CheckKind::OneBlankLineAfterClass(_)
|
||||
| CheckKind::OneBlankLineBeforeClass(_)
|
||||
| CheckKind::PEP3120UnnecessaryCodingComment
|
||||
| CheckKind::PPrintFound
|
||||
| CheckKind::PrintFound
|
||||
| CheckKind::RaiseNotImplemented
|
||||
| CheckKind::SectionNameEndsInColon(_)
|
||||
| CheckKind::SectionNotOverIndented(_)
|
||||
| CheckKind::SectionUnderlineAfterName(_)
|
||||
@@ -1470,14 +1759,19 @@ impl CheckKind {
|
||||
| CheckKind::TypeOfPrimitive(_)
|
||||
| CheckKind::UnnecessaryAbspath
|
||||
| CheckKind::UnnecessaryCollectionCall(_)
|
||||
| CheckKind::UnnecessaryComprehension(_)
|
||||
| CheckKind::UnnecessaryGeneratorDict
|
||||
| CheckKind::UnnecessaryGeneratorList
|
||||
| CheckKind::UnnecessaryGeneratorSet
|
||||
| CheckKind::UnnecessaryLRUCacheParams
|
||||
| CheckKind::UnnecessaryListCall
|
||||
| CheckKind::UnnecessaryListComprehensionDict
|
||||
| CheckKind::UnnecessaryListComprehensionSet
|
||||
| CheckKind::UnnecessaryLiteralDict(_)
|
||||
| CheckKind::UnnecessaryLiteralSet(_)
|
||||
| CheckKind::UnnecessaryLiteralWithinListCall(_)
|
||||
| CheckKind::UnnecessaryLiteralWithinTupleCall(_)
|
||||
| CheckKind::UnsortedImports
|
||||
| CheckKind::UnusedImport(_, false)
|
||||
| CheckKind::UnusedLoopControlVariable(_)
|
||||
| CheckKind::UnusedNOQA(_)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
//! File automatically generated by examples/generate_check_code_prefix.rs.
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum_macros::{AsRefStr, EnumString};
|
||||
use strum_macros::EnumString;
|
||||
|
||||
use crate::checks::CheckCode;
|
||||
|
||||
#[derive(AsRefStr, EnumString, Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
|
||||
#[derive(EnumString, Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Serialize, Deserialize)]
|
||||
pub enum CheckCodePrefix {
|
||||
A,
|
||||
A0,
|
||||
@@ -13,19 +13,48 @@ pub enum CheckCodePrefix {
|
||||
A001,
|
||||
A002,
|
||||
A003,
|
||||
ANN,
|
||||
ANN0,
|
||||
ANN00,
|
||||
ANN001,
|
||||
ANN002,
|
||||
ANN003,
|
||||
ANN1,
|
||||
ANN10,
|
||||
ANN101,
|
||||
ANN102,
|
||||
ANN2,
|
||||
ANN20,
|
||||
ANN201,
|
||||
ANN202,
|
||||
ANN204,
|
||||
ANN205,
|
||||
ANN206,
|
||||
ANN4,
|
||||
ANN40,
|
||||
ANN401,
|
||||
B,
|
||||
B0,
|
||||
B00,
|
||||
B002,
|
||||
B003,
|
||||
B004,
|
||||
B005,
|
||||
B006,
|
||||
B007,
|
||||
B008,
|
||||
B009,
|
||||
B01,
|
||||
B011,
|
||||
B013,
|
||||
B014,
|
||||
B015,
|
||||
B016,
|
||||
B017,
|
||||
B018,
|
||||
B02,
|
||||
B025,
|
||||
B026,
|
||||
C,
|
||||
C4,
|
||||
C40,
|
||||
@@ -174,6 +203,10 @@ pub enum CheckCodePrefix {
|
||||
F9,
|
||||
F90,
|
||||
F901,
|
||||
I,
|
||||
I0,
|
||||
I00,
|
||||
I001,
|
||||
M,
|
||||
M0,
|
||||
M00,
|
||||
@@ -204,6 +237,12 @@ pub enum CheckCodePrefix {
|
||||
Q001,
|
||||
Q002,
|
||||
Q003,
|
||||
RUF,
|
||||
RUF0,
|
||||
RUF00,
|
||||
RUF001,
|
||||
RUF002,
|
||||
RUF003,
|
||||
T,
|
||||
T2,
|
||||
T20,
|
||||
@@ -220,6 +259,10 @@ pub enum CheckCodePrefix {
|
||||
U006,
|
||||
U007,
|
||||
U008,
|
||||
U009,
|
||||
U01,
|
||||
U010,
|
||||
U011,
|
||||
W,
|
||||
W2,
|
||||
W29,
|
||||
@@ -246,44 +289,125 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::A001 => vec![CheckCode::A001],
|
||||
CheckCodePrefix::A002 => vec![CheckCode::A002],
|
||||
CheckCodePrefix::A003 => vec![CheckCode::A003],
|
||||
CheckCodePrefix::ANN => vec![
|
||||
CheckCode::ANN001,
|
||||
CheckCode::ANN002,
|
||||
CheckCode::ANN003,
|
||||
CheckCode::ANN101,
|
||||
CheckCode::ANN102,
|
||||
CheckCode::ANN201,
|
||||
CheckCode::ANN202,
|
||||
CheckCode::ANN204,
|
||||
CheckCode::ANN205,
|
||||
CheckCode::ANN206,
|
||||
CheckCode::ANN401,
|
||||
],
|
||||
CheckCodePrefix::ANN0 => vec![CheckCode::ANN001, CheckCode::ANN002, CheckCode::ANN003],
|
||||
CheckCodePrefix::ANN00 => vec![CheckCode::ANN001, CheckCode::ANN002, CheckCode::ANN003],
|
||||
CheckCodePrefix::ANN001 => vec![CheckCode::ANN001],
|
||||
CheckCodePrefix::ANN002 => vec![CheckCode::ANN002],
|
||||
CheckCodePrefix::ANN003 => vec![CheckCode::ANN003],
|
||||
CheckCodePrefix::ANN1 => vec![CheckCode::ANN101, CheckCode::ANN102],
|
||||
CheckCodePrefix::ANN10 => vec![CheckCode::ANN101, CheckCode::ANN102],
|
||||
CheckCodePrefix::ANN101 => vec![CheckCode::ANN101],
|
||||
CheckCodePrefix::ANN102 => vec![CheckCode::ANN102],
|
||||
CheckCodePrefix::ANN2 => vec![
|
||||
CheckCode::ANN201,
|
||||
CheckCode::ANN202,
|
||||
CheckCode::ANN204,
|
||||
CheckCode::ANN205,
|
||||
CheckCode::ANN206,
|
||||
],
|
||||
CheckCodePrefix::ANN20 => vec![
|
||||
CheckCode::ANN201,
|
||||
CheckCode::ANN202,
|
||||
CheckCode::ANN204,
|
||||
CheckCode::ANN205,
|
||||
CheckCode::ANN206,
|
||||
],
|
||||
CheckCodePrefix::ANN201 => vec![CheckCode::ANN201],
|
||||
CheckCodePrefix::ANN202 => vec![CheckCode::ANN202],
|
||||
CheckCodePrefix::ANN204 => vec![CheckCode::ANN204],
|
||||
CheckCodePrefix::ANN205 => vec![CheckCode::ANN205],
|
||||
CheckCodePrefix::ANN206 => vec![CheckCode::ANN206],
|
||||
CheckCodePrefix::ANN4 => vec![CheckCode::ANN401],
|
||||
CheckCodePrefix::ANN40 => vec![CheckCode::ANN401],
|
||||
CheckCodePrefix::ANN401 => vec![CheckCode::ANN401],
|
||||
CheckCodePrefix::B => vec![
|
||||
CheckCode::B002,
|
||||
CheckCode::B003,
|
||||
CheckCode::B004,
|
||||
CheckCode::B005,
|
||||
CheckCode::B006,
|
||||
CheckCode::B007,
|
||||
CheckCode::B008,
|
||||
CheckCode::B009,
|
||||
CheckCode::B011,
|
||||
CheckCode::B013,
|
||||
CheckCode::B014,
|
||||
CheckCode::B015,
|
||||
CheckCode::B016,
|
||||
CheckCode::B017,
|
||||
CheckCode::B018,
|
||||
CheckCode::B025,
|
||||
CheckCode::B026,
|
||||
],
|
||||
CheckCodePrefix::B0 => vec![
|
||||
CheckCode::B002,
|
||||
CheckCode::B003,
|
||||
CheckCode::B004,
|
||||
CheckCode::B005,
|
||||
CheckCode::B006,
|
||||
CheckCode::B007,
|
||||
CheckCode::B008,
|
||||
CheckCode::B009,
|
||||
CheckCode::B011,
|
||||
CheckCode::B013,
|
||||
CheckCode::B014,
|
||||
CheckCode::B015,
|
||||
CheckCode::B016,
|
||||
CheckCode::B017,
|
||||
CheckCode::B018,
|
||||
CheckCode::B025,
|
||||
CheckCode::B026,
|
||||
],
|
||||
CheckCodePrefix::B00 => vec![
|
||||
CheckCode::B002,
|
||||
CheckCode::B003,
|
||||
CheckCode::B004,
|
||||
CheckCode::B005,
|
||||
CheckCode::B006,
|
||||
CheckCode::B007,
|
||||
CheckCode::B008,
|
||||
CheckCode::B009,
|
||||
],
|
||||
CheckCodePrefix::B00 => vec![CheckCode::B002, CheckCode::B006, CheckCode::B007],
|
||||
CheckCodePrefix::B002 => vec![CheckCode::B002],
|
||||
CheckCodePrefix::B003 => vec![CheckCode::B003],
|
||||
CheckCodePrefix::B004 => vec![CheckCode::B004],
|
||||
CheckCodePrefix::B005 => vec![CheckCode::B005],
|
||||
CheckCodePrefix::B006 => vec![CheckCode::B006],
|
||||
CheckCodePrefix::B007 => vec![CheckCode::B007],
|
||||
CheckCodePrefix::B01 => {
|
||||
vec![
|
||||
CheckCode::B011,
|
||||
CheckCode::B013,
|
||||
CheckCode::B014,
|
||||
CheckCode::B017,
|
||||
]
|
||||
}
|
||||
CheckCodePrefix::B008 => vec![CheckCode::B008],
|
||||
CheckCodePrefix::B009 => vec![CheckCode::B009],
|
||||
CheckCodePrefix::B01 => vec![
|
||||
CheckCode::B011,
|
||||
CheckCode::B013,
|
||||
CheckCode::B014,
|
||||
CheckCode::B015,
|
||||
CheckCode::B016,
|
||||
CheckCode::B017,
|
||||
CheckCode::B018,
|
||||
],
|
||||
CheckCodePrefix::B011 => vec![CheckCode::B011],
|
||||
CheckCodePrefix::B013 => vec![CheckCode::B013],
|
||||
CheckCodePrefix::B014 => vec![CheckCode::B014],
|
||||
CheckCodePrefix::B015 => vec![CheckCode::B015],
|
||||
CheckCodePrefix::B016 => vec![CheckCode::B016],
|
||||
CheckCodePrefix::B017 => vec![CheckCode::B017],
|
||||
CheckCodePrefix::B02 => vec![CheckCode::B025],
|
||||
CheckCodePrefix::B018 => vec![CheckCode::B018],
|
||||
CheckCodePrefix::B02 => vec![CheckCode::B025, CheckCode::B026],
|
||||
CheckCodePrefix::B025 => vec![CheckCode::B025],
|
||||
CheckCodePrefix::B026 => vec![CheckCode::B026],
|
||||
CheckCodePrefix::C => vec![
|
||||
CheckCode::C400,
|
||||
CheckCode::C401,
|
||||
@@ -584,14 +708,12 @@ impl CheckCodePrefix {
|
||||
CheckCode::E742,
|
||||
CheckCode::E743,
|
||||
],
|
||||
CheckCodePrefix::E71 => {
|
||||
vec![
|
||||
CheckCode::E711,
|
||||
CheckCode::E712,
|
||||
CheckCode::E713,
|
||||
CheckCode::E714,
|
||||
]
|
||||
}
|
||||
CheckCodePrefix::E71 => vec![
|
||||
CheckCode::E711,
|
||||
CheckCode::E712,
|
||||
CheckCode::E713,
|
||||
CheckCode::E714,
|
||||
],
|
||||
CheckCodePrefix::E711 => vec![CheckCode::E711],
|
||||
CheckCodePrefix::E712 => vec![CheckCode::E712],
|
||||
CheckCodePrefix::E713 => vec![CheckCode::E713],
|
||||
@@ -684,14 +806,12 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::F62 => vec![CheckCode::F621, CheckCode::F622],
|
||||
CheckCodePrefix::F621 => vec![CheckCode::F621],
|
||||
CheckCodePrefix::F622 => vec![CheckCode::F622],
|
||||
CheckCodePrefix::F63 => {
|
||||
vec![
|
||||
CheckCode::F631,
|
||||
CheckCode::F632,
|
||||
CheckCode::F633,
|
||||
CheckCode::F634,
|
||||
]
|
||||
}
|
||||
CheckCodePrefix::F63 => vec![
|
||||
CheckCode::F631,
|
||||
CheckCode::F632,
|
||||
CheckCode::F633,
|
||||
CheckCode::F634,
|
||||
],
|
||||
CheckCodePrefix::F631 => vec![CheckCode::F631],
|
||||
CheckCodePrefix::F632 => vec![CheckCode::F632],
|
||||
CheckCodePrefix::F633 => vec![CheckCode::F633],
|
||||
@@ -736,6 +856,10 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::F9 => vec![CheckCode::F901],
|
||||
CheckCodePrefix::F90 => vec![CheckCode::F901],
|
||||
CheckCodePrefix::F901 => vec![CheckCode::F901],
|
||||
CheckCodePrefix::I => vec![CheckCode::I001],
|
||||
CheckCodePrefix::I0 => vec![CheckCode::I001],
|
||||
CheckCodePrefix::I00 => vec![CheckCode::I001],
|
||||
CheckCodePrefix::I001 => vec![CheckCode::I001],
|
||||
CheckCodePrefix::M => vec![CheckCode::M001],
|
||||
CheckCodePrefix::M0 => vec![CheckCode::M001],
|
||||
CheckCodePrefix::M00 => vec![CheckCode::M001],
|
||||
@@ -808,34 +932,34 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::N816 => vec![CheckCode::N816],
|
||||
CheckCodePrefix::N817 => vec![CheckCode::N817],
|
||||
CheckCodePrefix::N818 => vec![CheckCode::N818],
|
||||
CheckCodePrefix::Q => {
|
||||
vec![
|
||||
CheckCode::Q000,
|
||||
CheckCode::Q001,
|
||||
CheckCode::Q002,
|
||||
CheckCode::Q003,
|
||||
]
|
||||
}
|
||||
CheckCodePrefix::Q0 => {
|
||||
vec![
|
||||
CheckCode::Q000,
|
||||
CheckCode::Q001,
|
||||
CheckCode::Q002,
|
||||
CheckCode::Q003,
|
||||
]
|
||||
}
|
||||
CheckCodePrefix::Q00 => {
|
||||
vec![
|
||||
CheckCode::Q000,
|
||||
CheckCode::Q001,
|
||||
CheckCode::Q002,
|
||||
CheckCode::Q003,
|
||||
]
|
||||
}
|
||||
CheckCodePrefix::Q => vec![
|
||||
CheckCode::Q000,
|
||||
CheckCode::Q001,
|
||||
CheckCode::Q002,
|
||||
CheckCode::Q003,
|
||||
],
|
||||
CheckCodePrefix::Q0 => vec![
|
||||
CheckCode::Q000,
|
||||
CheckCode::Q001,
|
||||
CheckCode::Q002,
|
||||
CheckCode::Q003,
|
||||
],
|
||||
CheckCodePrefix::Q00 => vec![
|
||||
CheckCode::Q000,
|
||||
CheckCode::Q001,
|
||||
CheckCode::Q002,
|
||||
CheckCode::Q003,
|
||||
],
|
||||
CheckCodePrefix::Q000 => vec![CheckCode::Q000],
|
||||
CheckCodePrefix::Q001 => vec![CheckCode::Q001],
|
||||
CheckCodePrefix::Q002 => vec![CheckCode::Q002],
|
||||
CheckCodePrefix::Q003 => vec![CheckCode::Q003],
|
||||
CheckCodePrefix::RUF => vec![CheckCode::RUF001, CheckCode::RUF002, CheckCode::RUF003],
|
||||
CheckCodePrefix::RUF0 => vec![CheckCode::RUF001, CheckCode::RUF002, CheckCode::RUF003],
|
||||
CheckCodePrefix::RUF00 => vec![CheckCode::RUF001, CheckCode::RUF002, CheckCode::RUF003],
|
||||
CheckCodePrefix::RUF001 => vec![CheckCode::RUF001],
|
||||
CheckCodePrefix::RUF002 => vec![CheckCode::RUF002],
|
||||
CheckCodePrefix::RUF003 => vec![CheckCode::RUF003],
|
||||
CheckCodePrefix::T => vec![CheckCode::T201, CheckCode::T203],
|
||||
CheckCodePrefix::T2 => vec![CheckCode::T201, CheckCode::T203],
|
||||
CheckCodePrefix::T20 => vec![CheckCode::T201, CheckCode::T203],
|
||||
@@ -850,6 +974,9 @@ impl CheckCodePrefix {
|
||||
CheckCode::U006,
|
||||
CheckCode::U007,
|
||||
CheckCode::U008,
|
||||
CheckCode::U009,
|
||||
CheckCode::U010,
|
||||
CheckCode::U011,
|
||||
],
|
||||
CheckCodePrefix::U0 => vec![
|
||||
CheckCode::U001,
|
||||
@@ -860,6 +987,9 @@ impl CheckCodePrefix {
|
||||
CheckCode::U006,
|
||||
CheckCode::U007,
|
||||
CheckCode::U008,
|
||||
CheckCode::U009,
|
||||
CheckCode::U010,
|
||||
CheckCode::U011,
|
||||
],
|
||||
CheckCodePrefix::U00 => vec![
|
||||
CheckCode::U001,
|
||||
@@ -870,6 +1000,7 @@ impl CheckCodePrefix {
|
||||
CheckCode::U006,
|
||||
CheckCode::U007,
|
||||
CheckCode::U008,
|
||||
CheckCode::U009,
|
||||
],
|
||||
CheckCodePrefix::U001 => vec![CheckCode::U001],
|
||||
CheckCodePrefix::U002 => vec![CheckCode::U002],
|
||||
@@ -879,6 +1010,10 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::U006 => vec![CheckCode::U006],
|
||||
CheckCodePrefix::U007 => vec![CheckCode::U007],
|
||||
CheckCodePrefix::U008 => vec![CheckCode::U008],
|
||||
CheckCodePrefix::U009 => vec![CheckCode::U009],
|
||||
CheckCodePrefix::U01 => vec![CheckCode::U010, CheckCode::U011],
|
||||
CheckCodePrefix::U010 => vec![CheckCode::U010],
|
||||
CheckCodePrefix::U011 => vec![CheckCode::U011],
|
||||
CheckCodePrefix::W => vec![CheckCode::W292, CheckCode::W605],
|
||||
CheckCodePrefix::W2 => vec![CheckCode::W292],
|
||||
CheckCodePrefix::W29 => vec![CheckCode::W292],
|
||||
@@ -899,19 +1034,48 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::A001 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::A002 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::A003 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::ANN => PrefixSpecificity::Category,
|
||||
CheckCodePrefix::ANN0 => PrefixSpecificity::Hundreds,
|
||||
CheckCodePrefix::ANN00 => PrefixSpecificity::Tens,
|
||||
CheckCodePrefix::ANN001 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::ANN002 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::ANN003 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::ANN1 => PrefixSpecificity::Hundreds,
|
||||
CheckCodePrefix::ANN10 => PrefixSpecificity::Tens,
|
||||
CheckCodePrefix::ANN101 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::ANN102 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::ANN2 => PrefixSpecificity::Hundreds,
|
||||
CheckCodePrefix::ANN20 => PrefixSpecificity::Tens,
|
||||
CheckCodePrefix::ANN201 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::ANN202 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::ANN204 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::ANN205 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::ANN206 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::ANN4 => PrefixSpecificity::Hundreds,
|
||||
CheckCodePrefix::ANN40 => PrefixSpecificity::Tens,
|
||||
CheckCodePrefix::ANN401 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::B => PrefixSpecificity::Category,
|
||||
CheckCodePrefix::B0 => PrefixSpecificity::Hundreds,
|
||||
CheckCodePrefix::B00 => PrefixSpecificity::Tens,
|
||||
CheckCodePrefix::B002 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::B003 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::B004 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::B005 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::B006 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::B007 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::B008 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::B009 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::B01 => PrefixSpecificity::Tens,
|
||||
CheckCodePrefix::B011 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::B013 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::B014 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::B015 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::B016 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::B017 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::B018 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::B02 => PrefixSpecificity::Tens,
|
||||
CheckCodePrefix::B025 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::B026 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::C => PrefixSpecificity::Category,
|
||||
CheckCodePrefix::C4 => PrefixSpecificity::Hundreds,
|
||||
CheckCodePrefix::C40 => PrefixSpecificity::Tens,
|
||||
@@ -1060,6 +1224,10 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::F9 => PrefixSpecificity::Hundreds,
|
||||
CheckCodePrefix::F90 => PrefixSpecificity::Tens,
|
||||
CheckCodePrefix::F901 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::I => PrefixSpecificity::Category,
|
||||
CheckCodePrefix::I0 => PrefixSpecificity::Hundreds,
|
||||
CheckCodePrefix::I00 => PrefixSpecificity::Tens,
|
||||
CheckCodePrefix::I001 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::M => PrefixSpecificity::Category,
|
||||
CheckCodePrefix::M0 => PrefixSpecificity::Hundreds,
|
||||
CheckCodePrefix::M00 => PrefixSpecificity::Tens,
|
||||
@@ -1090,6 +1258,12 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::Q001 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::Q002 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::Q003 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::RUF => PrefixSpecificity::Category,
|
||||
CheckCodePrefix::RUF0 => PrefixSpecificity::Hundreds,
|
||||
CheckCodePrefix::RUF00 => PrefixSpecificity::Tens,
|
||||
CheckCodePrefix::RUF001 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::RUF002 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::RUF003 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::T => PrefixSpecificity::Category,
|
||||
CheckCodePrefix::T2 => PrefixSpecificity::Hundreds,
|
||||
CheckCodePrefix::T20 => PrefixSpecificity::Tens,
|
||||
@@ -1106,6 +1280,10 @@ impl CheckCodePrefix {
|
||||
CheckCodePrefix::U006 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::U007 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::U008 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::U009 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::U01 => PrefixSpecificity::Tens,
|
||||
CheckCodePrefix::U010 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::U011 => PrefixSpecificity::Explicit,
|
||||
CheckCodePrefix::W => PrefixSpecificity::Category,
|
||||
CheckCodePrefix::W2 => PrefixSpecificity::Hundreds,
|
||||
CheckCodePrefix::W29 => PrefixSpecificity::Tens,
|
||||
|
||||
32
src/cli.rs
32
src/cli.rs
@@ -10,7 +10,7 @@ use crate::checks_gen::CheckCodePrefix;
|
||||
use crate::logging::LogLevel;
|
||||
use crate::printer::SerializationFormat;
|
||||
use crate::settings::configuration::Configuration;
|
||||
use crate::settings::types::{PatternPrefixPair, PythonVersion};
|
||||
use crate::settings::types::{PatternPrefixPair, PerFileIgnore, PythonVersion};
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[command(author, about = "ruff: An extremely fast Python linter.")]
|
||||
@@ -38,8 +38,10 @@ pub struct Cli {
|
||||
#[arg(short, long)]
|
||||
pub watch: bool,
|
||||
/// Attempt to automatically fix lint errors.
|
||||
#[arg(short, long)]
|
||||
pub fix: bool,
|
||||
#[arg(long, overrides_with("no_fix"))]
|
||||
fix: bool,
|
||||
#[clap(long, overrides_with("fix"), hide = true)]
|
||||
no_fix: bool,
|
||||
/// Disable cache reads.
|
||||
#[arg(short, long)]
|
||||
pub no_cache: bool,
|
||||
@@ -94,6 +96,22 @@ pub struct Cli {
|
||||
pub stdin_filename: Option<String>,
|
||||
}
|
||||
|
||||
impl Cli {
|
||||
// See: https://github.com/clap-rs/clap/issues/3146
|
||||
pub fn fix(&self) -> Option<bool> {
|
||||
resolve_bool_arg(self.fix, self.no_fix)
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_bool_arg(yes: bool, no: bool) -> Option<bool> {
|
||||
match (yes, no) {
|
||||
(true, false) => Some(true),
|
||||
(false, true) => Some(false),
|
||||
(false, false) => None,
|
||||
(..) => unreachable!("Clap should make this impossible"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Map the CLI settings to a `LogLevel`.
|
||||
pub fn extract_log_level(cli: &Cli) -> LogLevel {
|
||||
if cli.silent {
|
||||
@@ -165,10 +183,11 @@ pub fn warn_on(
|
||||
}
|
||||
}
|
||||
|
||||
/// Collect a list of `PatternPrefixPair` structs as a `BTreeMap`.
|
||||
/// Convert a list of `PatternPrefixPair` structs to `PerFileIgnore`.
|
||||
pub fn collect_per_file_ignores(
|
||||
pairs: Vec<PatternPrefixPair>,
|
||||
) -> BTreeMap<String, Vec<CheckCodePrefix>> {
|
||||
project_root: &Option<PathBuf>,
|
||||
) -> Vec<PerFileIgnore> {
|
||||
let mut per_file_ignores: BTreeMap<String, Vec<CheckCodePrefix>> = BTreeMap::new();
|
||||
for pair in pairs {
|
||||
per_file_ignores
|
||||
@@ -177,4 +196,7 @@ pub fn collect_per_file_ignores(
|
||||
.push(pair.prefix);
|
||||
}
|
||||
per_file_ignores
|
||||
.iter()
|
||||
.map(|(pattern, prefixes)| PerFileIgnore::new(pattern, prefixes, project_root))
|
||||
.collect()
|
||||
}
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
use anyhow::Result;
|
||||
use libcst_native::Module;
|
||||
use rustpython_ast::Located;
|
||||
use libcst_native::{Expr, Module, SmallStatement, Statement};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::source_code_locator::SourceCodeLocator;
|
||||
|
||||
pub fn match_tree<'a, T>(
|
||||
locator: &'a SourceCodeLocator,
|
||||
located: &'a Located<T>,
|
||||
) -> Result<Module<'a>> {
|
||||
match libcst_native::parse_module(
|
||||
locator.slice_source_code_range(&Range::from_located(located)),
|
||||
None,
|
||||
) {
|
||||
pub fn match_module(module_text: &str) -> Result<Module> {
|
||||
match libcst_native::parse_module(module_text, None) {
|
||||
Ok(module) => Ok(module),
|
||||
Err(_) => return Err(anyhow::anyhow!("Failed to extract CST from source.")),
|
||||
Err(_) => Err(anyhow::anyhow!("Failed to extract CST from source.")),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn match_expr<'a, 'b>(module: &'a mut Module<'b>) -> Result<&'a mut Expr<'b>> {
|
||||
if let Some(Statement::Simple(expr)) = module.body.first_mut() {
|
||||
if let Some(SmallStatement::Expr(expr)) = expr.body.first_mut() {
|
||||
Ok(expr)
|
||||
} else {
|
||||
Err(anyhow::anyhow!("Expected node to be: SmallStatement::Expr"))
|
||||
}
|
||||
} else {
|
||||
Err(anyhow::anyhow!("Expected node to be: Statement::Simple"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use rustpython_ast::{Expr, Location};
|
||||
use rustpython_ast::{Located, Location};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::check_ast::Checker;
|
||||
@@ -24,13 +24,16 @@ pub fn leading_space(line: &str) -> String {
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Extract the leading indentation from a docstring.
|
||||
pub fn indentation<'a>(checker: &'a Checker, docstring: &Expr) -> &'a str {
|
||||
let range = Range::from_located(docstring);
|
||||
checker.locator.slice_source_code_range(&Range {
|
||||
location: Location::new(range.location.row(), 0),
|
||||
end_location: Location::new(range.location.row(), range.location.column()),
|
||||
})
|
||||
/// Extract the leading indentation from a line.
|
||||
pub fn indentation<'a, T>(checker: &'a Checker, located: &Located<T>) -> String {
|
||||
let range = Range::from_located(located);
|
||||
checker
|
||||
.locator
|
||||
.slice_source_code_range(&Range {
|
||||
location: Location::new(range.location.row(), 0),
|
||||
end_location: Location::new(range.location.row(), range.location.column()),
|
||||
})
|
||||
.to_string()
|
||||
}
|
||||
|
||||
/// Replace any non-whitespace characters from an indentation string.
|
||||
|
||||
138
src/flake8_annotations/mod.rs
Normal file
138
src/flake8_annotations/mod.rs
Normal file
@@ -0,0 +1,138 @@
|
||||
pub mod plugins;
|
||||
pub mod settings;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::autofix::fixer;
|
||||
use crate::checks::CheckCode;
|
||||
use crate::linter::test_path;
|
||||
use crate::{flake8_annotations, Settings};
|
||||
|
||||
#[test]
|
||||
fn defaults() -> Result<()> {
|
||||
let mut checks = test_path(
|
||||
Path::new("./resources/test/fixtures/flake8_annotations/annotation_presence.py"),
|
||||
&Settings {
|
||||
..Settings::for_rules(vec![
|
||||
CheckCode::ANN001,
|
||||
CheckCode::ANN002,
|
||||
CheckCode::ANN003,
|
||||
CheckCode::ANN101,
|
||||
CheckCode::ANN102,
|
||||
CheckCode::ANN201,
|
||||
CheckCode::ANN202,
|
||||
CheckCode::ANN204,
|
||||
CheckCode::ANN205,
|
||||
CheckCode::ANN206,
|
||||
CheckCode::ANN401,
|
||||
])
|
||||
},
|
||||
&fixer::Mode::Generate,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(checks);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn suppress_dummy_args() -> Result<()> {
|
||||
let mut checks = test_path(
|
||||
Path::new("./resources/test/fixtures/flake8_annotations/suppress_dummy_args.py"),
|
||||
&Settings {
|
||||
flake8_annotations: flake8_annotations::settings::Settings {
|
||||
mypy_init_return: false,
|
||||
suppress_dummy_args: true,
|
||||
suppress_none_returning: false,
|
||||
allow_star_arg_any: false,
|
||||
},
|
||||
..Settings::for_rules(vec![
|
||||
CheckCode::ANN001,
|
||||
CheckCode::ANN002,
|
||||
CheckCode::ANN003,
|
||||
CheckCode::ANN101,
|
||||
CheckCode::ANN102,
|
||||
])
|
||||
},
|
||||
&fixer::Mode::Generate,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(checks);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mypy_init_return() -> Result<()> {
|
||||
let mut checks = test_path(
|
||||
Path::new("./resources/test/fixtures/flake8_annotations/mypy_init_return.py"),
|
||||
&Settings {
|
||||
flake8_annotations: flake8_annotations::settings::Settings {
|
||||
mypy_init_return: true,
|
||||
suppress_dummy_args: false,
|
||||
suppress_none_returning: false,
|
||||
allow_star_arg_any: false,
|
||||
},
|
||||
..Settings::for_rules(vec![
|
||||
CheckCode::ANN201,
|
||||
CheckCode::ANN202,
|
||||
CheckCode::ANN204,
|
||||
CheckCode::ANN205,
|
||||
CheckCode::ANN206,
|
||||
])
|
||||
},
|
||||
&fixer::Mode::Generate,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(checks);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn suppress_none_returning() -> Result<()> {
|
||||
let mut checks = test_path(
|
||||
Path::new("./resources/test/fixtures/flake8_annotations/suppress_none_returning.py"),
|
||||
&Settings {
|
||||
flake8_annotations: flake8_annotations::settings::Settings {
|
||||
mypy_init_return: false,
|
||||
suppress_dummy_args: false,
|
||||
suppress_none_returning: true,
|
||||
allow_star_arg_any: false,
|
||||
},
|
||||
..Settings::for_rules(vec![
|
||||
CheckCode::ANN201,
|
||||
CheckCode::ANN202,
|
||||
CheckCode::ANN204,
|
||||
CheckCode::ANN205,
|
||||
CheckCode::ANN206,
|
||||
])
|
||||
},
|
||||
&fixer::Mode::Generate,
|
||||
)?;
|
||||
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(
|
||||
Path::new("./resources/test/fixtures/flake8_annotations/allow_star_arg_any.py"),
|
||||
&Settings {
|
||||
flake8_annotations: flake8_annotations::settings::Settings {
|
||||
mypy_init_return: false,
|
||||
suppress_dummy_args: false,
|
||||
suppress_none_returning: false,
|
||||
allow_star_arg_any: true,
|
||||
},
|
||||
..Settings::for_rules(vec![CheckCode::ANN401])
|
||||
},
|
||||
&fixer::Mode::Generate,
|
||||
)?;
|
||||
checks.sort_by_key(|check| check.location);
|
||||
insta::assert_yaml_snapshot!(checks);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
376
src/flake8_annotations/plugins.rs
Normal file
376
src/flake8_annotations/plugins.rs
Normal file
@@ -0,0 +1,376 @@
|
||||
use rustpython_ast::{Arguments, Constant, Expr, ExprKind, Stmt, StmtKind};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::ast::visitor;
|
||||
use crate::ast::visitor::Visitor;
|
||||
use crate::check_ast::Checker;
|
||||
use crate::checks::{CheckCode, CheckKind};
|
||||
use crate::docstrings::definition::{Definition, DefinitionKind};
|
||||
use crate::visibility::Visibility;
|
||||
use crate::{visibility, Check};
|
||||
|
||||
#[derive(Default)]
|
||||
struct ReturnStatementVisitor<'a> {
|
||||
returns: Vec<&'a Option<Box<Expr>>>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> Visitor<'b> for ReturnStatementVisitor<'a>
|
||||
where
|
||||
'b: 'a,
|
||||
{
|
||||
fn visit_stmt(&mut self, stmt: &'b Stmt) {
|
||||
match &stmt.node {
|
||||
StmtKind::FunctionDef { .. } | StmtKind::AsyncFunctionDef { .. } => {
|
||||
// No recurse.
|
||||
}
|
||||
StmtKind::Return { value } => self.returns.push(value),
|
||||
_ => visitor::walk_stmt(self, stmt),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_none_returning(body: &[Stmt]) -> bool {
|
||||
let mut visitor: ReturnStatementVisitor = Default::default();
|
||||
for stmt in body {
|
||||
visitor.visit_stmt(stmt);
|
||||
}
|
||||
for expr in visitor.returns.into_iter().flatten() {
|
||||
if !matches!(
|
||||
expr.node,
|
||||
ExprKind::Constant {
|
||||
value: Constant::None,
|
||||
..
|
||||
}
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
/// ANN401
|
||||
fn check_dynamically_typed(checker: &mut Checker, annotation: &Expr, name: &str) {
|
||||
if checker.match_typing_module(annotation, "Any") {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::DynamicallyTypedExpression(name.to_string()),
|
||||
Range::from_located(annotation),
|
||||
));
|
||||
};
|
||||
}
|
||||
|
||||
fn match_function_def(stmt: &Stmt) -> (&str, &Arguments, &Option<Box<Expr>>, &Vec<Stmt>) {
|
||||
match &stmt.node {
|
||||
StmtKind::FunctionDef {
|
||||
name,
|
||||
args,
|
||||
returns,
|
||||
body,
|
||||
..
|
||||
}
|
||||
| StmtKind::AsyncFunctionDef {
|
||||
name,
|
||||
args,
|
||||
returns,
|
||||
body,
|
||||
..
|
||||
} => (name, args, returns, body),
|
||||
_ => panic!("Found non-FunctionDef in match_name"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate flake8-annotation checks for a given `Definition`.
|
||||
pub fn definition(checker: &mut Checker, definition: &Definition, visibility: &Visibility) {
|
||||
// TODO(charlie): Consider using the AST directly here rather than `Definition`.
|
||||
// We could adhere more closely to `flake8-annotations` by defining public
|
||||
// vs. secret vs. protected.
|
||||
match &definition.kind {
|
||||
DefinitionKind::Module => {}
|
||||
DefinitionKind::Package => {}
|
||||
DefinitionKind::Class(_) => {}
|
||||
DefinitionKind::NestedClass(_) => {}
|
||||
DefinitionKind::Function(stmt) | DefinitionKind::NestedFunction(stmt) => {
|
||||
let (name, args, returns, body) = match_function_def(stmt);
|
||||
|
||||
// ANN001, ANN401
|
||||
for arg in args
|
||||
.args
|
||||
.iter()
|
||||
.chain(args.posonlyargs.iter())
|
||||
.chain(args.kwonlyargs.iter())
|
||||
{
|
||||
if let Some(expr) = &arg.node.annotation {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN401) {
|
||||
check_dynamically_typed(checker, expr, &arg.node.arg);
|
||||
};
|
||||
} else {
|
||||
if !(checker.settings.flake8_annotations.suppress_dummy_args
|
||||
&& checker.settings.dummy_variable_rgx.is_match(&arg.node.arg))
|
||||
{
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN001) {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingTypeFunctionArgument(arg.node.arg.to_string()),
|
||||
Range::from_located(arg),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ANN002, ANN401
|
||||
if let Some(arg) = &args.vararg {
|
||||
if let Some(expr) = &arg.node.annotation {
|
||||
if !checker.settings.flake8_annotations.allow_star_arg_any {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN401) {
|
||||
let name = arg.node.arg.to_string();
|
||||
check_dynamically_typed(checker, expr, &format!("*{name}"));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if !(checker.settings.flake8_annotations.suppress_dummy_args
|
||||
&& checker.settings.dummy_variable_rgx.is_match(&arg.node.arg))
|
||||
{
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN002) {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingTypeArgs(arg.node.arg.to_string()),
|
||||
Range::from_located(arg),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ANN003, ANN401
|
||||
if let Some(arg) = &args.kwarg {
|
||||
if let Some(expr) = &arg.node.annotation {
|
||||
if !checker.settings.flake8_annotations.allow_star_arg_any {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN401) {
|
||||
let name = arg.node.arg.to_string();
|
||||
check_dynamically_typed(checker, expr, &format!("**{name}"));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if !(checker.settings.flake8_annotations.suppress_dummy_args
|
||||
&& checker.settings.dummy_variable_rgx.is_match(&arg.node.arg))
|
||||
{
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN003) {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingTypeKwargs(arg.node.arg.to_string()),
|
||||
Range::from_located(arg),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ANN201, ANN202, ANN401
|
||||
if let Some(expr) = &returns {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN401) {
|
||||
check_dynamically_typed(checker, expr, name);
|
||||
};
|
||||
} else {
|
||||
// Allow omission of return annotation in `__init__` functions, if the function
|
||||
// only returns `None` (explicitly or implicitly).
|
||||
if checker.settings.flake8_annotations.suppress_none_returning
|
||||
&& is_none_returning(body)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
match visibility {
|
||||
Visibility::Public => {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN201) {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingReturnTypePublicFunction(name.to_string()),
|
||||
Range::from_located(stmt),
|
||||
));
|
||||
}
|
||||
}
|
||||
Visibility::Private => {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN202) {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingReturnTypePrivateFunction(name.to_string()),
|
||||
Range::from_located(stmt),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
DefinitionKind::Method(stmt) => {
|
||||
let (name, args, returns, body) = match_function_def(stmt);
|
||||
let mut has_any_typed_arg = false;
|
||||
|
||||
// ANN001
|
||||
for arg in args
|
||||
.args
|
||||
.iter()
|
||||
.chain(args.posonlyargs.iter())
|
||||
.chain(args.kwonlyargs.iter())
|
||||
.skip(
|
||||
// If this is a non-static method, skip `cls` or `self`.
|
||||
usize::from(!visibility::is_staticmethod(stmt)),
|
||||
)
|
||||
{
|
||||
// ANN401 for dynamically typed arguments
|
||||
if let Some(annotation) = &arg.node.annotation {
|
||||
has_any_typed_arg = true;
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN401) {
|
||||
check_dynamically_typed(checker, annotation, &arg.node.arg);
|
||||
}
|
||||
} else {
|
||||
if !(checker.settings.flake8_annotations.suppress_dummy_args
|
||||
&& checker.settings.dummy_variable_rgx.is_match(&arg.node.arg))
|
||||
{
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN001) {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingTypeFunctionArgument(arg.node.arg.to_string()),
|
||||
Range::from_located(arg),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ANN002, ANN401
|
||||
if let Some(arg) = &args.vararg {
|
||||
has_any_typed_arg = true;
|
||||
if let Some(expr) = &arg.node.annotation {
|
||||
if !checker.settings.flake8_annotations.allow_star_arg_any {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN401) {
|
||||
let name = arg.node.arg.to_string();
|
||||
check_dynamically_typed(checker, expr, &format!("*{name}"));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if !(checker.settings.flake8_annotations.suppress_dummy_args
|
||||
&& checker.settings.dummy_variable_rgx.is_match(&arg.node.arg))
|
||||
{
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN002) {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingTypeArgs(arg.node.arg.to_string()),
|
||||
Range::from_located(arg),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ANN003, ANN401
|
||||
if let Some(arg) = &args.kwarg {
|
||||
has_any_typed_arg = true;
|
||||
if let Some(expr) = &arg.node.annotation {
|
||||
if !checker.settings.flake8_annotations.allow_star_arg_any {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN401) {
|
||||
let name = arg.node.arg.to_string();
|
||||
check_dynamically_typed(checker, expr, &format!("**{name}"));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if !(checker.settings.flake8_annotations.suppress_dummy_args
|
||||
&& checker.settings.dummy_variable_rgx.is_match(&arg.node.arg))
|
||||
{
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN003) {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingTypeKwargs(arg.node.arg.to_string()),
|
||||
Range::from_located(arg),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ANN101, ANN102
|
||||
if !visibility::is_staticmethod(stmt) {
|
||||
if let Some(arg) = args.args.first() {
|
||||
if arg.node.annotation.is_none() {
|
||||
if visibility::is_classmethod(stmt) {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN102) {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingTypeCls(arg.node.arg.to_string()),
|
||||
Range::from_located(arg),
|
||||
));
|
||||
}
|
||||
} else {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN101) {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingTypeSelf(arg.node.arg.to_string()),
|
||||
Range::from_located(arg),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ANN201, ANN202
|
||||
if let Some(expr) = &returns {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN401) {
|
||||
check_dynamically_typed(checker, expr, name);
|
||||
}
|
||||
} else {
|
||||
// Allow omission of return annotation in `__init__` functions, if the function
|
||||
// only returns `None` (explicitly or implicitly).
|
||||
if checker.settings.flake8_annotations.suppress_none_returning
|
||||
&& is_none_returning(body)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if visibility::is_classmethod(stmt) {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN206) {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingReturnTypeClassMethod(name.to_string()),
|
||||
Range::from_located(stmt),
|
||||
));
|
||||
}
|
||||
} else if visibility::is_staticmethod(stmt) {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN205) {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingReturnTypeStaticMethod(name.to_string()),
|
||||
Range::from_located(stmt),
|
||||
));
|
||||
}
|
||||
} else if visibility::is_magic(stmt) {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN204) {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingReturnTypeMagicMethod(name.to_string()),
|
||||
Range::from_located(stmt),
|
||||
));
|
||||
}
|
||||
} else if visibility::is_init(stmt) {
|
||||
// Allow omission of return annotation in `__init__` functions, as long as at
|
||||
// least one argument is typed.
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN204) {
|
||||
if !(checker.settings.flake8_annotations.mypy_init_return
|
||||
&& has_any_typed_arg)
|
||||
{
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingReturnTypeMagicMethod(name.to_string()),
|
||||
Range::from_located(stmt),
|
||||
));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
match visibility {
|
||||
Visibility::Public => {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN201) {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingReturnTypePublicFunction(name.to_string()),
|
||||
Range::from_located(stmt),
|
||||
));
|
||||
}
|
||||
}
|
||||
Visibility::Private => {
|
||||
if checker.settings.enabled.contains(&CheckCode::ANN202) {
|
||||
checker.add_check(Check::new(
|
||||
CheckKind::MissingReturnTypePrivateFunction(name.to_string()),
|
||||
Range::from_located(stmt),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
40
src/flake8_annotations/settings.rs
Normal file
40
src/flake8_annotations/settings.rs
Normal file
@@ -0,0 +1,40 @@
|
||||
//! Settings for the `flake-annotations` plugin.
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
|
||||
pub struct Options {
|
||||
/// Allow omission of a return type hint for `__init__` if at least one
|
||||
/// argument is annotated.
|
||||
pub mypy_init_return: Option<bool>,
|
||||
/// Suppress ANN000-level errors for dummy arguments, like `_`.
|
||||
pub suppress_dummy_args: Option<bool>,
|
||||
/// Suppress ANN200-level errors for functions that meet one of the
|
||||
/// following criteria:
|
||||
/// - Contain no `return` statement
|
||||
/// - Explicit `return` statement(s) all return `None` (explicitly or
|
||||
/// implicitly).
|
||||
pub suppress_none_returning: Option<bool>,
|
||||
/// Suppress ANN401 for dynamically typed *args and **kwargs.
|
||||
pub allow_star_arg_any: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Hash, Default)]
|
||||
pub struct Settings {
|
||||
pub mypy_init_return: bool,
|
||||
pub suppress_dummy_args: bool,
|
||||
pub suppress_none_returning: bool,
|
||||
pub allow_star_arg_any: bool,
|
||||
}
|
||||
|
||||
impl Settings {
|
||||
pub fn from_options(options: Options) -> Self {
|
||||
Self {
|
||||
mypy_init_return: options.mypy_init_return.unwrap_or_default(),
|
||||
suppress_dummy_args: options.suppress_dummy_args.unwrap_or_default(),
|
||||
suppress_none_returning: options.suppress_none_returning.unwrap_or_default(),
|
||||
allow_star_arg_any: options.allow_star_arg_any.unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
---
|
||||
source: src/flake8_annotations/mod.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind:
|
||||
DynamicallyTypedExpression: a
|
||||
location:
|
||||
row: 10
|
||||
column: 11
|
||||
end_location:
|
||||
row: 10
|
||||
column: 14
|
||||
fix: ~
|
||||
- kind:
|
||||
DynamicallyTypedExpression: foo
|
||||
location:
|
||||
row: 15
|
||||
column: 46
|
||||
end_location:
|
||||
row: 15
|
||||
column: 49
|
||||
fix: ~
|
||||
- kind:
|
||||
DynamicallyTypedExpression: a
|
||||
location:
|
||||
row: 40
|
||||
column: 28
|
||||
end_location:
|
||||
row: 40
|
||||
column: 31
|
||||
fix: ~
|
||||
- kind:
|
||||
DynamicallyTypedExpression: foo_method
|
||||
location:
|
||||
row: 44
|
||||
column: 66
|
||||
end_location:
|
||||
row: 44
|
||||
column: 69
|
||||
fix: ~
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
---
|
||||
source: src/flake8_annotations/mod.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind:
|
||||
MissingReturnTypePublicFunction: foo
|
||||
location:
|
||||
row: 4
|
||||
column: 0
|
||||
end_location:
|
||||
row: 9
|
||||
column: 0
|
||||
fix: ~
|
||||
- kind:
|
||||
MissingTypeFunctionArgument: a
|
||||
location:
|
||||
row: 4
|
||||
column: 8
|
||||
end_location:
|
||||
row: 4
|
||||
column: 9
|
||||
fix: ~
|
||||
- kind:
|
||||
MissingTypeFunctionArgument: b
|
||||
location:
|
||||
row: 4
|
||||
column: 11
|
||||
end_location:
|
||||
row: 4
|
||||
column: 12
|
||||
fix: ~
|
||||
- kind:
|
||||
MissingReturnTypePublicFunction: foo
|
||||
location:
|
||||
row: 9
|
||||
column: 0
|
||||
end_location:
|
||||
row: 14
|
||||
column: 0
|
||||
fix: ~
|
||||
- kind:
|
||||
MissingTypeFunctionArgument: b
|
||||
location:
|
||||
row: 9
|
||||
column: 16
|
||||
end_location:
|
||||
row: 9
|
||||
column: 17
|
||||
fix: ~
|
||||
- kind:
|
||||
MissingTypeFunctionArgument: b
|
||||
location:
|
||||
row: 14
|
||||
column: 16
|
||||
end_location:
|
||||
row: 14
|
||||
column: 17
|
||||
fix: ~
|
||||
- kind:
|
||||
MissingReturnTypePublicFunction: foo
|
||||
location:
|
||||
row: 19
|
||||
column: 0
|
||||
end_location:
|
||||
row: 24
|
||||
column: 0
|
||||
fix: ~
|
||||
- kind:
|
||||
MissingReturnTypePublicFunction: foo
|
||||
location:
|
||||
row: 24
|
||||
column: 0
|
||||
end_location:
|
||||
row: 29
|
||||
column: 0
|
||||
fix: ~
|
||||
- kind:
|
||||
DynamicallyTypedExpression: a
|
||||
location:
|
||||
row: 44
|
||||
column: 11
|
||||
end_location:
|
||||
row: 44
|
||||
column: 14
|
||||
fix: ~
|
||||
- kind:
|
||||
DynamicallyTypedExpression: foo
|
||||
location:
|
||||
row: 49
|
||||
column: 46
|
||||
end_location:
|
||||
row: 49
|
||||
column: 49
|
||||
fix: ~
|
||||
- kind:
|
||||
DynamicallyTypedExpression: "*args"
|
||||
location:
|
||||
row: 54
|
||||
column: 23
|
||||
end_location:
|
||||
row: 54
|
||||
column: 26
|
||||
fix: ~
|
||||
- kind:
|
||||
DynamicallyTypedExpression: "**kwargs"
|
||||
location:
|
||||
row: 54
|
||||
column: 38
|
||||
end_location:
|
||||
row: 54
|
||||
column: 41
|
||||
fix: ~
|
||||
- kind:
|
||||
DynamicallyTypedExpression: "*args"
|
||||
location:
|
||||
row: 59
|
||||
column: 23
|
||||
end_location:
|
||||
row: 59
|
||||
column: 26
|
||||
fix: ~
|
||||
- kind:
|
||||
DynamicallyTypedExpression: "**kwargs"
|
||||
location:
|
||||
row: 64
|
||||
column: 38
|
||||
end_location:
|
||||
row: 64
|
||||
column: 41
|
||||
fix: ~
|
||||
- kind:
|
||||
MissingTypeSelf: self
|
||||
location:
|
||||
row: 74
|
||||
column: 12
|
||||
end_location:
|
||||
row: 74
|
||||
column: 16
|
||||
fix: ~
|
||||
- kind:
|
||||
DynamicallyTypedExpression: a
|
||||
location:
|
||||
row: 78
|
||||
column: 28
|
||||
end_location:
|
||||
row: 78
|
||||
column: 31
|
||||
fix: ~
|
||||
- kind:
|
||||
DynamicallyTypedExpression: foo
|
||||
location:
|
||||
row: 82
|
||||
column: 66
|
||||
end_location:
|
||||
row: 82
|
||||
column: 69
|
||||
fix: ~
|
||||
- kind:
|
||||
DynamicallyTypedExpression: "*params"
|
||||
location:
|
||||
row: 86
|
||||
column: 42
|
||||
end_location:
|
||||
row: 86
|
||||
column: 45
|
||||
fix: ~
|
||||
- kind:
|
||||
DynamicallyTypedExpression: "**options"
|
||||
location:
|
||||
row: 86
|
||||
column: 58
|
||||
end_location:
|
||||
row: 86
|
||||
column: 61
|
||||
fix: ~
|
||||
- kind:
|
||||
DynamicallyTypedExpression: "*params"
|
||||
location:
|
||||
row: 90
|
||||
column: 42
|
||||
end_location:
|
||||
row: 90
|
||||
column: 45
|
||||
fix: ~
|
||||
- kind:
|
||||
DynamicallyTypedExpression: "**options"
|
||||
location:
|
||||
row: 94
|
||||
column: 58
|
||||
end_location:
|
||||
row: 94
|
||||
column: 61
|
||||
fix: ~
|
||||
- kind:
|
||||
MissingTypeCls: cls
|
||||
location:
|
||||
row: 104
|
||||
column: 12
|
||||
end_location:
|
||||
row: 104
|
||||
column: 15
|
||||
fix: ~
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
source: src/flake8_annotations/mod.rs
|
||||
expression: checks
|
||||
---
|
||||
- kind:
|
||||
MissingReturnTypeMagicMethod: __init__
|
||||
location:
|
||||
row: 5
|
||||
column: 4
|
||||
end_location:
|
||||
row: 10
|
||||
column: 0
|
||||
fix: ~
|
||||
- kind:
|
||||
MissingReturnTypeMagicMethod: __init__
|
||||
location:
|
||||
row: 11
|
||||
column: 4
|
||||
end_location:
|
||||
row: 16
|
||||
column: 0
|
||||
fix: ~
|
||||
- kind:
|
||||
MissingReturnTypePrivateFunction: __init__
|
||||
location:
|
||||
row: 40
|
||||
column: 0
|
||||
end_location:
|
||||
row: 42
|
||||
column: 0
|
||||
fix: ~
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user