Compare commits
92 Commits
v0.0.255
...
blacklist_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c2d430430 | ||
|
|
b0242ccfa1 | ||
|
|
8ffc77d0ee | ||
|
|
adc677bc9c | ||
|
|
213e83aff2 | ||
|
|
4b91826a0b | ||
|
|
27903cdb11 | ||
|
|
3b1709ba1e | ||
|
|
33394e4a69 | ||
|
|
7b9bdc494a | ||
|
|
b06ca25421 | ||
|
|
c42f8b93d2 | ||
|
|
f59a22b6e5 | ||
|
|
b5edc6dfc9 | ||
|
|
626169e2ef | ||
|
|
e9f359ac5e | ||
|
|
318c2c80e2 | ||
|
|
92aa3a8178 | ||
|
|
22a4ab51f9 | ||
|
|
f70a49ed8b | ||
|
|
f039bf36a2 | ||
|
|
169dd72328 | ||
|
|
fd39ec4bdd | ||
|
|
7c0f17279c | ||
|
|
81d0884974 | ||
|
|
a45753f462 | ||
|
|
b08326162b | ||
|
|
3a65af4dae | ||
|
|
474aa0b196 | ||
|
|
4892167217 | ||
|
|
a5494b8541 | ||
|
|
9ac9a1c69e | ||
|
|
f06dff8af8 | ||
|
|
fe7443ce2f | ||
|
|
4bdb2dd362 | ||
|
|
53a4743631 | ||
|
|
4ffcd8366a | ||
|
|
dfb772c6f1 | ||
|
|
c21eb06922 | ||
|
|
16a350c731 | ||
|
|
fa04861724 | ||
|
|
404504ab41 | ||
|
|
621e4353e3 | ||
|
|
0c4926ff7b | ||
|
|
61653b9f27 | ||
|
|
8dd3959e74 | ||
|
|
50f9db21da | ||
|
|
1dd3cbd047 | ||
|
|
bd935cbd49 | ||
|
|
babd0a05ac | ||
|
|
87fab4a2e1 | ||
|
|
2e21920adf | ||
|
|
dedf4cbdeb | ||
|
|
92179e6369 | ||
|
|
33d2457909 | ||
|
|
373a77e8c2 | ||
|
|
73df267635 | ||
|
|
f5e5caaa25 | ||
|
|
d9ed0aae69 | ||
|
|
e0df62b841 | ||
|
|
bbc87b7177 | ||
|
|
667130a4c3 | ||
|
|
72febf98b7 | ||
|
|
e99e1fae2b | ||
|
|
eff84442bc | ||
|
|
aa51ecedc5 | ||
|
|
9ae9cc9d2f | ||
|
|
de1106b95a | ||
|
|
e636c5fcf0 | ||
|
|
12dfd57211 | ||
|
|
d188d242a0 | ||
|
|
57796c5e59 | ||
|
|
2545869797 | ||
|
|
58353a4bf4 | ||
|
|
a36139ae21 | ||
|
|
7e904111b1 | ||
|
|
344daebb1b | ||
|
|
432059de35 | ||
|
|
c50d6da8b4 | ||
|
|
1b738f88c4 | ||
|
|
1eff3dffa5 | ||
|
|
8c7317eb8d | ||
|
|
106a93eab0 | ||
|
|
78c2b0ac47 | ||
|
|
d5700d7c69 | ||
|
|
3a7bdb39c9 | ||
|
|
a82fe4a139 | ||
|
|
62ff3b62e3 | ||
|
|
1e5db58b7b | ||
|
|
a6e998d639 | ||
|
|
a8c1915e2e | ||
|
|
c515a1b31a |
@@ -1,5 +1,6 @@
|
||||
[alias]
|
||||
dev = "run --package ruff_dev --bin ruff_dev"
|
||||
benchmark = "bench -p ruff_benchmark --"
|
||||
|
||||
[target.'cfg(all())']
|
||||
rustflags = [
|
||||
|
||||
11
.github/dependabot.yml
vendored
Normal file
11
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
day: "monday"
|
||||
time: "12:00"
|
||||
timezone: "America/New_York"
|
||||
commit-message:
|
||||
prefix: "ci(deps)"
|
||||
135
.github/workflows/benchmark.yaml
vendored
Normal file
135
.github/workflows/benchmark.yaml
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
name: Benchmark
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
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"
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: bench
|
||||
args: -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"
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: bench
|
||||
args: -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 cargo-binstall"
|
||||
uses: taiki-e/install-action@cargo-binstall
|
||||
|
||||
- name: "Install critcmp"
|
||||
run: cargo binstall critcmp -y
|
||||
|
||||
- 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
|
||||
33
.github/workflows/ci.yaml
vendored
33
.github/workflows/ci.yaml
vendored
@@ -34,7 +34,7 @@ jobs:
|
||||
- name: "Install Rust toolchain"
|
||||
run: |
|
||||
rustup component add clippy
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- run: cargo clippy --workspace --all-targets --all-features -- -D warnings
|
||||
|
||||
cargo-clippy-wasm:
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
run: |
|
||||
rustup component add clippy
|
||||
rustup target add wasm32-unknown-unknown
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- run: cargo clippy -p ruff_wasm --target wasm32-unknown-unknown --all-features -- -D warnings
|
||||
|
||||
cargo-test:
|
||||
@@ -59,9 +59,9 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup show
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- run: cargo install cargo-insta
|
||||
- run: pip install black[d]==22.12.0
|
||||
- run: pip install black[d]==23.1.0
|
||||
- name: "Run tests (Ubuntu)"
|
||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||
run: |
|
||||
@@ -80,6 +80,7 @@ jobs:
|
||||
# Setting RUSTDOCFLAGS because `cargo doc --check` isn't yet implemented (https://github.com/rust-lang/cargo/issues/10025).
|
||||
RUSTDOCFLAGS: "-D warnings"
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||
with:
|
||||
name: ruff
|
||||
path: target/debug/ruff
|
||||
@@ -98,7 +99,7 @@ jobs:
|
||||
cache: "npm"
|
||||
cache-dependency-path: playground/package-lock.json
|
||||
- uses: jetli/wasm-pack-action@v0.4.0
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- name: "Run wasm-pack"
|
||||
run: |
|
||||
cd crates/ruff_wasm
|
||||
@@ -111,7 +112,7 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup show
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- run: ./scripts/add_rule.py --name DoTheThing --code PLC999 --linter pylint
|
||||
- run: cargo check
|
||||
- run: |
|
||||
@@ -139,27 +140,39 @@ jobs:
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.11"
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
name: Download Ruff binary
|
||||
id: ruff-target
|
||||
with:
|
||||
name: ruff
|
||||
path: target/debug
|
||||
|
||||
- uses: dawidd6/action-download-artifact@v2
|
||||
name: Download base results
|
||||
with:
|
||||
name: ruff
|
||||
branch: ${{ github.event.pull_request.base_ref }}
|
||||
branch: ${{ github.event.pull_request.base.ref }}
|
||||
check_artifacts: true
|
||||
|
||||
- name: Run ecosystem check
|
||||
run: |
|
||||
# Make executable, since artifact download doesn't preserve this
|
||||
chmod +x ruff ${{ steps.ruff-target.outputs.download-path }}/ruff
|
||||
|
||||
scripts/check_ecosystem.py ruff ${{ steps.ruff-target.outputs.download-path }}/ruff | tee ecosystem-result
|
||||
cat ecosystem-result > $GITHUB_STEP_SUMMARY
|
||||
|
||||
echo ${{ github.event.number }} > pr-number
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
name: Upload PR Number
|
||||
with:
|
||||
name: pr-number
|
||||
path: pr-number
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
name: Upload Results
|
||||
with:
|
||||
name: ecosystem-result
|
||||
path: |
|
||||
ecosystem-result
|
||||
pr-number
|
||||
path: ecosystem-result
|
||||
|
||||
2
.github/workflows/docs.yaml
vendored
2
.github/workflows/docs.yaml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
- uses: actions/setup-python@v4
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup show
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- name: "Install dependencies"
|
||||
run: |
|
||||
pip install -r docs/requirements.txt
|
||||
|
||||
31
.github/workflows/ecosystem-comment.yaml
vendored
31
.github/workflows/ecosystem-comment.yaml
vendored
@@ -1,31 +0,0 @@
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: [CI]
|
||||
types: [completed]
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
comment:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: dawidd6/action-download-artifact@v2
|
||||
id: download-result
|
||||
with:
|
||||
name: ecosystem-result
|
||||
workflow: ci.yaml
|
||||
run_id: ${{ github.event.workflow_run.id }}
|
||||
if_no_artifact_found: ignore
|
||||
- if: steps.download-result.outputs.found_artifact
|
||||
id: result
|
||||
run: |
|
||||
echo "pr-number=$(<pr-number)" >> $GITHUB_OUTPUT
|
||||
- name: Create comment
|
||||
if: steps.download-result.outputs.found_artifact
|
||||
uses: thollander/actions-comment-pull-request@v2
|
||||
with:
|
||||
pr_number: ${{ steps.result.outputs.pr-number }}
|
||||
filePath: ecosystem-result
|
||||
comment_tag: ecosystem-results
|
||||
4
.github/workflows/flake8-to-ruff.yaml
vendored
4
.github/workflows/flake8-to-ruff.yaml
vendored
@@ -133,7 +133,7 @@ jobs:
|
||||
target: ${{ matrix.target }}
|
||||
manylinux: auto
|
||||
args: --no-default-features --release --out dist -m ./${{ env.CRATE_NAME }}/Cargo.toml
|
||||
- uses: uraimo/run-on-arch-action@v2.5.0
|
||||
- uses: uraimo/run-on-arch-action@v2
|
||||
if: matrix.target != 'ppc64'
|
||||
name: Install built wheel
|
||||
with:
|
||||
@@ -206,7 +206,7 @@ jobs:
|
||||
target: ${{ matrix.platform.target }}
|
||||
manylinux: musllinux_1_2
|
||||
args: --release --out dist -m ./${{ env.CRATE_NAME }}/Cargo.toml
|
||||
- uses: uraimo/run-on-arch-action@master
|
||||
- uses: uraimo/run-on-arch-action@v2
|
||||
name: Install built wheel
|
||||
with:
|
||||
arch: ${{ matrix.platform.arch }}
|
||||
|
||||
84
.github/workflows/pr-comment.yaml
vendored
Normal file
84
.github/workflows/pr-comment.yaml
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
name: PR Check Comment
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: [CI, Benchmark]
|
||||
types: [completed]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
workflow_run_id:
|
||||
description: The ecosystem workflow that triggers the workflow run
|
||||
required: true
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
comment:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dawidd6/action-download-artifact@v2
|
||||
name: Download PR Number
|
||||
with:
|
||||
name: pr-number
|
||||
run_id: ${{ github.event.workflow_run.id || github.event.inputs.workflow_run_id }}
|
||||
if_no_artifact_found: ignore
|
||||
|
||||
- name: Extract PR Number
|
||||
id: pr-number
|
||||
run: |
|
||||
if [[ -f pr-number ]]
|
||||
then
|
||||
echo "pr-number=$(<pr-number)" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- uses: dawidd6/action-download-artifact@v2
|
||||
name: "Download Ecosystem Result"
|
||||
id: download-ecosystem-result
|
||||
if: steps.pr-number.outputs.pr-number
|
||||
with:
|
||||
name: ecosystem-result
|
||||
workflow: ci.yaml
|
||||
pr: ${{ steps.pr-number.outputs.pr-number }}
|
||||
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'
|
||||
run: |
|
||||
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
|
||||
|
||||
echo 'EOF' >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Create or update comment
|
||||
if: steps.generate-comment.outputs.comment
|
||||
uses: thollander/actions-comment-pull-request@v2
|
||||
with:
|
||||
pr_number: ${{ steps.pr-number.outputs.pr-number }}
|
||||
message: ${{ steps.generate-comment.outputs.comment }}
|
||||
comment_tag: PR Check Results
|
||||
4
.github/workflows/ruff.yaml
vendored
4
.github/workflows/ruff.yaml
vendored
@@ -208,7 +208,7 @@ jobs:
|
||||
target: ${{ matrix.platform.target }}
|
||||
manylinux: auto
|
||||
args: --release --out dist
|
||||
- uses: uraimo/run-on-arch-action@v2.5.0
|
||||
- uses: uraimo/run-on-arch-action@v2
|
||||
if: matrix.platform.arch != 'ppc64'
|
||||
name: Install built wheel
|
||||
with:
|
||||
@@ -309,7 +309,7 @@ jobs:
|
||||
target: ${{ matrix.platform.target }}
|
||||
manylinux: musllinux_1_2
|
||||
args: --release --out dist
|
||||
- uses: uraimo/run-on-arch-action@master
|
||||
- uses: uraimo/run-on-arch-action@v2
|
||||
name: Install built wheel
|
||||
with:
|
||||
arch: ${{ matrix.platform.arch }}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
fail_fast: true
|
||||
repos:
|
||||
- repo: https://github.com/abravalheri/validate-pyproject
|
||||
rev: v0.10.1
|
||||
rev: v0.12.1
|
||||
hooks:
|
||||
- id: validate-pyproject
|
||||
|
||||
@@ -28,17 +28,17 @@ repos:
|
||||
- id: cargo-fmt
|
||||
name: cargo fmt
|
||||
entry: cargo fmt --
|
||||
language: rust
|
||||
language: system
|
||||
types: [rust]
|
||||
- id: clippy
|
||||
name: clippy
|
||||
entry: cargo clippy --workspace --all-targets --all-features -- -D warnings
|
||||
language: rust
|
||||
language: system
|
||||
pass_filenames: false
|
||||
- id: ruff
|
||||
name: ruff
|
||||
entry: cargo run -p ruff_cli -- check --no-cache --force-exclude --fix --exit-non-zero-on-fix
|
||||
language: rust
|
||||
language: system
|
||||
types_or: [python, pyi]
|
||||
require_serial: true
|
||||
exclude: |
|
||||
@@ -49,7 +49,7 @@ repos:
|
||||
- id: dev-generate-all
|
||||
name: dev-generate-all
|
||||
entry: cargo dev generate-all
|
||||
language: rust
|
||||
language: system
|
||||
pass_filenames: false
|
||||
exclude: target
|
||||
|
||||
|
||||
@@ -145,4 +145,4 @@ default.
|
||||
`pyproject.toml` files are now resolved hierarchically, such that for each Python file, we find
|
||||
the first `pyproject.toml` file in its path, and use that to determine its lint settings.
|
||||
|
||||
See the [README](https://github.com/charliermarsh/ruff#pyprojecttoml-discovery) for more.
|
||||
See the [documentation](https://beta.ruff.rs/docs/configuration/#python-file-discovery) for more.
|
||||
|
||||
41
Cargo.lock
generated
41
Cargo.lock
generated
@@ -313,13 +313,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_complete_command"
|
||||
version = "0.4.0"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4160b4a4f72ef58bd766bad27c09e6ef1cc9d82a22f6a0f55d152985a4a48e31"
|
||||
checksum = "183495371ea78d4c9ff638bfc6497d46fed2396e4f9c50aebc1278a4a9919a3d"
|
||||
dependencies = [
|
||||
"clap 4.1.8",
|
||||
"clap_complete",
|
||||
"clap_complete_fig",
|
||||
"clap_complete_nushell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -332,6 +333,16 @@ dependencies = [
|
||||
"clap_complete",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_complete_nushell"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7fa41f5e6aa83bd151b70fd0ceaee703d68cd669522795dc812df9edad1252c"
|
||||
dependencies = [
|
||||
"clap 4.1.8",
|
||||
"clap_complete",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.1.8"
|
||||
@@ -769,7 +780,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.255"
|
||||
version = "0.0.257"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.1.8",
|
||||
@@ -1971,7 +1982,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.255"
|
||||
version = "0.0.257"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bisection",
|
||||
@@ -1979,7 +1990,6 @@ dependencies = [
|
||||
"chrono",
|
||||
"clap 4.1.8",
|
||||
"colored",
|
||||
"criterion",
|
||||
"dirs",
|
||||
"fern",
|
||||
"glob",
|
||||
@@ -2014,6 +2024,7 @@ dependencies = [
|
||||
"schemars",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"shellexpand",
|
||||
"smallvec",
|
||||
"strum",
|
||||
@@ -2024,6 +2035,21 @@ dependencies = [
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff_benchmark"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"criterion",
|
||||
"mimalloc",
|
||||
"once_cell",
|
||||
"ruff",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tikv-jemallocator",
|
||||
"ureq",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff_cache"
|
||||
version = "0.0.0"
|
||||
@@ -2037,7 +2063,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_cli"
|
||||
version = "0.0.255"
|
||||
version = "0.0.257"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.9.1",
|
||||
"anyhow",
|
||||
@@ -2065,6 +2091,7 @@ dependencies = [
|
||||
"ruff",
|
||||
"ruff_cache",
|
||||
"ruff_diagnostics",
|
||||
"ruff_python_stdlib",
|
||||
"rustc-hash",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -2184,7 +2211,6 @@ name = "ruff_python_stdlib"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
]
|
||||
|
||||
@@ -2479,6 +2505,7 @@ version = "1.0.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
|
||||
15
Cargo.toml
15
Cargo.toml
@@ -4,6 +4,10 @@ members = ["crates/*"]
|
||||
[workspace.package]
|
||||
edition = "2021"
|
||||
rust-version = "1.67"
|
||||
homepage = "https://beta.ruff.rs/docs/"
|
||||
documentation = "https://beta.ruff.rs/docs/"
|
||||
repository = "https://github.com/charliermarsh/ruff"
|
||||
authors = ["Charlie Marsh <charlie.r.marsh@gmail.com>"]
|
||||
|
||||
[workspace.dependencies]
|
||||
anyhow = { version = "1.0.69" }
|
||||
@@ -33,7 +37,7 @@ rustpython-parser = { features = [
|
||||
], git = "https://github.com/RustPython/RustPython.git", rev = "c15f670f2c30cfae6b41a1874893590148c74bc4" }
|
||||
schemars = { version = "0.8.12" }
|
||||
serde = { version = "1.0.152", features = ["derive"] }
|
||||
serde_json = { version = "1.0.93" }
|
||||
serde_json = { version = "1.0.93", features = ["preserve_order"] }
|
||||
shellexpand = { version = "3.0.0" }
|
||||
similar = { version = "2.2.1" }
|
||||
strum = { version = "0.24.1", features = ["strum_macros"] }
|
||||
@@ -44,8 +48,7 @@ textwrap = { version = "0.16.0" }
|
||||
toml = { version = "0.7.2" }
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
lto = "thin"
|
||||
lto = "fat"
|
||||
codegen-units = 1
|
||||
opt-level = 3
|
||||
|
||||
@@ -59,3 +62,9 @@ opt-level = 3
|
||||
# https://github.com/bytecodealliance/wasm-tools/blob/b5c3d98e40590512a3b12470ef358d5c7b983b15/crates/wasmparser/src/limits.rs#L29
|
||||
[profile.dev.package.rustpython-parser]
|
||||
opt-level = 1
|
||||
|
||||
# Use the `--profile release-debug` flag to show symbols in release mode.
|
||||
# e.g. `cargo build --profile release-debug`
|
||||
[profile.release-debug]
|
||||
inherits = "release"
|
||||
debug = 1
|
||||
|
||||
26
LICENSE
26
LICENSE
@@ -393,7 +393,6 @@ are:
|
||||
THE SOFTWARE.
|
||||
"""
|
||||
|
||||
|
||||
- autoflake, licensed as follows:
|
||||
"""
|
||||
Copyright (C) 2012-2018 Steven Myint
|
||||
@@ -417,6 +416,31 @@ are:
|
||||
SOFTWARE.
|
||||
"""
|
||||
|
||||
- autotyping, licensed as follows:
|
||||
"""
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Jelle Zijlstra
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
"""
|
||||
|
||||
- Flake8, licensed as follows:
|
||||
"""
|
||||
== Flake8 License (MIT) ==
|
||||
|
||||
55
README.md
55
README.md
@@ -137,7 +137,7 @@ Ruff can also be used as a [pre-commit](https://pre-commit.com) hook:
|
||||
```yaml
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: 'v0.0.255'
|
||||
rev: 'v0.0.257'
|
||||
hooks:
|
||||
- id: ruff
|
||||
```
|
||||
@@ -227,6 +227,54 @@ stylistic rules made obsolete by the use of an autoformatter, like
|
||||
If you're just getting started with Ruff, **the default rule set is a great place to start**: it
|
||||
catches a wide variety of common errors (like unused imports) with zero configuration.
|
||||
|
||||
Beyond the defaults, Ruff re-implements some of the most popular Flake8 plugins and related code
|
||||
quality tools, including:
|
||||
|
||||
- [autoflake](https://pypi.org/project/autoflake/)
|
||||
- [eradicate](https://pypi.org/project/eradicate/)
|
||||
- [flake8-2020](https://pypi.org/project/flake8-2020/)
|
||||
- [flake8-annotations](https://pypi.org/project/flake8-annotations/)
|
||||
- [flake8-bandit](https://pypi.org/project/flake8-bandit/) ([#1646](https://github.com/charliermarsh/ruff/issues/1646))
|
||||
- [flake8-blind-except](https://pypi.org/project/flake8-blind-except/)
|
||||
- [flake8-boolean-trap](https://pypi.org/project/flake8-boolean-trap/)
|
||||
- [flake8-bugbear](https://pypi.org/project/flake8-bugbear/)
|
||||
- [flake8-builtins](https://pypi.org/project/flake8-builtins/)
|
||||
- [flake8-commas](https://pypi.org/project/flake8-commas/)
|
||||
- [flake8-comprehensions](https://pypi.org/project/flake8-comprehensions/)
|
||||
- [flake8-datetimez](https://pypi.org/project/flake8-datetimez/)
|
||||
- [flake8-debugger](https://pypi.org/project/flake8-debugger/)
|
||||
- [flake8-django](https://pypi.org/project/flake8-django/) ([#2817](https://github.com/charliermarsh/ruff/issues/2817))
|
||||
- [flake8-docstrings](https://pypi.org/project/flake8-docstrings/)
|
||||
- [flake8-eradicate](https://pypi.org/project/flake8-eradicate/)
|
||||
- [flake8-errmsg](https://pypi.org/project/flake8-errmsg/)
|
||||
- [flake8-executable](https://pypi.org/project/flake8-executable/)
|
||||
- [flake8-implicit-str-concat](https://pypi.org/project/flake8-implicit-str-concat/)
|
||||
- [flake8-import-conventions](https://github.com/joaopalmeiro/flake8-import-conventions)
|
||||
- [flake8-logging-format](https://pypi.org/project/flake8-logging-format/)
|
||||
- [flake8-no-pep420](https://pypi.org/project/flake8-no-pep420)
|
||||
- [flake8-pie](https://pypi.org/project/flake8-pie/)
|
||||
- [flake8-print](https://pypi.org/project/flake8-print/)
|
||||
- [flake8-pyi](https://pypi.org/project/flake8-pyi/)
|
||||
- [flake8-pytest-style](https://pypi.org/project/flake8-pytest-style/)
|
||||
- [flake8-quotes](https://pypi.org/project/flake8-quotes/)
|
||||
- [flake8-raise](https://pypi.org/project/flake8-raise/)
|
||||
- [flake8-return](https://pypi.org/project/flake8-return/)
|
||||
- [flake8-self](https://pypi.org/project/flake8-self/)
|
||||
- [flake8-simplify](https://pypi.org/project/flake8-simplify/)
|
||||
- [flake8-super](https://pypi.org/project/flake8-super/)
|
||||
- [flake8-tidy-imports](https://pypi.org/project/flake8-tidy-imports/)
|
||||
- [flake8-type-checking](https://pypi.org/project/flake8-type-checking/)
|
||||
- [flake8-use-pathlib](https://pypi.org/project/flake8-use-pathlib/)
|
||||
- [isort](https://pypi.org/project/isort/)
|
||||
- [mccabe](https://pypi.org/project/mccabe/)
|
||||
- [pandas-vet](https://pypi.org/project/pandas-vet/)
|
||||
- [pep8-naming](https://pypi.org/project/pep8-naming/)
|
||||
- [pydocstyle](https://pypi.org/project/pydocstyle/)
|
||||
- [pygrep-hooks](https://github.com/pre-commit/pygrep-hooks) ([#980](https://github.com/charliermarsh/ruff/issues/980))
|
||||
- [pyupgrade](https://pypi.org/project/pyupgrade/)
|
||||
- [tryceratops](https://pypi.org/project/tryceratops/)
|
||||
- [yesqa](https://pypi.org/project/yesqa/)
|
||||
|
||||
<!-- End section: Rules -->
|
||||
|
||||
For a complete enumeration of the supported rules, see [_Rules_](https://beta.ruff.rs/docs/rules/).
|
||||
@@ -280,6 +328,7 @@ Ruff is used in a number of major open-source projects, including:
|
||||
- [Zulip](https://github.com/zulip/zulip)
|
||||
- [Bokeh](https://github.com/bokeh/bokeh)
|
||||
- [Pydantic](https://github.com/pydantic/pydantic)
|
||||
- [PostHog](https://github.com/PostHog/posthog)
|
||||
- [Dagster](https://github.com/dagster-io/dagster)
|
||||
- [Dagger](https://github.com/dagger/dagger)
|
||||
- [Sphinx](https://github.com/sphinx-doc/sphinx)
|
||||
@@ -309,6 +358,10 @@ Ruff is used in a number of major open-source projects, including:
|
||||
- [Starlite](https://github.com/starlite-api/starlite)
|
||||
- [telemetry-airflow (Mozilla)](https://github.com/mozilla/telemetry-airflow)
|
||||
- [Stable Baselines3](https://github.com/DLR-RM/stable-baselines3)
|
||||
- [PaddlePaddle](https://github.com/PaddlePaddle/Paddle)
|
||||
- [nox](https://github.com/wntrblm/nox)
|
||||
- [Neon](https://github.com/neondatabase/neon)
|
||||
- [The Algorithms](https://github.com/TheAlgorithms/Python)
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.255"
|
||||
version = "0.0.257"
|
||||
edition = { workspace = true }
|
||||
rust-version = { workspace = true }
|
||||
|
||||
|
||||
@@ -85,8 +85,9 @@ flake8-to-ruff path/to/.flake8 --plugin flake8-builtins --plugin flake8-quotes
|
||||
ignore unsupported options in the `.flake8` file (or equivalent). (Similarly, Ruff has a few
|
||||
configuration options that don't exist in Flake8.)
|
||||
1. Ruff will omit any rule codes that are unimplemented or unsupported by Ruff, including rule
|
||||
codes from unsupported plugins. (See the [Ruff README](https://github.com/charliermarsh/ruff#user-content-how-does-ruff-compare-to-flake8)
|
||||
for the complete list of supported plugins.)
|
||||
codes from unsupported plugins. (See the
|
||||
[documentation](https://beta.ruff.rs/docs/faq/#how-does-ruff-compare-to-flake8) for the complete
|
||||
list of supported plugins.)
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
[package]
|
||||
name = "ruff"
|
||||
version = "0.0.255"
|
||||
authors = ["Charlie Marsh <charlie.r.marsh@gmail.com>"]
|
||||
edition = { workspace = true }
|
||||
rust-version = { workspace = true }
|
||||
documentation = "https://github.com/charliermarsh/ruff"
|
||||
homepage = "https://github.com/charliermarsh/ruff"
|
||||
repository = "https://github.com/charliermarsh/ruff"
|
||||
version = "0.0.257"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
documentation.workspace = true
|
||||
homepage.workspace = true
|
||||
repository.workspace = true
|
||||
readme = "README.md"
|
||||
license = "MIT"
|
||||
|
||||
@@ -25,7 +25,7 @@ anyhow = { workspace = true }
|
||||
bisection = { version = "0.1.0" }
|
||||
bitflags = { workspace = true }
|
||||
chrono = { workspace = true }
|
||||
clap = { workspace = true, features = ["derive", "env", "string"] }
|
||||
clap = { workspace = true, features = ["derive", "string"], optional = true }
|
||||
colored = { workspace = true }
|
||||
dirs = { version = "4.0.0" }
|
||||
fern = { version = "0.6.1" }
|
||||
@@ -65,14 +65,13 @@ strum_macros = { workspace = true }
|
||||
textwrap = { workspace = true }
|
||||
thiserror = { version = "1.0.38" }
|
||||
toml = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = { version = "0.4.0" }
|
||||
insta = { workspace = true, features = ["yaml", "redactions"] }
|
||||
pretty_assertions = "1.3.0"
|
||||
test-case = { workspace = true }
|
||||
|
||||
|
||||
[features]
|
||||
default = []
|
||||
logical_lines = []
|
||||
jupyter_notebook = []
|
||||
|
||||
@@ -2,3 +2,6 @@ avoid-*
|
||||
do-not-*
|
||||
uses-*
|
||||
*-used
|
||||
rewrite-*
|
||||
prefer-*
|
||||
consider-*
|
||||
|
||||
42
crates/ruff/resources/test/fixtures/flake8_annotations/simple_magic_methods.py
vendored
Normal file
42
crates/ruff/resources/test/fixtures/flake8_annotations/simple_magic_methods.py
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
class Foo:
|
||||
def __str__(self):
|
||||
...
|
||||
|
||||
def __repr__(self):
|
||||
...
|
||||
|
||||
def __len__(self):
|
||||
...
|
||||
|
||||
def __length_hint__(self):
|
||||
...
|
||||
|
||||
def __init__(self):
|
||||
...
|
||||
|
||||
def __del__(self):
|
||||
...
|
||||
|
||||
def __bool__(self):
|
||||
...
|
||||
|
||||
def __bytes__(self):
|
||||
...
|
||||
|
||||
def __format__(self, format_spec):
|
||||
...
|
||||
|
||||
def __contains__(self, item):
|
||||
...
|
||||
|
||||
def __complex__(self):
|
||||
...
|
||||
|
||||
def __int__(self):
|
||||
...
|
||||
|
||||
def __float__(self):
|
||||
...
|
||||
|
||||
def __index__(self):
|
||||
...
|
||||
6
crates/ruff/resources/test/fixtures/flake8_bandit/S001.py
vendored
Normal file
6
crates/ruff/resources/test/fixtures/flake8_bandit/S001.py
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
import pickle
|
||||
from telnetlib import Telnet
|
||||
|
||||
pickle.loads()
|
||||
|
||||
Telnet("localhost", 23)
|
||||
11
crates/ruff/resources/test/fixtures/flake8_bugbear/B028.py
vendored
Normal file
11
crates/ruff/resources/test/fixtures/flake8_bugbear/B028.py
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
import warnings
|
||||
|
||||
"""
|
||||
Should emit:
|
||||
B028 - on lines 8 and 9
|
||||
"""
|
||||
|
||||
warnings.warn(DeprecationWarning("test"))
|
||||
warnings.warn(DeprecationWarning("test"), source=None)
|
||||
warnings.warn(DeprecationWarning("test"), source=None, stacklevel=2)
|
||||
warnings.warn(DeprecationWarning("test"), stacklevel=1)
|
||||
@@ -1,6 +1,19 @@
|
||||
x = [1, 2, 3]
|
||||
y = [("a", 1), ("b", 2), ("c", 3)]
|
||||
z = [(1,), (2,), (3,)]
|
||||
d = {"a": 1, "b": 2, "c": 3}
|
||||
|
||||
[i for i in x]
|
||||
{i for i in x}
|
||||
{k: v for k, v in y}
|
||||
{k: v for k, v in d.items()}
|
||||
|
||||
[i for i, in z]
|
||||
[i for i, j in y]
|
||||
[i for i in x if i > 1]
|
||||
[i for i in x for j in x]
|
||||
|
||||
{v: k for k, v in y}
|
||||
{k.foo: k for k in y}
|
||||
{k["foo"]: k for k in y}
|
||||
{k: v if v else None for k, v in y}
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
import math
|
||||
import os
|
||||
import sys
|
||||
from math import inf
|
||||
|
||||
import numpy as np
|
||||
|
||||
def f12(
|
||||
x,
|
||||
y: str = os.pathsep, # Error PYI011 Only simple default values allowed for typed arguments
|
||||
@@ -61,3 +68,49 @@ def f22(
|
||||
x: complex = -42.5j # Error PYI011 Only simple default values allowed for typed arguments
|
||||
+ 4.3j,
|
||||
) -> None: ...
|
||||
def f23(
|
||||
x: bool = True, # OK
|
||||
) -> None: ...
|
||||
def f24(
|
||||
x: float = 3.14, # OK
|
||||
) -> None: ...
|
||||
def f25(
|
||||
x: float = -3.14, # OK
|
||||
) -> None: ...
|
||||
def f26(
|
||||
x: complex = -3.14j, # OK
|
||||
) -> None: ...
|
||||
def f27(
|
||||
x: complex = -3 - 3.14j, # OK
|
||||
) -> None: ...
|
||||
def f28(
|
||||
x: float = math.tau, # OK
|
||||
) -> None: ...
|
||||
def f29(
|
||||
x: float = math.inf, # OK
|
||||
) -> None: ...
|
||||
def f30(
|
||||
x: float = -math.inf, # OK
|
||||
) -> None: ...
|
||||
def f31(
|
||||
x: float = inf, # Error PYI011 Only simple default values allowed for typed arguments
|
||||
) -> None: ...
|
||||
def f32(
|
||||
x: float = np.inf, # Error PYI011 Only simple default values allowed for typed arguments
|
||||
) -> None: ...
|
||||
def f33(
|
||||
x: float = math.nan, # OK
|
||||
) -> None: ...
|
||||
def f34(
|
||||
x: float = -math.nan, # Error PYI011 Only simple default values allowed for typed arguments
|
||||
) -> None: ...
|
||||
def f35(
|
||||
x: complex = math.inf # Error PYI011 Only simple default values allowed for typed arguments
|
||||
+ 1j,
|
||||
) -> None: ...
|
||||
def f36(
|
||||
*, x: str = sys.version, # OK
|
||||
) -> None: ...
|
||||
def f37(
|
||||
*, x: str = "" + "", # Error PYI011 Only simple default values allowed for typed arguments
|
||||
) -> None: ...
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
import sys, math
|
||||
from os import path, uname
|
||||
from json import detect_encoding
|
||||
from json import dump
|
||||
from json import dumps as json_dumps
|
||||
from json import load
|
||||
from json import loads as json_loads
|
||||
from logging.handlers import StreamHandler, FileHandler
|
||||
|
||||
# comment 1
|
||||
@@ -10,9 +15,10 @@ from third_party import lib4
|
||||
|
||||
from foo import bar # comment 3
|
||||
from foo2 import bar2 # comment 4
|
||||
from foo3 import bar3, baz3 # comment 5
|
||||
|
||||
# comment 5
|
||||
# comment 6
|
||||
from bar import (
|
||||
a, # comment 6
|
||||
b, # comment 7
|
||||
)
|
||||
a, # comment 7
|
||||
b, # comment 8
|
||||
)
|
||||
|
||||
10
crates/ruff/resources/test/fixtures/isort/ruff_skip_file.py
vendored
Normal file
10
crates/ruff/resources/test/fixtures/isort/ruff_skip_file.py
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
# ruff: isort: skip_file
|
||||
import e
|
||||
import f
|
||||
|
||||
# isort: split
|
||||
|
||||
import a
|
||||
import b
|
||||
import c
|
||||
import d
|
||||
@@ -6,6 +6,14 @@ def f():
|
||||
# isort: on
|
||||
|
||||
|
||||
def f():
|
||||
# ruff: isort: off
|
||||
import sys
|
||||
import os
|
||||
import collections
|
||||
# ruff: isort: on
|
||||
|
||||
|
||||
def f():
|
||||
import sys
|
||||
import os # isort: skip
|
||||
|
||||
32
crates/ruff/resources/test/fixtures/jupyter/R.ipynb
vendored
Normal file
32
crates/ruff/resources/test/fixtures/jupyter/R.ipynb
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(paste(\"Hello\",\"WoRld\"))\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "R",
|
||||
"language": "R",
|
||||
"name": "ir"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": "r",
|
||||
"file_extension": ".r",
|
||||
"mimetype": "text/x-r-source",
|
||||
"name": "R",
|
||||
"pygments_lexer": "r",
|
||||
"version": "3.2.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
24
crates/ruff/resources/test/fixtures/jupyter/invalid_extension.ipynb
vendored
Normal file
24
crates/ruff/resources/test/fixtures/jupyter/invalid_extension.ipynb
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
# In[1]:
|
||||
|
||||
|
||||
def unused_variable():
|
||||
x = 1
|
||||
y = 2
|
||||
print(f"cell one: {y}")
|
||||
|
||||
unused_variable()
|
||||
|
||||
|
||||
# Let's do another mistake
|
||||
|
||||
# In[2]:
|
||||
|
||||
|
||||
def mutable_argument(z=set()):
|
||||
print(f"cell two: {z}")
|
||||
|
||||
mutable_argument()
|
||||
|
||||
1
crates/ruff/resources/test/fixtures/jupyter/not_json.ipynb
vendored
Normal file
1
crates/ruff/resources/test/fixtures/jupyter/not_json.ipynb
vendored
Normal file
@@ -0,0 +1 @@
|
||||
broken "§=($/=(")
|
||||
88
crates/ruff/resources/test/fixtures/jupyter/valid.ipynb
vendored
Normal file
88
crates/ruff/resources/test/fixtures/jupyter/valid.ipynb
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"cell one: 2\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def unused_variable():\n",
|
||||
" x = 1\n",
|
||||
" y = 2\n",
|
||||
" print(f\"cell one: {y}\")\n",
|
||||
"\n",
|
||||
"unused_variable()"
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false,
|
||||
"ExecuteTime": {
|
||||
"start_time": "2023-03-08T23:01:09.705831Z",
|
||||
"end_time": "2023-03-08T23:01:09.782916Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Let's do another mistake"
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"collapsed": true,
|
||||
"ExecuteTime": {
|
||||
"start_time": "2023-03-08T23:01:09.733809Z",
|
||||
"end_time": "2023-03-08T23:01:09.915760Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"cell two: set()\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def mutable_argument(z=set()):\n",
|
||||
" print(f\"cell two: {z}\")\n",
|
||||
"\n",
|
||||
"mutable_argument()\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 2
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython2",
|
||||
"version": "2.7.6"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
||||
1
crates/ruff/resources/test/fixtures/jupyter/wrong_schema.ipynb
vendored
Normal file
1
crates/ruff/resources/test/fixtures/jupyter/wrong_schema.ipynb
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -54,3 +54,7 @@ if type(a) != type(b) or type(a) == type(ccc):
|
||||
pass
|
||||
|
||||
assert type(res) == type(None)
|
||||
|
||||
types = StrEnum
|
||||
if x == types.X:
|
||||
pass
|
||||
|
||||
3
crates/ruff/resources/test/fixtures/pydocstyle/D209_D400.py
vendored
Normal file
3
crates/ruff/resources/test/fixtures/pydocstyle/D209_D400.py
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
def lorem():
|
||||
"""lorem ipsum dolor sit amet consectetur adipiscing elit
|
||||
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua"""
|
||||
@@ -113,3 +113,13 @@ def f(x, *args, **kwargs):
|
||||
**kwargs: keyword arguments
|
||||
"""
|
||||
return x
|
||||
|
||||
|
||||
class Test:
|
||||
def f(self, /, arg1: int) -> None:
|
||||
"""
|
||||
Some beauty description.
|
||||
|
||||
Args:
|
||||
arg1: some description of arg
|
||||
"""
|
||||
|
||||
@@ -58,6 +58,15 @@ def no_underline_and_no_description(): # noqa: D416
|
||||
"""
|
||||
|
||||
|
||||
@expect(_D213)
|
||||
@expect("D407: Missing dashed underline after section ('Returns')")
|
||||
@expect("D414: Section has no content ('Returns')")
|
||||
def no_underline_and_no_newline(): # noqa: D416
|
||||
"""Toggle the gizmo.
|
||||
|
||||
Returns"""
|
||||
|
||||
|
||||
@expect(_D213)
|
||||
@expect("D410: Missing blank line after section ('Returns')")
|
||||
@expect("D414: Section has no content ('Returns')")
|
||||
@@ -495,3 +504,12 @@ Testing this incorrectly indented docstring.
|
||||
x: Test argument.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def implicit_string_concatenation():
|
||||
"""Toggle the gizmo.
|
||||
|
||||
Returns
|
||||
A value of some sort.
|
||||
|
||||
""""Extra content"
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"{1:{0}}".format(1, 2) # No issues
|
||||
"{1:{0}}".format(1, 2, 3) # F523
|
||||
"{0}{2}".format(1, 2) # F523, # F524
|
||||
"{1.arg[1]!r:0{2['arg']}{1}}".format(1, 2, 3, 4) # F523
|
||||
|
||||
# With no indexes
|
||||
"{}".format(1, 2) # F523
|
||||
|
||||
24
crates/ruff/resources/test/fixtures/pylint/assert_on_string_literal.py
vendored
Normal file
24
crates/ruff/resources/test/fixtures/pylint/assert_on_string_literal.py
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
def test_division():
|
||||
a = 9 / 3
|
||||
assert "No ZeroDivisionError were raised" # [assert-on-string-literal]
|
||||
|
||||
|
||||
def test_division():
|
||||
a = 9 / 3
|
||||
assert a == 3
|
||||
|
||||
|
||||
try:
|
||||
assert "bad" # [assert-on-string-literal]
|
||||
except:
|
||||
assert "bad again" # [assert-on-string-literal]
|
||||
|
||||
a = 12
|
||||
assert f"hello {a}" # [assert-on-string-literal]
|
||||
assert f"{a}" # [assert-on-string-literal]
|
||||
assert f"" # [assert-on-string-literal]
|
||||
assert "" # [assert-on-string-literal]
|
||||
assert b"hello" # [assert-on-string-literal]
|
||||
assert "", b"hi" # [assert-on-string-literal]
|
||||
assert "WhyNotHere?", "HereIsOk" # [assert-on-string-literal]
|
||||
assert 12, "ok here"
|
||||
14
crates/ruff/resources/test/fixtures/pylint/binary_op_exception.py
vendored
Normal file
14
crates/ruff/resources/test/fixtures/pylint/binary_op_exception.py
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
try:
|
||||
1 / 0
|
||||
except ZeroDivisionError or ValueError as e: # [binary-op-exception]
|
||||
pass
|
||||
|
||||
try:
|
||||
raise ValueError
|
||||
except ZeroDivisionError and ValueError as e: # [binary-op-exception]
|
||||
print(e)
|
||||
|
||||
try:
|
||||
pass
|
||||
except (ValueError, Exception, IOError):
|
||||
pass
|
||||
@@ -17,3 +17,7 @@ def errors():
|
||||
def ok():
|
||||
if x and not y:
|
||||
print("x is not an empty string, but y is an empty string")
|
||||
|
||||
|
||||
data.loc[data["a"] != ""]
|
||||
data.loc[data["a"] != "", :]
|
||||
|
||||
95
crates/ruff/resources/test/fixtures/pylint/continue_in_finally.py
vendored
Normal file
95
crates/ruff/resources/test/fixtures/pylint/continue_in_finally.py
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
while True:
|
||||
try:
|
||||
pass
|
||||
finally:
|
||||
continue # [continue-in-finally]
|
||||
|
||||
while True:
|
||||
try:
|
||||
pass
|
||||
except Exception:
|
||||
continue
|
||||
finally:
|
||||
try:
|
||||
pass
|
||||
finally:
|
||||
continue # [continue-in-finally]
|
||||
pass
|
||||
|
||||
while True:
|
||||
try:
|
||||
pass
|
||||
finally:
|
||||
test = "aa"
|
||||
match test:
|
||||
case "aa":
|
||||
continue # [continue-in-finally]
|
||||
|
||||
while True:
|
||||
try:
|
||||
pass
|
||||
finally:
|
||||
with "aa" as f:
|
||||
continue # [continue-in-finally]
|
||||
|
||||
while True:
|
||||
try:
|
||||
pass
|
||||
finally:
|
||||
if True:
|
||||
continue # [continue-in-finally]
|
||||
continue # [continue-in-finally]
|
||||
|
||||
def test():
|
||||
while True:
|
||||
continue
|
||||
try:
|
||||
pass
|
||||
finally:
|
||||
continue # [continue-in-finally]
|
||||
|
||||
|
||||
while True:
|
||||
try:
|
||||
pass
|
||||
finally:
|
||||
continue # [continue-in-finally]
|
||||
|
||||
def test():
|
||||
while True:
|
||||
continue
|
||||
|
||||
|
||||
while True:
|
||||
try:
|
||||
pass
|
||||
finally:
|
||||
for i in range(12):
|
||||
continue
|
||||
continue # [continue-in-finally]
|
||||
|
||||
while True:
|
||||
pass
|
||||
else:
|
||||
continue # [continue-in-finally]
|
||||
|
||||
def test():
|
||||
continue
|
||||
while True:
|
||||
continue
|
||||
|
||||
|
||||
while True:
|
||||
try:
|
||||
pass
|
||||
finally:
|
||||
if True:
|
||||
pass
|
||||
elif False:
|
||||
continue # [continue-in-finally]
|
||||
else:
|
||||
continue # [continue-in-finally]
|
||||
for i in range(10):
|
||||
pass
|
||||
else:
|
||||
continue # [continue-in-finally]
|
||||
BIN
crates/ruff/resources/test/fixtures/pylint/invalid_characters.py
vendored
Normal file
BIN
crates/ruff/resources/test/fixtures/pylint/invalid_characters.py
vendored
Normal file
Binary file not shown.
@@ -5,4 +5,8 @@ goodVar = os.getenv("TESTING", None)
|
||||
dictVarBad = os.getenv("AAA", {"a", 7}) # [invalid-envvar-default]
|
||||
print(os.getenv("TEST", False)) # [invalid-envvar-default]
|
||||
os.getenv("AA", "GOOD")
|
||||
os.getenv("AA", f"GOOD")
|
||||
os.getenv("AA", "GOOD" + "BAD")
|
||||
os.getenv("AA", "GOOD" + 1)
|
||||
os.getenv("AA", "GOOD %s" % "BAD")
|
||||
os.getenv("B", Z)
|
||||
|
||||
@@ -7,6 +7,9 @@ os.getenv(key="testingAgain")
|
||||
os.getenv(key=11) # [invalid-envvar-value]
|
||||
os.getenv(["hello"]) # [invalid-envvar-value]
|
||||
os.getenv(key="foo", default="bar")
|
||||
os.getenv(key=f"foo", default="bar")
|
||||
os.getenv(key="foo" + "bar", default=1)
|
||||
os.getenv(key=1 + "bar", default=1) # [invalid-envvar-value]
|
||||
|
||||
AA = "aa"
|
||||
os.getenv(AA)
|
||||
|
||||
50
crates/ruff/resources/test/fixtures/pylint/useless_return.py
vendored
Normal file
50
crates/ruff/resources/test/fixtures/pylint/useless_return.py
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
import sys
|
||||
|
||||
|
||||
def print_python_version():
|
||||
print(sys.version)
|
||||
return None # [useless-return]
|
||||
|
||||
|
||||
def print_python_version():
|
||||
print(sys.version)
|
||||
return None # [useless-return]
|
||||
|
||||
|
||||
def print_python_version():
|
||||
print(sys.version)
|
||||
return None # [useless-return]
|
||||
|
||||
|
||||
class SomeClass:
|
||||
def print_python_version(self):
|
||||
print(sys.version)
|
||||
return None # [useless-return]
|
||||
|
||||
|
||||
def print_python_version():
|
||||
if 2 * 2 == 4:
|
||||
return
|
||||
print(sys.version)
|
||||
|
||||
|
||||
def print_python_version():
|
||||
if 2 * 2 == 4:
|
||||
return None
|
||||
return
|
||||
|
||||
|
||||
def print_python_version():
|
||||
if 2 * 2 == 4:
|
||||
return None
|
||||
|
||||
|
||||
def print_python_version():
|
||||
"""This function returns None."""
|
||||
return None
|
||||
|
||||
|
||||
def print_python_version():
|
||||
"""This function returns None."""
|
||||
print(sys.version)
|
||||
return None # [useless-return]
|
||||
@@ -46,3 +46,8 @@ def f(x: Union[("str", "int"), float]) -> None:
|
||||
def f() -> None:
|
||||
x: Optional[str]
|
||||
x = Optional[str]
|
||||
|
||||
x = Union[str, int]
|
||||
x = Union["str", "int"]
|
||||
x: Union[str, int]
|
||||
x: Union["str", "int"]
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
from io import open
|
||||
|
||||
with open("f.txt") as f:
|
||||
print(f.read())
|
||||
|
||||
import io
|
||||
|
||||
with io.open("f.txt", mode="r", buffering=-1, **kwargs) as f:
|
||||
print(f.read())
|
||||
|
||||
from io import open
|
||||
|
||||
with open("f.txt") as f:
|
||||
print(f.read())
|
||||
|
||||
@@ -1,24 +1,29 @@
|
||||
# These should be changed
|
||||
# Error (`from unittest import mock`)
|
||||
if True:
|
||||
import mock
|
||||
|
||||
# Error (`from unittest import mock`)
|
||||
if True:
|
||||
import mock, sys
|
||||
|
||||
# This goes to from unitest import mock
|
||||
# Error (`from unittest.mock import *`)
|
||||
if True:
|
||||
from mock import *
|
||||
|
||||
# Error (`from unittest import mock`)
|
||||
import mock.mock
|
||||
|
||||
# Mock should go on a new line as `from unittest import mock`
|
||||
# Error (`from unittest import mock`)
|
||||
import contextlib, mock, sys
|
||||
|
||||
# Mock should go on a new line as `from unittest import mock`
|
||||
# Error (`from unittest import mock`)
|
||||
import mock, sys
|
||||
x = "This code should be preserved one line below the mock"
|
||||
|
||||
# Mock should go on a new line as `from unittest import mock`
|
||||
# Error (`from unittest import mock`)
|
||||
from mock import mock
|
||||
|
||||
# Should keep trailing comma
|
||||
# Error (keep trailing comma)
|
||||
from mock import (
|
||||
mock,
|
||||
a,
|
||||
@@ -32,7 +37,7 @@ from mock import (
|
||||
mock,
|
||||
)
|
||||
|
||||
# Should not get a trailing comma
|
||||
# Error (avoid trailing comma)
|
||||
from mock import (
|
||||
mock,
|
||||
a,
|
||||
@@ -57,16 +62,16 @@ if True:
|
||||
c
|
||||
)
|
||||
|
||||
# These should not change:
|
||||
# OK
|
||||
import os, io
|
||||
|
||||
# Mock should go on a new line as `from unittest import mock`
|
||||
# Error (`from unittest import mock`)
|
||||
import mock, mock
|
||||
|
||||
# Mock should go on a new line as `from unittest import mock as foo`
|
||||
# Error (`from unittest import mock as foo`)
|
||||
import mock as foo
|
||||
|
||||
# Mock should go on a new line as `from unittest import mock as foo`
|
||||
# Error (`from unittest import mock as foo`)
|
||||
from mock import mock as foo
|
||||
|
||||
if True:
|
||||
@@ -81,8 +86,8 @@ if True:
|
||||
from mock import mock as foo, mock as bar, mock
|
||||
|
||||
|
||||
# This should be unchanged.
|
||||
# OK.
|
||||
x = mock.Mock()
|
||||
|
||||
# This should change to `mock.Mock`().
|
||||
# Error (`mock.Mock()`).
|
||||
x = mock.mock.Mock()
|
||||
|
||||
@@ -73,3 +73,13 @@ print("%s \N{snowman}" % (a,))
|
||||
print("%(foo)s \N{snowman}" % {"foo": 1})
|
||||
|
||||
print(("foo %s " "bar %s") % (x, y))
|
||||
|
||||
# Single-value expressions
|
||||
print('Hello %s' % "World")
|
||||
print('Hello %s' % f"World")
|
||||
print('Hello %s (%s)' % bar)
|
||||
print('Hello %s (%s)' % bar.baz)
|
||||
print('Hello %s (%s)' % bar['bop'])
|
||||
print('Hello %(arg)s' % bar)
|
||||
print('Hello %(arg)s' % bar.baz)
|
||||
print('Hello %(arg)s' % bar['bop'])
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
# OK
|
||||
"%s" % unknown_type
|
||||
|
||||
b"%s" % (b"bytestring",)
|
||||
|
||||
"%*s" % (5, "hi")
|
||||
@@ -57,3 +55,9 @@ pytest.param('"%8s" % (None,)', id="unsafe width-string conversion"),
|
||||
"""
|
||||
% (x,)
|
||||
)
|
||||
|
||||
'Hello %s' % bar
|
||||
|
||||
'Hello %s' % bar.baz
|
||||
|
||||
'Hello %s' % bar['bop']
|
||||
|
||||
@@ -86,3 +86,14 @@ async def c():
|
||||
|
||||
async def c():
|
||||
return "{}".format(1 + await 3)
|
||||
|
||||
|
||||
def d(osname, version, release):
|
||||
return"{}-{}.{}".format(osname, version, release)
|
||||
|
||||
|
||||
def e():
|
||||
yield"{}".format(1)
|
||||
|
||||
|
||||
assert"{}".format(1)
|
||||
|
||||
@@ -41,7 +41,7 @@ if True:
|
||||
Good,
|
||||
)
|
||||
|
||||
from typing import Callable, Match, Pattern, List, OrderedDict, AbstractSet
|
||||
from typing import Callable, Match, Pattern, List, OrderedDict, AbstractSet, ContextManager
|
||||
|
||||
if True: from collections import (
|
||||
Mapping, Counter)
|
||||
|
||||
@@ -5,3 +5,5 @@ isinstance(1, int) # OK
|
||||
issubclass("yes", int) # OK
|
||||
isinstance(1, int | float) # OK
|
||||
issubclass("yes", int | str) # OK
|
||||
isinstance(1, ()) # OK
|
||||
isinstance(1, (int, *(str, bytes))) # OK
|
||||
|
||||
19
crates/ruff/resources/test/fixtures/ruff/RUF007.py
vendored
Normal file
19
crates/ruff/resources/test/fixtures/ruff/RUF007.py
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
input = [1, 2, 3]
|
||||
otherInput = [2, 3, 4]
|
||||
|
||||
# OK
|
||||
zip(input, otherInput) # different inputs
|
||||
zip(input, otherInput[1:]) # different inputs
|
||||
zip(input, input[2:]) # not successive
|
||||
zip(input[:-1], input[2:]) # not successive
|
||||
list(zip(input, otherInput)) # nested call
|
||||
zip(input, input[1::2]) # not successive
|
||||
|
||||
# Errors
|
||||
zip(input, input[1:])
|
||||
zip(input, input[1::1])
|
||||
zip(input[:-1], input[1:])
|
||||
zip(input[1:], input[2:])
|
||||
zip(input[1:-1], input[2:])
|
||||
list(zip(input, input[1:]))
|
||||
list(zip(input[:-1], input[1:]))
|
||||
@@ -2,12 +2,24 @@
|
||||
# noqa # comment
|
||||
print() # noqa
|
||||
print() # noqa # comment
|
||||
print() # noqa # comment
|
||||
print() # noqa comment
|
||||
print() # noqa comment
|
||||
print(a) # noqa
|
||||
print(a) # noqa # comment
|
||||
print(a) # noqa # comment
|
||||
print(a) # noqa comment
|
||||
print(a) # noqa comment
|
||||
|
||||
# noqa: E501, F821
|
||||
# noqa: E501, F821 # comment
|
||||
print() # noqa: E501, F821
|
||||
print() # noqa: E501, F821 # comment
|
||||
print() # noqa: E501, F821 # comment
|
||||
print() # noqa: E501, F821 comment
|
||||
print() # noqa: E501, F821 comment
|
||||
print(a) # noqa: E501, F821
|
||||
print(a) # noqa: E501, F821 # comment
|
||||
print(a) # noqa: E501, F821 # comment
|
||||
print(a) # noqa: E501, F821 comment
|
||||
print(a) # noqa: E501, F821 comment
|
||||
|
||||
@@ -45,3 +45,10 @@ def still_good():
|
||||
return process()
|
||||
except MyException:
|
||||
logger.exception("process failed")
|
||||
|
||||
def good_noexcept():
|
||||
try:
|
||||
pass
|
||||
return process()
|
||||
finally:
|
||||
logger.exception("process failed")
|
||||
|
||||
@@ -9,30 +9,30 @@ Running from the repo root should pick up and enforce the appropriate settings f
|
||||
|
||||
```console
|
||||
∴ cargo run -p ruff_cli -- check crates/ruff/resources/test/project/
|
||||
crates/ruff/resources/test/project/examples/.dotfiles/script.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
crates/ruff/resources/test/project/examples/.dotfiles/script.py:1:8: F401 `numpy` imported but unused
|
||||
crates/ruff/resources/test/project/examples/.dotfiles/script.py:2:17: F401 `app.app_file` imported but unused
|
||||
crates/ruff/resources/test/project/examples/docs/docs/file.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
crates/ruff/resources/test/project/examples/docs/docs/file.py:8:5: F841 Local variable `x` is assigned to but never used
|
||||
crates/ruff/resources/test/project/project/file.py:1:8: F401 `os` imported but unused
|
||||
crates/ruff/resources/test/project/project/import_file.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
crates/ruff/resources/test/project/examples/.dotfiles/script.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||
crates/ruff/resources/test/project/examples/.dotfiles/script.py:1:8: F401 [*] `numpy` imported but unused
|
||||
crates/ruff/resources/test/project/examples/.dotfiles/script.py:2:17: F401 [*] `app.app_file` imported but unused
|
||||
crates/ruff/resources/test/project/examples/docs/docs/file.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||
crates/ruff/resources/test/project/examples/docs/docs/file.py:8:5: F841 [*] Local variable `x` is assigned to but never used
|
||||
crates/ruff/resources/test/project/project/file.py:1:8: F401 [*] `os` imported but unused
|
||||
crates/ruff/resources/test/project/project/import_file.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||
Found 7 errors.
|
||||
7 potentially fixable with the --fix option.
|
||||
[*] 7 potentially fixable with the --fix option.
|
||||
```
|
||||
|
||||
Running from the project directory itself should exhibit the same behavior:
|
||||
|
||||
```console
|
||||
∴ (cd crates/ruff/resources/test/project/ && cargo run -p ruff_cli -- check .)
|
||||
examples/.dotfiles/script.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
examples/.dotfiles/script.py:1:8: F401 `numpy` imported but unused
|
||||
examples/.dotfiles/script.py:2:17: F401 `app.app_file` imported but unused
|
||||
examples/docs/docs/file.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
examples/docs/docs/file.py:8:5: F841 Local variable `x` is assigned to but never used
|
||||
project/file.py:1:8: F401 `os` imported but unused
|
||||
project/import_file.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
examples/.dotfiles/script.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||
examples/.dotfiles/script.py:1:8: F401 [*] `numpy` imported but unused
|
||||
examples/.dotfiles/script.py:2:17: F401 [*] `app.app_file` imported but unused
|
||||
examples/docs/docs/file.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||
examples/docs/docs/file.py:8:5: F841 [*] Local variable `x` is assigned to but never used
|
||||
project/file.py:1:8: F401 [*] `os` imported but unused
|
||||
project/import_file.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||
Found 7 errors.
|
||||
7 potentially fixable with the --fix option.
|
||||
[*] 7 potentially fixable with the --fix option.
|
||||
```
|
||||
|
||||
Running from the sub-package directory should exhibit the same behavior, but omit the top-level
|
||||
@@ -40,10 +40,10 @@ files:
|
||||
|
||||
```console
|
||||
∴ (cd crates/ruff/resources/test/project/examples/docs && cargo run -p ruff_cli -- check .)
|
||||
docs/file.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
docs/file.py:8:5: F841 Local variable `x` is assigned to but never used
|
||||
docs/file.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||
docs/file.py:8:5: F841 [*] Local variable `x` is assigned to but never used
|
||||
Found 2 errors.
|
||||
2 potentially fixable with the --fix option.
|
||||
[*] 2 potentially fixable with the --fix option.
|
||||
```
|
||||
|
||||
`--config` should force Ruff to use the specified `pyproject.toml` for all files, and resolve
|
||||
@@ -51,17 +51,17 @@ file paths from the current working directory:
|
||||
|
||||
```console
|
||||
∴ (cargo run -p ruff_cli -- check --config=crates/ruff/resources/test/project/pyproject.toml crates/ruff/resources/test/project/)
|
||||
crates/ruff/resources/test/project/examples/.dotfiles/script.py:1:8: F401 `numpy` imported but unused
|
||||
crates/ruff/resources/test/project/examples/.dotfiles/script.py:2:17: F401 `app.app_file` imported but unused
|
||||
crates/ruff/resources/test/project/examples/docs/docs/concepts/file.py:1:8: F401 `os` imported but unused
|
||||
crates/ruff/resources/test/project/examples/docs/docs/file.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
crates/ruff/resources/test/project/examples/docs/docs/file.py:1:8: F401 `os` imported but unused
|
||||
crates/ruff/resources/test/project/examples/docs/docs/file.py:3:8: F401 `numpy` imported but unused
|
||||
crates/ruff/resources/test/project/examples/docs/docs/file.py:4:27: F401 `docs.concepts.file` imported but unused
|
||||
crates/ruff/resources/test/project/examples/excluded/script.py:1:8: F401 `os` imported but unused
|
||||
crates/ruff/resources/test/project/project/file.py:1:8: F401 `os` imported but unused
|
||||
crates/ruff/resources/test/project/examples/.dotfiles/script.py:1:8: F401 [*] `numpy` imported but unused
|
||||
crates/ruff/resources/test/project/examples/.dotfiles/script.py:2:17: F401 [*] `app.app_file` imported but unused
|
||||
crates/ruff/resources/test/project/examples/docs/docs/concepts/file.py:1:8: F401 [*] `os` imported but unused
|
||||
crates/ruff/resources/test/project/examples/docs/docs/file.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||
crates/ruff/resources/test/project/examples/docs/docs/file.py:1:8: F401 [*] `os` imported but unused
|
||||
crates/ruff/resources/test/project/examples/docs/docs/file.py:3:8: F401 [*] `numpy` imported but unused
|
||||
crates/ruff/resources/test/project/examples/docs/docs/file.py:4:27: F401 [*] `docs.concepts.file` imported but unused
|
||||
crates/ruff/resources/test/project/examples/excluded/script.py:1:8: F401 [*] `os` imported but unused
|
||||
crates/ruff/resources/test/project/project/file.py:1:8: F401 [*] `os` imported but unused
|
||||
Found 9 errors.
|
||||
9 potentially fixable with the --fix option.
|
||||
[*] 9 potentially fixable with the --fix option.
|
||||
```
|
||||
|
||||
Running from a parent directory should "ignore" the `exclude` (hence, `concepts/file.py` gets
|
||||
@@ -69,21 +69,21 @@ included in the output):
|
||||
|
||||
```console
|
||||
∴ (cd crates/ruff/resources/test/project/examples && cargo run -p ruff_cli -- check --config=docs/ruff.toml .)
|
||||
docs/docs/concepts/file.py:5:5: F841 Local variable `x` is assigned to but never used
|
||||
docs/docs/file.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
docs/docs/file.py:8:5: F841 Local variable `x` is assigned to but never used
|
||||
excluded/script.py:5:5: F841 Local variable `x` is assigned to but never used
|
||||
docs/docs/concepts/file.py:5:5: F841 [*] Local variable `x` is assigned to but never used
|
||||
docs/docs/file.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||
docs/docs/file.py:8:5: F841 [*] Local variable `x` is assigned to but never used
|
||||
excluded/script.py:5:5: F841 [*] Local variable `x` is assigned to but never used
|
||||
Found 4 errors.
|
||||
4 potentially fixable with the --fix option.
|
||||
[*] 4 potentially fixable with the --fix option.
|
||||
```
|
||||
|
||||
Passing an excluded directory directly should report errors in the contained files:
|
||||
|
||||
```console
|
||||
∴ cargo run -p ruff_cli -- check crates/ruff/resources/test/project/examples/excluded/
|
||||
crates/ruff/resources/test/project/examples/excluded/script.py:1:8: F401 `os` imported but unused
|
||||
crates/ruff/resources/test/project/examples/excluded/script.py:1:8: F401 [*] `os` imported but unused
|
||||
Found 1 error.
|
||||
1 potentially fixable with the --fix option.
|
||||
[*] 1 potentially fixable with the --fix option.
|
||||
```
|
||||
|
||||
Unless we `--force-exclude`:
|
||||
|
||||
@@ -9,7 +9,7 @@ use ruff_python_ast::source_code::Locator;
|
||||
use ruff_python_ast::types::Range;
|
||||
|
||||
use crate::linter::FixTable;
|
||||
use crate::registry::AsRule;
|
||||
use crate::registry::{AsRule, Rule};
|
||||
|
||||
pub mod helpers;
|
||||
|
||||
@@ -28,7 +28,7 @@ fn apply_fixes<'a>(
|
||||
locator: &'a Locator<'a>,
|
||||
) -> (String, FixTable) {
|
||||
let mut output = String::with_capacity(locator.len());
|
||||
let mut last_pos: Location = Location::new(1, 0);
|
||||
let mut last_pos: Option<Location> = None;
|
||||
let mut applied: BTreeSet<&Fix> = BTreeSet::default();
|
||||
let mut fixed = FxHashMap::default();
|
||||
|
||||
@@ -39,7 +39,7 @@ fn apply_fixes<'a>(
|
||||
.as_ref()
|
||||
.map(|fix| (diagnostic.kind.rule(), fix))
|
||||
})
|
||||
.sorted_by_key(|(.., fix)| fix.location)
|
||||
.sorted_by(|(rule1, fix1), (rule2, fix2)| cmp_fix(*rule1, *rule2, fix1, fix2))
|
||||
{
|
||||
// If we already applied an identical fix as part of another correction, skip
|
||||
// any re-application.
|
||||
@@ -50,25 +50,25 @@ fn apply_fixes<'a>(
|
||||
|
||||
// Best-effort approach: if this fix overlaps with a fix we've already applied,
|
||||
// skip it.
|
||||
if last_pos > fix.location {
|
||||
if last_pos.map_or(false, |last_pos| last_pos >= fix.location) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add all contents from `last_pos` to `fix.location`.
|
||||
let slice = locator.slice(Range::new(last_pos, fix.location));
|
||||
let slice = locator.slice(Range::new(last_pos.unwrap_or_default(), fix.location));
|
||||
output.push_str(slice);
|
||||
|
||||
// Add the patch itself.
|
||||
output.push_str(&fix.content);
|
||||
|
||||
// Track that the fix was applied.
|
||||
last_pos = fix.end_location;
|
||||
last_pos = Some(fix.end_location);
|
||||
applied.insert(fix);
|
||||
*fixed.entry(rule).or_default() += 1;
|
||||
}
|
||||
|
||||
// Add the remaining content.
|
||||
let slice = locator.skip(last_pos);
|
||||
let slice = locator.skip(last_pos.unwrap_or_default());
|
||||
output.push_str(slice);
|
||||
|
||||
(output, fixed)
|
||||
@@ -92,6 +92,18 @@ pub(crate) fn apply_fix(fix: &Fix, locator: &Locator) -> String {
|
||||
output
|
||||
}
|
||||
|
||||
/// Compare two fixes.
|
||||
fn cmp_fix(rule1: Rule, rule2: Rule, fix1: &Fix, fix2: &Fix) -> std::cmp::Ordering {
|
||||
fix1.location
|
||||
.cmp(&fix2.location)
|
||||
.then_with(|| match (&rule1, &rule2) {
|
||||
// Apply `EndsInPeriod` fixes before `NewLineAfterLastParagraph` fixes.
|
||||
(Rule::EndsInPeriod, Rule::NewLineAfterLastParagraph) => std::cmp::Ordering::Less,
|
||||
(Rule::NewLineAfterLastParagraph, Rule::EndsInPeriod) => std::cmp::Ordering::Greater,
|
||||
_ => std::cmp::Ordering::Equal,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use rustpython_parser::ast::Location;
|
||||
@@ -101,14 +113,14 @@ mod tests {
|
||||
use ruff_python_ast::source_code::Locator;
|
||||
|
||||
use crate::autofix::{apply_fix, apply_fixes};
|
||||
use crate::rules::pycodestyle::rules::NoNewLineAtEndOfFile;
|
||||
use crate::rules::pycodestyle::rules::MissingNewlineAtEndOfFile;
|
||||
|
||||
fn create_diagnostics(fixes: impl IntoIterator<Item = Fix>) -> Vec<Diagnostic> {
|
||||
fixes
|
||||
.into_iter()
|
||||
.map(|fix| Diagnostic {
|
||||
// The choice of rule here is arbitrary.
|
||||
kind: NoNewLineAtEndOfFile.into(),
|
||||
kind: MissingNewlineAtEndOfFile.into(),
|
||||
location: fix.location,
|
||||
end_location: fix.end_location,
|
||||
fix: Some(fix),
|
||||
@@ -182,7 +194,7 @@ class A:
|
||||
fn apply_two_removals() {
|
||||
let locator = Locator::new(
|
||||
r#"
|
||||
class A(object, object):
|
||||
class A(object, object, object):
|
||||
...
|
||||
"#
|
||||
.trim(),
|
||||
@@ -190,13 +202,13 @@ class A(object, object):
|
||||
let diagnostics = create_diagnostics([
|
||||
Fix {
|
||||
content: String::new(),
|
||||
location: Location::new(1, 7),
|
||||
location: Location::new(1, 8),
|
||||
end_location: Location::new(1, 16),
|
||||
},
|
||||
Fix {
|
||||
content: String::new(),
|
||||
location: Location::new(1, 16),
|
||||
end_location: Location::new(1, 23),
|
||||
location: Location::new(1, 22),
|
||||
end_location: Location::new(1, 30),
|
||||
},
|
||||
]);
|
||||
let (contents, fixed) = apply_fixes(diagnostics.iter(), &locator);
|
||||
@@ -204,7 +216,7 @@ class A(object, object):
|
||||
assert_eq!(
|
||||
contents,
|
||||
r#"
|
||||
class A:
|
||||
class A(object):
|
||||
...
|
||||
"#
|
||||
.trim()
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use ruff_python_ast::scope::ScopeStack;
|
||||
use rustpython_parser::ast::{Expr, Stmt};
|
||||
|
||||
use ruff_python_ast::types::Range;
|
||||
@@ -7,7 +8,7 @@ use ruff_python_ast::visibility::{Visibility, VisibleScope};
|
||||
use crate::checkers::ast::AnnotationContext;
|
||||
use crate::docstrings::definition::Definition;
|
||||
|
||||
type Context<'a> = (Vec<usize>, Vec<RefEquality<'a, Stmt>>);
|
||||
type Context<'a> = (ScopeStack, Vec<RefEquality<'a, Stmt>>);
|
||||
|
||||
/// A collection of AST nodes that are deferred for later analysis.
|
||||
/// Used to, e.g., store functions, whose bodies shouldn't be analyzed until all
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -15,7 +15,7 @@ pub fn check_file_path(
|
||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||
|
||||
// flake8-no-pep420
|
||||
if settings.rules.enabled(&Rule::ImplicitNamespacePackage) {
|
||||
if settings.rules.enabled(Rule::ImplicitNamespacePackage) {
|
||||
if let Some(diagnostic) =
|
||||
implicit_namespace_package(path, package, &settings.project_root, &settings.src)
|
||||
{
|
||||
@@ -24,7 +24,7 @@ pub fn check_file_path(
|
||||
}
|
||||
|
||||
// pep8-naming
|
||||
if settings.rules.enabled(&Rule::InvalidModuleName) {
|
||||
if settings.rules.enabled(Rule::InvalidModuleName) {
|
||||
if let Some(diagnostic) = invalid_module_name(path, package) {
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ pub fn check_imports(
|
||||
|
||||
// Enforce import rules.
|
||||
let mut diagnostics = vec![];
|
||||
if settings.rules.enabled(&Rule::UnsortedImports) {
|
||||
if settings.rules.enabled(Rule::UnsortedImports) {
|
||||
for block in &blocks {
|
||||
if !block.imports.is_empty() {
|
||||
if let Some(diagnostic) = isort::rules::organize_imports(
|
||||
@@ -49,7 +49,7 @@ pub fn check_imports(
|
||||
}
|
||||
}
|
||||
}
|
||||
if settings.rules.enabled(&Rule::MissingRequiredImport) {
|
||||
if settings.rules.enabled(Rule::MissingRequiredImport) {
|
||||
diagnostics.extend(isort::rules::add_required_imports(
|
||||
&blocks, python_ast, locator, stylist, settings, autofix,
|
||||
));
|
||||
|
||||
@@ -165,10 +165,10 @@ pub fn check_logical_lines(
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "logical_lines")]
|
||||
let should_fix = autofix.into() && settings.rules.should_fix(&Rule::MissingWhitespace);
|
||||
#[cfg(debug_assertions)]
|
||||
let should_fix = autofix.into() && settings.rules.should_fix(Rule::MissingWhitespace);
|
||||
|
||||
#[cfg(not(feature = "logical_lines"))]
|
||||
#[cfg(not(debug_assertions))]
|
||||
let should_fix = false;
|
||||
|
||||
for diagnostic in missing_whitespace(&line.text, start_loc.row(), should_fix) {
|
||||
@@ -179,11 +179,11 @@ pub fn check_logical_lines(
|
||||
}
|
||||
|
||||
if line.flags.contains(TokenFlags::BRACKET) {
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
let should_fix =
|
||||
autofix.into() && settings.rules.should_fix(&Rule::WhitespaceBeforeParameters);
|
||||
autofix.into() && settings.rules.should_fix(Rule::WhitespaceBeforeParameters);
|
||||
|
||||
#[cfg(not(feature = "logical_lines"))]
|
||||
#[cfg(not(debug_assertions))]
|
||||
let should_fix = false;
|
||||
|
||||
for diagnostic in whitespace_before_parameters(&line.tokens, should_fix) {
|
||||
|
||||
@@ -24,7 +24,7 @@ pub fn check_noqa(
|
||||
settings: &Settings,
|
||||
autofix: flags::Autofix,
|
||||
) -> Vec<usize> {
|
||||
let enforce_noqa = settings.rules.enabled(&Rule::UnusedNOQA);
|
||||
let enforce_noqa = settings.rules.enabled(Rule::UnusedNOQA);
|
||||
|
||||
// Whether the file is exempted from all checks.
|
||||
let mut file_exempted = false;
|
||||
@@ -143,30 +143,26 @@ pub fn check_noqa(
|
||||
match directive {
|
||||
Directive::All(leading_spaces, start_byte, end_byte, trailing_spaces) => {
|
||||
if matches.is_empty() {
|
||||
let start = lines[row][..start_byte].chars().count();
|
||||
let end = start + lines[row][start_byte..end_byte].chars().count();
|
||||
let start_char = lines[row][..start_byte].chars().count();
|
||||
let end_char =
|
||||
start_char + lines[row][start_byte..end_byte].chars().count();
|
||||
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
UnusedNOQA { codes: None },
|
||||
Range::new(Location::new(row + 1, start), Location::new(row + 1, end)),
|
||||
Range::new(
|
||||
Location::new(row + 1, start_char),
|
||||
Location::new(row + 1, end_char),
|
||||
),
|
||||
);
|
||||
if autofix.into() && settings.rules.should_fix(diagnostic.kind.rule()) {
|
||||
if start - leading_spaces == 0 && end == lines[row].chars().count() {
|
||||
diagnostic.amend(Fix::deletion(
|
||||
Location::new(row + 1, 0),
|
||||
Location::new(row + 2, 0),
|
||||
));
|
||||
} else if end == lines[row].chars().count() {
|
||||
diagnostic.amend(Fix::deletion(
|
||||
Location::new(row + 1, start - leading_spaces),
|
||||
Location::new(row + 1, end + trailing_spaces),
|
||||
));
|
||||
} else {
|
||||
diagnostic.amend(Fix::deletion(
|
||||
Location::new(row + 1, start),
|
||||
Location::new(row + 1, end + trailing_spaces),
|
||||
));
|
||||
}
|
||||
diagnostic.amend(delete_noqa(
|
||||
row,
|
||||
lines[row],
|
||||
leading_spaces,
|
||||
start_byte,
|
||||
end_byte,
|
||||
trailing_spaces,
|
||||
));
|
||||
}
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
@@ -188,7 +184,7 @@ pub fn check_noqa(
|
||||
valid_codes.push(code);
|
||||
} else {
|
||||
if let Ok(rule) = Rule::from_code(code) {
|
||||
if settings.rules.enabled(&rule) {
|
||||
if settings.rules.enabled(rule) {
|
||||
unmatched_codes.push(code);
|
||||
} else {
|
||||
disabled_codes.push(code);
|
||||
@@ -207,8 +203,9 @@ pub fn check_noqa(
|
||||
&& unknown_codes.is_empty()
|
||||
&& unmatched_codes.is_empty())
|
||||
{
|
||||
let start = lines[row][..start_byte].chars().count();
|
||||
let end = start + lines[row][start_byte..end_byte].chars().count();
|
||||
let start_char = lines[row][..start_byte].chars().count();
|
||||
let end_char =
|
||||
start_char + lines[row][start_byte..end_byte].chars().count();
|
||||
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
UnusedNOQA {
|
||||
@@ -227,32 +224,26 @@ pub fn check_noqa(
|
||||
.collect(),
|
||||
}),
|
||||
},
|
||||
Range::new(Location::new(row + 1, start), Location::new(row + 1, end)),
|
||||
Range::new(
|
||||
Location::new(row + 1, start_char),
|
||||
Location::new(row + 1, end_char),
|
||||
),
|
||||
);
|
||||
if autofix.into() && settings.rules.should_fix(diagnostic.kind.rule()) {
|
||||
if valid_codes.is_empty() {
|
||||
if start - leading_spaces == 0 && end == lines[row].chars().count()
|
||||
{
|
||||
diagnostic.amend(Fix::deletion(
|
||||
Location::new(row + 1, 0),
|
||||
Location::new(row + 2, 0),
|
||||
));
|
||||
} else if end == lines[row].chars().count() {
|
||||
diagnostic.amend(Fix::deletion(
|
||||
Location::new(row + 1, start - leading_spaces),
|
||||
Location::new(row + 1, end + trailing_spaces),
|
||||
));
|
||||
} else {
|
||||
diagnostic.amend(Fix::deletion(
|
||||
Location::new(row + 1, start),
|
||||
Location::new(row + 1, end + trailing_spaces),
|
||||
));
|
||||
}
|
||||
diagnostic.amend(delete_noqa(
|
||||
row,
|
||||
lines[row],
|
||||
leading_spaces,
|
||||
start_byte,
|
||||
end_byte,
|
||||
trailing_spaces,
|
||||
));
|
||||
} else {
|
||||
diagnostic.amend(Fix::replacement(
|
||||
format!("# noqa: {}", valid_codes.join(", ")),
|
||||
Location::new(row + 1, start),
|
||||
Location::new(row + 1, end),
|
||||
Location::new(row + 1, start_char),
|
||||
Location::new(row + 1, end_char),
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -267,3 +258,42 @@ pub fn check_noqa(
|
||||
ignored_diagnostics.sort_unstable();
|
||||
ignored_diagnostics
|
||||
}
|
||||
|
||||
/// Generate a [`Fix`] to delete a `noqa` directive.
|
||||
fn delete_noqa(
|
||||
row: usize,
|
||||
line: &str,
|
||||
leading_spaces: usize,
|
||||
start_byte: usize,
|
||||
end_byte: usize,
|
||||
trailing_spaces: usize,
|
||||
) -> Fix {
|
||||
if start_byte - leading_spaces == 0 && end_byte == line.len() {
|
||||
// Ex) `# noqa`
|
||||
Fix::deletion(Location::new(row + 1, 0), Location::new(row + 2, 0))
|
||||
} else if end_byte == line.len() {
|
||||
// Ex) `x = 1 # noqa`
|
||||
let start_char = line[..start_byte].chars().count();
|
||||
let end_char = start_char + line[start_byte..end_byte].chars().count();
|
||||
Fix::deletion(
|
||||
Location::new(row + 1, start_char - leading_spaces),
|
||||
Location::new(row + 1, end_char + trailing_spaces),
|
||||
)
|
||||
} else if line[end_byte..].trim_start().starts_with('#') {
|
||||
// Ex) `x = 1 # noqa # type: ignore`
|
||||
let start_char = line[..start_byte].chars().count();
|
||||
let end_char = start_char + line[start_byte..end_byte].chars().count();
|
||||
Fix::deletion(
|
||||
Location::new(row + 1, start_char),
|
||||
Location::new(row + 1, end_char + trailing_spaces),
|
||||
)
|
||||
} else {
|
||||
// Ex) `x = 1 # noqa here`
|
||||
let start_char = line[..start_byte].chars().count();
|
||||
let end_char = start_char + line[start_byte..end_byte].chars().count();
|
||||
Fix::deletion(
|
||||
Location::new(row + 1, start_char + 1 + 1),
|
||||
Location::new(row + 1, end_char + trailing_spaces),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,8 +12,8 @@ use crate::rules::flake8_executable::rules::{
|
||||
shebang_missing, shebang_newline, shebang_not_executable, shebang_python, shebang_whitespace,
|
||||
};
|
||||
use crate::rules::pycodestyle::rules::{
|
||||
doc_line_too_long, indentation_contains_tabs, line_too_long, mixed_spaces_and_tabs,
|
||||
no_newline_at_end_of_file, trailing_whitespace,
|
||||
doc_line_too_long, line_too_long, mixed_spaces_and_tabs, no_newline_at_end_of_file,
|
||||
tab_indentation, trailing_whitespace,
|
||||
};
|
||||
use crate::rules::pygrep_hooks::rules::{blanket_noqa, blanket_type_ignore};
|
||||
use crate::rules::pylint;
|
||||
@@ -32,28 +32,28 @@ pub fn check_physical_lines(
|
||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||
let mut has_any_shebang = false;
|
||||
|
||||
let enforce_blanket_noqa = settings.rules.enabled(&Rule::BlanketNOQA);
|
||||
let enforce_shebang_not_executable = settings.rules.enabled(&Rule::ShebangNotExecutable);
|
||||
let enforce_shebang_missing = settings.rules.enabled(&Rule::ShebangMissingExecutableFile);
|
||||
let enforce_shebang_whitespace = settings.rules.enabled(&Rule::ShebangWhitespace);
|
||||
let enforce_shebang_newline = settings.rules.enabled(&Rule::ShebangNewline);
|
||||
let enforce_shebang_python = settings.rules.enabled(&Rule::ShebangPython);
|
||||
let enforce_blanket_type_ignore = settings.rules.enabled(&Rule::BlanketTypeIgnore);
|
||||
let enforce_doc_line_too_long = settings.rules.enabled(&Rule::DocLineTooLong);
|
||||
let enforce_line_too_long = settings.rules.enabled(&Rule::LineTooLong);
|
||||
let enforce_no_newline_at_end_of_file = settings.rules.enabled(&Rule::NoNewLineAtEndOfFile);
|
||||
let enforce_unnecessary_coding_comment = settings.rules.enabled(&Rule::UTF8EncodingDeclaration);
|
||||
let enforce_mixed_spaces_and_tabs = settings.rules.enabled(&Rule::MixedSpacesAndTabs);
|
||||
let enforce_bidirectional_unicode = settings.rules.enabled(&Rule::BidirectionalUnicode);
|
||||
let enforce_trailing_whitespace = settings.rules.enabled(&Rule::TrailingWhitespace);
|
||||
let enforce_blanket_noqa = settings.rules.enabled(Rule::BlanketNOQA);
|
||||
let enforce_shebang_not_executable = settings.rules.enabled(Rule::ShebangNotExecutable);
|
||||
let enforce_shebang_missing = settings.rules.enabled(Rule::ShebangMissingExecutableFile);
|
||||
let enforce_shebang_whitespace = settings.rules.enabled(Rule::ShebangLeadingWhitespace);
|
||||
let enforce_shebang_newline = settings.rules.enabled(Rule::ShebangNotFirstLine);
|
||||
let enforce_shebang_python = settings.rules.enabled(Rule::ShebangMissingPython);
|
||||
let enforce_blanket_type_ignore = settings.rules.enabled(Rule::BlanketTypeIgnore);
|
||||
let enforce_doc_line_too_long = settings.rules.enabled(Rule::DocLineTooLong);
|
||||
let enforce_line_too_long = settings.rules.enabled(Rule::LineTooLong);
|
||||
let enforce_no_newline_at_end_of_file = settings.rules.enabled(Rule::MissingNewlineAtEndOfFile);
|
||||
let enforce_unnecessary_coding_comment = settings.rules.enabled(Rule::UTF8EncodingDeclaration);
|
||||
let enforce_mixed_spaces_and_tabs = settings.rules.enabled(Rule::MixedSpacesAndTabs);
|
||||
let enforce_bidirectional_unicode = settings.rules.enabled(Rule::BidirectionalUnicode);
|
||||
let enforce_trailing_whitespace = settings.rules.enabled(Rule::TrailingWhitespace);
|
||||
let enforce_blank_line_contains_whitespace =
|
||||
settings.rules.enabled(&Rule::BlankLineContainsWhitespace);
|
||||
let enforce_indentation_contains_tabs = settings.rules.enabled(&Rule::IndentationContainsTabs);
|
||||
settings.rules.enabled(Rule::BlankLineWithWhitespace);
|
||||
let enforce_tab_indentation = settings.rules.enabled(Rule::TabIndentation);
|
||||
|
||||
let fix_unnecessary_coding_comment =
|
||||
autofix.into() && settings.rules.should_fix(&Rule::UTF8EncodingDeclaration);
|
||||
autofix.into() && settings.rules.should_fix(Rule::UTF8EncodingDeclaration);
|
||||
let fix_shebang_whitespace =
|
||||
autofix.into() && settings.rules.should_fix(&Rule::ShebangWhitespace);
|
||||
autofix.into() && settings.rules.should_fix(Rule::ShebangLeadingWhitespace);
|
||||
|
||||
let mut commented_lines_iter = commented_lines.iter().peekable();
|
||||
let mut doc_lines_iter = doc_lines.iter().peekable();
|
||||
@@ -154,8 +154,8 @@ pub fn check_physical_lines(
|
||||
}
|
||||
}
|
||||
|
||||
if enforce_indentation_contains_tabs {
|
||||
if let Some(diagnostic) = indentation_contains_tabs(index, line) {
|
||||
if enforce_tab_indentation {
|
||||
if let Some(diagnostic) = tab_indentation(index, line) {
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
@@ -165,7 +165,7 @@ pub fn check_physical_lines(
|
||||
if let Some(diagnostic) = no_newline_at_end_of_file(
|
||||
locator,
|
||||
stylist,
|
||||
autofix.into() && settings.rules.should_fix(&Rule::NoNewLineAtEndOfFile),
|
||||
autofix.into() && settings.rules.should_fix(Rule::MissingNewlineAtEndOfFile),
|
||||
) {
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::registry::{AsRule, Rule};
|
||||
use crate::rules::ruff::rules::Context;
|
||||
use crate::rules::{
|
||||
eradicate, flake8_commas, flake8_implicit_str_concat, flake8_pyi, flake8_quotes, pycodestyle,
|
||||
pyupgrade, ruff,
|
||||
pylint, pyupgrade, ruff,
|
||||
};
|
||||
use crate::settings::{flags, Settings};
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
@@ -23,41 +23,43 @@ pub fn check_tokens(
|
||||
) -> Vec<Diagnostic> {
|
||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||
|
||||
let enforce_ambiguous_unicode_character = settings
|
||||
.rules
|
||||
.enabled(&Rule::AmbiguousUnicodeCharacterString)
|
||||
|| settings
|
||||
.rules
|
||||
.enabled(&Rule::AmbiguousUnicodeCharacterDocstring)
|
||||
|| settings
|
||||
.rules
|
||||
.enabled(&Rule::AmbiguousUnicodeCharacterComment);
|
||||
let enforce_quotes = settings.rules.enabled(&Rule::BadQuotesInlineString)
|
||||
|| settings.rules.enabled(&Rule::BadQuotesMultilineString)
|
||||
|| settings.rules.enabled(&Rule::BadQuotesDocstring)
|
||||
|| settings.rules.enabled(&Rule::AvoidableEscapedQuote);
|
||||
let enforce_commented_out_code = settings.rules.enabled(&Rule::CommentedOutCode);
|
||||
let enforce_compound_statements = settings
|
||||
.rules
|
||||
.enabled(&Rule::MultipleStatementsOnOneLineColon)
|
||||
|| settings
|
||||
.rules
|
||||
.enabled(&Rule::MultipleStatementsOnOneLineSemicolon)
|
||||
|| settings.rules.enabled(&Rule::UselessSemicolon);
|
||||
let enforce_invalid_escape_sequence = settings.rules.enabled(&Rule::InvalidEscapeSequence);
|
||||
let enforce_implicit_string_concatenation = settings
|
||||
.rules
|
||||
.enabled(&Rule::SingleLineImplicitStringConcatenation)
|
||||
|| settings
|
||||
.rules
|
||||
.enabled(&Rule::MultiLineImplicitStringConcatenation);
|
||||
let enforce_trailing_comma = settings.rules.enabled(&Rule::TrailingCommaMissing)
|
||||
|| settings
|
||||
.rules
|
||||
.enabled(&Rule::TrailingCommaOnBareTupleProhibited)
|
||||
|| settings.rules.enabled(&Rule::TrailingCommaProhibited);
|
||||
let enforce_extraneous_parenthesis = settings.rules.enabled(&Rule::ExtraneousParentheses);
|
||||
let enforce_type_comment_in_stub = settings.rules.enabled(&Rule::TypeCommentInStub);
|
||||
let enforce_ambiguous_unicode_character = settings.rules.any_enabled(&[
|
||||
Rule::AmbiguousUnicodeCharacterString,
|
||||
Rule::AmbiguousUnicodeCharacterDocstring,
|
||||
Rule::AmbiguousUnicodeCharacterComment,
|
||||
]);
|
||||
let enforce_invalid_string_character = settings.rules.any_enabled(&[
|
||||
Rule::InvalidCharacterBackspace,
|
||||
Rule::InvalidCharacterSub,
|
||||
Rule::InvalidCharacterEsc,
|
||||
Rule::InvalidCharacterNul,
|
||||
Rule::InvalidCharacterZeroWidthSpace,
|
||||
]);
|
||||
let enforce_quotes = settings.rules.any_enabled(&[
|
||||
Rule::BadQuotesInlineString,
|
||||
Rule::BadQuotesMultilineString,
|
||||
Rule::BadQuotesDocstring,
|
||||
Rule::AvoidableEscapedQuote,
|
||||
]);
|
||||
let enforce_commented_out_code = settings.rules.enabled(Rule::CommentedOutCode);
|
||||
let enforce_compound_statements = settings.rules.any_enabled(&[
|
||||
Rule::MultipleStatementsOnOneLineColon,
|
||||
Rule::MultipleStatementsOnOneLineSemicolon,
|
||||
Rule::UselessSemicolon,
|
||||
]);
|
||||
let enforce_invalid_escape_sequence = settings.rules.enabled(Rule::InvalidEscapeSequence);
|
||||
let enforce_implicit_string_concatenation = settings.rules.any_enabled(&[
|
||||
Rule::SingleLineImplicitStringConcatenation,
|
||||
Rule::MultiLineImplicitStringConcatenation,
|
||||
]);
|
||||
|
||||
let enforce_trailing_comma = settings.rules.any_enabled(&[
|
||||
Rule::MissingTrailingComma,
|
||||
Rule::TrailingCommaOnBareTuple,
|
||||
Rule::ProhibitedTrailingComma,
|
||||
]);
|
||||
let enforce_extraneous_parenthesis = settings.rules.enabled(Rule::ExtraneousParentheses);
|
||||
let enforce_type_comment_in_stub = settings.rules.enabled(Rule::TypeCommentInStub);
|
||||
|
||||
// RUF001, RUF002, RUF003
|
||||
if enforce_ambiguous_unicode_character {
|
||||
@@ -111,11 +113,23 @@ pub fn check_tokens(
|
||||
locator,
|
||||
*start,
|
||||
*end,
|
||||
autofix.into() && settings.rules.should_fix(&Rule::InvalidEscapeSequence),
|
||||
autofix.into() && settings.rules.should_fix(Rule::InvalidEscapeSequence),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
// PLE2510, PLE2512, PLE2513
|
||||
if enforce_invalid_string_character {
|
||||
for (start, tok, end) in tokens.iter().flatten() {
|
||||
if matches!(tok, Tok::String { .. }) {
|
||||
diagnostics.extend(
|
||||
pylint::rules::invalid_string_characters(locator, *start, *end, autofix.into())
|
||||
.into_iter()
|
||||
.filter(|diagnostic| settings.rules.enabled(diagnostic.kind.rule())),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// E701, E702, E703
|
||||
if enforce_compound_statements {
|
||||
|
||||
@@ -26,67 +26,67 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
Some(match (linter, code) {
|
||||
// pycodestyle errors
|
||||
(Pycodestyle, "E101") => Rule::MixedSpacesAndTabs,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E111") => Rule::IndentationWithInvalidMultiple,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E112") => Rule::NoIndentedBlock,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E113") => Rule::UnexpectedIndentation,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E114") => Rule::IndentationWithInvalidMultipleComment,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E115") => Rule::NoIndentedBlockComment,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E116") => Rule::UnexpectedIndentationComment,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E117") => Rule::OverIndented,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E201") => Rule::WhitespaceAfterOpenBracket,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E202") => Rule::WhitespaceBeforeCloseBracket,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E203") => Rule::WhitespaceBeforePunctuation,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E211") => Rule::WhitespaceBeforeParameters,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E221") => Rule::MultipleSpacesBeforeOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E222") => Rule::MultipleSpacesAfterOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E223") => Rule::TabBeforeOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E224") => Rule::TabAfterOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E225") => Rule::MissingWhitespaceAroundOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E226") => Rule::MissingWhitespaceAroundArithmeticOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E227") => Rule::MissingWhitespaceAroundBitwiseOrShiftOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E228") => Rule::MissingWhitespaceAroundModuloOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E231") => Rule::MissingWhitespace,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E251") => Rule::UnexpectedSpacesAroundKeywordParameterEquals,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E252") => Rule::MissingWhitespaceAroundParameterEquals,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E261") => Rule::TooFewSpacesBeforeInlineComment,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E262") => Rule::NoSpaceAfterInlineComment,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E265") => Rule::NoSpaceAfterBlockComment,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E266") => Rule::MultipleLeadingHashesForBlockComment,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E271") => Rule::MultipleSpacesAfterKeyword,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E272") => Rule::MultipleSpacesBeforeKeyword,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E273") => Rule::TabAfterKeyword,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E274") => Rule::TabBeforeKeyword,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
(Pycodestyle, "E275") => Rule::MissingWhitespaceAfterKeyword,
|
||||
(Pycodestyle, "E401") => Rule::MultipleImportsOnOneLine,
|
||||
(Pycodestyle, "E402") => Rule::ModuleImportNotAtTopOfFile,
|
||||
@@ -108,20 +108,20 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Pycodestyle, "E999") => Rule::SyntaxError,
|
||||
|
||||
// pycodestyle warnings
|
||||
(Pycodestyle, "W191") => Rule::IndentationContainsTabs,
|
||||
(Pycodestyle, "W191") => Rule::TabIndentation,
|
||||
(Pycodestyle, "W291") => Rule::TrailingWhitespace,
|
||||
(Pycodestyle, "W292") => Rule::NoNewLineAtEndOfFile,
|
||||
(Pycodestyle, "W293") => Rule::BlankLineContainsWhitespace,
|
||||
(Pycodestyle, "W292") => Rule::MissingNewlineAtEndOfFile,
|
||||
(Pycodestyle, "W293") => Rule::BlankLineWithWhitespace,
|
||||
(Pycodestyle, "W505") => Rule::DocLineTooLong,
|
||||
(Pycodestyle, "W605") => Rule::InvalidEscapeSequence,
|
||||
|
||||
// pyflakes
|
||||
(Pyflakes, "401") => Rule::UnusedImport,
|
||||
(Pyflakes, "402") => Rule::ImportShadowedByLoopVar,
|
||||
(Pyflakes, "403") => Rule::ImportStar,
|
||||
(Pyflakes, "403") => Rule::UndefinedLocalWithImportStar,
|
||||
(Pyflakes, "404") => Rule::LateFutureImport,
|
||||
(Pyflakes, "405") => Rule::ImportStarUsage,
|
||||
(Pyflakes, "406") => Rule::ImportStarNotPermitted,
|
||||
(Pyflakes, "405") => Rule::UndefinedLocalWithImportStarUsage,
|
||||
(Pyflakes, "406") => Rule::UndefinedLocalWithNestedImportStarUsage,
|
||||
(Pyflakes, "407") => Rule::FutureFeatureNotDefined,
|
||||
(Pyflakes, "501") => Rule::PercentFormatInvalidFormat,
|
||||
(Pyflakes, "502") => Rule::PercentFormatExpectedMapping,
|
||||
@@ -141,7 +141,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Pyflakes, "601") => Rule::MultiValueRepeatedKeyLiteral,
|
||||
(Pyflakes, "602") => Rule::MultiValueRepeatedKeyVariable,
|
||||
(Pyflakes, "621") => Rule::ExpressionsInStarAssignment,
|
||||
(Pyflakes, "622") => Rule::TwoStarredExpressions,
|
||||
(Pyflakes, "622") => Rule::MultipleStarredExpressions,
|
||||
(Pyflakes, "631") => Rule::AssertTuple,
|
||||
(Pyflakes, "632") => Rule::IsLiteral,
|
||||
(Pyflakes, "633") => Rule::InvalidPrintSyntax,
|
||||
@@ -166,11 +166,11 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Pylint, "C3002") => Rule::UnnecessaryDirectLambdaCall,
|
||||
(Pylint, "E0100") => Rule::YieldInInit,
|
||||
(Pylint, "E0101") => Rule::ReturnInInit,
|
||||
(Pylint, "E0116") => Rule::ContinueInFinally,
|
||||
(Pylint, "E0117") => Rule::NonlocalWithoutBinding,
|
||||
(Pylint, "E0118") => Rule::UsedPriorGlobalDeclaration,
|
||||
(Pylint, "E0118") => Rule::UsePriorToGlobalDeclaration,
|
||||
(Pylint, "E0604") => Rule::InvalidAllObject,
|
||||
(Pylint, "E0605") => Rule::InvalidAllFormat,
|
||||
(Pylint, "W1508") => Rule::InvalidEnvvarDefault,
|
||||
(Pylint, "E1142") => Rule::AwaitOutsideAsync,
|
||||
(Pylint, "E1205") => Rule::LoggingTooManyArgs,
|
||||
(Pylint, "E1206") => Rule::LoggingTooFewArgs,
|
||||
@@ -178,20 +178,29 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Pylint, "E1310") => Rule::BadStrStripCall,
|
||||
(Pylint, "E1507") => Rule::InvalidEnvvarValue,
|
||||
(Pylint, "E2502") => Rule::BidirectionalUnicode,
|
||||
(Pylint, "E2510") => Rule::InvalidCharacterBackspace,
|
||||
(Pylint, "E2512") => Rule::InvalidCharacterSub,
|
||||
(Pylint, "E2513") => Rule::InvalidCharacterEsc,
|
||||
(Pylint, "E2514") => Rule::InvalidCharacterNul,
|
||||
(Pylint, "E2515") => Rule::InvalidCharacterZeroWidthSpace,
|
||||
(Pylint, "R0133") => Rule::ComparisonOfConstant,
|
||||
(Pylint, "R0206") => Rule::PropertyWithParameters,
|
||||
(Pylint, "R0402") => Rule::ConsiderUsingFromImport,
|
||||
(Pylint, "R0402") => Rule::ManualFromImport,
|
||||
(Pylint, "R0911") => Rule::TooManyReturnStatements,
|
||||
(Pylint, "R0912") => Rule::TooManyBranches,
|
||||
(Pylint, "R0913") => Rule::TooManyArguments,
|
||||
(Pylint, "R0915") => Rule::TooManyStatements,
|
||||
(Pylint, "R1701") => Rule::ConsiderMergingIsinstance,
|
||||
(Pylint, "R1722") => Rule::ConsiderUsingSysExit,
|
||||
(Pylint, "R1701") => Rule::RepeatedIsinstanceCalls,
|
||||
(Pylint, "R1711") => Rule::UselessReturn,
|
||||
(Pylint, "R1722") => Rule::SysExitAlias,
|
||||
(Pylint, "R2004") => Rule::MagicValueComparison,
|
||||
(Pylint, "R5501") => Rule::CollapsibleElseIf,
|
||||
(Pylint, "W0120") => Rule::UselessElseOnLoop,
|
||||
(Pylint, "W0129") => Rule::AssertOnStringLiteral,
|
||||
(Pylint, "W0602") => Rule::GlobalVariableNotAssigned,
|
||||
(Pylint, "W0603") => Rule::GlobalStatement,
|
||||
(Pylint, "W0711") => Rule::BinaryOpException,
|
||||
(Pylint, "W1508") => Rule::InvalidEnvvarDefault,
|
||||
(Pylint, "W2901") => Rule::RedefinedLoopName,
|
||||
|
||||
// flake8-builtins
|
||||
@@ -206,7 +215,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Flake8Bugbear, "005") => Rule::StripWithMultiCharacters,
|
||||
(Flake8Bugbear, "006") => Rule::MutableArgumentDefault,
|
||||
(Flake8Bugbear, "007") => Rule::UnusedLoopControlVariable,
|
||||
(Flake8Bugbear, "008") => Rule::FunctionCallArgumentDefault,
|
||||
(Flake8Bugbear, "008") => Rule::FunctionCallInDefaultArgument,
|
||||
(Flake8Bugbear, "009") => Rule::GetAttrWithConstant,
|
||||
(Flake8Bugbear, "010") => Rule::SetAttrWithConstant,
|
||||
(Flake8Bugbear, "011") => Rule::AssertFalse,
|
||||
@@ -226,6 +235,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Flake8Bugbear, "025") => Rule::DuplicateTryBlockException,
|
||||
(Flake8Bugbear, "026") => Rule::StarArgUnpackingAfterKeywordArg,
|
||||
(Flake8Bugbear, "027") => Rule::EmptyMethodWithoutAbstractDecorator,
|
||||
(Flake8Bugbear, "028") => Rule::NoExplicitStacklevel,
|
||||
(Flake8Bugbear, "029") => Rule::ExceptWithEmptyTuple,
|
||||
(Flake8Bugbear, "030") => Rule::ExceptWithNonExceptionClasses,
|
||||
(Flake8Bugbear, "032") => Rule::UnintentionalTypeAnnotation,
|
||||
@@ -279,8 +289,8 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Flake8ImplicitStrConcat, "003") => Rule::ExplicitStringConcatenation,
|
||||
|
||||
// flake8-print
|
||||
(Flake8Print, "1") => Rule::PrintFound,
|
||||
(Flake8Print, "3") => Rule::PPrintFound,
|
||||
(Flake8Print, "1") => Rule::Print,
|
||||
(Flake8Print, "3") => Rule::PPrint,
|
||||
|
||||
// flake8-quotes
|
||||
(Flake8Quotes, "000") => Rule::BadQuotesInlineString,
|
||||
@@ -294,7 +304,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Flake8Annotations, "003") => Rule::MissingTypeKwargs,
|
||||
(Flake8Annotations, "101") => Rule::MissingTypeSelf,
|
||||
(Flake8Annotations, "102") => Rule::MissingTypeCls,
|
||||
(Flake8Annotations, "201") => Rule::MissingReturnTypePublicFunction,
|
||||
(Flake8Annotations, "201") => Rule::MissingReturnTypeUndocumentedPublicFunction,
|
||||
(Flake8Annotations, "202") => Rule::MissingReturnTypePrivateFunction,
|
||||
(Flake8Annotations, "204") => Rule::MissingReturnTypeSpecialMethod,
|
||||
(Flake8Annotations, "205") => Rule::MissingReturnTypeStaticMethod,
|
||||
@@ -302,16 +312,16 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Flake8Annotations, "401") => Rule::AnyType,
|
||||
|
||||
// flake8-2020
|
||||
(Flake82020, "101") => Rule::SysVersionSlice3Referenced,
|
||||
(Flake82020, "102") => Rule::SysVersion2Referenced,
|
||||
(Flake82020, "101") => Rule::SysVersionSlice3,
|
||||
(Flake82020, "102") => Rule::SysVersion2,
|
||||
(Flake82020, "103") => Rule::SysVersionCmpStr3,
|
||||
(Flake82020, "201") => Rule::SysVersionInfo0Eq3Referenced,
|
||||
(Flake82020, "202") => Rule::SixPY3Referenced,
|
||||
(Flake82020, "201") => Rule::SysVersionInfo0Eq3,
|
||||
(Flake82020, "202") => Rule::SixPY3,
|
||||
(Flake82020, "203") => Rule::SysVersionInfo1CmpInt,
|
||||
(Flake82020, "204") => Rule::SysVersionInfoMinorCmpInt,
|
||||
(Flake82020, "301") => Rule::SysVersion0Referenced,
|
||||
(Flake82020, "301") => Rule::SysVersion0,
|
||||
(Flake82020, "302") => Rule::SysVersionCmpStr10,
|
||||
(Flake82020, "303") => Rule::SysVersionSlice1Referenced,
|
||||
(Flake82020, "303") => Rule::SysVersionSlice1,
|
||||
|
||||
// flake8-simplify
|
||||
(Flake8Simplify, "101") => Rule::DuplicateIsinstanceCall,
|
||||
@@ -319,16 +329,15 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Flake8Simplify, "103") => Rule::NeedlessBool,
|
||||
(Flake8Simplify, "105") => Rule::UseContextlibSuppress,
|
||||
(Flake8Simplify, "107") => Rule::ReturnInTryExceptFinally,
|
||||
(Flake8Simplify, "108") => Rule::UseTernaryOperator,
|
||||
(Flake8Simplify, "108") => Rule::IfElseBlockInsteadOfIfExp,
|
||||
(Flake8Simplify, "109") => Rule::CompareWithTuple,
|
||||
(Flake8Simplify, "110") => Rule::ReimplementedBuiltin,
|
||||
// (Flake8Simplify, "111") => Rule::ReimplementedBuiltin,
|
||||
(Flake8Simplify, "112") => Rule::UseCapitalEnvironmentVariables,
|
||||
(Flake8Simplify, "112") => Rule::UncapitalizedEnvironmentVariables,
|
||||
(Flake8Simplify, "114") => Rule::IfWithSameArms,
|
||||
(Flake8Simplify, "115") => Rule::OpenFileWithContextHandler,
|
||||
(Flake8Simplify, "116") => Rule::ManualDictLookup,
|
||||
(Flake8Simplify, "116") => Rule::IfElseBlockInsteadOfDictLookup,
|
||||
(Flake8Simplify, "117") => Rule::MultipleWithStatements,
|
||||
(Flake8Simplify, "118") => Rule::KeyInDict,
|
||||
(Flake8Simplify, "118") => Rule::InDictKeys,
|
||||
(Flake8Simplify, "201") => Rule::NegateEqualOp,
|
||||
(Flake8Simplify, "202") => Rule::NegateNotEqualOp,
|
||||
(Flake8Simplify, "208") => Rule::DoubleNegation,
|
||||
@@ -340,15 +349,15 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Flake8Simplify, "222") => Rule::ExprOrTrue,
|
||||
(Flake8Simplify, "223") => Rule::ExprAndFalse,
|
||||
(Flake8Simplify, "300") => Rule::YodaConditions,
|
||||
(Flake8Simplify, "401") => Rule::DictGetWithDefault,
|
||||
(Flake8Simplify, "401") => Rule::IfElseBlockInsteadOfDictGet,
|
||||
|
||||
// pyupgrade
|
||||
(Pyupgrade, "001") => Rule::UselessMetaclassType,
|
||||
(Pyupgrade, "003") => Rule::TypeOfPrimitive,
|
||||
(Pyupgrade, "004") => Rule::UselessObjectInheritance,
|
||||
(Pyupgrade, "005") => Rule::DeprecatedUnittestAlias,
|
||||
(Pyupgrade, "006") => Rule::DeprecatedCollectionType,
|
||||
(Pyupgrade, "007") => Rule::TypingUnion,
|
||||
(Pyupgrade, "006") => Rule::NonPEP585Annotation,
|
||||
(Pyupgrade, "007") => Rule::NonPEP604Annotation,
|
||||
(Pyupgrade, "008") => Rule::SuperCallWithParameters,
|
||||
(Pyupgrade, "009") => Rule::UTF8EncodingDeclaration,
|
||||
(Pyupgrade, "010") => Rule::UnnecessaryFutureImport,
|
||||
@@ -363,32 +372,32 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Pyupgrade, "020") => Rule::OpenAlias,
|
||||
(Pyupgrade, "021") => Rule::ReplaceUniversalNewlines,
|
||||
(Pyupgrade, "022") => Rule::ReplaceStdoutStderr,
|
||||
(Pyupgrade, "023") => Rule::RewriteCElementTree,
|
||||
(Pyupgrade, "023") => Rule::DeprecatedCElementTree,
|
||||
(Pyupgrade, "024") => Rule::OSErrorAlias,
|
||||
(Pyupgrade, "025") => Rule::RewriteUnicodeLiteral,
|
||||
(Pyupgrade, "026") => Rule::RewriteMockImport,
|
||||
(Pyupgrade, "027") => Rule::RewriteListComprehension,
|
||||
(Pyupgrade, "028") => Rule::RewriteYieldFrom,
|
||||
(Pyupgrade, "025") => Rule::UnicodeKindPrefix,
|
||||
(Pyupgrade, "026") => Rule::DeprecatedMockImport,
|
||||
(Pyupgrade, "027") => Rule::UnpackedListComprehension,
|
||||
(Pyupgrade, "028") => Rule::YieldInForLoop,
|
||||
(Pyupgrade, "029") => Rule::UnnecessaryBuiltinImport,
|
||||
(Pyupgrade, "030") => Rule::FormatLiterals,
|
||||
(Pyupgrade, "031") => Rule::PrintfStringFormatting,
|
||||
(Pyupgrade, "032") => Rule::FString,
|
||||
(Pyupgrade, "033") => Rule::FunctoolsCache,
|
||||
(Pyupgrade, "033") => Rule::LRUCacheWithMaxsizeNone,
|
||||
(Pyupgrade, "034") => Rule::ExtraneousParentheses,
|
||||
(Pyupgrade, "035") => Rule::DeprecatedImport,
|
||||
(Pyupgrade, "036") => Rule::OutdatedVersionBlock,
|
||||
(Pyupgrade, "037") => Rule::QuotedAnnotation,
|
||||
(Pyupgrade, "038") => Rule::IsinstanceWithTuple,
|
||||
(Pyupgrade, "038") => Rule::NonPEP604Isinstance,
|
||||
|
||||
// pydocstyle
|
||||
(Pydocstyle, "100") => Rule::PublicModule,
|
||||
(Pydocstyle, "101") => Rule::PublicClass,
|
||||
(Pydocstyle, "102") => Rule::PublicMethod,
|
||||
(Pydocstyle, "103") => Rule::PublicFunction,
|
||||
(Pydocstyle, "104") => Rule::PublicPackage,
|
||||
(Pydocstyle, "105") => Rule::MagicMethod,
|
||||
(Pydocstyle, "106") => Rule::PublicNestedClass,
|
||||
(Pydocstyle, "107") => Rule::PublicInit,
|
||||
(Pydocstyle, "100") => Rule::UndocumentedPublicModule,
|
||||
(Pydocstyle, "101") => Rule::UndocumentedPublicClass,
|
||||
(Pydocstyle, "102") => Rule::UndocumentedPublicMethod,
|
||||
(Pydocstyle, "103") => Rule::UndocumentedPublicFunction,
|
||||
(Pydocstyle, "104") => Rule::UndocumentedPublicPackage,
|
||||
(Pydocstyle, "105") => Rule::UndocumentedMagicMethod,
|
||||
(Pydocstyle, "106") => Rule::UndocumentedPublicNestedClass,
|
||||
(Pydocstyle, "107") => Rule::UndocumentedPublicInit,
|
||||
(Pydocstyle, "200") => Rule::FitsOnOneLine,
|
||||
(Pydocstyle, "201") => Rule::NoBlankLineBeforeFunction,
|
||||
(Pydocstyle, "202") => Rule::NoBlankLineAfterFunction,
|
||||
@@ -396,11 +405,11 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Pydocstyle, "204") => Rule::OneBlankLineAfterClass,
|
||||
(Pydocstyle, "205") => Rule::BlankLineAfterSummary,
|
||||
(Pydocstyle, "206") => Rule::IndentWithSpaces,
|
||||
(Pydocstyle, "207") => Rule::NoUnderIndentation,
|
||||
(Pydocstyle, "208") => Rule::NoOverIndentation,
|
||||
(Pydocstyle, "207") => Rule::UnderIndentation,
|
||||
(Pydocstyle, "208") => Rule::OverIndentation,
|
||||
(Pydocstyle, "209") => Rule::NewLineAfterLastParagraph,
|
||||
(Pydocstyle, "210") => Rule::NoSurroundingWhitespace,
|
||||
(Pydocstyle, "211") => Rule::NoBlankLineBeforeClass,
|
||||
(Pydocstyle, "210") => Rule::SurroundingWhitespace,
|
||||
(Pydocstyle, "211") => Rule::BlankLineBeforeClass,
|
||||
(Pydocstyle, "212") => Rule::MultiLineSummaryFirstLine,
|
||||
(Pydocstyle, "213") => Rule::MultiLineSummarySecondLine,
|
||||
(Pydocstyle, "214") => Rule::SectionNotOverIndented,
|
||||
@@ -417,9 +426,9 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Pydocstyle, "407") => Rule::DashedUnderlineAfterSection,
|
||||
(Pydocstyle, "408") => Rule::SectionUnderlineAfterName,
|
||||
(Pydocstyle, "409") => Rule::SectionUnderlineMatchesSectionLength,
|
||||
(Pydocstyle, "410") => Rule::BlankLineAfterSection,
|
||||
(Pydocstyle, "411") => Rule::BlankLineBeforeSection,
|
||||
(Pydocstyle, "412") => Rule::NoBlankLinesBetweenHeaderAndContent,
|
||||
(Pydocstyle, "410") => Rule::NoBlankLineAfterSection,
|
||||
(Pydocstyle, "411") => Rule::NoBlankLineBeforeSection,
|
||||
(Pydocstyle, "412") => Rule::BlankLinesBetweenHeaderAndContent,
|
||||
(Pydocstyle, "413") => Rule::BlankLineAfterLastSection,
|
||||
(Pydocstyle, "414") => Rule::EmptyDocstringSection,
|
||||
(Pydocstyle, "415") => Rule::EndsInPunctuation,
|
||||
@@ -454,6 +463,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Eradicate, "001") => Rule::CommentedOutCode,
|
||||
|
||||
// flake8-bandit
|
||||
(Flake8Bandit, "001") => Rule::DeniedFunctionCall,
|
||||
(Flake8Bandit, "101") => Rule::Assert,
|
||||
(Flake8Bandit, "102") => Rule::ExecBuiltin,
|
||||
(Flake8Bandit, "103") => Rule::BadFilePermissions,
|
||||
@@ -501,24 +511,24 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Flake8Datetimez, "012") => Rule::CallDateFromtimestamp,
|
||||
|
||||
// pygrep-hooks
|
||||
(PygrepHooks, "001") => Rule::NoEval,
|
||||
(PygrepHooks, "001") => Rule::Eval,
|
||||
(PygrepHooks, "002") => Rule::DeprecatedLogWarn,
|
||||
(PygrepHooks, "003") => Rule::BlanketTypeIgnore,
|
||||
(PygrepHooks, "004") => Rule::BlanketNOQA,
|
||||
|
||||
// pandas-vet
|
||||
(PandasVet, "002") => Rule::UseOfInplaceArgument,
|
||||
(PandasVet, "003") => Rule::UseOfDotIsNull,
|
||||
(PandasVet, "004") => Rule::UseOfDotNotNull,
|
||||
(PandasVet, "007") => Rule::UseOfDotIx,
|
||||
(PandasVet, "008") => Rule::UseOfDotAt,
|
||||
(PandasVet, "009") => Rule::UseOfDotIat,
|
||||
(PandasVet, "010") => Rule::UseOfDotPivotOrUnstack,
|
||||
(PandasVet, "011") => Rule::UseOfDotValues,
|
||||
(PandasVet, "012") => Rule::UseOfDotReadTable,
|
||||
(PandasVet, "013") => Rule::UseOfDotStack,
|
||||
(PandasVet, "015") => Rule::UseOfPdMerge,
|
||||
(PandasVet, "901") => Rule::DfIsABadVariableName,
|
||||
(PandasVet, "002") => Rule::PandasUseOfInplaceArgument,
|
||||
(PandasVet, "003") => Rule::PandasUseOfDotIsNull,
|
||||
(PandasVet, "004") => Rule::PandasUseOfDotNotNull,
|
||||
(PandasVet, "007") => Rule::PandasUseOfDotIx,
|
||||
(PandasVet, "008") => Rule::PandasUseOfDotAt,
|
||||
(PandasVet, "009") => Rule::PandasUseOfDotIat,
|
||||
(PandasVet, "010") => Rule::PandasUseOfDotPivotOrUnstack,
|
||||
(PandasVet, "011") => Rule::PandasUseOfDotValues,
|
||||
(PandasVet, "012") => Rule::PandasUseOfDotReadTable,
|
||||
(PandasVet, "013") => Rule::PandasUseOfDotStack,
|
||||
(PandasVet, "015") => Rule::PandasUseOfPdMerge,
|
||||
(PandasVet, "901") => Rule::PandasDfVariableName,
|
||||
|
||||
// flake8-errmsg
|
||||
(Flake8ErrMsg, "101") => Rule::RawStringInException,
|
||||
@@ -526,58 +536,58 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Flake8ErrMsg, "103") => Rule::DotFormatInException,
|
||||
|
||||
// flake8-pyi
|
||||
(Flake8Pyi, "001") => Rule::PrefixTypeParams,
|
||||
(Flake8Pyi, "001") => Rule::UnprefixedTypeParam,
|
||||
(Flake8Pyi, "006") => Rule::BadVersionInfoComparison,
|
||||
(Flake8Pyi, "007") => Rule::UnrecognizedPlatformCheck,
|
||||
(Flake8Pyi, "008") => Rule::UnrecognizedPlatformName,
|
||||
(Flake8Pyi, "009") => Rule::PassStatementStubBody,
|
||||
(Flake8Pyi, "010") => Rule::NonEmptyStubBody,
|
||||
(Flake8Pyi, "011") => Rule::TypedArgumentSimpleDefaults,
|
||||
(Flake8Pyi, "014") => Rule::ArgumentSimpleDefaults,
|
||||
(Flake8Pyi, "011") => Rule::TypedArgumentDefaultInStub,
|
||||
(Flake8Pyi, "014") => Rule::ArgumentDefaultInStub,
|
||||
(Flake8Pyi, "021") => Rule::DocstringInStub,
|
||||
(Flake8Pyi, "033") => Rule::TypeCommentInStub,
|
||||
|
||||
// flake8-pytest-style
|
||||
(Flake8PytestStyle, "001") => Rule::IncorrectFixtureParenthesesStyle,
|
||||
(Flake8PytestStyle, "002") => Rule::FixturePositionalArgs,
|
||||
(Flake8PytestStyle, "003") => Rule::ExtraneousScopeFunction,
|
||||
(Flake8PytestStyle, "004") => Rule::MissingFixtureNameUnderscore,
|
||||
(Flake8PytestStyle, "005") => Rule::IncorrectFixtureNameUnderscore,
|
||||
(Flake8PytestStyle, "006") => Rule::ParametrizeNamesWrongType,
|
||||
(Flake8PytestStyle, "007") => Rule::ParametrizeValuesWrongType,
|
||||
(Flake8PytestStyle, "008") => Rule::PatchWithLambda,
|
||||
(Flake8PytestStyle, "009") => Rule::UnittestAssertion,
|
||||
(Flake8PytestStyle, "010") => Rule::RaisesWithoutException,
|
||||
(Flake8PytestStyle, "011") => Rule::RaisesTooBroad,
|
||||
(Flake8PytestStyle, "012") => Rule::RaisesWithMultipleStatements,
|
||||
(Flake8PytestStyle, "013") => Rule::IncorrectPytestImport,
|
||||
(Flake8PytestStyle, "015") => Rule::AssertAlwaysFalse,
|
||||
(Flake8PytestStyle, "016") => Rule::FailWithoutMessage,
|
||||
(Flake8PytestStyle, "017") => Rule::AssertInExcept,
|
||||
(Flake8PytestStyle, "018") => Rule::CompositeAssertion,
|
||||
(Flake8PytestStyle, "019") => Rule::FixtureParamWithoutValue,
|
||||
(Flake8PytestStyle, "020") => Rule::DeprecatedYieldFixture,
|
||||
(Flake8PytestStyle, "021") => Rule::FixtureFinalizerCallback,
|
||||
(Flake8PytestStyle, "022") => Rule::UselessYieldFixture,
|
||||
(Flake8PytestStyle, "023") => Rule::IncorrectMarkParenthesesStyle,
|
||||
(Flake8PytestStyle, "024") => Rule::UnnecessaryAsyncioMarkOnFixture,
|
||||
(Flake8PytestStyle, "025") => Rule::ErroneousUseFixturesOnFixture,
|
||||
(Flake8PytestStyle, "026") => Rule::UseFixturesWithoutParameters,
|
||||
(Flake8PytestStyle, "001") => Rule::PytestFixtureIncorrectParenthesesStyle,
|
||||
(Flake8PytestStyle, "002") => Rule::PytestFixturePositionalArgs,
|
||||
(Flake8PytestStyle, "003") => Rule::PytestExtraneousScopeFunction,
|
||||
(Flake8PytestStyle, "004") => Rule::PytestMissingFixtureNameUnderscore,
|
||||
(Flake8PytestStyle, "005") => Rule::PytestIncorrectFixtureNameUnderscore,
|
||||
(Flake8PytestStyle, "006") => Rule::PytestParametrizeNamesWrongType,
|
||||
(Flake8PytestStyle, "007") => Rule::PytestParametrizeValuesWrongType,
|
||||
(Flake8PytestStyle, "008") => Rule::PytestPatchWithLambda,
|
||||
(Flake8PytestStyle, "009") => Rule::PytestUnittestAssertion,
|
||||
(Flake8PytestStyle, "010") => Rule::PytestRaisesWithoutException,
|
||||
(Flake8PytestStyle, "011") => Rule::PytestRaisesTooBroad,
|
||||
(Flake8PytestStyle, "012") => Rule::PytestRaisesWithMultipleStatements,
|
||||
(Flake8PytestStyle, "013") => Rule::PytestIncorrectPytestImport,
|
||||
(Flake8PytestStyle, "015") => Rule::PytestAssertAlwaysFalse,
|
||||
(Flake8PytestStyle, "016") => Rule::PytestFailWithoutMessage,
|
||||
(Flake8PytestStyle, "017") => Rule::PytestAssertInExcept,
|
||||
(Flake8PytestStyle, "018") => Rule::PytestCompositeAssertion,
|
||||
(Flake8PytestStyle, "019") => Rule::PytestFixtureParamWithoutValue,
|
||||
(Flake8PytestStyle, "020") => Rule::PytestDeprecatedYieldFixture,
|
||||
(Flake8PytestStyle, "021") => Rule::PytestFixtureFinalizerCallback,
|
||||
(Flake8PytestStyle, "022") => Rule::PytestUselessYieldFixture,
|
||||
(Flake8PytestStyle, "023") => Rule::PytestIncorrectMarkParenthesesStyle,
|
||||
(Flake8PytestStyle, "024") => Rule::PytestUnnecessaryAsyncioMarkOnFixture,
|
||||
(Flake8PytestStyle, "025") => Rule::PytestErroneousUseFixturesOnFixture,
|
||||
(Flake8PytestStyle, "026") => Rule::PytestUseFixturesWithoutParameters,
|
||||
|
||||
// flake8-pie
|
||||
(Flake8Pie, "790") => Rule::UnnecessaryPass,
|
||||
(Flake8Pie, "794") => Rule::DupeClassFieldDefinitions,
|
||||
(Flake8Pie, "796") => Rule::PreferUniqueEnums,
|
||||
(Flake8Pie, "794") => Rule::DuplicateClassFieldDefinition,
|
||||
(Flake8Pie, "796") => Rule::NonUniqueEnums,
|
||||
(Flake8Pie, "800") => Rule::UnnecessarySpread,
|
||||
(Flake8Pie, "802") => Rule::UnnecessaryComprehensionAnyAll,
|
||||
(Flake8Pie, "804") => Rule::UnnecessaryDictKwargs,
|
||||
(Flake8Pie, "807") => Rule::PreferListBuiltin,
|
||||
(Flake8Pie, "810") => Rule::SingleStartsEndsWith,
|
||||
(Flake8Pie, "807") => Rule::ReimplementedListBuiltin,
|
||||
(Flake8Pie, "810") => Rule::MultipleStartsEndsWith,
|
||||
|
||||
// flake8-commas
|
||||
(Flake8Commas, "812") => Rule::TrailingCommaMissing,
|
||||
(Flake8Commas, "818") => Rule::TrailingCommaOnBareTupleProhibited,
|
||||
(Flake8Commas, "819") => Rule::TrailingCommaProhibited,
|
||||
(Flake8Commas, "812") => Rule::MissingTrailingComma,
|
||||
(Flake8Commas, "818") => Rule::TrailingCommaOnBareTuple,
|
||||
(Flake8Commas, "819") => Rule::ProhibitedTrailingComma,
|
||||
|
||||
// flake8-no-pep420
|
||||
(Flake8NoPep420, "001") => Rule::ImplicitNamespacePackage,
|
||||
@@ -585,9 +595,9 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
// flake8-executable
|
||||
(Flake8Executable, "001") => Rule::ShebangNotExecutable,
|
||||
(Flake8Executable, "002") => Rule::ShebangMissingExecutableFile,
|
||||
(Flake8Executable, "003") => Rule::ShebangPython,
|
||||
(Flake8Executable, "004") => Rule::ShebangWhitespace,
|
||||
(Flake8Executable, "005") => Rule::ShebangNewline,
|
||||
(Flake8Executable, "003") => Rule::ShebangMissingPython,
|
||||
(Flake8Executable, "004") => Rule::ShebangLeadingWhitespace,
|
||||
(Flake8Executable, "005") => Rule::ShebangNotFirstLine,
|
||||
|
||||
// flake8-type-checking
|
||||
(Flake8TypeChecking, "001") => Rule::TypingOnlyFirstPartyImport,
|
||||
@@ -599,7 +609,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
// tryceratops
|
||||
(Tryceratops, "002") => Rule::RaiseVanillaClass,
|
||||
(Tryceratops, "003") => Rule::RaiseVanillaArgs,
|
||||
(Tryceratops, "004") => Rule::PreferTypeError,
|
||||
(Tryceratops, "004") => Rule::TypeCheckWithoutTypeError,
|
||||
(Tryceratops, "200") => Rule::ReraiseNoCause,
|
||||
(Tryceratops, "201") => Rule::VerboseRaise,
|
||||
(Tryceratops, "300") => Rule::TryConsiderElse,
|
||||
@@ -658,17 +668,18 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Ruff, "001") => Rule::AmbiguousUnicodeCharacterString,
|
||||
(Ruff, "002") => Rule::AmbiguousUnicodeCharacterDocstring,
|
||||
(Ruff, "003") => Rule::AmbiguousUnicodeCharacterComment,
|
||||
(Ruff, "005") => Rule::UnpackInsteadOfConcatenatingToCollectionLiteral,
|
||||
(Ruff, "005") => Rule::CollectionLiteralConcatenation,
|
||||
(Ruff, "006") => Rule::AsyncioDanglingTask,
|
||||
(Ruff, "007") => Rule::PairwiseOverZipped,
|
||||
(Ruff, "100") => Rule::UnusedNOQA,
|
||||
|
||||
// flake8-django
|
||||
(Flake8Django, "001") => Rule::NullableModelStringField,
|
||||
(Flake8Django, "003") => Rule::LocalsInRenderFunction,
|
||||
(Flake8Django, "006") => Rule::ExcludeWithModelForm,
|
||||
(Flake8Django, "007") => Rule::AllWithModelForm,
|
||||
(Flake8Django, "008") => Rule::ModelWithoutDunderStr,
|
||||
(Flake8Django, "013") => Rule::NonLeadingReceiverDecorator,
|
||||
(Flake8Django, "001") => Rule::DjangoNullableModelStringField,
|
||||
(Flake8Django, "003") => Rule::DjangoLocalsInRenderFunction,
|
||||
(Flake8Django, "006") => Rule::DjangoExcludeWithModelForm,
|
||||
(Flake8Django, "007") => Rule::DjangoAllWithModelForm,
|
||||
(Flake8Django, "008") => Rule::DjangoModelWithoutDunderStr,
|
||||
(Flake8Django, "013") => Rule::DjangoNonLeadingReceiverDecorator,
|
||||
|
||||
_ => return None,
|
||||
})
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use anyhow::{bail, Result};
|
||||
use libcst_native::{
|
||||
Call, Comparison, Expr, Expression, Import, ImportFrom, Module, SmallStatement, Statement,
|
||||
Attribute, Call, Comparison, Dict, Expr, Expression, Import, ImportFrom, Module, SimpleString,
|
||||
SmallStatement, Statement,
|
||||
};
|
||||
|
||||
pub fn match_module(module_text: &str) -> Result<Module> {
|
||||
@@ -70,3 +71,31 @@ pub fn match_comparison<'a, 'b>(
|
||||
bail!("Expected Expression::Comparison")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn match_dict<'a, 'b>(expression: &'a mut Expression<'b>) -> Result<&'a mut Dict<'b>> {
|
||||
if let Expression::Dict(dict) = expression {
|
||||
Ok(dict)
|
||||
} else {
|
||||
bail!("Expected Expression::Dict")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn match_attribute<'a, 'b>(
|
||||
expression: &'a mut Expression<'b>,
|
||||
) -> Result<&'a mut Attribute<'b>> {
|
||||
if let Expression::Attribute(attribute) = expression {
|
||||
Ok(attribute)
|
||||
} else {
|
||||
bail!("Expected Expression::Attribute")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn match_simple_string<'a, 'b>(
|
||||
expression: &'a mut Expression<'b>,
|
||||
) -> Result<&'a mut SimpleString<'b>> {
|
||||
if let Expression::SimpleString(simple_string) = expression {
|
||||
Ok(simple_string)
|
||||
} else {
|
||||
bail!("Expected Expression::SimpleString")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,15 +107,21 @@ pub fn extract_isort_directives(lxr: &[LexResult]) -> IsortDirectives {
|
||||
// omit a space after the colon. The remaining action comments are
|
||||
// required to include the space, and must appear on their own lines.
|
||||
let comment_text = comment_text.trim_end();
|
||||
if comment_text == "# isort: split" {
|
||||
if matches!(comment_text, "# isort: split" | "# ruff: isort: split") {
|
||||
splits.push(start.row());
|
||||
} else if comment_text == "# isort: skip_file" || comment_text == "# isort:skip_file" {
|
||||
} else if matches!(
|
||||
comment_text,
|
||||
"# isort: skip_file"
|
||||
| "# isort:skip_file"
|
||||
| "# ruff: isort: skip_file"
|
||||
| "# ruff: isort:skip_file"
|
||||
) {
|
||||
return IsortDirectives {
|
||||
skip_file: true,
|
||||
..IsortDirectives::default()
|
||||
};
|
||||
} else if off.is_some() {
|
||||
if comment_text == "# isort: on" {
|
||||
if comment_text == "# isort: on" || comment_text == "# ruff: isort: on" {
|
||||
if let Some(start) = off {
|
||||
for row in start.row() + 1..=end.row() {
|
||||
exclusions.insert(row);
|
||||
@@ -126,7 +132,7 @@ pub fn extract_isort_directives(lxr: &[LexResult]) -> IsortDirectives {
|
||||
} else {
|
||||
if comment_text.contains("isort: skip") || comment_text.contains("isort:skip") {
|
||||
exclusions.insert(start.row());
|
||||
} else if comment_text == "# isort: off" {
|
||||
} else if comment_text == "# isort: off" || comment_text == "# ruff: isort: off" {
|
||||
off = Some(start);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,15 +2,18 @@
|
||||
|
||||
use rustpython_parser::ast::{Constant, Expr, ExprKind, Stmt, StmtKind};
|
||||
|
||||
use crate::docstrings::definition::{Definition, DefinitionKind, Documentable};
|
||||
use ruff_python_ast::visibility::{Modifier, VisibleScope};
|
||||
|
||||
use crate::docstrings::definition::{Definition, DefinitionKind, Documentable};
|
||||
|
||||
/// Extract a docstring from a function or class body.
|
||||
pub fn docstring_from(suite: &[Stmt]) -> Option<&Expr> {
|
||||
let stmt = suite.first()?;
|
||||
// Require the docstring to be a standalone expression.
|
||||
let StmtKind::Expr { value } = &stmt.node else {
|
||||
return None;
|
||||
};
|
||||
// Only match strings.
|
||||
if !matches!(
|
||||
&value.node,
|
||||
ExprKind::Constant {
|
||||
|
||||
@@ -4,9 +4,8 @@ use anyhow::{anyhow, Result};
|
||||
use globset::GlobMatcher;
|
||||
use log::debug;
|
||||
use path_absolutize::{path_dedot, Absolutize};
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use crate::registry::Rule;
|
||||
use crate::registry::RuleSet;
|
||||
|
||||
/// Extract the absolute path and basename (as strings) from a Path.
|
||||
pub fn extract_path_names(path: &Path) -> Result<(&str, &str)> {
|
||||
@@ -22,33 +21,34 @@ pub fn extract_path_names(path: &Path) -> Result<(&str, &str)> {
|
||||
}
|
||||
|
||||
/// Create a set with codes matching the pattern/code pairs.
|
||||
pub(crate) fn ignores_from_path<'a>(
|
||||
pub(crate) fn ignores_from_path(
|
||||
path: &Path,
|
||||
pattern_code_pairs: &'a [(GlobMatcher, GlobMatcher, FxHashSet<Rule>)],
|
||||
) -> FxHashSet<&'a Rule> {
|
||||
pattern_code_pairs: &[(GlobMatcher, GlobMatcher, RuleSet)],
|
||||
) -> RuleSet {
|
||||
let (file_path, file_basename) = extract_path_names(path).expect("Unable to parse filename");
|
||||
|
||||
pattern_code_pairs
|
||||
.iter()
|
||||
.filter_map(|(absolute, basename, codes)| {
|
||||
.filter_map(|(absolute, basename, rules)| {
|
||||
if basename.is_match(file_basename) {
|
||||
debug!(
|
||||
"Adding per-file ignores for {:?} due to basename match on {:?}: {:?}",
|
||||
path,
|
||||
basename.glob().regex(),
|
||||
codes
|
||||
rules
|
||||
);
|
||||
return Some(codes.iter());
|
||||
}
|
||||
if absolute.is_match(file_path) {
|
||||
Some(rules)
|
||||
} else if absolute.is_match(file_path) {
|
||||
debug!(
|
||||
"Adding per-file ignores for {:?} due to absolute match on {:?}: {:?}",
|
||||
path,
|
||||
absolute.glob().regex(),
|
||||
codes
|
||||
rules
|
||||
);
|
||||
return Some(codes.iter());
|
||||
Some(rules)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
None
|
||||
})
|
||||
.flatten()
|
||||
.collect()
|
||||
|
||||
7
crates/ruff/src/jupyter/mod.rs
Normal file
7
crates/ruff/src/jupyter/mod.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
//! Utils for reading and writing jupyter notebooks
|
||||
|
||||
mod notebook;
|
||||
mod schema;
|
||||
|
||||
pub use notebook::*;
|
||||
pub use schema::*;
|
||||
283
crates/ruff/src/jupyter/notebook.rs
Normal file
283
crates/ruff/src/jupyter/notebook.rs
Normal file
@@ -0,0 +1,283 @@
|
||||
use std::fs::File;
|
||||
use std::io::{BufReader, BufWriter};
|
||||
use std::iter;
|
||||
use std::path::Path;
|
||||
|
||||
use serde::Serialize;
|
||||
use serde_json::error::Category;
|
||||
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
use ruff_python_ast::types::Range;
|
||||
|
||||
use crate::jupyter::{CellType, JupyterNotebook, SourceValue};
|
||||
use crate::rules::pycodestyle::rules::SyntaxError;
|
||||
use crate::IOError;
|
||||
|
||||
pub const JUPYTER_NOTEBOOK_EXT: &str = "ipynb";
|
||||
|
||||
/// Jupyter Notebook indexing table
|
||||
///
|
||||
/// When we lint a jupyter notebook, we have to translate the row/column based on
|
||||
/// [`crate::message::Location`]
|
||||
/// to jupyter notebook cell/row/column.
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct JupyterIndex {
|
||||
/// Enter a row (1-based), get back the cell (1-based)
|
||||
pub row_to_cell: Vec<u32>,
|
||||
/// Enter a row (1-based), get back the cell (1-based)
|
||||
pub row_to_row_in_cell: Vec<u32>,
|
||||
}
|
||||
|
||||
/// Return `true` if the [`Path`] appears to be that of a jupyter notebook file (`.ipynb`).
|
||||
pub fn is_jupyter_notebook(path: &Path) -> bool {
|
||||
path.extension()
|
||||
.map_or(false, |ext| ext == JUPYTER_NOTEBOOK_EXT)
|
||||
// For now this is feature gated here, the long term solution depends on
|
||||
// https://github.com/charliermarsh/ruff/issues/3410
|
||||
&& cfg!(feature = "jupyter_notebook")
|
||||
}
|
||||
|
||||
impl JupyterNotebook {
|
||||
/// See also the black implementation
|
||||
/// <https://github.com/psf/black/blob/69ca0a4c7a365c5f5eea519a90980bab72cab764/src/black/__init__.py#L1017-L1046>
|
||||
pub fn read(path: &Path) -> Result<Self, Box<Diagnostic>> {
|
||||
let reader = BufReader::new(File::open(path).map_err(|err| {
|
||||
Diagnostic::new(
|
||||
IOError {
|
||||
message: format!("{err}"),
|
||||
},
|
||||
Range::default(),
|
||||
)
|
||||
})?);
|
||||
let notebook: JupyterNotebook = match serde_json::from_reader(reader) {
|
||||
Ok(notebook) => notebook,
|
||||
Err(err) => {
|
||||
// Translate the error into a diagnostic
|
||||
return Err(Box::new({
|
||||
match err.classify() {
|
||||
Category::Io => Diagnostic::new(
|
||||
IOError {
|
||||
message: format!("{err}"),
|
||||
},
|
||||
Range::default(),
|
||||
),
|
||||
Category::Syntax | Category::Eof => {
|
||||
// Maybe someone saved the python sources (those with the `# %%` separator)
|
||||
// as jupyter notebook instead. Let's help them.
|
||||
let contents = std::fs::read_to_string(path).map_err(|err| {
|
||||
Diagnostic::new(
|
||||
IOError {
|
||||
message: format!("{err}"),
|
||||
},
|
||||
Range::default(),
|
||||
)
|
||||
})?;
|
||||
// Check if tokenizing was successful and the file is non-empty
|
||||
if (ruff_rustpython::tokenize(&contents))
|
||||
.last()
|
||||
.map_or(true, Result::is_err)
|
||||
{
|
||||
Diagnostic::new(
|
||||
SyntaxError {
|
||||
message: format!(
|
||||
"A Jupyter Notebook (.{JUPYTER_NOTEBOOK_EXT}) must internally be JSON, \
|
||||
but this file isn't valid JSON: {err}"
|
||||
),
|
||||
},
|
||||
Range::default(),
|
||||
)
|
||||
} else {
|
||||
Diagnostic::new(
|
||||
SyntaxError {
|
||||
message: format!(
|
||||
"Expected a Jupyter Notebook (.{JUPYTER_NOTEBOOK_EXT} extension), \
|
||||
which must be internally stored as JSON, \
|
||||
but found a Python source file: {err}"
|
||||
),
|
||||
},
|
||||
Range::default(),
|
||||
)
|
||||
}
|
||||
}
|
||||
Category::Data => {
|
||||
// We could try to read the schema version here but if this fails it's
|
||||
// a bug anyway
|
||||
Diagnostic::new(
|
||||
SyntaxError {
|
||||
message: format!(
|
||||
"This file does not match the schema expected of Jupyter Notebooks: {err}"
|
||||
),
|
||||
},
|
||||
Range::default(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
// v4 is what everybody uses
|
||||
if notebook.nbformat != 4 {
|
||||
// bail because we should have already failed at the json schema stage
|
||||
return Err(Box::new(Diagnostic::new(
|
||||
SyntaxError {
|
||||
message: format!(
|
||||
"Expected Jupyter Notebook format 4, found {}",
|
||||
notebook.nbformat
|
||||
),
|
||||
},
|
||||
Range::default(),
|
||||
)));
|
||||
}
|
||||
|
||||
Ok(notebook)
|
||||
}
|
||||
|
||||
/// Concatenates all cells into a single virtual file and builds an index that maps the content
|
||||
/// to notebook cell locations
|
||||
pub fn index(&self) -> (String, JupyterIndex) {
|
||||
let mut jupyter_index = JupyterIndex {
|
||||
// Enter a line number (1-based), get back the cell (1-based)
|
||||
// 0 index is just padding
|
||||
row_to_cell: vec![0],
|
||||
// Enter a line number (1-based), get back the row number in the cell (1-based)
|
||||
// 0 index is just padding
|
||||
row_to_row_in_cell: vec![0],
|
||||
};
|
||||
let size_hint = self
|
||||
.cells
|
||||
.iter()
|
||||
.filter(|cell| cell.cell_type == CellType::Code)
|
||||
.count();
|
||||
|
||||
let mut contents = Vec::with_capacity(size_hint);
|
||||
|
||||
for (pos, cell) in self
|
||||
.cells
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(_pos, cell)| cell.cell_type == CellType::Code)
|
||||
{
|
||||
let cell_contents = match &cell.source {
|
||||
SourceValue::String(string) => {
|
||||
// TODO(konstin): is or isn't there a trailing newline per cell?
|
||||
// i've only seen these as array and never as string
|
||||
let line_count = u32::try_from(string.lines().count()).unwrap();
|
||||
jupyter_index.row_to_cell.extend(
|
||||
iter::repeat(u32::try_from(pos + 1).unwrap()).take(line_count as usize),
|
||||
);
|
||||
jupyter_index.row_to_row_in_cell.extend(1..=line_count);
|
||||
string.clone()
|
||||
}
|
||||
SourceValue::StringArray(string_array) => {
|
||||
jupyter_index.row_to_cell.extend(
|
||||
iter::repeat(u32::try_from(pos + 1).unwrap()).take(string_array.len()),
|
||||
);
|
||||
jupyter_index
|
||||
.row_to_row_in_cell
|
||||
.extend(1..=u32::try_from(string_array.len()).unwrap());
|
||||
// lines already end in a newline character
|
||||
string_array.join("")
|
||||
}
|
||||
};
|
||||
contents.push(cell_contents);
|
||||
}
|
||||
// The last line doesn't end in a newline character
|
||||
(contents.join("\n"), jupyter_index)
|
||||
}
|
||||
|
||||
/// Write back with an indent of 1, just like black
|
||||
pub fn write(&self, path: &Path) -> anyhow::Result<()> {
|
||||
let mut writer = BufWriter::new(File::create(path)?);
|
||||
// https://github.com/psf/black/blob/69ca0a4c7a365c5f5eea519a90980bab72cab764/src/black/__init__.py#LL1041
|
||||
let formatter = serde_json::ser::PrettyFormatter::with_indent(b" ");
|
||||
let mut ser = serde_json::Serializer::with_formatter(&mut writer, formatter);
|
||||
self.serialize(&mut ser)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::path::Path;
|
||||
|
||||
#[cfg(feature = "jupyter_notebook")]
|
||||
use crate::jupyter::is_jupyter_notebook;
|
||||
use crate::jupyter::{JupyterIndex, JupyterNotebook};
|
||||
|
||||
#[test]
|
||||
fn test_valid() {
|
||||
let path = Path::new("resources/test/fixtures/jupyter/valid.ipynb");
|
||||
assert!(JupyterNotebook::read(path).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_r() {
|
||||
// We can load this, it will be filtered out later
|
||||
let path = Path::new("resources/test/fixtures/jupyter/R.ipynb");
|
||||
assert!(JupyterNotebook::read(path).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid() {
|
||||
let path = Path::new("resources/test/fixtures/jupyter/invalid_extension.ipynb");
|
||||
assert_eq!(
|
||||
JupyterNotebook::read(path).unwrap_err().kind.body,
|
||||
"SyntaxError: Expected a Jupyter Notebook (.ipynb extension), \
|
||||
which must be internally stored as JSON, \
|
||||
but found a Python source file: \
|
||||
expected value at line 1 column 1"
|
||||
);
|
||||
let path = Path::new("resources/test/fixtures/jupyter/not_json.ipynb");
|
||||
assert_eq!(
|
||||
JupyterNotebook::read(path).unwrap_err().kind.body,
|
||||
"SyntaxError: A Jupyter Notebook (.ipynb) must internally be JSON, \
|
||||
but this file isn't valid JSON: \
|
||||
expected value at line 1 column 1"
|
||||
);
|
||||
let path = Path::new("resources/test/fixtures/jupyter/wrong_schema.ipynb");
|
||||
assert_eq!(
|
||||
JupyterNotebook::read(path).unwrap_err().kind.body,
|
||||
"SyntaxError: This file does not match the schema expected of Jupyter Notebooks: \
|
||||
missing field `cells` at line 1 column 2"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "jupyter_notebook")]
|
||||
fn inclusions() {
|
||||
let path = Path::new("foo/bar/baz");
|
||||
assert!(!is_jupyter_notebook(path));
|
||||
|
||||
let path = Path::new("foo/bar/baz.ipynb");
|
||||
assert!(is_jupyter_notebook(path));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_concat_notebook() {
|
||||
let path = Path::new("resources/test/fixtures/jupyter/valid.ipynb");
|
||||
let notebook = JupyterNotebook::read(path).unwrap();
|
||||
let (contents, index) = notebook.index();
|
||||
assert_eq!(
|
||||
contents,
|
||||
r#"def unused_variable():
|
||||
x = 1
|
||||
y = 2
|
||||
print(f"cell one: {y}")
|
||||
|
||||
unused_variable()
|
||||
def mutable_argument(z=set()):
|
||||
print(f"cell two: {z}")
|
||||
|
||||
mutable_argument()
|
||||
"#
|
||||
);
|
||||
assert_eq!(
|
||||
index,
|
||||
JupyterIndex {
|
||||
row_to_cell: vec![0, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3],
|
||||
row_to_row_in_cell: vec![0, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4],
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
256
crates/ruff/src/jupyter/schema.rs
Normal file
256
crates/ruff/src/jupyter/schema.rs
Normal file
@@ -0,0 +1,256 @@
|
||||
//! The JSON schema of a Jupyter Notebook, entrypoint is [`JupyterNotebook`]
|
||||
//!
|
||||
//! Generated by <https://app.quicktype.io/> from
|
||||
//! <https://github.com/jupyter/nbformat/blob/16b53251aabf472ad9406ddb1f78b0421c014eeb/nbformat/v4/nbformat.v4.schema.json>
|
||||
//! Jupyter Notebook v4.5 JSON schema.
|
||||
//!
|
||||
//! The following changes were made to the generated version: `Cell::id` is optional because it
|
||||
//! wasn't required <v4.5, `#[serde(deny_unknown_fields)]` was added where the schema had
|
||||
//! `"additionalProperties": false` and `#[serde(flatten)] pub other: BTreeMap<String, Value>`
|
||||
//! for `"additionalProperties": true` as preparation for round-trip support.
|
||||
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
/// The root of the JSON of a Jupyter Notebook
|
||||
///
|
||||
/// Generated by <https://app.quicktype.io/> from
|
||||
/// <https://github.com/jupyter/nbformat/blob/16b53251aabf472ad9406ddb1f78b0421c014eeb/nbformat/v4/nbformat.v4.schema.json>
|
||||
/// Jupyter Notebook v4.5 JSON schema.
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct JupyterNotebook {
|
||||
/// Array of cells of the current notebook.
|
||||
pub cells: Vec<Cell>,
|
||||
/// Notebook root-level metadata.
|
||||
pub metadata: JupyterNotebookMetadata,
|
||||
/// Notebook format (major number). Incremented between backwards incompatible changes to the
|
||||
/// notebook format.
|
||||
pub nbformat: i64,
|
||||
/// Notebook format (minor number). Incremented for backward compatible changes to the
|
||||
/// notebook format.
|
||||
pub nbformat_minor: i64,
|
||||
}
|
||||
|
||||
/// Notebook raw nbconvert cell.
|
||||
///
|
||||
/// Notebook markdown cell.
|
||||
///
|
||||
/// Notebook code cell.
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Cell {
|
||||
pub attachments: Option<HashMap<String, HashMap<String, SourceValue>>>,
|
||||
/// String identifying the type of cell.
|
||||
pub cell_type: CellType,
|
||||
/// Technically, id isn't required (it's not even present) in schema v4.0 through v4.4, but
|
||||
/// it's required in v4.5. Main issue is that pycharm creates notebooks without an id
|
||||
/// <https://youtrack.jetbrains.com/issue/PY-59438/Jupyter-notebooks-created-with-PyCharm-are-missing-the-id-field-in-cells-in-the-.ipynb-json>
|
||||
pub id: Option<String>,
|
||||
/// Cell-level metadata.
|
||||
pub metadata: CellMetadata,
|
||||
pub source: SourceValue,
|
||||
/// The code cell's prompt number. Will be null if the cell has not been run.
|
||||
pub execution_count: Option<i64>,
|
||||
/// Execution, display, or stream outputs.
|
||||
pub outputs: Option<Vec<Output>>,
|
||||
}
|
||||
|
||||
/// Cell-level metadata.
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct CellMetadata {
|
||||
/// Raw cell metadata format for nbconvert.
|
||||
pub format: Option<String>,
|
||||
/// Official Jupyter Metadata for Raw Cells
|
||||
///
|
||||
/// Official Jupyter Metadata for Markdown Cells
|
||||
///
|
||||
/// Official Jupyter Metadata for Code Cells
|
||||
pub jupyter: Option<HashMap<String, Option<Value>>>,
|
||||
pub name: Option<String>,
|
||||
pub tags: Option<Vec<String>>,
|
||||
/// Whether the cell's output is collapsed/expanded.
|
||||
pub collapsed: Option<bool>,
|
||||
/// Execution time for the code in the cell. This tracks time at which messages are received
|
||||
/// from iopub or shell channels
|
||||
pub execution: Option<Execution>,
|
||||
/// Whether the cell's output is scrolled, unscrolled, or autoscrolled.
|
||||
pub scrolled: Option<ScrolledUnion>,
|
||||
/// Custom added: round-trip support
|
||||
#[serde(flatten)]
|
||||
pub other: BTreeMap<String, Value>,
|
||||
}
|
||||
|
||||
/// Execution time for the code in the cell. This tracks time at which messages are received
|
||||
/// from iopub or shell channels
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Execution {
|
||||
/// header.date (in ISO 8601 format) of iopub channel's execute_input message. It indicates
|
||||
/// the time at which the kernel broadcasts an execute_input message to connected frontends
|
||||
#[serde(rename = "iopub.execute_input")]
|
||||
pub iopub_execute_input: Option<String>,
|
||||
/// header.date (in ISO 8601 format) of iopub channel's kernel status message when the status
|
||||
/// is 'busy'
|
||||
#[serde(rename = "iopub.status.busy")]
|
||||
pub iopub_status_busy: Option<String>,
|
||||
/// header.date (in ISO 8601 format) of iopub channel's kernel status message when the status
|
||||
/// is 'idle'. It indicates the time at which kernel finished processing the associated
|
||||
/// request
|
||||
#[serde(rename = "iopub.status.idle")]
|
||||
pub iopub_status_idle: Option<String>,
|
||||
/// header.date (in ISO 8601 format) of the shell channel's execute_reply message. It
|
||||
/// indicates the time at which the execute_reply message was created
|
||||
#[serde(rename = "shell.execute_reply")]
|
||||
pub shell_execute_reply: Option<String>,
|
||||
}
|
||||
|
||||
/// Result of executing a code cell.
|
||||
///
|
||||
/// Data displayed as a result of code cell execution.
|
||||
///
|
||||
/// Stream output from a code cell.
|
||||
///
|
||||
/// Output of an error that occurred during code cell execution.
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Output {
|
||||
pub data: Option<HashMap<String, SourceValue>>,
|
||||
/// A result's prompt number.
|
||||
pub execution_count: Option<i64>,
|
||||
pub metadata: Option<HashMap<String, Option<Value>>>,
|
||||
/// Type of cell output.
|
||||
pub output_type: OutputType,
|
||||
/// The name of the stream (stdout, stderr).
|
||||
pub name: Option<String>,
|
||||
/// The stream's text output, represented as an array of strings.
|
||||
pub text: Option<TextUnion>,
|
||||
/// The name of the error.
|
||||
pub ename: Option<String>,
|
||||
/// The value, or message, of the error.
|
||||
pub evalue: Option<String>,
|
||||
/// The error's traceback, represented as an array of strings.
|
||||
pub traceback: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
/// Notebook root-level metadata.
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct JupyterNotebookMetadata {
|
||||
/// The author(s) of the notebook document
|
||||
pub authors: Option<Vec<Option<Value>>>,
|
||||
/// Kernel information.
|
||||
pub kernelspec: Option<Kernelspec>,
|
||||
/// Kernel information.
|
||||
pub language_info: Option<LanguageInfo>,
|
||||
/// Original notebook format (major number) before converting the notebook between versions.
|
||||
/// This should never be written to a file.
|
||||
pub orig_nbformat: Option<i64>,
|
||||
/// The title of the notebook document
|
||||
pub title: Option<String>,
|
||||
/// Custom added: round-trip support
|
||||
#[serde(flatten)]
|
||||
pub other: BTreeMap<String, Value>,
|
||||
}
|
||||
|
||||
/// Kernel information.
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Kernelspec {
|
||||
/// Name to display in UI.
|
||||
pub display_name: String,
|
||||
/// Name of the kernel specification.
|
||||
pub name: String,
|
||||
/// Custom added: round-trip support
|
||||
#[serde(flatten)]
|
||||
pub other: BTreeMap<String, Value>,
|
||||
}
|
||||
|
||||
/// Kernel information.
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct LanguageInfo {
|
||||
/// The codemirror mode to use for code in this language.
|
||||
pub codemirror_mode: Option<CodemirrorMode>,
|
||||
/// The file extension for files in this language.
|
||||
pub file_extension: Option<String>,
|
||||
/// The mimetype corresponding to files in this language.
|
||||
pub mimetype: Option<String>,
|
||||
/// The programming language which this kernel runs.
|
||||
pub name: String,
|
||||
/// The pygments lexer to use for code in this language.
|
||||
pub pygments_lexer: Option<String>,
|
||||
/// Custom added: round-trip support
|
||||
#[serde(flatten)]
|
||||
pub other: BTreeMap<String, Value>,
|
||||
}
|
||||
|
||||
/// mimetype output (e.g. text/plain), represented as either an array of strings or a
|
||||
/// string.
|
||||
///
|
||||
/// Contents of the cell, represented as an array of lines.
|
||||
///
|
||||
/// The stream's text output, represented as an array of strings.
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum SourceValue {
|
||||
String(String),
|
||||
StringArray(Vec<String>),
|
||||
}
|
||||
|
||||
/// Whether the cell's output is scrolled, unscrolled, or autoscrolled.
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum ScrolledUnion {
|
||||
Bool(bool),
|
||||
Enum(ScrolledEnum),
|
||||
}
|
||||
|
||||
/// mimetype output (e.g. text/plain), represented as either an array of strings or a
|
||||
/// string.
|
||||
///
|
||||
/// Contents of the cell, represented as an array of lines.
|
||||
///
|
||||
/// The stream's text output, represented as an array of strings.
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum TextUnion {
|
||||
String(String),
|
||||
StringArray(Vec<String>),
|
||||
}
|
||||
|
||||
/// The codemirror mode to use for code in this language.
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum CodemirrorMode {
|
||||
AnythingMap(HashMap<String, Option<Value>>),
|
||||
String(String),
|
||||
}
|
||||
|
||||
/// String identifying the type of cell.
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub enum CellType {
|
||||
#[serde(rename = "code")]
|
||||
Code,
|
||||
#[serde(rename = "markdown")]
|
||||
Markdown,
|
||||
#[serde(rename = "raw")]
|
||||
Raw,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum ScrolledEnum {
|
||||
#[serde(rename = "auto")]
|
||||
Auto,
|
||||
}
|
||||
|
||||
/// Type of cell output.
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum OutputType {
|
||||
#[serde(rename = "display_data")]
|
||||
DisplayData,
|
||||
#[serde(rename = "error")]
|
||||
Error,
|
||||
#[serde(rename = "execute_result")]
|
||||
ExecuteResult,
|
||||
#[serde(rename = "stream")]
|
||||
Stream,
|
||||
}
|
||||
@@ -20,6 +20,7 @@ mod docstrings;
|
||||
pub mod fix;
|
||||
pub mod flake8_to_ruff;
|
||||
pub mod fs;
|
||||
pub mod jupyter;
|
||||
mod lex;
|
||||
pub mod linter;
|
||||
pub mod logging;
|
||||
|
||||
@@ -50,7 +50,7 @@ impl<T> LinterResult<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub type FixTable = FxHashMap<&'static Rule, usize>;
|
||||
pub type FixTable = FxHashMap<Rule, usize>;
|
||||
|
||||
/// Generate `Diagnostic`s from the source code contents at the
|
||||
/// given `Path`.
|
||||
@@ -74,7 +74,7 @@ pub fn check_path(
|
||||
|
||||
// Collect doc lines. This requires a rare mix of tokens (for comments) and AST
|
||||
// (for docstrings), which demands special-casing at this level.
|
||||
let use_doc_lines = settings.rules.enabled(&Rule::DocLineTooLong);
|
||||
let use_doc_lines = settings.rules.enabled(Rule::DocLineTooLong);
|
||||
let mut doc_lines = vec![];
|
||||
if use_doc_lines {
|
||||
doc_lines.extend(doc_lines_from_tokens(&tokens));
|
||||
@@ -159,14 +159,14 @@ pub fn check_path(
|
||||
}
|
||||
}
|
||||
Err(parse_error) => {
|
||||
if settings.rules.enabled(&Rule::SyntaxError) {
|
||||
if settings.rules.enabled(Rule::SyntaxError) {
|
||||
pycodestyle::rules::syntax_error(&mut diagnostics, &parse_error);
|
||||
}
|
||||
|
||||
// If the syntax error is ignored, suppress it (regardless of whether
|
||||
// `Rule::SyntaxError` is enabled).
|
||||
if !rule_is_ignored(
|
||||
&Rule::SyntaxError,
|
||||
Rule::SyntaxError,
|
||||
parse_error.location.row(),
|
||||
&directives.noqa_line_for,
|
||||
locator,
|
||||
|
||||
@@ -1,8 +1,31 @@
|
||||
use std::sync::Mutex;
|
||||
|
||||
use anyhow::Result;
|
||||
use colored::Colorize;
|
||||
use fern;
|
||||
use log::Level;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
pub(crate) static WARNINGS: Lazy<Mutex<Vec<&'static str>>> = Lazy::new(Mutex::default);
|
||||
|
||||
/// Warn a user once, with uniqueness determined by the given ID.
|
||||
#[macro_export]
|
||||
macro_rules! warn_user_once_by_id {
|
||||
($id:expr, $($arg:tt)*) => {
|
||||
use colored::Colorize;
|
||||
use log::warn;
|
||||
|
||||
if let Ok(mut states) = $crate::logging::WARNINGS.lock() {
|
||||
if !states.contains(&$id) {
|
||||
let message = format!("{}", format_args!($($arg)*));
|
||||
warn!("{}", message.bold());
|
||||
states.push($id);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Warn a user once, with uniqueness determined by the calling location itself.
|
||||
#[macro_export]
|
||||
macro_rules! warn_user_once {
|
||||
($($arg:tt)*) => {
|
||||
|
||||
@@ -8,7 +8,7 @@ use log::warn;
|
||||
use nohash_hasher::IntMap;
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use rustc_hash::FxHashMap;
|
||||
use rustpython_parser::ast::Location;
|
||||
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
@@ -17,7 +17,7 @@ use ruff_python_ast::source_code::{LineEnding, Locator};
|
||||
use ruff_python_ast::types::Range;
|
||||
|
||||
use crate::codes::NoqaCode;
|
||||
use crate::registry::{AsRule, Rule};
|
||||
use crate::registry::{AsRule, Rule, RuleSet};
|
||||
use crate::rule_redirects::get_redirect_target;
|
||||
|
||||
static NOQA_LINE_REGEX: Lazy<Regex> = Lazy::new(|| {
|
||||
@@ -121,7 +121,7 @@ pub fn extract_noqa_directive(line: &str) -> Directive {
|
||||
|
||||
/// Returns `true` if the string list of `codes` includes `code` (or an alias
|
||||
/// thereof).
|
||||
pub fn includes(needle: &Rule, haystack: &[&str]) -> bool {
|
||||
pub fn includes(needle: Rule, haystack: &[&str]) -> bool {
|
||||
let needle = needle.noqa_code();
|
||||
haystack
|
||||
.iter()
|
||||
@@ -130,7 +130,7 @@ pub fn includes(needle: &Rule, haystack: &[&str]) -> bool {
|
||||
|
||||
/// Returns `true` if the given [`Rule`] is ignored at the specified `lineno`.
|
||||
pub fn rule_is_ignored(
|
||||
code: &Rule,
|
||||
code: Rule,
|
||||
lineno: usize,
|
||||
noqa_line_for: &IntMap<usize, usize>,
|
||||
locator: &Locator,
|
||||
@@ -174,7 +174,7 @@ fn add_noqa_inner(
|
||||
line_ending: &LineEnding,
|
||||
) -> (usize, String) {
|
||||
// Map of line number to set of (non-ignored) diagnostic codes that are triggered on that line.
|
||||
let mut matches_by_line: FxHashMap<usize, FxHashSet<&Rule>> = FxHashMap::default();
|
||||
let mut matches_by_line: FxHashMap<usize, RuleSet> = FxHashMap::default();
|
||||
|
||||
// Whether the file is exempted from all checks.
|
||||
let mut file_exempted = false;
|
||||
@@ -280,7 +280,7 @@ fn add_noqa_inner(
|
||||
output.push_str(" # noqa: ");
|
||||
|
||||
// Add codes.
|
||||
push_codes(&mut output, rules.iter().map(|r| r.noqa_code()));
|
||||
push_codes(&mut output, rules.iter().map(|rule| rule.noqa_code()));
|
||||
output.push_str(line_ending);
|
||||
count += 1;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
//! Registry of all [`Rule`] implementations.
|
||||
|
||||
mod rule_set;
|
||||
|
||||
use strum_macros::{AsRefStr, EnumIter};
|
||||
|
||||
use ruff_diagnostics::Violation;
|
||||
@@ -7,71 +9,72 @@ use ruff_macros::RuleNamespace;
|
||||
|
||||
use crate::codes::{self, RuleCodePrefix};
|
||||
use crate::rules;
|
||||
pub use rule_set::{RuleSet, RuleSetIterator};
|
||||
|
||||
ruff_macros::register_rules!(
|
||||
// pycodestyle errors
|
||||
rules::pycodestyle::rules::MixedSpacesAndTabs,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::IndentationWithInvalidMultiple,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::NoIndentedBlock,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::UnexpectedIndentation,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::IndentationWithInvalidMultipleComment,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::NoIndentedBlockComment,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::UnexpectedIndentationComment,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::OverIndented,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::WhitespaceAfterOpenBracket,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::WhitespaceBeforeCloseBracket,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::WhitespaceBeforePunctuation,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::MultipleSpacesBeforeOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::MultipleSpacesAfterOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::TabBeforeOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::TabAfterOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::TooFewSpacesBeforeInlineComment,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::NoSpaceAfterInlineComment,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::NoSpaceAfterBlockComment,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::MultipleLeadingHashesForBlockComment,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::MultipleSpacesAfterKeyword,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::MissingWhitespace,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::MissingWhitespaceAfterKeyword,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::MultipleSpacesBeforeKeyword,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::MissingWhitespaceAroundOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::MissingWhitespaceAroundArithmeticOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::MissingWhitespaceAroundBitwiseOrShiftOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::MissingWhitespaceAroundModuloOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::TabAfterKeyword,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::UnexpectedSpacesAroundKeywordParameterEquals,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::MissingWhitespaceAroundParameterEquals,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::WhitespaceBeforeParameters,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
rules::pycodestyle::rules::TabBeforeKeyword,
|
||||
rules::pycodestyle::rules::MultipleImportsOnOneLine,
|
||||
rules::pycodestyle::rules::ModuleImportNotAtTopOfFile,
|
||||
@@ -92,19 +95,19 @@ ruff_macros::register_rules!(
|
||||
rules::pycodestyle::rules::IOError,
|
||||
rules::pycodestyle::rules::SyntaxError,
|
||||
// pycodestyle warnings
|
||||
rules::pycodestyle::rules::IndentationContainsTabs,
|
||||
rules::pycodestyle::rules::TabIndentation,
|
||||
rules::pycodestyle::rules::TrailingWhitespace,
|
||||
rules::pycodestyle::rules::NoNewLineAtEndOfFile,
|
||||
rules::pycodestyle::rules::BlankLineContainsWhitespace,
|
||||
rules::pycodestyle::rules::MissingNewlineAtEndOfFile,
|
||||
rules::pycodestyle::rules::BlankLineWithWhitespace,
|
||||
rules::pycodestyle::rules::DocLineTooLong,
|
||||
rules::pycodestyle::rules::InvalidEscapeSequence,
|
||||
// pyflakes
|
||||
rules::pyflakes::rules::UnusedImport,
|
||||
rules::pyflakes::rules::ImportShadowedByLoopVar,
|
||||
rules::pyflakes::rules::ImportStar,
|
||||
rules::pyflakes::rules::UndefinedLocalWithImportStar,
|
||||
rules::pyflakes::rules::LateFutureImport,
|
||||
rules::pyflakes::rules::ImportStarUsage,
|
||||
rules::pyflakes::rules::ImportStarNotPermitted,
|
||||
rules::pyflakes::rules::UndefinedLocalWithImportStarUsage,
|
||||
rules::pyflakes::rules::UndefinedLocalWithNestedImportStarUsage,
|
||||
rules::pyflakes::rules::FutureFeatureNotDefined,
|
||||
rules::pyflakes::rules::PercentFormatInvalidFormat,
|
||||
rules::pyflakes::rules::PercentFormatExpectedMapping,
|
||||
@@ -124,7 +127,7 @@ ruff_macros::register_rules!(
|
||||
rules::pyflakes::rules::MultiValueRepeatedKeyLiteral,
|
||||
rules::pyflakes::rules::MultiValueRepeatedKeyVariable,
|
||||
rules::pyflakes::rules::ExpressionsInStarAssignment,
|
||||
rules::pyflakes::rules::TwoStarredExpressions,
|
||||
rules::pyflakes::rules::MultipleStarredExpressions,
|
||||
rules::pyflakes::rules::AssertTuple,
|
||||
rules::pyflakes::rules::IsLiteral,
|
||||
rules::pyflakes::rules::InvalidPrintSyntax,
|
||||
@@ -143,6 +146,8 @@ ruff_macros::register_rules!(
|
||||
rules::pyflakes::rules::UnusedAnnotation,
|
||||
rules::pyflakes::rules::RaiseNotImplemented,
|
||||
// pylint
|
||||
rules::pylint::rules::AssertOnStringLiteral,
|
||||
rules::pylint::rules::UselessReturn,
|
||||
rules::pylint::rules::YieldInInit,
|
||||
rules::pylint::rules::InvalidAllObject,
|
||||
rules::pylint::rules::InvalidAllFormat,
|
||||
@@ -150,20 +155,27 @@ ruff_macros::register_rules!(
|
||||
rules::pylint::rules::InvalidEnvvarValue,
|
||||
rules::pylint::rules::BadStringFormatType,
|
||||
rules::pylint::rules::BidirectionalUnicode,
|
||||
rules::pylint::rules::BinaryOpException,
|
||||
rules::pylint::rules::InvalidCharacterBackspace,
|
||||
rules::pylint::rules::InvalidCharacterSub,
|
||||
rules::pylint::rules::InvalidCharacterEsc,
|
||||
rules::pylint::rules::InvalidCharacterNul,
|
||||
rules::pylint::rules::InvalidCharacterZeroWidthSpace,
|
||||
rules::pylint::rules::BadStrStripCall,
|
||||
rules::pylint::rules::CollapsibleElseIf,
|
||||
rules::pylint::rules::ContinueInFinally,
|
||||
rules::pylint::rules::UselessImportAlias,
|
||||
rules::pylint::rules::UnnecessaryDirectLambdaCall,
|
||||
rules::pylint::rules::NonlocalWithoutBinding,
|
||||
rules::pylint::rules::UsedPriorGlobalDeclaration,
|
||||
rules::pylint::rules::UsePriorToGlobalDeclaration,
|
||||
rules::pylint::rules::AwaitOutsideAsync,
|
||||
rules::pylint::rules::PropertyWithParameters,
|
||||
rules::pylint::rules::ReturnInInit,
|
||||
rules::pylint::rules::ConsiderUsingFromImport,
|
||||
rules::pylint::rules::ManualFromImport,
|
||||
rules::pylint::rules::CompareToEmptyString,
|
||||
rules::pylint::rules::ComparisonOfConstant,
|
||||
rules::pylint::rules::ConsiderMergingIsinstance,
|
||||
rules::pylint::rules::ConsiderUsingSysExit,
|
||||
rules::pylint::rules::RepeatedIsinstanceCalls,
|
||||
rules::pylint::rules::SysExitAlias,
|
||||
rules::pylint::rules::MagicValueComparison,
|
||||
rules::pylint::rules::UselessElseOnLoop,
|
||||
rules::pylint::rules::GlobalStatement,
|
||||
@@ -185,8 +197,9 @@ ruff_macros::register_rules!(
|
||||
rules::flake8_bugbear::rules::UnreliableCallableCheck,
|
||||
rules::flake8_bugbear::rules::StripWithMultiCharacters,
|
||||
rules::flake8_bugbear::rules::MutableArgumentDefault,
|
||||
rules::flake8_bugbear::rules::NoExplicitStacklevel,
|
||||
rules::flake8_bugbear::rules::UnusedLoopControlVariable,
|
||||
rules::flake8_bugbear::rules::FunctionCallArgumentDefault,
|
||||
rules::flake8_bugbear::rules::FunctionCallInDefaultArgument,
|
||||
rules::flake8_bugbear::rules::GetAttrWithConstant,
|
||||
rules::flake8_bugbear::rules::SetAttrWithConstant,
|
||||
rules::flake8_bugbear::rules::AssertFalse,
|
||||
@@ -251,8 +264,8 @@ ruff_macros::register_rules!(
|
||||
rules::flake8_implicit_str_concat::rules::MultiLineImplicitStringConcatenation,
|
||||
rules::flake8_implicit_str_concat::rules::ExplicitStringConcatenation,
|
||||
// flake8-print
|
||||
rules::flake8_print::rules::PrintFound,
|
||||
rules::flake8_print::rules::PPrintFound,
|
||||
rules::flake8_print::rules::Print,
|
||||
rules::flake8_print::rules::PPrint,
|
||||
// flake8-quotes
|
||||
rules::flake8_quotes::rules::BadQuotesInlineString,
|
||||
rules::flake8_quotes::rules::BadQuotesMultilineString,
|
||||
@@ -264,38 +277,38 @@ ruff_macros::register_rules!(
|
||||
rules::flake8_annotations::rules::MissingTypeKwargs,
|
||||
rules::flake8_annotations::rules::MissingTypeSelf,
|
||||
rules::flake8_annotations::rules::MissingTypeCls,
|
||||
rules::flake8_annotations::rules::MissingReturnTypePublicFunction,
|
||||
rules::flake8_annotations::rules::MissingReturnTypeUndocumentedPublicFunction,
|
||||
rules::flake8_annotations::rules::MissingReturnTypePrivateFunction,
|
||||
rules::flake8_annotations::rules::MissingReturnTypeSpecialMethod,
|
||||
rules::flake8_annotations::rules::MissingReturnTypeStaticMethod,
|
||||
rules::flake8_annotations::rules::MissingReturnTypeClassMethod,
|
||||
rules::flake8_annotations::rules::AnyType,
|
||||
// flake8-2020
|
||||
rules::flake8_2020::rules::SysVersionSlice3Referenced,
|
||||
rules::flake8_2020::rules::SysVersion2Referenced,
|
||||
rules::flake8_2020::rules::SysVersionSlice3,
|
||||
rules::flake8_2020::rules::SysVersion2,
|
||||
rules::flake8_2020::rules::SysVersionCmpStr3,
|
||||
rules::flake8_2020::rules::SysVersionInfo0Eq3Referenced,
|
||||
rules::flake8_2020::rules::SixPY3Referenced,
|
||||
rules::flake8_2020::rules::SysVersionInfo0Eq3,
|
||||
rules::flake8_2020::rules::SixPY3,
|
||||
rules::flake8_2020::rules::SysVersionInfo1CmpInt,
|
||||
rules::flake8_2020::rules::SysVersionInfoMinorCmpInt,
|
||||
rules::flake8_2020::rules::SysVersion0Referenced,
|
||||
rules::flake8_2020::rules::SysVersion0,
|
||||
rules::flake8_2020::rules::SysVersionCmpStr10,
|
||||
rules::flake8_2020::rules::SysVersionSlice1Referenced,
|
||||
rules::flake8_2020::rules::SysVersionSlice1,
|
||||
// flake8-simplify
|
||||
rules::flake8_simplify::rules::ManualDictLookup,
|
||||
rules::flake8_simplify::rules::IfElseBlockInsteadOfDictLookup,
|
||||
rules::flake8_simplify::rules::DuplicateIsinstanceCall,
|
||||
rules::flake8_simplify::rules::CollapsibleIf,
|
||||
rules::flake8_simplify::rules::NeedlessBool,
|
||||
rules::flake8_simplify::rules::UseContextlibSuppress,
|
||||
rules::flake8_simplify::rules::ReturnInTryExceptFinally,
|
||||
rules::flake8_simplify::rules::UseTernaryOperator,
|
||||
rules::flake8_simplify::rules::IfElseBlockInsteadOfIfExp,
|
||||
rules::flake8_simplify::rules::CompareWithTuple,
|
||||
rules::flake8_simplify::rules::ReimplementedBuiltin,
|
||||
rules::flake8_simplify::rules::UseCapitalEnvironmentVariables,
|
||||
rules::flake8_simplify::rules::UncapitalizedEnvironmentVariables,
|
||||
rules::flake8_simplify::rules::IfWithSameArms,
|
||||
rules::flake8_simplify::rules::OpenFileWithContextHandler,
|
||||
rules::flake8_simplify::rules::MultipleWithStatements,
|
||||
rules::flake8_simplify::rules::KeyInDict,
|
||||
rules::flake8_simplify::rules::InDictKeys,
|
||||
rules::flake8_simplify::rules::NegateEqualOp,
|
||||
rules::flake8_simplify::rules::NegateNotEqualOp,
|
||||
rules::flake8_simplify::rules::DoubleNegation,
|
||||
@@ -307,14 +320,14 @@ ruff_macros::register_rules!(
|
||||
rules::flake8_simplify::rules::ExprOrTrue,
|
||||
rules::flake8_simplify::rules::ExprAndFalse,
|
||||
rules::flake8_simplify::rules::YodaConditions,
|
||||
rules::flake8_simplify::rules::DictGetWithDefault,
|
||||
rules::flake8_simplify::rules::IfElseBlockInsteadOfDictGet,
|
||||
// pyupgrade
|
||||
rules::pyupgrade::rules::UselessMetaclassType,
|
||||
rules::pyupgrade::rules::TypeOfPrimitive,
|
||||
rules::pyupgrade::rules::UselessObjectInheritance,
|
||||
rules::pyupgrade::rules::DeprecatedUnittestAlias,
|
||||
rules::pyupgrade::rules::DeprecatedCollectionType,
|
||||
rules::pyupgrade::rules::TypingUnion,
|
||||
rules::pyupgrade::rules::NonPEP585Annotation,
|
||||
rules::pyupgrade::rules::NonPEP604Annotation,
|
||||
rules::pyupgrade::rules::SuperCallWithParameters,
|
||||
rules::pyupgrade::rules::UTF8EncodingDeclaration,
|
||||
rules::pyupgrade::rules::UnnecessaryFutureImport,
|
||||
@@ -329,31 +342,31 @@ ruff_macros::register_rules!(
|
||||
rules::pyupgrade::rules::OpenAlias,
|
||||
rules::pyupgrade::rules::ReplaceUniversalNewlines,
|
||||
rules::pyupgrade::rules::ReplaceStdoutStderr,
|
||||
rules::pyupgrade::rules::RewriteCElementTree,
|
||||
rules::pyupgrade::rules::DeprecatedCElementTree,
|
||||
rules::pyupgrade::rules::OSErrorAlias,
|
||||
rules::pyupgrade::rules::RewriteUnicodeLiteral,
|
||||
rules::pyupgrade::rules::RewriteMockImport,
|
||||
rules::pyupgrade::rules::RewriteListComprehension,
|
||||
rules::pyupgrade::rules::RewriteYieldFrom,
|
||||
rules::pyupgrade::rules::UnicodeKindPrefix,
|
||||
rules::pyupgrade::rules::DeprecatedMockImport,
|
||||
rules::pyupgrade::rules::UnpackedListComprehension,
|
||||
rules::pyupgrade::rules::YieldInForLoop,
|
||||
rules::pyupgrade::rules::UnnecessaryBuiltinImport,
|
||||
rules::pyupgrade::rules::FormatLiterals,
|
||||
rules::pyupgrade::rules::PrintfStringFormatting,
|
||||
rules::pyupgrade::rules::FString,
|
||||
rules::pyupgrade::rules::FunctoolsCache,
|
||||
rules::pyupgrade::rules::LRUCacheWithMaxsizeNone,
|
||||
rules::pyupgrade::rules::ExtraneousParentheses,
|
||||
rules::pyupgrade::rules::DeprecatedImport,
|
||||
rules::pyupgrade::rules::OutdatedVersionBlock,
|
||||
rules::pyupgrade::rules::QuotedAnnotation,
|
||||
rules::pyupgrade::rules::IsinstanceWithTuple,
|
||||
rules::pyupgrade::rules::NonPEP604Isinstance,
|
||||
// pydocstyle
|
||||
rules::pydocstyle::rules::PublicModule,
|
||||
rules::pydocstyle::rules::PublicClass,
|
||||
rules::pydocstyle::rules::PublicMethod,
|
||||
rules::pydocstyle::rules::PublicFunction,
|
||||
rules::pydocstyle::rules::PublicPackage,
|
||||
rules::pydocstyle::rules::MagicMethod,
|
||||
rules::pydocstyle::rules::PublicNestedClass,
|
||||
rules::pydocstyle::rules::PublicInit,
|
||||
rules::pydocstyle::rules::UndocumentedPublicModule,
|
||||
rules::pydocstyle::rules::UndocumentedPublicClass,
|
||||
rules::pydocstyle::rules::UndocumentedPublicMethod,
|
||||
rules::pydocstyle::rules::UndocumentedPublicFunction,
|
||||
rules::pydocstyle::rules::UndocumentedPublicPackage,
|
||||
rules::pydocstyle::rules::UndocumentedMagicMethod,
|
||||
rules::pydocstyle::rules::UndocumentedPublicNestedClass,
|
||||
rules::pydocstyle::rules::UndocumentedPublicInit,
|
||||
rules::pydocstyle::rules::FitsOnOneLine,
|
||||
rules::pydocstyle::rules::NoBlankLineBeforeFunction,
|
||||
rules::pydocstyle::rules::NoBlankLineAfterFunction,
|
||||
@@ -361,11 +374,11 @@ ruff_macros::register_rules!(
|
||||
rules::pydocstyle::rules::OneBlankLineAfterClass,
|
||||
rules::pydocstyle::rules::BlankLineAfterSummary,
|
||||
rules::pydocstyle::rules::IndentWithSpaces,
|
||||
rules::pydocstyle::rules::NoUnderIndentation,
|
||||
rules::pydocstyle::rules::NoOverIndentation,
|
||||
rules::pydocstyle::rules::UnderIndentation,
|
||||
rules::pydocstyle::rules::OverIndentation,
|
||||
rules::pydocstyle::rules::NewLineAfterLastParagraph,
|
||||
rules::pydocstyle::rules::NoSurroundingWhitespace,
|
||||
rules::pydocstyle::rules::NoBlankLineBeforeClass,
|
||||
rules::pydocstyle::rules::SurroundingWhitespace,
|
||||
rules::pydocstyle::rules::BlankLineBeforeClass,
|
||||
rules::pydocstyle::rules::MultiLineSummaryFirstLine,
|
||||
rules::pydocstyle::rules::MultiLineSummarySecondLine,
|
||||
rules::pydocstyle::rules::SectionNotOverIndented,
|
||||
@@ -382,9 +395,9 @@ ruff_macros::register_rules!(
|
||||
rules::pydocstyle::rules::DashedUnderlineAfterSection,
|
||||
rules::pydocstyle::rules::SectionUnderlineAfterName,
|
||||
rules::pydocstyle::rules::SectionUnderlineMatchesSectionLength,
|
||||
rules::pydocstyle::rules::BlankLineAfterSection,
|
||||
rules::pydocstyle::rules::BlankLineBeforeSection,
|
||||
rules::pydocstyle::rules::NoBlankLinesBetweenHeaderAndContent,
|
||||
rules::pydocstyle::rules::NoBlankLineAfterSection,
|
||||
rules::pydocstyle::rules::NoBlankLineBeforeSection,
|
||||
rules::pydocstyle::rules::BlankLinesBetweenHeaderAndContent,
|
||||
rules::pydocstyle::rules::BlankLineAfterLastSection,
|
||||
rules::pydocstyle::rules::EmptyDocstringSection,
|
||||
rules::pydocstyle::rules::EndsInPunctuation,
|
||||
@@ -416,6 +429,7 @@ ruff_macros::register_rules!(
|
||||
rules::eradicate::rules::CommentedOutCode,
|
||||
// flake8-bandit
|
||||
rules::flake8_bandit::rules::Assert,
|
||||
rules::flake8_bandit::rules::DeniedFunctionCall,
|
||||
rules::flake8_bandit::rules::ExecBuiltin,
|
||||
rules::flake8_bandit::rules::BadFilePermissions,
|
||||
rules::flake8_bandit::rules::HardcodedBindAllInterfaces,
|
||||
@@ -457,85 +471,85 @@ ruff_macros::register_rules!(
|
||||
rules::flake8_datetimez::rules::CallDateToday,
|
||||
rules::flake8_datetimez::rules::CallDateFromtimestamp,
|
||||
// pygrep-hooks
|
||||
rules::pygrep_hooks::rules::NoEval,
|
||||
rules::pygrep_hooks::rules::Eval,
|
||||
rules::pygrep_hooks::rules::DeprecatedLogWarn,
|
||||
rules::pygrep_hooks::rules::BlanketTypeIgnore,
|
||||
rules::pygrep_hooks::rules::BlanketNOQA,
|
||||
// pandas-vet
|
||||
rules::pandas_vet::rules::UseOfInplaceArgument,
|
||||
rules::pandas_vet::rules::UseOfDotIsNull,
|
||||
rules::pandas_vet::rules::UseOfDotNotNull,
|
||||
rules::pandas_vet::rules::UseOfDotIx,
|
||||
rules::pandas_vet::rules::UseOfDotAt,
|
||||
rules::pandas_vet::rules::UseOfDotIat,
|
||||
rules::pandas_vet::rules::UseOfDotPivotOrUnstack,
|
||||
rules::pandas_vet::rules::UseOfDotValues,
|
||||
rules::pandas_vet::rules::UseOfDotReadTable,
|
||||
rules::pandas_vet::rules::UseOfDotStack,
|
||||
rules::pandas_vet::rules::UseOfPdMerge,
|
||||
rules::pandas_vet::rules::DfIsABadVariableName,
|
||||
rules::pandas_vet::rules::PandasUseOfInplaceArgument,
|
||||
rules::pandas_vet::rules::PandasUseOfDotIsNull,
|
||||
rules::pandas_vet::rules::PandasUseOfDotNotNull,
|
||||
rules::pandas_vet::rules::PandasUseOfDotIx,
|
||||
rules::pandas_vet::rules::PandasUseOfDotAt,
|
||||
rules::pandas_vet::rules::PandasUseOfDotIat,
|
||||
rules::pandas_vet::rules::PandasUseOfDotPivotOrUnstack,
|
||||
rules::pandas_vet::rules::PandasUseOfDotValues,
|
||||
rules::pandas_vet::rules::PandasUseOfDotReadTable,
|
||||
rules::pandas_vet::rules::PandasUseOfDotStack,
|
||||
rules::pandas_vet::rules::PandasUseOfPdMerge,
|
||||
rules::pandas_vet::rules::PandasDfVariableName,
|
||||
// flake8-errmsg
|
||||
rules::flake8_errmsg::rules::RawStringInException,
|
||||
rules::flake8_errmsg::rules::FStringInException,
|
||||
rules::flake8_errmsg::rules::DotFormatInException,
|
||||
// flake8-pyi
|
||||
rules::flake8_pyi::rules::PrefixTypeParams,
|
||||
rules::flake8_pyi::rules::UnprefixedTypeParam,
|
||||
rules::flake8_pyi::rules::BadVersionInfoComparison,
|
||||
rules::flake8_pyi::rules::UnrecognizedPlatformCheck,
|
||||
rules::flake8_pyi::rules::UnrecognizedPlatformName,
|
||||
rules::flake8_pyi::rules::PassStatementStubBody,
|
||||
rules::flake8_pyi::rules::NonEmptyStubBody,
|
||||
rules::flake8_pyi::rules::DocstringInStub,
|
||||
rules::flake8_pyi::rules::TypedArgumentSimpleDefaults,
|
||||
rules::flake8_pyi::rules::ArgumentSimpleDefaults,
|
||||
rules::flake8_pyi::rules::TypedArgumentDefaultInStub,
|
||||
rules::flake8_pyi::rules::ArgumentDefaultInStub,
|
||||
rules::flake8_pyi::rules::TypeCommentInStub,
|
||||
// flake8-pytest-style
|
||||
rules::flake8_pytest_style::rules::IncorrectFixtureParenthesesStyle,
|
||||
rules::flake8_pytest_style::rules::FixturePositionalArgs,
|
||||
rules::flake8_pytest_style::rules::ExtraneousScopeFunction,
|
||||
rules::flake8_pytest_style::rules::MissingFixtureNameUnderscore,
|
||||
rules::flake8_pytest_style::rules::IncorrectFixtureNameUnderscore,
|
||||
rules::flake8_pytest_style::rules::ParametrizeNamesWrongType,
|
||||
rules::flake8_pytest_style::rules::ParametrizeValuesWrongType,
|
||||
rules::flake8_pytest_style::rules::PatchWithLambda,
|
||||
rules::flake8_pytest_style::rules::UnittestAssertion,
|
||||
rules::flake8_pytest_style::rules::RaisesWithoutException,
|
||||
rules::flake8_pytest_style::rules::RaisesTooBroad,
|
||||
rules::flake8_pytest_style::rules::RaisesWithMultipleStatements,
|
||||
rules::flake8_pytest_style::rules::IncorrectPytestImport,
|
||||
rules::flake8_pytest_style::rules::AssertAlwaysFalse,
|
||||
rules::flake8_pytest_style::rules::FailWithoutMessage,
|
||||
rules::flake8_pytest_style::rules::AssertInExcept,
|
||||
rules::flake8_pytest_style::rules::CompositeAssertion,
|
||||
rules::flake8_pytest_style::rules::FixtureParamWithoutValue,
|
||||
rules::flake8_pytest_style::rules::DeprecatedYieldFixture,
|
||||
rules::flake8_pytest_style::rules::FixtureFinalizerCallback,
|
||||
rules::flake8_pytest_style::rules::UselessYieldFixture,
|
||||
rules::flake8_pytest_style::rules::IncorrectMarkParenthesesStyle,
|
||||
rules::flake8_pytest_style::rules::UnnecessaryAsyncioMarkOnFixture,
|
||||
rules::flake8_pytest_style::rules::ErroneousUseFixturesOnFixture,
|
||||
rules::flake8_pytest_style::rules::UseFixturesWithoutParameters,
|
||||
rules::flake8_pytest_style::rules::PytestFixtureIncorrectParenthesesStyle,
|
||||
rules::flake8_pytest_style::rules::PytestFixturePositionalArgs,
|
||||
rules::flake8_pytest_style::rules::PytestExtraneousScopeFunction,
|
||||
rules::flake8_pytest_style::rules::PytestMissingFixtureNameUnderscore,
|
||||
rules::flake8_pytest_style::rules::PytestIncorrectFixtureNameUnderscore,
|
||||
rules::flake8_pytest_style::rules::PytestParametrizeNamesWrongType,
|
||||
rules::flake8_pytest_style::rules::PytestParametrizeValuesWrongType,
|
||||
rules::flake8_pytest_style::rules::PytestPatchWithLambda,
|
||||
rules::flake8_pytest_style::rules::PytestUnittestAssertion,
|
||||
rules::flake8_pytest_style::rules::PytestRaisesWithoutException,
|
||||
rules::flake8_pytest_style::rules::PytestRaisesTooBroad,
|
||||
rules::flake8_pytest_style::rules::PytestRaisesWithMultipleStatements,
|
||||
rules::flake8_pytest_style::rules::PytestIncorrectPytestImport,
|
||||
rules::flake8_pytest_style::rules::PytestAssertAlwaysFalse,
|
||||
rules::flake8_pytest_style::rules::PytestFailWithoutMessage,
|
||||
rules::flake8_pytest_style::rules::PytestAssertInExcept,
|
||||
rules::flake8_pytest_style::rules::PytestCompositeAssertion,
|
||||
rules::flake8_pytest_style::rules::PytestFixtureParamWithoutValue,
|
||||
rules::flake8_pytest_style::rules::PytestDeprecatedYieldFixture,
|
||||
rules::flake8_pytest_style::rules::PytestFixtureFinalizerCallback,
|
||||
rules::flake8_pytest_style::rules::PytestUselessYieldFixture,
|
||||
rules::flake8_pytest_style::rules::PytestIncorrectMarkParenthesesStyle,
|
||||
rules::flake8_pytest_style::rules::PytestUnnecessaryAsyncioMarkOnFixture,
|
||||
rules::flake8_pytest_style::rules::PytestErroneousUseFixturesOnFixture,
|
||||
rules::flake8_pytest_style::rules::PytestUseFixturesWithoutParameters,
|
||||
// flake8-pie
|
||||
rules::flake8_pie::rules::UnnecessaryPass,
|
||||
rules::flake8_pie::rules::DupeClassFieldDefinitions,
|
||||
rules::flake8_pie::rules::PreferUniqueEnums,
|
||||
rules::flake8_pie::rules::DuplicateClassFieldDefinition,
|
||||
rules::flake8_pie::rules::NonUniqueEnums,
|
||||
rules::flake8_pie::rules::UnnecessarySpread,
|
||||
rules::flake8_pie::rules::UnnecessaryDictKwargs,
|
||||
rules::flake8_pie::rules::PreferListBuiltin,
|
||||
rules::flake8_pie::rules::SingleStartsEndsWith,
|
||||
rules::flake8_pie::rules::ReimplementedListBuiltin,
|
||||
rules::flake8_pie::rules::MultipleStartsEndsWith,
|
||||
rules::flake8_pie::rules::UnnecessaryComprehensionAnyAll,
|
||||
// flake8-commas
|
||||
rules::flake8_commas::rules::TrailingCommaMissing,
|
||||
rules::flake8_commas::rules::TrailingCommaOnBareTupleProhibited,
|
||||
rules::flake8_commas::rules::TrailingCommaProhibited,
|
||||
rules::flake8_commas::rules::MissingTrailingComma,
|
||||
rules::flake8_commas::rules::TrailingCommaOnBareTuple,
|
||||
rules::flake8_commas::rules::ProhibitedTrailingComma,
|
||||
// flake8-no-pep420
|
||||
rules::flake8_no_pep420::rules::ImplicitNamespacePackage,
|
||||
// flake8-executable
|
||||
rules::flake8_executable::rules::ShebangNotExecutable,
|
||||
rules::flake8_executable::rules::ShebangMissingExecutableFile,
|
||||
rules::flake8_executable::rules::ShebangPython,
|
||||
rules::flake8_executable::rules::ShebangWhitespace,
|
||||
rules::flake8_executable::rules::ShebangNewline,
|
||||
rules::flake8_executable::rules::ShebangMissingPython,
|
||||
rules::flake8_executable::rules::ShebangLeadingWhitespace,
|
||||
rules::flake8_executable::rules::ShebangNotFirstLine,
|
||||
// flake8-type-checking
|
||||
rules::flake8_type_checking::rules::TypingOnlyFirstPartyImport,
|
||||
rules::flake8_type_checking::rules::TypingOnlyThirdPartyImport,
|
||||
@@ -545,7 +559,7 @@ ruff_macros::register_rules!(
|
||||
// tryceratops
|
||||
rules::tryceratops::rules::RaiseVanillaClass,
|
||||
rules::tryceratops::rules::RaiseVanillaArgs,
|
||||
rules::tryceratops::rules::PreferTypeError,
|
||||
rules::tryceratops::rules::TypeCheckWithoutTypeError,
|
||||
rules::tryceratops::rules::ReraiseNoCause,
|
||||
rules::tryceratops::rules::VerboseRaise,
|
||||
rules::tryceratops::rules::TryConsiderElse,
|
||||
@@ -598,18 +612,23 @@ ruff_macros::register_rules!(
|
||||
rules::ruff::rules::AmbiguousUnicodeCharacterString,
|
||||
rules::ruff::rules::AmbiguousUnicodeCharacterDocstring,
|
||||
rules::ruff::rules::AmbiguousUnicodeCharacterComment,
|
||||
rules::ruff::rules::UnpackInsteadOfConcatenatingToCollectionLiteral,
|
||||
rules::ruff::rules::CollectionLiteralConcatenation,
|
||||
rules::ruff::rules::AsyncioDanglingTask,
|
||||
rules::ruff::rules::UnusedNOQA,
|
||||
rules::ruff::rules::PairwiseOverZipped,
|
||||
// flake8-django
|
||||
rules::flake8_django::rules::NullableModelStringField,
|
||||
rules::flake8_django::rules::LocalsInRenderFunction,
|
||||
rules::flake8_django::rules::ExcludeWithModelForm,
|
||||
rules::flake8_django::rules::AllWithModelForm,
|
||||
rules::flake8_django::rules::ModelWithoutDunderStr,
|
||||
rules::flake8_django::rules::NonLeadingReceiverDecorator,
|
||||
rules::flake8_django::rules::DjangoNullableModelStringField,
|
||||
rules::flake8_django::rules::DjangoLocalsInRenderFunction,
|
||||
rules::flake8_django::rules::DjangoExcludeWithModelForm,
|
||||
rules::flake8_django::rules::DjangoAllWithModelForm,
|
||||
rules::flake8_django::rules::DjangoModelWithoutDunderStr,
|
||||
rules::flake8_django::rules::DjangoNonLeadingReceiverDecorator,
|
||||
);
|
||||
|
||||
pub trait AsRule {
|
||||
fn rule(&self) -> Rule;
|
||||
}
|
||||
|
||||
impl Rule {
|
||||
pub fn from_code(code: &str) -> Result<Self, FromCodeError> {
|
||||
let (linter, code) = Linter::parse_code(code).ok_or(FromCodeError::Unknown)?;
|
||||
@@ -828,17 +847,17 @@ impl Rule {
|
||||
| Rule::DocLineTooLong
|
||||
| Rule::LineTooLong
|
||||
| Rule::MixedSpacesAndTabs
|
||||
| Rule::NoNewLineAtEndOfFile
|
||||
| Rule::MissingNewlineAtEndOfFile
|
||||
| Rule::UTF8EncodingDeclaration
|
||||
| Rule::ShebangMissingExecutableFile
|
||||
| Rule::ShebangNotExecutable
|
||||
| Rule::ShebangNewline
|
||||
| Rule::ShebangNotFirstLine
|
||||
| Rule::BidirectionalUnicode
|
||||
| Rule::ShebangPython
|
||||
| Rule::ShebangWhitespace
|
||||
| Rule::ShebangMissingPython
|
||||
| Rule::ShebangLeadingWhitespace
|
||||
| Rule::TrailingWhitespace
|
||||
| Rule::IndentationContainsTabs
|
||||
| Rule::BlankLineContainsWhitespace => LintSource::PhysicalLines,
|
||||
| Rule::TabIndentation
|
||||
| Rule::BlankLineWithWhitespace => LintSource::PhysicalLines,
|
||||
Rule::AmbiguousUnicodeCharacterComment
|
||||
| Rule::AmbiguousUnicodeCharacterDocstring
|
||||
| Rule::AmbiguousUnicodeCharacterString
|
||||
@@ -848,20 +867,25 @@ impl Rule {
|
||||
| Rule::BadQuotesMultilineString
|
||||
| Rule::CommentedOutCode
|
||||
| Rule::MultiLineImplicitStringConcatenation
|
||||
| Rule::InvalidCharacterBackspace
|
||||
| Rule::InvalidCharacterSub
|
||||
| Rule::InvalidCharacterEsc
|
||||
| Rule::InvalidCharacterNul
|
||||
| Rule::InvalidCharacterZeroWidthSpace
|
||||
| Rule::ExtraneousParentheses
|
||||
| Rule::InvalidEscapeSequence
|
||||
| Rule::SingleLineImplicitStringConcatenation
|
||||
| Rule::TrailingCommaMissing
|
||||
| Rule::TrailingCommaOnBareTupleProhibited
|
||||
| Rule::MissingTrailingComma
|
||||
| Rule::TrailingCommaOnBareTuple
|
||||
| Rule::MultipleStatementsOnOneLineColon
|
||||
| Rule::UselessSemicolon
|
||||
| Rule::MultipleStatementsOnOneLineSemicolon
|
||||
| Rule::TrailingCommaProhibited
|
||||
| Rule::ProhibitedTrailingComma
|
||||
| Rule::TypeCommentInStub => LintSource::Tokens,
|
||||
Rule::IOError => LintSource::Io,
|
||||
Rule::UnsortedImports | Rule::MissingRequiredImport => LintSource::Imports,
|
||||
Rule::ImplicitNamespacePackage | Rule::InvalidModuleName => LintSource::Filesystem,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
#[cfg(debug_assertions)]
|
||||
Rule::IndentationWithInvalidMultiple
|
||||
| Rule::IndentationWithInvalidMultipleComment
|
||||
| Rule::MissingWhitespace
|
||||
@@ -901,7 +925,7 @@ impl Rule {
|
||||
/// Pairs of checks that shouldn't be enabled together.
|
||||
pub const INCOMPATIBLE_CODES: &[(Rule, Rule, &str); 2] = &[
|
||||
(
|
||||
Rule::NoBlankLineBeforeClass,
|
||||
Rule::BlankLineBeforeClass,
|
||||
Rule::OneBlankLineBeforeClass,
|
||||
"`one-blank-line-before-class` (D203) and `no-blank-line-before-class` (D211) are \
|
||||
incompatible. Ignoring `one-blank-line-before-class`.",
|
||||
@@ -916,6 +940,7 @@ pub const INCOMPATIBLE_CODES: &[(Rule, Rule, &str); 2] = &[
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::mem::size_of;
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use super::{Linter, Rule, RuleNamespace};
|
||||
@@ -961,4 +986,9 @@ mod tests {
|
||||
assert_eq!(code, format!("{}{rest}", linter.common_prefix()));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rule_size() {
|
||||
assert_eq!(2, size_of::<Rule>());
|
||||
}
|
||||
}
|
||||
|
||||
365
crates/ruff/src/registry/rule_set.rs
Normal file
365
crates/ruff/src/registry/rule_set.rs
Normal file
@@ -0,0 +1,365 @@
|
||||
use crate::registry::Rule;
|
||||
use ruff_macros::CacheKey;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::iter::FusedIterator;
|
||||
|
||||
/// A set of [`Rule`]s.
|
||||
///
|
||||
/// Uses a bitset where a bit of one signals that the Rule with that [u16] is in this set.
|
||||
#[derive(Clone, Default, CacheKey, PartialEq, Eq)]
|
||||
pub struct RuleSet([u64; 9]);
|
||||
|
||||
impl RuleSet {
|
||||
const EMPTY: [u64; 9] = [0; 9];
|
||||
|
||||
// 64 fits into a u16 without truncation
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
const SLICE_BITS: u16 = u64::BITS as u16;
|
||||
|
||||
/// Returns an empty rule set.
|
||||
pub const fn empty() -> Self {
|
||||
Self(Self::EMPTY)
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.0 = Self::EMPTY;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn from_rule(rule: Rule) -> Self {
|
||||
let rule = rule as u16;
|
||||
|
||||
let index = (rule / Self::SLICE_BITS) as usize;
|
||||
|
||||
debug_assert!(
|
||||
index < Self::EMPTY.len(),
|
||||
"Rule index out of bounds. Increase the size of the bitset array."
|
||||
);
|
||||
|
||||
// The bit-position of this specific rule in the slice
|
||||
let shift = rule % Self::SLICE_BITS;
|
||||
// Set the index for that rule to 1
|
||||
let mask = 1 << shift;
|
||||
|
||||
let mut bits = Self::EMPTY;
|
||||
bits[index] = mask;
|
||||
|
||||
Self(bits)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn from_rules(rules: &[Rule]) -> Self {
|
||||
let mut set = RuleSet::empty();
|
||||
|
||||
let mut i = 0;
|
||||
|
||||
// Uses a while because for loops are not allowed in const functions.
|
||||
while i < rules.len() {
|
||||
set = set.union(&RuleSet::from_rule(rules[i]));
|
||||
i += 1;
|
||||
}
|
||||
|
||||
set
|
||||
}
|
||||
|
||||
/// Returns the union of the two rule sets `self` and `other`
|
||||
///
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use ruff::registry::{Rule, RuleSet};
|
||||
/// let set_1 = RuleSet::from_rules(&[Rule::AmbiguousFunctionName, Rule::AnyType]);
|
||||
/// let set_2 = RuleSet::from_rules(&[
|
||||
/// Rule::BadQuotesInlineString,
|
||||
/// Rule::BooleanPositionalValueInFunctionCall,
|
||||
/// ]);
|
||||
///
|
||||
/// let union = set_1.union(&set_2);
|
||||
///
|
||||
/// assert!(union.contains(Rule::AmbiguousFunctionName));
|
||||
/// assert!(union.contains(Rule::AnyType));
|
||||
/// assert!(union.contains(Rule::BadQuotesInlineString));
|
||||
/// assert!(union.contains(Rule::BooleanPositionalValueInFunctionCall));
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub const fn union(mut self, other: &Self) -> Self {
|
||||
let mut i = 0;
|
||||
|
||||
while i < self.0.len() {
|
||||
self.0[i] |= other.0[i];
|
||||
i += 1;
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
/// Returns `self` without any of the rules contained in `other`.
|
||||
///
|
||||
/// ## Examples
|
||||
/// ```rust
|
||||
/// # use ruff::registry::{Rule, RuleSet};
|
||||
/// let set_1 = RuleSet::from_rules(&[Rule::AmbiguousFunctionName, Rule::AnyType]);
|
||||
/// let set_2 = RuleSet::from_rules(&[Rule::AmbiguousFunctionName, Rule::Debugger]);
|
||||
///
|
||||
/// let subtract = set_1.subtract(&set_2);
|
||||
///
|
||||
/// assert!(subtract.contains(Rule::AnyType));
|
||||
/// assert!(!subtract.contains(Rule::AmbiguousFunctionName));
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub const fn subtract(mut self, other: &Self) -> Self {
|
||||
let mut i = 0;
|
||||
|
||||
while i < self.0.len() {
|
||||
self.0[i] ^= other.0[i];
|
||||
i += 1;
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
/// Returns true if `self` and `other` contain at least one common rule.
|
||||
///
|
||||
/// ## Examples
|
||||
/// ```rust
|
||||
/// # use ruff::registry::{Rule, RuleSet};
|
||||
/// let set_1 = RuleSet::from_rules(&[Rule::AmbiguousFunctionName, Rule::AnyType]);
|
||||
///
|
||||
/// assert!(set_1.intersects(&RuleSet::from_rules(&[
|
||||
/// Rule::AnyType,
|
||||
/// Rule::BadQuotesInlineString
|
||||
/// ])));
|
||||
///
|
||||
/// assert!(!set_1.intersects(&RuleSet::from_rules(&[
|
||||
/// Rule::BooleanPositionalValueInFunctionCall,
|
||||
/// Rule::BadQuotesInlineString
|
||||
/// ])));
|
||||
/// ```
|
||||
pub const fn intersects(&self, other: &Self) -> bool {
|
||||
let mut i = 0;
|
||||
|
||||
while i < self.0.len() {
|
||||
if self.0[i] & other.0[i] != 0 {
|
||||
return true;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
/// Returns `true` if this set contains no rules, `false` otherwise.
|
||||
///
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use ruff::registry::{Rule, RuleSet};
|
||||
/// assert!(RuleSet::empty().is_empty());
|
||||
/// assert!(
|
||||
/// !RuleSet::from_rules(&[Rule::AmbiguousFunctionName, Rule::BadQuotesInlineString])
|
||||
/// .is_empty()
|
||||
/// );
|
||||
/// ```
|
||||
pub const fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
/// Returns the number of rules in this set.
|
||||
///
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use ruff::registry::{Rule, RuleSet};
|
||||
/// assert_eq!(RuleSet::empty().len(), 0);
|
||||
/// assert_eq!(
|
||||
/// RuleSet::from_rules(&[Rule::AmbiguousFunctionName, Rule::BadQuotesInlineString]).len(),
|
||||
/// 2
|
||||
/// );
|
||||
pub const fn len(&self) -> usize {
|
||||
let mut len: u32 = 0;
|
||||
|
||||
let mut i = 0;
|
||||
|
||||
while i < self.0.len() {
|
||||
len += self.0[i].count_ones();
|
||||
i += 1;
|
||||
}
|
||||
|
||||
len as usize
|
||||
}
|
||||
|
||||
/// Inserts `rule` into the set.
|
||||
///
|
||||
/// ## Examples
|
||||
/// ```rust
|
||||
/// # use ruff::registry::{Rule, RuleSet};
|
||||
/// let mut set = RuleSet::empty();
|
||||
///
|
||||
/// assert!(!set.contains(Rule::AnyType));
|
||||
///
|
||||
/// set.insert(Rule::AnyType);
|
||||
///
|
||||
/// assert!(set.contains(Rule::AnyType));
|
||||
/// ```
|
||||
pub fn insert(&mut self, rule: Rule) {
|
||||
let set = std::mem::take(self);
|
||||
*self = set.union(&RuleSet::from_rule(rule));
|
||||
}
|
||||
|
||||
/// Removes `rule` from the set.
|
||||
///
|
||||
/// ## Examples
|
||||
/// ```rust
|
||||
/// # use ruff::registry::{Rule, RuleSet};
|
||||
/// let mut set = RuleSet::from_rules(&[Rule::AmbiguousFunctionName, Rule::AnyType]);
|
||||
///
|
||||
/// set.remove(Rule::AmbiguousFunctionName);
|
||||
///
|
||||
/// assert!(set.contains(Rule::AnyType));
|
||||
/// assert!(!set.contains(Rule::AmbiguousFunctionName));
|
||||
/// ```
|
||||
pub fn remove(&mut self, rule: Rule) {
|
||||
let set = std::mem::take(self);
|
||||
*self = set.subtract(&RuleSet::from_rule(rule));
|
||||
}
|
||||
|
||||
/// Returns `true` if `rule` is in this set.
|
||||
///
|
||||
/// ## Examples
|
||||
/// ```rust
|
||||
/// # use ruff::registry::{Rule, RuleSet};
|
||||
/// let set = RuleSet::from_rules(&[Rule::AmbiguousFunctionName, Rule::AnyType]);
|
||||
///
|
||||
/// assert!(set.contains(Rule::AmbiguousFunctionName));
|
||||
/// assert!(!set.contains(Rule::BreakOutsideLoop));
|
||||
/// ```
|
||||
pub const fn contains(&self, rule: Rule) -> bool {
|
||||
let rule = rule as u16;
|
||||
let index = rule as usize / Self::SLICE_BITS as usize;
|
||||
let shift = rule % Self::SLICE_BITS;
|
||||
let mask = 1 << shift;
|
||||
|
||||
self.0[index] & mask != 0
|
||||
}
|
||||
|
||||
/// Returns an iterator over the rules in this set.
|
||||
///
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use ruff::registry::{Rule, RuleSet};
|
||||
/// let set = RuleSet::from_rules(&[Rule::AmbiguousFunctionName, Rule::AnyType]);
|
||||
///
|
||||
/// let iter: Vec<_> = set.iter().collect();
|
||||
///
|
||||
/// assert_eq!(iter, vec![Rule::AmbiguousFunctionName, Rule::AnyType]);
|
||||
/// ```
|
||||
pub fn iter(&self) -> RuleSetIterator {
|
||||
RuleSetIterator {
|
||||
set: self.clone(),
|
||||
index: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for RuleSet {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_set().entries(self.iter()).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromIterator<Rule> for RuleSet {
|
||||
fn from_iter<T: IntoIterator<Item = Rule>>(iter: T) -> Self {
|
||||
let mut set = RuleSet::empty();
|
||||
|
||||
for rule in iter {
|
||||
set.insert(rule);
|
||||
}
|
||||
|
||||
set
|
||||
}
|
||||
}
|
||||
|
||||
impl Extend<Rule> for RuleSet {
|
||||
fn extend<T: IntoIterator<Item = Rule>>(&mut self, iter: T) {
|
||||
let set = std::mem::take(self);
|
||||
*self = set.union(&RuleSet::from_iter(iter));
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for RuleSet {
|
||||
type Item = Rule;
|
||||
type IntoIter = RuleSetIterator;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for &RuleSet {
|
||||
type Item = Rule;
|
||||
type IntoIter = RuleSetIterator;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RuleSetIterator {
|
||||
set: RuleSet,
|
||||
index: u16,
|
||||
}
|
||||
|
||||
impl Iterator for RuleSetIterator {
|
||||
type Item = Rule;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
loop {
|
||||
let slice = self.set.0.get_mut(self.index as usize)?;
|
||||
// `trailing_zeros` is guaranteed to return a value in [0;64]
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
let bit = slice.trailing_zeros() as u16;
|
||||
|
||||
if bit < RuleSet::SLICE_BITS {
|
||||
*slice ^= 1 << bit;
|
||||
let rule_value = self.index * RuleSet::SLICE_BITS + bit;
|
||||
// SAFETY: RuleSet guarantees that only valid rules are stored in the set.
|
||||
#[allow(unsafe_code)]
|
||||
return Some(unsafe { std::mem::transmute(rule_value) });
|
||||
}
|
||||
|
||||
self.index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let len = self.set.len();
|
||||
|
||||
(len, Some(len))
|
||||
}
|
||||
}
|
||||
|
||||
impl ExactSizeIterator for RuleSetIterator {}
|
||||
|
||||
impl FusedIterator for RuleSetIterator {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::registry::{Rule, RuleSet};
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
/// Tests that the set can contain all rules
|
||||
#[test]
|
||||
fn test_all_rules() {
|
||||
for rule in Rule::iter() {
|
||||
let set = RuleSet::from_rule(rule);
|
||||
|
||||
assert!(set.contains(rule));
|
||||
}
|
||||
|
||||
let all_rules_set: RuleSet = Rule::iter().collect();
|
||||
let all_rules: Vec<_> = all_rules_set.iter().collect();
|
||||
let expected_rules: Vec<_> = Rule::iter().collect();
|
||||
assert_eq!(all_rules, expected_rules);
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ use ruff_python_stdlib::path::is_python_file;
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use crate::fs;
|
||||
use crate::jupyter::is_jupyter_notebook;
|
||||
use crate::settings::configuration::Configuration;
|
||||
use crate::settings::pyproject::settings_toml;
|
||||
use crate::settings::{pyproject, AllSettings, Settings};
|
||||
@@ -128,7 +129,7 @@ pub fn resolve_configuration(
|
||||
|
||||
// Resolve the current path.
|
||||
let options = pyproject::load_options(&path)
|
||||
.map_err(|err| anyhow!("Failed to parse `{}`: {}", path.to_string_lossy(), err))?;
|
||||
.map_err(|err| anyhow!("Failed to parse `{}`: {}", path.display(), err))?;
|
||||
let project_root = relativity.resolve(&path);
|
||||
let configuration = Configuration::from_options(options, &project_root)?;
|
||||
|
||||
@@ -193,15 +194,15 @@ fn match_exclusion(file_path: &str, file_basename: &str, exclusion: &globset::Gl
|
||||
exclusion.is_match(file_path) || exclusion.is_match(file_basename)
|
||||
}
|
||||
|
||||
/// Return `true` if the [`DirEntry`] appears to be that of a Python file.
|
||||
/// Return `true` if the [`DirEntry`] appears to be that of a Python file or jupyter notebook.
|
||||
pub fn is_python_entry(entry: &DirEntry) -> bool {
|
||||
is_python_file(entry.path())
|
||||
(is_python_file(entry.path()) || is_jupyter_notebook(entry.path()))
|
||||
&& !entry
|
||||
.file_type()
|
||||
.map_or(false, |file_type| file_type.is_dir())
|
||||
}
|
||||
|
||||
/// Find all Python (`.py` and `.pyi` files) in a set of paths.
|
||||
/// Find all Python (`.py`, `.pyi` and `.ipynb` files) in a set of paths.
|
||||
pub fn python_files_in_path(
|
||||
paths: &[PathBuf],
|
||||
pyproject_strategy: &PyprojectDiscovery,
|
||||
@@ -260,38 +261,6 @@ pub fn python_files_in_path(
|
||||
std::sync::Mutex::new(vec![]);
|
||||
walker.run(|| {
|
||||
Box::new(|result| {
|
||||
// Search for the `pyproject.toml` file in this directory, before we visit any
|
||||
// of its contents.
|
||||
if pyproject_strategy.is_hierarchical() {
|
||||
if let Ok(entry) = &result {
|
||||
if entry
|
||||
.file_type()
|
||||
.map_or(false, |file_type| file_type.is_dir())
|
||||
{
|
||||
match settings_toml(entry.path()) {
|
||||
Ok(Some(pyproject)) => match resolve_scoped_settings(
|
||||
&pyproject,
|
||||
&Relativity::Parent,
|
||||
processor,
|
||||
) {
|
||||
Ok((root, settings)) => {
|
||||
resolver.write().unwrap().add(root, settings);
|
||||
}
|
||||
Err(err) => {
|
||||
*error.lock().unwrap() = Err(err);
|
||||
return WalkState::Quit;
|
||||
}
|
||||
},
|
||||
Ok(None) => {}
|
||||
Err(err) => {
|
||||
*error.lock().unwrap() = Err(err);
|
||||
return WalkState::Quit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Respect our own exclusion behavior.
|
||||
if let Ok(entry) = &result {
|
||||
if entry.depth() > 0 {
|
||||
@@ -324,6 +293,38 @@ pub fn python_files_in_path(
|
||||
}
|
||||
}
|
||||
|
||||
// Search for the `pyproject.toml` file in this directory, before we visit any
|
||||
// of its contents.
|
||||
if pyproject_strategy.is_hierarchical() {
|
||||
if let Ok(entry) = &result {
|
||||
if entry
|
||||
.file_type()
|
||||
.map_or(false, |file_type| file_type.is_dir())
|
||||
{
|
||||
match settings_toml(entry.path()) {
|
||||
Ok(Some(pyproject)) => match resolve_scoped_settings(
|
||||
&pyproject,
|
||||
&Relativity::Parent,
|
||||
processor,
|
||||
) {
|
||||
Ok((root, settings)) => {
|
||||
resolver.write().unwrap().add(root, settings);
|
||||
}
|
||||
Err(err) => {
|
||||
*error.lock().unwrap() = Err(err);
|
||||
return WalkState::Quit;
|
||||
}
|
||||
},
|
||||
Ok(None) => {}
|
||||
Err(err) => {
|
||||
*error.lock().unwrap() = Err(err);
|
||||
return WalkState::Quit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if result.as_ref().map_or(true, |entry| {
|
||||
// Accept all files that are passed-in directly.
|
||||
(entry.depth() == 0 && entry.file_type().map_or(false, |ft| ft.is_file()))
|
||||
|
||||
@@ -18,7 +18,6 @@ static REDIRECTS: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| {
|
||||
// The following are here because we don't yet have the many-to-one mapping enabled.
|
||||
("SIM111", "SIM110"),
|
||||
// The following are deprecated.
|
||||
("C4", "C40"),
|
||||
("C9", "C90"),
|
||||
("T1", "T10"),
|
||||
("T2", "T20"),
|
||||
|
||||
@@ -277,6 +277,7 @@ pub(crate) enum Specificity {
|
||||
Code5Chars,
|
||||
}
|
||||
|
||||
#[cfg(feature = "clap")]
|
||||
mod clap_completion {
|
||||
use clap::builder::{PossibleValue, TypedValueParser, ValueParserFactory};
|
||||
use strum::IntoEnumIterator;
|
||||
@@ -316,9 +317,7 @@ mod clap_completion {
|
||||
.map_err(|e| clap::Error::raw(clap::error::ErrorKind::InvalidValue, e))
|
||||
}
|
||||
|
||||
fn possible_values(
|
||||
&self,
|
||||
) -> Option<Box<dyn Iterator<Item = clap::builder::PossibleValue> + '_>> {
|
||||
fn possible_values(&self) -> Option<Box<dyn Iterator<Item = PossibleValue> + '_>> {
|
||||
Some(Box::new(
|
||||
std::iter::once(PossibleValue::new("ALL").help("all rules")).chain(
|
||||
Linter::iter()
|
||||
|
||||
@@ -61,7 +61,7 @@ pub fn commented_out_code(
|
||||
// Verify that the comment is on its own line, and that it contains code.
|
||||
if is_standalone_comment(line) && comment_contains_code(line, &settings.task_tags[..]) {
|
||||
let mut diagnostic = Diagnostic::new(CommentedOutCode, Range::new(start, end));
|
||||
if autofix.into() && settings.rules.should_fix(&Rule::CommentedOutCode) {
|
||||
if autofix.into() && settings.rules.should_fix(Rule::CommentedOutCode) {
|
||||
diagnostic.amend(Fix::deletion(location, end_location));
|
||||
}
|
||||
Some(diagnostic)
|
||||
|
||||
@@ -13,16 +13,16 @@ mod tests {
|
||||
use crate::settings;
|
||||
use crate::test::test_path;
|
||||
|
||||
#[test_case(Rule::SysVersionSlice3Referenced, Path::new("YTT101.py"); "YTT101")]
|
||||
#[test_case(Rule::SysVersion2Referenced, Path::new("YTT102.py"); "YTT102")]
|
||||
#[test_case(Rule::SysVersionSlice3, Path::new("YTT101.py"); "YTT101")]
|
||||
#[test_case(Rule::SysVersion2, Path::new("YTT102.py"); "YTT102")]
|
||||
#[test_case(Rule::SysVersionCmpStr3, Path::new("YTT103.py"); "YTT103")]
|
||||
#[test_case(Rule::SysVersionInfo0Eq3Referenced, Path::new("YTT201.py"); "YTT201")]
|
||||
#[test_case(Rule::SixPY3Referenced, Path::new("YTT202.py"); "YTT202")]
|
||||
#[test_case(Rule::SysVersionInfo0Eq3, Path::new("YTT201.py"); "YTT201")]
|
||||
#[test_case(Rule::SixPY3, Path::new("YTT202.py"); "YTT202")]
|
||||
#[test_case(Rule::SysVersionInfo1CmpInt, Path::new("YTT203.py"); "YTT203")]
|
||||
#[test_case(Rule::SysVersionInfoMinorCmpInt, Path::new("YTT204.py"); "YTT204")]
|
||||
#[test_case(Rule::SysVersion0Referenced, Path::new("YTT301.py"); "YTT301")]
|
||||
#[test_case(Rule::SysVersion0, Path::new("YTT301.py"); "YTT301")]
|
||||
#[test_case(Rule::SysVersionCmpStr10, Path::new("YTT302.py"); "YTT302")]
|
||||
#[test_case(Rule::SysVersionSlice1Referenced, Path::new("YTT303.py"); "YTT303")]
|
||||
#[test_case(Rule::SysVersionSlice1, Path::new("YTT303.py"); "YTT303")]
|
||||
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
|
||||
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
|
||||
let diagnostics = test_path(
|
||||
|
||||
@@ -9,9 +9,9 @@ use crate::checkers::ast::Checker;
|
||||
use crate::registry::Rule;
|
||||
|
||||
#[violation]
|
||||
pub struct SysVersionSlice3Referenced;
|
||||
pub struct SysVersionSlice3;
|
||||
|
||||
impl Violation for SysVersionSlice3Referenced {
|
||||
impl Violation for SysVersionSlice3 {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("`sys.version[:3]` referenced (python3.10), use `sys.version_info`")
|
||||
@@ -19,9 +19,9 @@ impl Violation for SysVersionSlice3Referenced {
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SysVersion2Referenced;
|
||||
pub struct SysVersion2;
|
||||
|
||||
impl Violation for SysVersion2Referenced {
|
||||
impl Violation for SysVersion2 {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("`sys.version[2]` referenced (python3.10), use `sys.version_info`")
|
||||
@@ -39,9 +39,9 @@ impl Violation for SysVersionCmpStr3 {
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SysVersionInfo0Eq3Referenced;
|
||||
pub struct SysVersionInfo0Eq3;
|
||||
|
||||
impl Violation for SysVersionInfo0Eq3Referenced {
|
||||
impl Violation for SysVersionInfo0Eq3 {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("`sys.version_info[0] == 3` referenced (python4), use `>=`")
|
||||
@@ -49,9 +49,9 @@ impl Violation for SysVersionInfo0Eq3Referenced {
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SixPY3Referenced;
|
||||
pub struct SixPY3;
|
||||
|
||||
impl Violation for SixPY3Referenced {
|
||||
impl Violation for SixPY3 {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("`six.PY3` referenced (python4), use `not six.PY2`")
|
||||
@@ -85,9 +85,9 @@ impl Violation for SysVersionInfoMinorCmpInt {
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SysVersion0Referenced;
|
||||
pub struct SysVersion0;
|
||||
|
||||
impl Violation for SysVersion0Referenced {
|
||||
impl Violation for SysVersion0 {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("`sys.version[0]` referenced (python10), use `sys.version_info`")
|
||||
@@ -105,9 +105,9 @@ impl Violation for SysVersionCmpStr10 {
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SysVersionSlice1Referenced;
|
||||
pub struct SysVersionSlice1;
|
||||
|
||||
impl Violation for SysVersionSlice1Referenced {
|
||||
impl Violation for SysVersionSlice1 {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("`sys.version[:1]` referenced (python10), use `sys.version_info`")
|
||||
@@ -137,25 +137,17 @@ pub fn subscript(checker: &mut Checker, value: &Expr, slice: &Expr) {
|
||||
} = &upper.node
|
||||
{
|
||||
if *i == BigInt::from(1)
|
||||
&& checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::SysVersionSlice1Referenced)
|
||||
&& checker.settings.rules.enabled(Rule::SysVersionSlice1)
|
||||
{
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
SysVersionSlice1Referenced,
|
||||
Range::from(value),
|
||||
));
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(SysVersionSlice1, Range::from(value)));
|
||||
} else if *i == BigInt::from(3)
|
||||
&& checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::SysVersionSlice3Referenced)
|
||||
&& checker.settings.rules.enabled(Rule::SysVersionSlice3)
|
||||
{
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
SysVersionSlice3Referenced,
|
||||
Range::from(value),
|
||||
));
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(SysVersionSlice3, Range::from(value)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -164,18 +156,15 @@ pub fn subscript(checker: &mut Checker, value: &Expr, slice: &Expr) {
|
||||
value: Constant::Int(i),
|
||||
..
|
||||
} => {
|
||||
if *i == BigInt::from(2)
|
||||
&& checker.settings.rules.enabled(&Rule::SysVersion2Referenced)
|
||||
if *i == BigInt::from(2) && checker.settings.rules.enabled(Rule::SysVersion2) {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(SysVersion2, Range::from(value)));
|
||||
} else if *i == BigInt::from(0) && checker.settings.rules.enabled(Rule::SysVersion0)
|
||||
{
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(SysVersion2Referenced, Range::from(value)));
|
||||
} else if *i == BigInt::from(0)
|
||||
&& checker.settings.rules.enabled(&Rule::SysVersion0Referenced)
|
||||
{
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(SysVersion0Referenced, Range::from(value)));
|
||||
.push(Diagnostic::new(SysVersion0, Range::from(value)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,15 +196,11 @@ pub fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], comparators: &
|
||||
) = (ops, comparators)
|
||||
{
|
||||
if *n == BigInt::from(3)
|
||||
&& checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::SysVersionInfo0Eq3Referenced)
|
||||
&& checker.settings.rules.enabled(Rule::SysVersionInfo0Eq3)
|
||||
{
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
SysVersionInfo0Eq3Referenced,
|
||||
Range::from(left),
|
||||
));
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(SysVersionInfo0Eq3, Range::from(left)));
|
||||
}
|
||||
}
|
||||
} else if *i == BigInt::from(1) {
|
||||
@@ -231,7 +216,7 @@ pub fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], comparators: &
|
||||
}],
|
||||
) = (ops, comparators)
|
||||
{
|
||||
if checker.settings.rules.enabled(&Rule::SysVersionInfo1CmpInt) {
|
||||
if checker.settings.rules.enabled(Rule::SysVersionInfo1CmpInt) {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(SysVersionInfo1CmpInt, Range::from(left)));
|
||||
@@ -259,7 +244,7 @@ pub fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], comparators: &
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::SysVersionInfoMinorCmpInt)
|
||||
.enabled(Rule::SysVersionInfoMinorCmpInt)
|
||||
{
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
SysVersionInfoMinorCmpInt,
|
||||
@@ -286,12 +271,12 @@ pub fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], comparators: &
|
||||
) = (ops, comparators)
|
||||
{
|
||||
if s.len() == 1 {
|
||||
if checker.settings.rules.enabled(&Rule::SysVersionCmpStr10) {
|
||||
if checker.settings.rules.enabled(Rule::SysVersionCmpStr10) {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(SysVersionCmpStr10, Range::from(left)));
|
||||
}
|
||||
} else if checker.settings.rules.enabled(&Rule::SysVersionCmpStr3) {
|
||||
} else if checker.settings.rules.enabled(Rule::SysVersionCmpStr3) {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(SysVersionCmpStr3, Range::from(left)));
|
||||
@@ -309,6 +294,6 @@ pub fn name_or_attribute(checker: &mut Checker, expr: &Expr) {
|
||||
{
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(SixPY3Referenced, Range::from(expr)));
|
||||
.push(Diagnostic::new(SixPY3, Range::from(expr)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ source: crates/ruff/src/rules/flake8_2020/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: SysVersionSlice3Referenced
|
||||
name: SysVersionSlice3
|
||||
body: "`sys.version[:3]` referenced (python3.10), use `sys.version_info`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -16,7 +16,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: SysVersionSlice3Referenced
|
||||
name: SysVersionSlice3
|
||||
body: "`sys.version[:3]` referenced (python3.10), use `sys.version_info`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -29,7 +29,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: SysVersionSlice3Referenced
|
||||
name: SysVersionSlice3
|
||||
body: "`sys.version[:3]` referenced (python3.10), use `sys.version_info`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
|
||||
@@ -3,7 +3,7 @@ source: crates/ruff/src/rules/flake8_2020/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: SysVersion2Referenced
|
||||
name: SysVersion2
|
||||
body: "`sys.version[2]` referenced (python3.10), use `sys.version_info`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -16,7 +16,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: SysVersion2Referenced
|
||||
name: SysVersion2
|
||||
body: "`sys.version[2]` referenced (python3.10), use `sys.version_info`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
|
||||
@@ -3,7 +3,7 @@ source: crates/ruff/src/rules/flake8_2020/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: SysVersionInfo0Eq3Referenced
|
||||
name: SysVersionInfo0Eq3
|
||||
body: "`sys.version_info[0] == 3` referenced (python4), use `>=`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -16,7 +16,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: SysVersionInfo0Eq3Referenced
|
||||
name: SysVersionInfo0Eq3
|
||||
body: "`sys.version_info[0] == 3` referenced (python4), use `>=`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -29,7 +29,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: SysVersionInfo0Eq3Referenced
|
||||
name: SysVersionInfo0Eq3
|
||||
body: "`sys.version_info[0] == 3` referenced (python4), use `>=`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -42,7 +42,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: SysVersionInfo0Eq3Referenced
|
||||
name: SysVersionInfo0Eq3
|
||||
body: "`sys.version_info[0] == 3` referenced (python4), use `>=`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
|
||||
@@ -3,7 +3,7 @@ source: crates/ruff/src/rules/flake8_2020/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: SixPY3Referenced
|
||||
name: SixPY3
|
||||
body: "`six.PY3` referenced (python4), use `not six.PY2`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
@@ -16,7 +16,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: SixPY3Referenced
|
||||
name: SixPY3
|
||||
body: "`six.PY3` referenced (python4), use `not six.PY2`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user