Compare commits
97 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e9a236f740 | ||
|
|
ebb31dc29b | ||
|
|
b9e92affb1 | ||
|
|
68fbd0f029 | ||
|
|
8d01efb571 | ||
|
|
da5a25b421 | ||
|
|
bfdab4ac94 | ||
|
|
d1389894a4 | ||
|
|
8b277138de | ||
|
|
e0fe34c523 | ||
|
|
995fee5ddd | ||
|
|
99906c16db | ||
|
|
b6cb35414e | ||
|
|
b351221049 | ||
|
|
afb6f55b8d | ||
|
|
03a8ece954 | ||
|
|
8aeec35bfb | ||
|
|
93259acb31 | ||
|
|
ca7fe686d5 | ||
|
|
5dd9e99a4b | ||
|
|
8f0270acfe | ||
|
|
7ce38840a2 | ||
|
|
8ab8217ca5 | ||
|
|
5d3ff69053 | ||
|
|
726399b2b3 | ||
|
|
8329237f19 | ||
|
|
cd5882c66d | ||
|
|
0c05488740 | ||
|
|
1425b21d93 | ||
|
|
e5a59f41b0 | ||
|
|
8647bec3cb | ||
|
|
14042800c2 | ||
|
|
21986e89fd | ||
|
|
c4014ef2d3 | ||
|
|
9ffd20707f | ||
|
|
6d5aa344a1 | ||
|
|
e9be5fc7be | ||
|
|
f74050e5b1 | ||
|
|
90b2d85c85 | ||
|
|
ccf848705d | ||
|
|
3b535fcc74 | ||
|
|
06321fd240 | ||
|
|
cdae2f0e67 | ||
|
|
f52691a90a | ||
|
|
07e47bef4b | ||
|
|
86b61806a5 | ||
|
|
31ce37dd8e | ||
|
|
2cf6d05586 | ||
|
|
65c34c56d6 | ||
|
|
2315db7d13 | ||
|
|
f1a183c171 | ||
|
|
509c6d5ec7 | ||
|
|
6695988b59 | ||
|
|
e3867b172d | ||
|
|
4b8e30f350 | ||
|
|
8fd0d8e9d8 | ||
|
|
70895a8f1e | ||
|
|
f2c9f94f73 | ||
|
|
605c6069e2 | ||
|
|
92c2981b6d | ||
|
|
4ad8db3d61 | ||
|
|
0e8c237167 | ||
|
|
960c5e2006 | ||
|
|
9ba17fbf92 | ||
|
|
bfdf972a5d | ||
|
|
0c215365ae | ||
|
|
815284f890 | ||
|
|
6880338a9a | ||
|
|
68b749c67d | ||
|
|
c0fc55b812 | ||
|
|
ba9cf70917 | ||
|
|
f73dfbbfd3 | ||
|
|
62c273cd22 | ||
|
|
938ad9a39e | ||
|
|
14248cb8cb | ||
|
|
3a280039e1 | ||
|
|
4e9e58bdc0 | ||
|
|
926b5494ad | ||
|
|
6717b48ca5 | ||
|
|
f7bb5bc858 | ||
|
|
3e23fd1487 | ||
|
|
01c74e0629 | ||
|
|
1e3cf87f67 | ||
|
|
248447e139 | ||
|
|
95f139583a | ||
|
|
74903f23d6 | ||
|
|
3ee20a70d3 | ||
|
|
4c2fbb7ac0 | ||
|
|
7a66f98590 | ||
|
|
a2bf3916f3 | ||
|
|
c9aa7b9308 | ||
|
|
d880ca6cc6 | ||
|
|
080f99b908 | ||
|
|
a7dc491ff1 | ||
|
|
cdc8f8c91a | ||
|
|
138c46e793 | ||
|
|
a86c57a832 |
23
.github/workflows/ci.yaml
vendored
23
.github/workflows/ci.yaml
vendored
@@ -38,10 +38,9 @@ jobs:
|
||||
- run: cargo build --all --release
|
||||
- run: ./target/release/ruff_dev generate-all
|
||||
- run: git diff --quiet README.md || echo "::error file=README.md::This file is outdated. Run 'cargo +nightly dev generate-all'."
|
||||
- run: git diff --quiet src/checks_gen.rs || echo "::error file=src/checks_gen.rs::This file is outdated. Run 'cargo +nightly dev generate-all'."
|
||||
- run: git diff --quiet src/registry_gen.rs || echo "::error file=src/registry_gen.rs::This file is outdated. Run 'cargo +nightly dev generate-all'."
|
||||
- run: git diff --quiet ruff.schema.json || echo "::error file=ruff.schema.json::This file is outdated. Run 'cargo +nightly dev generate-all'."
|
||||
- run: git diff --quiet playground/src/ruff_options.ts || echo "::error file=playground/src/ruff_options.ts::This file is outdated. Run 'cargo +nightly dev generate-all'."
|
||||
- run: git diff --exit-code -- README.md src/checks_gen.rs ruff.schema.json playground/src/ruff_options.ts
|
||||
- run: git diff --exit-code -- README.md src/registry_gen.rs ruff.schema.json
|
||||
|
||||
cargo-fmt:
|
||||
name: "cargo fmt"
|
||||
@@ -117,8 +116,12 @@ jobs:
|
||||
${{ runner.os }}-build-${{ env.cache-name }}-
|
||||
${{ runner.os }}-build-
|
||||
${{ runner.os }}-
|
||||
- run: cargo install cargo-insta
|
||||
- run: pip install black[d]==22.12.0
|
||||
- run: cargo test --all
|
||||
- name: Run tests
|
||||
run: |
|
||||
cargo insta test --all --delete-unreferenced-snapshots
|
||||
git diff --exit-code
|
||||
- run: cargo test --package ruff --test black_compatibility_test -- --ignored
|
||||
|
||||
# TODO(charlie): Re-enable the `wasm-pack` tests.
|
||||
@@ -178,3 +181,15 @@ jobs:
|
||||
${{ runner.os }}-build-
|
||||
${{ runner.os }}-
|
||||
- run: maturin build -b bin
|
||||
|
||||
typos:
|
||||
name: Spell Check with Typos
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Actions Repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Check spelling of file.txt
|
||||
uses: crate-ci/typos@master
|
||||
with:
|
||||
files: .
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -181,3 +181,4 @@ cython_debug/
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
.idea/
|
||||
.vimspector.json
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
repos:
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
rev: v0.0.202
|
||||
rev: v0.0.209
|
||||
hooks:
|
||||
- id: ruff
|
||||
|
||||
|
||||
@@ -9,6 +9,15 @@ free to submit a PR. For larger changes (e.g., new lint rules, new functionality
|
||||
options), consider submitting an [Issue](https://github.com/charliermarsh/ruff/issues) outlining
|
||||
your proposed change.
|
||||
|
||||
If you're looking for a place to start, we recommend implementing a new lint rule (see:
|
||||
[_Adding a new lint rule_](#example-adding-a-new-lint-rule), which will allow you to learn from and
|
||||
pattern-match against the examples in the existing codebase. Many lint rules are inspired by
|
||||
existing Python plugins, which can be used as a reference implementation.
|
||||
|
||||
As a concrete example: consider taking on one of the rules in [`flake8-simplify`](https://github.com/charliermarsh/ruff/issues/998),
|
||||
and looking to the originating [Python source](https://github.com/MartinThoma/flake8-simplify) for
|
||||
guidance.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Ruff is written in Rust. You'll need to install the
|
||||
@@ -65,21 +74,15 @@ understand how other, similar rules are implemented.
|
||||
|
||||
To add a test fixture, create a file under `resources/test/fixtures`, named to match the `CheckCode`
|
||||
you defined earlier (e.g., `E402.py`). This file should contain a variety of violations and
|
||||
non-violations designed to evaluate and demonstrate the behavior of your lint rule. Run Ruff locally
|
||||
with (e.g.) `cargo run resources/test/fixtures/E402.py --no-cache --select E402`. Once you're satisfied with the
|
||||
output, codify the behavior as a snapshot test by adding a new `testcase` macro to the `mod tests`
|
||||
section of `src/linter.rs`, like so:
|
||||
non-violations designed to evaluate and demonstrate the behavior of your lint rule.
|
||||
|
||||
```rust
|
||||
use test_case::test_case;
|
||||
Run `cargo +nightly dev generate-all` to generate the code for your new fixture. Then run Ruff
|
||||
locally with (e.g.) `cargo run resources/test/fixtures/E402.py --no-cache --select E402`.
|
||||
|
||||
#[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.
|
||||
Once you're satisfied with the output, codify the behavior as a snapshot test by adding a new
|
||||
`test_case` macro in the relevant `src/[test-suite-name]/mod.rs` file. 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, regenerate the documentation and generated code with `cargo +nightly dev generate-all`.
|
||||
|
||||
|
||||
39
Cargo.lock
generated
39
Cargo.lock
generated
@@ -356,9 +356,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clearscreen"
|
||||
version = "1.0.10"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c969a6b6dadff9f3349b1f783f553e2411104763ca4789e1c6ca6a41f46a57b0"
|
||||
checksum = "41aa24cc5e1d6b3fc49ad4cd540b522fedcbe88bc6f259ff16e20e7010b6f8c7"
|
||||
dependencies = [
|
||||
"nix",
|
||||
"terminfo",
|
||||
@@ -397,12 +397,6 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "common-path"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2382f75942f4b3be3690fe4f86365e9c853c1587d6ee58212cebf6e2a9ccd101"
|
||||
|
||||
[[package]]
|
||||
name = "configparser"
|
||||
version = "3.0.2"
|
||||
@@ -750,7 +744,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.202-dev.0"
|
||||
version = "0.0.209-dev.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.0.32",
|
||||
@@ -1274,13 +1268,14 @@ checksum = "d906846a98739ed9d73d66e62c2641eef8321f1734b7a1156ab045a0248fb2b3"
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.24.3"
|
||||
version = "0.26.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069"
|
||||
checksum = "46a58d1d356c6597d08cde02c2f09d785b09e28711837b1ed667dc652c08a694"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1878,7 +1873,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.202"
|
||||
version = "0.0.209"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.9.1",
|
||||
"anyhow",
|
||||
@@ -1893,7 +1888,6 @@ dependencies = [
|
||||
"clap_complete_command",
|
||||
"clearscreen",
|
||||
"colored",
|
||||
"common-path",
|
||||
"console_error_panic_hook",
|
||||
"console_log",
|
||||
"criterion",
|
||||
@@ -1913,6 +1907,7 @@ dependencies = [
|
||||
"nohash-hasher",
|
||||
"notify",
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
"once_cell",
|
||||
"path-absolutize",
|
||||
"quick-junit",
|
||||
@@ -1946,7 +1941,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_dev"
|
||||
version = "0.0.202"
|
||||
version = "0.0.209"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.0.32",
|
||||
@@ -1967,7 +1962,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_macros"
|
||||
version = "0.0.202"
|
||||
version = "0.0.209"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -2010,7 +2005,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-ast"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=68d26955b3e24198a150315e7959719b03709dee#68d26955b3e24198a150315e7959719b03709dee"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=4d53c7cb27c0379adf8b51c4d3d0d2174f41d590#4d53c7cb27c0379adf8b51c4d3d0d2174f41d590"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"rustpython-common",
|
||||
@@ -2020,11 +2015,13 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-common"
|
||||
version = "0.0.0"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=68d26955b3e24198a150315e7959719b03709dee#68d26955b3e24198a150315e7959719b03709dee"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=4d53c7cb27c0379adf8b51c4d3d0d2174f41d590#4d53c7cb27c0379adf8b51c4d3d0d2174f41d590"
|
||||
dependencies = [
|
||||
"ascii",
|
||||
"bitflags",
|
||||
"cfg-if 1.0.0",
|
||||
"hexf-parse",
|
||||
"itertools",
|
||||
"lexical-parse-float",
|
||||
"libc",
|
||||
"lock_api",
|
||||
@@ -2043,7 +2040,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-compiler-core"
|
||||
version = "0.1.2"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=68d26955b3e24198a150315e7959719b03709dee#68d26955b3e24198a150315e7959719b03709dee"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=4d53c7cb27c0379adf8b51c4d3d0d2174f41d590#4d53c7cb27c0379adf8b51c4d3d0d2174f41d590"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"bitflags",
|
||||
@@ -2060,7 +2057,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-parser"
|
||||
version = "0.1.2"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=68d26955b3e24198a150315e7959719b03709dee#68d26955b3e24198a150315e7959719b03709dee"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=4d53c7cb27c0379adf8b51c4d3d0d2174f41d590#4d53c7cb27c0379adf8b51c4d3d0d2174f41d590"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"anyhow",
|
||||
@@ -2638,9 +2635,9 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
|
||||
|
||||
[[package]]
|
||||
name = "update-informer"
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f154aee470c0882ea0f3b1cc2a46c5f4d24f282655f7b0cec065614fe24c447f"
|
||||
checksum = "152ff185ca29f7f487c51ca785b0f1d85970c4581f4cdd12ed499227890200f5"
|
||||
dependencies = [
|
||||
"directories",
|
||||
"semver",
|
||||
|
||||
16
Cargo.toml
16
Cargo.toml
@@ -6,7 +6,7 @@ members = [
|
||||
|
||||
[package]
|
||||
name = "ruff"
|
||||
version = "0.0.202"
|
||||
version = "0.0.209"
|
||||
authors = ["Charlie Marsh <charlie.r.marsh@gmail.com>"]
|
||||
edition = "2021"
|
||||
rust-version = "1.65.0"
|
||||
@@ -32,7 +32,6 @@ chrono = { version = "0.4.21", default-features = false, features = ["clock"] }
|
||||
clap = { version = "4.0.1", features = ["derive"] }
|
||||
clap_complete_command = { version = "0.4.0" }
|
||||
colored = { version = "2.0.0" }
|
||||
common-path = { version = "1.0.0" }
|
||||
dirs = { version = "4.0.0" }
|
||||
fern = { version = "0.6.1" }
|
||||
filetime = { version = "0.2.17" }
|
||||
@@ -46,16 +45,17 @@ natord = { version = "1.0.9" }
|
||||
nohash-hasher = { version = "0.2.0" }
|
||||
notify = { version = "5.0.0" }
|
||||
num-bigint = { version = "0.4.3" }
|
||||
num-traits = "0.2.15"
|
||||
once_cell = { version = "1.16.0" }
|
||||
path-absolutize = { version = "3.0.14", features = ["once_cell_cache", "use_unix_paths_on_wasm"] }
|
||||
quick-junit = { version = "0.3.2" }
|
||||
regex = { version = "1.6.0" }
|
||||
ropey = { version = "1.5.0", features = ["cr_lines", "simd"], default-features = false }
|
||||
ruff_macros = { version = "0.0.202", path = "ruff_macros" }
|
||||
ruff_macros = { version = "0.0.209", path = "ruff_macros" }
|
||||
rustc-hash = { version = "1.1.0" }
|
||||
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "68d26955b3e24198a150315e7959719b03709dee" }
|
||||
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "68d26955b3e24198a150315e7959719b03709dee" }
|
||||
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "68d26955b3e24198a150315e7959719b03709dee" }
|
||||
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "4d53c7cb27c0379adf8b51c4d3d0d2174f41d590" }
|
||||
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "4d53c7cb27c0379adf8b51c4d3d0d2174f41d590" }
|
||||
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "4d53c7cb27c0379adf8b51c4d3d0d2174f41d590" }
|
||||
schemars = { version = "0.8.11" }
|
||||
semver = { version = "1.0.16" }
|
||||
serde = { version = "1.0.147", features = ["derive"] }
|
||||
@@ -70,9 +70,9 @@ toml = { version = "0.5.9" }
|
||||
walkdir = { version = "2.3.2" }
|
||||
|
||||
[target.'cfg(not(target_family = "wasm"))'.dependencies]
|
||||
clearscreen = { version = "1.0.10" }
|
||||
clearscreen = { version = "2.0.0" }
|
||||
rayon = { version = "1.5.3" }
|
||||
update-informer = { version = "0.5.0", default-features = false, features = ["pypi"], optional = true }
|
||||
update-informer = { version = "0.6.0", default-features = false, features = ["pypi"], optional = true }
|
||||
|
||||
# https://docs.rs/getrandom/0.2.7/getrandom/#webassembly-support
|
||||
# For (future) wasm-pack support
|
||||
|
||||
377
README.md
377
README.md
@@ -8,7 +8,11 @@
|
||||
An extremely fast Python linter, written in Rust.
|
||||
|
||||
<p align="center">
|
||||
<img alt="Bar chart with benchmark results" src="https://user-images.githubusercontent.com/1309177/187504482-6d9df992-a81d-4e86-9f6a-d958741c8182.svg">
|
||||
<picture align="center">
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/1309177/210156880-a97c2a0d-2c03-4393-8695-36547935a94e.svg">
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://user-images.githubusercontent.com/1309177/210156881-a88fd142-5008-4695-9407-d028cec3eff7.svg">
|
||||
<img alt="Shows a bar chart with benchmark results." src="https://user-images.githubusercontent.com/1309177/210156881-a88fd142-5008-4695-9407-d028cec3eff7.svg">
|
||||
</picture>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
@@ -22,8 +26,9 @@ An extremely fast Python linter, written in Rust.
|
||||
- 📦 Built-in caching, to avoid re-analyzing unchanged files
|
||||
- 🔧 Autofix support, for automatic error correction (e.g., automatically remove unused imports)
|
||||
- ⚖️ [Near-parity](#how-does-ruff-compare-to-flake8) with the built-in Flake8 rule set
|
||||
- 🔌 Native re-implementations of popular Flake8 plugins, like [`flake8-bugbear`](https://pypi.org/project/flake8-bugbear/)
|
||||
- 🌎 Monorepo-friendly configuration via hierarchical and cascading settings
|
||||
- 🔌 Native re-implementations of dozens of Flake8 plugins, like [`flake8-bugbear`](https://pypi.org/project/flake8-bugbear/)
|
||||
- ⌨️ First-party editor integrations for [VS Code](https://github.com/charliermarsh/ruff-vscode) and [more](https://github.com/charliermarsh/ruff-lsp)
|
||||
- 🌎 Monorepo-friendly, with [hierarchical and cascading configuration](#pyprojecttoml-discovery)
|
||||
|
||||
Ruff aims to be orders of magnitude faster than alternative tools while integrating more
|
||||
functionality behind a single, common interface.
|
||||
@@ -98,6 +103,7 @@ of [Conda](https://docs.conda.io/en/latest/):
|
||||
1. [flake8-implicit-str-concat (ISC)](#flake8-implicit-str-concat-isc)
|
||||
1. [flake8-import-conventions (ICN)](#flake8-import-conventions-icn)
|
||||
1. [flake8-print (T20)](#flake8-print-t20)
|
||||
1. [flake8-pytest-style (PT)](#flake8-pytest-style-pt)
|
||||
1. [flake8-quotes (Q)](#flake8-quotes-q)
|
||||
1. [flake8-return (RET)](#flake8-return-ret)
|
||||
1. [flake8-simplify (SIM)](#flake8-simplify-sim)
|
||||
@@ -108,6 +114,7 @@ of [Conda](https://docs.conda.io/en/latest/):
|
||||
1. [pandas-vet (PD)](#pandas-vet-pd)
|
||||
1. [pygrep-hooks (PGH)](#pygrep-hooks-pgh)
|
||||
1. [Pylint (PLC, PLE, PLR, PLW)](#pylint-plc-ple-plr-plw)
|
||||
1. [flake8-pie (PIE)](#flake8-pie-pie)
|
||||
1. [Ruff-specific rules (RUF)](#ruff-specific-rules-ruf)<!-- End auto-generated table of contents. -->
|
||||
1. [Editor Integrations](#editor-integrations)
|
||||
1. [FAQ](#faq)
|
||||
@@ -153,9 +160,9 @@ pacman -S ruff
|
||||
To run Ruff, try any of the following:
|
||||
|
||||
```shell
|
||||
ruff path/to/code/to/check.py
|
||||
ruff path/to/code/
|
||||
ruff path/to/code/*.py
|
||||
ruff path/to/code/to/check.py # Run Ruff over `check.py`
|
||||
ruff path/to/code/ # Run Ruff over all files in `/path/to/code` (and any subdirectories)
|
||||
ruff path/to/code/*.py # Run Ruff over all `.py` files in `/path/to/code`
|
||||
```
|
||||
|
||||
You can run Ruff in `--watch` mode to automatically re-run on-change:
|
||||
@@ -169,7 +176,7 @@ Ruff also works with [pre-commit](https://pre-commit.com):
|
||||
```yaml
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: 'v0.0.202'
|
||||
rev: 'v0.0.209'
|
||||
hooks:
|
||||
- id: ruff
|
||||
# Respect `exclude` and `extend-exclude` settings.
|
||||
@@ -270,7 +277,7 @@ alternative docstring formats. Enabling `ALL` without further configuration may
|
||||
behavior, especially for the `pydocstyle` plugin.
|
||||
|
||||
As an alternative to `pyproject.toml`, Ruff will also respect a `ruff.toml` file, which implements
|
||||
an equivalent schema (though the `[tool.ruff]` hierarchy can be omitted). For example, the above
|
||||
an equivalent schema (though the `[tool.ruff]` hierarchy can be omitted). For example, the
|
||||
`pyproject.toml` described above would be represented via the following `ruff.toml`:
|
||||
|
||||
```toml
|
||||
@@ -300,6 +307,7 @@ ruff path/to/code/ --select F401 --select F403
|
||||
|
||||
See `ruff --help` for more:
|
||||
|
||||
<!-- Begin auto-generated cli help. -->
|
||||
```shell
|
||||
Ruff: An extremely fast Python linter.
|
||||
|
||||
@@ -349,6 +357,10 @@ Options:
|
||||
List of mappings from file pattern to code to exclude
|
||||
--format <FORMAT>
|
||||
Output serialization format for error messages [possible values: text, json, junit, grouped, github, gitlab]
|
||||
--stdin-filename <STDIN_FILENAME>
|
||||
The name of the file when passing it through stdin
|
||||
--cache-dir <CACHE_DIR>
|
||||
Path to the cache directory
|
||||
--show-source
|
||||
Show violations with source code
|
||||
--respect-gitignore
|
||||
@@ -357,12 +369,6 @@ Options:
|
||||
Enforce exclusions, even for paths passed to Ruff directly on the command-line
|
||||
--update-check
|
||||
Enable or disable automatic update checks
|
||||
--show-files
|
||||
See the files Ruff will be run against with the current settings
|
||||
--show-settings
|
||||
See the settings Ruff will use to check a given Python file
|
||||
--add-noqa
|
||||
Enable automatic additions of `noqa` directives to failing lines
|
||||
--dummy-variable-rgx <DUMMY_VARIABLE_RGX>
|
||||
Regular expression matching the name of dummy variables
|
||||
--target-version <TARGET_VERSION>
|
||||
@@ -371,17 +377,22 @@ Options:
|
||||
Set the line-length for length-associated checks and automatic formatting
|
||||
--max-complexity <MAX_COMPLEXITY>
|
||||
Maximum McCabe complexity allowed for a given function
|
||||
--stdin-filename <STDIN_FILENAME>
|
||||
The name of the file when passing it through stdin
|
||||
--add-noqa
|
||||
Enable automatic additions of `noqa` directives to failing lines
|
||||
--clean
|
||||
Clear any caches in the current directory or any subdirectories
|
||||
--explain <EXPLAIN>
|
||||
Explain a rule
|
||||
--cache-dir <CACHE_DIR>
|
||||
Path to the cache directory
|
||||
--show-files
|
||||
See the files Ruff will be run against with the current settings
|
||||
--show-settings
|
||||
See the settings Ruff will use to check a given Python file
|
||||
-h, --help
|
||||
Print help information
|
||||
-V, --version
|
||||
Print version information
|
||||
```
|
||||
<!-- End auto-generated cli help. -->
|
||||
|
||||
### `pyproject.toml` discovery
|
||||
|
||||
@@ -393,7 +404,7 @@ directory hierarchy is used for every individual file, with all paths in the `py
|
||||
|
||||
There are a few exceptions to these rules:
|
||||
|
||||
1. In locating the "closest" `pyproject.toml` file for a given path, Ruff ignore any
|
||||
1. In locating the "closest" `pyproject.toml` file for a given path, Ruff ignores any
|
||||
`pyproject.toml` files that lack a `[tool.ruff]` section.
|
||||
2. If a configuration file is passed directly via `--config`, those settings are used for across
|
||||
files. Any relative paths in that configuration file (like `exclude` globs or `src` paths) are
|
||||
@@ -438,7 +449,7 @@ For example, `ruff /path/to/excluded/file.py` will always check `file.py`.
|
||||
### Ignoring errors
|
||||
|
||||
To omit a lint check entirely, add it to the "ignore" list via [`ignore`](#ignore) or
|
||||
[`extend-ignore`](#extend-ignore), either on the command-line or in your `project.toml` file.
|
||||
[`extend-ignore`](#extend-ignore), either on the command-line or in your `pyproject.toml` file.
|
||||
|
||||
To ignore an error inline, Ruff uses a `noqa` system similar to [Flake8](https://flake8.pycqa.org/en/3.1.1/user/ignoring-errors.html).
|
||||
To ignore an individual error, add `# noqa: {code}` to the end of the line, like so:
|
||||
@@ -535,13 +546,13 @@ For more, see [Pyflakes](https://pypi.org/project/pyflakes/2.5.0/) on PyPI.
|
||||
| F523 | StringDotFormatExtraPositionalArguments | '...'.format(...) has unused arguments at position(s): ... | |
|
||||
| F524 | StringDotFormatMissingArguments | '...'.format(...) is missing argument(s) for placeholder(s): ... | |
|
||||
| F525 | StringDotFormatMixingAutomatic | '...'.format(...) mixes automatic and manual numbering | |
|
||||
| F541 | FStringMissingPlaceholders | f-string without any placeholders | |
|
||||
| F541 | FStringMissingPlaceholders | f-string without any placeholders | 🛠 |
|
||||
| F601 | MultiValueRepeatedKeyLiteral | Dictionary key literal repeated | |
|
||||
| F602 | MultiValueRepeatedKeyVariable | Dictionary key `...` repeated | |
|
||||
| F621 | ExpressionsInStarAssignment | Too many expressions in star-unpacking assignment | |
|
||||
| F622 | TwoStarredExpressions | Two starred expressions in assignment | |
|
||||
| F631 | AssertTuple | Assert test is a non-empty tuple, which is always `True` | |
|
||||
| F632 | IsLiteral | Use `==` and `!=` to compare constant literals | 🛠 |
|
||||
| F632 | IsLiteral | Use `==` to compare constant literals | 🛠 |
|
||||
| F633 | InvalidPrintSyntax | Use of `>>` is invalid with `print` function | |
|
||||
| F634 | IfTuple | If test is a tuple, which is always `True` | |
|
||||
| F701 | BreakOutsideLoop | `break` outside loop | |
|
||||
@@ -554,7 +565,6 @@ For more, see [Pyflakes](https://pypi.org/project/pyflakes/2.5.0/) on PyPI.
|
||||
| F821 | UndefinedName | Undefined name `...` | |
|
||||
| F822 | UndefinedExport | Undefined name `...` in `__all__` | |
|
||||
| F823 | UndefinedLocal | Local variable `...` referenced before assignment | |
|
||||
| F831 | DuplicateArgumentName | Duplicate argument name in function definition | |
|
||||
| F841 | UnusedVariable | Local variable `...` is assigned to but never used | |
|
||||
| F842 | UnusedAnnotation | Local variable `...` is annotated but never used | |
|
||||
| F901 | RaiseNotImplemented | `raise NotImplemented` should be `raise NotImplementedError` | 🛠 |
|
||||
@@ -574,7 +584,7 @@ For more, see [pycodestyle](https://pypi.org/project/pycodestyle/2.9.1/) on PyPI
|
||||
| E714 | NotIsTest | Test for object identity should be `is not` | 🛠 |
|
||||
| E721 | TypeComparison | Do not compare types, use `isinstance()` | |
|
||||
| E722 | DoNotUseBareExcept | Do not use bare `except` | |
|
||||
| E731 | DoNotAssignLambda | Do not assign a lambda expression, use a def | 🛠 |
|
||||
| E731 | DoNotAssignLambda | Do not assign a `lambda` expression, use a `def` | 🛠 |
|
||||
| E741 | AmbiguousVariableName | Ambiguous variable name: `...` | |
|
||||
| E742 | AmbiguousClassName | Ambiguous class name: `...` | |
|
||||
| E743 | AmbiguousFunctionName | Ambiguous function name: `...` | |
|
||||
@@ -659,7 +669,7 @@ For more, see [pyupgrade](https://pypi.org/project/pyupgrade/3.2.0/) on PyPI.
|
||||
| ---- | ---- | ------- | --- |
|
||||
| UP001 | UselessMetaclassType | `__metaclass__ = type` is implied | 🛠 |
|
||||
| UP003 | TypeOfPrimitive | Use `str` instead of `type(...)` | 🛠 |
|
||||
| UP004 | UselessObjectInheritance | Class `...` inherits from object | 🛠 |
|
||||
| UP004 | UselessObjectInheritance | Class `...` inherits from `object` | 🛠 |
|
||||
| UP005 | DeprecatedUnittestAlias | `assertEquals` is deprecated, use `assertEqual` | 🛠 |
|
||||
| UP006 | UsePEP585Annotation | Use `list` instead of `List` for type annotations | 🛠 |
|
||||
| UP007 | UsePEP604Annotation | Use `X \| Y` for type annotations | 🛠 |
|
||||
@@ -673,13 +683,16 @@ For more, see [pyupgrade](https://pypi.org/project/pyupgrade/3.2.0/) on PyPI.
|
||||
| UP015 | RedundantOpenModes | Unnecessary open mode parameters | 🛠 |
|
||||
| UP016 | RemoveSixCompat | Unnecessary `six` compatibility usage | 🛠 |
|
||||
| UP017 | DatetimeTimezoneUTC | Use `datetime.UTC` alias | 🛠 |
|
||||
| UP018 | NativeLiterals | Unnecessary call to `str` and `bytes` | 🛠 |
|
||||
| UP018 | NativeLiterals | Unnecessary call to `str` | 🛠 |
|
||||
| UP019 | TypingTextStrAlias | `typing.Text` is deprecated, use `str` | 🛠 |
|
||||
| UP020 | OpenAlias | Use builtin `open` | 🛠 |
|
||||
| UP021 | ReplaceUniversalNewlines | `universal_newlines` is deprecated, use `text` | 🛠 |
|
||||
| UP022 | ReplaceStdoutStderr | Sending stdout and stderr to pipe is deprecated, use `capture_output` | 🛠 |
|
||||
| UP023 | RewriteCElementTree | `cElementTree` is deprecated, use `ElementTree` | 🛠 |
|
||||
| UP024 | OSErrorAlias | Replace aliased errors with `OSError` | 🛠 |
|
||||
| UP025 | RewriteUnicodeLiteral | Remove unicode literals from strings | 🛠 |
|
||||
| UP026 | RewriteMockImport | `mock` is deprecated, use `unittest.mock` | 🛠 |
|
||||
| UP027 | RewriteListComprehension | Replace unpacked list comprehension with a generator expression | 🛠 |
|
||||
|
||||
### pep8-naming (N)
|
||||
|
||||
@@ -880,6 +893,38 @@ For more, see [flake8-print](https://pypi.org/project/flake8-print/5.0.0/) on Py
|
||||
| T201 | PrintFound | `print` found | 🛠 |
|
||||
| T203 | PPrintFound | `pprint` found | 🛠 |
|
||||
|
||||
### flake8-pytest-style (PT)
|
||||
|
||||
For more, see [flake8-pytest-style](https://pypi.org/project/flake8-pytest-style/1.6.0/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| PT001 | IncorrectFixtureParenthesesStyle | Use `@pytest.fixture()` over `@pytest.fixture` | 🛠 |
|
||||
| PT002 | FixturePositionalArgs | Configuration for fixture `...` specified via positional args, use kwargs | |
|
||||
| PT003 | ExtraneousScopeFunction | `scope='function'` is implied in `@pytest.fixture()` | |
|
||||
| PT004 | MissingFixtureNameUnderscore | Fixture `...` does not return anything, add leading underscore | |
|
||||
| PT005 | IncorrectFixtureNameUnderscore | Fixture `...` returns a value, remove leading underscore | |
|
||||
| PT006 | ParametrizeNamesWrongType | Wrong name(s) type in `@pytest.mark.parametrize`, expected `tuple` | 🛠 |
|
||||
| PT007 | ParametrizeValuesWrongType | Wrong values type in `@pytest.mark.parametrize` expected `list` of `tuple` | |
|
||||
| PT008 | PatchWithLambda | Use `return_value=` instead of patching with lambda | |
|
||||
| PT009 | UnittestAssertion | Use a regular assert instead of unittest-style '...' | |
|
||||
| PT010 | RaisesWithoutException | set the expected exception in `pytest.raises()` | |
|
||||
| PT011 | RaisesTooBroad | `pytest.raises(...)` is too broad, set the `match` parameter or use a more specific exception | |
|
||||
| PT012 | RaisesWithMultipleStatements | `pytest.raises()` block should contain a single simple statement | |
|
||||
| PT013 | IncorrectPytestImport | Found incorrect import of pytest, use simple `import pytest` instead | |
|
||||
| PT015 | AssertAlwaysFalse | Assertion always fails, replace with `pytest.fail()` | |
|
||||
| PT016 | FailWithoutMessage | No message passed to `pytest.fail()` | |
|
||||
| PT017 | AssertInExcept | Found assertion on exception ... in except block, use pytest.raises() instead | |
|
||||
| PT018 | CompositeAssertion | Assertion should be broken down into multiple parts | |
|
||||
| PT019 | FixtureParamWithoutValue | Fixture ... without value is injected as parameter, use @pytest.mark.usefixtures instead | |
|
||||
| PT020 | DeprecatedYieldFixture | `@pytest.yield_fixture` is deprecated, use `@pytest.fixture` | |
|
||||
| PT021 | FixtureFinalizerCallback | Use `yield` instead of `request.addfinalizer` | |
|
||||
| PT022 | UselessYieldFixture | No teardown in fixture ..., use `return` instead of `yield` | |
|
||||
| PT023 | IncorrectMarkParenthesesStyle | Use `@pytest.mark....` over `@pytest.mark....()` | 🛠 |
|
||||
| PT024 | UnnecessaryAsyncioMarkOnFixture | `pytest.mark.asyncio` is unnecessary for fixtures | |
|
||||
| PT025 | ErroneousUseFixturesOnFixture | `pytest.mark.usefixtures` has no effect on fixtures | |
|
||||
| PT026 | UseFixturesWithoutParameters | Useless `pytest.mark.usefixtures` without parameters | 🛠 |
|
||||
|
||||
### flake8-quotes (Q)
|
||||
|
||||
For more, see [flake8-quotes](https://pypi.org/project/flake8-quotes/3.3.1/) on PyPI.
|
||||
@@ -913,6 +958,9 @@ For more, see [flake8-simplify](https://pypi.org/project/flake8-simplify/0.19.3/
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| SIM118 | KeyInDict | Use `key in dict` instead of `key in dict.keys()` | 🛠 |
|
||||
| SIM222 | OrTrue | Use `True` instead of `... or True` | 🛠 |
|
||||
| SIM223 | AndFalse | Use `False` instead of `... and False` | 🛠 |
|
||||
| SIM300 | YodaConditions | Use `left == right` instead of `right == left (Yoda-conditions)` | 🛠 |
|
||||
|
||||
### flake8-tidy-imports (TID)
|
||||
|
||||
@@ -1008,13 +1056,23 @@ For more, see [Pylint](https://pypi.org/project/pylint/2.15.7/) on PyPI.
|
||||
| PLW0120 | UselessElseOnLoop | Else clause on loop without a break statement, remove the else and de-indent all the code inside it | |
|
||||
| PLW0602 | GlobalVariableNotAssigned | Using global for `...` but no assignment is done | |
|
||||
|
||||
### flake8-pie (PIE)
|
||||
|
||||
For more, see [flake8-pie](https://pypi.org/project/flake8-pie/0.16.0/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| PIE790 | NoUnnecessaryPass | Unnecessary `pass` statement | 🛠 |
|
||||
| PIE794 | DupeClassFieldDefinitions | Class field `...` is defined multiple times | 🛠 |
|
||||
| PIE807 | PreferListBuiltin | Prefer `list()` over useless lambda | 🛠 |
|
||||
|
||||
### Ruff-specific rules (RUF)
|
||||
|
||||
| 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'?) | |
|
||||
| RUF003 | AmbiguousUnicodeCharacterComment | Comment contains ambiguous unicode character '𝐁' (did you mean 'B'?) | 🛠 |
|
||||
| RUF004 | KeywordArgumentBeforeStarArgument | Keyword argument `...` must come after starred arguments | |
|
||||
| RUF100 | UnusedNOQA | Unused blanket `noqa` directive | 🛠 |
|
||||
|
||||
@@ -1287,10 +1345,11 @@ natively, including:
|
||||
- [`flake8-errmsg`](https://pypi.org/project/flake8-errmsg/)
|
||||
- [`flake8-implicit-str-concat`](https://pypi.org/project/flake8-implicit-str-concat/)
|
||||
- [`flake8-import-conventions`](https://github.com/joaopalmeiro/flake8-import-conventions)
|
||||
- [`flake8-pie`](https://pypi.org/project/flake8-pie/) (3/7)
|
||||
- [`flake8-print`](https://pypi.org/project/flake8-print/)
|
||||
- [`flake8-quotes`](https://pypi.org/project/flake8-quotes/)
|
||||
- [`flake8-return`](https://pypi.org/project/flake8-return/)
|
||||
- [`flake8-simplify`](https://pypi.org/project/flake8-simplify/) (1/37)
|
||||
- [`flake8-simplify`](https://pypi.org/project/flake8-simplify/) (4/37)
|
||||
- [`flake8-super`](https://pypi.org/project/flake8-super/)
|
||||
- [`flake8-tidy-imports`](https://pypi.org/project/flake8-tidy-imports/) (1/3)
|
||||
- [`isort`](https://pypi.org/project/isort/)
|
||||
@@ -1298,7 +1357,7 @@ natively, including:
|
||||
- [`pep8-naming`](https://pypi.org/project/pep8-naming/)
|
||||
- [`pydocstyle`](https://pypi.org/project/pydocstyle/)
|
||||
- [`pygrep-hooks`](https://github.com/pre-commit/pygrep-hooks) (3/10)
|
||||
- [`pyupgrade`](https://pypi.org/project/pyupgrade/) (20/33)
|
||||
- [`pyupgrade`](https://pypi.org/project/pyupgrade/) (21/33)
|
||||
- [`yesqa`](https://github.com/asottile/yesqa)
|
||||
|
||||
Note that, in some cases, Ruff uses different error code prefixes than would be found in the
|
||||
@@ -1344,10 +1403,11 @@ Today, Ruff can be used to replace Flake8 when used with any of the following pl
|
||||
- [`flake8-errmsg`](https://pypi.org/project/flake8-errmsg/)
|
||||
- [`flake8-implicit-str-concat`](https://pypi.org/project/flake8-implicit-str-concat/)
|
||||
- [`flake8-import-conventions`](https://github.com/joaopalmeiro/flake8-import-conventions)
|
||||
- [`flake8-pie`](https://pypi.org/project/flake8-pie/) (3/7)
|
||||
- [`flake8-print`](https://pypi.org/project/flake8-print/)
|
||||
- [`flake8-quotes`](https://pypi.org/project/flake8-quotes/)
|
||||
- [`flake8-return`](https://pypi.org/project/flake8-return/)
|
||||
- [`flake8-simplify`](https://pypi.org/project/flake8-simplify/) (1/37)
|
||||
- [`flake8-simplify`](https://pypi.org/project/flake8-simplify/) (4/37)
|
||||
- [`flake8-super`](https://pypi.org/project/flake8-super/)
|
||||
- [`flake8-tidy-imports`](https://pypi.org/project/flake8-tidy-imports/) (1/3)
|
||||
- [`mccabe`](https://pypi.org/project/mccabe/)
|
||||
@@ -1357,9 +1417,9 @@ Today, Ruff can be used to replace Flake8 when used with any of the following pl
|
||||
Ruff can also replace [`isort`](https://pypi.org/project/isort/),
|
||||
[`yesqa`](https://github.com/asottile/yesqa), [`eradicate`](https://pypi.org/project/eradicate/),
|
||||
[`pygrep-hooks`](https://github.com/pre-commit/pygrep-hooks) (3/10), and a subset of the rules
|
||||
implemented in [`pyupgrade`](https://pypi.org/project/pyupgrade/) (20/33).
|
||||
implemented in [`pyupgrade`](https://pypi.org/project/pyupgrade/) (21/33).
|
||||
|
||||
If you're looking to use Ruff, but rely on an unsupported Flake8 plugin, free to file an Issue.
|
||||
If you're looking to use Ruff, but rely on an unsupported Flake8 plugin, feel free to file an Issue.
|
||||
|
||||
### Do I need to install Rust to use Ruff?
|
||||
|
||||
@@ -1422,59 +1482,49 @@ Found 3 error(s).
|
||||
|
||||
### Does Ruff support NumPy- or Google-style docstrings?
|
||||
|
||||
Yes! To enable a specific docstring convention, start by enabling all `pydocstyle` error codes, and
|
||||
then selectively disabling based on your [preferred convention](https://www.pydocstyle.org/en/latest/error_codes.html#default-conventions).
|
||||
|
||||
For example, if you're coming from `flake8-docstrings`, the following configuration is equivalent to
|
||||
`--docstring-convention=numpy`:
|
||||
Yes! To enable specific docstring convention, add the following to your `pyproject.toml`:
|
||||
|
||||
```toml
|
||||
[tool.ruff]
|
||||
extend-select = ["D"]
|
||||
extend-ignore = [
|
||||
"D107",
|
||||
"D203",
|
||||
"D212",
|
||||
"D213",
|
||||
"D402",
|
||||
"D413",
|
||||
"D415",
|
||||
"D416",
|
||||
"D417",
|
||||
]
|
||||
[tool.ruff.pydocstyle]
|
||||
convention = "google" # Accepts: "google", "numpy", or "pep257".
|
||||
```
|
||||
|
||||
Similarly, the following is equivalent to `--docstring-convention=google`:
|
||||
For example, if you're coming from `flake8-docstrings`, and your originating configuration uses
|
||||
`--docstring-convention=numpy`, you'd instead set `convention = "numpy"` in your `pyproject.toml`,
|
||||
as above.
|
||||
|
||||
Note that setting a `convention` is equivalent to adding that convention's specific set of codes to
|
||||
your `select`. For example, `convention = "numpy"` is equivalent to:
|
||||
|
||||
```toml
|
||||
[tool.ruff]
|
||||
extend-select = ["D"]
|
||||
extend-ignore = [
|
||||
"D203",
|
||||
# Enable all `D` errors except `D107`, `D203`, `D212`, `D213`, `D402`, `D413`, `D415`, `D416`,
|
||||
# and `D417`.
|
||||
select = [
|
||||
"D100",
|
||||
"D101",
|
||||
"D102",
|
||||
"D103",
|
||||
"D104",
|
||||
"D105",
|
||||
"D106",
|
||||
"D200",
|
||||
"D201",
|
||||
"D202",
|
||||
"D204",
|
||||
"D213",
|
||||
"D215",
|
||||
"D400",
|
||||
"D404",
|
||||
"D406",
|
||||
"D407",
|
||||
"D408",
|
||||
"D409",
|
||||
"D413",
|
||||
]
|
||||
```
|
||||
|
||||
Similarly, the following is equivalent to `--docstring-convention=pep8`:
|
||||
|
||||
```toml
|
||||
[tool.ruff]
|
||||
extend-select = ["D"]
|
||||
extend-ignore = [
|
||||
"D203",
|
||||
"D212",
|
||||
"D213",
|
||||
"D205",
|
||||
"D206",
|
||||
"D207",
|
||||
"D208",
|
||||
"D209",
|
||||
"D210",
|
||||
"D211",
|
||||
"D214",
|
||||
"D215",
|
||||
"D300",
|
||||
"D301",
|
||||
"D400",
|
||||
"D403",
|
||||
"D404",
|
||||
"D405",
|
||||
"D406",
|
||||
@@ -1483,24 +1533,16 @@ extend-ignore = [
|
||||
"D409",
|
||||
"D410",
|
||||
"D411",
|
||||
"D413",
|
||||
"D415",
|
||||
"D416",
|
||||
"D417",
|
||||
"D412",
|
||||
"D414",
|
||||
"D418",
|
||||
"D419",
|
||||
]
|
||||
```
|
||||
|
||||
Note that Ruff _also_ supports a [`convention`](#convention) setting:
|
||||
### How can I tell what settings Ruff is using to check my code?
|
||||
|
||||
```toml
|
||||
[tool.ruff.pydocstyle]
|
||||
convention = "google"
|
||||
```
|
||||
|
||||
However, this setting is purely used to implement robust detection of Google and NumPy-style
|
||||
sections, and thus avoid the [false negatives](https://github.com/PyCQA/pydocstyle/issues/459) seen
|
||||
in `pydocstyle`; it does not affect which errors are enabled, which is driven by the `select` and
|
||||
`ignore` settings, as described above.
|
||||
Run `ruff /path/to/code.py --show-settings` to view the resolved settings for a given file.
|
||||
|
||||
## Development
|
||||
|
||||
@@ -1669,7 +1711,6 @@ Summary
|
||||
|
||||
<!-- Sections automatically generated by `cargo dev generate-options`. -->
|
||||
<!-- Begin auto-generated options sections. -->
|
||||
|
||||
#### [`allowed-confusables`](#allowed-confusables)
|
||||
|
||||
A list of allowed "confusable" Unicode characters to ignore when
|
||||
@@ -2398,6 +2439,157 @@ will be added to the `aliases` mapping.
|
||||
|
||||
---
|
||||
|
||||
### `flake8-pytest-style`
|
||||
|
||||
#### [`fixture-parentheses`](#fixture-parentheses)
|
||||
|
||||
Boolean flag specifying whether `@pytest.fixture()` without parameters
|
||||
should have parentheses. If the option is set to `true` (the
|
||||
default), `@pytest.fixture()` is valid and `@pytest.fixture` is an
|
||||
error. If set to `false`, `@pytest.fixture` is valid and
|
||||
`@pytest.fixture()` is an error.
|
||||
|
||||
**Default value**: `true`
|
||||
|
||||
**Type**: `bool`
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```toml
|
||||
[tool.ruff.flake8-pytest-style]
|
||||
fixture-parentheses = true
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### [`mark-parentheses`](#mark-parentheses)
|
||||
|
||||
Boolean flag specifying whether `@pytest.mark.foo()` without parameters
|
||||
should have parentheses. If the option is set to `true` (the
|
||||
default), `@pytest.mark.foo()` is valid and `@pytest.mark.foo` is an
|
||||
error. If set to `false`, `@pytest.fixture` is valid and
|
||||
`@pytest.mark.foo()` is an error.
|
||||
|
||||
**Default value**: `true`
|
||||
|
||||
**Type**: `bool`
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```toml
|
||||
[tool.ruff.flake8-pytest-style]
|
||||
mark-parentheses = true
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### [`parametrize-names-type`](#parametrize-names-type)
|
||||
|
||||
Expected type for multiple argument names in `@pytest.mark.parametrize`.
|
||||
The following values are supported:
|
||||
* `csv` — a comma-separated list, e.g.
|
||||
`@pytest.mark.parametrize('name1,name2', ...)`
|
||||
* `tuple` (default) — e.g. `@pytest.mark.parametrize(('name1', 'name2'),
|
||||
...)`
|
||||
* `list` — e.g. `@pytest.mark.parametrize(['name1', 'name2'], ...)`
|
||||
|
||||
**Default value**: `tuple`
|
||||
|
||||
**Type**: `ParametrizeNameType`
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```toml
|
||||
[tool.ruff.flake8-pytest-style]
|
||||
parametrize-names-type = "list"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### [`parametrize-values-row-type`](#parametrize-values-row-type)
|
||||
|
||||
Expected type for each row of values in `@pytest.mark.parametrize` in
|
||||
case of multiple parameters. The following values are supported:
|
||||
* `tuple` (default) — e.g. `@pytest.mark.parametrize(('name1', 'name2'),
|
||||
[(1, 2), (3, 4)])`
|
||||
* `list` — e.g. `@pytest.mark.parametrize(('name1', 'name2'), [[1, 2],
|
||||
[3, 4]])`
|
||||
|
||||
**Default value**: `tuple`
|
||||
|
||||
**Type**: `ParametrizeValuesRowType`
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```toml
|
||||
[tool.ruff.flake8-pytest-style]
|
||||
parametrize-values-row-type = "list"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### [`parametrize-values-type`](#parametrize-values-type)
|
||||
|
||||
Expected type for the list of values rows in `@pytest.mark.parametrize`.
|
||||
The following values are supported:
|
||||
* `tuple` — e.g. `@pytest.mark.parametrize('name', (1, 2, 3))`
|
||||
* `list` (default) — e.g. `@pytest.mark.parametrize('name', [1, 2, 3])`
|
||||
|
||||
**Default value**: `list`
|
||||
|
||||
**Type**: `ParametrizeValuesType`
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```toml
|
||||
[tool.ruff.flake8-pytest-style]
|
||||
parametrize-values-type = "tuple"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### [`raises-extend-require-match-for`](#raises-extend-require-match-for)
|
||||
|
||||
List of additional exception names that require a match= parameter in a
|
||||
`pytest.raises()` call. This extends the default list of exceptions
|
||||
that require a match= parameter.
|
||||
This option is useful if you want to extend the default list of
|
||||
exceptions that require a match= parameter without having to specify
|
||||
the entire list.
|
||||
Note that this option does not remove any exceptions from the default
|
||||
list.
|
||||
|
||||
**Default value**: `[]`
|
||||
|
||||
**Type**: `Vec<String>`
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```toml
|
||||
[tool.ruff.flake8-pytest-style]
|
||||
raises-extend-require-match-for = ["requests.RequestException"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### [`raises-require-match-for`](#raises-require-match-for)
|
||||
|
||||
List of exception names that require a match= parameter in a
|
||||
`pytest.raises()` call.
|
||||
|
||||
**Default value**: `["BaseException", "Exception", "ValueError", "OSError", "IOError", "EnvironmentError", "socket.error"]`
|
||||
|
||||
**Type**: `Vec<String>`
|
||||
|
||||
**Example usage**:
|
||||
|
||||
```toml
|
||||
[tool.ruff.flake8-pytest-style]
|
||||
raises-require-match-for = ["requests.RequestException"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `flake8-quotes`
|
||||
|
||||
#### [`avoid-escape`](#avoid-escape)
|
||||
@@ -2781,9 +2973,8 @@ staticmethod-decorators = ["staticmethod", "stcmthd"]
|
||||
|
||||
#### [`convention`](#convention)
|
||||
|
||||
Whether to use Google-style or Numpy-style conventions when detecting
|
||||
docstring sections. By default, conventions will be inferred from
|
||||
the available sections.
|
||||
Whether to use Google-style or NumPy-style conventions or the PEP257
|
||||
defaults when analyzing docstring sections.
|
||||
|
||||
**Default value**: `None`
|
||||
|
||||
|
||||
4
flake8_to_ruff/Cargo.lock
generated
4
flake8_to_ruff/Cargo.lock
generated
@@ -771,7 +771,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8_to_ruff"
|
||||
version = "0.0.202"
|
||||
version = "0.0.209"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@@ -1975,7 +1975,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.202"
|
||||
version = "0.0.209"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.202-dev.0"
|
||||
version = "0.0.209-dev.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
|
||||
43
flake8_to_ruff/examples/manim.ini
Normal file
43
flake8_to_ruff/examples/manim.ini
Normal file
@@ -0,0 +1,43 @@
|
||||
[flake8]
|
||||
# Exclude the grpc generated code
|
||||
exclude = ./manim/grpc/gen/*
|
||||
max-complexity = 15
|
||||
max-line-length = 88
|
||||
statistics = True
|
||||
# Prevents some flake8-rst-docstrings errors
|
||||
rst-roles = attr,class,func,meth,mod,obj,ref,doc,exc
|
||||
rst-directives = manim, SEEALSO, seealso
|
||||
docstring-convention=numpy
|
||||
|
||||
select = A,A00,B,B9,C4,C90,D,E,F,F,PT,RST,SIM,W
|
||||
|
||||
# General Compatibility
|
||||
extend-ignore = E203, W503, D202, D212, D213, D404
|
||||
|
||||
# Misc
|
||||
F401, F403, F405, F841, E501, E731, E402, F811, F821,
|
||||
|
||||
# Plug-in: flake8-builtins
|
||||
A001, A002, A003,
|
||||
|
||||
# Plug-in: flake8-bugbear
|
||||
B006, B007, B008, B009, B010, B903, B950,
|
||||
|
||||
# Plug-in: flake8-simplify
|
||||
SIM105, SIM106, SIM119,
|
||||
|
||||
# Plug-in: flake8-comprehensions
|
||||
C901
|
||||
|
||||
# Plug-in: flake8-pytest-style
|
||||
PT001, PT004, PT006, PT011, PT018, PT022, PT023,
|
||||
|
||||
# Plug-in: flake8-docstrings
|
||||
D100, D101, D102, D103, D104, D105, D106, D107,
|
||||
D200, D202, D204, D205, D209,
|
||||
D301,
|
||||
D400, D401, D402, D403, D405, D406, D407, D409, D411, D412, D414,
|
||||
|
||||
# Plug-in: flake8-rst-docstrings
|
||||
RST201, RST203, RST210, RST212, RST213, RST215,
|
||||
RST301, RST303,
|
||||
@@ -1,15 +1,18 @@
|
||||
use std::collections::{BTreeSet, HashMap};
|
||||
|
||||
use anyhow::Result;
|
||||
use ruff::checks_gen::CheckCodePrefix;
|
||||
use ruff::flake8_pytest_style::types::{
|
||||
ParametrizeNameType, ParametrizeValuesRowType, ParametrizeValuesType,
|
||||
};
|
||||
use ruff::flake8_quotes::settings::Quote;
|
||||
use ruff::flake8_tidy_imports::settings::Strictness;
|
||||
use ruff::pydocstyle::settings::Convention;
|
||||
use ruff::registry_gen::CheckCodePrefix;
|
||||
use ruff::settings::options::Options;
|
||||
use ruff::settings::pyproject::Pyproject;
|
||||
use ruff::{
|
||||
flake8_annotations, flake8_bugbear, flake8_errmsg, flake8_quotes, flake8_tidy_imports, mccabe,
|
||||
pep8_naming, pydocstyle,
|
||||
flake8_annotations, flake8_bugbear, flake8_errmsg, flake8_pytest_style, flake8_quotes,
|
||||
flake8_tidy_imports, mccabe, pep8_naming, pydocstyle,
|
||||
};
|
||||
|
||||
use crate::black::Black;
|
||||
@@ -49,6 +52,19 @@ pub fn convert(
|
||||
}
|
||||
}
|
||||
|
||||
// Infer plugins, if not provided.
|
||||
let plugins = plugins.unwrap_or_else(|| {
|
||||
let from_options = plugin::infer_plugins_from_options(flake8);
|
||||
if !from_options.is_empty() {
|
||||
eprintln!("Inferred plugins from settings: {from_options:#?}");
|
||||
}
|
||||
let from_codes = plugin::infer_plugins_from_codes(&referenced_codes);
|
||||
if !from_codes.is_empty() {
|
||||
eprintln!("Inferred plugins from referenced check codes: {from_codes:#?}");
|
||||
}
|
||||
from_options.into_iter().chain(from_codes).collect()
|
||||
});
|
||||
|
||||
// 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
|
||||
@@ -58,22 +74,7 @@ pub fn convert(
|
||||
.as_ref()
|
||||
.map(|value| BTreeSet::from_iter(parser::parse_prefix_codes(value)))
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
plugin::resolve_select(
|
||||
flake8,
|
||||
&plugins.unwrap_or_else(|| {
|
||||
let from_options = plugin::infer_plugins_from_options(flake8);
|
||||
if !from_options.is_empty() {
|
||||
eprintln!("Inferred plugins from settings: {from_options:#?}");
|
||||
}
|
||||
let from_codes = plugin::infer_plugins_from_codes(&referenced_codes);
|
||||
if !from_codes.is_empty() {
|
||||
eprintln!("Inferred plugins from referenced check codes: {from_codes:#?}");
|
||||
}
|
||||
from_options.into_iter().chain(from_codes).collect()
|
||||
}),
|
||||
)
|
||||
});
|
||||
.unwrap_or_else(|| plugin::resolve_select(flake8, &plugins));
|
||||
let mut ignore = flake8
|
||||
.get("ignore")
|
||||
.and_then(|value| {
|
||||
@@ -88,6 +89,7 @@ pub fn convert(
|
||||
let mut flake8_annotations = flake8_annotations::settings::Options::default();
|
||||
let mut flake8_bugbear = flake8_bugbear::settings::Options::default();
|
||||
let mut flake8_errmsg = flake8_errmsg::settings::Options::default();
|
||||
let mut flake8_pytest_style = flake8_pytest_style::settings::Options::default();
|
||||
let mut flake8_quotes = flake8_quotes::settings::Options::default();
|
||||
let mut flake8_tidy_imports = flake8_tidy_imports::settings::Options::default();
|
||||
let mut mccabe = mccabe::settings::Options::default();
|
||||
@@ -205,7 +207,8 @@ pub fn convert(
|
||||
"docstring-convention" => match value.trim() {
|
||||
"google" => pydocstyle.convention = Some(Convention::Google),
|
||||
"numpy" => pydocstyle.convention = Some(Convention::Numpy),
|
||||
"pep257" | "all" => pydocstyle.convention = None,
|
||||
"pep257" => pydocstyle.convention = Some(Convention::Pep257),
|
||||
"all" => pydocstyle.convention = None,
|
||||
_ => eprintln!("Unexpected '{key}' value: {value}"),
|
||||
},
|
||||
// mccabe
|
||||
@@ -222,12 +225,79 @@ pub fn convert(
|
||||
Err(e) => eprintln!("Unable to parse '{key}' property: {e}"),
|
||||
}
|
||||
}
|
||||
// flake8-pytest-style
|
||||
"pytest-fixture-no-parentheses" | "pytest_fixture_no_parentheses " => {
|
||||
match parser::parse_bool(value.as_ref()) {
|
||||
Ok(bool) => flake8_pytest_style.fixture_parentheses = Some(!bool),
|
||||
Err(e) => eprintln!("Unable to parse '{key}' property: {e}"),
|
||||
}
|
||||
}
|
||||
"pytest-parametrize-names-type" | "pytest_parametrize_names_type" => {
|
||||
match value.trim() {
|
||||
"csv" => {
|
||||
flake8_pytest_style.parametrize_names_type =
|
||||
Some(ParametrizeNameType::CSV);
|
||||
}
|
||||
"tuple" => {
|
||||
flake8_pytest_style.parametrize_names_type =
|
||||
Some(ParametrizeNameType::Tuple);
|
||||
}
|
||||
"list" => {
|
||||
flake8_pytest_style.parametrize_names_type =
|
||||
Some(ParametrizeNameType::List);
|
||||
}
|
||||
_ => eprintln!("Unexpected '{key}' value: {value}"),
|
||||
}
|
||||
}
|
||||
"pytest-parametrize-values-type" | "pytest_parametrize_values_type" => {
|
||||
match value.trim() {
|
||||
"tuple" => {
|
||||
flake8_pytest_style.parametrize_values_type =
|
||||
Some(ParametrizeValuesType::Tuple);
|
||||
}
|
||||
"list" => {
|
||||
flake8_pytest_style.parametrize_values_type =
|
||||
Some(ParametrizeValuesType::List);
|
||||
}
|
||||
_ => eprintln!("Unexpected '{key}' value: {value}"),
|
||||
}
|
||||
}
|
||||
"pytest-parametrize-values-row-type" | "pytest_parametrize_values_row_type" => {
|
||||
match value.trim() {
|
||||
"tuple" => {
|
||||
flake8_pytest_style.parametrize_values_row_type =
|
||||
Some(ParametrizeValuesRowType::Tuple);
|
||||
}
|
||||
"list" => {
|
||||
flake8_pytest_style.parametrize_values_row_type =
|
||||
Some(ParametrizeValuesRowType::List);
|
||||
}
|
||||
_ => eprintln!("Unexpected '{key}' value: {value}"),
|
||||
}
|
||||
}
|
||||
"pytest-raises-require-match-for" | "pytest_raises_require_match_for" => {
|
||||
flake8_pytest_style.raises_require_match_for =
|
||||
Some(parser::parse_strings(value.as_ref()));
|
||||
}
|
||||
"pytest-mark-no-parentheses" | "pytest_mark_no_parentheses" => {
|
||||
match parser::parse_bool(value.as_ref()) {
|
||||
Ok(bool) => flake8_pytest_style.mark_parentheses = Some(!bool),
|
||||
Err(e) => eprintln!("Unable to parse '{key}' property: {e}"),
|
||||
}
|
||||
}
|
||||
// Unknown
|
||||
_ => eprintln!("Skipping unsupported property: {key}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set default `convention`.
|
||||
if plugins.contains(&Plugin::Flake8Docstrings) {
|
||||
if pydocstyle.convention.is_none() {
|
||||
pydocstyle.convention = Some(Convention::Pep257);
|
||||
}
|
||||
}
|
||||
|
||||
// Deduplicate and sort.
|
||||
options.select = Some(Vec::from_iter(select));
|
||||
options.ignore = Some(Vec::from_iter(ignore));
|
||||
@@ -240,6 +310,9 @@ pub fn convert(
|
||||
if flake8_errmsg != flake8_errmsg::settings::Options::default() {
|
||||
options.flake8_errmsg = Some(flake8_errmsg);
|
||||
}
|
||||
if flake8_pytest_style != flake8_pytest_style::settings::Options::default() {
|
||||
options.flake8_pytest_style = Some(flake8_pytest_style);
|
||||
}
|
||||
if flake8_quotes != flake8_quotes::settings::Options::default() {
|
||||
options.flake8_quotes = Some(flake8_quotes);
|
||||
}
|
||||
@@ -278,8 +351,8 @@ mod tests {
|
||||
use std::collections::HashMap;
|
||||
|
||||
use anyhow::Result;
|
||||
use ruff::checks_gen::CheckCodePrefix;
|
||||
use ruff::pydocstyle::settings::Convention;
|
||||
use ruff::registry_gen::CheckCodePrefix;
|
||||
use ruff::settings::options::Options;
|
||||
use ruff::settings::pyproject::Pyproject;
|
||||
use ruff::{flake8_quotes, pydocstyle};
|
||||
@@ -328,6 +401,7 @@ mod tests {
|
||||
flake8_annotations: None,
|
||||
flake8_bugbear: None,
|
||||
flake8_errmsg: None,
|
||||
flake8_pytest_style: None,
|
||||
flake8_quotes: None,
|
||||
flake8_tidy_imports: None,
|
||||
flake8_import_conventions: None,
|
||||
@@ -387,6 +461,7 @@ mod tests {
|
||||
flake8_annotations: None,
|
||||
flake8_bugbear: None,
|
||||
flake8_errmsg: None,
|
||||
flake8_pytest_style: None,
|
||||
flake8_quotes: None,
|
||||
flake8_tidy_imports: None,
|
||||
flake8_import_conventions: None,
|
||||
@@ -446,6 +521,7 @@ mod tests {
|
||||
flake8_annotations: None,
|
||||
flake8_bugbear: None,
|
||||
flake8_errmsg: None,
|
||||
flake8_pytest_style: None,
|
||||
flake8_quotes: None,
|
||||
flake8_tidy_imports: None,
|
||||
flake8_import_conventions: None,
|
||||
@@ -505,6 +581,7 @@ mod tests {
|
||||
flake8_annotations: None,
|
||||
flake8_bugbear: None,
|
||||
flake8_errmsg: None,
|
||||
flake8_pytest_style: None,
|
||||
flake8_quotes: None,
|
||||
flake8_tidy_imports: None,
|
||||
flake8_import_conventions: None,
|
||||
@@ -564,6 +641,7 @@ mod tests {
|
||||
flake8_annotations: None,
|
||||
flake8_bugbear: None,
|
||||
flake8_errmsg: None,
|
||||
flake8_pytest_style: None,
|
||||
flake8_quotes: Some(flake8_quotes::settings::Options {
|
||||
inline_quotes: Some(flake8_quotes::settings::Quote::Single),
|
||||
multiline_quotes: None,
|
||||
@@ -619,42 +697,6 @@ mod tests {
|
||||
required_version: None,
|
||||
respect_gitignore: 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::D301,
|
||||
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,
|
||||
@@ -667,6 +709,7 @@ mod tests {
|
||||
flake8_annotations: None,
|
||||
flake8_bugbear: None,
|
||||
flake8_errmsg: None,
|
||||
flake8_pytest_style: None,
|
||||
flake8_quotes: None,
|
||||
flake8_tidy_imports: None,
|
||||
flake8_import_conventions: None,
|
||||
@@ -729,6 +772,7 @@ mod tests {
|
||||
flake8_annotations: None,
|
||||
flake8_bugbear: None,
|
||||
flake8_errmsg: None,
|
||||
flake8_pytest_style: None,
|
||||
flake8_quotes: Some(flake8_quotes::settings::Options {
|
||||
inline_quotes: Some(flake8_quotes::settings::Quote::Single),
|
||||
multiline_quotes: None,
|
||||
|
||||
@@ -3,8 +3,8 @@ use std::str::FromStr;
|
||||
use anyhow::{bail, Result};
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use ruff::checks::PREFIX_REDIRECTS;
|
||||
use ruff::checks_gen::CheckCodePrefix;
|
||||
use ruff::registry::PREFIX_REDIRECTS;
|
||||
use ruff::registry_gen::CheckCodePrefix;
|
||||
use ruff::settings::types::PatternPrefixPair;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
@@ -201,7 +201,7 @@ pub fn collect_per_file_ignores(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use anyhow::Result;
|
||||
use ruff::checks_gen::CheckCodePrefix;
|
||||
use ruff::registry_gen::CheckCodePrefix;
|
||||
use ruff::settings::types::PatternPrefixPair;
|
||||
|
||||
use crate::parser::{parse_files_to_codes_mapping, parse_prefix_codes, parse_strings};
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::fmt;
|
||||
use std::str::FromStr;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use ruff::checks_gen::CheckCodePrefix;
|
||||
use ruff::registry_gen::CheckCodePrefix;
|
||||
|
||||
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
|
||||
pub enum Plugin {
|
||||
@@ -20,6 +20,7 @@ pub enum Plugin {
|
||||
Flake8ErrMsg,
|
||||
Flake8ImplicitStrConcat,
|
||||
Flake8Print,
|
||||
Flake8PytestStyle,
|
||||
Flake8Quotes,
|
||||
Flake8Return,
|
||||
Flake8Simplify,
|
||||
@@ -48,6 +49,7 @@ impl FromStr for Plugin {
|
||||
"flake8-errmsg" => Ok(Plugin::Flake8ErrMsg),
|
||||
"flake8-implicit-str-concat" => Ok(Plugin::Flake8ImplicitStrConcat),
|
||||
"flake8-print" => Ok(Plugin::Flake8Print),
|
||||
"flake8-pytest-style" => Ok(Plugin::Flake8PytestStyle),
|
||||
"flake8-quotes" => Ok(Plugin::Flake8Quotes),
|
||||
"flake8-return" => Ok(Plugin::Flake8Return),
|
||||
"flake8-simplify" => Ok(Plugin::Flake8Simplify),
|
||||
@@ -80,6 +82,7 @@ impl fmt::Debug for Plugin {
|
||||
Plugin::Flake8ErrMsg => "flake8-errmsg",
|
||||
Plugin::Flake8ImplicitStrConcat => "flake8-implicit-str-concat",
|
||||
Plugin::Flake8Print => "flake8-print",
|
||||
Plugin::Flake8PytestStyle => "flake8-pytest-style",
|
||||
Plugin::Flake8Quotes => "flake8-quotes",
|
||||
Plugin::Flake8Return => "flake8-return",
|
||||
Plugin::Flake8Simplify => "flake8-simplify",
|
||||
@@ -111,6 +114,7 @@ impl Plugin {
|
||||
Plugin::Flake8ErrMsg => CheckCodePrefix::EM,
|
||||
Plugin::Flake8ImplicitStrConcat => CheckCodePrefix::ISC,
|
||||
Plugin::Flake8Print => CheckCodePrefix::T2,
|
||||
Plugin::Flake8PytestStyle => CheckCodePrefix::PT,
|
||||
Plugin::Flake8Quotes => CheckCodePrefix::Q,
|
||||
Plugin::Flake8Return => CheckCodePrefix::RET,
|
||||
Plugin::Flake8Simplify => CheckCodePrefix::SIM,
|
||||
@@ -145,13 +149,14 @@ impl Plugin {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Default to PEP8.
|
||||
DocstringConvention::PEP8.select()
|
||||
// Default to PEP257.
|
||||
DocstringConvention::Pep257.select()
|
||||
}
|
||||
Plugin::Flake8Eradicate => vec![CheckCodePrefix::ERA],
|
||||
Plugin::Flake8ErrMsg => vec![CheckCodePrefix::EM],
|
||||
Plugin::Flake8ImplicitStrConcat => vec![CheckCodePrefix::ISC],
|
||||
Plugin::Flake8Print => vec![CheckCodePrefix::T2],
|
||||
Plugin::Flake8PytestStyle => vec![CheckCodePrefix::PT],
|
||||
Plugin::Flake8Quotes => vec![CheckCodePrefix::Q],
|
||||
Plugin::Flake8Return => vec![CheckCodePrefix::RET],
|
||||
Plugin::Flake8Simplify => vec![CheckCodePrefix::SIM],
|
||||
@@ -166,8 +171,8 @@ impl Plugin {
|
||||
|
||||
pub enum DocstringConvention {
|
||||
All,
|
||||
PEP8,
|
||||
NumPy,
|
||||
Pep257,
|
||||
Numpy,
|
||||
Google,
|
||||
}
|
||||
|
||||
@@ -177,8 +182,8 @@ impl FromStr for DocstringConvention {
|
||||
fn from_str(string: &str) -> Result<Self, Self::Err> {
|
||||
match string {
|
||||
"all" => Ok(DocstringConvention::All),
|
||||
"pep8" => Ok(DocstringConvention::PEP8),
|
||||
"numpy" => Ok(DocstringConvention::NumPy),
|
||||
"pep257" => Ok(DocstringConvention::Pep257),
|
||||
"numpy" => Ok(DocstringConvention::Numpy),
|
||||
"google" => Ok(DocstringConvention::Google),
|
||||
_ => Err(anyhow!("Unknown docstring convention: {string}")),
|
||||
}
|
||||
@@ -189,151 +194,14 @@ 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::D301,
|
||||
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::Pep257 => vec![
|
||||
// Covered by the `convention` setting.
|
||||
],
|
||||
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::D301,
|
||||
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![
|
||||
// Covered by the `convention` setting.
|
||||
],
|
||||
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::D301,
|
||||
// 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,
|
||||
// Covered by the `convention` setting.
|
||||
],
|
||||
}
|
||||
}
|
||||
@@ -394,6 +262,25 @@ pub fn infer_plugins_from_options(flake8: &HashMap<String, Option<String>>) -> V
|
||||
"eradicate-whitelist-extend" | "eradicate_whitelist_extend" => {
|
||||
plugins.insert(Plugin::Flake8Eradicate);
|
||||
}
|
||||
// flake8-pytest-style
|
||||
"pytest-fixture-no-parentheses" | "pytest_fixture_no_parentheses " => {
|
||||
plugins.insert(Plugin::Flake8PytestStyle);
|
||||
}
|
||||
"pytest-parametrize-names-type" | "pytest_parametrize_names_type" => {
|
||||
plugins.insert(Plugin::Flake8PytestStyle);
|
||||
}
|
||||
"pytest-parametrize-values-type" | "pytest_parametrize_values_type" => {
|
||||
plugins.insert(Plugin::Flake8PytestStyle);
|
||||
}
|
||||
"pytest-parametrize-values-row-type" | "pytest_parametrize_values_row_type" => {
|
||||
plugins.insert(Plugin::Flake8PytestStyle);
|
||||
}
|
||||
"pytest-raises-require-match-for" | "pytest_raises_require_match_for" => {
|
||||
plugins.insert(Plugin::Flake8PytestStyle);
|
||||
}
|
||||
"pytest-mark-no-parentheses" | "pytest_mark_no_parentheses" => {
|
||||
plugins.insert(Plugin::Flake8PytestStyle);
|
||||
}
|
||||
// flake8-quotes
|
||||
"quotes" | "inline-quotes" | "inline_quotes" => {
|
||||
plugins.insert(Plugin::Flake8Quotes);
|
||||
@@ -485,7 +372,7 @@ pub fn resolve_select(
|
||||
plugins: &[Plugin],
|
||||
) -> BTreeSet<CheckCodePrefix> {
|
||||
// Include default Pyflakes and pycodestyle checks.
|
||||
let mut select = BTreeSet::from([CheckCodePrefix::E, CheckCodePrefix::F, CheckCodePrefix::W]);
|
||||
let mut select = BTreeSet::from([CheckCodePrefix::F, CheckCodePrefix::E, CheckCodePrefix::W]);
|
||||
|
||||
// Add prefix codes for every plugin.
|
||||
for plugin in plugins {
|
||||
|
||||
@@ -11,20 +11,12 @@
|
||||
<title>Ruff Playground</title>
|
||||
<link
|
||||
rel="icon"
|
||||
href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🛠️</text></svg>"
|
||||
href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>⚡</text></svg>"
|
||||
/>
|
||||
<link rel="stylesheet" href="https://rsms.me/inter/inter.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<div style="display: flex; position: fixed; right: 16px; bottom: 16px">
|
||||
<a href="https://GitHub.com/charliermarsh/ruff"
|
||||
><img
|
||||
src="https://img.shields.io/github/stars/charliermarsh/ruff.svg?style=social&label=GitHub&maxAge=2592000&?logoWidth=100"
|
||||
alt="GitHub stars"
|
||||
style="width: 120px"
|
||||
/></a>
|
||||
</div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import classNames from "classnames";
|
||||
import RepoButton from "./RepoButton";
|
||||
import ThemeButton from "./ThemeButton";
|
||||
import ShareButton from "./ShareButton";
|
||||
import { Theme } from "./theme";
|
||||
@@ -83,14 +84,19 @@ export default function Header({
|
||||
/>
|
||||
Settings
|
||||
</button>
|
||||
</div>
|
||||
<div className={"flex items-center min-w-0"}>
|
||||
{version ? (
|
||||
<div className={"flex items-center"}>
|
||||
<div className={"hidden sm:flex items-center"}>
|
||||
<VersionTag>v{version}</VersionTag>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
<div className={"hidden sm:flex items-center min-w-0"}>
|
||||
<ShareButton key={edit} onShare={onShare} />
|
||||
<div className="hidden sm:block mx-6 lg:mx-4 w-px h-6 bg-gray-200 dark:bg-gray-700" />
|
||||
<RepoButton />
|
||||
<div className="hidden sm:block mx-6 lg:mx-4 w-px h-6 bg-gray-200 dark:bg-gray-700" />
|
||||
<div className="hidden sm:block">
|
||||
<ShareButton key={edit} onShare={onShare} />
|
||||
</div>
|
||||
<div className="hidden sm:block mx-6 lg:mx-4 w-px h-6 bg-gray-200 dark:bg-gray-700" />
|
||||
<ThemeButton theme={theme} onChange={onChangeTheme} />
|
||||
</div>
|
||||
|
||||
27
playground/src/Editor/RepoButton.tsx
Normal file
27
playground/src/Editor/RepoButton.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
export default function RepoButton() {
|
||||
return (
|
||||
<a
|
||||
className={"hover:text-ayu-accent/70 text-ayu-accent"}
|
||||
href={"https://github.com/charliermarsh/ruff"}
|
||||
target={"_blank"}
|
||||
rel={"noreferrer"}
|
||||
>
|
||||
<svg
|
||||
xmlns={"http://www.w3.org/2000/svg"}
|
||||
width={"24"}
|
||||
height={"24"}
|
||||
viewBox={"0 0 16 16"}
|
||||
fill={"none"}
|
||||
>
|
||||
<path
|
||||
fillRule={"evenodd"}
|
||||
clipRule={"evenodd"}
|
||||
d={
|
||||
"M8 0C3.58 0 0 3.58 0 8C0 11.54 2.29 14.53 5.47 15.59C5.87 15.66 6.02 15.42 6.02 15.21C6.02 15.02 6.01 14.39 6.01 13.72C4 14.09 3.48 13.23 3.32 12.78C3.23 12.55 2.84 11.84 2.5 11.65C2.22 11.5 1.82 11.13 2.49 11.12C3.12 11.11 3.57 11.7 3.72 11.94C4.44 13.15 5.59 12.81 6.05 12.6C6.12 12.08 6.33 11.73 6.56 11.53C4.78 11.33 2.92 10.64 2.92 7.58C2.92 6.71 3.23 5.99 3.74 5.43C3.66 5.23 3.38 4.41 3.82 3.31C3.82 3.31 4.49 3.1 6.02 4.13C6.66 3.95 7.34 3.86 8.02 3.86C8.7 3.86 9.38 3.95 10.02 4.13C11.55 3.09 12.22 3.31 12.22 3.31C12.66 4.41 12.38 5.23 12.3 5.43C12.81 5.99 13.12 6.7 13.12 7.58C13.12 10.65 11.25 11.33 9.47 11.53C9.76 11.78 10.01 12.26 10.01 13.01C10.01 14.08 10 14.94 10 15.21C10 15.42 10.15 15.67 10.55 15.59C13.71 14.53 16 11.53 16 8C16 3.58 12.42 0 8 0Z"
|
||||
}
|
||||
fill={"currentColor"}
|
||||
/>
|
||||
</svg>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
@@ -28,7 +28,7 @@ export default function ShareButton({ onShare }: { onShare?: () => void }) {
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
className="relative flex-none rounded-md text-sm font-semibold leading-6 py-1.5 px-3 enabled:hover:bg-ayu-accent/80 bg-ayu-accent text-white shadow-sm dark:shadow-highlight/20 disabled:opacity-50"
|
||||
className="relative flex-none rounded-md text-sm font-semibold leading-6 py-1.5 px-3 enabled:hover:bg-ayu-accent/70 bg-ayu-accent text-white shadow-sm dark:shadow-highlight/20 disabled:opacity-50"
|
||||
disabled={!onShare || copied}
|
||||
onClick={
|
||||
onShare
|
||||
|
||||
@@ -56,7 +56,9 @@ export default function SourceEditor({
|
||||
.filter((check) => position.startLineNumber === check.location.row)
|
||||
.filter((check) => check.fix)
|
||||
.map((check) => ({
|
||||
title: `Fix ${check.code}`,
|
||||
title: check.fix
|
||||
? `${check.code}: ${check.fix.message}` ?? `Fix ${check.code}`
|
||||
: "Autofix",
|
||||
id: `fix-${check.code}`,
|
||||
kind: "quickfix",
|
||||
edit: check.fix
|
||||
|
||||
@@ -7,7 +7,7 @@ module.exports = {
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
"ayu-accent": "#f07171",
|
||||
"ayu-accent": "#fa8d3e",
|
||||
"ayu-background": {
|
||||
DEFAULT: "#f8f9fa",
|
||||
dark: "#0b0e14",
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
[build-system]
|
||||
requires = ["maturin>=0.14,<0.15"]
|
||||
build-backend = "maturin"
|
||||
|
||||
[project]
|
||||
name = "ruff"
|
||||
version = "0.0.209"
|
||||
description = "An extremely fast Python linter, written in Rust."
|
||||
authors = [
|
||||
{ name = "Charlie Marsh", email = "charlie.r.marsh@gmail.com" },
|
||||
]
|
||||
maintainers = [
|
||||
{ name = "Charlie Marsh", email = "charlie.r.marsh@gmail.com" },
|
||||
]
|
||||
requires-python = ">=3.7"
|
||||
license = { file = "LICENSE" }
|
||||
keywords = ["automation", "flake8", "pycodestyle", "pyflakes", "pylint", "clippy"]
|
||||
classifiers = [
|
||||
"Development Status :: 3 - Alpha",
|
||||
@@ -17,30 +31,8 @@ classifiers = [
|
||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||
"Topic :: Software Development :: Quality Assurance",
|
||||
]
|
||||
author = "Charlie Marsh"
|
||||
author_email = "charlie.r.marsh@gmail.com"
|
||||
description = "An extremely fast Python linter, written in Rust."
|
||||
requires-python = ">=3.7"
|
||||
|
||||
[project.urls]
|
||||
repository = "https://github.com/charliermarsh/ruff"
|
||||
|
||||
[build-system]
|
||||
requires = ["maturin>=0.14,<0.15"]
|
||||
build-backend = "maturin"
|
||||
urls = { repository = "https://github.com/charliermarsh/ruff-lsp" }
|
||||
|
||||
[tool.maturin]
|
||||
bindings = "bin"
|
||||
strip = true
|
||||
|
||||
[tool.ruff]
|
||||
update-check = true
|
||||
|
||||
[tool.ruff.isort]
|
||||
force-wrap-aliases = true
|
||||
combine-as-imports = true
|
||||
force-single-line = true
|
||||
single-line-exclusions = ["os", "logging.handlers"]
|
||||
|
||||
[tool.ruff.pydocstyle]
|
||||
convention = "google"
|
||||
|
||||
@@ -51,3 +51,12 @@ secret == "s3cr3t"
|
||||
token == "s3cr3t"
|
||||
secrete == "s3cr3t"
|
||||
password == safe == "s3cr3t"
|
||||
|
||||
if token == "1\n2":
|
||||
pass
|
||||
|
||||
if token == "3\t4":
|
||||
pass
|
||||
|
||||
if token == "5\r6":
|
||||
pass
|
||||
|
||||
115
resources/test/fixtures/flake8_pie/PIE790.py
vendored
Normal file
115
resources/test/fixtures/flake8_pie/PIE790.py
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
class Foo:
|
||||
"""buzz"""
|
||||
|
||||
pass # PIE790
|
||||
|
||||
|
||||
if foo:
|
||||
"""foo"""
|
||||
pass # PIE790
|
||||
|
||||
|
||||
if foo:
|
||||
pass
|
||||
else:
|
||||
"""bar"""
|
||||
pass # PIE790
|
||||
|
||||
|
||||
while True:
|
||||
pass
|
||||
else:
|
||||
"""bar"""
|
||||
pass # PIE790
|
||||
|
||||
|
||||
for _ in range(10):
|
||||
pass
|
||||
else:
|
||||
"""bar"""
|
||||
pass # PIE790
|
||||
|
||||
|
||||
async for _ in range(10):
|
||||
pass
|
||||
else:
|
||||
"""bar"""
|
||||
pass # PIE790
|
||||
|
||||
|
||||
def foo() -> None:
|
||||
"""
|
||||
buzz
|
||||
"""
|
||||
|
||||
pass # PIE790
|
||||
|
||||
|
||||
async def foo():
|
||||
"""
|
||||
buzz
|
||||
"""
|
||||
|
||||
pass # PIE790
|
||||
|
||||
|
||||
try:
|
||||
"""
|
||||
buzz
|
||||
"""
|
||||
pass # PIE790
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
|
||||
try:
|
||||
bar()
|
||||
except ValueError:
|
||||
"""bar"""
|
||||
pass # PIE790
|
||||
|
||||
|
||||
for _ in range(10):
|
||||
"""buzz"""
|
||||
pass # PIE790
|
||||
|
||||
async for _ in range(10):
|
||||
"""buzz"""
|
||||
pass # PIE790
|
||||
|
||||
while cond:
|
||||
"""buzz"""
|
||||
pass # PIE790
|
||||
|
||||
|
||||
with bar:
|
||||
"""buzz"""
|
||||
pass # PIE790
|
||||
|
||||
async with bar:
|
||||
"""buzz"""
|
||||
pass # PIE790
|
||||
|
||||
|
||||
class Foo:
|
||||
# bar
|
||||
pass
|
||||
|
||||
|
||||
if foo:
|
||||
# foo
|
||||
pass
|
||||
|
||||
|
||||
class Error(Exception):
|
||||
pass
|
||||
|
||||
|
||||
try:
|
||||
foo()
|
||||
except NetworkError:
|
||||
pass
|
||||
|
||||
|
||||
def foo() -> None:
|
||||
pass
|
||||
33
resources/test/fixtures/flake8_pie/PIE794.py
vendored
Normal file
33
resources/test/fixtures/flake8_pie/PIE794.py
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
class Foo(BaseModel):
|
||||
name = StringField()
|
||||
# ....
|
||||
name = StringField() # PIE794
|
||||
|
||||
def remove(self) -> None:
|
||||
...
|
||||
|
||||
|
||||
class Foo(BaseModel):
|
||||
name: str = StringField()
|
||||
# ....
|
||||
name = StringField() # PIE794
|
||||
|
||||
def foo(self) -> None:
|
||||
...
|
||||
|
||||
|
||||
class User(BaseModel):
|
||||
bar: str = StringField()
|
||||
foo: bool = BooleanField()
|
||||
# ...
|
||||
bar = StringField() # PIE794
|
||||
|
||||
|
||||
class User(BaseModel):
|
||||
@property
|
||||
def buzz(self) -> str:
|
||||
...
|
||||
|
||||
@buzz.setter
|
||||
def buzz(self, value: str | int) -> None:
|
||||
...
|
||||
20
resources/test/fixtures/flake8_pie/PIE807.py
vendored
Normal file
20
resources/test/fixtures/flake8_pie/PIE807.py
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
@dataclass
|
||||
class Foo:
|
||||
foo: List[str] = field(default_factory=lambda: []) # PIE807
|
||||
|
||||
|
||||
class FooTable(BaseTable):
|
||||
bar = fields.ListField(default=lambda: []) # PIE807
|
||||
|
||||
|
||||
class FooTable(BaseTable):
|
||||
bar = fields.ListField(lambda: []) # PIE807
|
||||
|
||||
|
||||
@dataclass
|
||||
class Foo:
|
||||
foo: List[str] = field(default_factory=list)
|
||||
|
||||
|
||||
class FooTable(BaseTable):
|
||||
bar = fields.ListField(list)
|
||||
78
resources/test/fixtures/flake8_pytest_style/PT001.py
vendored
Normal file
78
resources/test/fixtures/flake8_pytest_style/PT001.py
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
import pytest
|
||||
from pytest import fixture
|
||||
from pytest import fixture as aliased
|
||||
|
||||
|
||||
# `import pytest`
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def no_parentheses():
|
||||
return 42
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def parentheses_no_params():
|
||||
return 42
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def parentheses_with_params():
|
||||
return 42
|
||||
|
||||
|
||||
@pytest.fixture(
|
||||
|
||||
)
|
||||
def parentheses_no_params_multiline():
|
||||
return 42
|
||||
|
||||
|
||||
# `from pytest import fixture`
|
||||
|
||||
|
||||
@fixture
|
||||
def imported_from_no_parentheses():
|
||||
return 42
|
||||
|
||||
|
||||
@fixture()
|
||||
def imported_from_parentheses_no_params():
|
||||
return 42
|
||||
|
||||
|
||||
@fixture(scope="module")
|
||||
def imported_from_parentheses_with_params():
|
||||
return 42
|
||||
|
||||
|
||||
@fixture(
|
||||
|
||||
)
|
||||
def imported_from_parentheses_no_params_multiline():
|
||||
return 42
|
||||
|
||||
|
||||
# `from pytest import fixture as aliased`
|
||||
|
||||
|
||||
@aliased
|
||||
def aliased_no_parentheses():
|
||||
return 42
|
||||
|
||||
|
||||
@aliased()
|
||||
def aliased_parentheses_no_params():
|
||||
return 42
|
||||
|
||||
|
||||
@aliased(scope="module")
|
||||
def aliased_parentheses_with_params():
|
||||
return 42
|
||||
|
||||
|
||||
@aliased(
|
||||
|
||||
)
|
||||
def aliased_parentheses_no_params_multiline():
|
||||
return 42
|
||||
21
resources/test/fixtures/flake8_pytest_style/PT002.py
vendored
Normal file
21
resources/test/fixtures/flake8_pytest_style/PT002.py
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def my_fixture(): # OK no args
|
||||
return 0
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def my_fixture(): # OK only kwargs
|
||||
return 0
|
||||
|
||||
|
||||
@pytest.fixture("module")
|
||||
def my_fixture(): # Error only args
|
||||
return 0
|
||||
|
||||
|
||||
@pytest.fixture("module", autouse=True)
|
||||
def my_fixture(): # Error mixed
|
||||
return 0
|
||||
16
resources/test/fixtures/flake8_pytest_style/PT003.py
vendored
Normal file
16
resources/test/fixtures/flake8_pytest_style/PT003.py
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def ok_no_scope():
|
||||
...
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def ok_other_scope():
|
||||
...
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def error():
|
||||
...
|
||||
58
resources/test/fixtures/flake8_pytest_style/PT004.py
vendored
Normal file
58
resources/test/fixtures/flake8_pytest_style/PT004.py
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
import abc
|
||||
from abc import abstractmethod
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def _patch_something(mocker): # OK simple
|
||||
mocker.patch("some.thing")
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def _patch_something(mocker): # OK with return
|
||||
if something:
|
||||
return
|
||||
mocker.patch("some.thing")
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def _activate_context(): # OK with yield
|
||||
with context:
|
||||
yield
|
||||
|
||||
|
||||
class BaseTest:
|
||||
@pytest.fixture()
|
||||
@abc.abstractmethod
|
||||
def my_fixture(): # OK abstract with import abc
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class BaseTest:
|
||||
@pytest.fixture()
|
||||
@abstractmethod
|
||||
def my_fixture(): # OK abstract with from import
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def my_fixture(): # OK ignoring yield from
|
||||
yield from some_generator()
|
||||
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def my_fixture(): # OK ignoring yield value
|
||||
yield 1
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def patch_something(mocker): # Error simple
|
||||
mocker.patch("some.thing")
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def activate_context(): # Error with yield
|
||||
with context:
|
||||
yield
|
||||
57
resources/test/fixtures/flake8_pytest_style/PT005.py
vendored
Normal file
57
resources/test/fixtures/flake8_pytest_style/PT005.py
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
import abc
|
||||
from abc import abstractmethod
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def my_fixture(mocker): # OK with return
|
||||
return 0
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def activate_context(): # OK with yield
|
||||
with get_context() as context:
|
||||
yield context
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def _any_fixture(mocker): # Ok nested function
|
||||
def nested_function():
|
||||
return 1
|
||||
|
||||
mocker.patch("...", nested_function)
|
||||
|
||||
|
||||
class BaseTest:
|
||||
@pytest.fixture()
|
||||
@abc.abstractmethod
|
||||
def _my_fixture(): # OK abstract with import abc
|
||||
return NotImplemented
|
||||
|
||||
|
||||
class BaseTest:
|
||||
@pytest.fixture()
|
||||
@abstractmethod
|
||||
def _my_fixture(): # OK abstract with from import
|
||||
return NotImplemented
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def _my_fixture(mocker): # Error with return
|
||||
return 0
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def _activate_context(): # Error with yield
|
||||
with get_context() as context:
|
||||
yield context
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def _activate_context(): # Error with conditional yield from
|
||||
if some_condition:
|
||||
with get_context() as context:
|
||||
yield context
|
||||
else:
|
||||
yield from other_context()
|
||||
36
resources/test/fixtures/flake8_pytest_style/PT006.py
vendored
Normal file
36
resources/test/fixtures/flake8_pytest_style/PT006.py
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.parametrize("param", [1, 2, 3])
|
||||
def test_always_ok(param):
|
||||
...
|
||||
|
||||
|
||||
@pytest.mark.parametrize("param1,param2", [(1, 2), (3, 4)])
|
||||
def test_csv(param1, param2):
|
||||
...
|
||||
|
||||
|
||||
@pytest.mark.parametrize(" param1, , param2 , ", [(1, 2), (3, 4)])
|
||||
def test_csv_with_whitespace(param1, param2):
|
||||
...
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("param1", "param2"), [(1, 2), (3, 4)])
|
||||
def test_tuple(param1, param2):
|
||||
...
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("param1",), [1, 2, 3])
|
||||
def test_tuple_one_elem(param1, param2):
|
||||
...
|
||||
|
||||
|
||||
@pytest.mark.parametrize(["param1", "param2"], [(1, 2), (3, 4)])
|
||||
def test_list(param1, param2):
|
||||
...
|
||||
|
||||
|
||||
@pytest.mark.parametrize(["param1"], [1, 2, 3])
|
||||
def test_list_one_elem(param1, param2):
|
||||
...
|
||||
55
resources/test/fixtures/flake8_pytest_style/PT007.py
vendored
Normal file
55
resources/test/fixtures/flake8_pytest_style/PT007.py
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.parametrize("param", (1, 2))
|
||||
def test_tuple(param):
|
||||
...
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("param1", "param2"),
|
||||
(
|
||||
(1, 2),
|
||||
(3, 4),
|
||||
),
|
||||
)
|
||||
def test_tuple_of_tuples(param1, param2):
|
||||
...
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("param1", "param2"),
|
||||
(
|
||||
[1, 2],
|
||||
[3, 4],
|
||||
),
|
||||
)
|
||||
def test_tuple_of_lists(param1, param2):
|
||||
...
|
||||
|
||||
|
||||
@pytest.mark.parametrize("param", [1, 2])
|
||||
def test_list(param):
|
||||
...
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("param1", "param2"),
|
||||
[
|
||||
(1, 2),
|
||||
(3, 4),
|
||||
],
|
||||
)
|
||||
def test_list_of_tuples(param1, param2):
|
||||
...
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("param1", "param2"),
|
||||
[
|
||||
[1, 2],
|
||||
[3, 4],
|
||||
],
|
||||
)
|
||||
def test_list_of_lists(param1, param2):
|
||||
...
|
||||
48
resources/test/fixtures/flake8_pytest_style/PT008.py
vendored
Normal file
48
resources/test/fixtures/flake8_pytest_style/PT008.py
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
# OK
|
||||
|
||||
mocker.patch("module.name", not_lambda)
|
||||
module_mocker.patch("module.name", not_lambda)
|
||||
mocker.patch.object(obj, "attr", not_lambda)
|
||||
module_mocker.patch.object(obj, "attr", not_lambda)
|
||||
|
||||
mocker.patch("module.name", return_value=None)
|
||||
module_mocker.patch("module.name", return_value=None)
|
||||
mocker.patch.object(obj, "attr", return_value=None)
|
||||
module_mocker.patch.object(obj, "attr", return_value=None)
|
||||
|
||||
mocker.patch("module.name", lambda x, y: x)
|
||||
module_mocker.patch("module.name", lambda x, y: x)
|
||||
mocker.patch.object(obj, "attr", lambda x, y: x)
|
||||
module_mocker.patch.object(obj, "attr", lambda x, y: x)
|
||||
|
||||
mocker.patch("module.name", lambda *args: args)
|
||||
module_mocker.patch("module.name", lambda *args: args)
|
||||
mocker.patch.object(obj, "attr", lambda *args: args)
|
||||
module_mocker.patch.object(obj, "attr", lambda *args: args)
|
||||
|
||||
mocker.patch("module.name", lambda **kwargs: kwargs)
|
||||
module_mocker.patch("module.name", lambda **kwargs: kwargs)
|
||||
mocker.patch.object(obj, "attr", lambda **kwargs: kwargs)
|
||||
module_mocker.patch.object(obj, "attr", lambda **kwargs: kwargs)
|
||||
|
||||
mocker.patch("module.name", lambda x, /, y: x)
|
||||
module_mocker.patch("module.name", lambda x, /, y: x)
|
||||
mocker.patch.object(obj, "attr", lambda x, /, y: x)
|
||||
module_mocker.patch.object(obj, "attr", lambda x, /, y: x)
|
||||
|
||||
# Error
|
||||
|
||||
mocker.patch("module.name", lambda: None)
|
||||
module_mocker.patch("module.name", lambda: None)
|
||||
mocker.patch.object(obj, "attr", lambda: None)
|
||||
module_mocker.patch.object(obj, "attr", lambda: None)
|
||||
|
||||
mocker.patch("module.name", lambda x, y: None)
|
||||
module_mocker.patch("module.name", lambda x, y: None)
|
||||
mocker.patch.object(obj, "attr", lambda x, y: None)
|
||||
module_mocker.patch.object(obj, "attr", lambda x, y: None)
|
||||
|
||||
mocker.patch("module.name", lambda *args, **kwargs: None)
|
||||
module_mocker.patch("module.name", lambda *args, **kwargs: None)
|
||||
mocker.patch.object(obj, "attr", lambda *args, **kwargs: None)
|
||||
module_mocker.patch.object(obj, "attr", lambda *args, **kwargs: None)
|
||||
9
resources/test/fixtures/flake8_pytest_style/PT009.py
vendored
Normal file
9
resources/test/fixtures/flake8_pytest_style/PT009.py
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
import pytest
|
||||
|
||||
|
||||
def test_xxx():
|
||||
assert 1 == 1 # OK no parameters
|
||||
|
||||
|
||||
def test_xxx():
|
||||
self.assertEqual(1, 1) # Error
|
||||
11
resources/test/fixtures/flake8_pytest_style/PT010.py
vendored
Normal file
11
resources/test/fixtures/flake8_pytest_style/PT010.py
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
import pytest
|
||||
|
||||
|
||||
def test_ok():
|
||||
with pytest.raises():
|
||||
pass
|
||||
|
||||
|
||||
def test_error():
|
||||
with pytest.raises(UnicodeError):
|
||||
pass
|
||||
32
resources/test/fixtures/flake8_pytest_style/PT011.py
vendored
Normal file
32
resources/test/fixtures/flake8_pytest_style/PT011.py
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
import socket
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
def test_ok():
|
||||
with pytest.raises(ValueError, match="Can't divide by 0"):
|
||||
raise ValueError("Can't divide by 0")
|
||||
|
||||
|
||||
def test_ok_different_error_from_config():
|
||||
with pytest.raises(ZeroDivisionError):
|
||||
raise ZeroDivisionError("Can't divide by 0")
|
||||
|
||||
|
||||
def test_error_no_argument_given():
|
||||
with pytest.raises(ValueError):
|
||||
raise ValueError("Can't divide 1 by 0")
|
||||
|
||||
with pytest.raises(socket.error):
|
||||
raise ValueError("Can't divide 1 by 0")
|
||||
|
||||
|
||||
def test_error_match_is_empty():
|
||||
with pytest.raises(ValueError, match=None):
|
||||
raise ValueError("Can't divide 1 by 0")
|
||||
|
||||
with pytest.raises(ValueError, match=""):
|
||||
raise ValueError("Can't divide 1 by 0")
|
||||
|
||||
with pytest.raises(ValueError, match=f""):
|
||||
raise ValueError("Can't divide 1 by 0")
|
||||
64
resources/test/fixtures/flake8_pytest_style/PT012.py
vendored
Normal file
64
resources/test/fixtures/flake8_pytest_style/PT012.py
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
import pytest
|
||||
|
||||
|
||||
def test_ok():
|
||||
with pytest.raises(AttributeError):
|
||||
[].size
|
||||
|
||||
|
||||
async def test_ok_trivial_with():
|
||||
with pytest.raises(AttributeError):
|
||||
with context_manager_under_test():
|
||||
pass
|
||||
|
||||
with pytest.raises(AttributeError):
|
||||
async with context_manager_under_test():
|
||||
pass
|
||||
|
||||
|
||||
def test_ok_complex_single_call():
|
||||
with pytest.raises(AttributeError):
|
||||
my_func(
|
||||
[].size,
|
||||
[].size,
|
||||
)
|
||||
|
||||
|
||||
def test_error_multiple_statements():
|
||||
with pytest.raises(AttributeError):
|
||||
len([])
|
||||
[].size
|
||||
|
||||
|
||||
async def test_error_complex_statement():
|
||||
with pytest.raises(AttributeError):
|
||||
if True:
|
||||
[].size
|
||||
|
||||
with pytest.raises(AttributeError):
|
||||
for i in []:
|
||||
[].size
|
||||
|
||||
with pytest.raises(AttributeError):
|
||||
async for i in []:
|
||||
[].size
|
||||
|
||||
with pytest.raises(AttributeError):
|
||||
while True:
|
||||
[].size
|
||||
|
||||
with pytest.raises(AttributeError):
|
||||
with context_manager_under_test():
|
||||
[].size
|
||||
|
||||
with pytest.raises(AttributeError):
|
||||
async with context_manager_under_test():
|
||||
[].size
|
||||
|
||||
|
||||
def test_error_try():
|
||||
with pytest.raises(AttributeError):
|
||||
try:
|
||||
[].size
|
||||
except:
|
||||
raise
|
||||
13
resources/test/fixtures/flake8_pytest_style/PT013.py
vendored
Normal file
13
resources/test/fixtures/flake8_pytest_style/PT013.py
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
# OK
|
||||
|
||||
import pytest
|
||||
import pytest as pytest
|
||||
from notpytest import fixture
|
||||
from . import fixture
|
||||
from .pytest import fixture
|
||||
|
||||
# Error
|
||||
|
||||
import pytest as other_name
|
||||
from pytest import fixture
|
||||
from pytest import fixture as other_name
|
||||
25
resources/test/fixtures/flake8_pytest_style/PT015.py
vendored
Normal file
25
resources/test/fixtures/flake8_pytest_style/PT015.py
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
import pytest
|
||||
|
||||
|
||||
def test_ok():
|
||||
assert [0]
|
||||
|
||||
|
||||
def test_error():
|
||||
assert None
|
||||
assert False
|
||||
assert 0
|
||||
assert 0.0
|
||||
assert ""
|
||||
assert f""
|
||||
assert []
|
||||
assert ()
|
||||
assert {}
|
||||
assert list()
|
||||
assert set()
|
||||
assert tuple()
|
||||
assert dict()
|
||||
assert frozenset()
|
||||
assert list([])
|
||||
assert set(set())
|
||||
assert tuple("")
|
||||
17
resources/test/fixtures/flake8_pytest_style/PT016.py
vendored
Normal file
17
resources/test/fixtures/flake8_pytest_style/PT016.py
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
import pytest
|
||||
|
||||
|
||||
def test_xxx():
|
||||
pytest.fail("this is a failure") # Test OK arg
|
||||
|
||||
|
||||
def test_xxx():
|
||||
pytest.fail(msg="this is a failure") # Test OK kwarg
|
||||
|
||||
|
||||
def test_xxx(): # Error
|
||||
pytest.fail()
|
||||
pytest.fail("")
|
||||
pytest.fail(f"")
|
||||
pytest.fail(msg="")
|
||||
pytest.fail(msg=f"")
|
||||
19
resources/test/fixtures/flake8_pytest_style/PT017.py
vendored
Normal file
19
resources/test/fixtures/flake8_pytest_style/PT017.py
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
import pytest
|
||||
|
||||
|
||||
def test_ok():
|
||||
try:
|
||||
something()
|
||||
except Exception as e:
|
||||
something_else()
|
||||
|
||||
with pytest.raises(ZeroDivisionError) as e:
|
||||
1 / 0
|
||||
assert e.value.message
|
||||
|
||||
|
||||
def test_error():
|
||||
try:
|
||||
something()
|
||||
except Exception as e:
|
||||
assert e.message, "blah blah"
|
||||
18
resources/test/fixtures/flake8_pytest_style/PT018.py
vendored
Normal file
18
resources/test/fixtures/flake8_pytest_style/PT018.py
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
import pytest
|
||||
|
||||
|
||||
def test_ok():
|
||||
assert something
|
||||
assert something or something_else
|
||||
assert something or something_else and something_third
|
||||
assert not (something and something_else)
|
||||
|
||||
|
||||
def test_error():
|
||||
assert something and something_else
|
||||
assert something and something_else and something_third
|
||||
assert something and not something_else
|
||||
assert something and (something_else or something_third)
|
||||
assert not (something or something_else)
|
||||
assert not (something or something_else or something_third)
|
||||
assert not (something or something_else and something_third)
|
||||
14
resources/test/fixtures/flake8_pytest_style/PT019.py
vendored
Normal file
14
resources/test/fixtures/flake8_pytest_style/PT019.py
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
def test_xxx(fixture): # Ok good param name
|
||||
pass
|
||||
|
||||
|
||||
def xxx(_param): # Ok not a test
|
||||
pass
|
||||
|
||||
|
||||
def test_xxx(_fixture): # Error arg
|
||||
pass
|
||||
|
||||
|
||||
def test_xxx(*, _fixture): # Error kwonly
|
||||
pass
|
||||
21
resources/test/fixtures/flake8_pytest_style/PT020.py
vendored
Normal file
21
resources/test/fixtures/flake8_pytest_style/PT020.py
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def ok_no_parameters():
|
||||
return 0
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def ok_without_parens():
|
||||
return 0
|
||||
|
||||
|
||||
@pytest.yield_fixture()
|
||||
def error_without_parens():
|
||||
return 0
|
||||
|
||||
|
||||
@pytest.yield_fixture
|
||||
def error_with_parens():
|
||||
return 0
|
||||
58
resources/test/fixtures/flake8_pytest_style/PT021.py
vendored
Normal file
58
resources/test/fixtures/flake8_pytest_style/PT021.py
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
import functools
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def my_fixture(): # OK return
|
||||
return 0
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def my_fixture(): # OK yield
|
||||
resource = acquire_resource()
|
||||
yield resource
|
||||
resource.release()
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def my_fixture(): # OK other request
|
||||
request = get_request()
|
||||
request.addfinalizer(finalizer)
|
||||
return request
|
||||
|
||||
|
||||
def create_resource(arg, request): # OK other function
|
||||
resource = Resource(arg)
|
||||
request.addfinalizer(resource.release)
|
||||
return resource
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def resource_factory(request):
|
||||
return functools.partial(create_resource, request=request)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def resource_factory(request): # OK other function
|
||||
def create_resource(arg) -> Resource:
|
||||
resource = Resource(arg)
|
||||
request.addfinalizer(resource.release)
|
||||
return resource
|
||||
|
||||
return create_resource
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def my_fixture(request): # Error return
|
||||
resource = acquire_resource()
|
||||
request.addfinalizer(resource.release)
|
||||
return resource
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def my_fixture(request): # Error yield
|
||||
resource = acquire_resource()
|
||||
request.addfinalizer(resource.release)
|
||||
yield resource
|
||||
resource # prevent PT022
|
||||
17
resources/test/fixtures/flake8_pytest_style/PT022.py
vendored
Normal file
17
resources/test/fixtures/flake8_pytest_style/PT022.py
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def ok_complex_logic():
|
||||
if some_condition:
|
||||
resource = acquire_resource()
|
||||
yield resource
|
||||
resource.release()
|
||||
return
|
||||
yield None
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def error():
|
||||
resource = acquire_resource()
|
||||
yield resource
|
||||
74
resources/test/fixtures/flake8_pytest_style/PT023.py
vendored
Normal file
74
resources/test/fixtures/flake8_pytest_style/PT023.py
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.foo(scope="module")
|
||||
def ok_with_parameters_regardless_of_config():
|
||||
pass
|
||||
|
||||
|
||||
# Without parentheses
|
||||
|
||||
|
||||
@pytest.mark.foo
|
||||
def test_something():
|
||||
pass
|
||||
|
||||
|
||||
@pytest.mark.foo
|
||||
class TestClass:
|
||||
def test_something():
|
||||
pass
|
||||
|
||||
|
||||
class TestClass:
|
||||
@pytest.mark.foo
|
||||
def test_something():
|
||||
pass
|
||||
|
||||
|
||||
class TestClass:
|
||||
@pytest.mark.foo
|
||||
class TestNestedClass:
|
||||
def test_something():
|
||||
pass
|
||||
|
||||
|
||||
class TestClass:
|
||||
class TestNestedClass:
|
||||
@pytest.mark.foo
|
||||
def test_something():
|
||||
pass
|
||||
|
||||
|
||||
# With parentheses
|
||||
|
||||
|
||||
@pytest.mark.foo()
|
||||
def test_something():
|
||||
pass
|
||||
|
||||
|
||||
@pytest.mark.foo()
|
||||
class TestClass:
|
||||
def test_something():
|
||||
pass
|
||||
|
||||
|
||||
class TestClass:
|
||||
@pytest.mark.foo()
|
||||
def test_something():
|
||||
pass
|
||||
|
||||
|
||||
class TestClass:
|
||||
@pytest.mark.foo()
|
||||
class TestNestedClass:
|
||||
def test_something():
|
||||
pass
|
||||
|
||||
|
||||
class TestClass:
|
||||
class TestNestedClass:
|
||||
@pytest.mark.foo()
|
||||
def test_something():
|
||||
pass
|
||||
35
resources/test/fixtures/flake8_pytest_style/PT024.py
vendored
Normal file
35
resources/test/fixtures/flake8_pytest_style/PT024.py
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.asyncio()
|
||||
async def test_something(): # Ok not fixture
|
||||
pass
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_something(): # Ok not fixture no parens
|
||||
pass
|
||||
|
||||
|
||||
@pytest.mark.asyncio()
|
||||
@pytest.fixture()
|
||||
async def my_fixture(): # Error before
|
||||
return 0
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.fixture()
|
||||
async def my_fixture(): # Error before no parens
|
||||
return 0
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
@pytest.mark.asyncio()
|
||||
async def my_fixture(): # Error after
|
||||
return 0
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
@pytest.mark.asyncio
|
||||
async def my_fixture(): # Error after no parens
|
||||
return 0
|
||||
18
resources/test/fixtures/flake8_pytest_style/PT025.py
vendored
Normal file
18
resources/test/fixtures/flake8_pytest_style/PT025.py
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("a")
|
||||
def test_something(): # Ok not fixture
|
||||
pass
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("a")
|
||||
@pytest.fixture()
|
||||
def my_fixture(): # Error before
|
||||
return 0
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
@pytest.mark.usefixtures("a")
|
||||
def my_fixture(): # Error after
|
||||
return 0
|
||||
26
resources/test/fixtures/flake8_pytest_style/PT026.py
vendored
Normal file
26
resources/test/fixtures/flake8_pytest_style/PT026.py
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("a")
|
||||
def test_ok():
|
||||
pass
|
||||
|
||||
|
||||
@pytest.mark.foo()
|
||||
def test_ok_another_mark_with_parens():
|
||||
pass
|
||||
|
||||
|
||||
@pytest.mark.foo
|
||||
def test_ok_another_mark_no_parens():
|
||||
pass
|
||||
|
||||
|
||||
@pytest.mark.usefixtures()
|
||||
def test_error_with_parens():
|
||||
pass
|
||||
|
||||
|
||||
@pytest.mark.usefixtures
|
||||
def test_error_no_parens():
|
||||
pass
|
||||
11
resources/test/fixtures/flake8_return/RET504.py
vendored
11
resources/test/fixtures/flake8_return/RET504.py
vendored
@@ -137,6 +137,14 @@ def x():
|
||||
return a
|
||||
|
||||
|
||||
# Considered OK, since attribute assignments can have side effects.
|
||||
class X:
|
||||
def x(self):
|
||||
a = self.property
|
||||
self.property = None
|
||||
return a
|
||||
|
||||
|
||||
# Test cases for using value for assignment then returning it
|
||||
# See:https://github.com/afonasev/flake8-return/issues/47
|
||||
def resolve_from_url(self, url: str) -> dict:
|
||||
@@ -238,13 +246,16 @@ def close(self):
|
||||
report(traceback.format_exc())
|
||||
return any_failed
|
||||
|
||||
|
||||
def global_assignment():
|
||||
global X
|
||||
X = 1
|
||||
return X
|
||||
|
||||
|
||||
def nonlocal_assignment():
|
||||
X = 1
|
||||
|
||||
def inner():
|
||||
nonlocal X
|
||||
X = 1
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
key in dict.keys() # SIM118
|
||||
key in obj.keys() # SIM118
|
||||
|
||||
foo["bar"] in dict.keys() # SIM118
|
||||
foo["bar"] in obj.keys() # SIM118
|
||||
|
||||
foo() in dict.keys() # SIM118
|
||||
foo['bar'] in obj.keys() # SIM118
|
||||
|
||||
for key in dict.keys(): # SIM118
|
||||
foo() in obj.keys() # SIM118
|
||||
|
||||
for key in obj.keys(): # SIM118
|
||||
pass
|
||||
|
||||
for key in list(dict.keys()):
|
||||
for key in list(obj.keys()):
|
||||
if some_property(key):
|
||||
del dict[key]
|
||||
del obj[key]
|
||||
|
||||
14
resources/test/fixtures/flake8_simplify/SIM222.py
vendored
Normal file
14
resources/test/fixtures/flake8_simplify/SIM222.py
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
if a or True: # SIM223
|
||||
pass
|
||||
|
||||
if (a or b) or True: # SIM223
|
||||
pass
|
||||
|
||||
if a or (b or True): # SIM223
|
||||
pass
|
||||
|
||||
if a and True:
|
||||
pass
|
||||
|
||||
if True:
|
||||
pass
|
||||
14
resources/test/fixtures/flake8_simplify/SIM223.py
vendored
Normal file
14
resources/test/fixtures/flake8_simplify/SIM223.py
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
if a and False: # SIM223
|
||||
pass
|
||||
|
||||
if (a or b) and False: # SIM223
|
||||
pass
|
||||
|
||||
if a or (b and False): # SIM223
|
||||
pass
|
||||
|
||||
if a or False:
|
||||
pass
|
||||
|
||||
if False:
|
||||
pass
|
||||
12
resources/test/fixtures/flake8_simplify/SIM300.py
vendored
Normal file
12
resources/test/fixtures/flake8_simplify/SIM300.py
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
# Errors
|
||||
"yoda" == compare # SIM300
|
||||
'yoda' == compare # SIM300
|
||||
42 == age # SIM300
|
||||
|
||||
# OK
|
||||
compare == "yoda"
|
||||
age == 42
|
||||
x == y
|
||||
"yoda" == compare == 1
|
||||
"yoda" == compare == someothervar
|
||||
"yoda" == "yoda"
|
||||
5
resources/test/fixtures/isort/comments.py
vendored
5
resources/test/fixtures/isort/comments.py
vendored
@@ -26,3 +26,8 @@ from A import (
|
||||
|
||||
from D import a_long_name_to_force_multiple_lines # Comment 12
|
||||
from D import another_long_name_to_force_multiple_lines # Comment 13
|
||||
|
||||
from E import a # Comment 1
|
||||
|
||||
from F import a # Comment 1
|
||||
from F import b
|
||||
|
||||
1
resources/test/fixtures/isort/line_ending_cr.py
vendored
Normal file
1
resources/test/fixtures/isort/line_ending_cr.py
vendored
Normal file
@@ -0,0 +1 @@
|
||||
from long_module_name import member_one, member_two, member_three, member_four, member_five
|
||||
2
resources/test/fixtures/isort/line_ending_crlf.py
vendored
Normal file
2
resources/test/fixtures/isort/line_ending_crlf.py
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
from long_module_name import member_one, member_two, member_three, member_four, member_five
|
||||
|
||||
2
resources/test/fixtures/isort/line_ending_lf.py
vendored
Normal file
2
resources/test/fixtures/isort/line_ending_lf.py
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
from long_module_name import member_one, member_two, member_three, member_four, member_five
|
||||
|
||||
0
resources/test/fixtures/pydocstyle/D104/__init__.py
vendored
Normal file
0
resources/test/fixtures/pydocstyle/D104/__init__.py
vendored
Normal file
22
resources/test/fixtures/pydocstyle/D400.py
vendored
22
resources/test/fixtures/pydocstyle/D400.py
vendored
@@ -35,7 +35,6 @@ def f():
|
||||
...
|
||||
|
||||
|
||||
|
||||
def f():
|
||||
r"Here's a line without a period"
|
||||
...
|
||||
@@ -71,3 +70,24 @@ def f():
|
||||
Here's a line without a period,
|
||||
but here's the next line with trailing space """
|
||||
...
|
||||
|
||||
|
||||
def f(rounds: list[int], number: int) -> bool:
|
||||
"""
|
||||
:param rounds: list - rounds played.
|
||||
:param number: int - round number.
|
||||
:return: bool - was the round played?
|
||||
"""
|
||||
return number in rounds
|
||||
|
||||
|
||||
def f(rounds: list[int], number: int) -> bool:
|
||||
"""
|
||||
Args:
|
||||
rounds (list): rounds played.
|
||||
number (int): round number.
|
||||
|
||||
Returns:
|
||||
bool: was the round played?
|
||||
"""
|
||||
return number in rounds
|
||||
|
||||
@@ -376,7 +376,7 @@ class TestGoogle: # noqa: D203
|
||||
Etiam at tellus a tellus faucibus maximus. Curabitur tellus
|
||||
mauris, semper id vehicula ac, feugiat ut tortor.
|
||||
verbose (bool):
|
||||
If True, print out as much infromation as possible.
|
||||
If True, print out as much information as possible.
|
||||
If False, print out concise "one-liner" information.
|
||||
|
||||
"""
|
||||
|
||||
68
resources/test/fixtures/pyflakes/F401_7.py
vendored
68
resources/test/fixtures/pyflakes/F401_7.py
vendored
@@ -1,16 +1,66 @@
|
||||
"""Test: noqa directives."""
|
||||
|
||||
from module import (
|
||||
A, # noqa: F401
|
||||
B,
|
||||
# This should ignore both errors.
|
||||
from typing import ( # noqa: F401
|
||||
List,
|
||||
Sequence,
|
||||
)
|
||||
|
||||
from module import (
|
||||
A, # noqa: F401
|
||||
B, # noqa: F401
|
||||
# This should ignore both errors.
|
||||
from typing import ( # noqa
|
||||
List,
|
||||
Sequence,
|
||||
)
|
||||
|
||||
from module import (
|
||||
A,
|
||||
B,
|
||||
# This should ignore both errors.
|
||||
from typing import (
|
||||
List, # noqa: F401
|
||||
Sequence, # noqa: F401
|
||||
)
|
||||
|
||||
# This should ignore both errors.
|
||||
from typing import (
|
||||
List, # noqa
|
||||
Sequence, # noqa
|
||||
)
|
||||
|
||||
# This should ignore the first error.
|
||||
from typing import (
|
||||
Mapping, # noqa: F401
|
||||
Union,
|
||||
)
|
||||
|
||||
# This should ignore both errors.
|
||||
from typing import ( # noqa
|
||||
List,
|
||||
Sequence,
|
||||
)
|
||||
|
||||
# This should ignore the error, but the inner noqa should be marked as unused.
|
||||
from typing import ( # noqa: F401
|
||||
Optional, # noqa: F401
|
||||
)
|
||||
|
||||
# This should ignore the error, but the inner noqa should be marked as unused.
|
||||
from typing import ( # noqa
|
||||
Optional, # noqa: F401
|
||||
)
|
||||
|
||||
# This should ignore the error, but mark F501 as unused.
|
||||
from typing import ( # noqa: F401
|
||||
Dict, # noqa: F501
|
||||
)
|
||||
|
||||
# This should ignore the error, but mark F501 as unused.
|
||||
from typing import ( # noqa: F501
|
||||
Tuple, # noqa: F401
|
||||
)
|
||||
|
||||
# This should ignore both errors.
|
||||
from typing import Any, AnyStr # noqa: F401
|
||||
|
||||
# This should ignore both errors.
|
||||
from typing import AsyncIterable, AsyncGenerator # noqa
|
||||
|
||||
# This should mark F501 as unused.
|
||||
from typing import Awaitable, AwaitableGenerator # noqa: F501
|
||||
|
||||
23
resources/test/fixtures/pyflakes/F541.py
vendored
23
resources/test/fixtures/pyflakes/F541.py
vendored
@@ -1,12 +1,35 @@
|
||||
# OK
|
||||
a = "abc"
|
||||
b = f"ghi{'jkl'}"
|
||||
|
||||
# Errors
|
||||
c = f"def"
|
||||
d = f"def" + "ghi"
|
||||
e = (
|
||||
f"def" +
|
||||
"ghi"
|
||||
)
|
||||
f = (
|
||||
f"a"
|
||||
F"b"
|
||||
"c"
|
||||
rf"d"
|
||||
fr"e"
|
||||
)
|
||||
g = f""
|
||||
|
||||
# OK
|
||||
g = f"ghi{123:{45}}"
|
||||
|
||||
# Error
|
||||
h = "x" "y" f"z"
|
||||
|
||||
v = 23.234234
|
||||
|
||||
# OK
|
||||
f"{v:0.2f}"
|
||||
f"{f'{v:0.2f}'}"
|
||||
|
||||
# Errors
|
||||
f"{v:{f'0.2f'}}"
|
||||
f"{f''}"
|
||||
|
||||
3
resources/test/fixtures/pyflakes/F821_0.py
vendored
3
resources/test/fixtures/pyflakes/F821_0.py
vendored
@@ -89,7 +89,8 @@ A = (
|
||||
f'B'
|
||||
f'{B}'
|
||||
)
|
||||
|
||||
C = f'{A:{B}}'
|
||||
C = f'{A:{f"{B}"}}'
|
||||
|
||||
from typing import Annotated, Literal
|
||||
|
||||
|
||||
10
resources/test/fixtures/pyflakes/F831.py
vendored
10
resources/test/fixtures/pyflakes/F831.py
vendored
@@ -1,10 +0,0 @@
|
||||
def foo(x: int, y: int, x: int) -> None:
|
||||
pass
|
||||
|
||||
|
||||
def bar(x: int, y: int, *, x: int) -> None:
|
||||
pass
|
||||
|
||||
|
||||
def baz(x: int, y: int, **x: int) -> None:
|
||||
pass
|
||||
6
resources/test/fixtures/pyflakes/F841_2.py
vendored
Normal file
6
resources/test/fixtures/pyflakes/F841_2.py
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
# test case for https://github.com/charliermarsh/ruff/issues/1552
|
||||
def _():
|
||||
x = 0
|
||||
list()[x:]
|
||||
@@ -18,8 +18,8 @@ def isinstances():
|
||||
|
||||
result = isinstance(var[5], int) or True or isinstance(var[5], float) # [consider-merging-isinstance]
|
||||
|
||||
infered_isinstance = isinstance
|
||||
result = infered_isinstance(var[6], int) or infered_isinstance(var[6], float) or infered_isinstance(var[6], list) and False # [consider-merging-isinstance]
|
||||
inferred_isinstance = isinstance
|
||||
result = inferred_isinstance(var[6], int) or inferred_isinstance(var[6], float) or inferred_isinstance(var[6], list) and False # [consider-merging-isinstance]
|
||||
result = isinstance(var[10], str) or isinstance(var[10], int) and var[8] * 14 or isinstance(var[10], float) and var[5] * 14.4 or isinstance(var[10], list) # [consider-merging-isinstance]
|
||||
result = isinstance(var[11], int) or isinstance(var[11], int) or isinstance(var[11], float) # [consider-merging-isinstance]
|
||||
|
||||
|
||||
9
resources/test/fixtures/pyproject.toml
vendored
9
resources/test/fixtures/pyproject.toml
vendored
@@ -54,3 +54,12 @@ pandas = "pd"
|
||||
|
||||
[tool.ruff.flake8-import-conventions.extend-aliases]
|
||||
"dask.dataframe" = "dd"
|
||||
|
||||
[tool.ruff.flake8-pytest-style]
|
||||
fixture-parentheses = false
|
||||
parametrize-names-type = "csv"
|
||||
parametrize-values-type = "tuple"
|
||||
parametrize-values-row-type = "list"
|
||||
raises-require-match-for = ["Exception", "TypeError", "KeyError"]
|
||||
raises-extend-require-match-for = ["requests.RequestException"]
|
||||
mark-parentheses = false
|
||||
|
||||
4
resources/test/fixtures/pyupgrade/UP012.py
vendored
4
resources/test/fixtures/pyupgrade/UP012.py
vendored
@@ -45,8 +45,8 @@ f"foo{bar}".encode(encoding)
|
||||
"unicode text©".encode()
|
||||
"unicode text©".encode(encoding="UTF8") # "unicode text©".encode()
|
||||
|
||||
r"fo\o".encode("utf-8") # br"fo\o"
|
||||
r"foo\o".encode("utf-8") # br"foo\o"
|
||||
u"foo".encode("utf-8") # b"foo"
|
||||
R"fo\o".encode("utf-8") # br"fo\o"
|
||||
R"foo\o".encode("utf-8") # br"foo\o"
|
||||
U"foo".encode("utf-8") # b"foo"
|
||||
print("foo".encode()) # print(b"foo")
|
||||
|
||||
98
resources/test/fixtures/pyupgrade/UP024_0.py
vendored
Normal file
98
resources/test/fixtures/pyupgrade/UP024_0.py
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
import mmap, select, socket
|
||||
from mmap import error
|
||||
# These should be fixed
|
||||
try:
|
||||
pass
|
||||
except EnvironmentError:
|
||||
pass
|
||||
|
||||
try:
|
||||
pass
|
||||
except IOError:
|
||||
pass
|
||||
|
||||
try:
|
||||
pass
|
||||
except WindowsError:
|
||||
pass
|
||||
|
||||
try:
|
||||
pass
|
||||
except mmap.error:
|
||||
pass
|
||||
|
||||
try:
|
||||
pass
|
||||
except select.error:
|
||||
pass
|
||||
|
||||
try:
|
||||
pass
|
||||
except socket.error:
|
||||
pass
|
||||
|
||||
try:
|
||||
pass
|
||||
except error:
|
||||
pass
|
||||
|
||||
# Should NOT be in parentheses when replaced
|
||||
|
||||
try:
|
||||
pass
|
||||
except (IOError,):
|
||||
pass
|
||||
try:
|
||||
pass
|
||||
except (mmap.error,):
|
||||
pass
|
||||
try:
|
||||
pass
|
||||
except (EnvironmentError, IOError, OSError, select.error):
|
||||
pass
|
||||
|
||||
# Should be kept in parentheses (because multiple)
|
||||
|
||||
try:
|
||||
pass
|
||||
except (IOError, KeyError, OSError):
|
||||
pass
|
||||
|
||||
# First should change, second should not
|
||||
from .mmap import error
|
||||
try:
|
||||
pass
|
||||
except (IOError, error):
|
||||
pass
|
||||
# These should not change
|
||||
|
||||
from foo import error
|
||||
|
||||
try:
|
||||
pass
|
||||
except (OSError, error):
|
||||
pass
|
||||
|
||||
try:
|
||||
pass
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
pass
|
||||
except AssertionError:
|
||||
pass
|
||||
try:
|
||||
pass
|
||||
except (mmap).error:
|
||||
pass
|
||||
|
||||
try:
|
||||
pass
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
try:
|
||||
pass
|
||||
except (OSError, KeyError):
|
||||
pass
|
||||
17
resources/test/fixtures/pyupgrade/UP024_1.py
vendored
Normal file
17
resources/test/fixtures/pyupgrade/UP024_1.py
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
import mmap, socket, select
|
||||
|
||||
try:
|
||||
pass
|
||||
except (OSError, mmap.error, IOError):
|
||||
pass
|
||||
except (OSError, socket.error, KeyError):
|
||||
pass
|
||||
|
||||
try:
|
||||
pass
|
||||
except (
|
||||
OSError,
|
||||
select.error,
|
||||
IOError,
|
||||
):
|
||||
pass
|
||||
50
resources/test/fixtures/pyupgrade/UP024_2.py
vendored
Normal file
50
resources/test/fixtures/pyupgrade/UP024_2.py
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
# These should not change
|
||||
raise ValueError
|
||||
raise ValueError(1)
|
||||
|
||||
from .mmap import error
|
||||
raise error
|
||||
|
||||
# Testing the modules
|
||||
import socket, mmap, select
|
||||
raise socket.error
|
||||
raise mmap.error
|
||||
raise select.error
|
||||
|
||||
raise socket.error()
|
||||
raise mmap.error(1)
|
||||
raise select.error(1, 2)
|
||||
|
||||
raise socket.error(
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
)
|
||||
|
||||
from mmap import error
|
||||
raise error
|
||||
|
||||
from socket import error
|
||||
raise error(1)
|
||||
|
||||
from select import error
|
||||
raise error(1, 2)
|
||||
|
||||
# Testing the names
|
||||
raise EnvironmentError
|
||||
raise IOError
|
||||
raise WindowsError
|
||||
|
||||
raise EnvironmentError()
|
||||
raise IOError(1)
|
||||
raise WindowsError(1, 2)
|
||||
|
||||
raise EnvironmentError(
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
)
|
||||
|
||||
raise WindowsError
|
||||
raise EnvironmentError(1)
|
||||
raise IOError(1, 2)
|
||||
88
resources/test/fixtures/pyupgrade/UP026.py
vendored
Normal file
88
resources/test/fixtures/pyupgrade/UP026.py
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
# These should be changed
|
||||
if True:
|
||||
import mock
|
||||
|
||||
if True:
|
||||
import mock, sys
|
||||
|
||||
# This goes to from unitest import mock
|
||||
import mock.mock
|
||||
|
||||
# Mock should go on a new line as `from unittest import mock`
|
||||
import contextlib, mock, sys
|
||||
|
||||
# Mock should go on a new line as `from unittest import mock`
|
||||
import mock, sys
|
||||
x = "This code should be preserved one line below the mock"
|
||||
|
||||
# Mock should go on a new line as `from unittest import mock`
|
||||
from mock import mock
|
||||
|
||||
# Should keep trailing comma
|
||||
from mock import (
|
||||
mock,
|
||||
a,
|
||||
b,
|
||||
c,
|
||||
)
|
||||
from mock import (
|
||||
a,
|
||||
b,
|
||||
c,
|
||||
mock,
|
||||
)
|
||||
|
||||
# Should not get a trailing comma
|
||||
from mock import (
|
||||
mock,
|
||||
a,
|
||||
b,
|
||||
c
|
||||
)
|
||||
from mock import (
|
||||
a,
|
||||
b,
|
||||
c,
|
||||
mock
|
||||
)
|
||||
from mock import mock, a, b, c
|
||||
from mock import a, b, c, mock
|
||||
|
||||
if True:
|
||||
if False:
|
||||
from mock import (
|
||||
mock,
|
||||
a,
|
||||
b,
|
||||
c
|
||||
)
|
||||
|
||||
# These should not change:
|
||||
import os, io
|
||||
|
||||
# Mock should go on a new line as `from unittest import mock`
|
||||
import mock, mock
|
||||
|
||||
# Mock should go on a new line as `from unittest import mock as foo`
|
||||
import mock as foo
|
||||
|
||||
# Mock should go on a new line as `from unittest import mock as foo`
|
||||
from mock import mock as foo
|
||||
|
||||
if True:
|
||||
# This should yield multiple, aliased imports.
|
||||
import mock as foo, mock as bar, mock
|
||||
|
||||
# This should yield multiple, aliased imports, and preserve `os`.
|
||||
import mock as foo, mock as bar, mock, os
|
||||
|
||||
if True:
|
||||
# This should yield multiple, aliased imports.
|
||||
from mock import mock as foo, mock as bar, mock
|
||||
|
||||
|
||||
# This should be unchanged.
|
||||
x = mock.Mock()
|
||||
|
||||
# This should change to `mock.Mock`().
|
||||
x = mock.mock.Mock()
|
||||
18
resources/test/fixtures/pyupgrade/UP027.py
vendored
Normal file
18
resources/test/fixtures/pyupgrade/UP027.py
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
# Should change
|
||||
foo, bar, baz = [fn(x) for x in items]
|
||||
|
||||
foo, bar, baz =[fn(x) for x in items]
|
||||
|
||||
foo, bar, baz = [fn(x) for x in items]
|
||||
|
||||
foo, bar, baz = [[i for i in fn(x)] for x in items]
|
||||
|
||||
foo, bar, baz = [
|
||||
fn(x)
|
||||
for x in items
|
||||
]
|
||||
|
||||
# Should not change
|
||||
foo = [fn(x) for x in items]
|
||||
|
||||
x, = [await foo for foo in bar]
|
||||
64
resources/test/fixtures/ruff/RUF100_1.py
vendored
Normal file
64
resources/test/fixtures/ruff/RUF100_1.py
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
# This should ignore both errors.
|
||||
from typing import ( # noqa: F401
|
||||
List,
|
||||
Sequence,
|
||||
)
|
||||
|
||||
# This should ignore both errors.
|
||||
from typing import ( # noqa
|
||||
List,
|
||||
Sequence,
|
||||
)
|
||||
|
||||
# This should ignore both errors.
|
||||
from typing import (
|
||||
List, # noqa: F401
|
||||
Sequence, # noqa: F401
|
||||
)
|
||||
|
||||
# This should ignore both errors.
|
||||
from typing import (
|
||||
List, # noqa
|
||||
Sequence, # noqa
|
||||
)
|
||||
|
||||
# This should ignore the first error.
|
||||
from typing import (
|
||||
Mapping, # noqa: F401
|
||||
Union,
|
||||
)
|
||||
|
||||
# This should ignore both errors.
|
||||
from typing import ( # noqa
|
||||
List,
|
||||
Sequence,
|
||||
)
|
||||
|
||||
# This should ignore the error, but the inner noqa should be marked as unused.
|
||||
from typing import ( # noqa: F401
|
||||
Optional, # noqa: F401
|
||||
)
|
||||
|
||||
# This should ignore the error, but the inner noqa should be marked as unused.
|
||||
from typing import ( # noqa
|
||||
Optional, # noqa: F401
|
||||
)
|
||||
|
||||
# This should ignore the error, but mark F501 as unused.
|
||||
from typing import ( # noqa: F401
|
||||
Dict, # noqa: F501
|
||||
)
|
||||
|
||||
# This should ignore the error, but mark F501 as unused.
|
||||
from typing import ( # noqa: F501
|
||||
Tuple, # noqa: F401
|
||||
)
|
||||
|
||||
# This should ignore both errors.
|
||||
from typing import Any, AnyStr # noqa: F401
|
||||
|
||||
# This should ignore both errors.
|
||||
from typing import AsyncIterable, AsyncGenerator # noqa
|
||||
|
||||
# This should mark F501 as unused.
|
||||
from typing import Awaitable, AwaitableGenerator # noqa: F501
|
||||
@@ -64,11 +64,11 @@ Found 9 error(s).
|
||||
9 potentially fixable with the --fix option.
|
||||
```
|
||||
|
||||
Running from a parent directory should this "ignore" the `exclude` (hence, `concepts/file.py` gets
|
||||
Running from a parent directory should "ignore" the `exclude` (hence, `concepts/file.py` gets
|
||||
included in the output):
|
||||
|
||||
```
|
||||
∴ (cd resources/test/project/examples && cargo run -- --config=docs/pyproject.toml .)
|
||||
∴ (cd resources/test/project/examples && cargo run -- --config=docs/ruff.toml .)
|
||||
docs/docs/concepts/file.py:5:5: F841 Local variable `x` is assigned to but never used
|
||||
docs/docs/file.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
docs/docs/file.py:8:5: F841 Local variable `x` is assigned to but never used
|
||||
@@ -90,5 +90,7 @@ Unless we `--force-exclude`:
|
||||
|
||||
```
|
||||
∴ cargo run resources/test/project/examples/excluded/ --force-exclude
|
||||
warning: No Python files found under the given path(s)
|
||||
∴ cargo run resources/test/project/examples/excluded/script.py --force-exclude
|
||||
warning: No Python files found under the given path(s)
|
||||
```
|
||||
|
||||
165
ruff.schema.json
165
ruff.schema.json
@@ -154,6 +154,17 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"flake8-pytest-style": {
|
||||
"description": "Options for the `flake8-pytest-style` plugin.",
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/Flake8PytestStyleOptions"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"flake8-quotes": {
|
||||
"description": "Options for the `flake8-quotes` plugin.",
|
||||
"anyOf": [
|
||||
@@ -652,8 +663,6 @@
|
||||
"F821",
|
||||
"F822",
|
||||
"F823",
|
||||
"F83",
|
||||
"F831",
|
||||
"F84",
|
||||
"F841",
|
||||
"F842",
|
||||
@@ -753,6 +762,14 @@
|
||||
"PGH002",
|
||||
"PGH003",
|
||||
"PGH004",
|
||||
"PIE",
|
||||
"PIE7",
|
||||
"PIE79",
|
||||
"PIE790",
|
||||
"PIE794",
|
||||
"PIE8",
|
||||
"PIE80",
|
||||
"PIE807",
|
||||
"PLC",
|
||||
"PLC0",
|
||||
"PLC04",
|
||||
@@ -798,6 +815,36 @@
|
||||
"PLW06",
|
||||
"PLW060",
|
||||
"PLW0602",
|
||||
"PT",
|
||||
"PT0",
|
||||
"PT00",
|
||||
"PT001",
|
||||
"PT002",
|
||||
"PT003",
|
||||
"PT004",
|
||||
"PT005",
|
||||
"PT006",
|
||||
"PT007",
|
||||
"PT008",
|
||||
"PT009",
|
||||
"PT01",
|
||||
"PT010",
|
||||
"PT011",
|
||||
"PT012",
|
||||
"PT013",
|
||||
"PT015",
|
||||
"PT016",
|
||||
"PT017",
|
||||
"PT018",
|
||||
"PT019",
|
||||
"PT02",
|
||||
"PT020",
|
||||
"PT021",
|
||||
"PT022",
|
||||
"PT023",
|
||||
"PT024",
|
||||
"PT025",
|
||||
"PT026",
|
||||
"Q",
|
||||
"Q0",
|
||||
"Q00",
|
||||
@@ -850,6 +897,13 @@
|
||||
"SIM1",
|
||||
"SIM11",
|
||||
"SIM118",
|
||||
"SIM2",
|
||||
"SIM22",
|
||||
"SIM222",
|
||||
"SIM223",
|
||||
"SIM3",
|
||||
"SIM30",
|
||||
"SIM300",
|
||||
"T",
|
||||
"T1",
|
||||
"T10",
|
||||
@@ -911,7 +965,10 @@
|
||||
"UP021",
|
||||
"UP022",
|
||||
"UP023",
|
||||
"UP024",
|
||||
"UP025",
|
||||
"UP026",
|
||||
"UP027",
|
||||
"W",
|
||||
"W2",
|
||||
"W29",
|
||||
@@ -953,6 +1010,13 @@
|
||||
"enum": [
|
||||
"numpy"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Use PEP257-style docstrings.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"pep257"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -1047,6 +1111,79 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Flake8PytestStyleOptions": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"fixture-parentheses": {
|
||||
"description": "Boolean flag specifying whether `@pytest.fixture()` without parameters should have parentheses. If the option is set to `true` (the default), `@pytest.fixture()` is valid and `@pytest.fixture` is an error. If set to `false`, `@pytest.fixture` is valid and `@pytest.fixture()` is an error.",
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"mark-parentheses": {
|
||||
"description": "Boolean flag specifying whether `@pytest.mark.foo()` without parameters should have parentheses. If the option is set to `true` (the default), `@pytest.mark.foo()` is valid and `@pytest.mark.foo` is an error. If set to `false`, `@pytest.fixture` is valid and `@pytest.mark.foo()` is an error.",
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"parametrize-names-type": {
|
||||
"description": "Expected type for multiple argument names in `@pytest.mark.parametrize`. The following values are supported: * `csv` — a comma-separated list, e.g. `@pytest.mark.parametrize('name1,name2', ...)` * `tuple` (default) — e.g. `@pytest.mark.parametrize(('name1', 'name2'), ...)` * `list` — e.g. `@pytest.mark.parametrize(['name1', 'name2'], ...)`",
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ParametrizeNameType"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"parametrize-values-row-type": {
|
||||
"description": "Expected type for each row of values in `@pytest.mark.parametrize` in case of multiple parameters. The following values are supported: * `tuple` (default) — e.g. `@pytest.mark.parametrize(('name1', 'name2'), [(1, 2), (3, 4)])` * `list` — e.g. `@pytest.mark.parametrize(('name1', 'name2'), [[1, 2], [3, 4]])`",
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ParametrizeValuesRowType"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"parametrize-values-type": {
|
||||
"description": "Expected type for the list of values rows in `@pytest.mark.parametrize`. The following values are supported: * `tuple` — e.g. `@pytest.mark.parametrize('name', (1, 2, 3))` * `list` (default) — e.g. `@pytest.mark.parametrize('name', [1, 2, 3])`",
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ParametrizeValuesType"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"raises-extend-require-match-for": {
|
||||
"description": "List of additional exception names that require a match= parameter in a `pytest.raises()` call. This extends the default list of exceptions that require a match= parameter. This option is useful if you want to extend the default list of exceptions that require a match= parameter without having to specify the entire list. Note that this option does not remove any exceptions from the default list.",
|
||||
"type": [
|
||||
"array",
|
||||
"null"
|
||||
],
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"raises-require-match-for": {
|
||||
"description": "List of exception names that require a match= parameter in a `pytest.raises()` call.",
|
||||
"type": [
|
||||
"array",
|
||||
"null"
|
||||
],
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"Flake8QuotesOptions": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -1222,6 +1359,28 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"ParametrizeNameType": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"csv",
|
||||
"tuple",
|
||||
"list"
|
||||
]
|
||||
},
|
||||
"ParametrizeValuesRowType": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"tuple",
|
||||
"list"
|
||||
]
|
||||
},
|
||||
"ParametrizeValuesType": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"tuple",
|
||||
"list"
|
||||
]
|
||||
},
|
||||
"Pep8NamingOptions": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -1275,7 +1434,7 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"convention": {
|
||||
"description": "Whether to use Google-style or Numpy-style conventions when detecting docstring sections. By default, conventions will be inferred from the available sections.",
|
||||
"description": "Whether to use Google-style or NumPy-style conventions or the PEP257 defaults when analyzing docstring sections.",
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/Convention"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff_dev"
|
||||
version = "0.0.202"
|
||||
version = "0.0.209"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
@@ -11,9 +11,9 @@ itertools = { version = "0.10.5" }
|
||||
libcst = { git = "https://github.com/charliermarsh/LibCST", rev = "f2f0b7a487a8725d161fe8b3ed73a6758b21e177" }
|
||||
once_cell = { version = "1.16.0" }
|
||||
ruff = { path = ".." }
|
||||
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "68d26955b3e24198a150315e7959719b03709dee" }
|
||||
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "68d26955b3e24198a150315e7959719b03709dee" }
|
||||
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "68d26955b3e24198a150315e7959719b03709dee" }
|
||||
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "4d53c7cb27c0379adf8b51c4d3d0d2174f41d590" }
|
||||
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "4d53c7cb27c0379adf8b51c4d3d0d2174f41d590" }
|
||||
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "4d53c7cb27c0379adf8b51c4d3d0d2174f41d590" }
|
||||
schemars = { version = "0.8.11" }
|
||||
serde_json = {version="1.0.91"}
|
||||
strum = { version = "0.24.1", features = ["strum_macros"] }
|
||||
|
||||
@@ -4,7 +4,8 @@ use anyhow::Result;
|
||||
use clap::Args;
|
||||
|
||||
use crate::{
|
||||
generate_check_code_prefix, generate_json_schema, generate_options, generate_rules_table,
|
||||
generate_check_code_prefix, generate_cli_help, generate_json_schema, generate_options,
|
||||
generate_rules_table,
|
||||
};
|
||||
|
||||
#[derive(Args)]
|
||||
@@ -27,5 +28,8 @@ pub fn main(cli: &Cli) -> Result<()> {
|
||||
generate_options::main(&generate_options::Cli {
|
||||
dry_run: cli.dry_run,
|
||||
})?;
|
||||
generate_cli_help::main(&generate_cli_help::Cli {
|
||||
dry_run: cli.dry_run,
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ use anyhow::{ensure, Result};
|
||||
use clap::Parser;
|
||||
use codegen::{Scope, Type, Variant};
|
||||
use itertools::Itertools;
|
||||
use ruff::checks::{CheckCode, PREFIX_REDIRECTS};
|
||||
use ruff::registry::{CheckCode, PREFIX_REDIRECTS};
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
const ALL: &str = "ALL";
|
||||
@@ -19,7 +19,7 @@ const ALL: &str = "ALL";
|
||||
#[command(author, version, about, long_about = None)]
|
||||
pub struct Cli {
|
||||
/// Write the generated source code to stdout (rather than to
|
||||
/// `src/checks_gen.rs`).
|
||||
/// `src/registry_gen.rs`).
|
||||
#[arg(long)]
|
||||
pub(crate) dry_run: bool,
|
||||
}
|
||||
@@ -172,7 +172,7 @@ pub fn main(cli: &Cli) -> Result<()> {
|
||||
output.push_str("use strum_macros::{AsRefStr, EnumString};");
|
||||
output.push('\n');
|
||||
output.push('\n');
|
||||
output.push_str("use crate::checks::CheckCode;");
|
||||
output.push_str("use crate::registry::CheckCode;");
|
||||
output.push('\n');
|
||||
output.push_str("use crate::one_time_warning;");
|
||||
output.push('\n');
|
||||
@@ -204,14 +204,14 @@ pub fn main(cli: &Cli) -> Result<()> {
|
||||
let Output { status, stdout, .. } = rustfmt.wait_with_output()?;
|
||||
ensure!(status.success(), "rustfmt failed with {status}");
|
||||
|
||||
// Write the output to `src/checks_gen.rs` (or stdout).
|
||||
// Write the output to `src/registry_gen.rs` (or stdout).
|
||||
if cli.dry_run {
|
||||
println!("{}", String::from_utf8(stdout)?);
|
||||
} else {
|
||||
let file = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||
.parent()
|
||||
.expect("Failed to find root directory")
|
||||
.join("src/checks_gen.rs");
|
||||
.join("src/registry_gen.rs");
|
||||
if fs::read(&file).map_or(true, |old| old != stdout) {
|
||||
fs::write(&file, stdout)?;
|
||||
}
|
||||
|
||||
38
ruff_dev/src/generate_cli_help.rs
Normal file
38
ruff_dev/src/generate_cli_help.rs
Normal file
@@ -0,0 +1,38 @@
|
||||
//! Generate CLI help.
|
||||
|
||||
use anyhow::Result;
|
||||
use clap::{Args, CommandFactory};
|
||||
use ruff::cli::Cli as MainCli;
|
||||
|
||||
use crate::utils::replace_readme_section;
|
||||
|
||||
const HELP_BEGIN_PRAGMA: &str = "<!-- Begin auto-generated cli help. -->";
|
||||
const HELP_END_PRAGMA: &str = "<!-- End auto-generated cli help. -->";
|
||||
|
||||
#[derive(Args)]
|
||||
pub struct Cli {
|
||||
/// Write the generated help to stdout (rather than to `README.md`).
|
||||
#[arg(long)]
|
||||
pub(crate) dry_run: bool,
|
||||
}
|
||||
|
||||
fn trim_lines(s: &str) -> String {
|
||||
s.lines().map(str::trim_end).collect::<Vec<_>>().join("\n")
|
||||
}
|
||||
|
||||
pub fn main(cli: &Cli) -> Result<()> {
|
||||
let mut cmd = MainCli::command();
|
||||
let output = trim_lines(cmd.render_help().to_string().trim());
|
||||
|
||||
if cli.dry_run {
|
||||
print!("{output}");
|
||||
} else {
|
||||
replace_readme_section(
|
||||
&format!("```shell\n{output}\n```\n"),
|
||||
HELP_BEGIN_PRAGMA,
|
||||
HELP_END_PRAGMA,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,16 +1,13 @@
|
||||
//! Generate a Markdown-compatible listing of configuration options.
|
||||
|
||||
use std::fs;
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use anyhow::Result;
|
||||
use clap::Args;
|
||||
use itertools::Itertools;
|
||||
use ruff::settings::options::Options;
|
||||
use ruff::settings::options_base::{ConfigurationOptions, OptionEntry, OptionField};
|
||||
|
||||
use crate::utils::replace_readme_section;
|
||||
|
||||
const BEGIN_PRAGMA: &str = "<!-- Begin auto-generated options sections. -->";
|
||||
const END_PRAGMA: &str = "<!-- End auto-generated options sections. -->";
|
||||
|
||||
@@ -95,30 +92,7 @@ pub fn main(cli: &Cli) -> Result<()> {
|
||||
if cli.dry_run {
|
||||
print!("{output}");
|
||||
} else {
|
||||
// Read the existing file.
|
||||
let file = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||
.parent()
|
||||
.expect("Failed to find root directory")
|
||||
.join("README.md");
|
||||
let existing = fs::read_to_string(&file)?;
|
||||
|
||||
// Extract the prefix.
|
||||
let index = existing
|
||||
.find(BEGIN_PRAGMA)
|
||||
.expect("Unable to find begin pragma");
|
||||
let prefix = &existing[..index + BEGIN_PRAGMA.len()];
|
||||
|
||||
// Extract the suffix.
|
||||
let index = existing
|
||||
.find(END_PRAGMA)
|
||||
.expect("Unable to find end pragma");
|
||||
let suffix = &existing[index..];
|
||||
|
||||
// Write the prefix, new contents, and suffix.
|
||||
let mut f = OpenOptions::new().write(true).truncate(true).open(&file)?;
|
||||
write!(f, "{prefix}\n\n")?;
|
||||
write!(f, "{output}")?;
|
||||
write!(f, "{suffix}")?;
|
||||
replace_readme_section(&output, BEGIN_PRAGMA, END_PRAGMA)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
//! Generate a Markdown-compatible table of supported lint rules.
|
||||
|
||||
use std::fs;
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use anyhow::Result;
|
||||
use clap::Args;
|
||||
use itertools::Itertools;
|
||||
use ruff::checks::{CheckCategory, CheckCode};
|
||||
use ruff::registry::{CheckCategory, CheckCode};
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use crate::utils::replace_readme_section;
|
||||
|
||||
const TABLE_BEGIN_PRAGMA: &str = "<!-- Begin auto-generated sections. -->";
|
||||
const TABLE_END_PRAGMA: &str = "<!-- End auto-generated sections. -->";
|
||||
|
||||
@@ -85,32 +82,3 @@ pub fn main(cli: &Cli) -> Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn replace_readme_section(content: &str, begin_pragma: &str, end_pragma: &str) -> Result<()> {
|
||||
// Read the existing file.
|
||||
let file = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||
.parent()
|
||||
.expect("Failed to find root directory")
|
||||
.join("README.md");
|
||||
let existing = fs::read_to_string(&file)?;
|
||||
|
||||
// Extract the prefix.
|
||||
let index = existing
|
||||
.find(begin_pragma)
|
||||
.expect("Unable to find begin pragma");
|
||||
let prefix = &existing[..index + begin_pragma.len()];
|
||||
|
||||
// Extract the suffix.
|
||||
let index = existing
|
||||
.find(end_pragma)
|
||||
.expect("Unable to find end pragma");
|
||||
let suffix = &existing[index..];
|
||||
|
||||
// Write the prefix, new contents, and suffix.
|
||||
let mut f = OpenOptions::new().write(true).truncate(true).open(&file)?;
|
||||
writeln!(f, "{prefix}")?;
|
||||
write!(f, "{content}")?;
|
||||
write!(f, "{suffix}")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
pub mod generate_all;
|
||||
pub mod generate_check_code_prefix;
|
||||
pub mod generate_cli_help;
|
||||
pub mod generate_json_schema;
|
||||
pub mod generate_options;
|
||||
pub mod generate_rules_table;
|
||||
@@ -20,3 +21,4 @@ pub mod print_ast;
|
||||
pub mod print_cst;
|
||||
pub mod print_tokens;
|
||||
pub mod round_trip;
|
||||
mod utils;
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
use anyhow::Result;
|
||||
use clap::{Parser, Subcommand};
|
||||
use ruff_dev::{
|
||||
generate_all, generate_check_code_prefix, generate_json_schema, generate_options,
|
||||
generate_rules_table, print_ast, print_cst, print_tokens, round_trip,
|
||||
generate_all, generate_check_code_prefix, generate_cli_help, generate_json_schema,
|
||||
generate_options, generate_rules_table, print_ast, print_cst, print_tokens, round_trip,
|
||||
};
|
||||
|
||||
#[derive(Parser)]
|
||||
@@ -38,6 +38,8 @@ enum Commands {
|
||||
GenerateRulesTable(generate_rules_table::Cli),
|
||||
/// Generate a Markdown-compatible listing of configuration options.
|
||||
GenerateOptions(generate_options::Cli),
|
||||
/// Generate CLI help.
|
||||
GenerateCliHelp(generate_cli_help::Cli),
|
||||
/// Print the AST for a given Python file.
|
||||
PrintAST(print_ast::Cli),
|
||||
/// Print the LibCST CST for a given Python file.
|
||||
@@ -56,6 +58,7 @@ fn main() -> Result<()> {
|
||||
Commands::GenerateJSONSchema(args) => generate_json_schema::main(args)?,
|
||||
Commands::GenerateRulesTable(args) => generate_rules_table::main(args)?,
|
||||
Commands::GenerateOptions(args) => generate_options::main(args)?,
|
||||
Commands::GenerateCliHelp(args) => generate_cli_help::main(args)?,
|
||||
Commands::PrintAST(args) => print_ast::main(args)?,
|
||||
Commands::PrintCST(args) => print_cst::main(args)?,
|
||||
Commands::PrintTokens(args) => print_tokens::main(args)?,
|
||||
|
||||
@@ -22,7 +22,11 @@ pub fn main(cli: &Cli) -> Result<()> {
|
||||
let python_ast = parser::parse_program(&contents, &cli.file.to_string_lossy())?;
|
||||
let locator = SourceCodeLocator::new(&contents);
|
||||
let stylist = SourceCodeStyleDetector::from_contents(&contents, &locator);
|
||||
let mut generator = SourceCodeGenerator::new(stylist.indentation(), stylist.quote());
|
||||
let mut generator = SourceCodeGenerator::new(
|
||||
stylist.indentation(),
|
||||
stylist.quote(),
|
||||
stylist.line_ending(),
|
||||
);
|
||||
generator.unparse_suite(&python_ast);
|
||||
println!("{}", generator.generate()?);
|
||||
Ok(())
|
||||
|
||||
35
ruff_dev/src/utils.rs
Normal file
35
ruff_dev/src/utils.rs
Normal file
@@ -0,0 +1,35 @@
|
||||
use std::fs;
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
pub fn replace_readme_section(content: &str, begin_pragma: &str, end_pragma: &str) -> Result<()> {
|
||||
// Read the existing file.
|
||||
let file = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||
.parent()
|
||||
.expect("Failed to find root directory")
|
||||
.join("README.md");
|
||||
let existing = fs::read_to_string(&file)?;
|
||||
|
||||
// Extract the prefix.
|
||||
let index = existing
|
||||
.find(begin_pragma)
|
||||
.expect("Unable to find begin pragma");
|
||||
let prefix = &existing[..index + begin_pragma.len()];
|
||||
|
||||
// Extract the suffix.
|
||||
let index = existing
|
||||
.find(end_pragma)
|
||||
.expect("Unable to find end pragma");
|
||||
let suffix = &existing[index..];
|
||||
|
||||
// Write the prefix, new contents, and suffix.
|
||||
let mut f = OpenOptions::new().write(true).truncate(true).open(&file)?;
|
||||
writeln!(f, "{prefix}")?;
|
||||
write!(f, "{content}")?;
|
||||
write!(f, "{suffix}")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff_macros"
|
||||
version = "0.0.202"
|
||||
version = "0.0.209"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
[flake8]
|
||||
exclude =
|
||||
# Defaults
|
||||
.svn,
|
||||
CVS,
|
||||
.bzr,
|
||||
.hg,
|
||||
.git,
|
||||
__pycache__,
|
||||
.tox,
|
||||
.idea,
|
||||
.mypy_cache,
|
||||
.venv,
|
||||
node_modules,
|
||||
# Custom
|
||||
_state_machine.py,
|
||||
test_fstring.py,
|
||||
bad_coding2.py,
|
||||
badsyntax_*.py
|
||||
ignore_names = foo, bar
|
||||
quotes = double
|
||||
139
scripts/add_check.py
Normal file
139
scripts/add_check.py
Normal file
@@ -0,0 +1,139 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate boilerplate for a new check.
|
||||
|
||||
Example usage:
|
||||
|
||||
python scripts/add_check.py \
|
||||
--name PreferListBuiltin \
|
||||
--code PIE807 \
|
||||
--plugin flake8-pie
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
|
||||
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
|
||||
def dir_name(plugin: str) -> str:
|
||||
return plugin.replace("-", "_")
|
||||
|
||||
|
||||
def pascal_case(plugin: str) -> str:
|
||||
"""Convert from snake-case to PascalCase."""
|
||||
return "".join(word.title() for word in plugin.split("-"))
|
||||
|
||||
|
||||
def snake_case(name: str) -> str:
|
||||
"""Convert from PascalCase to snake_case."""
|
||||
return "".join(f"_{word.lower()}" if word.isupper() else word for word in name).lstrip("_")
|
||||
|
||||
|
||||
def main(*, name: str, code: str, plugin: str) -> None:
|
||||
# Create a test fixture.
|
||||
with open(
|
||||
os.path.join(ROOT_DIR, f"resources/test/fixtures/{dir_name(plugin)}/{code}.py"),
|
||||
"a",
|
||||
):
|
||||
pass
|
||||
|
||||
# Add the relevant `#testcase` macro.
|
||||
with open(os.path.join(ROOT_DIR, f"src/{dir_name(plugin)}/mod.rs"), "r") as fp:
|
||||
content = fp.read()
|
||||
|
||||
with open(os.path.join(ROOT_DIR, f"src/{dir_name(plugin)}/mod.rs"), "w") as fp:
|
||||
for line in content.splitlines():
|
||||
if line.strip() == "fn checks(check_code: CheckCode, path: &Path) -> Result<()> {":
|
||||
indent = line.split("fn checks(check_code: CheckCode, path: &Path) -> Result<()> {")[0]
|
||||
fp.write(f'{indent}#[test_case(CheckCode::{code}, Path::new("{code}.py"); "{code}")]')
|
||||
fp.write("\n")
|
||||
|
||||
fp.write(line)
|
||||
fp.write("\n")
|
||||
|
||||
# Add the relevant plugin function.
|
||||
with open(os.path.join(ROOT_DIR, f"src/{dir_name(plugin)}/plugins.rs"), "a") as fp:
|
||||
fp.write(
|
||||
f"""
|
||||
/// {code}
|
||||
pub fn {snake_case(name)}(checker: &mut Checker) {{}}
|
||||
"""
|
||||
)
|
||||
fp.write("\n")
|
||||
|
||||
# Add the relevant sections to `src/registry.rs`.
|
||||
with open(os.path.join(ROOT_DIR, "src/registry.rs"), "r") as fp:
|
||||
content = fp.read()
|
||||
|
||||
index = 0
|
||||
with open(os.path.join(ROOT_DIR, "src/registry.rs"), "w") as fp:
|
||||
for line in content.splitlines():
|
||||
fp.write(line)
|
||||
fp.write("\n")
|
||||
|
||||
if line.strip() == f"// {plugin}":
|
||||
if index == 0:
|
||||
# `CheckCode` definition
|
||||
indent = line.split(f"// {plugin}")[0]
|
||||
fp.write(f"{indent}{code},")
|
||||
fp.write("\n")
|
||||
|
||||
elif index == 1:
|
||||
# `CheckKind` definition
|
||||
indent = line.split(f"// {plugin}")[0]
|
||||
fp.write(f"{indent}{name},")
|
||||
fp.write("\n")
|
||||
|
||||
elif index == 2:
|
||||
# `CheckCode#kind()`
|
||||
indent = line.split(f"// {plugin}")[0]
|
||||
fp.write(f"{indent}CheckCode::{code} => CheckKind::{name},")
|
||||
fp.write("\n")
|
||||
|
||||
elif index == 3:
|
||||
# `CheckCode#category()`
|
||||
indent = line.split(f"// {plugin}")[0]
|
||||
fp.write(f"{indent}CheckCode::{code} => CheckCategory::{pascal_case(plugin)},")
|
||||
fp.write("\n")
|
||||
|
||||
elif index == 4:
|
||||
# `CheckKind#code()`
|
||||
indent = line.split(f"// {plugin}")[0]
|
||||
fp.write(f"{indent}CheckKind::{name} => &CheckCode::{code},")
|
||||
fp.write("\n")
|
||||
|
||||
elif index == 5:
|
||||
# `CheckCode#body`
|
||||
indent = line.split(f"// {plugin}")[0]
|
||||
fp.write(f'{indent}CheckKind::{name} => todo!("Write message body for {code}"),')
|
||||
fp.write("\n")
|
||||
|
||||
index += 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Generate boilerplate for a new check.",
|
||||
epilog="python scripts/add_check.py --name PreferListBuiltin --code PIE807 --plugin flake8-pie",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--name",
|
||||
type=str,
|
||||
required=True,
|
||||
help="The name of the check to generate, in PascalCase (e.g., 'LineTooLong').",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--code",
|
||||
type=str,
|
||||
required=True,
|
||||
help="The code of the check to generate (e.g., 'A001').",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--plugin",
|
||||
type=str,
|
||||
required=True,
|
||||
help="The plugin with which the check is associated (e.g., 'flake8-builtins').",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
main(name=args.name, code=args.code, plugin=args.plugin)
|
||||
133
scripts/add_plugin.py
Normal file
133
scripts/add_plugin.py
Normal file
@@ -0,0 +1,133 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate boilerplate for a new plugin.
|
||||
|
||||
Example usage:
|
||||
|
||||
python scripts/add_plugin.py \
|
||||
flake8-pie \
|
||||
--url https://pypi.org/project/flake8-pie/0.16.0/
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
|
||||
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
|
||||
def dir_name(plugin: str) -> str:
|
||||
return plugin.replace("-", "_")
|
||||
|
||||
|
||||
def pascal_case(plugin: str) -> str:
|
||||
return "".join(word.title() for word in plugin.split("-"))
|
||||
|
||||
|
||||
def main(*, plugin: str, url: str) -> None:
|
||||
# Create the test fixture folder.
|
||||
os.makedirs(
|
||||
os.path.join(ROOT_DIR, f"resources/test/fixtures/{dir_name(plugin)}"),
|
||||
exist_ok=True,
|
||||
)
|
||||
|
||||
# Create the Rust module.
|
||||
os.makedirs(os.path.join(ROOT_DIR, f"src/{dir_name(plugin)}"), exist_ok=True)
|
||||
with open(os.path.join(ROOT_DIR, f"src/{dir_name(plugin)}/plugins.rs"), "a"):
|
||||
pass
|
||||
with open(os.path.join(ROOT_DIR, f"src/{dir_name(plugin)}/mod.rs"), "w+") as fp:
|
||||
fp.write("pub mod plugins;\n")
|
||||
fp.write("\n")
|
||||
fp.write(
|
||||
"""#[cfg(test)]
|
||||
mod tests {
|
||||
use std::convert::AsRef;
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::Result;
|
||||
use test_case::test_case;
|
||||
|
||||
use crate::registry::CheckCode;
|
||||
use crate::linter::test_path;
|
||||
use crate::settings;
|
||||
|
||||
fn checks(check_code: CheckCode, path: &Path) -> Result<()> {
|
||||
let snapshot = format!("{}_{}", check_code.as_ref(), path.to_string_lossy());
|
||||
let checks = test_path(
|
||||
Path::new("./resources/test/fixtures/%s")
|
||||
.join(path)
|
||||
.as_path(),
|
||||
&settings::Settings::for_rule(check_code),
|
||||
)?;
|
||||
insta::assert_yaml_snapshot!(snapshot, checks);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
"""
|
||||
% dir_name(plugin)
|
||||
)
|
||||
|
||||
# Add the plugin to `lib.rs`.
|
||||
with open(os.path.join(ROOT_DIR, "src/lib.rs"), "a") as fp:
|
||||
fp.write(f"pub mod {dir_name(plugin)};")
|
||||
|
||||
# Add the relevant sections to `src/registry.rs`.
|
||||
with open(os.path.join(ROOT_DIR, "src/registry.rs"), "r") as fp:
|
||||
content = fp.read()
|
||||
|
||||
with open(os.path.join(ROOT_DIR, "src/registry.rs"), "w") as fp:
|
||||
for line in content.splitlines():
|
||||
if line.strip() == "// Ruff":
|
||||
indent = line.split("// Ruff")[0]
|
||||
fp.write(f"{indent}// {plugin}")
|
||||
fp.write("\n")
|
||||
|
||||
elif line.strip() == "Ruff,":
|
||||
indent = line.split("Ruff,")[0]
|
||||
fp.write(f"{indent}{pascal_case(plugin)},")
|
||||
fp.write("\n")
|
||||
|
||||
elif line.strip() == 'CheckCategory::Ruff => "Ruff-specific rules",':
|
||||
indent = line.split('CheckCategory::Ruff => "Ruff-specific rules",')[0]
|
||||
fp.write(f'{indent}CheckCategory::{pascal_case(plugin)} => "{plugin}",')
|
||||
fp.write("\n")
|
||||
|
||||
elif line.strip() == "CheckCategory::Ruff => vec![CheckCodePrefix::RUF],":
|
||||
indent = line.split("CheckCategory::Ruff => vec![CheckCodePrefix::RUF],")[0]
|
||||
fp.write(
|
||||
f"{indent}CheckCategory::{pascal_case(plugin)} => vec![\n"
|
||||
f'{indent} todo!("Fill-in prefix after generating codes")\n'
|
||||
f"{indent}],"
|
||||
)
|
||||
fp.write("\n")
|
||||
|
||||
elif line.strip() == "CheckCategory::Ruff => None,":
|
||||
indent = line.split("CheckCategory::Ruff => None,")[0]
|
||||
fp.write(f"{indent}CheckCategory::{pascal_case(plugin)} => " f'Some(("{url}", &Platform::PyPI)),')
|
||||
fp.write("\n")
|
||||
|
||||
fp.write(line)
|
||||
fp.write("\n")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Generate boilerplate for a new plugin.",
|
||||
epilog=(
|
||||
"Example usage: python scripts/add_plugin.py flake8-pie "
|
||||
"--url https://pypi.org/project/flake8-pie/0.16.0/"
|
||||
),
|
||||
)
|
||||
parser.add_argument(
|
||||
"plugin",
|
||||
required=True,
|
||||
type=str,
|
||||
help="The name of the plugin to generate.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--url",
|
||||
required=True,
|
||||
type=str,
|
||||
help="The URL of the latest release in PyPI.",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
main(plugin=args.plugin, url=args.url)
|
||||
462
scripts/poetry.lock
generated
462
scripts/poetry.lock
generated
@@ -1,10 +1,16 @@
|
||||
# This file is automatically @generated by Poetry and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "astroid"
|
||||
version = "2.12.4"
|
||||
version = "2.12.13"
|
||||
description = "An abstract syntax tree for Python with inference support."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7.2"
|
||||
files = [
|
||||
{file = "astroid-2.12.13-py3-none-any.whl", hash = "sha256:10e0ad5f7b79c435179d0d0f0df69998c4eef4597534aae44910db060baeb907"},
|
||||
{file = "astroid-2.12.13.tar.gz", hash = "sha256:1493fe8bd3dfd73dc35bd53c9d5b6e49ead98497c47b2307662556a5692d29d7"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
lazy-object-proxy = ">=1.4.0"
|
||||
@@ -12,39 +18,43 @@ wrapt = {version = ">=1.11,<2", markers = "python_version < \"3.11\""}
|
||||
|
||||
[[package]]
|
||||
name = "autoflake"
|
||||
version = "1.5.1"
|
||||
version = "1.7.8"
|
||||
description = "Removes unused imports and unused variables"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "autoflake-1.7.8-py3-none-any.whl", hash = "sha256:46373ef69b6714f5064c923bb28bd797c4f8a9497f557d87fc36665c6d956b39"},
|
||||
{file = "autoflake-1.7.8.tar.gz", hash = "sha256:e7e46372dee46fa1c97acf310d99d922b63d369718a270809d7c278d34a194cf"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pyflakes = ">=1.1.0"
|
||||
toml = ">=0.10.2"
|
||||
pyflakes = ">=1.1.0,<3"
|
||||
tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""}
|
||||
|
||||
[[package]]
|
||||
name = "colorama"
|
||||
version = "0.4.5"
|
||||
version = "0.4.6"
|
||||
description = "Cross-platform colored terminal text."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
|
||||
[[package]]
|
||||
name = "cycler"
|
||||
version = "0.11.0"
|
||||
description = "Composable style cycles"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
||||
files = [
|
||||
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
|
||||
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dill"
|
||||
version = "0.3.5.1"
|
||||
version = "0.3.6"
|
||||
description = "serialize all of python"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*"
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "dill-0.3.6-py3-none-any.whl", hash = "sha256:a07ffd2351b8c678dfc4a856a3005f8067aea51d6ba6c700796a4d9e280f39f0"},
|
||||
{file = "dill-0.3.6.tar.gz", hash = "sha256:e5db55f3687856d8fbdab002ed78544e1c4559a130302693d839dfe8f93f2373"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
graph = ["objgraph (>=1.7.2)"]
|
||||
@@ -56,82 +66,62 @@ description = "the modular source code checker: pep8 pyflakes and co"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6.1"
|
||||
files = [
|
||||
{file = "flake8-5.0.4-py2.py3-none-any.whl", hash = "sha256:7a1cf6b73744f5806ab95e526f6f0d8c01c66d7bbe349562d22dfca20610b248"},
|
||||
{file = "flake8-5.0.4.tar.gz", hash = "sha256:6fbe320aad8d6b95cec8b8e47bc933004678dc63095be98528b7bdd2a9f510db"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
mccabe = ">=0.7.0,<0.8.0"
|
||||
pycodestyle = ">=2.9.0,<2.10.0"
|
||||
pyflakes = ">=2.5.0,<2.6.0"
|
||||
|
||||
[[package]]
|
||||
name = "fonttools"
|
||||
version = "4.37.1"
|
||||
description = "Tools to manipulate font files"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[package.extras]
|
||||
all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=14.0.0)", "xattr", "zopfli (>=0.1.4)"]
|
||||
graphite = ["lz4 (>=1.7.4.2)"]
|
||||
interpolatable = ["munkres", "scipy"]
|
||||
lxml = ["lxml (>=4.0,<5)"]
|
||||
pathops = ["skia-pathops (>=0.5.0)"]
|
||||
plot = ["matplotlib"]
|
||||
repacker = ["uharfbuzz (>=0.23.0)"]
|
||||
symfont = ["sympy"]
|
||||
type1 = ["xattr"]
|
||||
ufo = ["fs (>=2.2.0,<3)"]
|
||||
unicode = ["unicodedata2 (>=14.0.0)"]
|
||||
woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"]
|
||||
|
||||
[[package]]
|
||||
name = "isort"
|
||||
version = "5.10.1"
|
||||
version = "5.11.4"
|
||||
description = "A Python utility / library to sort Python imports."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6.1,<4.0"
|
||||
python-versions = ">=3.7.0"
|
||||
files = [
|
||||
{file = "isort-5.11.4-py3-none-any.whl", hash = "sha256:c033fd0edb91000a7f09527fe5c75321878f98322a77ddcc81adbd83724afb7b"},
|
||||
{file = "isort-5.11.4.tar.gz", hash = "sha256:6db30c5ded9815d813932c04c2f85a360bcdd35fed496f4d8f35495ef0a261b6"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
colors = ["colorama (>=0.4.3,<0.5.0)"]
|
||||
pipfile_deprecated_finder = ["pipreqs", "requirementslib"]
|
||||
pipfile-deprecated-finder = ["pipreqs", "requirementslib"]
|
||||
plugins = ["setuptools"]
|
||||
requirements_deprecated_finder = ["pip-api", "pipreqs"]
|
||||
|
||||
[[package]]
|
||||
name = "kiwisolver"
|
||||
version = "1.4.4"
|
||||
description = "A fast implementation of the Cassowary constraint solver"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
requirements-deprecated-finder = ["pip-api", "pipreqs"]
|
||||
|
||||
[[package]]
|
||||
name = "lazy-object-proxy"
|
||||
version = "1.7.1"
|
||||
version = "1.8.0"
|
||||
description = "A fast and thorough lazy object proxy."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[[package]]
|
||||
name = "matplotlib"
|
||||
version = "3.5.3"
|
||||
description = "Python plotting package"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[package.dependencies]
|
||||
cycler = ">=0.10"
|
||||
fonttools = ">=4.22.0"
|
||||
kiwisolver = ">=1.0.1"
|
||||
numpy = ">=1.17"
|
||||
packaging = ">=20.0"
|
||||
pillow = ">=6.2.0"
|
||||
pyparsing = ">=2.2.1"
|
||||
python-dateutil = ">=2.7"
|
||||
setuptools_scm = ">=4,<7"
|
||||
files = [
|
||||
{file = "lazy-object-proxy-1.8.0.tar.gz", hash = "sha256:c219a00245af0f6fa4e95901ed28044544f50152840c5b6a3e7b2568db34d156"},
|
||||
{file = "lazy_object_proxy-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4fd031589121ad46e293629b39604031d354043bb5cdf83da4e93c2d7f3389fe"},
|
||||
{file = "lazy_object_proxy-1.8.0-cp310-cp310-win32.whl", hash = "sha256:b70d6e7a332eb0217e7872a73926ad4fdc14f846e85ad6749ad111084e76df25"},
|
||||
{file = "lazy_object_proxy-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:eb329f8d8145379bf5dbe722182410fe8863d186e51bf034d2075eb8d85ee25b"},
|
||||
{file = "lazy_object_proxy-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4e2d9f764f1befd8bdc97673261b8bb888764dfdbd7a4d8f55e4fbcabb8c3fb7"},
|
||||
{file = "lazy_object_proxy-1.8.0-cp311-cp311-win32.whl", hash = "sha256:e20bfa6db17a39c706d24f82df8352488d2943a3b7ce7d4c22579cb89ca8896e"},
|
||||
{file = "lazy_object_proxy-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:14010b49a2f56ec4943b6cf925f597b534ee2fe1f0738c84b3bce0c1a11ff10d"},
|
||||
{file = "lazy_object_proxy-1.8.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6850e4aeca6d0df35bb06e05c8b934ff7c533734eb51d0ceb2d63696f1e6030c"},
|
||||
{file = "lazy_object_proxy-1.8.0-cp37-cp37m-win32.whl", hash = "sha256:5b51d6f3bfeb289dfd4e95de2ecd464cd51982fe6f00e2be1d0bf94864d58acd"},
|
||||
{file = "lazy_object_proxy-1.8.0-cp37-cp37m-win_amd64.whl", hash = "sha256:6f593f26c470a379cf7f5bc6db6b5f1722353e7bf937b8d0d0b3fba911998858"},
|
||||
{file = "lazy_object_proxy-1.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c1c7c0433154bb7c54185714c6929acc0ba04ee1b167314a779b9025517eada"},
|
||||
{file = "lazy_object_proxy-1.8.0-cp38-cp38-win32.whl", hash = "sha256:d176f392dbbdaacccf15919c77f526edf11a34aece58b55ab58539807b85436f"},
|
||||
{file = "lazy_object_proxy-1.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:afcaa24e48bb23b3be31e329deb3f1858f1f1df86aea3d70cb5c8578bfe5261c"},
|
||||
{file = "lazy_object_proxy-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:71d9ae8a82203511a6f60ca5a1b9f8ad201cac0fc75038b2dc5fa519589c9288"},
|
||||
{file = "lazy_object_proxy-1.8.0-cp39-cp39-win32.whl", hash = "sha256:8f6ce2118a90efa7f62dd38c7dbfffd42f468b180287b748626293bf12ed468f"},
|
||||
{file = "lazy_object_proxy-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:eac3a9a5ef13b332c059772fd40b4b1c3d45a3a2b05e33a361dee48e54a4dad0"},
|
||||
{file = "lazy_object_proxy-1.8.0-pp37-pypy37_pp73-any.whl", hash = "sha256:ae032743794fba4d171b5b67310d69176287b5bf82a21f588282406a79498891"},
|
||||
{file = "lazy_object_proxy-1.8.0-pp38-pypy38_pp73-any.whl", hash = "sha256:7e1561626c49cb394268edd00501b289053a652ed762c58e1081224c8d881cec"},
|
||||
{file = "lazy_object_proxy-1.8.0-pp39-pypy39_pp73-any.whl", hash = "sha256:ce58b2b3734c73e68f0e30e4e725264d4d6be95818ec0a0be4bb6bf9a7e79aa8"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mccabe"
|
||||
@@ -140,49 +130,26 @@ description = "McCabe checker, plugin for flake8"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[[package]]
|
||||
name = "numpy"
|
||||
version = "1.23.2"
|
||||
description = "NumPy is the fundamental package for array computing with Python."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "21.3"
|
||||
description = "Core utilities for Python packages"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[package.dependencies]
|
||||
pyparsing = ">=2.0.2,<3.0.5 || >3.0.5"
|
||||
|
||||
[[package]]
|
||||
name = "pillow"
|
||||
version = "9.2.0"
|
||||
description = "Python Imaging Library (Fork)"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-issues (>=3.0.1)", "sphinx-removed-in", "sphinxext-opengraph"]
|
||||
tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"]
|
||||
files = [
|
||||
{file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"},
|
||||
{file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "platformdirs"
|
||||
version = "2.5.2"
|
||||
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
|
||||
version = "2.6.2"
|
||||
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "platformdirs-2.6.2-py3-none-any.whl", hash = "sha256:83c8f6d04389165de7c9b6f0c682439697887bca0aa2f1c87ef1826be3584490"},
|
||||
{file = "platformdirs-2.6.2.tar.gz", hash = "sha256:e1fea1fe471b9ff8332e229df3cb7de4f53eeea4998d3b6bfff542115e998bd2"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx (>=4)", "sphinx-autodoc-typehints (>=1.12)"]
|
||||
test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"]
|
||||
docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.5)"]
|
||||
test = ["appdirs (==1.4.4)", "covdefaults (>=2.2.2)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"]
|
||||
|
||||
[[package]]
|
||||
name = "pycodestyle"
|
||||
@@ -191,6 +158,10 @@ description = "Python style guide checker"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "pycodestyle-2.9.1-py2.py3-none-any.whl", hash = "sha256:d1735fc58b418fd7c5f658d28d943854f8a849b01a5d0a1e6f3f3fdd0166804b"},
|
||||
{file = "pycodestyle-2.9.1.tar.gz", hash = "sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyflakes"
|
||||
@@ -199,19 +170,27 @@ description = "passive checker of Python programs"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "pyflakes-2.5.0-py2.py3-none-any.whl", hash = "sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2"},
|
||||
{file = "pyflakes-2.5.0.tar.gz", hash = "sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pylint"
|
||||
version = "2.15.0"
|
||||
version = "2.15.9"
|
||||
description = "python code static checker"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7.2"
|
||||
files = [
|
||||
{file = "pylint-2.15.9-py3-none-any.whl", hash = "sha256:349c8cd36aede4d50a0754a8c0218b43323d13d5d88f4b2952ddfe3e169681eb"},
|
||||
{file = "pylint-2.15.9.tar.gz", hash = "sha256:18783cca3cfee5b83c6c5d10b3cdb66c6594520ffae61890858fe8d932e1c6b4"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
astroid = ">=2.12.4,<=2.14.0-dev0"
|
||||
astroid = ">=2.12.13,<=2.14.0-dev0"
|
||||
colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""}
|
||||
dill = ">=0.2"
|
||||
dill = {version = ">=0.2", markers = "python_version < \"3.11\""}
|
||||
isort = ">=4.2.5,<6"
|
||||
mccabe = ">=0.6,<0.8"
|
||||
platformdirs = ">=2.2.0"
|
||||
@@ -222,71 +201,6 @@ tomlkit = ">=0.10.1"
|
||||
spelling = ["pyenchant (>=3.2,<4.0)"]
|
||||
testutils = ["gitpython (>3)"]
|
||||
|
||||
[[package]]
|
||||
name = "pyparsing"
|
||||
version = "3.0.9"
|
||||
description = "pyparsing module - Classes and methods to define and execute parsing grammars"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6.8"
|
||||
|
||||
[package.extras]
|
||||
diagrams = ["jinja2", "railroad-diagrams"]
|
||||
|
||||
[[package]]
|
||||
name = "python-dateutil"
|
||||
version = "2.8.2"
|
||||
description = "Extensions to the standard Python datetime module"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
|
||||
|
||||
[package.dependencies]
|
||||
six = ">=1.5"
|
||||
|
||||
[[package]]
|
||||
name = "scipy"
|
||||
version = "1.9.1"
|
||||
description = "SciPy: Scientific Library for Python"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.8,<3.12"
|
||||
|
||||
[package.dependencies]
|
||||
numpy = ">=1.18.5,<1.25.0"
|
||||
|
||||
[[package]]
|
||||
name = "setuptools-scm"
|
||||
version = "6.4.2"
|
||||
description = "the blessed package to manage your versions by scm tags"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[package.dependencies]
|
||||
packaging = ">=20.0"
|
||||
tomli = ">=1.0.0"
|
||||
|
||||
[package.extras]
|
||||
test = ["pytest (>=6.2)", "virtualenv (>20)"]
|
||||
toml = ["setuptools (>=42)"]
|
||||
|
||||
[[package]]
|
||||
name = "six"
|
||||
version = "1.16.0"
|
||||
description = "Python 2 and 3 compatibility utilities"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.10.2"
|
||||
description = "Python Library for Tom's Obvious, Minimal Language"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||
|
||||
[[package]]
|
||||
name = "tomli"
|
||||
version = "2.0.1"
|
||||
@@ -294,14 +208,22 @@ description = "A lil' TOML parser"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
|
||||
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tomlkit"
|
||||
version = "0.11.4"
|
||||
version = "0.11.6"
|
||||
description = "Style preserving TOML library"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6,<4.0"
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "tomlkit-0.11.6-py3-none-any.whl", hash = "sha256:07de26b0d8cfc18f871aec595fda24d95b08fef89d147caa861939f37230bf4b"},
|
||||
{file = "tomlkit-0.11.6.tar.gz", hash = "sha256:71b952e5721688937fb02cf9d354dbcf0785066149d2855e44531ebdd2b65d73"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wrapt"
|
||||
@@ -310,190 +232,7 @@ description = "Module for decorators, wrappers and monkey patching."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
|
||||
|
||||
[metadata]
|
||||
lock-version = "1.1"
|
||||
python-versions = ">=3.10,<3.11"
|
||||
content-hash = "45e5caa8c4ac70f1b0d0a4f52a19bf7e2cacd55fa2e3f2ac36480491974d3cf8"
|
||||
|
||||
[metadata.files]
|
||||
astroid = [
|
||||
{file = "astroid-2.12.4-py3-none-any.whl", hash = "sha256:af71cdc0775b6e4d88076746620e2c8cd1bf4533a9977cfdd00eeea97d95530c"},
|
||||
{file = "astroid-2.12.4.tar.gz", hash = "sha256:39fa822c82dc112f5072a208ddf01c58184043aa90e3e469786fa0520c71aaa7"},
|
||||
]
|
||||
autoflake = [
|
||||
{file = "autoflake-1.5.1-py2.py3-none-any.whl", hash = "sha256:275e05e3caa8307269ad4d46f2e058b76a5c41ca7d1a7f57158d64e9df3ffdd6"},
|
||||
{file = "autoflake-1.5.1.tar.gz", hash = "sha256:8272efbecf7c6d5e2b00fa3b2998478a3ad92d7c914a49a527d733dae7f800c5"},
|
||||
]
|
||||
colorama = [
|
||||
{file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"},
|
||||
{file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"},
|
||||
]
|
||||
cycler = [
|
||||
{file = "cycler-0.11.0-py3-none-any.whl", hash = "sha256:3a27e95f763a428a739d2add979fa7494c912a32c17c4c38c4d5f082cad165a3"},
|
||||
{file = "cycler-0.11.0.tar.gz", hash = "sha256:9c87405839a19696e837b3b818fed3f5f69f16f1eec1a1ad77e043dcea9c772f"},
|
||||
]
|
||||
dill = [
|
||||
{file = "dill-0.3.5.1-py2.py3-none-any.whl", hash = "sha256:33501d03270bbe410c72639b350e941882a8b0fd55357580fbc873fba0c59302"},
|
||||
{file = "dill-0.3.5.1.tar.gz", hash = "sha256:d75e41f3eff1eee599d738e76ba8f4ad98ea229db8b085318aa2b3333a208c86"},
|
||||
]
|
||||
flake8 = []
|
||||
fonttools = [
|
||||
{file = "fonttools-4.37.1-py3-none-any.whl", hash = "sha256:fff6b752e326c15756c819fe2fe7ceab69f96a1dbcfe8911d0941cdb49905007"},
|
||||
{file = "fonttools-4.37.1.zip", hash = "sha256:4606e1a88ee1f6699d182fea9511bd9a8a915d913eab4584e5226da1180fcce7"},
|
||||
]
|
||||
isort = [
|
||||
{file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"},
|
||||
{file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"},
|
||||
]
|
||||
kiwisolver = []
|
||||
lazy-object-proxy = [
|
||||
{file = "lazy-object-proxy-1.7.1.tar.gz", hash = "sha256:d609c75b986def706743cdebe5e47553f4a5a1da9c5ff66d76013ef396b5a8a4"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bb8c5fd1684d60a9902c60ebe276da1f2281a318ca16c1d0a96db28f62e9166b"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a57d51ed2997e97f3b8e3500c984db50a554bb5db56c50b5dab1b41339b37e36"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd45683c3caddf83abbb1249b653a266e7069a09f486daa8863fb0e7496a9fdb"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8561da8b3dd22d696244d6d0d5330618c993a215070f473b699e00cf1f3f6443"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fccdf7c2c5821a8cbd0a9440a456f5050492f2270bd54e94360cac663398739b"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp310-cp310-win32.whl", hash = "sha256:898322f8d078f2654d275124a8dd19b079080ae977033b713f677afcfc88e2b9"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:85b232e791f2229a4f55840ed54706110c80c0a210d076eee093f2b2e33e1bfd"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:46ff647e76f106bb444b4533bb4153c7370cdf52efc62ccfc1a28bdb3cc95442"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12f3bb77efe1367b2515f8cb4790a11cffae889148ad33adad07b9b55e0ab22c"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c19814163728941bb871240d45c4c30d33b8a2e85972c44d4e63dd7107faba44"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:e40f2013d96d30217a51eeb1db28c9ac41e9d0ee915ef9d00da639c5b63f01a1"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:2052837718516a94940867e16b1bb10edb069ab475c3ad84fd1e1a6dd2c0fcfc"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp36-cp36m-win32.whl", hash = "sha256:6a24357267aa976abab660b1d47a34aaf07259a0c3859a34e536f1ee6e76b5bb"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp36-cp36m-win_amd64.whl", hash = "sha256:6aff3fe5de0831867092e017cf67e2750c6a1c7d88d84d2481bd84a2e019ec35"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6a6e94c7b02641d1311228a102607ecd576f70734dc3d5e22610111aeacba8a0"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4ce15276a1a14549d7e81c243b887293904ad2d94ad767f42df91e75fd7b5b6"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e368b7f7eac182a59ff1f81d5f3802161932a41dc1b1cc45c1f757dc876b5d2c"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6ecbb350991d6434e1388bee761ece3260e5228952b1f0c46ffc800eb313ff42"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:553b0f0d8dbf21890dd66edd771f9b1b5f51bd912fa5f26de4449bfc5af5e029"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp37-cp37m-win32.whl", hash = "sha256:c7a683c37a8a24f6428c28c561c80d5f4fd316ddcf0c7cab999b15ab3f5c5c69"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp37-cp37m-win_amd64.whl", hash = "sha256:df2631f9d67259dc9620d831384ed7732a198eb434eadf69aea95ad18c587a28"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:07fa44286cda977bd4803b656ffc1c9b7e3bc7dff7d34263446aec8f8c96f88a"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4dca6244e4121c74cc20542c2ca39e5c4a5027c81d112bfb893cf0790f96f57e"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91ba172fc5b03978764d1df5144b4ba4ab13290d7bab7a50f12d8117f8630c38"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:043651b6cb706eee4f91854da4a089816a6606c1428fd391573ef8cb642ae4f7"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b9e89b87c707dd769c4ea91f7a31538888aad05c116a59820f28d59b3ebfe25a"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp38-cp38-win32.whl", hash = "sha256:9d166602b525bf54ac994cf833c385bfcc341b364e3ee71e3bf5a1336e677b55"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:8f3953eb575b45480db6568306893f0bd9d8dfeeebd46812aa09ca9579595148"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dd7ed7429dbb6c494aa9bc4e09d94b778a3579be699f9d67da7e6804c422d3de"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70ed0c2b380eb6248abdef3cd425fc52f0abd92d2b07ce26359fcbc399f636ad"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7096a5e0c1115ec82641afbdd70451a144558ea5cf564a896294e346eb611be1"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f769457a639403073968d118bc70110e7dce294688009f5c24ab78800ae56dc8"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:39b0e26725c5023757fc1ab2a89ef9d7ab23b84f9251e28f9cc114d5b59c1b09"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp39-cp39-win32.whl", hash = "sha256:2130db8ed69a48a3440103d4a520b89d8a9405f1b06e2cc81640509e8bf6548f"},
|
||||
{file = "lazy_object_proxy-1.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:677ea950bef409b47e51e733283544ac3d660b709cfce7b187f5ace137960d61"},
|
||||
{file = "lazy_object_proxy-1.7.1-pp37.pp38-none-any.whl", hash = "sha256:d66906d5785da8e0be7360912e99c9188b70f52c422f9fc18223347235691a84"},
|
||||
]
|
||||
matplotlib = [
|
||||
{file = "matplotlib-3.5.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a206a1b762b39398efea838f528b3a6d60cdb26fe9d58b48265787e29cd1d693"},
|
||||
{file = "matplotlib-3.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cd45a6f3e93a780185f70f05cf2a383daed13c3489233faad83e81720f7ede24"},
|
||||
{file = "matplotlib-3.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d62880e1f60e5a30a2a8484432bcb3a5056969dc97258d7326ad465feb7ae069"},
|
||||
{file = "matplotlib-3.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9ab29589cef03bc88acfa3a1490359000c18186fc30374d8aa77d33cc4a51a4a"},
|
||||
{file = "matplotlib-3.5.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2886cc009f40e2984c083687251821f305d811d38e3df8ded414265e4583f0c5"},
|
||||
{file = "matplotlib-3.5.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c995f7d9568f18b5db131ab124c64e51b6820a92d10246d4f2b3f3a66698a15b"},
|
||||
{file = "matplotlib-3.5.3-cp310-cp310-win32.whl", hash = "sha256:6bb93a0492d68461bd458eba878f52fdc8ac7bdb6c4acdfe43dba684787838c2"},
|
||||
{file = "matplotlib-3.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:2e6d184ebe291b9e8f7e78bbab7987d269c38ea3e062eace1fe7d898042ef804"},
|
||||
{file = "matplotlib-3.5.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6ea6aef5c4338e58d8d376068e28f80a24f54e69f09479d1c90b7172bad9f25b"},
|
||||
{file = "matplotlib-3.5.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:839d47b8ead7ad9669aaacdbc03f29656dc21f0d41a6fea2d473d856c39c8b1c"},
|
||||
{file = "matplotlib-3.5.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3b4fa56159dc3c7f9250df88f653f085068bcd32dcd38e479bba58909254af7f"},
|
||||
{file = "matplotlib-3.5.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:94ff86af56a3869a4ae26a9637a849effd7643858a1a04dd5ee50e9ab75069a7"},
|
||||
{file = "matplotlib-3.5.3-cp37-cp37m-win32.whl", hash = "sha256:35a8ad4dddebd51f94c5d24bec689ec0ec66173bf614374a1244c6241c1595e0"},
|
||||
{file = "matplotlib-3.5.3-cp37-cp37m-win_amd64.whl", hash = "sha256:43e9d3fa077bf0cc95ded13d331d2156f9973dce17c6f0c8b49ccd57af94dbd9"},
|
||||
{file = "matplotlib-3.5.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:22227c976ad4dc8c5a5057540421f0d8708c6560744ad2ad638d48e2984e1dbc"},
|
||||
{file = "matplotlib-3.5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bf618a825deb6205f015df6dfe6167a5d9b351203b03fab82043ae1d30f16511"},
|
||||
{file = "matplotlib-3.5.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9befa5954cdbc085e37d974ff6053da269474177921dd61facdad8023c4aeb51"},
|
||||
{file = "matplotlib-3.5.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3840c280ebc87a48488a46f760ea1c0c0c83fcf7abbe2e6baf99d033fd35fd8"},
|
||||
{file = "matplotlib-3.5.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dacddf5bfcec60e3f26ec5c0ae3d0274853a258b6c3fc5ef2f06a8eb23e042be"},
|
||||
{file = "matplotlib-3.5.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b428076a55fb1c084c76cb93e68006f27d247169f056412607c5c88828d08f88"},
|
||||
{file = "matplotlib-3.5.3-cp38-cp38-win32.whl", hash = "sha256:874df7505ba820e0400e7091199decf3ff1fde0583652120c50cd60d5820ca9a"},
|
||||
{file = "matplotlib-3.5.3-cp38-cp38-win_amd64.whl", hash = "sha256:b28de401d928890187c589036857a270a032961411934bdac4cf12dde3d43094"},
|
||||
{file = "matplotlib-3.5.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3211ba82b9f1518d346f6309df137b50c3dc4421b4ed4815d1d7eadc617f45a1"},
|
||||
{file = "matplotlib-3.5.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6fe807e8a22620b4cd95cfbc795ba310dc80151d43b037257250faf0bfcd82bc"},
|
||||
{file = "matplotlib-3.5.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5c096363b206a3caf43773abebdbb5a23ea13faef71d701b21a9c27fdcef72f4"},
|
||||
{file = "matplotlib-3.5.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bcdfcb0f976e1bac6721d7d457c17be23cf7501f977b6a38f9d38a3762841f7"},
|
||||
{file = "matplotlib-3.5.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1e64ac9be9da6bfff0a732e62116484b93b02a0b4d4b19934fb4f8e7ad26ad6a"},
|
||||
{file = "matplotlib-3.5.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:73dd93dc35c85dece610cca8358003bf0760d7986f70b223e2306b4ea6d1406b"},
|
||||
{file = "matplotlib-3.5.3-cp39-cp39-win32.whl", hash = "sha256:879c7e5fce4939c6aa04581dfe08d57eb6102a71f2e202e3314d5fbc072fd5a0"},
|
||||
{file = "matplotlib-3.5.3-cp39-cp39-win_amd64.whl", hash = "sha256:ab8d26f07fe64f6f6736d635cce7bfd7f625320490ed5bfc347f2cdb4fae0e56"},
|
||||
{file = "matplotlib-3.5.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:99482b83ebf4eb6d5fc6813d7aacdefdd480f0d9c0b52dcf9f1cc3b2c4b3361a"},
|
||||
{file = "matplotlib-3.5.3-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f814504e459c68118bf2246a530ed953ebd18213dc20e3da524174d84ed010b2"},
|
||||
{file = "matplotlib-3.5.3-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:57f1b4e69f438a99bb64d7f2c340db1b096b41ebaa515cf61ea72624279220ce"},
|
||||
{file = "matplotlib-3.5.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:d2484b350bf3d32cae43f85dcfc89b3ed7bd2bcd781ef351f93eb6fb2cc483f9"},
|
||||
{file = "matplotlib-3.5.3.tar.gz", hash = "sha256:339cac48b80ddbc8bfd05daae0a3a73414651a8596904c2a881cfd1edb65f26c"},
|
||||
]
|
||||
mccabe = []
|
||||
numpy = []
|
||||
packaging = [
|
||||
{file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
|
||||
{file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"},
|
||||
]
|
||||
pillow = []
|
||||
platformdirs = [
|
||||
{file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"},
|
||||
{file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"},
|
||||
]
|
||||
pycodestyle = []
|
||||
pyflakes = []
|
||||
pylint = [
|
||||
{file = "pylint-2.15.0-py3-none-any.whl", hash = "sha256:4b124affc198b7f7c9b5f9ab690d85db48282a025ef9333f51d2d7281b92a6c3"},
|
||||
{file = "pylint-2.15.0.tar.gz", hash = "sha256:4f3f7e869646b0bd63b3dfb79f3c0f28fc3d2d923ea220d52620fd625aed92b0"},
|
||||
]
|
||||
pyparsing = [
|
||||
{file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"},
|
||||
{file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"},
|
||||
]
|
||||
python-dateutil = [
|
||||
{file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"},
|
||||
{file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"},
|
||||
]
|
||||
scipy = [
|
||||
{file = "scipy-1.9.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c61b4a91a702e8e04aeb0bfc40460e1f17a640977c04dda8757efb0199c75332"},
|
||||
{file = "scipy-1.9.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:d79da472015d0120ba9b357b28a99146cd6c17b9609403164b1a8ed149b4dfc8"},
|
||||
{file = "scipy-1.9.1-cp310-cp310-macosx_12_0_universal2.macosx_10_9_x86_64.whl", hash = "sha256:825951b88f56765aeb6e5e38ac9d7d47407cfaaeb008d40aa1b45a2d7ea2731e"},
|
||||
{file = "scipy-1.9.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f950a04b33e17b38ff561d5a0951caf3f5b47caa841edd772ffb7959f20a6af0"},
|
||||
{file = "scipy-1.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cc81ac25659fec73599ccc52c989670e5ccd8974cf34bacd7b54a8d809aff1a"},
|
||||
{file = "scipy-1.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:8d3faa40ac16c6357aaf7ea50394ea6f1e8e99d75e927a51102b1943b311b4d9"},
|
||||
{file = "scipy-1.9.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7a412c476a91b080e456229e413792bbb5d6202865dae963d1e6e28c2bb58691"},
|
||||
{file = "scipy-1.9.1-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:eb954f5aca4d26f468bbebcdc5448348eb287f7bea536c6306f62ea062f63d9a"},
|
||||
{file = "scipy-1.9.1-cp38-cp38-macosx_12_0_universal2.macosx_10_9_x86_64.whl", hash = "sha256:3c6f5d1d4b9a5e4fe5e14f26ffc9444fc59473bbf8d45dc4a9a15283b7063a72"},
|
||||
{file = "scipy-1.9.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:bc4e2c77d4cd015d739e75e74ebbafed59ba8497a7ed0fd400231ed7683497c4"},
|
||||
{file = "scipy-1.9.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0419485dbcd0ed78c0d5bf234c5dd63e86065b39b4d669e45810d42199d49521"},
|
||||
{file = "scipy-1.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:34441dfbee5b002f9e15285014fd56e5e3372493c3e64ae297bae2c4b9659f5a"},
|
||||
{file = "scipy-1.9.1-cp38-cp38-win32.whl", hash = "sha256:b97b479f39c7e4aaf807efd0424dec74bbb379108f7d22cf09323086afcd312c"},
|
||||
{file = "scipy-1.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:e8fe305d9d67a81255e06203454729405706907dccbdfcc330b7b3482a6c371d"},
|
||||
{file = "scipy-1.9.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:39ab9240cd215a9349c85ab908dda6d732f7d3b4b192fa05780812495536acc4"},
|
||||
{file = "scipy-1.9.1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:71487c503e036740635f18324f62a11f283a632ace9d35933b2b0a04fd898c98"},
|
||||
{file = "scipy-1.9.1-cp39-cp39-macosx_12_0_universal2.macosx_10_9_x86_64.whl", hash = "sha256:3bc1ab68b9a096f368ba06c3a5e1d1d50957a86665fc929c4332d21355e7e8f4"},
|
||||
{file = "scipy-1.9.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f7c39f7dbb57cce00c108d06d731f3b0e2a4d3a95c66d96bce697684876ce4d4"},
|
||||
{file = "scipy-1.9.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47d1a95bd9d37302afcfe1b84c8011377c4f81e33649c5a5785db9ab827a6ade"},
|
||||
{file = "scipy-1.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96d7cf7b25c9f23c59a766385f6370dab0659741699ecc7a451f9b94604938ce"},
|
||||
{file = "scipy-1.9.1-cp39-cp39-win32.whl", hash = "sha256:09412eb7fb60b8f00b328037fd814d25d261066ebc43a1e339cdce4f7502877e"},
|
||||
{file = "scipy-1.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:90c805f30c46cf60f1e76e947574f02954d25e3bb1e97aa8a07bc53aa31cf7d1"},
|
||||
{file = "scipy-1.9.1.tar.gz", hash = "sha256:26d28c468900e6d5fdb37d2812ab46db0ccd22c63baa095057871faa3a498bc9"},
|
||||
]
|
||||
setuptools-scm = [
|
||||
{file = "setuptools_scm-6.4.2-py3-none-any.whl", hash = "sha256:acea13255093849de7ccb11af9e1fb8bde7067783450cee9ef7a93139bddf6d4"},
|
||||
{file = "setuptools_scm-6.4.2.tar.gz", hash = "sha256:6833ac65c6ed9711a4d5d2266f8024cfa07c533a0e55f4c12f6eff280a5a9e30"},
|
||||
]
|
||||
six = [
|
||||
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
|
||||
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
|
||||
]
|
||||
toml = [
|
||||
{file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
|
||||
{file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
|
||||
]
|
||||
tomli = [
|
||||
{file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
|
||||
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
|
||||
]
|
||||
tomlkit = [
|
||||
{file = "tomlkit-0.11.4-py3-none-any.whl", hash = "sha256:25d4e2e446c453be6360c67ddfb88838cfc42026322770ba13d1fbd403a93a5c"},
|
||||
{file = "tomlkit-0.11.4.tar.gz", hash = "sha256:3235a9010fae54323e727c3ac06fb720752fe6635b3426e379daec60fbd44a83"},
|
||||
]
|
||||
wrapt = [
|
||||
files = [
|
||||
{file = "wrapt-1.14.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1b376b3f4896e7930f1f772ac4b064ac12598d1c38d04907e696cc4d794b43d3"},
|
||||
{file = "wrapt-1.14.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:903500616422a40a98a5a3c4ff4ed9d0066f3b4c951fa286018ecdf0750194ef"},
|
||||
{file = "wrapt-1.14.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5a9a0d155deafd9448baff28c08e150d9b24ff010e899311ddd63c45c2445e28"},
|
||||
@@ -559,3 +298,8 @@ wrapt = [
|
||||
{file = "wrapt-1.14.1-cp39-cp39-win_amd64.whl", hash = "sha256:dee60e1de1898bde3b238f18340eec6148986da0455d8ba7848d50470a7a32fb"},
|
||||
{file = "wrapt-1.14.1.tar.gz", hash = "sha256:380a85cf89e0e69b7cfbe2ea9f765f004ff419f34194018a6827ac0e3edfed4d"},
|
||||
]
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = ">=3.10,<3.11"
|
||||
content-hash = "959633dfe6335ab3f943a95c5fdd12ff1bb66cd03c5917704f10ae38d3a5009c"
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
[tool.black]
|
||||
line-length = 120
|
||||
|
||||
[tool.ruff]
|
||||
line-length = 120
|
||||
select = ["E", "F", "W", "I", "C", "RET", "ANN", "UP"]
|
||||
target-version = "py310"
|
||||
|
||||
[tool.poetry]
|
||||
name = "scripts"
|
||||
version = "0.1.0"
|
||||
@@ -8,12 +16,9 @@ authors = ["Charles Marsh <charlie.r.marsh@gmail.com>"]
|
||||
python = ">=3.10,<3.11"
|
||||
autoflake = "^1.4"
|
||||
flake8 = "^5.0.4"
|
||||
matplotlib = "^3.5.3"
|
||||
numpy = "^1.23.2"
|
||||
pycodestyle = "^2.9.1"
|
||||
pyflakes = "^2.5.0"
|
||||
pylint = "^2.15.0"
|
||||
scipy = "^1.9.1"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
"""Wrapper around Flake8 to enable multiprocessing on all operating systems.
|
||||
|
||||
As of Python 3.8, macOS's default "start method" for multiprocessing is `spawn`. Flake8
|
||||
|
||||
@@ -5,10 +5,11 @@ use regex::Regex;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use rustpython_ast::{
|
||||
Arguments, Constant, Excepthandler, ExcepthandlerKind, Expr, ExprKind, Keyword, KeywordData,
|
||||
Location, Stmt, StmtKind,
|
||||
Located, Location, Stmt, StmtKind,
|
||||
};
|
||||
use rustpython_parser::lexer;
|
||||
use rustpython_parser::lexer::Tok;
|
||||
use rustpython_parser::token::StringKind;
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::SourceCodeLocator;
|
||||
@@ -212,6 +213,23 @@ pub fn is_constant_non_singleton(expr: &Expr) -> bool {
|
||||
is_constant(expr) && !is_singleton(expr)
|
||||
}
|
||||
|
||||
/// Return `true` if an `Expr` is not a reference to a variable (or something
|
||||
/// that could resolve to a variable, like a function call).
|
||||
pub fn is_non_variable(expr: &Expr) -> bool {
|
||||
matches!(
|
||||
expr.node,
|
||||
ExprKind::Constant { .. }
|
||||
| ExprKind::Tuple { .. }
|
||||
| ExprKind::List { .. }
|
||||
| ExprKind::Set { .. }
|
||||
| ExprKind::Dict { .. }
|
||||
| ExprKind::SetComp { .. }
|
||||
| ExprKind::ListComp { .. }
|
||||
| ExprKind::DictComp { .. }
|
||||
| ExprKind::GeneratorExp { .. }
|
||||
)
|
||||
}
|
||||
|
||||
/// Return the `Keyword` with the given name, if it's present in the list of
|
||||
/// `Keyword` arguments.
|
||||
pub fn find_keyword<'a>(keywords: &'a [Keyword], keyword_name: &str) -> Option<&'a Keyword> {
|
||||
@@ -335,20 +353,17 @@ pub fn to_absolute(relative: Location, base: Location) -> Location {
|
||||
|
||||
/// Return `true` if a `Stmt` has leading content.
|
||||
pub fn match_leading_content(stmt: &Stmt, locator: &SourceCodeLocator) -> bool {
|
||||
let range = Range {
|
||||
location: Location::new(stmt.location.row(), 0),
|
||||
end_location: stmt.location,
|
||||
};
|
||||
let range = Range::new(Location::new(stmt.location.row(), 0), stmt.location);
|
||||
let prefix = locator.slice_source_code_range(&range);
|
||||
prefix.chars().any(|char| !char.is_whitespace())
|
||||
}
|
||||
|
||||
/// Return `true` if a `Stmt` has trailing content.
|
||||
pub fn match_trailing_content(stmt: &Stmt, locator: &SourceCodeLocator) -> bool {
|
||||
let range = Range {
|
||||
location: stmt.end_location.unwrap(),
|
||||
end_location: Location::new(stmt.end_location.unwrap().row() + 1, 0),
|
||||
};
|
||||
let range = Range::new(
|
||||
stmt.end_location.unwrap(),
|
||||
Location::new(stmt.end_location.unwrap().row() + 1, 0),
|
||||
);
|
||||
let suffix = locator.slice_source_code_range(&range);
|
||||
for char in suffix.chars() {
|
||||
if char == '#' {
|
||||
@@ -384,10 +399,7 @@ pub fn identifier_range(stmt: &Stmt, locator: &SourceCodeLocator) -> Range {
|
||||
let contents = locator.slice_source_code_range(&Range::from_located(stmt));
|
||||
for (start, tok, end) in lexer::make_tokenizer_located(&contents, stmt.location).flatten() {
|
||||
if matches!(tok, Tok::Name { .. }) {
|
||||
return Range {
|
||||
location: start,
|
||||
end_location: end,
|
||||
};
|
||||
return Range::new(start, end);
|
||||
}
|
||||
}
|
||||
error!("Failed to find identifier for {:?}", stmt);
|
||||
@@ -395,6 +407,19 @@ pub fn identifier_range(stmt: &Stmt, locator: &SourceCodeLocator) -> Range {
|
||||
Range::from_located(stmt)
|
||||
}
|
||||
|
||||
// Return the ranges of `Name` tokens within a specified node.
|
||||
pub fn find_names<T>(located: &Located<T>, locator: &SourceCodeLocator) -> Vec<Range> {
|
||||
let contents = locator.slice_source_code_range(&Range::from_located(located));
|
||||
lexer::make_tokenizer_located(&contents, located.location)
|
||||
.flatten()
|
||||
.filter(|(_, tok, _)| matches!(tok, Tok::Name { .. }))
|
||||
.map(|(start, _, end)| Range {
|
||||
location: start,
|
||||
end_location: end,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Return the `Range` of `name` in `Excepthandler`.
|
||||
pub fn excepthandler_name_range(
|
||||
handler: &Excepthandler,
|
||||
@@ -406,17 +431,107 @@ pub fn excepthandler_name_range(
|
||||
match (name, type_) {
|
||||
(Some(_), Some(type_)) => {
|
||||
let type_end_location = type_.end_location.unwrap();
|
||||
let contents = locator.slice_source_code_range(&Range {
|
||||
location: type_end_location,
|
||||
end_location: body[0].location,
|
||||
});
|
||||
let contents =
|
||||
locator.slice_source_code_range(&Range::new(type_end_location, body[0].location));
|
||||
let range = lexer::make_tokenizer_located(&contents, type_end_location)
|
||||
.flatten()
|
||||
.tuple_windows()
|
||||
.find(|(tok, next_tok)| {
|
||||
matches!(tok.1, Tok::As) && matches!(next_tok.1, Tok::Name { .. })
|
||||
})
|
||||
.map(|((..), (location, _, end_location))| Range {
|
||||
.map(|((..), (location, _, end_location))| Range::new(location, end_location));
|
||||
range
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the `Range` of `except` in `Excepthandler`.
|
||||
pub fn except_range(handler: &Excepthandler, locator: &SourceCodeLocator) -> Range {
|
||||
let ExcepthandlerKind::ExceptHandler { body, type_, .. } = &handler.node;
|
||||
let end = if let Some(type_) = type_ {
|
||||
type_.location
|
||||
} else {
|
||||
body.first()
|
||||
.expect("Expected body to be non-empty")
|
||||
.location
|
||||
};
|
||||
let contents = locator.slice_source_code_range(&Range {
|
||||
location: handler.location,
|
||||
end_location: end,
|
||||
});
|
||||
let range = lexer::make_tokenizer_located(&contents, handler.location)
|
||||
.flatten()
|
||||
.find(|(_, kind, _)| matches!(kind, Tok::Except { .. }))
|
||||
.map(|(location, _, end_location)| Range {
|
||||
location,
|
||||
end_location,
|
||||
})
|
||||
.expect("Failed to find `except` range");
|
||||
range
|
||||
}
|
||||
|
||||
/// Find f-strings that don't contain any formatted values in a `JoinedStr`.
|
||||
pub fn find_useless_f_strings(expr: &Expr, locator: &SourceCodeLocator) -> Vec<(Range, Range)> {
|
||||
let contents = locator.slice_source_code_range(&Range::from_located(expr));
|
||||
lexer::make_tokenizer_located(&contents, expr.location)
|
||||
.flatten()
|
||||
.filter_map(|(location, tok, end_location)| match tok {
|
||||
Tok::String {
|
||||
kind: StringKind::FString | StringKind::RawFString,
|
||||
..
|
||||
} => {
|
||||
let first_char = locator.slice_source_code_range(&Range {
|
||||
location,
|
||||
end_location: Location::new(location.row(), location.column() + 1),
|
||||
});
|
||||
// f"..." => f_position = 0
|
||||
// fr"..." => f_position = 0
|
||||
// rf"..." => f_position = 1
|
||||
let f_position = usize::from(!(first_char == "f" || first_char == "F"));
|
||||
Some((
|
||||
Range {
|
||||
location: Location::new(location.row(), location.column() + f_position),
|
||||
end_location: Location::new(
|
||||
location.row(),
|
||||
location.column() + f_position + 1,
|
||||
),
|
||||
},
|
||||
Range {
|
||||
location,
|
||||
end_location,
|
||||
},
|
||||
))
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Return the `Range` of `else` in `For`, `AsyncFor`, and `While` statements.
|
||||
pub fn else_range(stmt: &Stmt, locator: &SourceCodeLocator) -> Option<Range> {
|
||||
match &stmt.node {
|
||||
StmtKind::For { body, orelse, .. }
|
||||
| StmtKind::AsyncFor { body, orelse, .. }
|
||||
| StmtKind::While { body, orelse, .. }
|
||||
if !orelse.is_empty() =>
|
||||
{
|
||||
let body_end = body
|
||||
.last()
|
||||
.expect("Expected body to be non-empty")
|
||||
.end_location
|
||||
.unwrap();
|
||||
let contents = locator.slice_source_code_range(&Range {
|
||||
location: body_end,
|
||||
end_location: orelse
|
||||
.first()
|
||||
.expect("Expected orelse to be non-empty")
|
||||
.location,
|
||||
});
|
||||
let range = lexer::make_tokenizer_located(&contents, body_end)
|
||||
.flatten()
|
||||
.find(|(_, kind, _)| matches!(kind, Tok::Else))
|
||||
.map(|(location, _, end_location)| Range {
|
||||
location,
|
||||
end_location,
|
||||
});
|
||||
@@ -435,10 +550,10 @@ pub fn preceded_by_continuation(stmt: &Stmt, locator: &SourceCodeLocator) -> boo
|
||||
// make conservative choices.
|
||||
// TODO(charlie): Come up with a more robust strategy.
|
||||
if stmt.location.row() > 1 {
|
||||
let range = Range {
|
||||
location: Location::new(stmt.location.row() - 1, 0),
|
||||
end_location: Location::new(stmt.location.row(), 0),
|
||||
};
|
||||
let range = Range::new(
|
||||
Location::new(stmt.location.row() - 1, 0),
|
||||
Location::new(stmt.location.row(), 0),
|
||||
);
|
||||
let line = locator.slice_source_code_range(&range);
|
||||
if line.trim().ends_with('\\') {
|
||||
return true;
|
||||
@@ -466,7 +581,9 @@ mod tests {
|
||||
use rustpython_ast::Location;
|
||||
use rustpython_parser::parser;
|
||||
|
||||
use crate::ast::helpers::{identifier_range, match_module_member, match_trailing_content};
|
||||
use crate::ast::helpers::{
|
||||
else_range, identifier_range, match_module_member, match_trailing_content,
|
||||
};
|
||||
use crate::ast::types::Range;
|
||||
use crate::source_code_locator::SourceCodeLocator;
|
||||
|
||||
@@ -660,10 +777,7 @@ y = 2
|
||||
let locator = SourceCodeLocator::new(contents);
|
||||
assert_eq!(
|
||||
identifier_range(stmt, &locator),
|
||||
Range {
|
||||
location: Location::new(1, 4),
|
||||
end_location: Location::new(1, 5),
|
||||
}
|
||||
Range::new(Location::new(1, 4), Location::new(1, 5),)
|
||||
);
|
||||
|
||||
let contents = r#"
|
||||
@@ -677,10 +791,7 @@ def \
|
||||
let locator = SourceCodeLocator::new(contents);
|
||||
assert_eq!(
|
||||
identifier_range(stmt, &locator),
|
||||
Range {
|
||||
location: Location::new(2, 2),
|
||||
end_location: Location::new(2, 3),
|
||||
}
|
||||
Range::new(Location::new(2, 2), Location::new(2, 3),)
|
||||
);
|
||||
|
||||
let contents = "class Class(): pass".trim();
|
||||
@@ -689,10 +800,7 @@ def \
|
||||
let locator = SourceCodeLocator::new(contents);
|
||||
assert_eq!(
|
||||
identifier_range(stmt, &locator),
|
||||
Range {
|
||||
location: Location::new(1, 6),
|
||||
end_location: Location::new(1, 11),
|
||||
}
|
||||
Range::new(Location::new(1, 6), Location::new(1, 11),)
|
||||
);
|
||||
|
||||
let contents = "class Class: pass".trim();
|
||||
@@ -701,10 +809,7 @@ def \
|
||||
let locator = SourceCodeLocator::new(contents);
|
||||
assert_eq!(
|
||||
identifier_range(stmt, &locator),
|
||||
Range {
|
||||
location: Location::new(1, 6),
|
||||
end_location: Location::new(1, 11),
|
||||
}
|
||||
Range::new(Location::new(1, 6), Location::new(1, 11),)
|
||||
);
|
||||
|
||||
let contents = r#"
|
||||
@@ -718,10 +823,7 @@ class Class():
|
||||
let locator = SourceCodeLocator::new(contents);
|
||||
assert_eq!(
|
||||
identifier_range(stmt, &locator),
|
||||
Range {
|
||||
location: Location::new(2, 6),
|
||||
end_location: Location::new(2, 11),
|
||||
}
|
||||
Range::new(Location::new(2, 6), Location::new(2, 11),)
|
||||
);
|
||||
|
||||
let contents = r#"x = y + 1"#.trim();
|
||||
@@ -730,12 +832,29 @@ class Class():
|
||||
let locator = SourceCodeLocator::new(contents);
|
||||
assert_eq!(
|
||||
identifier_range(stmt, &locator),
|
||||
Range {
|
||||
location: Location::new(1, 0),
|
||||
end_location: Location::new(1, 9),
|
||||
}
|
||||
Range::new(Location::new(1, 0), Location::new(1, 9),)
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_else_range() -> Result<()> {
|
||||
let contents = r#"
|
||||
for x in y:
|
||||
pass
|
||||
else:
|
||||
pass
|
||||
"#
|
||||
.trim();
|
||||
let program = parser::parse_program(contents, "<filename>")?;
|
||||
let stmt = program.first().unwrap();
|
||||
let locator = SourceCodeLocator::new(contents);
|
||||
let range = else_range(stmt, &locator).unwrap();
|
||||
assert_eq!(range.location.row(), 3);
|
||||
assert_eq!(range.location.column(), 0);
|
||||
assert_eq!(range.end_location.row(), 3);
|
||||
assert_eq!(range.end_location.column(), 4);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,10 +266,7 @@ pub type LocatedCmpop<U = ()> = Located<Cmpop, U>;
|
||||
/// `CPython` doesn't either. This method iterates over the token stream and
|
||||
/// re-identifies `Cmpop` nodes, annotating them with valid ranges.
|
||||
pub fn locate_cmpops(contents: &str) -> Vec<LocatedCmpop> {
|
||||
let mut tok_iter = lexer::make_tokenizer(contents)
|
||||
.flatten()
|
||||
.into_iter()
|
||||
.peekable();
|
||||
let mut tok_iter = lexer::make_tokenizer(contents).flatten().peekable();
|
||||
let mut ops: Vec<LocatedCmpop> = vec![];
|
||||
let mut count: usize = 0;
|
||||
loop {
|
||||
|
||||
@@ -22,12 +22,16 @@ pub struct Range {
|
||||
}
|
||||
|
||||
impl Range {
|
||||
pub fn from_located<T>(located: &Located<T>) -> Self {
|
||||
Range {
|
||||
location: located.location,
|
||||
end_location: located.end_location.unwrap(),
|
||||
pub fn new(location: Location, end_location: Location) -> Self {
|
||||
Self {
|
||||
location,
|
||||
end_location,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_located<T>(located: &Located<T>) -> Self {
|
||||
Range::new(located.location, located.end_location.unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
||||
@@ -38,6 +38,9 @@ pub trait Visitor<'a> {
|
||||
fn visit_excepthandler(&mut self, excepthandler: &'a Excepthandler) {
|
||||
walk_excepthandler(self, excepthandler);
|
||||
}
|
||||
fn visit_format_spec(&mut self, format_spec: &'a Expr) {
|
||||
walk_expr(self, format_spec);
|
||||
}
|
||||
fn visit_arguments(&mut self, arguments: &'a Arguments) {
|
||||
walk_arguments(self, arguments);
|
||||
}
|
||||
@@ -59,6 +62,15 @@ pub trait Visitor<'a> {
|
||||
fn visit_pattern(&mut self, pattern: &'a Pattern) {
|
||||
walk_pattern(self, pattern);
|
||||
}
|
||||
fn visit_body(&mut self, body: &'a [Stmt]) {
|
||||
walk_body(self, body);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_body<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, body: &'a [Stmt]) {
|
||||
for stmt in body {
|
||||
visitor.visit_stmt(stmt);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_stmt<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, stmt: &'a Stmt) {
|
||||
@@ -77,9 +89,7 @@ pub fn walk_stmt<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, stmt: &'a Stmt) {
|
||||
for expr in returns {
|
||||
visitor.visit_annotation(expr);
|
||||
}
|
||||
for stmt in body {
|
||||
visitor.visit_stmt(stmt);
|
||||
}
|
||||
visitor.visit_body(body);
|
||||
}
|
||||
StmtKind::AsyncFunctionDef {
|
||||
args,
|
||||
@@ -95,9 +105,7 @@ pub fn walk_stmt<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, stmt: &'a Stmt) {
|
||||
for expr in returns {
|
||||
visitor.visit_annotation(expr);
|
||||
}
|
||||
for stmt in body {
|
||||
visitor.visit_stmt(stmt);
|
||||
}
|
||||
visitor.visit_body(body);
|
||||
}
|
||||
StmtKind::ClassDef {
|
||||
bases,
|
||||
@@ -115,9 +123,7 @@ pub fn walk_stmt<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, stmt: &'a Stmt) {
|
||||
for expr in decorator_list {
|
||||
visitor.visit_expr(expr);
|
||||
}
|
||||
for stmt in body {
|
||||
visitor.visit_stmt(stmt);
|
||||
}
|
||||
visitor.visit_body(body);
|
||||
}
|
||||
StmtKind::Return { value } => {
|
||||
if let Some(expr) = value {
|
||||
@@ -161,12 +167,8 @@ pub fn walk_stmt<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, stmt: &'a Stmt) {
|
||||
} => {
|
||||
visitor.visit_expr(iter);
|
||||
visitor.visit_expr(target);
|
||||
for stmt in body {
|
||||
visitor.visit_stmt(stmt);
|
||||
}
|
||||
for stmt in orelse {
|
||||
visitor.visit_stmt(stmt);
|
||||
}
|
||||
visitor.visit_body(body);
|
||||
visitor.visit_body(orelse);
|
||||
}
|
||||
StmtKind::AsyncFor {
|
||||
target,
|
||||
@@ -177,46 +179,30 @@ pub fn walk_stmt<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, stmt: &'a Stmt) {
|
||||
} => {
|
||||
visitor.visit_expr(iter);
|
||||
visitor.visit_expr(target);
|
||||
for stmt in body {
|
||||
visitor.visit_stmt(stmt);
|
||||
}
|
||||
for stmt in orelse {
|
||||
visitor.visit_stmt(stmt);
|
||||
}
|
||||
visitor.visit_body(body);
|
||||
visitor.visit_body(orelse);
|
||||
}
|
||||
StmtKind::While { test, body, orelse } => {
|
||||
visitor.visit_expr(test);
|
||||
for stmt in body {
|
||||
visitor.visit_stmt(stmt);
|
||||
}
|
||||
for stmt in orelse {
|
||||
visitor.visit_stmt(stmt);
|
||||
}
|
||||
visitor.visit_body(body);
|
||||
visitor.visit_body(orelse);
|
||||
}
|
||||
StmtKind::If { test, body, orelse } => {
|
||||
visitor.visit_expr(test);
|
||||
for stmt in body {
|
||||
visitor.visit_stmt(stmt);
|
||||
}
|
||||
for stmt in orelse {
|
||||
visitor.visit_stmt(stmt);
|
||||
}
|
||||
visitor.visit_body(body);
|
||||
visitor.visit_body(orelse);
|
||||
}
|
||||
StmtKind::With { items, body, .. } => {
|
||||
for withitem in items {
|
||||
visitor.visit_withitem(withitem);
|
||||
}
|
||||
for stmt in body {
|
||||
visitor.visit_stmt(stmt);
|
||||
}
|
||||
visitor.visit_body(body);
|
||||
}
|
||||
StmtKind::AsyncWith { items, body, .. } => {
|
||||
for withitem in items {
|
||||
visitor.visit_withitem(withitem);
|
||||
}
|
||||
for stmt in body {
|
||||
visitor.visit_stmt(stmt);
|
||||
}
|
||||
visitor.visit_body(body);
|
||||
}
|
||||
StmtKind::Match { subject, cases } => {
|
||||
// TODO(charlie): Handle `cases`.
|
||||
@@ -239,18 +225,12 @@ pub fn walk_stmt<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, stmt: &'a Stmt) {
|
||||
orelse,
|
||||
finalbody,
|
||||
} => {
|
||||
for stmt in body {
|
||||
visitor.visit_stmt(stmt);
|
||||
}
|
||||
visitor.visit_body(body);
|
||||
for excepthandler in handlers {
|
||||
visitor.visit_excepthandler(excepthandler);
|
||||
}
|
||||
for stmt in orelse {
|
||||
visitor.visit_stmt(stmt);
|
||||
}
|
||||
for stmt in finalbody {
|
||||
visitor.visit_stmt(stmt);
|
||||
}
|
||||
visitor.visit_body(orelse);
|
||||
visitor.visit_body(finalbody);
|
||||
}
|
||||
StmtKind::Assert { test, msg } => {
|
||||
visitor.visit_expr(test);
|
||||
@@ -387,7 +367,7 @@ pub fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a Expr) {
|
||||
} => {
|
||||
visitor.visit_expr(value);
|
||||
if let Some(expr) = format_spec {
|
||||
visitor.visit_expr(expr);
|
||||
visitor.visit_format_spec(expr);
|
||||
}
|
||||
}
|
||||
ExprKind::JoinedStr { values } => {
|
||||
@@ -466,9 +446,7 @@ pub fn walk_excepthandler<'a, V: Visitor<'a> + ?Sized>(
|
||||
if let Some(expr) = type_ {
|
||||
visitor.visit_expr(expr);
|
||||
}
|
||||
for stmt in body {
|
||||
visitor.visit_stmt(stmt);
|
||||
}
|
||||
visitor.visit_body(body);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -519,9 +497,7 @@ pub fn walk_match_case<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, match_case:
|
||||
if let Some(expr) = &match_case.guard {
|
||||
visitor.visit_expr(expr);
|
||||
}
|
||||
for stmt in &match_case.body {
|
||||
visitor.visit_stmt(stmt);
|
||||
}
|
||||
visitor.visit_body(&match_case.body);
|
||||
}
|
||||
|
||||
pub fn walk_pattern<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, pattern: &'a Pattern) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user