Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9e704a7c63 | ||
|
|
c9da98e0b7 | ||
|
|
5377d24507 | ||
|
|
db8e4500ee | ||
|
|
bd2de5624e | ||
|
|
3a81f893cc | ||
|
|
fd6dc2a343 | ||
|
|
8693236f9e | ||
|
|
44e2b6208a | ||
|
|
16c81f75c2 | ||
|
|
e1d6ac3265 | ||
|
|
3aec1100f5 | ||
|
|
c00df647e1 | ||
|
|
f012877be1 | ||
|
|
ff6defc988 | ||
|
|
67ca50e9f2 | ||
|
|
6cc160bc2b | ||
|
|
4bdf506d80 | ||
|
|
4af2353ef9 | ||
|
|
6072edf5bf | ||
|
|
4061eeeb32 | ||
|
|
bea6deb0c3 | ||
|
|
81db00a3c4 |
19
.github/workflows/ci.yaml
vendored
19
.github/workflows/ci.yaml
vendored
@@ -70,7 +70,7 @@ jobs:
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly-2022-11-01
|
||||
toolchain: 1.65.0
|
||||
override: true
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- run: cargo install cargo-insta
|
||||
@@ -84,6 +84,21 @@ jobs:
|
||||
# Setting RUSTDOCFLAGS because `cargo doc --check` isn't yet implemented (https://github.com/rust-lang/cargo/issues/10025).
|
||||
- run: RUSTDOCFLAGS="-D warnings" cargo doc --all --no-deps
|
||||
|
||||
scripts:
|
||||
name: "test scripts"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
override: true
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- run: ./scripts/add_rule.py --name DoTheThing --code PLC999 --origin pylint
|
||||
- run: cargo check
|
||||
- run: ./scripts/add_plugin.py test --url https://pypi.org/project/-test/0.1.0/
|
||||
- run: cargo check
|
||||
|
||||
# TODO(charlie): Re-enable the `wasm-pack` tests.
|
||||
# See: https://github.com/charliermarsh/ruff/issues/1425
|
||||
# wasm-pack-test:
|
||||
@@ -122,7 +137,7 @@ jobs:
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly-2022-11-01
|
||||
toolchain: 1.65.0
|
||||
override: true
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- uses: actions/setup-python@v4
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
repos:
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
rev: v0.0.227
|
||||
rev: v0.0.228
|
||||
hooks:
|
||||
- id: ruff
|
||||
|
||||
|
||||
@@ -37,13 +37,16 @@ After cloning the repository, run Ruff locally with:
|
||||
cargo run resources/test/fixtures --no-cache
|
||||
```
|
||||
|
||||
Prior to opening a pull request, ensure that your code has been auto-formatted, and that it passes
|
||||
both the lint and test validation checks:
|
||||
Prior to opening a pull request, ensure that your code has been auto-formatted,
|
||||
and that it passes both the lint and test validation checks.
|
||||
|
||||
For rustfmt and Clippy, we use [nightly Rust][nightly], as it is stricter than stable Rust.
|
||||
(However, tests and builds use stable Rust.)
|
||||
|
||||
```shell
|
||||
cargo +nightly fmt --all # Auto-formatting...
|
||||
cargo +nightly clippy --all # Linting...
|
||||
cargo +nightly test --all # Testing...
|
||||
cargo +nightly clippy --fix --workspace --all-targets --all-features -- -W clippy::pedantic # Linting...
|
||||
cargo test --all # Testing...
|
||||
```
|
||||
|
||||
These checks will run on GitHub Actions when you open your Pull Request, but running them locally
|
||||
@@ -127,3 +130,5 @@ them to [PyPI](https://pypi.org/project/ruff/).
|
||||
|
||||
Ruff follows the [semver](https://semver.org/) versioning standard. However, as pre-1.0 software,
|
||||
even patch releases may contain [non-backwards-compatible changes](https://semver.org/#spec-item-4).
|
||||
|
||||
[nightly]: https://rust-lang.github.io/rustup/concepts/channels.html#working-with-nightly-rust
|
||||
|
||||
233
Cargo.lock
generated
233
Cargo.lock
generated
@@ -14,7 +14,7 @@ version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
|
||||
dependencies = [
|
||||
"getrandom 0.2.8",
|
||||
"getrandom",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
]
|
||||
@@ -197,12 +197,6 @@ version = "1.0.78"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
@@ -413,7 +407,7 @@ version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
@@ -439,7 +433,7 @@ version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -484,7 +478,7 @@ version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
@@ -494,7 +488,7 @@ version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
@@ -506,7 +500,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
"memoffset",
|
||||
"scopeguard",
|
||||
@@ -518,7 +512,7 @@ version = "0.8.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -592,16 +586,6 @@ dependencies = [
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10",
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "4.0.0"
|
||||
@@ -617,7 +601,7 @@ version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"dirs-sys-next",
|
||||
]
|
||||
|
||||
@@ -721,7 +705,7 @@ version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e884668cd0c7480504233e951174ddc3b382f7c2666e3b7310b5c4e7b0c37f9"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"windows-sys",
|
||||
@@ -735,7 +719,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.227"
|
||||
version = "0.0.228"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.0.32",
|
||||
@@ -786,24 +770,13 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"wasi 0.9.0+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
@@ -926,6 +899,16 @@ dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "imperative"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f92123bf2fe0d9f1b5df1964727b970ca3b2d0203d47cf97fb1f36d856b6398"
|
||||
dependencies = [
|
||||
"phf 0.11.1",
|
||||
"rust-stemmers",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.2"
|
||||
@@ -976,7 +959,7 @@ version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1186,7 +1169,7 @@ version = "0.4.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1265,7 +1248,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46a58d1d356c6597d08cde02c2f09d785b09e28711837b1ed667dc652c08a694"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"static_assertions",
|
||||
]
|
||||
@@ -1419,7 +1402,7 @@ version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
@@ -1493,15 +1476,6 @@ dependencies = [
|
||||
"indexmap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12"
|
||||
dependencies = [
|
||||
"phf_shared 0.8.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf"
|
||||
version = "0.10.1"
|
||||
@@ -1512,13 +1486,12 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_codegen"
|
||||
version = "0.8.0"
|
||||
name = "phf"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815"
|
||||
checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c"
|
||||
dependencies = [
|
||||
"phf_generator 0.8.0",
|
||||
"phf_shared 0.8.0",
|
||||
"phf_shared 0.11.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1532,13 +1505,13 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_generator"
|
||||
version = "0.8.0"
|
||||
name = "phf_codegen"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526"
|
||||
checksum = "a56ac890c5e3ca598bbdeaa99964edb5b0258a583a9eb6ef4e89fc85d9224770"
|
||||
dependencies = [
|
||||
"phf_shared 0.8.0",
|
||||
"rand 0.7.3",
|
||||
"phf_generator 0.11.1",
|
||||
"phf_shared 0.11.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1548,16 +1521,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6"
|
||||
dependencies = [
|
||||
"phf_shared 0.10.0",
|
||||
"rand 0.8.5",
|
||||
"rand",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_shared"
|
||||
version = "0.8.0"
|
||||
name = "phf_generator"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7"
|
||||
checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf"
|
||||
dependencies = [
|
||||
"siphasher",
|
||||
"phf_shared 0.11.1",
|
||||
"rand",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1569,6 +1543,15 @@ dependencies = [
|
||||
"siphasher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_shared"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676"
|
||||
dependencies = [
|
||||
"siphasher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pico-args"
|
||||
version = "0.4.2"
|
||||
@@ -1724,20 +1707,6 @@ version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
||||
dependencies = [
|
||||
"getrandom 0.1.16",
|
||||
"libc",
|
||||
"rand_chacha 0.2.2",
|
||||
"rand_core 0.5.1",
|
||||
"rand_hc",
|
||||
"rand_pcg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
@@ -1745,18 +1714,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha 0.3.1",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.5.1",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1766,16 +1725,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
|
||||
dependencies = [
|
||||
"getrandom 0.1.16",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1784,25 +1734,7 @@ version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom 0.2.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
||||
dependencies = [
|
||||
"rand_core 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_pcg"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429"
|
||||
dependencies = [
|
||||
"rand_core 0.5.1",
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1842,7 +1774,7 @@ version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
|
||||
dependencies = [
|
||||
"getrandom 0.2.8",
|
||||
"getrandom",
|
||||
"redox_syscall",
|
||||
"thiserror",
|
||||
]
|
||||
@@ -1906,23 +1838,24 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.227"
|
||||
version = "0.0.228"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags",
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"chrono",
|
||||
"clap 4.0.32",
|
||||
"colored",
|
||||
"console_error_panic_hook",
|
||||
"console_log",
|
||||
"criterion",
|
||||
"dirs 4.0.0",
|
||||
"dirs",
|
||||
"fern",
|
||||
"getrandom 0.2.8",
|
||||
"getrandom",
|
||||
"glob",
|
||||
"globset",
|
||||
"ignore",
|
||||
"imperative",
|
||||
"insta",
|
||||
"itertools",
|
||||
"js-sys",
|
||||
@@ -1960,7 +1893,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_cli"
|
||||
version = "0.0.227"
|
||||
version = "0.0.228"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.9.1",
|
||||
"anyhow",
|
||||
@@ -1997,7 +1930,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_dev"
|
||||
version = "0.0.227"
|
||||
version = "0.0.228"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.0.32",
|
||||
@@ -2018,7 +1951,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_macros"
|
||||
version = "0.0.227"
|
||||
version = "0.0.228"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
@@ -2027,6 +1960,16 @@ dependencies = [
|
||||
"textwrap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-stemmers"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e46a2036019fdb888131db7a4c847a1063a7493f971ed94ea82c67eada63ca54"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "1.1.0"
|
||||
@@ -2076,7 +2019,7 @@ source = "git+https://github.com/RustPython/RustPython.git?rev=ff90fe52eea578c8e
|
||||
dependencies = [
|
||||
"ascii",
|
||||
"bitflags",
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"hexf-parse",
|
||||
"itertools",
|
||||
"lexical-parse-float",
|
||||
@@ -2087,7 +2030,7 @@ dependencies = [
|
||||
"num-traits",
|
||||
"once_cell",
|
||||
"radium",
|
||||
"rand 0.8.5",
|
||||
"rand",
|
||||
"siphasher",
|
||||
"unic-ucd-category",
|
||||
"volatile",
|
||||
@@ -2274,7 +2217,7 @@ version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd1c7ddea665294d484c39fd0c0d2b7e35bbfe10035c5fe1854741a57f6880e1"
|
||||
dependencies = [
|
||||
"dirs 4.0.0",
|
||||
"dirs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2377,7 +2320,7 @@ version = "3.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
@@ -2417,15 +2360,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "terminfo"
|
||||
version = "0.7.3"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76971977e6121664ec1b960d1313aacfa75642adc93b9d4d53b247bd4cb1747e"
|
||||
checksum = "da31aef70da0f6352dbcb462683eb4dd2bfad01cf3fc96cf204547b9a839a585"
|
||||
dependencies = [
|
||||
"dirs 2.0.2",
|
||||
"dirs",
|
||||
"fnv",
|
||||
"nom",
|
||||
"phf 0.8.0",
|
||||
"phf_codegen 0.8.0",
|
||||
"phf 0.11.1",
|
||||
"phf_codegen 0.11.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2449,7 +2392,7 @@ version = "2.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e45b7bf6e19353ddd832745c8fcf77a17a93171df7151187f26623f2b75b5b26"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -2589,7 +2532,7 @@ version = "1.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
@@ -2793,12 +2736,6 @@ dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.9.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.0+wasi-snapshot-preview1"
|
||||
@@ -2817,7 +2754,7 @@ version = "0.2.83"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
@@ -2842,7 +2779,7 @@ version = "0.4.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
|
||||
@@ -8,7 +8,7 @@ default-members = [".", "ruff_cli"]
|
||||
|
||||
[package]
|
||||
name = "ruff"
|
||||
version = "0.0.227"
|
||||
version = "0.0.228"
|
||||
authors = ["Charlie Marsh <charlie.r.marsh@gmail.com>"]
|
||||
edition = "2021"
|
||||
rust-version = "1.65.0"
|
||||
@@ -35,6 +35,7 @@ fern = { version = "0.6.1" }
|
||||
glob = { version = "0.3.0" }
|
||||
globset = { version = "0.4.9" }
|
||||
ignore = { version = "0.4.18" }
|
||||
imperative = { version = "1.0.3" }
|
||||
itertools = { version = "0.10.5" }
|
||||
libcst = { git = "https://github.com/charliermarsh/LibCST", rev = "f2f0b7a487a8725d161fe8b3ed73a6758b21e177" }
|
||||
log = { version = "0.4.17" }
|
||||
@@ -46,7 +47,7 @@ once_cell = { version = "1.16.0" }
|
||||
path-absolutize = { version = "3.0.14", features = ["once_cell_cache", "use_unix_paths_on_wasm"] }
|
||||
regex = { version = "1.6.0" }
|
||||
ropey = { version = "1.5.0", features = ["cr_lines", "simd"], default-features = false }
|
||||
ruff_macros = { version = "0.0.227", path = "ruff_macros" }
|
||||
ruff_macros = { version = "0.0.228", path = "ruff_macros" }
|
||||
rustc-hash = { version = "1.1.0" }
|
||||
rustpython-ast = { features = ["unparse"], git = "https://github.com/RustPython/RustPython.git", rev = "ff90fe52eea578c8ebdd9d95e078cc041a5959fa" }
|
||||
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "ff90fe52eea578c8ebdd9d95e078cc041a5959fa" }
|
||||
@@ -59,9 +60,9 @@ smallvec = { version = "1.10.0" }
|
||||
strum = { version = "0.24.1", features = ["strum_macros"] }
|
||||
strum_macros = { version = "0.24.3" }
|
||||
textwrap = { version = "0.16.0" }
|
||||
thiserror = { version = "1.0" }
|
||||
titlecase = { version = "2.2.1" }
|
||||
toml_edit = { version = "0.17.1", features = ["easy"] }
|
||||
thiserror = { version = "1.0" }
|
||||
|
||||
# https://docs.rs/getrandom/0.2.7/getrandom/#webassembly-support
|
||||
# For (future) wasm-pack support
|
||||
|
||||
34
README.md
34
README.md
@@ -141,12 +141,11 @@ developer of [Zulip](https://github.com/zulip/zulip):
|
||||
1. [Ruff-specific rules (RUF)](#ruff-specific-rules-ruf)<!-- End auto-generated table of contents. -->
|
||||
1. [Editor Integrations](#editor-integrations)
|
||||
1. [FAQ](#faq)
|
||||
1. [Development](#development)
|
||||
1. [Contributing](#contributing)
|
||||
1. [Releases](#releases)
|
||||
1. [Benchmarks](#benchmarks)
|
||||
1. [Reference](#reference)
|
||||
1. [License](#license)
|
||||
1. [Contributing](#contributing)
|
||||
|
||||
## Installation and Usage
|
||||
|
||||
@@ -199,7 +198,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.227'
|
||||
rev: 'v0.0.228'
|
||||
hooks:
|
||||
- id: ruff
|
||||
# Respect `exclude` and `extend-exclude` settings.
|
||||
@@ -672,6 +671,7 @@ For more, see [pydocstyle](https://pypi.org/project/pydocstyle/6.1.1/) on PyPI.
|
||||
| D300 | uses-triple-quotes | Use """triple double quotes""" | |
|
||||
| D301 | uses-r-prefix-for-backslashed-content | Use r""" if any backslashes in a docstring | |
|
||||
| D400 | ends-in-period | First line should end with a period | 🛠 |
|
||||
| D401 | non-imperative-mood | First line of docstring should be in imperative mood: "{first_line}" | |
|
||||
| D402 | no-signature | First line should not be the function's signature | |
|
||||
| D403 | first-line-capitalized | First word of the first line should be properly capitalized | |
|
||||
| D404 | no-this-prefix | First word of the docstring should not be "This" | |
|
||||
@@ -728,6 +728,7 @@ For more, see [pyupgrade](https://pypi.org/project/pyupgrade/3.2.0/) on PyPI.
|
||||
| UP030 | format-literals | Use implicit references for positional format fields | 🛠 |
|
||||
| UP032 | f-string | Use f-string instead of `format` call | 🛠 |
|
||||
| UP033 | functools-cache | Use `@functools.cache` instead of `@functools.lru_cache(maxsize=None)` | 🛠 |
|
||||
| UP034 | extraneous-parentheses | Avoid extraneous parentheses | 🛠 |
|
||||
|
||||
### pep8-naming (N)
|
||||
|
||||
@@ -1062,7 +1063,7 @@ For more, see [flake8-datetimez](https://pypi.org/project/flake8-datetimez/20.10
|
||||
| DTZ004 | call-datetime-utcfromtimestamp | The use of `datetime.datetime.utcfromtimestamp()` is not allowed | |
|
||||
| DTZ005 | call-datetime-now-without-tzinfo | The use of `datetime.datetime.now()` without `tz` argument is not allowed | |
|
||||
| DTZ006 | call-datetime-fromtimestamp | The use of `datetime.datetime.fromtimestamp()` without `tz` argument is not allowed | |
|
||||
| DTZ007 | call-datetime-strptime-without-zone | The use of `datetime.datetime.strptime()` without %z must be followed by `.replace(tzinfo=)` | |
|
||||
| DTZ007 | call-datetime-strptime-without-zone | The use of `datetime.datetime.strptime()` without %z must be followed by `.replace(tzinfo=)` or `.astimezone()` | |
|
||||
| DTZ011 | call-date-today | The use of `datetime.date.today()` is not allowed. | |
|
||||
| DTZ012 | call-date-fromtimestamp | The use of `datetime.date.fromtimestamp()` is not allowed | |
|
||||
|
||||
@@ -1639,24 +1640,10 @@ matter how they're provided, which avoids accidental incompatibilities and simpl
|
||||
|
||||
Run `ruff /path/to/code.py --show-settings` to view the resolved settings for a given file.
|
||||
|
||||
## Development
|
||||
## Contributing
|
||||
|
||||
Ruff is written in Rust (1.65.0). You'll need to install the [Rust toolchain](https://www.rust-lang.org/tools/install)
|
||||
for development.
|
||||
|
||||
Assuming you have `cargo` installed, you can run:
|
||||
|
||||
```shell
|
||||
cargo run resources/test/fixtures
|
||||
```
|
||||
|
||||
For development, we use [nightly Rust](https://rust-lang.github.io/rustup/concepts/channels.html#working-with-nightly-rust):
|
||||
|
||||
```shell
|
||||
cargo +nightly fmt
|
||||
cargo +nightly clippy --fix --workspace --all-targets --all-features -- -W clippy::pedantic
|
||||
cargo +nightly test --all
|
||||
```
|
||||
Contributions are welcome and hugely appreciated. To get started, check out the
|
||||
[contributing guidelines](https://github.com/charliermarsh/ruff/blob/main/CONTRIBUTING.md).
|
||||
|
||||
## Releases
|
||||
|
||||
@@ -3456,8 +3443,3 @@ keep-runtime-typing = true
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome and hugely appreciated. To get started, check out the
|
||||
[contributing guidelines](https://github.com/charliermarsh/ruff/blob/main/CONTRIBUTING.md).
|
||||
|
||||
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.227"
|
||||
version = "0.0.228"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@@ -1975,7 +1975,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.227"
|
||||
version = "0.0.228"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.227"
|
||||
version = "0.0.228"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -7,7 +7,7 @@ build-backend = "maturin"
|
||||
|
||||
[project]
|
||||
name = "ruff"
|
||||
version = "0.0.227"
|
||||
version = "0.0.228"
|
||||
description = "An extremely fast Python linter, written in Rust."
|
||||
authors = [
|
||||
{ name = "Charlie Marsh", email = "charlie.r.marsh@gmail.com" },
|
||||
|
||||
@@ -383,7 +383,7 @@ s = (
|
||||
|
||||
s2 = (
|
||||
'this'
|
||||
'is a also a string'
|
||||
'is also a string'
|
||||
)
|
||||
|
||||
t = (
|
||||
|
||||
@@ -42,3 +42,11 @@ def f():
|
||||
return "foo"
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def f():
|
||||
# SIM103 (but not fixable)
|
||||
if a:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
28
resources/test/fixtures/pydocstyle/D.py
vendored
28
resources/test/fixtures/pydocstyle/D.py
vendored
@@ -606,3 +606,31 @@ def one_liner():
|
||||
r"""Wrong.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
@expect('D200: One-line docstring should fit on one line with quotes '
|
||||
'(found 3)')
|
||||
@expect('D212: Multi-line docstring summary should start at the first line')
|
||||
def one_liner():
|
||||
"""Wrong."
|
||||
|
||||
"""
|
||||
|
||||
|
||||
@expect('D200: One-line docstring should fit on one line with quotes '
|
||||
'(found 3)')
|
||||
@expect('D212: Multi-line docstring summary should start at the first line')
|
||||
def one_liner():
|
||||
"""
|
||||
|
||||
"Wrong."""
|
||||
|
||||
|
||||
@expect('D404: First word of the docstring should not be "This"')
|
||||
def starts_with_this():
|
||||
"""This is a docstring."""
|
||||
|
||||
|
||||
@expect('D404: First word of the docstring should not be "This"')
|
||||
def starts_with_space_then_this():
|
||||
""" This is a docstring that starts with a space.""" # noqa: D210
|
||||
|
||||
43
resources/test/fixtures/pydocstyle/D401.py
vendored
Normal file
43
resources/test/fixtures/pydocstyle/D401.py
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
# Bad examples
|
||||
|
||||
def bad_liouiwnlkjl():
|
||||
"""Returns foo."""
|
||||
|
||||
|
||||
def bad_sdgfsdg23245():
|
||||
"""Constructor for a foo."""
|
||||
|
||||
|
||||
def bad_sdgfsdg23245777():
|
||||
"""
|
||||
|
||||
Constructor for a boa.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def bad_run_something():
|
||||
"""Runs something"""
|
||||
pass
|
||||
|
||||
|
||||
def multi_line():
|
||||
"""Writes a logical line that
|
||||
extends to two physical lines.
|
||||
"""
|
||||
|
||||
|
||||
# Good examples
|
||||
|
||||
def good_run_something():
|
||||
"""Run away."""
|
||||
|
||||
|
||||
def good_construct():
|
||||
"""Construct a beautiful house."""
|
||||
|
||||
|
||||
def good_multi_line():
|
||||
"""Write a logical line that
|
||||
extends to two physical lines.
|
||||
"""
|
||||
61
resources/test/fixtures/pyupgrade/UP034.py
vendored
Normal file
61
resources/test/fixtures/pyupgrade/UP034.py
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
# UP034
|
||||
print(("foo"))
|
||||
|
||||
# UP034
|
||||
print(("hell((goodybe))o"))
|
||||
|
||||
# UP034
|
||||
print((("foo")))
|
||||
|
||||
# UP034
|
||||
print((((1))))
|
||||
|
||||
# UP034
|
||||
print(("foo{}".format(1)))
|
||||
|
||||
# UP034
|
||||
print(
|
||||
("foo{}".format(1))
|
||||
)
|
||||
|
||||
# UP034
|
||||
print(
|
||||
(
|
||||
"foo"
|
||||
)
|
||||
)
|
||||
|
||||
# UP034
|
||||
def f():
|
||||
x = int(((yield 1)))
|
||||
|
||||
# UP034
|
||||
if True:
|
||||
print(
|
||||
("foo{}".format(1))
|
||||
)
|
||||
|
||||
# UP034
|
||||
print((x for x in range(3)))
|
||||
|
||||
# OK
|
||||
print("foo")
|
||||
|
||||
# OK
|
||||
print((1, 2, 3))
|
||||
|
||||
# OK
|
||||
print(())
|
||||
|
||||
# OK
|
||||
print((1,))
|
||||
|
||||
# OK
|
||||
sum((block.code for block in blocks), [])
|
||||
|
||||
# OK
|
||||
def f():
|
||||
x = int((yield 1))
|
||||
|
||||
# OK
|
||||
sum((i for i in range(3)), [])
|
||||
@@ -1277,6 +1277,7 @@
|
||||
"D4",
|
||||
"D40",
|
||||
"D400",
|
||||
"D401",
|
||||
"D402",
|
||||
"D403",
|
||||
"D404",
|
||||
@@ -1768,6 +1769,7 @@
|
||||
"UP030",
|
||||
"UP032",
|
||||
"UP033",
|
||||
"UP034",
|
||||
"W",
|
||||
"W2",
|
||||
"W29",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff_cli"
|
||||
version = "0.0.227"
|
||||
version = "0.0.228"
|
||||
authors = ["Charlie Marsh <charlie.r.marsh@gmail.com>"]
|
||||
edition = "2021"
|
||||
rust-version = "1.65.0"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff_dev"
|
||||
version = "0.0.227"
|
||||
version = "0.0.228"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff_macros"
|
||||
version = "0.0.227"
|
||||
version = "0.0.228"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
|
||||
18
scripts/_utils.py
Normal file
18
scripts/_utils.py
Normal file
@@ -0,0 +1,18 @@
|
||||
import os
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
ROOT_DIR = Path(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
|
||||
def dir_name(origin: str) -> str:
|
||||
return origin.replace("-", "_")
|
||||
|
||||
|
||||
def pascal_case(origin: str) -> str:
|
||||
"""Convert from snake-case to PascalCase."""
|
||||
return "".join(word.title() for word in origin.split("-"))
|
||||
|
||||
|
||||
def get_indent(line: str) -> str:
|
||||
return re.match(r"^\s*", line).group() # pyright: ignore[reportOptionalMemberAccess]
|
||||
36
scripts/add_plugin.py
Normal file → Executable file
36
scripts/add_plugin.py
Normal file → Executable file
@@ -10,17 +10,8 @@ Example usage:
|
||||
|
||||
import argparse
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
ROOT_DIR = Path(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("-"))
|
||||
from _utils import ROOT_DIR, dir_name, get_indent, pascal_case
|
||||
|
||||
|
||||
def main(*, plugin: str, url: str) -> None:
|
||||
@@ -36,6 +27,7 @@ def main(*, plugin: str, url: str) -> None:
|
||||
with open(rust_module / "rules.rs", "w+") as fp:
|
||||
fp.write("use crate::checkers::ast::Checker;\n")
|
||||
with open(rust_module / "mod.rs", "w+") as fp:
|
||||
fp.write(f"//! Rules from [{plugin}]({url}).\n")
|
||||
fp.write("pub(crate) mod rules;\n")
|
||||
fp.write("\n")
|
||||
fp.write(
|
||||
@@ -76,35 +68,23 @@ mod tests {
|
||||
|
||||
with open(ROOT_DIR / "src/registry.rs", "w") as fp:
|
||||
for line in content.splitlines():
|
||||
indent = get_indent(line)
|
||||
|
||||
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() == 'RuleOrigin::Ruff => "Ruff-specific rules",':
|
||||
indent = line.split('RuleOrigin::Ruff => "Ruff-specific rules",')[0]
|
||||
fp.write(f'{indent}RuleOrigin::{pascal_case(plugin)} => "{plugin}",')
|
||||
fp.write("\n")
|
||||
|
||||
elif line.strip() == "RuleOrigin::Ruff => vec![RuleCodePrefix::RUF],":
|
||||
indent = line.split("RuleOrigin::Ruff => vec![RuleCodePrefix::RUF],")[0]
|
||||
elif line.strip() == "RuleOrigin::Ruff => Prefixes::Single(RuleCodePrefix::RUF),":
|
||||
prefix = 'todo!("Fill-in prefix after generating codes")'
|
||||
fp.write(
|
||||
f"{indent}RuleOrigin::{pascal_case(plugin)} => vec![\n"
|
||||
f'{indent} todo!("Fill-in prefix after generating codes")\n'
|
||||
f"{indent}],"
|
||||
f"{indent}RuleOrigin::{pascal_case(plugin)} => Prefixes::Single({prefix}),"
|
||||
)
|
||||
fp.write("\n")
|
||||
|
||||
elif line.strip() == "RuleOrigin::Ruff => None,":
|
||||
indent = line.split("RuleOrigin::Ruff => None,")[0]
|
||||
fp.write(f"{indent}RuleOrigin::{pascal_case(plugin)} => " f'Some(("{url}", &Platform::PyPI)),')
|
||||
fp.write("\n")
|
||||
|
||||
fp.write(line)
|
||||
fp.write("\n")
|
||||
|
||||
@@ -114,7 +94,7 @@ mod tests {
|
||||
with open(ROOT_DIR / "src/violations.rs", "w") as fp:
|
||||
for line in content.splitlines():
|
||||
if line.strip() == "// Ruff":
|
||||
indent = line.split("// Ruff")[0]
|
||||
indent = get_indent(line)
|
||||
fp.write(f"{indent}// {plugin}")
|
||||
fp.write("\n")
|
||||
|
||||
|
||||
33
scripts/add_rule.py
Normal file → Executable file
33
scripts/add_rule.py
Normal file → Executable file
@@ -10,19 +10,8 @@ Example usage:
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
ROOT_DIR = Path(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
|
||||
def dir_name(origin: str) -> str:
|
||||
return origin.replace("-", "_")
|
||||
|
||||
|
||||
def pascal_case(origin: str) -> str:
|
||||
"""Convert from snake-case to PascalCase."""
|
||||
return "".join(word.title() for word in origin.split("-"))
|
||||
from _utils import ROOT_DIR, dir_name, get_indent
|
||||
|
||||
|
||||
def snake_case(name: str) -> str:
|
||||
@@ -45,7 +34,7 @@ def main(*, name: str, code: str, origin: str) -> None:
|
||||
with open(mod_rs, "w") as fp:
|
||||
for line in content.splitlines():
|
||||
if line.strip() == "fn rules(rule_code: Rule, path: &Path) -> Result<()> {":
|
||||
indent = line.split("fn rules(rule_code: Rule, path: &Path) -> Result<()> {")[0]
|
||||
indent = get_indent(line)
|
||||
fp.write(f'{indent}#[test_case(Rule::{code}, Path::new("{code}.py"); "{code}")]')
|
||||
fp.write("\n")
|
||||
|
||||
@@ -53,7 +42,7 @@ def main(*, name: str, code: str, origin: str) -> None:
|
||||
fp.write("\n")
|
||||
|
||||
# Add the relevant rule function.
|
||||
with open(ROOT_DIR / "src/rules" / dir_name(origin) / "rules.rs", "a") as fp:
|
||||
with open(ROOT_DIR / "src/rules" / dir_name(origin) / (snake_case(name) + ".rs"), "w") as fp:
|
||||
fp.write(
|
||||
f"""
|
||||
/// {code}
|
||||
@@ -76,16 +65,14 @@ pub fn {snake_case(name)}(checker: &mut Checker) {{}}
|
||||
pub struct %s;
|
||||
);
|
||||
impl Violation for %s {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
todo!("Implement message")
|
||||
}
|
||||
|
||||
fn placeholder() -> Self {
|
||||
%s
|
||||
todo!("implement message");
|
||||
format!("TODO: write message")
|
||||
}
|
||||
}
|
||||
"""
|
||||
% (name, name, name)
|
||||
% (name, name)
|
||||
)
|
||||
fp.write("\n")
|
||||
|
||||
@@ -102,7 +89,7 @@ impl Violation for %s {
|
||||
if has_written:
|
||||
continue
|
||||
|
||||
if line.startswith("define_rule_mapping!"):
|
||||
if line.startswith("ruff_macros::define_rule_mapping!"):
|
||||
seen_macro = True
|
||||
continue
|
||||
|
||||
@@ -110,11 +97,13 @@ impl Violation for %s {
|
||||
continue
|
||||
|
||||
if line.strip() == f"// {origin}":
|
||||
indent = line.split("//")[0]
|
||||
indent = get_indent(line)
|
||||
fp.write(f"{indent}{code} => violations::{name},")
|
||||
fp.write("\n")
|
||||
has_written = True
|
||||
|
||||
assert has_written
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(
|
||||
|
||||
9
scripts/pyproject.toml
Normal file
9
scripts/pyproject.toml
Normal file
@@ -0,0 +1,9 @@
|
||||
[tool.ruff]
|
||||
select = ["ALL"]
|
||||
ignore = [
|
||||
"S101", # assert-used
|
||||
"PLR2004", # magic-value-comparison
|
||||
]
|
||||
|
||||
[tool.ruff.pydocstyle]
|
||||
convention = "pep257"
|
||||
@@ -4497,6 +4497,7 @@ impl<'a> Checker<'a> {
|
||||
.rules
|
||||
.enabled(&Rule::UsesRPrefixForBackslashedContent)
|
||||
|| self.settings.rules.enabled(&Rule::EndsInPeriod)
|
||||
|| self.settings.rules.enabled(&Rule::NonImperativeMood)
|
||||
|| self.settings.rules.enabled(&Rule::NoSignature)
|
||||
|| self.settings.rules.enabled(&Rule::FirstLineCapitalized)
|
||||
|| self.settings.rules.enabled(&Rule::NoThisPrefix)
|
||||
@@ -4645,6 +4646,9 @@ impl<'a> Checker<'a> {
|
||||
if self.settings.rules.enabled(&Rule::EndsInPeriod) {
|
||||
pydocstyle::rules::ends_with_period(self, &docstring);
|
||||
}
|
||||
if self.settings.rules.enabled(&Rule::NonImperativeMood) {
|
||||
pydocstyle::rules::non_imperative_mood::non_imperative_mood(self, &docstring);
|
||||
}
|
||||
if self.settings.rules.enabled(&Rule::NoSignature) {
|
||||
pydocstyle::rules::no_signature(self, &docstring);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,8 @@ use crate::lex::docstring_detection::StateMachine;
|
||||
use crate::registry::{Diagnostic, Rule};
|
||||
use crate::rules::ruff::rules::Context;
|
||||
use crate::rules::{
|
||||
eradicate, flake8_commas, flake8_implicit_str_concat, flake8_quotes, pycodestyle, ruff,
|
||||
eradicate, flake8_commas, flake8_implicit_str_concat, flake8_quotes, pycodestyle, pyupgrade,
|
||||
ruff,
|
||||
};
|
||||
use crate::settings::{flags, Settings};
|
||||
use crate::source_code::Locator;
|
||||
@@ -45,6 +46,7 @@ pub fn check_tokens(
|
||||
.rules
|
||||
.enabled(&Rule::TrailingCommaOnBareTupleProhibited)
|
||||
|| settings.rules.enabled(&Rule::TrailingCommaProhibited);
|
||||
let enforce_extraneous_parenthesis = settings.rules.enabled(&Rule::ExtraneousParentheses);
|
||||
|
||||
let mut state_machine = StateMachine::default();
|
||||
for &(start, ref tok, end) in tokens.iter().flatten() {
|
||||
@@ -137,5 +139,13 @@ pub fn check_tokens(
|
||||
);
|
||||
}
|
||||
|
||||
// UP034
|
||||
if enforce_extraneous_parenthesis {
|
||||
diagnostics.extend(
|
||||
pyupgrade::rules::extraneous_parentheses(tokens, locator, settings, autofix)
|
||||
.into_iter(),
|
||||
);
|
||||
}
|
||||
|
||||
diagnostics
|
||||
}
|
||||
|
||||
@@ -251,7 +251,8 @@ ruff_macros::define_rule_mapping!(
|
||||
UP029 => violations::UnnecessaryBuiltinImport,
|
||||
UP030 => violations::FormatLiterals,
|
||||
UP032 => violations::FString,
|
||||
UP033 => violations::FunctoolsCache,
|
||||
UP033 => violations::FunctoolsCache,
|
||||
UP034 => violations::ExtraneousParentheses,
|
||||
// pydocstyle
|
||||
D100 => violations::PublicModule,
|
||||
D101 => violations::PublicClass,
|
||||
@@ -280,6 +281,7 @@ ruff_macros::define_rule_mapping!(
|
||||
D300 => violations::UsesTripleQuotes,
|
||||
D301 => violations::UsesRPrefixForBackslashedContent,
|
||||
D400 => violations::EndsInPeriod,
|
||||
D401 => crate::rules::pydocstyle::rules::non_imperative_mood::NonImperativeMood,
|
||||
D402 => violations::NoSignature,
|
||||
D403 => violations::FirstLineCapitalized,
|
||||
D404 => violations::NoThisPrefix,
|
||||
@@ -555,20 +557,21 @@ impl Rule {
|
||||
| Rule::PEP3120UnnecessaryCodingComment
|
||||
| Rule::BlanketTypeIgnore
|
||||
| Rule::BlanketNOQA => &LintSource::Lines,
|
||||
Rule::CommentedOutCode
|
||||
| Rule::SingleLineImplicitStringConcatenation
|
||||
| Rule::MultiLineImplicitStringConcatenation
|
||||
Rule::AmbiguousUnicodeCharacterComment
|
||||
| Rule::AmbiguousUnicodeCharacterDocstring
|
||||
| Rule::AmbiguousUnicodeCharacterString
|
||||
| Rule::AvoidQuoteEscape
|
||||
| Rule::BadQuotesDocstring
|
||||
| Rule::BadQuotesInlineString
|
||||
| Rule::BadQuotesMultilineString
|
||||
| Rule::BadQuotesDocstring
|
||||
| Rule::AvoidQuoteEscape
|
||||
| Rule::CommentedOutCode
|
||||
| Rule::ExtraneousParentheses
|
||||
| Rule::InvalidEscapeSequence
|
||||
| Rule::MultiLineImplicitStringConcatenation
|
||||
| Rule::SingleLineImplicitStringConcatenation
|
||||
| Rule::TrailingCommaMissing
|
||||
| Rule::TrailingCommaOnBareTupleProhibited
|
||||
| Rule::TrailingCommaProhibited
|
||||
| Rule::AmbiguousUnicodeCharacterString
|
||||
| Rule::AmbiguousUnicodeCharacterDocstring
|
||||
| Rule::AmbiguousUnicodeCharacterComment => &LintSource::Tokens,
|
||||
| Rule::TrailingCommaProhibited => &LintSource::Tokens,
|
||||
Rule::IOError => &LintSource::Io,
|
||||
Rule::UnsortedImports | Rule::MissingRequiredImport => &LintSource::Imports,
|
||||
Rule::ImplicitNamespacePackage => &LintSource::Filesystem,
|
||||
|
||||
@@ -75,7 +75,7 @@ pub fn nested_if_statements(checker: &mut Checker, stmt: &Stmt) {
|
||||
Range::new(stmt.location, nested_if.location),
|
||||
checker.locator,
|
||||
) {
|
||||
match fix_if::fix_nested_if_statements(checker.locator, stmt) {
|
||||
match fix_if::fix_nested_if_statements(checker.locator, checker.stylist, stmt) {
|
||||
Ok(fix) => {
|
||||
if fix
|
||||
.content
|
||||
@@ -92,17 +92,35 @@ pub fn nested_if_statements(checker: &mut Checker, stmt: &Stmt) {
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
|
||||
fn is_one_line_return_bool(stmts: &[Stmt]) -> bool {
|
||||
enum Bool {
|
||||
True,
|
||||
False,
|
||||
}
|
||||
|
||||
impl From<bool> for Bool {
|
||||
fn from(value: bool) -> Self {
|
||||
if value {
|
||||
Bool::True
|
||||
} else {
|
||||
Bool::False
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_one_line_return_bool(stmts: &[Stmt]) -> Option<Bool> {
|
||||
if stmts.len() != 1 {
|
||||
return false;
|
||||
return None;
|
||||
}
|
||||
let StmtKind::Return { value } = &stmts[0].node else {
|
||||
return false;
|
||||
return None;
|
||||
};
|
||||
let Some(ExprKind::Constant { value, .. }) = value.as_ref().map(|value| &value.node) else {
|
||||
return false;
|
||||
return None;
|
||||
};
|
||||
matches!(value, Constant::Bool(_))
|
||||
let Constant::Bool(value) = value else {
|
||||
return None;
|
||||
};
|
||||
Some((*value).into())
|
||||
}
|
||||
|
||||
/// SIM103
|
||||
@@ -110,17 +128,18 @@ pub fn return_bool_condition_directly(checker: &mut Checker, stmt: &Stmt) {
|
||||
let StmtKind::If { test, body, orelse } = &stmt.node else {
|
||||
return;
|
||||
};
|
||||
if !(is_one_line_return_bool(body) && is_one_line_return_bool(orelse)) {
|
||||
let (Some(if_return), Some(else_return)) = (is_one_line_return_bool(body), is_one_line_return_bool(orelse)) else {
|
||||
return;
|
||||
}
|
||||
};
|
||||
let condition = unparse_expr(test, checker.stylist);
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
violations::ReturnBoolConditionDirectly(condition),
|
||||
Range::from_located(stmt),
|
||||
);
|
||||
if checker.patch(&Rule::ReturnBoolConditionDirectly)
|
||||
&& !(has_comments_in(Range::from_located(stmt), checker.locator)
|
||||
|| has_comments_in(Range::from_located(&orelse[0]), checker.locator))
|
||||
&& matches!(if_return, Bool::True)
|
||||
&& matches!(else_return, Bool::False)
|
||||
&& !has_comments_in(Range::from_located(stmt), checker.locator)
|
||||
{
|
||||
let return_stmt = create_stmt(StmtKind::Return {
|
||||
value: Some(test.clone()),
|
||||
|
||||
@@ -12,7 +12,7 @@ use crate::ast::types::Range;
|
||||
use crate::ast::whitespace;
|
||||
use crate::cst::matchers::match_module;
|
||||
use crate::fix::Fix;
|
||||
use crate::source_code::Locator;
|
||||
use crate::source_code::{Locator, Stylist};
|
||||
|
||||
fn parenthesize_and_operand(expr: Expression) -> Expression {
|
||||
match &expr {
|
||||
@@ -32,6 +32,7 @@ fn parenthesize_and_operand(expr: Expression) -> Expression {
|
||||
/// (SIM102) Convert `if a: if b:` to `if a and b:`.
|
||||
pub(crate) fn fix_nested_if_statements(
|
||||
locator: &Locator,
|
||||
stylist: &Stylist,
|
||||
stmt: &rustpython_ast::Stmt,
|
||||
) -> Result<Fix> {
|
||||
// Infer the indentation of the outer block.
|
||||
@@ -62,7 +63,10 @@ pub(crate) fn fix_nested_if_statements(
|
||||
let module_text = if outer_indent.is_empty() {
|
||||
module_text
|
||||
} else {
|
||||
Cow::Owned(format!("def f():\n{module_text}"))
|
||||
Cow::Owned(format!(
|
||||
"def f():{}{module_text}",
|
||||
stylist.line_ending().as_str()
|
||||
))
|
||||
};
|
||||
|
||||
// Parse the CST.
|
||||
@@ -113,7 +117,10 @@ pub(crate) fn fix_nested_if_statements(
|
||||
}));
|
||||
outer_if.body = inner_if.body.clone();
|
||||
|
||||
let mut state = CodegenState::default();
|
||||
let mut state = CodegenState {
|
||||
default_newline: stylist.line_ending(),
|
||||
..Default::default()
|
||||
};
|
||||
tree.codegen(&mut state);
|
||||
|
||||
// Reconstruct and reformat the code.
|
||||
@@ -121,7 +128,9 @@ pub(crate) fn fix_nested_if_statements(
|
||||
let module_text = if outer_indent.is_empty() {
|
||||
&module_text
|
||||
} else {
|
||||
module_text.strip_prefix("def f():\n").unwrap()
|
||||
module_text
|
||||
.strip_prefix(&format!("def f():{}", stylist.line_ending().as_str()))
|
||||
.unwrap()
|
||||
};
|
||||
let contents = if is_elif {
|
||||
module_text.replacen("if", "elif", 1)
|
||||
|
||||
@@ -53,4 +53,14 @@ expression: diagnostics
|
||||
row: 27
|
||||
column: 24
|
||||
parent: ~
|
||||
- kind:
|
||||
ReturnBoolConditionDirectly: a
|
||||
location:
|
||||
row: 49
|
||||
column: 4
|
||||
end_location:
|
||||
row: 52
|
||||
column: 19
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
|
||||
@@ -55,3 +55,11 @@ pub fn logical_line(content: &str) -> Option<usize> {
|
||||
}
|
||||
logical_line
|
||||
}
|
||||
|
||||
/// Normalize a word by removing all non-alphanumeric characters
|
||||
/// and converting it to lowercase.
|
||||
pub fn normalize_word(first_word: &str) -> String {
|
||||
first_word
|
||||
.replace(|c: char| !c.is_alphanumeric(), "")
|
||||
.to_lowercase()
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ mod tests {
|
||||
#[test_case(Rule::UsesRPrefixForBackslashedContent, Path::new("D.py"); "D301")]
|
||||
#[test_case(Rule::EndsInPeriod, Path::new("D.py"); "D400_0")]
|
||||
#[test_case(Rule::EndsInPeriod, Path::new("D400.py"); "D400_1")]
|
||||
#[test_case(Rule::NonImperativeMood, Path::new("D401.py"); "D401")]
|
||||
#[test_case(Rule::NoSignature, Path::new("D.py"); "D402")]
|
||||
#[test_case(Rule::FirstLineCapitalized, Path::new("D.py"); "D403")]
|
||||
#[test_case(Rule::NoThisPrefix, Path::new("D.py"); "D404")]
|
||||
|
||||
@@ -31,6 +31,7 @@ mod multi_line_summary_start;
|
||||
mod newline_after_last_paragraph;
|
||||
mod no_signature;
|
||||
mod no_surrounding_whitespace;
|
||||
pub mod non_imperative_mood;
|
||||
mod not_empty;
|
||||
mod not_missing;
|
||||
mod one_liner;
|
||||
|
||||
@@ -30,22 +30,22 @@ pub fn no_surrounding_whitespace(checker: &mut Checker, docstring: &Docstring) {
|
||||
);
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
if let Some(pattern) = leading_quote(contents) {
|
||||
if let Some(quote) = pattern.chars().last() {
|
||||
// If removing whitespace would lead to an invalid string of quote
|
||||
// characters, avoid applying the fix.
|
||||
if !trimmed.ends_with(quote) {
|
||||
diagnostic.amend(Fix::replacement(
|
||||
trimmed.to_string(),
|
||||
Location::new(
|
||||
docstring.expr.location.row(),
|
||||
docstring.expr.location.column() + pattern.len(),
|
||||
),
|
||||
Location::new(
|
||||
docstring.expr.location.row(),
|
||||
docstring.expr.location.column() + pattern.len() + line.chars().count(),
|
||||
),
|
||||
));
|
||||
}
|
||||
// If removing whitespace would lead to an invalid string of quote
|
||||
// characters, avoid applying the fix.
|
||||
if !trimmed.ends_with(pattern.chars().last().unwrap())
|
||||
&& !trimmed.starts_with(pattern.chars().last().unwrap())
|
||||
{
|
||||
diagnostic.amend(Fix::replacement(
|
||||
trimmed.to_string(),
|
||||
Location::new(
|
||||
docstring.expr.location.row(),
|
||||
docstring.expr.location.column() + pattern.len(),
|
||||
),
|
||||
Location::new(
|
||||
docstring.expr.location.row(),
|
||||
docstring.expr.location.column() + pattern.len() + line.chars().count(),
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
50
src/rules/pydocstyle/rules/non_imperative_mood.rs
Normal file
50
src/rules/pydocstyle/rules/non_imperative_mood.rs
Normal file
@@ -0,0 +1,50 @@
|
||||
use imperative::Mood;
|
||||
use once_cell::sync::Lazy;
|
||||
use ruff_macros::derive_message_formats;
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::define_violation;
|
||||
use crate::docstrings::definition::Docstring;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::rules::pydocstyle::helpers::normalize_word;
|
||||
use crate::violation::Violation;
|
||||
|
||||
static MOOD: Lazy<Mood> = Lazy::new(Mood::new);
|
||||
|
||||
/// D401
|
||||
pub fn non_imperative_mood(checker: &mut Checker, docstring: &Docstring) {
|
||||
let body = docstring.body;
|
||||
|
||||
// Find first line, disregarding whitespace.
|
||||
let line = match body.trim().lines().next() {
|
||||
Some(line) => line.trim(),
|
||||
None => return,
|
||||
};
|
||||
// Find the first word on that line and normalize it to lower-case.
|
||||
let first_word_norm = match line.split_whitespace().next() {
|
||||
Some(word) => normalize_word(word),
|
||||
None => return,
|
||||
};
|
||||
if first_word_norm.is_empty() {
|
||||
return;
|
||||
}
|
||||
if let Some(false) = MOOD.is_imperative(&first_word_norm) {
|
||||
let diagnostic = Diagnostic::new(
|
||||
NonImperativeMood(line.to_string()),
|
||||
Range::from_located(docstring.expr),
|
||||
);
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct NonImperativeMood(pub String);
|
||||
);
|
||||
impl Violation for NonImperativeMood {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let NonImperativeMood(first_line) = self;
|
||||
format!("First line of docstring should be in imperative mood: \"{first_line}\"")
|
||||
}
|
||||
}
|
||||
@@ -31,11 +31,18 @@ pub fn one_liner(checker: &mut Checker, docstring: &Docstring) {
|
||||
helpers::leading_quote(docstring.contents),
|
||||
helpers::trailing_quote(docstring.contents),
|
||||
) {
|
||||
diagnostic.amend(Fix::replacement(
|
||||
format!("{leading}{}{trailing}", docstring.body.trim()),
|
||||
docstring.expr.location,
|
||||
docstring.expr.end_location.unwrap(),
|
||||
));
|
||||
// If removing whitespace would lead to an invalid string of quote
|
||||
// characters, avoid applying the fix.
|
||||
let trimmed = docstring.body.trim();
|
||||
if !trimmed.ends_with(trailing.chars().last().unwrap())
|
||||
&& !trimmed.starts_with(leading.chars().last().unwrap())
|
||||
{
|
||||
diagnostic.amend(Fix::replacement(
|
||||
format!("{leading}{trimmed}{trailing}"),
|
||||
docstring.expr.location,
|
||||
docstring.expr.end_location.unwrap(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
|
||||
@@ -2,6 +2,7 @@ use crate::ast::types::Range;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::docstrings::definition::Docstring;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::rules::pydocstyle::helpers::normalize_word;
|
||||
use crate::violations;
|
||||
|
||||
/// D404
|
||||
@@ -13,14 +14,10 @@ pub fn starts_with_this(checker: &mut Checker, docstring: &Docstring) {
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(first_word) = body.split(' ').next() else {
|
||||
let Some(first_word) = trimmed.split(' ').next() else {
|
||||
return
|
||||
};
|
||||
if first_word
|
||||
.replace(|c: char| !c.is_alphanumeric(), "")
|
||||
.to_lowercase()
|
||||
!= "this"
|
||||
{
|
||||
if normalize_word(first_word) != "this" {
|
||||
return;
|
||||
}
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
|
||||
@@ -53,4 +53,24 @@ expression: diagnostics
|
||||
row: 608
|
||||
column: 7
|
||||
parent: ~
|
||||
- kind:
|
||||
FitsOnOneLine: ~
|
||||
location:
|
||||
row: 615
|
||||
column: 4
|
||||
end_location:
|
||||
row: 617
|
||||
column: 7
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
FitsOnOneLine: ~
|
||||
location:
|
||||
row: 624
|
||||
column: 4
|
||||
end_location:
|
||||
row: 626
|
||||
column: 14
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
|
||||
@@ -22,4 +22,14 @@ expression: diagnostics
|
||||
column: 13
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
MultiLineSummaryFirstLine: ~
|
||||
location:
|
||||
row: 624
|
||||
column: 4
|
||||
end_location:
|
||||
row: 626
|
||||
column: 14
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
|
||||
@@ -212,4 +212,14 @@ expression: diagnostics
|
||||
column: 7
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
MultiLineSummarySecondLine: ~
|
||||
location:
|
||||
row: 615
|
||||
column: 4
|
||||
end_location:
|
||||
row: 617
|
||||
column: 7
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
|
||||
@@ -240,4 +240,21 @@ expression: diagnostics
|
||||
row: 581
|
||||
column: 47
|
||||
parent: ~
|
||||
- kind:
|
||||
EndsInPeriod: ~
|
||||
location:
|
||||
row: 615
|
||||
column: 4
|
||||
end_location:
|
||||
row: 617
|
||||
column: 7
|
||||
fix:
|
||||
content: "."
|
||||
location:
|
||||
row: 615
|
||||
column: 14
|
||||
end_location:
|
||||
row: 615
|
||||
column: 14
|
||||
parent: ~
|
||||
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
---
|
||||
source: src/rules/pydocstyle/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
NonImperativeMood: Returns foo.
|
||||
location:
|
||||
row: 4
|
||||
column: 4
|
||||
end_location:
|
||||
row: 4
|
||||
column: 22
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
NonImperativeMood: Constructor for a foo.
|
||||
location:
|
||||
row: 8
|
||||
column: 4
|
||||
end_location:
|
||||
row: 8
|
||||
column: 32
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
NonImperativeMood: Constructor for a boa.
|
||||
location:
|
||||
row: 12
|
||||
column: 4
|
||||
end_location:
|
||||
row: 16
|
||||
column: 7
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
NonImperativeMood: Runs something
|
||||
location:
|
||||
row: 20
|
||||
column: 4
|
||||
end_location:
|
||||
row: 20
|
||||
column: 24
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
NonImperativeMood: Writes a logical line that
|
||||
location:
|
||||
row: 25
|
||||
column: 4
|
||||
end_location:
|
||||
row: 27
|
||||
column: 7
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
@@ -2,5 +2,24 @@
|
||||
source: src/rules/pydocstyle/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
[]
|
||||
- kind:
|
||||
NoThisPrefix: ~
|
||||
location:
|
||||
row: 631
|
||||
column: 4
|
||||
end_location:
|
||||
row: 631
|
||||
column: 30
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
NoThisPrefix: ~
|
||||
location:
|
||||
row: 636
|
||||
column: 4
|
||||
end_location:
|
||||
row: 636
|
||||
column: 56
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
|
||||
@@ -223,4 +223,21 @@ expression: diagnostics
|
||||
row: 581
|
||||
column: 47
|
||||
parent: ~
|
||||
- kind:
|
||||
EndsInPunctuation: ~
|
||||
location:
|
||||
row: 615
|
||||
column: 4
|
||||
end_location:
|
||||
row: 617
|
||||
column: 7
|
||||
fix:
|
||||
content: "."
|
||||
location:
|
||||
row: 615
|
||||
column: 14
|
||||
end_location:
|
||||
row: 615
|
||||
column: 14
|
||||
parent: ~
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ mod tests {
|
||||
#[test_case(Rule::FormatLiterals, Path::new("UP030_1.py"); "UP030_1")]
|
||||
#[test_case(Rule::FString, Path::new("UP032.py"); "UP032")]
|
||||
#[test_case(Rule::FunctoolsCache, Path::new("UP033.py"); "UP033")]
|
||||
#[test_case(Rule::ExtraneousParentheses, Path::new("UP034.py"); "UP034")]
|
||||
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
|
||||
let snapshot = format!("{}_{}", rule_code.code(), path.to_string_lossy());
|
||||
let diagnostics = test_path(
|
||||
|
||||
143
src/rules/pyupgrade/rules/extraneous_parentheses.rs
Normal file
143
src/rules/pyupgrade/rules/extraneous_parentheses.rs
Normal file
@@ -0,0 +1,143 @@
|
||||
use rustpython_parser::lexer::{LexResult, Tok};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::fix::Fix;
|
||||
use crate::registry::{Diagnostic, Rule};
|
||||
use crate::settings::{flags, Settings};
|
||||
use crate::source_code::Locator;
|
||||
use crate::violations;
|
||||
|
||||
// See: https://github.com/asottile/pyupgrade/blob/97ed6fb3cf2e650d4f762ba231c3f04c41797710/pyupgrade/_main.py#L148
|
||||
fn match_extraneous_parentheses(tokens: &[LexResult], mut i: usize) -> Option<(usize, usize)> {
|
||||
i += 1;
|
||||
|
||||
loop {
|
||||
if i >= tokens.len() {
|
||||
return None;
|
||||
}
|
||||
let Ok((_, tok, _)) = &tokens[i] else {
|
||||
return None;
|
||||
};
|
||||
match tok {
|
||||
Tok::Comment(..) | Tok::NonLogicalNewline => {
|
||||
i += 1;
|
||||
}
|
||||
Tok::Lpar => {
|
||||
break;
|
||||
}
|
||||
_ => {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Store the location of the extraneous opening parenthesis.
|
||||
let start = i;
|
||||
|
||||
// Verify that we're not in a tuple or coroutine.
|
||||
let mut depth = 1;
|
||||
while depth > 0 {
|
||||
i += 1;
|
||||
if i >= tokens.len() {
|
||||
return None;
|
||||
}
|
||||
let Ok((_, tok, _)) = &tokens[i] else {
|
||||
return None;
|
||||
};
|
||||
|
||||
// If we find a comma or a yield at depth 1 or 2, it's a tuple or coroutine.
|
||||
if depth == 1 && matches!(tok, Tok::Comma | Tok::Yield) {
|
||||
return None;
|
||||
} else if matches!(tok, Tok::Lpar | Tok::Lbrace | Tok::Lsqb) {
|
||||
depth += 1;
|
||||
} else if matches!(tok, Tok::Rpar | Tok::Rbrace | Tok::Rsqb) {
|
||||
depth -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Store the location of the extraneous closing parenthesis.
|
||||
let end = i;
|
||||
|
||||
// Verify that we're not in an empty tuple.
|
||||
if (start + 1..i).all(|i| {
|
||||
matches!(
|
||||
tokens[i],
|
||||
Ok((_, Tok::Comment(..) | Tok::NonLogicalNewline, _))
|
||||
)
|
||||
}) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Find the next non-coding token.
|
||||
i += 1;
|
||||
loop {
|
||||
if i >= tokens.len() {
|
||||
return None;
|
||||
}
|
||||
let Ok((_, tok, _)) = &tokens[i] else {
|
||||
return None;
|
||||
};
|
||||
match tok {
|
||||
Tok::Comment(..) | Tok::NonLogicalNewline => {
|
||||
i += 1;
|
||||
}
|
||||
_ => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if i >= tokens.len() {
|
||||
return None;
|
||||
}
|
||||
let Ok((_, tok, _)) = &tokens[i] else {
|
||||
return None;
|
||||
};
|
||||
if matches!(tok, Tok::Rpar) {
|
||||
Some((start, end))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// UP034
|
||||
pub fn extraneous_parentheses(
|
||||
tokens: &[LexResult],
|
||||
locator: &Locator,
|
||||
settings: &Settings,
|
||||
autofix: flags::Autofix,
|
||||
) -> Vec<Diagnostic> {
|
||||
let mut diagnostics = vec![];
|
||||
let mut i = 0;
|
||||
while i < tokens.len() {
|
||||
if matches!(tokens[i], Ok((_, Tok::Lpar, _))) {
|
||||
if let Some((start, end)) = match_extraneous_parentheses(tokens, i) {
|
||||
i = end + 1;
|
||||
let Ok((start, ..)) = &tokens[start] else {
|
||||
return diagnostics;
|
||||
};
|
||||
let Ok((.., end)) = &tokens[end] else {
|
||||
return diagnostics;
|
||||
};
|
||||
let mut diagnostic =
|
||||
Diagnostic::new(violations::ExtraneousParentheses, Range::new(*start, *end));
|
||||
if matches!(autofix, flags::Autofix::Enabled)
|
||||
&& settings.rules.should_fix(&Rule::ExtraneousParentheses)
|
||||
{
|
||||
let contents = locator.slice_source_code_range(&Range::new(*start, *end));
|
||||
diagnostic.amend(Fix::replacement(
|
||||
contents[1..contents.len() - 1].to_string(),
|
||||
*start,
|
||||
*end,
|
||||
));
|
||||
}
|
||||
diagnostics.push(diagnostic);
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
diagnostics
|
||||
}
|
||||
@@ -2,6 +2,7 @@ pub(crate) use convert_named_tuple_functional_to_class::convert_named_tuple_func
|
||||
pub(crate) use convert_typed_dict_functional_to_class::convert_typed_dict_functional_to_class;
|
||||
pub(crate) use datetime_utc_alias::datetime_utc_alias;
|
||||
pub(crate) use deprecated_unittest_alias::deprecated_unittest_alias;
|
||||
pub(crate) use extraneous_parentheses::extraneous_parentheses;
|
||||
pub(crate) use f_strings::f_strings;
|
||||
pub(crate) use format_literals::format_literals;
|
||||
pub(crate) use functools_cache::functools_cache;
|
||||
@@ -43,6 +44,7 @@ mod convert_named_tuple_functional_to_class;
|
||||
mod convert_typed_dict_functional_to_class;
|
||||
mod datetime_utc_alias;
|
||||
mod deprecated_unittest_alias;
|
||||
mod extraneous_parentheses;
|
||||
mod f_strings;
|
||||
mod format_literals;
|
||||
mod functools_cache;
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
---
|
||||
source: src/rules/pyupgrade/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
ExtraneousParentheses: ~
|
||||
location:
|
||||
row: 2
|
||||
column: 6
|
||||
end_location:
|
||||
row: 2
|
||||
column: 13
|
||||
fix:
|
||||
content: "\"foo\""
|
||||
location:
|
||||
row: 2
|
||||
column: 6
|
||||
end_location:
|
||||
row: 2
|
||||
column: 13
|
||||
parent: ~
|
||||
- kind:
|
||||
ExtraneousParentheses: ~
|
||||
location:
|
||||
row: 5
|
||||
column: 6
|
||||
end_location:
|
||||
row: 5
|
||||
column: 26
|
||||
fix:
|
||||
content: "\"hell((goodybe))o\""
|
||||
location:
|
||||
row: 5
|
||||
column: 6
|
||||
end_location:
|
||||
row: 5
|
||||
column: 26
|
||||
parent: ~
|
||||
- kind:
|
||||
ExtraneousParentheses: ~
|
||||
location:
|
||||
row: 8
|
||||
column: 6
|
||||
end_location:
|
||||
row: 8
|
||||
column: 15
|
||||
fix:
|
||||
content: "(\"foo\")"
|
||||
location:
|
||||
row: 8
|
||||
column: 6
|
||||
end_location:
|
||||
row: 8
|
||||
column: 15
|
||||
parent: ~
|
||||
- kind:
|
||||
ExtraneousParentheses: ~
|
||||
location:
|
||||
row: 11
|
||||
column: 6
|
||||
end_location:
|
||||
row: 11
|
||||
column: 13
|
||||
fix:
|
||||
content: ((1))
|
||||
location:
|
||||
row: 11
|
||||
column: 6
|
||||
end_location:
|
||||
row: 11
|
||||
column: 13
|
||||
parent: ~
|
||||
- kind:
|
||||
ExtraneousParentheses: ~
|
||||
location:
|
||||
row: 14
|
||||
column: 6
|
||||
end_location:
|
||||
row: 14
|
||||
column: 25
|
||||
fix:
|
||||
content: "\"foo{}\".format(1)"
|
||||
location:
|
||||
row: 14
|
||||
column: 6
|
||||
end_location:
|
||||
row: 14
|
||||
column: 25
|
||||
parent: ~
|
||||
- kind:
|
||||
ExtraneousParentheses: ~
|
||||
location:
|
||||
row: 18
|
||||
column: 4
|
||||
end_location:
|
||||
row: 18
|
||||
column: 23
|
||||
fix:
|
||||
content: "\"foo{}\".format(1)"
|
||||
location:
|
||||
row: 18
|
||||
column: 4
|
||||
end_location:
|
||||
row: 18
|
||||
column: 23
|
||||
parent: ~
|
||||
- kind:
|
||||
ExtraneousParentheses: ~
|
||||
location:
|
||||
row: 23
|
||||
column: 4
|
||||
end_location:
|
||||
row: 25
|
||||
column: 5
|
||||
fix:
|
||||
content: "\n \"foo\"\n "
|
||||
location:
|
||||
row: 23
|
||||
column: 4
|
||||
end_location:
|
||||
row: 25
|
||||
column: 5
|
||||
parent: ~
|
||||
- kind:
|
||||
ExtraneousParentheses: ~
|
||||
location:
|
||||
row: 30
|
||||
column: 12
|
||||
end_location:
|
||||
row: 30
|
||||
column: 23
|
||||
fix:
|
||||
content: (yield 1)
|
||||
location:
|
||||
row: 30
|
||||
column: 12
|
||||
end_location:
|
||||
row: 30
|
||||
column: 23
|
||||
parent: ~
|
||||
- kind:
|
||||
ExtraneousParentheses: ~
|
||||
location:
|
||||
row: 35
|
||||
column: 8
|
||||
end_location:
|
||||
row: 35
|
||||
column: 27
|
||||
fix:
|
||||
content: "\"foo{}\".format(1)"
|
||||
location:
|
||||
row: 35
|
||||
column: 8
|
||||
end_location:
|
||||
row: 35
|
||||
column: 27
|
||||
parent: ~
|
||||
- kind:
|
||||
ExtraneousParentheses: ~
|
||||
location:
|
||||
row: 39
|
||||
column: 6
|
||||
end_location:
|
||||
row: 39
|
||||
column: 27
|
||||
fix:
|
||||
content: x for x in range(3)
|
||||
location:
|
||||
row: 39
|
||||
column: 6
|
||||
end_location:
|
||||
row: 39
|
||||
column: 27
|
||||
parent: ~
|
||||
|
||||
@@ -118,23 +118,38 @@ impl Deref for Indentation {
|
||||
|
||||
/// The line ending style used in Python source code.
|
||||
/// See <https://docs.python.org/3/reference/lexical_analysis.html#physical-lines>
|
||||
#[derive(Debug, Default, PartialEq, Eq)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum LineEnding {
|
||||
#[default]
|
||||
Lf,
|
||||
Cr,
|
||||
CrLf,
|
||||
}
|
||||
|
||||
impl Default for LineEnding {
|
||||
fn default() -> Self {
|
||||
if cfg!(windows) {
|
||||
LineEnding::CrLf
|
||||
} else {
|
||||
LineEnding::Lf
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LineEnding {
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
LineEnding::CrLf => "\r\n",
|
||||
LineEnding::Lf => "\n",
|
||||
LineEnding::Cr => "\r",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for LineEnding {
|
||||
type Target = str;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
match &self {
|
||||
LineEnding::CrLf => "\r\n",
|
||||
LineEnding::Lf => "\n",
|
||||
LineEnding::Cr => "\r",
|
||||
}
|
||||
self.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3152,6 +3152,20 @@ impl AlwaysAutofixableViolation for FormatLiterals {
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct ExtraneousParentheses;
|
||||
);
|
||||
impl AlwaysAutofixableViolation for ExtraneousParentheses {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Avoid extraneous parentheses")
|
||||
}
|
||||
|
||||
fn autofix_title(&self) -> String {
|
||||
"Remove extraneous parentheses".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct FString;
|
||||
);
|
||||
@@ -4366,7 +4380,7 @@ impl Violation for CallDatetimeStrptimeWithoutZone {
|
||||
fn message(&self) -> String {
|
||||
format!(
|
||||
"The use of `datetime.datetime.strptime()` without %z must be followed by \
|
||||
`.replace(tzinfo=)`"
|
||||
`.replace(tzinfo=)` or `.astimezone()`"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,12 +80,12 @@ pub fn is_init(name: &str) -> bool {
|
||||
name == "__init__"
|
||||
}
|
||||
|
||||
/// Returns `true` if a function is an `__new__`.
|
||||
/// Returns `true` if a function is a `__new__`.
|
||||
pub fn is_new(name: &str) -> bool {
|
||||
name == "__new__"
|
||||
}
|
||||
|
||||
/// Returns `true` if a function is an `__call__`.
|
||||
/// Returns `true` if a function is a `__call__`.
|
||||
pub fn is_call(name: &str) -> bool {
|
||||
name == "__call__"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user