Compare commits
83 Commits
v0.0.286
...
charlie/cl
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ffbbb8d912 | ||
|
|
b9f0ade746 | ||
|
|
dd4bf76adf | ||
|
|
6761f33600 | ||
|
|
792b76583b | ||
|
|
3e0d849c24 | ||
|
|
8b8fd411e2 | ||
|
|
96a9717c1a | ||
|
|
f4ba0ea144 | ||
|
|
92143afeee | ||
|
|
eb552da8a9 | ||
|
|
e2b2b1759f | ||
|
|
a3f4d7745a | ||
|
|
edfd888bd6 | ||
|
|
9c382e8291 | ||
|
|
eb2b226142 | ||
|
|
31947af6a3 | ||
|
|
b404e54f33 | ||
|
|
34e8de738e | ||
|
|
1550a6bfe7 | ||
|
|
dc4db39f78 | ||
|
|
f3aaf84a28 | ||
|
|
5de95d7054 | ||
|
|
8d1610d960 | ||
|
|
fad23bbe60 | ||
|
|
25c374856a | ||
|
|
34221346c1 | ||
|
|
924f10186f | ||
|
|
b7634b6ede | ||
|
|
4d49d5e845 | ||
|
|
715d86dae9 | ||
|
|
adb48692d6 | ||
|
|
19ccf1d073 | ||
|
|
e3c36465ec | ||
|
|
7e36284684 | ||
|
|
c448b4086a | ||
|
|
3200015c06 | ||
|
|
26d53c56a2 | ||
|
|
1439bb592e | ||
|
|
fc47e0dab2 | ||
|
|
87aa5d6b66 | ||
|
|
d1ad20c9ea | ||
|
|
ecca125f9a | ||
|
|
005e21a139 | ||
|
|
e1db036f90 | ||
|
|
9ad67b0758 | ||
|
|
af61abc747 | ||
|
|
ec575188c4 | ||
|
|
aea7500c1e | ||
|
|
58f5f27dc3 | ||
|
|
2893a9f6b5 | ||
|
|
60097bebcd | ||
|
|
9c98416b96 | ||
|
|
99f4c6886e | ||
|
|
30ebf7fc86 | ||
|
|
fa25dabf17 | ||
|
|
e615870659 | ||
|
|
a6aa16630d | ||
|
|
039694aaed | ||
|
|
6bc1ba6d62 | ||
|
|
cd47368ae4 | ||
|
|
a871714705 | ||
|
|
292fdd978e | ||
|
|
c2413dcd2c | ||
|
|
059757a8c8 | ||
|
|
fc89976c24 | ||
|
|
88c8bece38 | ||
|
|
d0b051e447 | ||
|
|
381fc5b2a8 | ||
|
|
7c480236e0 | ||
|
|
3f3494ad44 | ||
|
|
f33277a057 | ||
|
|
eae59cf088 | ||
|
|
15b73bdb8a | ||
|
|
ed1b4122d0 | ||
|
|
9d77552e18 | ||
|
|
f91bacbb94 | ||
|
|
2883ae4d46 | ||
|
|
bd625b1928 | ||
|
|
e0a40783ca | ||
|
|
0e79074c31 | ||
|
|
edb9b0c62a | ||
|
|
91a780c771 |
136
.github/workflows/benchmark.yaml
vendored
136
.github/workflows/benchmark.yaml
vendored
@@ -1,136 +0,0 @@
|
||||
name: Benchmark
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "Cargo.toml"
|
||||
- "Cargo.lock"
|
||||
- "rust-toolchain"
|
||||
- "crates/**"
|
||||
- "!crates/ruff_dev"
|
||||
- "!crates/ruff_shrinking"
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.sha }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
run-benchmark:
|
||||
if: github.event_name == 'pull_request'
|
||||
name: "Run | ${{ matrix.os }}"
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- name: "PR - Checkout Branch"
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
- name: "PR - Install Rust toolchain"
|
||||
run: rustup show
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
|
||||
- name: "PR - Build benchmarks"
|
||||
run: cargo bench -p ruff_benchmark --no-run
|
||||
|
||||
- name: "PR - Run benchmarks"
|
||||
run: cargo benchmark --save-baseline=pr
|
||||
|
||||
- name: "Main - Checkout Branch"
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
clean: false
|
||||
ref: main
|
||||
|
||||
- name: "Main - Install Rust toolchain"
|
||||
run: rustup show
|
||||
|
||||
- name: "Main - Build benchmarks"
|
||||
run: cargo bench -p ruff_benchmark --no-run
|
||||
|
||||
- name: "Main - Run benchmarks"
|
||||
run: cargo benchmark --save-baseline=main
|
||||
|
||||
- name: "Upload benchmark results"
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: benchmark-results-${{ matrix.os }}
|
||||
path: ./target/criterion
|
||||
|
||||
# Cleanup
|
||||
- name: Remove Criterion Artifact
|
||||
uses: JesseTG/rm@v1.0.3
|
||||
with:
|
||||
path: ./target/criterion
|
||||
|
||||
benchmark-compare:
|
||||
if: github.event_name == 'pull_request'
|
||||
runs-on: ubuntu-latest
|
||||
name: Compare
|
||||
needs:
|
||||
- run-benchmark
|
||||
|
||||
steps:
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup show
|
||||
|
||||
- name: "Install critcmp"
|
||||
uses: taiki-e/install-action@v2
|
||||
with:
|
||||
tool: critcmp
|
||||
|
||||
- name: "Linux | Download PR benchmark results"
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: benchmark-results-ubuntu-latest
|
||||
path: ./target/criterion
|
||||
|
||||
- name: "Linux | Compare benchmark results"
|
||||
shell: bash
|
||||
run: |
|
||||
echo "### Benchmark" >> summary.md
|
||||
echo "#### Linux" >> summary.md
|
||||
echo "\`\`\`" >> summary.md
|
||||
critcmp main pr >> summary.md
|
||||
echo "\`\`\`" >> summary.md
|
||||
echo "" >> summary.md
|
||||
|
||||
- name: "Linux | Cleanup benchmark results"
|
||||
run: rm -rf ./target/criterion
|
||||
|
||||
- name: "Windows | Download PR benchmark results"
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: benchmark-results-windows-latest
|
||||
path: ./target/criterion
|
||||
|
||||
- name: "Windows | Compare benchmark results"
|
||||
shell: bash
|
||||
run: |
|
||||
echo "#### Windows" >> summary.md
|
||||
echo "\`\`\`" >> summary.md
|
||||
critcmp main pr >> summary.md
|
||||
echo "\`\`\`" >> summary.md
|
||||
echo "" >> summary.md
|
||||
|
||||
echo ${{ github.event.pull_request.number }} > pr-number
|
||||
|
||||
cat summary.md > $GITHUB_STEP_SUMMARY
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
name: Upload PR Number
|
||||
with:
|
||||
name: pr-number
|
||||
path: pr-number
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
name: Upload Summary
|
||||
with:
|
||||
name: summary
|
||||
path: summary.md
|
||||
27
.github/workflows/ci.yaml
vendored
27
.github/workflows/ci.yaml
vendored
@@ -30,7 +30,7 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: tj-actions/changed-files@v37
|
||||
- uses: tj-actions/changed-files@v38
|
||||
id: changed
|
||||
with:
|
||||
files_yaml: |
|
||||
@@ -341,3 +341,28 @@ jobs:
|
||||
run: cat target/progress_projects_stats.txt > $GITHUB_STEP_SUMMARY
|
||||
- name: "Remove checkouts from cache"
|
||||
run: rm -r target/progress_projects
|
||||
|
||||
benchmarks:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: "Checkout Branch"
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup show
|
||||
|
||||
- name: "Install codspeed"
|
||||
uses: taiki-e/install-action@v2
|
||||
with:
|
||||
tool: cargo-codspeed
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
|
||||
- name: "Build benchmarks"
|
||||
run: cargo codspeed build --features codspeed -p ruff_benchmark
|
||||
|
||||
- name: "Run benchmarks"
|
||||
uses: CodSpeedHQ/action@v1
|
||||
with:
|
||||
run: cargo codspeed run
|
||||
token: ${{ secrets.CODSPEED_TOKEN }}
|
||||
|
||||
58
.github/workflows/pr-comment.yaml
vendored
58
.github/workflows/pr-comment.yaml
vendored
@@ -2,7 +2,7 @@ name: PR Check Comment
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: [CI, Benchmark]
|
||||
workflows: [CI]
|
||||
types: [completed]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
@@ -43,42 +43,34 @@ jobs:
|
||||
path: pr/ecosystem
|
||||
if_no_artifact_found: ignore
|
||||
|
||||
- uses: dawidd6/action-download-artifact@v2
|
||||
name: "Download Benchmark Result"
|
||||
id: download-benchmark-result
|
||||
if: steps.pr-number.outputs.pr-number
|
||||
with:
|
||||
name: summary
|
||||
workflow: benchmark.yaml
|
||||
pr: ${{ steps.pr-number.outputs.pr-number }}
|
||||
path: pr/benchmark
|
||||
if_no_artifact_found: ignore
|
||||
|
||||
- name: Generate Comment
|
||||
id: generate-comment
|
||||
if: steps.download-ecosystem-result.outputs.found_artifact == 'true' || steps.download-benchmark-result.outputs.found_artifact == 'true'
|
||||
if: steps.download-ecosystem-result.outputs.found_artifact == 'true'
|
||||
run: |
|
||||
echo '## PR Check Results' >> comment.txt
|
||||
|
||||
echo "### Ecosystem" >> comment.txt
|
||||
cat pr/ecosystem/ecosystem-result >> comment.txt
|
||||
echo "" >> comment.txt
|
||||
|
||||
echo 'comment<<EOF' >> $GITHUB_OUTPUT
|
||||
echo '## PR Check Results' >> $GITHUB_OUTPUT
|
||||
|
||||
if [[ -f pr/ecosystem/ecosystem-result ]]
|
||||
then
|
||||
echo "### Ecosystem" >> $GITHUB_OUTPUT
|
||||
cat pr/ecosystem/ecosystem-result >> $GITHUB_OUTPUT
|
||||
echo "" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
if [[ -f pr/benchmark/summary.md ]]
|
||||
then
|
||||
cat pr/benchmark/summary.md >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
cat comment.txt >> $GITHUB_OUTPUT
|
||||
echo 'EOF' >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Create or update comment
|
||||
if: steps.generate-comment.outputs.comment
|
||||
uses: thollander/actions-comment-pull-request@v2
|
||||
- name: Find Comment
|
||||
uses: peter-evans/find-comment@v2
|
||||
if: steps.generate-comment.outcome == 'success'
|
||||
id: find-comment
|
||||
with:
|
||||
pr_number: ${{ steps.pr-number.outputs.pr-number }}
|
||||
message: ${{ steps.generate-comment.outputs.comment }}
|
||||
comment_tag: PR Check Results
|
||||
issue-number: ${{ steps.pr-number.outputs.pr-number }}
|
||||
comment-author: "github-actions[bot]"
|
||||
body-includes: PR Check Results
|
||||
|
||||
- name: Create or update comment
|
||||
if: steps.find-comment.outcome == 'success'
|
||||
uses: peter-evans/create-or-update-comment@v3
|
||||
with:
|
||||
comment-id: ${{ steps.find-comment.outputs.comment-id }}
|
||||
issue-number: ${{ steps.pr-number.outputs.pr-number }}
|
||||
body-path: comment.txt
|
||||
edit-mode: replace
|
||||
|
||||
113
Cargo.lock
generated
113
Cargo.lock
generated
@@ -414,6 +414,28 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codspeed"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5aeec2fbed4969dc38b5ca201115dd5c2614b8ef78e0a7221dd5f0977fb1552b"
|
||||
dependencies = [
|
||||
"colored",
|
||||
"libc",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codspeed-criterion-compat"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b13f0a08d40ce7c95bdf288f725b975e62fcadfa8ba152340943bab6de43af7"
|
||||
dependencies = [
|
||||
"codspeed",
|
||||
"colored",
|
||||
"criterion",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.0"
|
||||
@@ -588,9 +610,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.20.1"
|
||||
version = "0.20.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0558d22a7b463ed0241e993f76f09f30b126687447751a8638587b864e4b3944"
|
||||
checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
@@ -598,9 +620,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.20.1"
|
||||
version = "0.20.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab8bfa2e259f8ee1ce5e97824a3c55ec4404a0d772ca7fa96bf19f0752a046eb"
|
||||
checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
@@ -612,15 +634,24 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.20.1"
|
||||
version = "0.20.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29a358ff9f12ec09c3e61fef9b5a9902623a695a46a917b07f269bff1445611a"
|
||||
checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn 2.0.23",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diff"
|
||||
version = "0.1.13"
|
||||
@@ -818,9 +849,14 @@ dependencies = [
|
||||
"clap",
|
||||
"colored",
|
||||
"configparser",
|
||||
"itertools",
|
||||
"log",
|
||||
"once_cell",
|
||||
"pep440_rs",
|
||||
"pretty_assertions",
|
||||
"regex",
|
||||
"ruff",
|
||||
"ruff_workspace",
|
||||
"rustc-hash",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -1044,6 +1080,7 @@ checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.14.0",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2074,11 +2111,9 @@ dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
"colored",
|
||||
"dirs 5.0.1",
|
||||
"fern",
|
||||
"glob",
|
||||
"globset",
|
||||
"ignore",
|
||||
"imperative",
|
||||
"insta",
|
||||
"is-macro",
|
||||
@@ -2118,7 +2153,6 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_with",
|
||||
"shellexpand",
|
||||
"similar",
|
||||
"smallvec",
|
||||
"strum",
|
||||
@@ -2138,6 +2172,7 @@ dependencies = [
|
||||
name = "ruff_benchmark"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"codspeed-criterion-compat",
|
||||
"criterion",
|
||||
"mimalloc",
|
||||
"once_cell",
|
||||
@@ -2185,6 +2220,7 @@ dependencies = [
|
||||
"glob",
|
||||
"ignore",
|
||||
"insta",
|
||||
"is-macro",
|
||||
"itertools",
|
||||
"itoa",
|
||||
"log",
|
||||
@@ -2196,6 +2232,7 @@ dependencies = [
|
||||
"ruff",
|
||||
"ruff_cache",
|
||||
"ruff_diagnostics",
|
||||
"ruff_formatter",
|
||||
"ruff_macros",
|
||||
"ruff_python_ast",
|
||||
"ruff_python_formatter",
|
||||
@@ -2203,6 +2240,7 @@ dependencies = [
|
||||
"ruff_python_trivia",
|
||||
"ruff_source_file",
|
||||
"ruff_text_size",
|
||||
"ruff_workspace",
|
||||
"rustc-hash",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -2210,7 +2248,9 @@ dependencies = [
|
||||
"similar",
|
||||
"strum",
|
||||
"tempfile",
|
||||
"thiserror",
|
||||
"tikv-jemallocator",
|
||||
"tracing",
|
||||
"ureq",
|
||||
"walkdir",
|
||||
"wild",
|
||||
@@ -2243,6 +2283,7 @@ dependencies = [
|
||||
"ruff_python_parser",
|
||||
"ruff_python_stdlib",
|
||||
"ruff_python_trivia",
|
||||
"ruff_workspace",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -2502,18 +2543,48 @@ dependencies = [
|
||||
"log",
|
||||
"ruff",
|
||||
"ruff_diagnostics",
|
||||
"ruff_formatter",
|
||||
"ruff_python_ast",
|
||||
"ruff_python_codegen",
|
||||
"ruff_python_formatter",
|
||||
"ruff_python_index",
|
||||
"ruff_python_parser",
|
||||
"ruff_source_file",
|
||||
"ruff_text_size",
|
||||
"ruff_workspace",
|
||||
"serde",
|
||||
"serde-wasm-bindgen",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-test",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff_workspace"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"colored",
|
||||
"dirs 5.0.1",
|
||||
"glob",
|
||||
"globset",
|
||||
"ignore",
|
||||
"itertools",
|
||||
"log",
|
||||
"path-absolutize",
|
||||
"pep440_rs",
|
||||
"regex",
|
||||
"ruff",
|
||||
"ruff_cache",
|
||||
"ruff_macros",
|
||||
"rustc-hash",
|
||||
"schemars",
|
||||
"serde",
|
||||
"shellexpand",
|
||||
"strum",
|
||||
"tempfile",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-stemmers"
|
||||
version = "1.2.0"
|
||||
@@ -2696,9 +2767,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.100"
|
||||
version = "1.0.105"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f1e14e89be7aa4c4b78bdbdc9eb5bf8517829a600ae8eaa39a6e1d960b5185c"
|
||||
checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
@@ -2725,25 +2796,26 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_with"
|
||||
version = "3.0.0"
|
||||
version = "3.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f02d8aa6e3c385bf084924f660ce2a3a6bd333ba55b35e8590b321f35d88513"
|
||||
checksum = "1ca3b16a3d82c4088f343b7480a93550b3eabe1a358569c2dfe38bbcead07237"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"chrono",
|
||||
"hex",
|
||||
"indexmap 1.9.3",
|
||||
"indexmap 2.0.0",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_with_macros",
|
||||
"time 0.3.22",
|
||||
"time 0.3.26",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_with_macros"
|
||||
version = "3.0.0"
|
||||
version = "3.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "edc7d5d3932fb12ce722ee5e64dd38c504efba37567f0c402f6ca728c3b8b070"
|
||||
checksum = "2e6be15c453eb305019bfa438b1593c731f36a289a7853f7707ee29e870b3b3c"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
@@ -3028,10 +3100,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.22"
|
||||
version = "0.3.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd"
|
||||
checksum = "a79d09ac6b08c1ab3906a2f7cc2e81a0e27c7ae89c63812df75e52bef0751e07"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"itoa",
|
||||
"serde",
|
||||
"time-core",
|
||||
@@ -3046,9 +3119,9 @@ checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb"
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.9"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b"
|
||||
checksum = "75c65469ed6b3a4809d987a41eb1dc918e9bc1d92211cbad7ae82931846f7451"
|
||||
dependencies = [
|
||||
"time-core",
|
||||
]
|
||||
|
||||
@@ -14,12 +14,16 @@ license = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
ruff = { path = "../ruff", default-features = false }
|
||||
ruff_workspace = { path = "../ruff_workspace" }
|
||||
|
||||
anyhow = { workspace = true }
|
||||
clap = { workspace = true }
|
||||
colored = { workspace = true }
|
||||
configparser = { version = "3.0.2" }
|
||||
itertools = { workspace = true }
|
||||
log = { workspace = true }
|
||||
once_cell = { workspace = true }
|
||||
pep440_rs = { version = "0.3.1", features = ["serde"] }
|
||||
regex = { workspace = true }
|
||||
rustc-hash = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
@@ -27,3 +31,6 @@ serde_json = { workspace = true }
|
||||
strum = { workspace = true }
|
||||
strum_macros = { workspace = true }
|
||||
toml = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "1.3.0"
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
//! Extract Black configuration settings from a pyproject.toml.
|
||||
|
||||
use ruff::line_width::LineLength;
|
||||
use ruff::settings::types::PythonVersion;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::settings::types::PythonVersion;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
pub struct Black {
|
||||
pub(crate) struct Black {
|
||||
#[serde(alias = "line-length", alias = "line_length")]
|
||||
pub line_length: Option<usize>,
|
||||
pub(crate) line_length: Option<LineLength>,
|
||||
#[serde(alias = "target-version", alias = "target_version")]
|
||||
pub target_version: Option<Vec<PythonVersion>>,
|
||||
pub(crate) target_version: Option<Vec<PythonVersion>>,
|
||||
}
|
||||
@@ -1,25 +1,25 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::str::FromStr;
|
||||
|
||||
use anyhow::Result;
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::line_width::LineLength;
|
||||
use crate::registry::Linter;
|
||||
use crate::rule_selector::RuleSelector;
|
||||
use crate::rules::flake8_pytest_style::types::{
|
||||
use ruff::line_width::LineLength;
|
||||
use ruff::registry::Linter;
|
||||
use ruff::rule_selector::RuleSelector;
|
||||
use ruff::rules::flake8_pytest_style::types::{
|
||||
ParametrizeNameType, ParametrizeValuesRowType, ParametrizeValuesType,
|
||||
};
|
||||
use crate::rules::flake8_quotes::settings::Quote;
|
||||
use crate::rules::flake8_tidy_imports::settings::Strictness;
|
||||
use crate::rules::pydocstyle::settings::Convention;
|
||||
use crate::rules::{
|
||||
flake8_annotations, flake8_bugbear, flake8_builtins, flake8_errmsg, flake8_pytest_style,
|
||||
flake8_quotes, flake8_tidy_imports, mccabe, pep8_naming, pydocstyle,
|
||||
use ruff::rules::flake8_quotes::settings::Quote;
|
||||
use ruff::rules::flake8_tidy_imports::settings::Strictness;
|
||||
use ruff::rules::pydocstyle::settings::Convention;
|
||||
use ruff::settings::types::PythonVersion;
|
||||
use ruff::warn_user;
|
||||
use ruff_workspace::options::{
|
||||
Flake8AnnotationsOptions, Flake8BugbearOptions, Flake8BuiltinsOptions, Flake8ErrMsgOptions,
|
||||
Flake8PytestStyleOptions, Flake8QuotesOptions, Flake8TidyImportsOptions, McCabeOptions,
|
||||
Options, Pep8NamingOptions, PydocstyleOptions,
|
||||
};
|
||||
use crate::settings::options::Options;
|
||||
use crate::settings::pyproject::Pyproject;
|
||||
use crate::settings::types::PythonVersion;
|
||||
use crate::warn_user;
|
||||
use ruff_workspace::pyproject::Pyproject;
|
||||
|
||||
use super::external_config::ExternalConfig;
|
||||
use super::plugin::Plugin;
|
||||
@@ -30,11 +30,11 @@ const DEFAULT_SELECTORS: &[RuleSelector] = &[
|
||||
RuleSelector::Linter(Linter::Pycodestyle),
|
||||
];
|
||||
|
||||
pub fn convert(
|
||||
pub(crate) fn convert(
|
||||
config: &HashMap<String, HashMap<String, Option<String>>>,
|
||||
external_config: &ExternalConfig,
|
||||
plugins: Option<Vec<Plugin>>,
|
||||
) -> Result<Pyproject> {
|
||||
) -> Pyproject {
|
||||
// Extract the Flake8 section.
|
||||
let flake8 = config
|
||||
.get("flake8")
|
||||
@@ -103,16 +103,16 @@ pub fn convert(
|
||||
|
||||
// Parse each supported option.
|
||||
let mut options = Options::default();
|
||||
let mut flake8_annotations = flake8_annotations::settings::Options::default();
|
||||
let mut flake8_bugbear = flake8_bugbear::settings::Options::default();
|
||||
let mut flake8_builtins = flake8_builtins::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::options::Options::default();
|
||||
let mut mccabe = mccabe::settings::Options::default();
|
||||
let mut pep8_naming = pep8_naming::settings::Options::default();
|
||||
let mut pydocstyle = pydocstyle::settings::Options::default();
|
||||
let mut flake8_annotations = Flake8AnnotationsOptions::default();
|
||||
let mut flake8_bugbear = Flake8BugbearOptions::default();
|
||||
let mut flake8_builtins = Flake8BuiltinsOptions::default();
|
||||
let mut flake8_errmsg = Flake8ErrMsgOptions::default();
|
||||
let mut flake8_pytest_style = Flake8PytestStyleOptions::default();
|
||||
let mut flake8_quotes = Flake8QuotesOptions::default();
|
||||
let mut flake8_tidy_imports = Flake8TidyImportsOptions::default();
|
||||
let mut mccabe = McCabeOptions::default();
|
||||
let mut pep8_naming = Pep8NamingOptions::default();
|
||||
let mut pydocstyle = PydocstyleOptions::default();
|
||||
for (key, value) in flake8 {
|
||||
if let Some(value) = value {
|
||||
match key.as_str() {
|
||||
@@ -120,10 +120,8 @@ pub fn convert(
|
||||
"builtins" => {
|
||||
options.builtins = Some(parser::parse_strings(value.as_ref()));
|
||||
}
|
||||
"max-line-length" | "max_line_length" => match value.parse::<usize>() {
|
||||
Ok(line_length) => {
|
||||
options.line_length = Some(LineLength::from(line_length));
|
||||
}
|
||||
"max-line-length" | "max_line_length" => match LineLength::from_str(value) {
|
||||
Ok(line_length) => options.line_length = Some(line_length),
|
||||
Err(e) => {
|
||||
warn_user!("Unable to parse '{key}' property: {e}");
|
||||
}
|
||||
@@ -372,41 +370,41 @@ pub fn convert(
|
||||
.sorted_by_key(RuleSelector::prefix_and_code)
|
||||
.collect(),
|
||||
);
|
||||
if flake8_annotations != flake8_annotations::settings::Options::default() {
|
||||
if flake8_annotations != Flake8AnnotationsOptions::default() {
|
||||
options.flake8_annotations = Some(flake8_annotations);
|
||||
}
|
||||
if flake8_bugbear != flake8_bugbear::settings::Options::default() {
|
||||
if flake8_bugbear != Flake8BugbearOptions::default() {
|
||||
options.flake8_bugbear = Some(flake8_bugbear);
|
||||
}
|
||||
if flake8_builtins != flake8_builtins::settings::Options::default() {
|
||||
if flake8_builtins != Flake8BuiltinsOptions::default() {
|
||||
options.flake8_builtins = Some(flake8_builtins);
|
||||
}
|
||||
if flake8_errmsg != flake8_errmsg::settings::Options::default() {
|
||||
if flake8_errmsg != Flake8ErrMsgOptions::default() {
|
||||
options.flake8_errmsg = Some(flake8_errmsg);
|
||||
}
|
||||
if flake8_pytest_style != flake8_pytest_style::settings::Options::default() {
|
||||
if flake8_pytest_style != Flake8PytestStyleOptions::default() {
|
||||
options.flake8_pytest_style = Some(flake8_pytest_style);
|
||||
}
|
||||
if flake8_quotes != flake8_quotes::settings::Options::default() {
|
||||
if flake8_quotes != Flake8QuotesOptions::default() {
|
||||
options.flake8_quotes = Some(flake8_quotes);
|
||||
}
|
||||
if flake8_tidy_imports != flake8_tidy_imports::options::Options::default() {
|
||||
if flake8_tidy_imports != Flake8TidyImportsOptions::default() {
|
||||
options.flake8_tidy_imports = Some(flake8_tidy_imports);
|
||||
}
|
||||
if mccabe != mccabe::settings::Options::default() {
|
||||
if mccabe != McCabeOptions::default() {
|
||||
options.mccabe = Some(mccabe);
|
||||
}
|
||||
if pep8_naming != pep8_naming::settings::Options::default() {
|
||||
if pep8_naming != Pep8NamingOptions::default() {
|
||||
options.pep8_naming = Some(pep8_naming);
|
||||
}
|
||||
if pydocstyle != pydocstyle::settings::Options::default() {
|
||||
if pydocstyle != PydocstyleOptions::default() {
|
||||
options.pydocstyle = Some(pydocstyle);
|
||||
}
|
||||
|
||||
// Extract any settings from the existing `pyproject.toml`.
|
||||
if let Some(black) = &external_config.black {
|
||||
if let Some(line_length) = &black.line_length {
|
||||
options.line_length = Some(LineLength::from(*line_length));
|
||||
options.line_length = Some(*line_length);
|
||||
}
|
||||
|
||||
if let Some(target_version) = &black.target_version {
|
||||
@@ -439,7 +437,7 @@ pub fn convert(
|
||||
}
|
||||
|
||||
// Create the pyproject.toml.
|
||||
Ok(Pyproject::new(options))
|
||||
Pyproject::new(options)
|
||||
}
|
||||
|
||||
/// Resolve the set of enabled `RuleSelector` values for the given
|
||||
@@ -458,19 +456,20 @@ mod tests {
|
||||
use anyhow::Result;
|
||||
use itertools::Itertools;
|
||||
use pep440_rs::VersionSpecifiers;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use crate::flake8_to_ruff::converter::DEFAULT_SELECTORS;
|
||||
use crate::flake8_to_ruff::pep621::Project;
|
||||
use crate::flake8_to_ruff::ExternalConfig;
|
||||
use crate::line_width::LineLength;
|
||||
use crate::registry::Linter;
|
||||
use crate::rule_selector::RuleSelector;
|
||||
use crate::rules::pydocstyle::settings::Convention;
|
||||
use crate::rules::{flake8_quotes, pydocstyle};
|
||||
use crate::settings::options::Options;
|
||||
use crate::settings::pyproject::Pyproject;
|
||||
use crate::settings::types::PythonVersion;
|
||||
use pretty_assertions::assert_eq;
|
||||
use ruff::line_width::LineLength;
|
||||
use ruff::registry::Linter;
|
||||
use ruff::rule_selector::RuleSelector;
|
||||
use ruff::rules::flake8_quotes;
|
||||
use ruff::rules::pydocstyle::settings::Convention;
|
||||
use ruff::settings::types::PythonVersion;
|
||||
use ruff_workspace::options::{Flake8QuotesOptions, Options, PydocstyleOptions};
|
||||
use ruff_workspace::pyproject::Pyproject;
|
||||
|
||||
use crate::converter::DEFAULT_SELECTORS;
|
||||
use crate::pep621::Project;
|
||||
use crate::ExternalConfig;
|
||||
|
||||
use super::super::plugin::Plugin;
|
||||
use super::convert;
|
||||
@@ -491,20 +490,18 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_converts_empty() -> Result<()> {
|
||||
fn it_converts_empty() {
|
||||
let actual = convert(
|
||||
&HashMap::from([("flake8".to_string(), HashMap::default())]),
|
||||
&ExternalConfig::default(),
|
||||
None,
|
||||
)?;
|
||||
);
|
||||
let expected = Pyproject::new(default_options([]));
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_converts_dashes() -> Result<()> {
|
||||
fn it_converts_dashes() {
|
||||
let actual = convert(
|
||||
&HashMap::from([(
|
||||
"flake8".to_string(),
|
||||
@@ -512,18 +509,16 @@ mod tests {
|
||||
)]),
|
||||
&ExternalConfig::default(),
|
||||
Some(vec![]),
|
||||
)?;
|
||||
);
|
||||
let expected = Pyproject::new(Options {
|
||||
line_length: Some(LineLength::from(100)),
|
||||
line_length: Some(LineLength::try_from(100).unwrap()),
|
||||
..default_options([])
|
||||
});
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_converts_underscores() -> Result<()> {
|
||||
fn it_converts_underscores() {
|
||||
let actual = convert(
|
||||
&HashMap::from([(
|
||||
"flake8".to_string(),
|
||||
@@ -531,18 +526,16 @@ mod tests {
|
||||
)]),
|
||||
&ExternalConfig::default(),
|
||||
Some(vec![]),
|
||||
)?;
|
||||
);
|
||||
let expected = Pyproject::new(Options {
|
||||
line_length: Some(LineLength::from(100)),
|
||||
line_length: Some(LineLength::try_from(100).unwrap()),
|
||||
..default_options([])
|
||||
});
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_ignores_parse_errors() -> Result<()> {
|
||||
fn it_ignores_parse_errors() {
|
||||
let actual = convert(
|
||||
&HashMap::from([(
|
||||
"flake8".to_string(),
|
||||
@@ -550,15 +543,13 @@ mod tests {
|
||||
)]),
|
||||
&ExternalConfig::default(),
|
||||
Some(vec![]),
|
||||
)?;
|
||||
);
|
||||
let expected = Pyproject::new(default_options([]));
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_converts_plugin_options() -> Result<()> {
|
||||
fn it_converts_plugin_options() {
|
||||
let actual = convert(
|
||||
&HashMap::from([(
|
||||
"flake8".to_string(),
|
||||
@@ -566,9 +557,9 @@ mod tests {
|
||||
)]),
|
||||
&ExternalConfig::default(),
|
||||
Some(vec![]),
|
||||
)?;
|
||||
);
|
||||
let expected = Pyproject::new(Options {
|
||||
flake8_quotes: Some(flake8_quotes::settings::Options {
|
||||
flake8_quotes: Some(Flake8QuotesOptions {
|
||||
inline_quotes: Some(flake8_quotes::settings::Quote::Single),
|
||||
multiline_quotes: None,
|
||||
docstring_quotes: None,
|
||||
@@ -577,12 +568,10 @@ mod tests {
|
||||
..default_options([])
|
||||
});
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_converts_docstring_conventions() -> Result<()> {
|
||||
fn it_converts_docstring_conventions() {
|
||||
let actual = convert(
|
||||
&HashMap::from([(
|
||||
"flake8".to_string(),
|
||||
@@ -593,9 +582,9 @@ mod tests {
|
||||
)]),
|
||||
&ExternalConfig::default(),
|
||||
Some(vec![Plugin::Flake8Docstrings]),
|
||||
)?;
|
||||
);
|
||||
let expected = Pyproject::new(Options {
|
||||
pydocstyle: Some(pydocstyle::settings::Options {
|
||||
pydocstyle: Some(PydocstyleOptions {
|
||||
convention: Some(Convention::Numpy),
|
||||
ignore_decorators: None,
|
||||
property_decorators: None,
|
||||
@@ -603,12 +592,10 @@ mod tests {
|
||||
..default_options([Linter::Pydocstyle.into()])
|
||||
});
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_infers_plugins_if_omitted() -> Result<()> {
|
||||
fn it_infers_plugins_if_omitted() {
|
||||
let actual = convert(
|
||||
&HashMap::from([(
|
||||
"flake8".to_string(),
|
||||
@@ -616,9 +603,9 @@ mod tests {
|
||||
)]),
|
||||
&ExternalConfig::default(),
|
||||
None,
|
||||
)?;
|
||||
);
|
||||
let expected = Pyproject::new(Options {
|
||||
flake8_quotes: Some(flake8_quotes::settings::Options {
|
||||
flake8_quotes: Some(Flake8QuotesOptions {
|
||||
inline_quotes: Some(flake8_quotes::settings::Quote::Single),
|
||||
multiline_quotes: None,
|
||||
docstring_quotes: None,
|
||||
@@ -627,8 +614,6 @@ mod tests {
|
||||
..default_options([Linter::Flake8Quotes.into()])
|
||||
});
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -642,7 +627,7 @@ mod tests {
|
||||
..ExternalConfig::default()
|
||||
},
|
||||
Some(vec![]),
|
||||
)?;
|
||||
);
|
||||
let expected = Pyproject::new(Options {
|
||||
target_version: Some(PythonVersion::Py38),
|
||||
..default_options([])
|
||||
10
crates/flake8_to_ruff/src/external_config.rs
Normal file
10
crates/flake8_to_ruff/src/external_config.rs
Normal file
@@ -0,0 +1,10 @@
|
||||
use super::black::Black;
|
||||
use super::isort::Isort;
|
||||
use super::pep621::Project;
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct ExternalConfig<'a> {
|
||||
pub(crate) black: Option<&'a Black>,
|
||||
pub(crate) isort: Option<&'a Isort>,
|
||||
pub(crate) project: Option<&'a Project>,
|
||||
}
|
||||
@@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
/// The [isort configuration](https://pycqa.github.io/isort/docs/configuration/config_files.html).
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
pub struct Isort {
|
||||
pub(crate) struct Isort {
|
||||
#[serde(alias = "src-paths", alias = "src_paths")]
|
||||
pub src_paths: Option<Vec<String>>,
|
||||
pub(crate) src_paths: Option<Vec<String>>,
|
||||
}
|
||||
@@ -1,12 +1,24 @@
|
||||
//! Utility to generate Ruff's `pyproject.toml` section from a Flake8 INI file.
|
||||
|
||||
mod black;
|
||||
mod converter;
|
||||
mod external_config;
|
||||
mod isort;
|
||||
mod parser;
|
||||
mod pep621;
|
||||
mod plugin;
|
||||
mod pyproject;
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
use anyhow::Result;
|
||||
use clap::Parser;
|
||||
use configparser::ini::Ini;
|
||||
|
||||
use ruff::flake8_to_ruff::{self, ExternalConfig};
|
||||
use crate::converter::convert;
|
||||
use crate::external_config::ExternalConfig;
|
||||
use crate::plugin::Plugin;
|
||||
use crate::pyproject::parse;
|
||||
use ruff::logging::{set_up_logging, LogLevel};
|
||||
|
||||
#[derive(Parser)]
|
||||
@@ -25,7 +37,7 @@ struct Args {
|
||||
pyproject: Option<PathBuf>,
|
||||
/// List of plugins to enable.
|
||||
#[arg(long, value_delimiter = ',')]
|
||||
plugin: Option<Vec<flake8_to_ruff::Plugin>>,
|
||||
plugin: Option<Vec<Plugin>>,
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
@@ -39,7 +51,7 @@ fn main() -> Result<()> {
|
||||
let config = ini.load(args.file).map_err(|msg| anyhow::anyhow!(msg))?;
|
||||
|
||||
// Read the pyproject.toml file.
|
||||
let pyproject = args.pyproject.map(flake8_to_ruff::parse).transpose()?;
|
||||
let pyproject = args.pyproject.map(parse).transpose()?;
|
||||
let external_config = pyproject
|
||||
.as_ref()
|
||||
.and_then(|pyproject| pyproject.tool.as_ref())
|
||||
@@ -57,7 +69,7 @@ fn main() -> Result<()> {
|
||||
};
|
||||
|
||||
// Create Ruff's pyproject.toml section.
|
||||
let pyproject = flake8_to_ruff::convert(&config, &external_config, args.plugin)?;
|
||||
let pyproject = convert(&config, &external_config, args.plugin);
|
||||
|
||||
#[allow(clippy::print_stdout)]
|
||||
{
|
||||
|
||||
@@ -3,12 +3,10 @@ use std::str::FromStr;
|
||||
use anyhow::{bail, Result};
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use ruff::settings::types::PatternPrefixPair;
|
||||
use ruff::{warn_user, RuleSelector};
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::rule_selector::RuleSelector;
|
||||
use crate::settings::types::PatternPrefixPair;
|
||||
use crate::warn_user;
|
||||
|
||||
static COMMA_SEPARATED_LIST_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"[,\s]").unwrap());
|
||||
|
||||
/// Parse a comma-separated list of `RuleSelector` values (e.g.,
|
||||
@@ -194,11 +192,11 @@ pub(crate) fn collect_per_file_ignores(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use anyhow::Result;
|
||||
use ruff::RuleSelector;
|
||||
|
||||
use crate::codes;
|
||||
use crate::registry::Linter;
|
||||
use crate::rule_selector::RuleSelector;
|
||||
use crate::settings::types::PatternPrefixPair;
|
||||
use ruff::codes;
|
||||
use ruff::registry::Linter;
|
||||
use ruff::settings::types::PatternPrefixPair;
|
||||
|
||||
use super::{parse_files_to_codes_mapping, parse_prefix_codes, parse_strings};
|
||||
|
||||
@@ -4,7 +4,7 @@ use pep440_rs::VersionSpecifiers;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
pub struct Project {
|
||||
pub(crate) struct Project {
|
||||
#[serde(alias = "requires-python", alias = "requires_python")]
|
||||
pub requires_python: Option<VersionSpecifiers>,
|
||||
pub(crate) requires_python: Option<VersionSpecifiers>,
|
||||
}
|
||||
@@ -3,9 +3,9 @@ use std::fmt;
|
||||
use std::str::FromStr;
|
||||
|
||||
use anyhow::anyhow;
|
||||
|
||||
use crate::registry::Linter;
|
||||
use crate::rule_selector::RuleSelector;
|
||||
use ruff::registry::Linter;
|
||||
use ruff::settings::types::PreviewMode;
|
||||
use ruff::RuleSelector;
|
||||
|
||||
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
|
||||
pub enum Plugin {
|
||||
@@ -332,7 +332,7 @@ pub(crate) fn infer_plugins_from_codes(selectors: &HashSet<RuleSelector>) -> Vec
|
||||
.filter(|plugin| {
|
||||
for selector in selectors {
|
||||
if selector
|
||||
.into_iter()
|
||||
.rules(PreviewMode::Disabled)
|
||||
.any(|rule| Linter::from(plugin).rules().any(|r| r == rule))
|
||||
{
|
||||
return true;
|
||||
@@ -8,18 +8,18 @@ use super::isort::Isort;
|
||||
use super::pep621::Project;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Tools {
|
||||
pub black: Option<Black>,
|
||||
pub isort: Option<Isort>,
|
||||
pub(crate) struct Tools {
|
||||
pub(crate) black: Option<Black>,
|
||||
pub(crate) isort: Option<Isort>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Pyproject {
|
||||
pub tool: Option<Tools>,
|
||||
pub project: Option<Project>,
|
||||
pub(crate) struct Pyproject {
|
||||
pub(crate) tool: Option<Tools>,
|
||||
pub(crate) project: Option<Project>,
|
||||
}
|
||||
|
||||
pub fn parse<P: AsRef<Path>>(path: P) -> Result<Pyproject> {
|
||||
pub(crate) fn parse<P: AsRef<Path>>(path: P) -> Result<Pyproject> {
|
||||
let contents = std::fs::read_to_string(path)?;
|
||||
let pyproject = toml::from_str::<Pyproject>(&contents)?;
|
||||
Ok(pyproject)
|
||||
@@ -36,11 +36,9 @@ bitflags = { workspace = true }
|
||||
chrono = { workspace = true }
|
||||
clap = { workspace = true, features = ["derive", "string"], optional = true }
|
||||
colored = { workspace = true }
|
||||
dirs = { version = "5.0.0" }
|
||||
fern = { version = "0.6.1" }
|
||||
glob = { workspace = true }
|
||||
globset = { workspace = true }
|
||||
ignore = { workspace = true }
|
||||
imperative = { version = "1.0.4" }
|
||||
is-macro = { workspace = true }
|
||||
itertools = { workspace = true }
|
||||
@@ -68,7 +66,6 @@ serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
serde_with = { version = "3.0.0" }
|
||||
similar = { workspace = true }
|
||||
shellexpand = { workspace = true }
|
||||
smallvec = { workspace = true }
|
||||
strum = { workspace = true }
|
||||
strum_macros = { workspace = true }
|
||||
|
||||
@@ -37,3 +37,6 @@ map(lambda x: lambda x: x, range(4))
|
||||
map(lambda x=1: x, nums)
|
||||
map(lambda *args: len(args), range(4))
|
||||
map(lambda **kwargs: len(kwargs), range(4))
|
||||
|
||||
# Ok because multiple arguments are allowed.
|
||||
dict(map(lambda k, v: (k, v), keys, values))
|
||||
|
||||
9
crates/ruff/resources/test/fixtures/flake8_import_conventions/tricky.py
vendored
Normal file
9
crates/ruff/resources/test/fixtures/flake8_import_conventions/tricky.py
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
"""Test cases for difficult renames."""
|
||||
|
||||
|
||||
def rename_global():
|
||||
try:
|
||||
global pandas
|
||||
import pandas
|
||||
except ImportError:
|
||||
return False
|
||||
@@ -68,3 +68,14 @@ import ctypes
|
||||
|
||||
# OK
|
||||
raise ctypes.WinError(1)
|
||||
|
||||
|
||||
# RSE102
|
||||
raise IndexError()from ZeroDivisionError
|
||||
|
||||
raise IndexError()\
|
||||
from ZeroDivisionError
|
||||
|
||||
raise IndexError() from ZeroDivisionError
|
||||
|
||||
raise IndexError();
|
||||
|
||||
@@ -18,11 +18,11 @@ def f():
|
||||
result = []
|
||||
for i in items:
|
||||
if i % 2:
|
||||
result.append(i) # PERF401
|
||||
result.append(i) # Ok
|
||||
elif i % 2:
|
||||
result.append(i) # PERF401
|
||||
result.append(i)
|
||||
else:
|
||||
result.append(i) # PERF401
|
||||
result.append(i)
|
||||
|
||||
|
||||
def f():
|
||||
@@ -60,3 +60,15 @@ def f():
|
||||
for i in range(20):
|
||||
foo.fibonacci.append(sum(foo.fibonacci[-2:])) # OK
|
||||
print(foo.fibonacci)
|
||||
|
||||
|
||||
class Foo:
|
||||
def append(self, x):
|
||||
pass
|
||||
|
||||
|
||||
def f():
|
||||
items = [1, 2, 3, 4]
|
||||
result = Foo()
|
||||
for i in items:
|
||||
result.append(i) # Ok
|
||||
|
||||
@@ -24,3 +24,22 @@ def f():
|
||||
result = {}
|
||||
for i in items:
|
||||
result[i].append(i * i) # OK
|
||||
|
||||
|
||||
class Foo:
|
||||
def append(self, x):
|
||||
pass
|
||||
|
||||
|
||||
def f():
|
||||
items = [1, 2, 3, 4]
|
||||
result = Foo()
|
||||
for i in items:
|
||||
result.append(i) # OK
|
||||
|
||||
|
||||
def f():
|
||||
import sys
|
||||
|
||||
for path in ("foo", "bar"):
|
||||
sys.path.append(path) # OK
|
||||
|
||||
@@ -59,3 +59,35 @@ def f() -> None:
|
||||
x = Union["str", "int"]
|
||||
x: Union[str, int]
|
||||
x: Union["str", "int"]
|
||||
|
||||
|
||||
def f(x: Union[int : float]) -> None:
|
||||
...
|
||||
|
||||
|
||||
def f(x: Union[str, int : float]) -> None:
|
||||
...
|
||||
|
||||
|
||||
def f(x: Union[x := int]) -> None:
|
||||
...
|
||||
|
||||
|
||||
def f(x: Union[str, x := int]) -> None:
|
||||
...
|
||||
|
||||
|
||||
def f(x: Union[lambda: int]) -> None:
|
||||
...
|
||||
|
||||
|
||||
def f(x: Union[str, lambda: int]) -> None:
|
||||
...
|
||||
|
||||
|
||||
def f(x: Optional[int : float]) -> None:
|
||||
...
|
||||
|
||||
|
||||
def f(x: Optional[str, int : float]) -> None:
|
||||
...
|
||||
|
||||
@@ -22,3 +22,4 @@ MyType = typing.NamedTuple("MyType", a=int, b=tuple[str, ...])
|
||||
# unfixable
|
||||
MyType = typing.NamedTuple("MyType", [("a", int)], [("b", str)])
|
||||
MyType = typing.NamedTuple("MyType", [("a", int)], b=str)
|
||||
MyType = typing.NamedTuple(typename="MyType", a=int, b=str)
|
||||
|
||||
169
crates/ruff/resources/test/fixtures/refurb/FURB113.py
vendored
Normal file
169
crates/ruff/resources/test/fixtures/refurb/FURB113.py
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
from typing import List
|
||||
|
||||
|
||||
def func():
|
||||
pass
|
||||
|
||||
|
||||
nums = []
|
||||
nums2 = []
|
||||
nums3: list[int] = func()
|
||||
nums4: List[int]
|
||||
|
||||
|
||||
class C:
|
||||
def append(self, x):
|
||||
pass
|
||||
|
||||
|
||||
# Errors.
|
||||
|
||||
|
||||
# FURB113
|
||||
nums.append(1)
|
||||
nums.append(2)
|
||||
pass
|
||||
|
||||
|
||||
# FURB113
|
||||
nums3.append(1)
|
||||
nums3.append(2)
|
||||
pass
|
||||
|
||||
|
||||
# FURB113
|
||||
nums4.append(1)
|
||||
nums4.append(2)
|
||||
pass
|
||||
|
||||
|
||||
# FURB113
|
||||
nums.append(1)
|
||||
nums2.append(1)
|
||||
nums.append(2)
|
||||
nums.append(3)
|
||||
pass
|
||||
|
||||
|
||||
# FURB113
|
||||
nums.append(1)
|
||||
nums2.append(1)
|
||||
nums.append(2)
|
||||
# FURB113
|
||||
nums3.append(1)
|
||||
nums.append(3)
|
||||
# FURB113
|
||||
nums4.append(1)
|
||||
nums4.append(2)
|
||||
nums3.append(2)
|
||||
pass
|
||||
|
||||
# FURB113
|
||||
nums.append(1)
|
||||
nums.append(2)
|
||||
nums.append(3)
|
||||
|
||||
|
||||
if True:
|
||||
# FURB113
|
||||
nums.append(1)
|
||||
nums.append(2)
|
||||
|
||||
|
||||
if True:
|
||||
# FURB113
|
||||
nums.append(1)
|
||||
nums.append(2)
|
||||
pass
|
||||
|
||||
|
||||
if True:
|
||||
# FURB113
|
||||
nums.append(1)
|
||||
nums2.append(1)
|
||||
nums.append(2)
|
||||
nums.append(3)
|
||||
|
||||
|
||||
def yes_one(x: list[int]):
|
||||
# FURB113
|
||||
x.append(1)
|
||||
x.append(2)
|
||||
|
||||
|
||||
def yes_two(x: List[int]):
|
||||
# FURB113
|
||||
x.append(1)
|
||||
x.append(2)
|
||||
|
||||
|
||||
def yes_three(*, x: list[int]):
|
||||
# FURB113
|
||||
x.append(1)
|
||||
x.append(2)
|
||||
|
||||
|
||||
def yes_four(x: list[int], /):
|
||||
# FURB113
|
||||
x.append(1)
|
||||
x.append(2)
|
||||
|
||||
|
||||
def yes_five(x: list[int], y: list[int]):
|
||||
# FURB113
|
||||
x.append(1)
|
||||
x.append(2)
|
||||
y.append(1)
|
||||
x.append(3)
|
||||
|
||||
|
||||
def yes_six(x: list):
|
||||
# FURB113
|
||||
x.append(1)
|
||||
x.append(2)
|
||||
|
||||
|
||||
# Non-errors.
|
||||
|
||||
nums.append(1)
|
||||
pass
|
||||
nums.append(2)
|
||||
|
||||
|
||||
if True:
|
||||
nums.append(1)
|
||||
pass
|
||||
nums.append(2)
|
||||
|
||||
|
||||
nums.append(1)
|
||||
pass
|
||||
|
||||
|
||||
nums.append(1)
|
||||
nums2.append(2)
|
||||
|
||||
|
||||
nums.copy()
|
||||
nums.copy()
|
||||
|
||||
|
||||
c = C()
|
||||
c.append(1)
|
||||
c.append(2)
|
||||
|
||||
|
||||
def not_one(x):
|
||||
x.append(1)
|
||||
x.append(2)
|
||||
|
||||
|
||||
def not_two(x: C):
|
||||
x.append(1)
|
||||
x.append(2)
|
||||
|
||||
|
||||
# redefining a list variable with a new type shouldn't confuse ruff.
|
||||
nums2 = C()
|
||||
nums2.append(1)
|
||||
nums2.append(2)
|
||||
64
crates/ruff/resources/test/fixtures/refurb/FURB131.py
vendored
Normal file
64
crates/ruff/resources/test/fixtures/refurb/FURB131.py
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
from typing import Dict, List
|
||||
|
||||
names = {"key": "value"}
|
||||
nums = [1, 2, 3]
|
||||
x = 42
|
||||
y = "hello"
|
||||
|
||||
# these should match
|
||||
|
||||
# FURB131
|
||||
del nums[:]
|
||||
|
||||
|
||||
# FURB131
|
||||
del names[:]
|
||||
|
||||
|
||||
# FURB131
|
||||
del x, nums[:]
|
||||
|
||||
|
||||
# FURB131
|
||||
del y, names[:], x
|
||||
|
||||
|
||||
def yes_one(x: list[int]):
|
||||
# FURB131
|
||||
del x[:]
|
||||
|
||||
|
||||
def yes_two(x: dict[int, str]):
|
||||
# FURB131
|
||||
del x[:]
|
||||
|
||||
|
||||
def yes_three(x: List[int]):
|
||||
# FURB131
|
||||
del x[:]
|
||||
|
||||
|
||||
def yes_four(x: Dict[int, str]):
|
||||
# FURB131
|
||||
del x[:]
|
||||
|
||||
|
||||
# these should not
|
||||
|
||||
del names["key"]
|
||||
del nums[0]
|
||||
|
||||
x = 1
|
||||
del x
|
||||
|
||||
|
||||
del nums[1:2]
|
||||
|
||||
|
||||
del nums[:2]
|
||||
del nums[1:]
|
||||
del nums[::2]
|
||||
|
||||
|
||||
def no_one(param):
|
||||
del param[:]
|
||||
80
crates/ruff/resources/test/fixtures/refurb/FURB132.py
vendored
Normal file
80
crates/ruff/resources/test/fixtures/refurb/FURB132.py
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
from typing import Set
|
||||
from some.package.name import foo, bar
|
||||
|
||||
|
||||
s = set()
|
||||
s2 = {}
|
||||
s3: set[int] = foo()
|
||||
|
||||
# these should match
|
||||
|
||||
# FURB132
|
||||
if "x" in s:
|
||||
s.remove("x")
|
||||
|
||||
|
||||
# FURB132
|
||||
if "x" in s2:
|
||||
s2.remove("x")
|
||||
|
||||
|
||||
# FURB132
|
||||
if "x" in s3:
|
||||
s3.remove("x")
|
||||
|
||||
|
||||
var = "y"
|
||||
# FURB132
|
||||
if var in s:
|
||||
s.remove(var)
|
||||
|
||||
|
||||
if f"{var}:{var}" in s:
|
||||
s.remove(f"{var}:{var}")
|
||||
|
||||
|
||||
def identity(x):
|
||||
return x
|
||||
|
||||
|
||||
# TODO: FURB132
|
||||
if identity("x") in s2:
|
||||
s2.remove(identity("x"))
|
||||
|
||||
|
||||
# these should not
|
||||
|
||||
if "x" in s:
|
||||
s.remove("y")
|
||||
|
||||
s.discard("x")
|
||||
|
||||
s2 = set()
|
||||
|
||||
if "x" in s:
|
||||
s2.remove("x")
|
||||
|
||||
if "x" in s:
|
||||
s.remove("x")
|
||||
print("removed item")
|
||||
|
||||
if bar() in s:
|
||||
# bar() might have a side effect
|
||||
s.remove(bar())
|
||||
|
||||
if "x" in s:
|
||||
s.remove("x")
|
||||
else:
|
||||
print("not found")
|
||||
|
||||
class Container:
|
||||
def remove(self, item) -> None:
|
||||
return
|
||||
|
||||
def __contains__(self, other) -> bool:
|
||||
return True
|
||||
|
||||
c = Container()
|
||||
|
||||
if "x" in c:
|
||||
c.remove("x")
|
||||
@@ -4,8 +4,8 @@ use anyhow::{bail, Result};
|
||||
use libcst_native::{
|
||||
Codegen, CodegenState, ImportNames, ParenthesizableWhitespace, SmallStatement, Statement,
|
||||
};
|
||||
use ruff_python_ast::{Ranged, Stmt};
|
||||
|
||||
use ruff_python_ast::Stmt;
|
||||
use ruff_python_codegen::Stylist;
|
||||
use ruff_source_file::Locator;
|
||||
|
||||
@@ -38,7 +38,7 @@ pub(crate) fn remove_imports<'a>(
|
||||
locator: &Locator,
|
||||
stylist: &Stylist,
|
||||
) -> Result<Option<String>> {
|
||||
let module_text = locator.slice(stmt.range());
|
||||
let module_text = locator.slice(stmt);
|
||||
let mut tree = match_statement(module_text)?;
|
||||
|
||||
let Statement::Simple(body) = &mut tree else {
|
||||
@@ -117,7 +117,7 @@ pub(crate) fn retain_imports(
|
||||
locator: &Locator,
|
||||
stylist: &Stylist,
|
||||
) -> Result<String> {
|
||||
let module_text = locator.slice(stmt.range());
|
||||
let module_text = locator.slice(stmt);
|
||||
let mut tree = match_statement(module_text)?;
|
||||
|
||||
let Statement::Simple(body) = &mut tree else {
|
||||
|
||||
@@ -3,15 +3,14 @@
|
||||
use anyhow::{Context, Result};
|
||||
|
||||
use ruff_diagnostics::Edit;
|
||||
use ruff_python_ast::{self as ast, Arguments, ExceptHandler, Expr, Keyword, Ranged, Stmt};
|
||||
use ruff_python_ast::{self as ast, Arguments, ExceptHandler, Expr, Keyword, Stmt};
|
||||
use ruff_python_codegen::Stylist;
|
||||
use ruff_python_index::Indexer;
|
||||
|
||||
use ruff_python_trivia::{
|
||||
has_leading_content, is_python_whitespace, PythonWhitespace, SimpleTokenKind, SimpleTokenizer,
|
||||
};
|
||||
use ruff_source_file::{Locator, NewlineWithTrailingNewline};
|
||||
use ruff_text_size::{TextLen, TextSize};
|
||||
use ruff_text_size::{Ranged, TextLen, TextSize};
|
||||
|
||||
use crate::autofix::codemods;
|
||||
|
||||
@@ -254,10 +253,9 @@ fn next_stmt_break(semicolon: TextSize, locator: &Locator) -> TextSize {
|
||||
mod tests {
|
||||
use anyhow::Result;
|
||||
|
||||
use ruff_python_ast::Ranged;
|
||||
use ruff_python_parser::parse_suite;
|
||||
use ruff_source_file::Locator;
|
||||
use ruff_text_size::TextSize;
|
||||
use ruff_text_size::{Ranged, TextSize};
|
||||
|
||||
use crate::autofix::edits::{next_stmt_break, trailing_semicolon};
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use itertools::Itertools;
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use ruff_text_size::{TextLen, TextRange, TextSize};
|
||||
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Edit, Fix, IsolationLevel};
|
||||
@@ -138,11 +138,9 @@ fn cmp_fix(rule1: Rule, rule2: Rule, fix1: &Fix, fix2: &Fix) -> std::cmp::Orderi
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use ruff_text_size::TextSize;
|
||||
use ruff_text_size::{Ranged, TextSize};
|
||||
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
use ruff_diagnostics::Edit;
|
||||
use ruff_diagnostics::Fix;
|
||||
use ruff_diagnostics::{Diagnostic, Edit, Fix};
|
||||
use ruff_source_file::Locator;
|
||||
|
||||
use crate::autofix::source_map::SourceMarker;
|
||||
|
||||
@@ -9,6 +9,10 @@ impl SourceCodeSnippet {
|
||||
Self(source_code)
|
||||
}
|
||||
|
||||
pub(crate) fn from_str(source_code: &str) -> Self {
|
||||
Self(source_code.to_string())
|
||||
}
|
||||
|
||||
/// Return the full snippet for user-facing display, or `None` if the snippet should be
|
||||
/// truncated.
|
||||
pub(crate) fn full_display(&self) -> Option<&str> {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use ruff_text_size::TextSize;
|
||||
use ruff_text_size::{Ranged, TextSize};
|
||||
|
||||
use ruff_diagnostics::Edit;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use ruff_diagnostics::{Diagnostic, Fix};
|
||||
use ruff_python_ast::Ranged;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::codes::Rule;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
use ruff_python_ast::Ranged;
|
||||
use ruff_python_semantic::analyze::visibility;
|
||||
use ruff_python_semantic::{Binding, BindingKind, ScopeKind};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::codes::Rule;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use ruff_python_ast::str::raw_contents_range;
|
||||
use ruff_python_ast::Ranged;
|
||||
use ruff_text_size::TextRange;
|
||||
use ruff_text_size::{Ranged, TextRange};
|
||||
|
||||
use ruff_python_semantic::{BindingKind, ContextualizedDefinition, Export};
|
||||
|
||||
@@ -164,9 +163,9 @@ pub(crate) fn definitions(checker: &mut Checker) {
|
||||
continue;
|
||||
};
|
||||
|
||||
let contents = checker.locator.slice(expr.range());
|
||||
let contents = checker.locator().slice(expr);
|
||||
|
||||
let indentation = checker.locator.slice(TextRange::new(
|
||||
let indentation = checker.locator().slice(TextRange::new(
|
||||
checker.locator.line_start(expr.start()),
|
||||
expr.start(),
|
||||
));
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use ruff_python_ast::{self as ast, ExceptHandler, Ranged};
|
||||
use ruff_python_ast::{self as ast, ExceptHandler};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::Rule;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use ruff_python_ast::{self as ast, Arguments, Constant, Expr, ExprContext, Operator, Ranged};
|
||||
use ruff_python_ast::{self as ast, Arguments, Constant, Expr, ExprContext, Operator};
|
||||
use ruff_python_literal::cformat::{CFormatError, CFormatErrorType};
|
||||
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
@@ -6,6 +6,7 @@ use ruff_diagnostics::Diagnostic;
|
||||
use ruff_python_ast::types::Node;
|
||||
use ruff_python_semantic::analyze::typing;
|
||||
use ruff_python_semantic::ScopeKind;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::Rule;
|
||||
@@ -1038,12 +1039,7 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
|
||||
}
|
||||
}
|
||||
if checker.enabled(Rule::PrintfStringFormatting) {
|
||||
pyupgrade::rules::printf_string_formatting(
|
||||
checker,
|
||||
expr,
|
||||
right,
|
||||
checker.locator,
|
||||
);
|
||||
pyupgrade::rules::printf_string_formatting(checker, expr, right);
|
||||
}
|
||||
if checker.enabled(Rule::BadStringFormatCharacter) {
|
||||
pylint::rules::bad_string_format_character::percent(checker, expr);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use ruff_python_ast::{Parameter, Ranged};
|
||||
use ruff_python_ast::Parameter;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::codes::Rule;
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
use ruff_python_ast::{self as ast, Expr, Ranged, Stmt};
|
||||
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
use ruff_python_ast::helpers;
|
||||
|
||||
use ruff_python_ast::types::Node;
|
||||
use ruff_python_ast::{self as ast, Expr, Stmt};
|
||||
use ruff_python_semantic::analyze::typing;
|
||||
use ruff_python_semantic::ScopeKind;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::Rule;
|
||||
@@ -14,7 +13,7 @@ use crate::rules::{
|
||||
flake8_django, flake8_errmsg, flake8_import_conventions, flake8_pie, flake8_pyi,
|
||||
flake8_pytest_style, flake8_raise, flake8_return, flake8_simplify, flake8_slots,
|
||||
flake8_tidy_imports, flake8_type_checking, mccabe, pandas_vet, pep8_naming, perflint,
|
||||
pycodestyle, pyflakes, pygrep_hooks, pylint, pyupgrade, ruff, tryceratops,
|
||||
pycodestyle, pyflakes, pygrep_hooks, pylint, pyupgrade, refurb, ruff, tryceratops,
|
||||
};
|
||||
use crate::settings::types::PythonVersion;
|
||||
|
||||
@@ -1057,6 +1056,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
if checker.enabled(Rule::CheckAndRemoveFromSet) {
|
||||
refurb::rules::check_and_remove_from_set(checker, if_);
|
||||
}
|
||||
if checker.source_type.is_stub() {
|
||||
if checker.any_enabled(&[
|
||||
Rule::UnrecognizedVersionInfoCheck,
|
||||
@@ -1460,7 +1462,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
||||
}
|
||||
}
|
||||
}
|
||||
Stmt::Delete(ast::StmtDelete { targets, range: _ }) => {
|
||||
Stmt::Delete(delete @ ast::StmtDelete { targets, range: _ }) => {
|
||||
if checker.enabled(Rule::GlobalStatement) {
|
||||
for target in targets {
|
||||
if let Expr::Name(ast::ExprName { id, .. }) = target {
|
||||
@@ -1468,6 +1470,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if checker.enabled(Rule::DeleteFullSlice) {
|
||||
refurb::rules::delete_full_slice(checker, delete);
|
||||
}
|
||||
}
|
||||
Stmt::Expr(ast::StmtExpr { value, range: _ }) => {
|
||||
if checker.enabled(Rule::UselessComparison) {
|
||||
@@ -1485,6 +1490,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
||||
if checker.enabled(Rule::AsyncioDanglingTask) {
|
||||
ruff::rules::asyncio_dangling_task(checker, value);
|
||||
}
|
||||
if checker.enabled(Rule::RepeatedAppend) {
|
||||
refurb::rules::repeated_append(checker, stmt);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
@@ -32,10 +32,10 @@ use itertools::Itertools;
|
||||
use log::error;
|
||||
use ruff_python_ast::{
|
||||
self as ast, Arguments, Comprehension, Constant, ElifElseClause, ExceptHandler, Expr,
|
||||
ExprContext, Keyword, MatchCase, Parameter, ParameterWithDefault, Parameters, Pattern, Ranged,
|
||||
Stmt, Suite, UnaryOp,
|
||||
ExprContext, Keyword, MatchCase, Parameter, ParameterWithDefault, Parameters, Pattern, Stmt,
|
||||
Suite, UnaryOp,
|
||||
};
|
||||
use ruff_text_size::{TextRange, TextSize};
|
||||
use ruff_text_size::{Ranged, TextRange, TextSize};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, IsolationLevel};
|
||||
use ruff_python_ast::all::{extract_all_names, DunderAllFlags};
|
||||
@@ -1895,6 +1895,8 @@ impl<'a> Checker<'a> {
|
||||
for (name, range) in exports {
|
||||
if let Some(binding_id) = self.semantic.global_scope().get(name) {
|
||||
// Mark anything referenced in `__all__` as used.
|
||||
// TODO(charlie): `range` here should be the range of the name in `__all__`, not
|
||||
// the range of `__all__` itself.
|
||||
self.semantic.add_global_reference(binding_id, range);
|
||||
} else {
|
||||
if self.semantic.global_scope().uses_star_imports() {
|
||||
|
||||
@@ -2,16 +2,15 @@
|
||||
use std::borrow::Cow;
|
||||
use std::path::Path;
|
||||
|
||||
use ruff_python_ast::{self as ast, PySourceType, Ranged, Stmt, Suite};
|
||||
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
use ruff_python_ast::helpers::to_module_path;
|
||||
use ruff_python_ast::imports::{ImportMap, ModuleImport};
|
||||
use ruff_python_ast::statement_visitor::StatementVisitor;
|
||||
use ruff_python_ast::{self as ast, PySourceType, Stmt, Suite};
|
||||
use ruff_python_codegen::Stylist;
|
||||
use ruff_python_index::Indexer;
|
||||
|
||||
use ruff_source_file::Locator;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::directives::IsortDirectives;
|
||||
use crate::registry::Rule;
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
use ruff_diagnostics::{Diagnostic, DiagnosticKind};
|
||||
use ruff_python_ast::Ranged;
|
||||
use ruff_python_codegen::Stylist;
|
||||
use ruff_python_parser::lexer::LexResult;
|
||||
use ruff_python_parser::TokenKind;
|
||||
use ruff_source_file::Locator;
|
||||
use ruff_text_size::TextRange;
|
||||
use ruff_text_size::{Ranged, TextRange};
|
||||
|
||||
use crate::registry::{AsRule, Rule};
|
||||
use crate::rules::pycodestyle::rules::logical_lines::{
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
use std::path::Path;
|
||||
|
||||
use itertools::Itertools;
|
||||
use ruff_python_ast::Ranged;
|
||||
use ruff_text_size::{TextLen, TextRange, TextSize};
|
||||
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Edit, Fix};
|
||||
use ruff_source_file::Locator;
|
||||
@@ -111,7 +110,7 @@ pub(crate) fn check_noqa(
|
||||
Diagnostic::new(UnusedNOQA { codes: None }, directive.range());
|
||||
if settings.rules.should_fix(diagnostic.kind.rule()) {
|
||||
diagnostic
|
||||
.set_fix(Fix::automatic(delete_noqa(directive.range(), locator)));
|
||||
.set_fix(Fix::suggested(delete_noqa(directive.range(), locator)));
|
||||
}
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
@@ -175,12 +174,12 @@ pub(crate) fn check_noqa(
|
||||
);
|
||||
if settings.rules.should_fix(diagnostic.kind.rule()) {
|
||||
if valid_codes.is_empty() {
|
||||
diagnostic.set_fix(Fix::automatic(delete_noqa(
|
||||
diagnostic.set_fix(Fix::suggested(delete_noqa(
|
||||
directive.range(),
|
||||
locator,
|
||||
)));
|
||||
} else {
|
||||
diagnostic.set_fix(Fix::automatic(Edit::range_replacement(
|
||||
diagnostic.set_fix(Fix::suggested(Edit::range_replacement(
|
||||
format!("# noqa: {}", valid_codes.join(", ")),
|
||||
directive.range(),
|
||||
)));
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
//! Lint rules based on checking physical lines.
|
||||
use ruff_text_size::TextSize;
|
||||
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
use ruff_python_codegen::Stylist;
|
||||
use ruff_python_index::Indexer;
|
||||
use ruff_source_file::{Locator, UniversalNewlines};
|
||||
use ruff_text_size::TextSize;
|
||||
|
||||
use crate::registry::Rule;
|
||||
use crate::rules::flake8_copyright::rules::missing_copyright_notice;
|
||||
@@ -99,11 +98,10 @@ pub(crate) fn check_physical_lines(
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use ruff_python_parser::lexer::lex;
|
||||
use ruff_python_parser::Mode;
|
||||
|
||||
use ruff_python_codegen::Stylist;
|
||||
use ruff_python_index::Indexer;
|
||||
use ruff_python_parser::lexer::lex;
|
||||
use ruff_python_parser::Mode;
|
||||
use ruff_source_file::Locator;
|
||||
|
||||
use crate::line_width::LineLength;
|
||||
@@ -132,7 +130,7 @@ mod tests {
|
||||
},
|
||||
)
|
||||
};
|
||||
let line_length = LineLength::from(8);
|
||||
let line_length = LineLength::try_from(8).unwrap();
|
||||
assert_eq!(check_with_max_line_length(line_length), vec![]);
|
||||
assert_eq!(check_with_max_line_length(line_length), vec![]);
|
||||
}
|
||||
|
||||
@@ -51,8 +51,8 @@ impl PartialEq<&str> for NoqaCode {
|
||||
pub enum RuleGroup {
|
||||
/// The rule has not been assigned to any specific group.
|
||||
Unspecified,
|
||||
/// The rule is still under development, and must be enabled explicitly.
|
||||
Nursery,
|
||||
/// The rule is unstable, and must be enabled explicitly or by enabling preview.
|
||||
Preview,
|
||||
}
|
||||
|
||||
#[ruff_macros::map_codes]
|
||||
@@ -64,39 +64,39 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
|
||||
Some(match (linter, code) {
|
||||
// pycodestyle errors
|
||||
(Pycodestyle, "E101") => (RuleGroup::Unspecified, rules::pycodestyle::rules::MixedSpacesAndTabs),
|
||||
(Pycodestyle, "E111") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::IndentationWithInvalidMultiple),
|
||||
(Pycodestyle, "E112") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::NoIndentedBlock),
|
||||
(Pycodestyle, "E113") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::UnexpectedIndentation),
|
||||
(Pycodestyle, "E114") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::IndentationWithInvalidMultipleComment),
|
||||
(Pycodestyle, "E115") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::NoIndentedBlockComment),
|
||||
(Pycodestyle, "E116") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::UnexpectedIndentationComment),
|
||||
(Pycodestyle, "E117") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::OverIndented),
|
||||
(Pycodestyle, "E201") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::WhitespaceAfterOpenBracket),
|
||||
(Pycodestyle, "E202") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::WhitespaceBeforeCloseBracket),
|
||||
(Pycodestyle, "E203") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::WhitespaceBeforePunctuation),
|
||||
(Pycodestyle, "E211") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::WhitespaceBeforeParameters),
|
||||
(Pycodestyle, "E221") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::MultipleSpacesBeforeOperator),
|
||||
(Pycodestyle, "E222") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::MultipleSpacesAfterOperator),
|
||||
(Pycodestyle, "E223") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::TabBeforeOperator),
|
||||
(Pycodestyle, "E224") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::TabAfterOperator),
|
||||
(Pycodestyle, "E225") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::MissingWhitespaceAroundOperator),
|
||||
(Pycodestyle, "E226") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::MissingWhitespaceAroundArithmeticOperator),
|
||||
(Pycodestyle, "E227") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::MissingWhitespaceAroundBitwiseOrShiftOperator),
|
||||
(Pycodestyle, "E228") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::MissingWhitespaceAroundModuloOperator),
|
||||
(Pycodestyle, "E231") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::MissingWhitespace),
|
||||
(Pycodestyle, "E241") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::MultipleSpacesAfterComma),
|
||||
(Pycodestyle, "E242") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::TabAfterComma),
|
||||
(Pycodestyle, "E251") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::UnexpectedSpacesAroundKeywordParameterEquals),
|
||||
(Pycodestyle, "E252") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::MissingWhitespaceAroundParameterEquals),
|
||||
(Pycodestyle, "E261") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::TooFewSpacesBeforeInlineComment),
|
||||
(Pycodestyle, "E262") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::NoSpaceAfterInlineComment),
|
||||
(Pycodestyle, "E265") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::NoSpaceAfterBlockComment),
|
||||
(Pycodestyle, "E266") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::MultipleLeadingHashesForBlockComment),
|
||||
(Pycodestyle, "E271") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::MultipleSpacesAfterKeyword),
|
||||
(Pycodestyle, "E272") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::MultipleSpacesBeforeKeyword),
|
||||
(Pycodestyle, "E273") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::TabAfterKeyword),
|
||||
(Pycodestyle, "E274") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::TabBeforeKeyword),
|
||||
(Pycodestyle, "E275") => (RuleGroup::Nursery, rules::pycodestyle::rules::logical_lines::MissingWhitespaceAfterKeyword),
|
||||
(Pycodestyle, "E111") => (RuleGroup::Preview, rules::pycodestyle::rules::logical_lines::IndentationWithInvalidMultiple),
|
||||
(Pycodestyle, "E112") => (RuleGroup::Preview, rules::pycodestyle::rules::logical_lines::NoIndentedBlock),
|
||||
(Pycodestyle, "E113") => (RuleGroup::Preview, rules::pycodestyle::rules::logical_lines::UnexpectedIndentation),
|
||||
(Pycodestyle, "E114") => (RuleGroup::Preview, rules::pycodestyle::rules::logical_lines::IndentationWithInvalidMultipleComment),
|
||||
(Pycodestyle, "E115") => (RuleGroup::Preview, rules::pycodestyle::rules::logical_lines::NoIndentedBlockComment),
|
||||
(Pycodestyle, "E116") => (RuleGroup::Preview, rules::pycodestyle::rules::logical_lines::UnexpectedIndentationComment),
|
||||
(Pycodestyle, "E117") => (RuleGroup::Preview, rules::pycodestyle::rules::logical_lines::OverIndented),
|
||||
(Pycodestyle, "E201") => (RuleGroup::Preview, rules::pycodestyle::rules::logical_lines::WhitespaceAfterOpenBracket),
|
||||
(Pycodestyle, "E202") => (RuleGroup::Preview, rules::pycodestyle::rules::logical_lines::WhitespaceBeforeCloseBracket),
|
||||
(Pycodestyle, "E203") => (RuleGroup::Preview, rules::pycodestyle::rules::logical_lines::WhitespaceBeforePunctuation),
|
||||
(Pycodestyle, "E211") => (RuleGroup::Preview, rules::pycodestyle::rules::logical_lines::WhitespaceBeforeParameters),
|
||||
(Pycodestyle, "E221") => (RuleGroup::Preview, rules::pycodestyle::rules::logical_lines::MultipleSpacesBeforeOperator),
|
||||
(Pycodestyle, "E222") => (RuleGroup::Preview, rules::pycodestyle::rules::logical_lines::MultipleSpacesAfterOperator),
|
||||
(Pycodestyle, "E223") => (RuleGroup::Preview, rules::pycodestyle::rules::logical_lines::TabBeforeOperator),
|
||||
(Pycodestyle, "E224") => (RuleGroup::Preview, rules::pycodestyle::rules::logical_lines::TabAfterOperator),
|
||||
(Pycodestyle, "E225") => (RuleGroup::Preview, rules::pycodestyle::rules::logical_lines::MissingWhitespaceAroundOperator),
|
||||
(Pycodestyle, "E226") => (RuleGroup::Preview, rules::pycodestyle::rules::logical_lines::MissingWhitespaceAroundArithmeticOperator),
|
||||
(Pycodestyle, "E227") => (RuleGroup::Preview, rules::pycodestyle::rules::logical_lines::MissingWhitespaceAroundBitwiseOrShiftOperator),
|
||||
(Pycodestyle, "E228") => (RuleGroup::Preview, rules::pycodestyle::rules::logical_lines::MissingWhitespaceAroundModuloOperator),
|
||||
(Pycodestyle, "E231") => (RuleGroup::Preview, rules::pycodestyle::rules::logical_lines::MissingWhitespace),
|
||||
(Pycodestyle, "E241") => (RuleGroup::Preview, rules::pycodestyle::rules::logical_lines::MultipleSpacesAfterComma),
|
||||
(Pycodestyle, "E242") => (RuleGroup::Preview, rules::pycodestyle::rules::logical_lines::TabAfterComma),
|
||||
(Pycodestyle, "E251") => (RuleGroup::Preview, rules::pycodestyle::rules::logical_lines::UnexpectedSpacesAroundKeywordParameterEquals),
|
||||
(Pycodestyle, "E252") => (RuleGroup::Preview, rules::pycodestyle::rules::logical_lines::MissingWhitespaceAroundParameterEquals),
|
||||
(Pycodestyle, "E261") => (RuleGroup::Preview, rules::pycodestyle::rules::logical_lines::TooFewSpacesBeforeInlineComment),
|
||||
(Pycodestyle, "E262") => (RuleGroup::Preview, rules::pycodestyle::rules::logical_lines::NoSpaceAfterInlineComment),
|
||||
(Pycodestyle, "E265") => (RuleGroup::Preview, rules::pycodestyle::rules::logical_lines::NoSpaceAfterBlockComment),
|
||||
(Pycodestyle, "E266") => (RuleGroup::Preview, rules::pycodestyle::rules::logical_lines::MultipleLeadingHashesForBlockComment),
|
||||
(Pycodestyle, "E271") => (RuleGroup::Preview, rules::pycodestyle::rules::logical_lines::MultipleSpacesAfterKeyword),
|
||||
(Pycodestyle, "E272") => (RuleGroup::Preview, rules::pycodestyle::rules::logical_lines::MultipleSpacesBeforeKeyword),
|
||||
(Pycodestyle, "E273") => (RuleGroup::Preview, rules::pycodestyle::rules::logical_lines::TabAfterKeyword),
|
||||
(Pycodestyle, "E274") => (RuleGroup::Preview, rules::pycodestyle::rules::logical_lines::TabBeforeKeyword),
|
||||
(Pycodestyle, "E275") => (RuleGroup::Preview, rules::pycodestyle::rules::logical_lines::MissingWhitespaceAfterKeyword),
|
||||
(Pycodestyle, "E401") => (RuleGroup::Unspecified, rules::pycodestyle::rules::MultipleImportsOnOneLine),
|
||||
(Pycodestyle, "E402") => (RuleGroup::Unspecified, rules::pycodestyle::rules::ModuleImportNotAtTopOfFile),
|
||||
(Pycodestyle, "E501") => (RuleGroup::Unspecified, rules::pycodestyle::rules::LineTooLong),
|
||||
@@ -176,7 +176,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
|
||||
(Pylint, "C0205") => (RuleGroup::Unspecified, rules::pylint::rules::SingleStringSlots),
|
||||
(Pylint, "C0208") => (RuleGroup::Unspecified, rules::pylint::rules::IterationOverSet),
|
||||
(Pylint, "C0414") => (RuleGroup::Unspecified, rules::pylint::rules::UselessImportAlias),
|
||||
(Pylint, "C1901") => (RuleGroup::Nursery, rules::pylint::rules::CompareToEmptyString),
|
||||
(Pylint, "C1901") => (RuleGroup::Preview, rules::pylint::rules::CompareToEmptyString),
|
||||
(Pylint, "C3002") => (RuleGroup::Unspecified, rules::pylint::rules::UnnecessaryDirectLambdaCall),
|
||||
(Pylint, "E0100") => (RuleGroup::Unspecified, rules::pylint::rules::YieldInInit),
|
||||
(Pylint, "E0101") => (RuleGroup::Unspecified, rules::pylint::rules::ReturnInInit),
|
||||
@@ -216,7 +216,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
|
||||
(Pylint, "R1722") => (RuleGroup::Unspecified, rules::pylint::rules::SysExitAlias),
|
||||
(Pylint, "R2004") => (RuleGroup::Unspecified, rules::pylint::rules::MagicValueComparison),
|
||||
(Pylint, "R5501") => (RuleGroup::Unspecified, rules::pylint::rules::CollapsibleElseIf),
|
||||
(Pylint, "R6301") => (RuleGroup::Nursery, rules::pylint::rules::NoSelfUse),
|
||||
(Pylint, "R6301") => (RuleGroup::Preview, rules::pylint::rules::NoSelfUse),
|
||||
(Pylint, "W0120") => (RuleGroup::Unspecified, rules::pylint::rules::UselessElseOnLoop),
|
||||
(Pylint, "W0127") => (RuleGroup::Unspecified, rules::pylint::rules::SelfAssigningVariable),
|
||||
(Pylint, "W0129") => (RuleGroup::Unspecified, rules::pylint::rules::AssertOnStringLiteral),
|
||||
@@ -228,9 +228,9 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
|
||||
(Pylint, "W1508") => (RuleGroup::Unspecified, rules::pylint::rules::InvalidEnvvarDefault),
|
||||
(Pylint, "W1509") => (RuleGroup::Unspecified, rules::pylint::rules::SubprocessPopenPreexecFn),
|
||||
(Pylint, "W1510") => (RuleGroup::Unspecified, rules::pylint::rules::SubprocessRunWithoutCheck),
|
||||
(Pylint, "W1641") => (RuleGroup::Nursery, rules::pylint::rules::EqWithoutHash),
|
||||
(Pylint, "W1641") => (RuleGroup::Preview, rules::pylint::rules::EqWithoutHash),
|
||||
(Pylint, "W2901") => (RuleGroup::Unspecified, rules::pylint::rules::RedefinedLoopName),
|
||||
(Pylint, "W3201") => (RuleGroup::Nursery, rules::pylint::rules::BadDunderMethodName),
|
||||
(Pylint, "W3201") => (RuleGroup::Preview, rules::pylint::rules::BadDunderMethodName),
|
||||
(Pylint, "W3301") => (RuleGroup::Unspecified, rules::pylint::rules::NestedMinMax),
|
||||
|
||||
// flake8-async
|
||||
@@ -403,7 +403,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
|
||||
(Flake8Simplify, "910") => (RuleGroup::Unspecified, rules::flake8_simplify::rules::DictGetWithNoneDefault),
|
||||
|
||||
// flake8-copyright
|
||||
(Flake8Copyright, "001") => (RuleGroup::Nursery, rules::flake8_copyright::rules::MissingCopyrightNotice),
|
||||
(Flake8Copyright, "001") => (RuleGroup::Preview, rules::flake8_copyright::rules::MissingCopyrightNotice),
|
||||
|
||||
// pyupgrade
|
||||
(Pyupgrade, "001") => (RuleGroup::Unspecified, rules::pyupgrade::rules::UselessMetaclassType),
|
||||
@@ -815,10 +815,10 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
|
||||
(Ruff, "012") => (RuleGroup::Unspecified, rules::ruff::rules::MutableClassDefault),
|
||||
(Ruff, "013") => (RuleGroup::Unspecified, rules::ruff::rules::ImplicitOptional),
|
||||
#[cfg(feature = "unreachable-code")] // When removing this feature gate, also update rules_selector.rs
|
||||
(Ruff, "014") => (RuleGroup::Nursery, rules::ruff::rules::UnreachableCode),
|
||||
(Ruff, "014") => (RuleGroup::Preview, rules::ruff::rules::UnreachableCode),
|
||||
(Ruff, "015") => (RuleGroup::Unspecified, rules::ruff::rules::UnnecessaryIterableAllocationForFirstElement),
|
||||
(Ruff, "016") => (RuleGroup::Unspecified, rules::ruff::rules::InvalidIndexType),
|
||||
(Ruff, "017") => (RuleGroup::Nursery, rules::ruff::rules::QuadraticListSummation),
|
||||
(Ruff, "017") => (RuleGroup::Preview, rules::ruff::rules::QuadraticListSummation),
|
||||
(Ruff, "100") => (RuleGroup::Unspecified, rules::ruff::rules::UnusedNOQA),
|
||||
(Ruff, "200") => (RuleGroup::Unspecified, rules::ruff::rules::InvalidPyprojectToml),
|
||||
|
||||
@@ -865,6 +865,11 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
|
||||
(Flake8Slots, "001") => (RuleGroup::Unspecified, rules::flake8_slots::rules::NoSlotsInTupleSubclass),
|
||||
(Flake8Slots, "002") => (RuleGroup::Unspecified, rules::flake8_slots::rules::NoSlotsInNamedtupleSubclass),
|
||||
|
||||
// refurb
|
||||
(Refurb, "113") => (RuleGroup::Preview, rules::refurb::rules::RepeatedAppend),
|
||||
(Refurb, "131") => (RuleGroup::Preview, rules::refurb::rules::DeleteFullSlice),
|
||||
(Refurb, "132") => (RuleGroup::Preview, rules::refurb::rules::CheckAndRemoveFromSet),
|
||||
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use std::str::FromStr;
|
||||
use bitflags::bitflags;
|
||||
use ruff_python_parser::lexer::LexResult;
|
||||
use ruff_python_parser::Tok;
|
||||
use ruff_text_size::{TextLen, TextRange, TextSize};
|
||||
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
|
||||
|
||||
use ruff_python_index::Indexer;
|
||||
use ruff_source_file::Locator;
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
|
||||
use std::iter::FusedIterator;
|
||||
|
||||
use ruff_python_ast::{self as ast, Constant, Expr, Ranged, Stmt, Suite};
|
||||
use ruff_python_ast::{self as ast, Constant, Expr, Stmt, Suite};
|
||||
use ruff_python_parser::lexer::LexResult;
|
||||
use ruff_python_parser::Tok;
|
||||
use ruff_text_size::TextSize;
|
||||
use ruff_text_size::{Ranged, TextSize};
|
||||
|
||||
use ruff_python_ast::statement_visitor::{walk_stmt, StatementVisitor};
|
||||
use ruff_source_file::{Locator, UniversalNewlineIterator};
|
||||
@@ -76,7 +76,7 @@ impl StatementVisitor<'_> for StringLinesVisitor<'_> {
|
||||
}) = value.as_ref()
|
||||
{
|
||||
for line in UniversalNewlineIterator::with_offset(
|
||||
self.locator.slice(value.range()),
|
||||
self.locator.slice(value.as_ref()),
|
||||
value.start(),
|
||||
) {
|
||||
self.string_lines.push(line.start());
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::ops::Deref;
|
||||
|
||||
use ruff_python_ast::{Expr, Ranged};
|
||||
use ruff_python_ast::Expr;
|
||||
use ruff_python_semantic::Definition;
|
||||
use ruff_text_size::TextRange;
|
||||
use ruff_text_size::{Ranged, TextRange};
|
||||
|
||||
pub(crate) mod extraction;
|
||||
pub(crate) mod google;
|
||||
|
||||
@@ -2,8 +2,7 @@ use std::fmt::{Debug, Formatter};
|
||||
use std::iter::FusedIterator;
|
||||
|
||||
use ruff_python_ast::docstrings::{leading_space, leading_words};
|
||||
use ruff_python_ast::Ranged;
|
||||
use ruff_text_size::{TextLen, TextRange, TextSize};
|
||||
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
|
||||
use strum_macros::EnumIter;
|
||||
|
||||
use ruff_source_file::{Line, UniversalNewlineIterator, UniversalNewlines};
|
||||
@@ -165,7 +164,7 @@ impl<'a> SectionContexts<'a> {
|
||||
lines.peek(),
|
||||
) {
|
||||
if let Some(mut last) = last.take() {
|
||||
last.range = TextRange::new(last.range.start(), line.start());
|
||||
last.range = TextRange::new(last.start(), line.start());
|
||||
contexts.push(last);
|
||||
}
|
||||
|
||||
@@ -182,7 +181,7 @@ impl<'a> SectionContexts<'a> {
|
||||
}
|
||||
|
||||
if let Some(mut last) = last.take() {
|
||||
last.range = TextRange::new(last.range.start(), contents.text_len());
|
||||
last.range = TextRange::new(last.start(), contents.text_len());
|
||||
contexts.push(last);
|
||||
}
|
||||
|
||||
@@ -268,6 +267,12 @@ struct SectionContextData {
|
||||
summary_full_end: TextSize,
|
||||
}
|
||||
|
||||
impl Ranged for SectionContextData {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct SectionContext<'a> {
|
||||
data: &'a SectionContextData,
|
||||
docstring_body: DocstringBody<'a>,
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
use super::black::Black;
|
||||
use super::isort::Isort;
|
||||
use super::pep621::Project;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ExternalConfig<'a> {
|
||||
pub black: Option<&'a Black>,
|
||||
pub isort: Option<&'a Isort>,
|
||||
pub project: Option<&'a Project>,
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
pub use converter::convert;
|
||||
pub use external_config::ExternalConfig;
|
||||
pub use plugin::Plugin;
|
||||
pub use pyproject::parse;
|
||||
|
||||
mod black;
|
||||
mod converter;
|
||||
mod external_config;
|
||||
mod isort;
|
||||
mod parser;
|
||||
pub mod pep621;
|
||||
mod plugin;
|
||||
mod pyproject;
|
||||
@@ -1,9 +1,9 @@
|
||||
//! Insert statements into Python code.
|
||||
use std::ops::Add;
|
||||
|
||||
use ruff_python_ast::{PySourceType, Ranged, Stmt};
|
||||
use ruff_python_ast::{PySourceType, Stmt};
|
||||
use ruff_python_parser::{lexer, AsMode, Tok};
|
||||
use ruff_text_size::TextSize;
|
||||
use ruff_text_size::{Ranged, TextSize};
|
||||
|
||||
use ruff_diagnostics::Edit;
|
||||
use ruff_python_ast::helpers::is_docstring_stmt;
|
||||
|
||||
@@ -7,8 +7,8 @@ use std::error::Error;
|
||||
|
||||
use anyhow::Result;
|
||||
use libcst_native::{ImportAlias, Name, NameOrAttribute};
|
||||
use ruff_python_ast::{self as ast, PySourceType, Ranged, Stmt, Suite};
|
||||
use ruff_text_size::TextSize;
|
||||
use ruff_python_ast::{self as ast, PySourceType, Stmt, Suite};
|
||||
use ruff_text_size::{Ranged, TextSize};
|
||||
|
||||
use ruff_diagnostics::Edit;
|
||||
use ruff_python_ast::imports::{AnyImport, Import, ImportFrom};
|
||||
@@ -319,7 +319,7 @@ impl<'a> Importer<'a> {
|
||||
|
||||
/// Add the given member to an existing `Stmt::ImportFrom` statement.
|
||||
fn add_member(&self, stmt: &Stmt, member: &str) -> Result<Edit> {
|
||||
let mut statement = match_statement(self.locator.slice(stmt.range()))?;
|
||||
let mut statement = match_statement(self.locator.slice(stmt))?;
|
||||
let import_from = match_import_from(&mut statement)?;
|
||||
let aliases = match_aliases(import_from)?;
|
||||
aliases.push(ImportAlias {
|
||||
|
||||
@@ -12,13 +12,12 @@ pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
mod autofix;
|
||||
mod checkers;
|
||||
mod codes;
|
||||
pub mod codes;
|
||||
mod comments;
|
||||
mod cst;
|
||||
pub mod directives;
|
||||
mod doc_lines;
|
||||
mod docstrings;
|
||||
pub mod flake8_to_ruff;
|
||||
pub mod fs;
|
||||
mod importer;
|
||||
pub mod jupyter;
|
||||
@@ -32,9 +31,8 @@ pub mod packaging;
|
||||
pub mod pyproject_toml;
|
||||
pub mod registry;
|
||||
mod renamer;
|
||||
pub mod resolver;
|
||||
mod rule_redirects;
|
||||
mod rule_selector;
|
||||
pub mod rule_selector;
|
||||
pub mod rules;
|
||||
pub mod settings;
|
||||
pub mod source_kind;
|
||||
@@ -42,3 +40,5 @@ pub mod upstream_categories;
|
||||
|
||||
#[cfg(any(test, fuzzing))]
|
||||
pub mod test;
|
||||
|
||||
pub const RUFF_PKG_VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
@@ -1,30 +1,111 @@
|
||||
use ruff_cache::{CacheKey, CacheKeyHasher};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::num::NonZeroU8;
|
||||
use std::error::Error;
|
||||
use std::hash::Hasher;
|
||||
use std::num::{NonZeroU16, NonZeroU8, ParseIntError};
|
||||
use std::str::FromStr;
|
||||
use unicode_width::UnicodeWidthChar;
|
||||
|
||||
use ruff_macros::CacheKey;
|
||||
|
||||
/// The length of a line of text that is considered too long.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, CacheKey)]
|
||||
///
|
||||
/// The allowed range of values is 1..=320
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub struct LineLength(usize);
|
||||
|
||||
impl Default for LineLength {
|
||||
/// The default line length.
|
||||
fn default() -> Self {
|
||||
Self(88)
|
||||
}
|
||||
}
|
||||
pub struct LineLength(NonZeroU16);
|
||||
|
||||
impl LineLength {
|
||||
pub const fn get(&self) -> usize {
|
||||
self.0
|
||||
/// Maximum allowed value for a valid [`LineLength`]
|
||||
pub const MAX: u16 = 320;
|
||||
|
||||
/// Return the numeric value for this [`LineLength`]
|
||||
pub fn value(&self) -> u16 {
|
||||
self.0.get()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for LineLength {
|
||||
fn from(value: usize) -> Self {
|
||||
Self(value)
|
||||
impl Default for LineLength {
|
||||
fn default() -> Self {
|
||||
Self(NonZeroU16::new(88).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl CacheKey for LineLength {
|
||||
fn cache_key(&self, state: &mut CacheKeyHasher) {
|
||||
state.write_u16(self.0.get());
|
||||
}
|
||||
}
|
||||
|
||||
/// Error type returned when parsing a [`LineLength`] from a string fails
|
||||
pub enum ParseLineWidthError {
|
||||
/// The string could not be parsed as a valid [u16]
|
||||
ParseError(ParseIntError),
|
||||
/// The [u16] value of the string is not a valid [LineLength]
|
||||
TryFromIntError(LineLengthFromIntError),
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for ParseLineWidthError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ParseLineWidthError {
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
ParseLineWidthError::ParseError(err) => std::fmt::Display::fmt(err, fmt),
|
||||
ParseLineWidthError::TryFromIntError(err) => std::fmt::Display::fmt(err, fmt),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for ParseLineWidthError {}
|
||||
|
||||
impl FromStr for LineLength {
|
||||
type Err = ParseLineWidthError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let value = u16::from_str(s).map_err(ParseLineWidthError::ParseError)?;
|
||||
let value = Self::try_from(value).map_err(ParseLineWidthError::TryFromIntError)?;
|
||||
Ok(value)
|
||||
}
|
||||
}
|
||||
|
||||
/// Error type returned when converting a u16 to a [`LineLength`] fails
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct LineLengthFromIntError(pub u16);
|
||||
|
||||
impl TryFrom<u16> for LineLength {
|
||||
type Error = LineLengthFromIntError;
|
||||
|
||||
fn try_from(value: u16) -> Result<Self, Self::Error> {
|
||||
match NonZeroU16::try_from(value) {
|
||||
Ok(value) if value.get() <= Self::MAX => Ok(LineLength(value)),
|
||||
Ok(_) | Err(_) => Err(LineLengthFromIntError(value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for LineLengthFromIntError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
writeln!(
|
||||
f,
|
||||
"The line width must be a value between 1 and {}.",
|
||||
LineLength::MAX
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<LineLength> for u16 {
|
||||
fn from(value: LineLength) -> Self {
|
||||
value.0.get()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<LineLength> for NonZeroU16 {
|
||||
fn from(value: LineLength) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +114,7 @@ impl From<usize> for LineLength {
|
||||
/// This is used to determine if a line is too long.
|
||||
/// It should be compared to a [`LineLength`].
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct LineWidth {
|
||||
pub struct LineWidthBuilder {
|
||||
/// The width of the line.
|
||||
width: usize,
|
||||
/// The column of the line.
|
||||
@@ -43,40 +124,40 @@ pub struct LineWidth {
|
||||
tab_size: TabSize,
|
||||
}
|
||||
|
||||
impl Default for LineWidth {
|
||||
impl Default for LineWidthBuilder {
|
||||
fn default() -> Self {
|
||||
Self::new(TabSize::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for LineWidth {
|
||||
impl PartialEq for LineWidthBuilder {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.width == other.width
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for LineWidth {}
|
||||
impl Eq for LineWidthBuilder {}
|
||||
|
||||
impl PartialOrd for LineWidth {
|
||||
impl PartialOrd for LineWidthBuilder {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for LineWidth {
|
||||
impl Ord for LineWidthBuilder {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.width.cmp(&other.width)
|
||||
}
|
||||
}
|
||||
|
||||
impl LineWidth {
|
||||
impl LineWidthBuilder {
|
||||
pub fn get(&self) -> usize {
|
||||
self.width
|
||||
}
|
||||
|
||||
/// Creates a new `LineWidth` with the given tab size.
|
||||
pub fn new(tab_size: TabSize) -> Self {
|
||||
LineWidth {
|
||||
LineWidthBuilder {
|
||||
width: 0,
|
||||
column: 0,
|
||||
tab_size,
|
||||
@@ -119,7 +200,7 @@ impl LineWidth {
|
||||
|
||||
/// Adds the given width to the line width.
|
||||
/// Also adds the given width to the column.
|
||||
/// It is generally better to use [`LineWidth::add_str`] or [`LineWidth::add_char`].
|
||||
/// It is generally better to use [`LineWidthBuilder::add_str`] or [`LineWidthBuilder::add_char`].
|
||||
/// The width and column should be the same for the corresponding text.
|
||||
/// Currently, this is only used to add spaces.
|
||||
#[must_use]
|
||||
@@ -130,15 +211,15 @@ impl LineWidth {
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<LineLength> for LineWidth {
|
||||
impl PartialEq<LineLength> for LineWidthBuilder {
|
||||
fn eq(&self, other: &LineLength) -> bool {
|
||||
self.width == other.0
|
||||
self.width == (other.value() as usize)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<LineLength> for LineWidth {
|
||||
impl PartialOrd<LineLength> for LineWidthBuilder {
|
||||
fn partial_cmp(&self, other: &LineLength) -> Option<std::cmp::Ordering> {
|
||||
self.width.partial_cmp(&other.0)
|
||||
self.width.partial_cmp(&(other.value() as usize))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ use ruff_python_codegen::Stylist;
|
||||
use ruff_python_index::Indexer;
|
||||
|
||||
use ruff_source_file::{Locator, SourceFileBuilder};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::autofix::{fix_file, FixResult};
|
||||
use crate::checkers::ast::check_ast;
|
||||
@@ -267,9 +268,12 @@ pub fn check_path(
|
||||
const MAX_ITERATIONS: usize = 100;
|
||||
|
||||
/// Add any missing `# noqa` pragmas to the source code at the given `Path`.
|
||||
pub fn add_noqa_to_path(path: &Path, package: Option<&Path>, settings: &Settings) -> Result<usize> {
|
||||
let source_type = PySourceType::from(path);
|
||||
|
||||
pub fn add_noqa_to_path(
|
||||
path: &Path,
|
||||
package: Option<&Path>,
|
||||
source_type: PySourceType,
|
||||
settings: &Settings,
|
||||
) -> Result<usize> {
|
||||
// Read the file from disk.
|
||||
let contents = std::fs::read_to_string(path)?;
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ use crate::fs;
|
||||
use crate::jupyter::Notebook;
|
||||
use crate::source_kind::SourceKind;
|
||||
|
||||
pub(crate) static WARNINGS: Lazy<Mutex<Vec<&'static str>>> = Lazy::new(Mutex::default);
|
||||
pub static WARNINGS: Lazy<Mutex<Vec<&'static str>>> = Lazy::new(Mutex::default);
|
||||
|
||||
/// Warn a user once, with uniqueness determined by the given ID.
|
||||
#[macro_export]
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::num::NonZeroUsize;
|
||||
|
||||
use colored::{Color, ColoredString, Colorize, Styles};
|
||||
|
||||
use ruff_text_size::{TextRange, TextSize};
|
||||
use ruff_text_size::{Ranged, TextRange, TextSize};
|
||||
use similar::{ChangeTag, TextDiff};
|
||||
|
||||
use ruff_diagnostics::{Applicability, Fix};
|
||||
|
||||
@@ -6,6 +6,7 @@ use serde_json::{json, Value};
|
||||
|
||||
use ruff_diagnostics::Edit;
|
||||
use ruff_source_file::SourceCode;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::message::{Emitter, EmitterContext, Message};
|
||||
use crate::registry::AsRule;
|
||||
|
||||
@@ -15,7 +15,7 @@ pub use junit::JunitEmitter;
|
||||
pub use pylint::PylintEmitter;
|
||||
use ruff_diagnostics::{Diagnostic, DiagnosticKind, Fix};
|
||||
use ruff_source_file::{SourceFile, SourceLocation};
|
||||
use ruff_text_size::{TextRange, TextSize};
|
||||
use ruff_text_size::{Ranged, TextRange, TextSize};
|
||||
pub use text::TextEmitter;
|
||||
|
||||
use crate::jupyter::Notebook;
|
||||
@@ -66,14 +66,6 @@ impl Message {
|
||||
pub fn compute_end_location(&self) -> SourceLocation {
|
||||
self.file.to_source_code().source_location(self.end())
|
||||
}
|
||||
|
||||
pub const fn start(&self) -> TextSize {
|
||||
self.range.start()
|
||||
}
|
||||
|
||||
pub const fn end(&self) -> TextSize {
|
||||
self.range.end()
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Message {
|
||||
@@ -88,6 +80,12 @@ impl PartialOrd for Message {
|
||||
}
|
||||
}
|
||||
|
||||
impl Ranged for Message {
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
|
||||
struct MessageWithLocation<'a> {
|
||||
message: &'a Message,
|
||||
start_location: SourceLocation,
|
||||
@@ -154,7 +152,7 @@ mod tests {
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, DiagnosticKind, Edit, Fix};
|
||||
use ruff_source_file::SourceFileBuilder;
|
||||
use ruff_text_size::{TextRange, TextSize};
|
||||
use ruff_text_size::{Ranged, TextRange, TextSize};
|
||||
|
||||
use crate::message::{Emitter, EmitterContext, Message};
|
||||
|
||||
|
||||
@@ -8,11 +8,11 @@ use bitflags::bitflags;
|
||||
use colored::Colorize;
|
||||
|
||||
use ruff_source_file::{OneIndexed, SourceLocation};
|
||||
use ruff_text_size::{TextRange, TextSize};
|
||||
use ruff_text_size::{Ranged, TextRange, TextSize};
|
||||
|
||||
use crate::fs::relativize_path;
|
||||
use crate::jupyter::{Notebook, NotebookIndex};
|
||||
use crate::line_width::{LineWidth, TabSize};
|
||||
use crate::line_width::{LineWidthBuilder, TabSize};
|
||||
use crate::message::diff::Diff;
|
||||
use crate::message::{Emitter, EmitterContext, Message};
|
||||
use crate::registry::AsRule;
|
||||
@@ -292,7 +292,7 @@ fn replace_whitespace(source: &str, annotation_range: TextRange) -> SourceCode {
|
||||
let mut result = String::new();
|
||||
let mut last_end = 0;
|
||||
let mut range = annotation_range;
|
||||
let mut line_width = LineWidth::new(TabSize::default());
|
||||
let mut line_width = LineWidthBuilder::new(TabSize::default());
|
||||
|
||||
for (index, c) in source.char_indices() {
|
||||
let old_width = line_width.get();
|
||||
|
||||
@@ -8,8 +8,7 @@ use std::path::Path;
|
||||
use anyhow::Result;
|
||||
use itertools::Itertools;
|
||||
use log::warn;
|
||||
use ruff_python_ast::Ranged;
|
||||
use ruff_text_size::{TextLen, TextRange, TextSize};
|
||||
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
|
||||
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
use ruff_python_trivia::indentation_at_offset;
|
||||
@@ -537,7 +536,7 @@ fn add_noqa_inner(
|
||||
let rule = diagnostic.kind.rule();
|
||||
if !includes(rule, codes) {
|
||||
matches_by_line
|
||||
.entry(directive_line.range.start())
|
||||
.entry(directive_line.start())
|
||||
.or_insert_with(|| {
|
||||
(RuleSet::default(), Some(&directive_line.directive))
|
||||
})
|
||||
@@ -645,6 +644,13 @@ pub(crate) struct NoqaDirectiveLine<'a> {
|
||||
pub(crate) matches: Vec<NoqaCode>,
|
||||
}
|
||||
|
||||
impl Ranged for NoqaDirectiveLine<'_> {
|
||||
/// The range of the `noqa` directive.
|
||||
fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub(crate) struct NoqaDirectives<'a> {
|
||||
inner: Vec<NoqaDirectiveLine<'a>>,
|
||||
|
||||
@@ -2,10 +2,6 @@
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::resolver::{PyprojectConfig, Resolver};
|
||||
|
||||
// If we have a Python package layout like:
|
||||
// - root/
|
||||
// - foo/
|
||||
@@ -51,68 +47,6 @@ pub fn detect_package_root<'a>(
|
||||
current
|
||||
}
|
||||
|
||||
/// A wrapper around `is_package` to cache filesystem lookups.
|
||||
fn is_package_with_cache<'a>(
|
||||
path: &'a Path,
|
||||
namespace_packages: &'a [PathBuf],
|
||||
package_cache: &mut FxHashMap<&'a Path, bool>,
|
||||
) -> bool {
|
||||
*package_cache
|
||||
.entry(path)
|
||||
.or_insert_with(|| is_package(path, namespace_packages))
|
||||
}
|
||||
|
||||
/// A wrapper around `detect_package_root` to cache filesystem lookups.
|
||||
fn detect_package_root_with_cache<'a>(
|
||||
path: &'a Path,
|
||||
namespace_packages: &'a [PathBuf],
|
||||
package_cache: &mut FxHashMap<&'a Path, bool>,
|
||||
) -> Option<&'a Path> {
|
||||
let mut current = None;
|
||||
for parent in path.ancestors() {
|
||||
if !is_package_with_cache(parent, namespace_packages, package_cache) {
|
||||
return current;
|
||||
}
|
||||
current = Some(parent);
|
||||
}
|
||||
current
|
||||
}
|
||||
|
||||
/// Return a mapping from Python package to its package root.
|
||||
pub fn detect_package_roots<'a>(
|
||||
files: &[&'a Path],
|
||||
resolver: &'a Resolver,
|
||||
pyproject_config: &'a PyprojectConfig,
|
||||
) -> FxHashMap<&'a Path, Option<&'a Path>> {
|
||||
// Pre-populate the module cache, since the list of files could (but isn't
|
||||
// required to) contain some `__init__.py` files.
|
||||
let mut package_cache: FxHashMap<&Path, bool> = FxHashMap::default();
|
||||
for file in files {
|
||||
if file.ends_with("__init__.py") {
|
||||
if let Some(parent) = file.parent() {
|
||||
package_cache.insert(parent, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Search for the package root for each file.
|
||||
let mut package_roots: FxHashMap<&Path, Option<&Path>> = FxHashMap::default();
|
||||
for file in files {
|
||||
let namespace_packages = &resolver.resolve(file, pyproject_config).namespace_packages;
|
||||
if let Some(package) = file.parent() {
|
||||
if package_roots.contains_key(package) {
|
||||
continue;
|
||||
}
|
||||
package_roots.insert(
|
||||
package,
|
||||
detect_package_root_with_cache(package, namespace_packages, &mut package_cache),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
package_roots
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::path::PathBuf;
|
||||
|
||||
@@ -196,6 +196,9 @@ pub enum Linter {
|
||||
/// [Perflint](https://pypi.org/project/perflint/)
|
||||
#[prefix = "PERF"]
|
||||
Perflint,
|
||||
/// [refurb](https://pypi.org/project/refurb/)
|
||||
#[prefix = "FURB"]
|
||||
Refurb,
|
||||
/// Ruff-specific rules
|
||||
#[prefix = "RUF"]
|
||||
Ruff,
|
||||
|
||||
@@ -4,8 +4,8 @@ use anyhow::{anyhow, Result};
|
||||
use itertools::Itertools;
|
||||
|
||||
use ruff_diagnostics::Edit;
|
||||
use ruff_python_ast::Ranged;
|
||||
use ruff_python_semantic::{Binding, BindingKind, Scope, ScopeId, SemanticModel};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
pub(crate) struct Renamer;
|
||||
|
||||
|
||||
@@ -9,13 +9,14 @@ use crate::codes::RuleCodePrefix;
|
||||
use crate::codes::RuleIter;
|
||||
use crate::registry::{Linter, Rule, RuleNamespace};
|
||||
use crate::rule_redirects::get_redirect;
|
||||
use crate::settings::types::PreviewMode;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum RuleSelector {
|
||||
/// Select all stable rules.
|
||||
All,
|
||||
/// Select all nursery rules.
|
||||
Nursery,
|
||||
/// Category to select all preview rules, previously known as the nursery
|
||||
Preview,
|
||||
/// Legacy category to select both the `mccabe` and `flake8-comprehensions` linters
|
||||
/// via a single selector.
|
||||
C,
|
||||
@@ -29,6 +30,11 @@ pub enum RuleSelector {
|
||||
prefix: RuleCodePrefix,
|
||||
redirected_from: Option<&'static str>,
|
||||
},
|
||||
/// Select an individual rule with a given prefix.
|
||||
Rule {
|
||||
prefix: RuleCodePrefix,
|
||||
redirected_from: Option<&'static str>,
|
||||
},
|
||||
}
|
||||
|
||||
impl From<Linter> for RuleSelector {
|
||||
@@ -43,7 +49,9 @@ impl FromStr for RuleSelector {
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"ALL" => Ok(Self::All),
|
||||
"NURSERY" => Ok(Self::Nursery),
|
||||
// Legacy support for selecting preview rules as "nursery"
|
||||
"NURSERY" => Ok(Self::Preview),
|
||||
"PREVIEW" => Ok(Self::Preview),
|
||||
"C" => Ok(Self::C),
|
||||
"T" => Ok(Self::T),
|
||||
_ => {
|
||||
@@ -59,16 +67,42 @@ impl FromStr for RuleSelector {
|
||||
return Ok(Self::Linter(linter));
|
||||
}
|
||||
|
||||
Ok(Self::Prefix {
|
||||
prefix: RuleCodePrefix::parse(&linter, code)
|
||||
.map_err(|_| ParseError::Unknown(s.to_string()))?,
|
||||
redirected_from,
|
||||
})
|
||||
// Does the selector select a single rule?
|
||||
let prefix = RuleCodePrefix::parse(&linter, code)
|
||||
.map_err(|_| ParseError::Unknown(s.to_string()))?;
|
||||
if is_single_rule_selector(&prefix) {
|
||||
Ok(Self::Rule {
|
||||
prefix,
|
||||
redirected_from,
|
||||
})
|
||||
} else {
|
||||
Ok(Self::Prefix {
|
||||
prefix,
|
||||
redirected_from,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the [`RuleCodePrefix`] matches a single rule exactly
|
||||
/// (e.g., `E225`, as opposed to `E2`).
|
||||
fn is_single_rule_selector(prefix: &RuleCodePrefix) -> bool {
|
||||
let mut rules = prefix.rules();
|
||||
|
||||
// The selector must match a single rule.
|
||||
let Some(rule) = rules.next() else {
|
||||
return false;
|
||||
};
|
||||
if rules.next().is_some() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The rule must match the selector exactly.
|
||||
rule.noqa_code().suffix() == prefix.short_code()
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum ParseError {
|
||||
#[error("Unknown rule selector: `{0}`")]
|
||||
@@ -81,10 +115,10 @@ impl RuleSelector {
|
||||
pub fn prefix_and_code(&self) -> (&'static str, &'static str) {
|
||||
match self {
|
||||
RuleSelector::All => ("", "ALL"),
|
||||
RuleSelector::Nursery => ("", "NURSERY"),
|
||||
RuleSelector::Preview => ("", "PREVIEW"),
|
||||
RuleSelector::C => ("", "C"),
|
||||
RuleSelector::T => ("", "T"),
|
||||
RuleSelector::Prefix { prefix, .. } => {
|
||||
RuleSelector::Prefix { prefix, .. } | RuleSelector::Rule { prefix, .. } => {
|
||||
(prefix.linter().common_prefix(), prefix.short_code())
|
||||
}
|
||||
RuleSelector::Linter(l) => (l.common_prefix(), ""),
|
||||
@@ -135,26 +169,13 @@ impl Visitor<'_> for SelectorVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RuleCodePrefix> for RuleSelector {
|
||||
fn from(prefix: RuleCodePrefix) -> Self {
|
||||
Self::Prefix {
|
||||
prefix,
|
||||
redirected_from: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for &RuleSelector {
|
||||
type IntoIter = RuleSelectorIter;
|
||||
type Item = Rule;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
impl RuleSelector {
|
||||
/// Return all matching rules, regardless of whether they're in preview.
|
||||
pub fn all_rules(&self) -> impl Iterator<Item = Rule> + '_ {
|
||||
match self {
|
||||
RuleSelector::All => {
|
||||
RuleSelectorIter::All(Rule::iter().filter(|rule| !rule.is_nursery()))
|
||||
}
|
||||
RuleSelector::Nursery => {
|
||||
RuleSelectorIter::Nursery(Rule::iter().filter(Rule::is_nursery))
|
||||
RuleSelector::All => RuleSelectorIter::All(Rule::iter()),
|
||||
RuleSelector::Preview => {
|
||||
RuleSelectorIter::Nursery(Rule::iter().filter(Rule::is_preview))
|
||||
}
|
||||
RuleSelector::C => RuleSelectorIter::Chain(
|
||||
Linter::Flake8Comprehensions
|
||||
@@ -167,13 +188,22 @@ impl IntoIterator for &RuleSelector {
|
||||
.chain(Linter::Flake8Print.rules()),
|
||||
),
|
||||
RuleSelector::Linter(linter) => RuleSelectorIter::Vec(linter.rules()),
|
||||
RuleSelector::Prefix { prefix, .. } => RuleSelectorIter::Vec(prefix.clone().rules()),
|
||||
RuleSelector::Prefix { prefix, .. } | RuleSelector::Rule { prefix, .. } => {
|
||||
RuleSelectorIter::Vec(prefix.clone().rules())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns rules matching the selector, taking into account whether preview mode is enabled.
|
||||
pub fn rules(&self, preview: PreviewMode) -> impl Iterator<Item = Rule> + '_ {
|
||||
self.all_rules().filter(move |rule| {
|
||||
matches!(self, RuleSelector::Rule { .. }) || preview.is_enabled() || !rule.is_preview()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub enum RuleSelectorIter {
|
||||
All(std::iter::Filter<RuleIter, fn(&Rule) -> bool>),
|
||||
All(RuleIter),
|
||||
Nursery(std::iter::Filter<RuleIter, fn(&Rule) -> bool>),
|
||||
Chain(std::iter::Chain<std::vec::IntoIter<Rule>, std::vec::IntoIter<Rule>>),
|
||||
Vec(std::vec::IntoIter<Rule>),
|
||||
@@ -263,21 +293,21 @@ mod schema {
|
||||
}
|
||||
|
||||
impl RuleSelector {
|
||||
pub(crate) fn specificity(&self) -> Specificity {
|
||||
pub fn specificity(&self) -> Specificity {
|
||||
match self {
|
||||
RuleSelector::All => Specificity::All,
|
||||
RuleSelector::Nursery => Specificity::All,
|
||||
RuleSelector::Preview => Specificity::All,
|
||||
RuleSelector::T => Specificity::LinterGroup,
|
||||
RuleSelector::C => Specificity::LinterGroup,
|
||||
RuleSelector::Linter(..) => Specificity::Linter,
|
||||
RuleSelector::Rule { .. } => Specificity::Rule,
|
||||
RuleSelector::Prefix { prefix, .. } => {
|
||||
let prefix: &'static str = prefix.short_code();
|
||||
match prefix.len() {
|
||||
1 => Specificity::Code1Char,
|
||||
2 => Specificity::Code2Chars,
|
||||
3 => Specificity::Code3Chars,
|
||||
4 => Specificity::Code4Chars,
|
||||
5 => Specificity::Code5Chars,
|
||||
1 => Specificity::Prefix1Char,
|
||||
2 => Specificity::Prefix2Chars,
|
||||
3 => Specificity::Prefix3Chars,
|
||||
4 => Specificity::Prefix4Chars,
|
||||
_ => panic!("RuleSelector::specificity doesn't yet support codes with so many characters"),
|
||||
}
|
||||
}
|
||||
@@ -285,16 +315,24 @@ impl RuleSelector {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(EnumIter, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
|
||||
pub(crate) enum Specificity {
|
||||
#[derive(EnumIter, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Debug)]
|
||||
pub enum Specificity {
|
||||
/// The specificity when selecting all rules (e.g., `--select ALL`).
|
||||
All,
|
||||
/// The specificity when selecting a linter group (e.g., `--select PL`).
|
||||
LinterGroup,
|
||||
/// The specificity when selecting a linter (e.g., `--select PLE` or `--select UP`).
|
||||
Linter,
|
||||
Code1Char,
|
||||
Code2Chars,
|
||||
Code3Chars,
|
||||
Code4Chars,
|
||||
Code5Chars,
|
||||
/// The specificity when selecting via a rule prefix at one-character depth (e.g., `--select PLE1`).
|
||||
Prefix1Char,
|
||||
/// The specificity when selecting via a rule prefix at two-character depth (e.g., `--select PLE12`).
|
||||
Prefix2Chars,
|
||||
/// The specificity when selecting via a rule prefix at one-character depth (e.g., `--select PLE120`).
|
||||
Prefix3Chars,
|
||||
/// The specificity when selecting via a rule prefix at one-character depth (e.g., `--select PLE120`).
|
||||
Prefix4Chars,
|
||||
/// The specificity when selecting an individual rule (e.g., `--select PLE1205`).
|
||||
Rule,
|
||||
}
|
||||
|
||||
#[cfg(feature = "clap")]
|
||||
|
||||
@@ -2,7 +2,8 @@ use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast as ast;
|
||||
use ruff_python_ast::Constant;
|
||||
use ruff_python_ast::{Expr, Ranged};
|
||||
use ruff_python_ast::Expr;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use num_bigint::BigInt;
|
||||
use ruff_python_ast::{self as ast, CmpOp, Constant, Expr, Ranged};
|
||||
use ruff_python_ast::{self as ast, CmpOp, Constant, Expr};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::Rule;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use ruff_python_ast::{Expr, Ranged};
|
||||
use ruff_python_ast::Expr;
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use num_bigint::BigInt;
|
||||
use ruff_python_ast::{self as ast, Constant, Expr, Ranged};
|
||||
use ruff_python_ast::{self as ast, Constant, Expr};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::Rule;
|
||||
|
||||
@@ -3,11 +3,12 @@ use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::helpers::ReturnStatementVisitor;
|
||||
use ruff_python_ast::identifier::Identifier;
|
||||
use ruff_python_ast::statement_visitor::StatementVisitor;
|
||||
use ruff_python_ast::{self as ast, Constant, Expr, ParameterWithDefault, Ranged, Stmt};
|
||||
use ruff_python_ast::{self as ast, Constant, Expr, ParameterWithDefault, Stmt};
|
||||
use ruff_python_parser::typing::parse_type_annotation;
|
||||
use ruff_python_semantic::analyze::visibility;
|
||||
use ruff_python_semantic::Definition;
|
||||
use ruff_python_stdlib::typing::simple_magic_return_type;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::{AsRule, Rule};
|
||||
|
||||
@@ -1,65 +1,6 @@
|
||||
//! Settings for the `flake-annotations` plugin.
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use ruff_macros::{CacheKey, CombineOptions, ConfigurationOptions};
|
||||
|
||||
#[derive(
|
||||
Debug, PartialEq, Eq, Default, Serialize, Deserialize, ConfigurationOptions, CombineOptions,
|
||||
)]
|
||||
#[serde(
|
||||
deny_unknown_fields,
|
||||
rename_all = "kebab-case",
|
||||
rename = "Flake8AnnotationsOptions"
|
||||
)]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub struct Options {
|
||||
#[option(
|
||||
default = "false",
|
||||
value_type = "bool",
|
||||
example = "mypy-init-return = true"
|
||||
)]
|
||||
/// Whether to allow the omission of a return type hint for `__init__` if at
|
||||
/// least one argument is annotated.
|
||||
pub mypy_init_return: Option<bool>,
|
||||
#[option(
|
||||
default = "false",
|
||||
value_type = "bool",
|
||||
example = "suppress-dummy-args = true"
|
||||
)]
|
||||
/// Whether to suppress `ANN000`-level violations for arguments matching the
|
||||
/// "dummy" variable regex (like `_`).
|
||||
pub suppress_dummy_args: Option<bool>,
|
||||
#[option(
|
||||
default = "false",
|
||||
value_type = "bool",
|
||||
example = "suppress-none-returning = true"
|
||||
)]
|
||||
/// Whether to suppress `ANN200`-level violations for functions that meet
|
||||
/// either of the following criteria:
|
||||
///
|
||||
/// - Contain no `return` statement.
|
||||
/// - Explicit `return` statement(s) all return `None` (explicitly or
|
||||
/// implicitly).
|
||||
pub suppress_none_returning: Option<bool>,
|
||||
#[option(
|
||||
default = "false",
|
||||
value_type = "bool",
|
||||
example = "allow-star-arg-any = true"
|
||||
)]
|
||||
/// Whether to suppress `ANN401` for dynamically typed `*args` and
|
||||
/// `**kwargs` arguments.
|
||||
pub allow_star_arg_any: Option<bool>,
|
||||
#[option(
|
||||
default = "false",
|
||||
value_type = "bool",
|
||||
example = "ignore-fully-untyped = true"
|
||||
)]
|
||||
/// Whether to suppress `ANN*` rules for any declaration
|
||||
/// that hasn't been typed at all.
|
||||
/// This makes it easier to gradually add types to a codebase.
|
||||
pub ignore_fully_untyped: Option<bool>,
|
||||
}
|
||||
use ruff_macros::CacheKey;
|
||||
|
||||
#[derive(Debug, Default, CacheKey)]
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
@@ -70,27 +11,3 @@ pub struct Settings {
|
||||
pub allow_star_arg_any: bool,
|
||||
pub ignore_fully_untyped: bool,
|
||||
}
|
||||
|
||||
impl From<Options> for Settings {
|
||||
fn from(options: Options) -> Self {
|
||||
Self {
|
||||
mypy_init_return: options.mypy_init_return.unwrap_or(false),
|
||||
suppress_dummy_args: options.suppress_dummy_args.unwrap_or(false),
|
||||
suppress_none_returning: options.suppress_none_returning.unwrap_or(false),
|
||||
allow_star_arg_any: options.allow_star_arg_any.unwrap_or(false),
|
||||
ignore_fully_untyped: options.ignore_fully_untyped.unwrap_or(false),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Settings> for Options {
|
||||
fn from(settings: Settings) -> Self {
|
||||
Self {
|
||||
mypy_init_return: Some(settings.mypy_init_return),
|
||||
suppress_dummy_args: Some(settings.suppress_dummy_args),
|
||||
suppress_none_returning: Some(settings.suppress_none_returning),
|
||||
allow_star_arg_any: Some(settings.allow_star_arg_any),
|
||||
ignore_fully_untyped: Some(settings.ignore_fully_untyped),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
use ruff_python_ast as ast;
|
||||
use ruff_python_ast::{Expr, Ranged};
|
||||
use ruff_python_ast::Expr;
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::call_path::CallPath;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
use ruff_python_ast as ast;
|
||||
use ruff_python_ast::{Expr, Ranged};
|
||||
use ruff_python_ast::Expr;
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::call_path::CallPath;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
use ruff_python_ast as ast;
|
||||
use ruff_python_ast::{Expr, Ranged};
|
||||
use ruff_python_ast::Expr;
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::call_path::CallPath;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use ruff_python_ast::{Ranged, Stmt};
|
||||
use ruff_python_ast::Stmt;
|
||||
use ruff_text_size::{TextLen, TextRange};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for uses of the `assert` keyword.
|
||||
@@ -22,6 +23,10 @@ use ruff_macros::{derive_message_formats, violation};
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// if not x > 0:
|
||||
/// raise ValueError("Expected positive value.")
|
||||
///
|
||||
/// # or even better:
|
||||
/// if x <= 0:
|
||||
/// raise ValueError("Expected positive value.")
|
||||
/// ```
|
||||
|
||||
@@ -3,8 +3,9 @@ use num_traits::ToPrimitive;
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::call_path::CallPath;
|
||||
use ruff_python_ast::{self as ast, Constant, Expr, Operator, Ranged};
|
||||
use ruff_python_ast::{self as ast, Constant, Expr, Operator};
|
||||
use ruff_python_semantic::SemanticModel;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use ruff_python_ast::{Expr, Ranged};
|
||||
use ruff_python_ast::Expr;
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use ruff_python_ast::{Expr, Parameter, ParameterWithDefault, Parameters, Ranged};
|
||||
use ruff_python_ast::{Expr, Parameter, ParameterWithDefault, Parameters};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use ruff_python_ast::{Keyword, Ranged};
|
||||
use ruff_python_ast::Keyword;
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use ruff_python_ast::{self as ast, Constant, Expr, Ranged};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::{self as ast, Constant, Expr};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use ruff_python_ast::{self as ast, Expr, Operator, Ranged};
|
||||
use ruff_python_ast::{self as ast, Expr, Operator};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::helpers::any_over_expr;
|
||||
use ruff_python_semantic::SemanticModel;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use ruff_python_ast::{self as ast, Expr, Ranged};
|
||||
use ruff_python_ast::{self as ast, Expr};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::helpers::is_const_false;
|
||||
use ruff_python_ast::{self as ast, Arguments, Ranged};
|
||||
use ruff_python_ast::{self as ast, Arguments};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::{self as ast, Constant, Expr, Ranged};
|
||||
use ruff_python_ast::{self as ast, Constant, Expr};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::{self as ast, Ranged};
|
||||
use ruff_python_ast::{self as ast};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use ruff_python_ast::{Expr, Ranged};
|
||||
use ruff_python_ast::Expr;
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast as ast;
|
||||
use ruff_python_ast::helpers::is_const_false;
|
||||
use ruff_python_ast::{self as ast, Ranged};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast as ast;
|
||||
use ruff_python_ast::helpers::is_const_none;
|
||||
use ruff_python_ast::{self as ast, Ranged};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::helpers::Truthiness;
|
||||
use ruff_python_ast::{self as ast, Arguments, Constant, Expr, Keyword, Ranged};
|
||||
use ruff_python_ast::{self as ast, Arguments, Constant, Expr, Keyword};
|
||||
use ruff_python_semantic::SemanticModel;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::{
|
||||
checkers::ast::Checker, registry::Rule, rules::flake8_bandit::helpers::string_literal,
|
||||
|
||||
@@ -2,7 +2,8 @@ use num_traits::{One, Zero};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::{self as ast, Constant, Expr, Ranged};
|
||||
use ruff_python_ast::{self as ast, Constant, Expr};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::{self as ast, Ranged};
|
||||
use ruff_python_ast::{self as ast};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
//! Check for calls to suspicious functions, or calls into suspicious modules.
|
||||
//!
|
||||
//! See: <https://bandit.readthedocs.io/en/latest/blacklists/blacklist_calls.html>
|
||||
use ruff_python_ast::{self as ast, Expr, Ranged};
|
||||
use ruff_python_ast::{self as ast, Expr};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, DiagnosticKind, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::AsRule;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use ruff_python_ast::{ExceptHandler, Expr, Ranged, Stmt};
|
||||
use ruff_python_ast::{ExceptHandler, Expr, Stmt};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::rules::flake8_bandit::helpers::is_untyped_exception;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use ruff_python_ast::{ExceptHandler, Expr, Ranged, Stmt};
|
||||
use ruff_python_ast::{ExceptHandler, Expr, Stmt};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::rules::flake8_bandit::helpers::is_untyped_exception;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::{self as ast, Expr, Ranged};
|
||||
use ruff_python_ast::{self as ast, Expr};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
|
||||
@@ -1,81 +1,19 @@
|
||||
//! Settings for the `flake8-bandit` plugin.
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ruff_macros::CacheKey;
|
||||
|
||||
use ruff_macros::{CacheKey, CombineOptions, ConfigurationOptions};
|
||||
|
||||
fn default_tmp_dirs() -> Vec<String> {
|
||||
pub fn default_tmp_dirs() -> Vec<String> {
|
||||
["/tmp", "/var/tmp", "/dev/shm"]
|
||||
.map(ToString::to_string)
|
||||
.to_vec()
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug, PartialEq, Eq, Serialize, Deserialize, Default, ConfigurationOptions, CombineOptions,
|
||||
)]
|
||||
#[serde(
|
||||
deny_unknown_fields,
|
||||
rename_all = "kebab-case",
|
||||
rename = "Flake8BanditOptions"
|
||||
)]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub struct Options {
|
||||
#[option(
|
||||
default = "[\"/tmp\", \"/var/tmp\", \"/dev/shm\"]",
|
||||
value_type = "list[str]",
|
||||
example = "hardcoded-tmp-directory = [\"/foo/bar\"]"
|
||||
)]
|
||||
/// A list of directories to consider temporary.
|
||||
pub hardcoded_tmp_directory: Option<Vec<String>>,
|
||||
#[option(
|
||||
default = "[]",
|
||||
value_type = "list[str]",
|
||||
example = "extend-hardcoded-tmp-directory = [\"/foo/bar\"]"
|
||||
)]
|
||||
/// A list of directories to consider temporary, in addition to those
|
||||
/// specified by `hardcoded-tmp-directory`.
|
||||
pub hardcoded_tmp_directory_extend: Option<Vec<String>>,
|
||||
#[option(
|
||||
default = "false",
|
||||
value_type = "bool",
|
||||
example = "check-typed-exception = true"
|
||||
)]
|
||||
/// Whether to disallow `try`-`except`-`pass` (`S110`) for specific
|
||||
/// exception types. By default, `try`-`except`-`pass` is only
|
||||
/// disallowed for `Exception` and `BaseException`.
|
||||
pub check_typed_exception: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, CacheKey)]
|
||||
pub struct Settings {
|
||||
pub hardcoded_tmp_directory: Vec<String>,
|
||||
pub check_typed_exception: bool,
|
||||
}
|
||||
|
||||
impl From<Options> for Settings {
|
||||
fn from(options: Options) -> Self {
|
||||
Self {
|
||||
hardcoded_tmp_directory: options
|
||||
.hardcoded_tmp_directory
|
||||
.unwrap_or_else(default_tmp_dirs)
|
||||
.into_iter()
|
||||
.chain(options.hardcoded_tmp_directory_extend.unwrap_or_default())
|
||||
.collect(),
|
||||
check_typed_exception: options.check_typed_exception.unwrap_or(false),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Settings> for Options {
|
||||
fn from(settings: Settings) -> Self {
|
||||
Self {
|
||||
hardcoded_tmp_directory: Some(settings.hardcoded_tmp_directory),
|
||||
hardcoded_tmp_directory_extend: None,
|
||||
check_typed_exception: Some(settings.check_typed_exception),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Settings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::helpers::is_const_true;
|
||||
use ruff_python_ast::{self as ast, Expr, Ranged, Stmt};
|
||||
use ruff_python_ast::{self as ast, Expr, Stmt};
|
||||
use ruff_python_semantic::analyze::logging;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::call_path::collect_call_path;
|
||||
use ruff_python_ast::{Decorator, ParameterWithDefault, Parameters, Ranged};
|
||||
use ruff_python_ast::{Decorator, ParameterWithDefault, Parameters};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::rules::flake8_boolean_trap::helpers::{is_allowed_func_def, is_boolean};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::{Expr, Ranged};
|
||||
use ruff_python_ast::Expr;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::rules::flake8_boolean_trap::helpers::{allow_boolean_trap, is_boolean};
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
use ruff_python_ast::{
|
||||
self as ast, Constant, Decorator, Expr, ParameterWithDefault, Parameters, Ranged,
|
||||
};
|
||||
use ruff_python_ast::{self as ast, Constant, Decorator, Expr, ParameterWithDefault, Parameters};
|
||||
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
use ruff_diagnostics::Violation;
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::call_path::collect_call_path;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::rules::flake8_boolean_trap::helpers::is_allowed_func_def;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
use ruff_python_ast::{self as ast, Arguments, Constant, Expr, Keyword, Ranged, Stmt};
|
||||
use ruff_python_ast::{self as ast, Arguments, Constant, Expr, Keyword, Stmt};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::identifier::Identifier;
|
||||
use ruff_python_semantic::analyze::visibility::{is_abstract, is_overload};
|
||||
use ruff_python_semantic::SemanticModel;
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::Rule;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user