Compare commits
6 Commits
v0.0.255
...
sasanjac/2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a8b65b429 | ||
|
|
5afe4bf711 | ||
|
|
b307200e42 | ||
|
|
13f63072df | ||
|
|
bcba5f176d | ||
|
|
223a5b4631 |
76
.github/workflows/ci.yaml
vendored
76
.github/workflows/ci.yaml
vendored
@@ -17,6 +17,20 @@ env:
|
||||
RUSTUP_MAX_RETRIES: 10
|
||||
|
||||
jobs:
|
||||
cargo-build:
|
||||
name: "cargo build"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup show
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- run: cargo build --all
|
||||
- run: ./target/debug/ruff_dev generate-all
|
||||
- run: git diff --quiet README.md || echo "::error file=README.md::This file is outdated. Run 'cargo dev generate-all'."
|
||||
- run: git diff --quiet ruff.schema.json || echo "::error file=ruff.schema.json::This file is outdated. Run 'cargo dev generate-all'."
|
||||
- run: git diff --exit-code -- README.md ruff.schema.json docs
|
||||
|
||||
cargo-fmt:
|
||||
name: "cargo fmt"
|
||||
runs-on: ubuntu-latest
|
||||
@@ -47,7 +61,7 @@ jobs:
|
||||
rustup component add clippy
|
||||
rustup target add wasm32-unknown-unknown
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- run: cargo clippy -p ruff_wasm --target wasm32-unknown-unknown --all-features -- -D warnings
|
||||
- run: cargo clippy -p ruff --target wasm32-unknown-unknown --all-features -- -D warnings
|
||||
|
||||
cargo-test:
|
||||
strategy:
|
||||
@@ -79,30 +93,6 @@ jobs:
|
||||
env:
|
||||
# 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
|
||||
with:
|
||||
name: ruff
|
||||
path: target/debug/ruff
|
||||
|
||||
|
||||
cargo-test-wasm:
|
||||
runs-on: ubuntu-latest
|
||||
name: "cargo test (wasm)"
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup target add wasm32-unknown-unknown
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
cache: "npm"
|
||||
cache-dependency-path: playground/package-lock.json
|
||||
- uses: jetli/wasm-pack-action@v0.4.0
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- name: "Run wasm-pack"
|
||||
run: |
|
||||
cd crates/ruff_wasm
|
||||
wasm-pack test --node
|
||||
|
||||
scripts:
|
||||
name: "test scripts"
|
||||
@@ -127,39 +117,3 @@ jobs:
|
||||
- uses: crate-ci/typos@master
|
||||
with:
|
||||
files: .
|
||||
|
||||
ecosystem:
|
||||
name: "ecosystem"
|
||||
runs-on: ubuntu-latest
|
||||
needs: cargo-test
|
||||
# Only runs on pull requests, since that is the only we way we can find the base version for comparison.
|
||||
if: github.event_name == 'pull_request'
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.11"
|
||||
- uses: actions/download-artifact@v3
|
||||
id: ruff-target
|
||||
with:
|
||||
name: ruff
|
||||
path: target/debug
|
||||
- uses: dawidd6/action-download-artifact@v2
|
||||
with:
|
||||
name: ruff
|
||||
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
|
||||
|
||||
echo ${{ github.event.number }} > pr-number
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ecosystem-result
|
||||
path: |
|
||||
ecosystem-result
|
||||
pr-number
|
||||
|
||||
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
|
||||
2
.github/workflows/playground.yaml
vendored
2
.github/workflows/playground.yaml
vendored
@@ -28,7 +28,7 @@ jobs:
|
||||
- uses: jetli/wasm-pack-action@v0.4.0
|
||||
- uses: jetli/wasm-bindgen-action@v0.2.0
|
||||
- name: "Run wasm-pack"
|
||||
run: wasm-pack build --target web --out-dir ../../playground/src/pkg crates/ruff_wasm
|
||||
run: wasm-pack build --target web --out-dir ../../playground/src/pkg crates/ruff
|
||||
- name: "Install Node dependencies"
|
||||
run: npm ci
|
||||
working-directory: playground
|
||||
|
||||
@@ -104,7 +104,7 @@ At a high level, the steps involved in adding a new lint rule are as follows:
|
||||
|
||||
1. Determine a name for the new rule as per our [rule naming convention](#rule-naming-convention).
|
||||
1. Create a file for your rule (e.g., `crates/ruff/src/rules/flake8_bugbear/rules/abstract_base_class.rs`).
|
||||
1. In that file, define a violation struct. You can grep for `#[violation]` to see examples.
|
||||
1. In that file, define a violation struct. You can grep for `define_violation!` to see examples.
|
||||
1. Map the violation struct to a rule code in `crates/ruff/src/registry.rs` (e.g., `E402`).
|
||||
1. Define the logic for triggering the violation in `crates/ruff/src/checkers/ast.rs` (for AST-based
|
||||
checks), `crates/ruff/src/checkers/tokens.rs` (for token-based checks), `crates/ruff/src/checkers/lines.rs`
|
||||
@@ -115,7 +115,7 @@ At a high level, the steps involved in adding a new lint rule are as follows:
|
||||
|
||||
To define the violation, start by creating a dedicated file for your rule under the appropriate
|
||||
rule linter (e.g., `crates/ruff/src/rules/flake8_bugbear/rules/abstract_base_class.rs`). That file should
|
||||
contain a struct defined via `#[violation]`, along with a function that creates the violation
|
||||
contain a struct defined via `define_violation!`, along with a function that creates the violation
|
||||
based on any required inputs. (Many of the existing examples live in `crates/ruff/src/violations.rs`,
|
||||
but we're looking to place new rules in their own files.)
|
||||
|
||||
|
||||
171
Cargo.lock
generated
171
Cargo.lock
generated
@@ -554,16 +554,6 @@ dependencies = [
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ctor"
|
||||
version = "0.1.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxx"
|
||||
version = "1.0.91"
|
||||
@@ -608,6 +598,17 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derivative"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diff"
|
||||
version = "0.1.13"
|
||||
@@ -769,7 +770,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.255"
|
||||
version = "0.0.254"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.1.8",
|
||||
@@ -1447,15 +1448,6 @@ version = "6.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
|
||||
|
||||
[[package]]
|
||||
name = "output_vt100"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.1"
|
||||
@@ -1503,12 +1495,6 @@ dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pathdiff"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
|
||||
|
||||
[[package]]
|
||||
name = "peg"
|
||||
version = "0.8.1"
|
||||
@@ -1536,18 +1522,6 @@ version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fa00462b37ead6d11a82c9d568b26682d78e0477dc02d1966c013af80969739"
|
||||
|
||||
[[package]]
|
||||
name = "pep440_rs"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/konstin/pep440-rs.git?rev=a8fef4ec47f4c25b070b39cdbe6a0b9847e49941#a8fef4ec47f4c25b070b39cdbe6a0b9847e49941"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"regex",
|
||||
"serde",
|
||||
"tracing",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.2.0"
|
||||
@@ -1745,18 +1719,6 @@ dependencies = [
|
||||
"termtree",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pretty_assertions"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755"
|
||||
dependencies = [
|
||||
"ctor",
|
||||
"diff",
|
||||
"output_vt100",
|
||||
"yansi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
@@ -1971,17 +1933,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.255"
|
||||
version = "0.0.254"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bisection",
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"chrono",
|
||||
"clap 4.1.8",
|
||||
"colored",
|
||||
"console_error_panic_hook",
|
||||
"console_log",
|
||||
"criterion",
|
||||
"derivative",
|
||||
"dirs",
|
||||
"fern",
|
||||
"getrandom",
|
||||
"glob",
|
||||
"globset",
|
||||
"ignore",
|
||||
@@ -1989,6 +1956,7 @@ dependencies = [
|
||||
"insta",
|
||||
"is-macro",
|
||||
"itertools",
|
||||
"js-sys",
|
||||
"libcst",
|
||||
"log",
|
||||
"natord",
|
||||
@@ -1997,16 +1965,11 @@ dependencies = [
|
||||
"num-traits",
|
||||
"once_cell",
|
||||
"path-absolutize",
|
||||
"pathdiff",
|
||||
"pep440_rs",
|
||||
"pretty_assertions",
|
||||
"regex",
|
||||
"result-like",
|
||||
"ruff_cache",
|
||||
"ruff_diagnostics",
|
||||
"ruff_macros",
|
||||
"ruff_python_ast",
|
||||
"ruff_python_stdlib",
|
||||
"ruff_python",
|
||||
"ruff_rustpython",
|
||||
"rustc-hash",
|
||||
"rustpython-common",
|
||||
@@ -2014,6 +1977,7 @@ dependencies = [
|
||||
"schemars",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde-wasm-bindgen",
|
||||
"shellexpand",
|
||||
"smallvec",
|
||||
"strum",
|
||||
@@ -2022,6 +1986,8 @@ dependencies = [
|
||||
"textwrap",
|
||||
"thiserror",
|
||||
"toml",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-test",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2037,7 +2003,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_cli"
|
||||
version = "0.0.255"
|
||||
version = "0.0.254"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.9.1",
|
||||
"anyhow",
|
||||
@@ -2064,7 +2030,6 @@ dependencies = [
|
||||
"regex",
|
||||
"ruff",
|
||||
"ruff_cache",
|
||||
"ruff_diagnostics",
|
||||
"rustc-hash",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -2086,11 +2051,9 @@ dependencies = [
|
||||
"itertools",
|
||||
"libcst",
|
||||
"once_cell",
|
||||
"pretty_assertions",
|
||||
"regex",
|
||||
"ruff",
|
||||
"ruff_cli",
|
||||
"ruff_diagnostics",
|
||||
"rustpython-common",
|
||||
"rustpython-parser",
|
||||
"schemars",
|
||||
@@ -2100,15 +2063,6 @@ dependencies = [
|
||||
"textwrap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff_diagnostics"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"ruff_python_ast",
|
||||
"rustpython-parser",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff_formatter"
|
||||
version = "0.0.0"
|
||||
@@ -2135,25 +2089,12 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff_python_ast"
|
||||
name = "ruff_python"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags",
|
||||
"is-macro",
|
||||
"itertools",
|
||||
"log",
|
||||
"nohash-hasher",
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
"once_cell",
|
||||
"regex",
|
||||
"ruff_python_stdlib",
|
||||
"ruff_rustpython",
|
||||
"rustc-hash",
|
||||
"rustpython-common",
|
||||
"rustpython-parser",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2167,8 +2108,7 @@ dependencies = [
|
||||
"itertools",
|
||||
"once_cell",
|
||||
"ruff_formatter",
|
||||
"ruff_python_ast",
|
||||
"ruff_python_stdlib",
|
||||
"ruff_python",
|
||||
"ruff_rustpython",
|
||||
"ruff_testing_macros",
|
||||
"ruff_text_size",
|
||||
@@ -2179,15 +2119,6 @@ dependencies = [
|
||||
"test-case",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff_python_stdlib"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff_rustpython"
|
||||
version = "0.0.0"
|
||||
@@ -2203,6 +2134,7 @@ name = "ruff_testing_macros"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"glob",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
@@ -2218,25 +2150,6 @@ dependencies = [
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff_wasm"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"console_error_panic_hook",
|
||||
"console_log",
|
||||
"getrandom",
|
||||
"js-sys",
|
||||
"log",
|
||||
"ruff",
|
||||
"ruff_python_ast",
|
||||
"ruff_rustpython",
|
||||
"rustpython-parser",
|
||||
"serde",
|
||||
"serde-wasm-bindgen",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-test",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-stemmers"
|
||||
version = "1.2.0"
|
||||
@@ -2282,7 +2195,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-ast"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=c15f670f2c30cfae6b41a1874893590148c74bc4#c15f670f2c30cfae6b41a1874893590148c74bc4"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=1871a1632e310985414211222f5bf8069678892f#1871a1632e310985414211222f5bf8069678892f"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"rustpython-compiler-core",
|
||||
@@ -2291,7 +2204,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-common"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=c15f670f2c30cfae6b41a1874893590148c74bc4#c15f670f2c30cfae6b41a1874893590148c74bc4"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=1871a1632e310985414211222f5bf8069678892f#1871a1632e310985414211222f5bf8069678892f"
|
||||
dependencies = [
|
||||
"ascii",
|
||||
"bitflags",
|
||||
@@ -2316,7 +2229,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-compiler-core"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=c15f670f2c30cfae6b41a1874893590148c74bc4#c15f670f2c30cfae6b41a1874893590148c74bc4"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=1871a1632e310985414211222f5bf8069678892f#1871a1632e310985414211222f5bf8069678892f"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bstr 0.2.17",
|
||||
@@ -2330,7 +2243,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "rustpython-parser"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=c15f670f2c30cfae6b41a1874893590148c74bc4#c15f670f2c30cfae6b41a1874893590148c74bc4"
|
||||
source = "git+https://github.com/RustPython/RustPython.git?rev=1871a1632e310985414211222f5bf8069678892f#1871a1632e310985414211222f5bf8069678892f"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"anyhow",
|
||||
@@ -2442,9 +2355,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde-wasm-bindgen"
|
||||
version = "0.5.0"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3b143e2833c57ab9ad3ea280d21fd34e285a42837aeb0ee301f4f41890fa00e"
|
||||
checksum = "e3b4c031cd0d9014307d82b8abf653c0290fbdaeb4c02d00c63cf52f728628bf"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"serde",
|
||||
@@ -2855,21 +2768,9 @@ checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"pin-project-lite",
|
||||
"tracing-attributes",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-attributes"
|
||||
version = "0.1.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.30"
|
||||
@@ -3365,12 +3266,6 @@ dependencies = [
|
||||
"linked-hash-map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yansi"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
|
||||
|
||||
[[package]]
|
||||
name = "yansi-term"
|
||||
version = "0.1.2"
|
||||
|
||||
@@ -3,7 +3,7 @@ members = ["crates/*"]
|
||||
|
||||
[workspace.package]
|
||||
edition = "2021"
|
||||
rust-version = "1.67"
|
||||
rust-version = "1.67.0"
|
||||
|
||||
[workspace.dependencies]
|
||||
anyhow = { version = "1.0.69" }
|
||||
@@ -26,11 +26,11 @@ proc-macro2 = { version = "1.0.51" }
|
||||
quote = { version = "1.0.23" }
|
||||
regex = { version = "1.7.1" }
|
||||
rustc-hash = { version = "1.1.0" }
|
||||
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "c15f670f2c30cfae6b41a1874893590148c74bc4" }
|
||||
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "1871a1632e310985414211222f5bf8069678892f" }
|
||||
rustpython-parser = { features = [
|
||||
"lalrpop",
|
||||
"serde",
|
||||
], git = "https://github.com/RustPython/RustPython.git", rev = "c15f670f2c30cfae6b41a1874893590148c74bc4" }
|
||||
], git = "https://github.com/RustPython/RustPython.git", rev = "1871a1632e310985414211222f5bf8069678892f" }
|
||||
schemars = { version = "0.8.12" }
|
||||
serde = { version = "1.0.152", features = ["derive"] }
|
||||
serde_json = { version = "1.0.93" }
|
||||
|
||||
@@ -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.254'
|
||||
hooks:
|
||||
- id: ruff
|
||||
```
|
||||
@@ -306,9 +306,6 @@ Ruff is used in a number of major open-source projects, including:
|
||||
- [meson-python](https://github.com/mesonbuild/meson-python)
|
||||
- [ZenML](https://github.com/zenml-io/zenml)
|
||||
- [delta-rs](https://github.com/delta-io/delta-rs)
|
||||
- [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)
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
[package]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.255"
|
||||
version = "0.0.254"
|
||||
edition = { workspace = true }
|
||||
rust-version = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
ruff = { path = "../ruff", default-features = false }
|
||||
|
||||
anyhow = { workspace = true }
|
||||
clap = { workspace = true }
|
||||
colored = { workspace = true }
|
||||
configparser = { version = "3.0.2" }
|
||||
once_cell = { workspace = true }
|
||||
regex = { workspace = true }
|
||||
ruff = { path = "../ruff", default-features = false }
|
||||
rustc-hash = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
|
||||
@@ -46,15 +46,8 @@ fn main() -> Result<()> {
|
||||
.map(|tool| ExternalConfig {
|
||||
black: tool.black.as_ref(),
|
||||
isort: tool.isort.as_ref(),
|
||||
..Default::default()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
let external_config = ExternalConfig {
|
||||
project: pyproject
|
||||
.as_ref()
|
||||
.and_then(|pyproject| pyproject.project.as_ref()),
|
||||
..external_config
|
||||
};
|
||||
|
||||
// Create Ruff's pyproject.toml section.
|
||||
let pyproject = flake8_to_ruff::convert(&config, &external_config, args.plugin)?;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff"
|
||||
version = "0.0.255"
|
||||
version = "0.0.254"
|
||||
authors = ["Charlie Marsh <charlie.r.marsh@gmail.com>"]
|
||||
edition = { workspace = true }
|
||||
rust-version = { workspace = true }
|
||||
@@ -12,21 +12,23 @@ license = "MIT"
|
||||
|
||||
[lib]
|
||||
name = "ruff"
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
ruff_cache = { path = "../ruff_cache" }
|
||||
ruff_diagnostics = { path = "../ruff_diagnostics", features = ["serde"] }
|
||||
ruff_macros = { path = "../ruff_macros" }
|
||||
ruff_python_ast = { path = "../ruff_python_ast" }
|
||||
ruff_python_stdlib = { path = "../ruff_python_stdlib" }
|
||||
ruff_python = { path = "../ruff_python" }
|
||||
ruff_rustpython = { path = "../ruff_rustpython" }
|
||||
ruff_cache = { path = "../ruff_cache" }
|
||||
|
||||
anyhow = { workspace = true }
|
||||
bisection = { version = "0.1.0" }
|
||||
bitflags = { workspace = true }
|
||||
cfg-if = { version = "1.0.0" }
|
||||
chrono = { workspace = true }
|
||||
clap = { workspace = true, features = ["derive", "env", "string"] }
|
||||
colored = { workspace = true }
|
||||
derivative = { version = "2.2.0" }
|
||||
dirs = { version = "4.0.0" }
|
||||
fern = { version = "0.6.1" }
|
||||
glob = { workspace = true }
|
||||
@@ -46,10 +48,6 @@ path-absolutize = { workspace = true, features = [
|
||||
"once_cell_cache",
|
||||
"use_unix_paths_on_wasm",
|
||||
] }
|
||||
pathdiff = { version = "0.2.1" }
|
||||
pep440_rs = { git = "https://github.com/konstin/pep440-rs.git", features = [
|
||||
"serde",
|
||||
], rev = "a8fef4ec47f4c25b070b39cdbe6a0b9847e49941" }
|
||||
regex = { workspace = true }
|
||||
result-like = { version = "0.4.6" }
|
||||
rustc-hash = { workspace = true }
|
||||
@@ -66,12 +64,22 @@ textwrap = { workspace = true }
|
||||
thiserror = { version = "1.0.38" }
|
||||
toml = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = { version = "0.4.0" }
|
||||
insta = { workspace = true, features = ["yaml", "redactions"] }
|
||||
pretty_assertions = "1.3.0"
|
||||
test-case = { workspace = true }
|
||||
# https://docs.rs/getrandom/0.2.7/getrandom/#webassembly-support
|
||||
[target.'cfg(all(target_family = "wasm", target_os = "unknown"))'.dependencies]
|
||||
getrandom = { version = "0.2.8", features = ["js"] }
|
||||
console_error_panic_hook = { version = "0.1.7" }
|
||||
console_log = { version = "0.2.1" }
|
||||
serde-wasm-bindgen = { version = "0.4.5" }
|
||||
js-sys = { version = "0.3.61" }
|
||||
wasm-bindgen = { version = "0.2.84" }
|
||||
|
||||
[dev-dependencies]
|
||||
insta = { workspace = true, features = ["yaml", "redactions"] }
|
||||
test-case = { workspace = true }
|
||||
wasm-bindgen-test = { version = "0.3.34" }
|
||||
|
||||
[target.'cfg(not(target_family = "wasm"))'.dev-dependencies]
|
||||
criterion = { version = "0.4.0" }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
"""
|
||||
Should emit:
|
||||
B030:
|
||||
- line 12, column 8
|
||||
- line 17, column 9
|
||||
- line 22, column 21
|
||||
- line 27, column 37
|
||||
"""
|
||||
|
||||
try:
|
||||
pass
|
||||
except 1: # error
|
||||
pass
|
||||
|
||||
try:
|
||||
pass
|
||||
except (1, ValueError): # error
|
||||
pass
|
||||
|
||||
try:
|
||||
pass
|
||||
except (ValueError, (RuntimeError, (KeyError, TypeError))): # error
|
||||
pass
|
||||
|
||||
try:
|
||||
pass
|
||||
except (ValueError, *(RuntimeError, (KeyError, TypeError))): # error
|
||||
pass
|
||||
|
||||
|
||||
try:
|
||||
pass
|
||||
except (ValueError, *(RuntimeError, TypeError)): # ok
|
||||
pass
|
||||
|
||||
try:
|
||||
pass
|
||||
except (ValueError, *[RuntimeError, *(TypeError,)]): # ok
|
||||
pass
|
||||
|
||||
def what_to_catch():
|
||||
return ...
|
||||
|
||||
try:
|
||||
pass
|
||||
except what_to_catch(): # ok
|
||||
pass
|
||||
@@ -8,9 +8,3 @@ any({x.id for x in bar})
|
||||
# PIE 802
|
||||
any([x.id for x in bar])
|
||||
all([x.id for x in bar])
|
||||
any( # first comment
|
||||
[x.id for x in bar], # second comment
|
||||
) # third comment
|
||||
all( # first comment
|
||||
[x.id for x in bar], # second comment
|
||||
) # third comment
|
||||
|
||||
@@ -6,8 +6,6 @@ obj.endswith("foo") or obj.endswith("bar")
|
||||
obj.startswith(foo) or obj.startswith(bar)
|
||||
# error
|
||||
obj.startswith(foo) or obj.startswith("foo")
|
||||
# error
|
||||
obj.endswith(foo) or obj.startswith(foo) or obj.startswith("foo")
|
||||
|
||||
# ok
|
||||
obj.startswith(("foo", "bar"))
|
||||
|
||||
@@ -43,6 +43,3 @@ def f21(
|
||||
def f22(
|
||||
x=-42.5j + 4.3j, # Error PYI014
|
||||
) -> None: ...
|
||||
def f23(
|
||||
x=True, # OK
|
||||
) -> None: ...
|
||||
|
||||
@@ -6,6 +6,22 @@ def x():
|
||||
return a # error
|
||||
|
||||
|
||||
def x():
|
||||
a = 1
|
||||
print(a)
|
||||
a = 2
|
||||
return a # error
|
||||
|
||||
|
||||
def x():
|
||||
a = 1
|
||||
if True:
|
||||
return a # error
|
||||
a = 2
|
||||
print(a)
|
||||
return a
|
||||
|
||||
|
||||
# Can be refactored false positives
|
||||
# https://github.com/afonasev/flake8-return/issues/47#issuecomment-1122571066
|
||||
def get_bar_if_exists(obj):
|
||||
@@ -149,6 +165,44 @@ def my_func():
|
||||
return foo
|
||||
|
||||
|
||||
# Refactored incorrect false positives
|
||||
# See test cases above marked: "Can be refactored false positives"
|
||||
# https://github.com/afonasev/flake8-return/issues/47#issuecomment-1122571066
|
||||
def get_bar_if_exists(obj):
|
||||
if hasattr(obj, "bar"):
|
||||
return str(obj.bar)
|
||||
return ""
|
||||
|
||||
|
||||
# https://github.com/afonasev/flake8-return/issues/47#issue-641117366
|
||||
def x():
|
||||
formatted = _USER_AGENT_FORMATTER.format(format_string, **values)
|
||||
# clean up after any blank components
|
||||
return formatted.replace("()", "").replace(" ", " ").strip()
|
||||
|
||||
|
||||
# https://github.com/afonasev/flake8-return/issues/47#issue-641117366
|
||||
def user_agent_username(username=None):
|
||||
|
||||
if not username:
|
||||
return ""
|
||||
|
||||
username = username.replace(" ", "_") # Avoid spaces or %20.
|
||||
try:
|
||||
username.encode("ascii") # just test,
|
||||
# but not actually use it
|
||||
except UnicodeEncodeError:
|
||||
username = quote(username.encode("utf-8"))
|
||||
else:
|
||||
# % is legal in the default $wgLegalTitleChars
|
||||
# This is so that ops know the real pywikibot will not
|
||||
# allow a useragent in the username to allow through a
|
||||
# hand-coded percent-encoded value.
|
||||
if "%" in username:
|
||||
username = quote(username)
|
||||
return username
|
||||
|
||||
|
||||
# https://github.com/afonasev/flake8-return/issues/116#issue-1367575481
|
||||
def no_exception_loop():
|
||||
success = False
|
||||
@@ -206,44 +260,3 @@ def nonlocal_assignment():
|
||||
nonlocal X
|
||||
X = 1
|
||||
return X
|
||||
|
||||
|
||||
def decorator() -> Flask:
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route('/hello')
|
||||
def hello() -> str:
|
||||
"""Hello endpoint."""
|
||||
return 'Hello, World!'
|
||||
|
||||
return app
|
||||
|
||||
|
||||
def default():
|
||||
y = 1
|
||||
|
||||
def f(x = y) -> X:
|
||||
return x
|
||||
|
||||
return y
|
||||
|
||||
|
||||
def get_queryset(option_1, option_2):
|
||||
queryset: Any = None
|
||||
queryset = queryset.filter(a=1)
|
||||
if option_1:
|
||||
queryset = queryset.annotate(b=Value(2))
|
||||
if option_2:
|
||||
queryset = queryset.filter(c=3)
|
||||
return queryset
|
||||
|
||||
|
||||
def get_queryset():
|
||||
queryset = Model.filter(a=1)
|
||||
queryset = queryset.filter(c=3)
|
||||
return queryset
|
||||
|
||||
|
||||
def get_queryset():
|
||||
queryset = Model.filter(a=1)
|
||||
return queryset # error
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
from typing import Tuple
|
||||
|
||||
x: Tuple
|
||||
@@ -1 +0,0 @@
|
||||
''' SAM macro definitions '''
|
||||
@@ -1,19 +0,0 @@
|
||||
x = "a string"
|
||||
y = "another string"
|
||||
z = ""
|
||||
|
||||
|
||||
def errors():
|
||||
if x is "" or x == "":
|
||||
print("x is an empty string")
|
||||
|
||||
if y is not "" or y != "":
|
||||
print("y is not an empty string")
|
||||
|
||||
if "" != z:
|
||||
print("z is an empty string")
|
||||
|
||||
|
||||
def ok():
|
||||
if x and not y:
|
||||
print("x is not an empty string, but y is an empty string")
|
||||
@@ -1,8 +0,0 @@
|
||||
import os
|
||||
|
||||
tempVar = os.getenv("TEST", 12) # [invalid-envvar-default]
|
||||
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("B", Z)
|
||||
@@ -1,12 +0,0 @@
|
||||
import os
|
||||
|
||||
os.getenv(1) # [invalid-envvar-value]
|
||||
os.getenv("a")
|
||||
os.getenv("test")
|
||||
os.getenv(key="testingAgain")
|
||||
os.getenv(key=11) # [invalid-envvar-value]
|
||||
os.getenv(["hello"]) # [invalid-envvar-value]
|
||||
os.getenv(key="foo", default="bar")
|
||||
|
||||
AA = "aa"
|
||||
os.getenv(AA)
|
||||
@@ -12,17 +12,11 @@ Ipsum
|
||||
""".encode(
|
||||
"utf-8"
|
||||
)
|
||||
(
|
||||
"Lorem "
|
||||
"Ipsum".encode()
|
||||
)
|
||||
(
|
||||
"Lorem " # Comment
|
||||
"Ipsum".encode() # Comment
|
||||
)
|
||||
(
|
||||
"Lorem " "Ipsum".encode()
|
||||
)
|
||||
# b"""
|
||||
# Lorem
|
||||
#
|
||||
# Ipsum
|
||||
# """
|
||||
|
||||
# `encode` on variables should not be processed.
|
||||
string = "hello there"
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
import socket
|
||||
|
||||
from kombu import Connection, exceptions
|
||||
|
||||
try:
|
||||
conn = Connection(settings.CELERY_BROKER_URL)
|
||||
conn.ensure_connection(max_retries=2)
|
||||
conn._close()
|
||||
except (socket.error, exceptions.OperationalError):
|
||||
return HttpResponseServerError("cache: cannot connect to broker.")
|
||||
@@ -41,7 +41,7 @@ if True:
|
||||
Good,
|
||||
)
|
||||
|
||||
from typing import Callable, Match, Pattern, List, OrderedDict, AbstractSet
|
||||
from typing import Callable, Match, Pattern, List
|
||||
|
||||
if True: from collections import (
|
||||
Mapping, Counter)
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
# noqa
|
||||
# noqa # comment
|
||||
print() # noqa
|
||||
print() # noqa # comment
|
||||
print(a) # noqa
|
||||
print(a) # noqa # comment
|
||||
|
||||
# noqa: E501, F821
|
||||
# noqa: E501, F821 # comment
|
||||
print() # noqa: E501, F821
|
||||
print() # noqa: E501, F821 # comment
|
||||
print(a) # noqa: E501, F821
|
||||
print(a) # noqa: E501, F821 # comment
|
||||
@@ -4,7 +4,7 @@ use rustc_hash::FxHashMap;
|
||||
use rustpython_parser::ast::ExcepthandlerKind::ExceptHandler;
|
||||
use rustpython_parser::ast::{Stmt, StmtKind};
|
||||
|
||||
use crate::types::RefEquality;
|
||||
use crate::ast::types::RefEquality;
|
||||
|
||||
/// Return the common ancestor of `left` and `right` below `stop`, or `None`.
|
||||
fn common_ancestor<'a>(
|
||||
@@ -1,14 +1,13 @@
|
||||
//! An equivalent object hierarchy to the [`Expr`] hierarchy, but with the
|
||||
//! ability to compare expressions for equality (via [`Eq`] and [`Hash`]).
|
||||
|
||||
use num_bigint::BigInt;
|
||||
use rustpython_parser::ast::{
|
||||
Alias, Arg, Arguments, Boolop, Cmpop, Comprehension, Constant, Excepthandler,
|
||||
ExcepthandlerKind, Expr, ExprContext, ExprKind, Keyword, MatchCase, Operator, Pattern,
|
||||
PatternKind, Stmt, StmtKind, Unaryop, Withitem,
|
||||
};
|
||||
|
||||
use num_bigint::BigInt;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
pub enum ComparableExprContext {
|
||||
Load,
|
||||
@@ -5,11 +5,11 @@ use rustc_hash::FxHashMap;
|
||||
use rustpython_parser::ast::{Expr, Stmt};
|
||||
use smallvec::smallvec;
|
||||
|
||||
use ruff_python_stdlib::path::is_python_stub_file;
|
||||
use ruff_python_stdlib::typing::TYPING_EXTENSIONS;
|
||||
use ruff_python::typing::TYPING_EXTENSIONS;
|
||||
|
||||
use crate::helpers::{collect_call_path, from_relative_import, Exceptions};
|
||||
use crate::types::{Binding, BindingKind, CallPath, ExecutionContext, RefEquality, Scope};
|
||||
use crate::ast::helpers::{collect_call_path, from_relative_import, Exceptions};
|
||||
use crate::ast::types::{Binding, BindingKind, CallPath, ExecutionContext, RefEquality, Scope};
|
||||
use crate::resolver::is_interface_definition_path;
|
||||
use crate::visibility::{module_visibility, Modifier, VisibleScope};
|
||||
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
@@ -82,7 +82,7 @@ impl<'a> Context<'a> {
|
||||
in_type_checking_block: false,
|
||||
seen_import_boundary: false,
|
||||
futures_allowed: true,
|
||||
annotations_future_enabled: is_python_stub_file(path),
|
||||
annotations_future_enabled: is_interface_definition_path(path),
|
||||
handled_exceptions: Vec::default(),
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
use rustpython_parser::ast::Expr;
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::helpers::{map_callable, to_call_path};
|
||||
use crate::types::{Scope, ScopeKind};
|
||||
use crate::ast::context::Context;
|
||||
use crate::ast::helpers::{map_callable, to_call_path};
|
||||
use crate::ast::types::{Scope, ScopeKind};
|
||||
|
||||
const CLASS_METHODS: [&str; 3] = ["__new__", "__init_subclass__", "__class_getitem__"];
|
||||
const METACLASS_BASES: [(&str, &str); 2] = [("", "type"), ("abc", "ABCMeta")];
|
||||
@@ -2,7 +2,7 @@ use std::hash::Hash;
|
||||
|
||||
use rustpython_parser::ast::Expr;
|
||||
|
||||
use crate::comparable::ComparableExpr;
|
||||
use crate::ast::comparable::ComparableExpr;
|
||||
|
||||
/// Wrapper around `Expr` that implements `Hash` and `PartialEq`.
|
||||
pub struct HashableExpr<'a>(&'a Expr);
|
||||
@@ -30,11 +30,11 @@ impl<'a> From<&'a Expr> for HashableExpr<'a> {
|
||||
}
|
||||
|
||||
impl<'a> HashableExpr<'a> {
|
||||
pub const fn from_expr(expr: &'a Expr) -> Self {
|
||||
pub(crate) const fn from_expr(expr: &'a Expr) -> Self {
|
||||
Self(expr)
|
||||
}
|
||||
|
||||
pub const fn as_expr(&self) -> &'a Expr {
|
||||
pub(crate) const fn as_expr(&self) -> &'a Expr {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
@@ -13,12 +13,11 @@ use rustpython_parser::ast::{
|
||||
use rustpython_parser::{lexer, Mode, StringKind, Tok};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::newlines::StrExt;
|
||||
use crate::ast::context::Context;
|
||||
use crate::ast::types::{Binding, BindingKind, CallPath, Range};
|
||||
use crate::ast::visitor;
|
||||
use crate::ast::visitor::Visitor;
|
||||
use crate::source_code::{Generator, Indexer, Locator, Stylist};
|
||||
use crate::types::{Binding, BindingKind, CallPath, Range};
|
||||
use crate::visitor;
|
||||
use crate::visitor::Visitor;
|
||||
|
||||
/// Create an `Expr` with default location from an `ExprKind`.
|
||||
pub fn create_expr(node: ExprKind) -> Expr {
|
||||
@@ -653,7 +652,7 @@ pub fn has_comments<T>(located: &Located<T>, locator: &Locator) -> bool {
|
||||
|
||||
/// Returns `true` if a [`Range`] includes at least one comment.
|
||||
pub fn has_comments_in(range: Range, locator: &Locator) -> bool {
|
||||
for tok in lexer::lex_located(locator.slice(range), Mode::Module, range.location) {
|
||||
for tok in lexer::lex_located(locator.slice(&range), Mode::Module, range.location) {
|
||||
match tok {
|
||||
Ok((_, tok, _)) => {
|
||||
if matches!(tok, Tok::Comment(..)) {
|
||||
@@ -742,7 +741,7 @@ pub fn to_module_path(package: &Path, path: &Path) -> Option<Vec<String>> {
|
||||
.ok()?
|
||||
.iter()
|
||||
.map(Path::new)
|
||||
.map(Path::file_stem)
|
||||
.map(std::path::Path::file_stem)
|
||||
.map(|path| path.and_then(|path| path.to_os_string().into_string().ok()))
|
||||
.collect::<Option<Vec<String>>>()
|
||||
}
|
||||
@@ -800,7 +799,7 @@ where
|
||||
match &stmt.node {
|
||||
StmtKind::Raise { exc, cause } => {
|
||||
self.raises
|
||||
.push((Range::from(stmt), exc.as_deref(), cause.as_deref()));
|
||||
.push((Range::from_located(stmt), exc.as_deref(), cause.as_deref()));
|
||||
}
|
||||
StmtKind::ClassDef { .. }
|
||||
| StmtKind::FunctionDef { .. }
|
||||
@@ -855,7 +854,7 @@ pub fn to_relative(absolute: Location, base: Location) -> Location {
|
||||
/// Return `true` if a [`Located`] has leading content.
|
||||
pub fn match_leading_content<T>(located: &Located<T>, locator: &Locator) -> bool {
|
||||
let range = Range::new(Location::new(located.location.row(), 0), located.location);
|
||||
let prefix = locator.slice(range);
|
||||
let prefix = locator.slice(&range);
|
||||
prefix.chars().any(|char| !char.is_whitespace())
|
||||
}
|
||||
|
||||
@@ -865,7 +864,7 @@ pub fn match_trailing_content<T>(located: &Located<T>, locator: &Locator) -> boo
|
||||
located.end_location.unwrap(),
|
||||
Location::new(located.end_location.unwrap().row() + 1, 0),
|
||||
);
|
||||
let suffix = locator.slice(range);
|
||||
let suffix = locator.slice(&range);
|
||||
for char in suffix.chars() {
|
||||
if char == '#' {
|
||||
return false;
|
||||
@@ -883,7 +882,7 @@ pub fn match_trailing_comment<T>(located: &Located<T>, locator: &Locator) -> Opt
|
||||
located.end_location.unwrap(),
|
||||
Location::new(located.end_location.unwrap().row() + 1, 0),
|
||||
);
|
||||
let suffix = locator.slice(range);
|
||||
let suffix = locator.slice(&range);
|
||||
for (i, char) in suffix.chars().enumerate() {
|
||||
if char == '#' {
|
||||
return Some(i);
|
||||
@@ -941,7 +940,7 @@ pub fn identifier_range(stmt: &Stmt, locator: &Locator) -> Range {
|
||||
| StmtKind::FunctionDef { .. }
|
||||
| StmtKind::AsyncFunctionDef { .. }
|
||||
) {
|
||||
let contents = locator.slice(stmt);
|
||||
let contents = locator.slice(&Range::from_located(stmt));
|
||||
for (start, tok, end) in lexer::lex_located(contents, Mode::Module, stmt.location).flatten()
|
||||
{
|
||||
if matches!(tok, Tok::Name { .. }) {
|
||||
@@ -950,7 +949,7 @@ pub fn identifier_range(stmt: &Stmt, locator: &Locator) -> Range {
|
||||
}
|
||||
error!("Failed to find identifier for {:?}", stmt);
|
||||
}
|
||||
Range::from(stmt)
|
||||
Range::from_located(stmt)
|
||||
}
|
||||
|
||||
/// Like `identifier_range`, but accepts a `Binding`.
|
||||
@@ -968,12 +967,12 @@ pub fn binding_range(binding: &Binding, locator: &Locator) -> Range {
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the ranges of [`Tok::Name`] tokens within a specified node.
|
||||
pub fn find_names<'a, T>(
|
||||
located: &'a Located<T>,
|
||||
// Return the ranges of `Name` tokens within a specified node.
|
||||
pub fn find_names<'a, T, U>(
|
||||
located: &'a Located<T, U>,
|
||||
locator: &'a Locator,
|
||||
) -> impl Iterator<Item = Range> + 'a {
|
||||
let contents = locator.slice(located);
|
||||
let contents = locator.slice(&Range::from_located(located));
|
||||
lexer::lex_located(contents, Mode::Module, located.location)
|
||||
.flatten()
|
||||
.filter(|(_, tok, _)| matches!(tok, Tok::Name { .. }))
|
||||
@@ -991,7 +990,7 @@ pub fn excepthandler_name_range(handler: &Excepthandler, locator: &Locator) -> O
|
||||
match (name, type_) {
|
||||
(Some(_), Some(type_)) => {
|
||||
let type_end_location = type_.end_location.unwrap();
|
||||
let contents = locator.slice(Range::new(type_end_location, body[0].location));
|
||||
let contents = locator.slice(&Range::new(type_end_location, body[0].location));
|
||||
let range = lexer::lex_located(contents, Mode::Module, type_end_location)
|
||||
.flatten()
|
||||
.tuple_windows()
|
||||
@@ -1015,7 +1014,7 @@ pub fn except_range(handler: &Excepthandler, locator: &Locator) -> Range {
|
||||
.expect("Expected body to be non-empty")
|
||||
.location
|
||||
};
|
||||
let contents = locator.slice(Range {
|
||||
let contents = locator.slice(&Range {
|
||||
location: handler.location,
|
||||
end_location: end,
|
||||
});
|
||||
@@ -1032,7 +1031,7 @@ pub fn except_range(handler: &Excepthandler, locator: &Locator) -> Range {
|
||||
|
||||
/// Find f-strings that don't contain any formatted values in a `JoinedStr`.
|
||||
pub fn find_useless_f_strings(expr: &Expr, locator: &Locator) -> Vec<(Range, Range)> {
|
||||
let contents = locator.slice(expr);
|
||||
let contents = locator.slice(&Range::from_located(expr));
|
||||
lexer::lex_located(contents, Mode::Module, expr.location)
|
||||
.flatten()
|
||||
.filter_map(|(location, tok, end_location)| match tok {
|
||||
@@ -1040,7 +1039,7 @@ pub fn find_useless_f_strings(expr: &Expr, locator: &Locator) -> Vec<(Range, Ran
|
||||
kind: StringKind::FString | StringKind::RawFString,
|
||||
..
|
||||
} => {
|
||||
let first_char = locator.slice(Range {
|
||||
let first_char = locator.slice(&Range {
|
||||
location,
|
||||
end_location: Location::new(location.row(), location.column() + 1),
|
||||
});
|
||||
@@ -1080,7 +1079,7 @@ pub fn else_range(stmt: &Stmt, locator: &Locator) -> Option<Range> {
|
||||
.expect("Expected body to be non-empty")
|
||||
.end_location
|
||||
.unwrap();
|
||||
let contents = locator.slice(Range {
|
||||
let contents = locator.slice(&Range {
|
||||
location: body_end,
|
||||
end_location: orelse
|
||||
.first()
|
||||
@@ -1102,7 +1101,7 @@ pub fn else_range(stmt: &Stmt, locator: &Locator) -> Option<Range> {
|
||||
|
||||
/// Return the `Range` of the first `Tok::Colon` token in a `Range`.
|
||||
pub fn first_colon_range(range: Range, locator: &Locator) -> Option<Range> {
|
||||
let contents = locator.slice(range);
|
||||
let contents = locator.slice(&range);
|
||||
let range = lexer::lex_located(contents, Mode::Module, range.location)
|
||||
.flatten()
|
||||
.find(|(_, kind, _)| matches!(kind, Tok::Colon))
|
||||
@@ -1126,7 +1125,7 @@ pub fn end_of_statement(stmt: &Stmt, locator: &Locator) -> Location {
|
||||
}
|
||||
|
||||
// Otherwise, find the end of the last line that's "part of" the statement.
|
||||
for (lineno, line) in contents.universal_newlines().enumerate() {
|
||||
for (lineno, line) in contents.lines().enumerate() {
|
||||
if line.ends_with('\\') {
|
||||
continue;
|
||||
}
|
||||
@@ -1158,7 +1157,7 @@ pub fn elif_else_range(stmt: &Stmt, locator: &Locator) -> Option<Range> {
|
||||
[stmt, ..] => stmt.location,
|
||||
_ => return None,
|
||||
};
|
||||
let contents = locator.slice(Range::new(start, end));
|
||||
let contents = locator.slice(&Range::new(start, end));
|
||||
let range = lexer::lex_located(contents, Mode::Module, start)
|
||||
.flatten()
|
||||
.find(|(_, kind, _)| matches!(kind, Tok::Elif | Tok::Else))
|
||||
@@ -1213,50 +1212,48 @@ pub struct SimpleCallArgs<'a> {
|
||||
}
|
||||
|
||||
impl<'a> SimpleCallArgs<'a> {
|
||||
pub fn new(
|
||||
args: impl IntoIterator<Item = &'a Expr>,
|
||||
keywords: impl IntoIterator<Item = &'a Keyword>,
|
||||
) -> Self {
|
||||
let args = args
|
||||
.into_iter()
|
||||
.take_while(|arg| !matches!(arg.node, ExprKind::Starred { .. }))
|
||||
.collect();
|
||||
pub fn new(args: &'a [Expr], keywords: &'a [Keyword]) -> Self {
|
||||
let mut result = SimpleCallArgs::default();
|
||||
|
||||
let kwargs = keywords
|
||||
.into_iter()
|
||||
.filter_map(|keyword| {
|
||||
let node = &keyword.node;
|
||||
node.arg.as_ref().map(|arg| (arg.as_ref(), &node.value))
|
||||
})
|
||||
.collect();
|
||||
for arg in args {
|
||||
match &arg.node {
|
||||
ExprKind::Starred { .. } => {
|
||||
break;
|
||||
}
|
||||
_ => {
|
||||
result.args.push(arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SimpleCallArgs { args, kwargs }
|
||||
}
|
||||
for keyword in keywords {
|
||||
if let Some(arg) = &keyword.node.arg {
|
||||
result.kwargs.insert(arg, &keyword.node.value);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the argument with the given name.
|
||||
/// If the argument is not found by name, return
|
||||
/// `None`.
|
||||
pub fn keyword_argument(&self, name: &str) -> Option<&'a Expr> {
|
||||
self.kwargs.get(name).copied()
|
||||
result
|
||||
}
|
||||
|
||||
/// Get the argument with the given name or position.
|
||||
/// If the argument is not found with either name or position, return
|
||||
/// `None`.
|
||||
pub fn argument(&self, name: &str, position: usize) -> Option<&'a Expr> {
|
||||
self.keyword_argument(name)
|
||||
.or_else(|| self.args.get(position).copied())
|
||||
pub fn get_argument(&self, name: &'a str, position: Option<usize>) -> Option<&'a Expr> {
|
||||
if let Some(kwarg) = self.kwargs.get(name) {
|
||||
return Some(kwarg);
|
||||
}
|
||||
if let Some(position) = position {
|
||||
if position < self.args.len() {
|
||||
return Some(self.args[position]);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Return the number of positional and keyword arguments.
|
||||
/// Get the number of positional and keyword arguments used.
|
||||
pub fn len(&self) -> usize {
|
||||
self.args.len() + self.kwargs.len()
|
||||
}
|
||||
|
||||
/// Return `true` if there are no positional or keyword arguments.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
}
|
||||
|
||||
/// Return `true` if the given `Expr` is a potential logging call. Matches
|
||||
@@ -1280,11 +1277,11 @@ mod tests {
|
||||
use rustpython_parser as parser;
|
||||
use rustpython_parser::ast::Location;
|
||||
|
||||
use crate::helpers::{
|
||||
use crate::ast::helpers::{
|
||||
elif_else_range, else_range, first_colon_range, identifier_range, match_trailing_content,
|
||||
};
|
||||
use crate::ast::types::Range;
|
||||
use crate::source_code::Locator;
|
||||
use crate::types::Range;
|
||||
|
||||
#[test]
|
||||
fn trailing_content() -> Result<()> {
|
||||
@@ -9,7 +9,7 @@ pub enum LoggingLevel {
|
||||
}
|
||||
|
||||
impl LoggingLevel {
|
||||
pub fn from_attribute(level: &str) -> Option<Self> {
|
||||
pub fn from_str(level: &str) -> Option<Self> {
|
||||
match level {
|
||||
"debug" => Some(LoggingLevel::Debug),
|
||||
"critical" => Some(LoggingLevel::Critical),
|
||||
@@ -6,13 +6,9 @@ pub mod function_type;
|
||||
pub mod hashable;
|
||||
pub mod helpers;
|
||||
pub mod logging;
|
||||
pub mod newlines;
|
||||
pub mod operations;
|
||||
pub mod relocate;
|
||||
pub mod source_code;
|
||||
pub mod str;
|
||||
pub mod types;
|
||||
pub mod typing;
|
||||
pub mod visibility;
|
||||
pub mod visitor;
|
||||
pub mod whitespace;
|
||||
@@ -3,11 +3,11 @@ use rustc_hash::FxHashMap;
|
||||
use rustpython_parser::ast::{Cmpop, Constant, Expr, ExprKind, Located, Stmt, StmtKind};
|
||||
use rustpython_parser::{lexer, Mode, Tok};
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::helpers::any_over_expr;
|
||||
use crate::types::{BindingKind, Scope};
|
||||
use crate::visitor;
|
||||
use crate::visitor::Visitor;
|
||||
use crate::ast::context::Context;
|
||||
use crate::ast::helpers::any_over_expr;
|
||||
use crate::ast::types::{BindingKind, Scope};
|
||||
use crate::ast::visitor;
|
||||
use crate::ast::visitor::Visitor;
|
||||
|
||||
bitflags! {
|
||||
#[derive(Default)]
|
||||
@@ -348,7 +348,7 @@ pub fn locate_cmpops(contents: &str) -> Vec<LocatedCmpop> {
|
||||
mod tests {
|
||||
use rustpython_parser::ast::{Cmpop, Location};
|
||||
|
||||
use crate::operations::{locate_cmpops, LocatedCmpop};
|
||||
use crate::ast::operations::{locate_cmpops, LocatedCmpop};
|
||||
|
||||
#[test]
|
||||
fn locates_cmpops() {
|
||||
@@ -1,6 +1,6 @@
|
||||
use rustpython_parser::ast::{Expr, ExprKind, Keyword};
|
||||
|
||||
use crate::types::Range;
|
||||
use crate::ast::types::Range;
|
||||
|
||||
fn relocate_keyword(keyword: &mut Keyword, location: Range) {
|
||||
keyword.location = location.location;
|
||||
@@ -28,17 +28,13 @@ impl Range {
|
||||
end_location,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<&Located<T>> for Range {
|
||||
fn from(located: &Located<T>) -> Self {
|
||||
pub fn from_located<T, U>(located: &Located<T, U>) -> Self {
|
||||
Range::new(located.location, located.end_location.unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<&Box<Located<T>>> for Range {
|
||||
fn from(located: &Box<Located<T>>) -> Self {
|
||||
Range::new(located.location, located.end_location.unwrap())
|
||||
pub fn contains(&self, other: &Range) -> bool {
|
||||
self.location <= other.location && self.end_location >= other.end_location
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use ruff_python_stdlib::typing::{PEP_585_BUILTINS_ELIGIBLE, PEP_593_SUBSCRIPTS, SUBSCRIPTS};
|
||||
use ruff_python::typing::{PEP_585_BUILTINS_ELIGIBLE, PEP_593_SUBSCRIPTS, SUBSCRIPTS};
|
||||
use rustpython_parser::ast::{Expr, ExprKind};
|
||||
|
||||
use crate::types::CallPath;
|
||||
use crate::ast::types::CallPath;
|
||||
|
||||
pub enum Callable {
|
||||
ForwardRef,
|
||||
@@ -1,12 +1,14 @@
|
||||
use std::str::Lines;
|
||||
|
||||
use rustpython_parser::ast::{Located, Location};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::source_code::Locator;
|
||||
use crate::types::Range;
|
||||
|
||||
/// Extract the leading indentation from a line.
|
||||
pub fn indentation<'a, T>(locator: &'a Locator, located: &'a Located<T>) -> Option<&'a str> {
|
||||
let range = Range::from(located);
|
||||
let indentation = locator.slice(Range::new(
|
||||
let range = Range::from_located(located);
|
||||
let indentation = locator.slice(&Range::new(
|
||||
Location::new(range.location.row(), 0),
|
||||
Location::new(range.location.row(), range.location.column()),
|
||||
));
|
||||
@@ -37,3 +39,38 @@ pub fn clean(indentation: &str) -> String {
|
||||
.map(|char| if char.is_whitespace() { char } else { ' ' })
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Like `str#lines`, but includes a trailing newline as an empty line.
|
||||
pub struct LinesWithTrailingNewline<'a> {
|
||||
trailing: Option<&'a str>,
|
||||
underlying: Lines<'a>,
|
||||
}
|
||||
|
||||
impl<'a> LinesWithTrailingNewline<'a> {
|
||||
pub fn from(input: &'a str) -> LinesWithTrailingNewline<'a> {
|
||||
LinesWithTrailingNewline {
|
||||
underlying: input.lines(),
|
||||
trailing: if input.ends_with('\n') {
|
||||
Some("")
|
||||
} else {
|
||||
None
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for LinesWithTrailingNewline<'a> {
|
||||
type Item = &'a str;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<&'a str> {
|
||||
let mut next = self.underlying.next();
|
||||
if next.is_none() {
|
||||
if self.trailing.is_some() {
|
||||
next = self.trailing;
|
||||
self.trailing = None;
|
||||
}
|
||||
}
|
||||
next
|
||||
}
|
||||
}
|
||||
@@ -6,14 +6,14 @@ use libcst_native::{
|
||||
use rustpython_parser::ast::{ExcepthandlerKind, Expr, Keyword, Location, Stmt, StmtKind};
|
||||
use rustpython_parser::{lexer, Mode, Tok};
|
||||
|
||||
use ruff_diagnostics::Fix;
|
||||
use ruff_python_ast::helpers;
|
||||
use ruff_python_ast::helpers::to_absolute;
|
||||
use ruff_python_ast::newlines::NewlineWithTrailingNewline;
|
||||
use ruff_python_ast::source_code::{Indexer, Locator, Stylist};
|
||||
|
||||
use crate::ast::helpers;
|
||||
use crate::ast::helpers::to_absolute;
|
||||
use crate::ast::types::Range;
|
||||
use crate::ast::whitespace::LinesWithTrailingNewline;
|
||||
use crate::cst::helpers::compose_module_path;
|
||||
use crate::cst::matchers::match_module;
|
||||
use crate::fix::Fix;
|
||||
use crate::source_code::{Indexer, Locator, Stylist};
|
||||
|
||||
/// Determine if a body contains only a single statement, taking into account
|
||||
/// deleted.
|
||||
@@ -100,7 +100,7 @@ fn is_lone_child(child: &Stmt, parent: &Stmt, deleted: &[&Stmt]) -> Result<bool>
|
||||
/// of a multi-statement line.
|
||||
fn trailing_semicolon(stmt: &Stmt, locator: &Locator) -> Option<Location> {
|
||||
let contents = locator.skip(stmt.end_location.unwrap());
|
||||
for (row, line) in NewlineWithTrailingNewline::from(contents).enumerate() {
|
||||
for (row, line) in LinesWithTrailingNewline::from(contents).enumerate() {
|
||||
let trimmed = line.trim();
|
||||
if trimmed.starts_with(';') {
|
||||
let column = line
|
||||
@@ -123,7 +123,7 @@ fn trailing_semicolon(stmt: &Stmt, locator: &Locator) -> Option<Location> {
|
||||
fn next_stmt_break(semicolon: Location, locator: &Locator) -> Location {
|
||||
let start_location = Location::new(semicolon.row(), semicolon.column() + 1);
|
||||
let contents = locator.skip(start_location);
|
||||
for (row, line) in NewlineWithTrailingNewline::from(contents).enumerate() {
|
||||
for (row, line) in LinesWithTrailingNewline::from(contents).enumerate() {
|
||||
let trimmed = line.trim();
|
||||
// Skip past any continuations.
|
||||
if trimmed.starts_with('\\') {
|
||||
@@ -227,7 +227,7 @@ pub fn remove_unused_imports<'a>(
|
||||
indexer: &Indexer,
|
||||
stylist: &Stylist,
|
||||
) -> Result<Fix> {
|
||||
let module_text = locator.slice(stmt);
|
||||
let module_text = locator.slice(&Range::from_located(stmt));
|
||||
let mut tree = match_module(module_text)?;
|
||||
|
||||
let Some(Statement::Simple(body)) = tree.body.first_mut() else {
|
||||
@@ -450,9 +450,8 @@ mod tests {
|
||||
use rustpython_parser as parser;
|
||||
use rustpython_parser::ast::Location;
|
||||
|
||||
use ruff_python_ast::source_code::Locator;
|
||||
|
||||
use crate::autofix::helpers::{next_stmt_break, trailing_semicolon};
|
||||
use crate::source_code::Locator;
|
||||
|
||||
#[test]
|
||||
fn find_semicolon() -> Result<()> {
|
||||
|
||||
@@ -4,12 +4,11 @@ use itertools::Itertools;
|
||||
use rustc_hash::FxHashMap;
|
||||
use rustpython_parser::ast::Location;
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Fix};
|
||||
use ruff_python_ast::source_code::Locator;
|
||||
use ruff_python_ast::types::Range;
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::fix::Fix;
|
||||
use crate::linter::FixTable;
|
||||
use crate::registry::AsRule;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::source_code::Locator;
|
||||
|
||||
pub mod helpers;
|
||||
|
||||
@@ -55,7 +54,7 @@ fn apply_fixes<'a>(
|
||||
}
|
||||
|
||||
// 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, fix.location));
|
||||
output.push_str(slice);
|
||||
|
||||
// Add the patch itself.
|
||||
@@ -79,7 +78,7 @@ pub(crate) fn apply_fix(fix: &Fix, locator: &Locator) -> String {
|
||||
let mut output = String::with_capacity(locator.len());
|
||||
|
||||
// Add all contents from `last_pos` to `fix.location`.
|
||||
let slice = locator.slice(Range::new(Location::new(1, 0), fix.location));
|
||||
let slice = locator.slice(&Range::new(Location::new(1, 0), fix.location));
|
||||
output.push_str(slice);
|
||||
|
||||
// Add the patch itself.
|
||||
@@ -96,38 +95,43 @@ pub(crate) fn apply_fix(fix: &Fix, locator: &Locator) -> String {
|
||||
mod tests {
|
||||
use rustpython_parser::ast::Location;
|
||||
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
use ruff_diagnostics::Fix;
|
||||
use ruff_python_ast::source_code::Locator;
|
||||
|
||||
use crate::autofix::{apply_fix, apply_fixes};
|
||||
use crate::fix::Fix;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::rules::pycodestyle::rules::NoNewLineAtEndOfFile;
|
||||
|
||||
fn create_diagnostics(fixes: impl IntoIterator<Item = Fix>) -> Vec<Diagnostic> {
|
||||
fixes
|
||||
.into_iter()
|
||||
.map(|fix| Diagnostic {
|
||||
use crate::source_code::Locator;
|
||||
|
||||
#[test]
|
||||
fn empty_file() {
|
||||
let fixes: Vec<Diagnostic> = vec![];
|
||||
let locator = Locator::new(r#""#);
|
||||
let (contents, fixed) = apply_fixes(fixes.iter(), &locator);
|
||||
assert_eq!(contents, "");
|
||||
assert_eq!(fixed.values().sum::<usize>(), 0);
|
||||
}
|
||||
|
||||
impl From<Fix> for Diagnostic {
|
||||
fn from(fix: Fix) -> Self {
|
||||
Diagnostic {
|
||||
// The choice of rule here is arbitrary.
|
||||
kind: NoNewLineAtEndOfFile.into(),
|
||||
location: fix.location,
|
||||
end_location: fix.end_location,
|
||||
fix: Some(fix),
|
||||
parent: None,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_file() {
|
||||
let locator = Locator::new(r#""#);
|
||||
let diagnostics = create_diagnostics([]);
|
||||
let (contents, fixed) = apply_fixes(diagnostics.iter(), &locator);
|
||||
assert_eq!(contents, "");
|
||||
assert_eq!(fixed.values().sum::<usize>(), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn apply_one_replacement() {
|
||||
let fixes: Vec<Diagnostic> = vec![Fix {
|
||||
content: "Bar".to_string(),
|
||||
location: Location::new(1, 8),
|
||||
end_location: Location::new(1, 14),
|
||||
}
|
||||
.into()];
|
||||
let locator = Locator::new(
|
||||
r#"
|
||||
class A(object):
|
||||
@@ -135,12 +139,7 @@ class A(object):
|
||||
"#
|
||||
.trim(),
|
||||
);
|
||||
let diagnostics = create_diagnostics([Fix {
|
||||
content: "Bar".to_string(),
|
||||
location: Location::new(1, 8),
|
||||
end_location: Location::new(1, 14),
|
||||
}]);
|
||||
let (contents, fixed) = apply_fixes(diagnostics.iter(), &locator);
|
||||
let (contents, fixed) = apply_fixes(fixes.iter(), &locator);
|
||||
assert_eq!(
|
||||
contents,
|
||||
r#"
|
||||
@@ -154,6 +153,12 @@ class A(Bar):
|
||||
|
||||
#[test]
|
||||
fn apply_one_removal() {
|
||||
let fixes: Vec<Diagnostic> = vec![Fix {
|
||||
content: String::new(),
|
||||
location: Location::new(1, 7),
|
||||
end_location: Location::new(1, 15),
|
||||
}
|
||||
.into()];
|
||||
let locator = Locator::new(
|
||||
r#"
|
||||
class A(object):
|
||||
@@ -161,12 +166,7 @@ class A(object):
|
||||
"#
|
||||
.trim(),
|
||||
);
|
||||
let diagnostics = create_diagnostics([Fix {
|
||||
content: String::new(),
|
||||
location: Location::new(1, 7),
|
||||
end_location: Location::new(1, 15),
|
||||
}]);
|
||||
let (contents, fixed) = apply_fixes(diagnostics.iter(), &locator);
|
||||
let (contents, fixed) = apply_fixes(fixes.iter(), &locator);
|
||||
assert_eq!(
|
||||
contents,
|
||||
r#"
|
||||
@@ -180,6 +180,20 @@ class A:
|
||||
|
||||
#[test]
|
||||
fn apply_two_removals() {
|
||||
let fixes: Vec<Diagnostic> = vec![
|
||||
Fix {
|
||||
content: String::new(),
|
||||
location: Location::new(1, 7),
|
||||
end_location: Location::new(1, 16),
|
||||
}
|
||||
.into(),
|
||||
Fix {
|
||||
content: String::new(),
|
||||
location: Location::new(1, 16),
|
||||
end_location: Location::new(1, 23),
|
||||
}
|
||||
.into(),
|
||||
];
|
||||
let locator = Locator::new(
|
||||
r#"
|
||||
class A(object, object):
|
||||
@@ -187,19 +201,7 @@ class A(object, object):
|
||||
"#
|
||||
.trim(),
|
||||
);
|
||||
let diagnostics = create_diagnostics([
|
||||
Fix {
|
||||
content: String::new(),
|
||||
location: Location::new(1, 7),
|
||||
end_location: Location::new(1, 16),
|
||||
},
|
||||
Fix {
|
||||
content: String::new(),
|
||||
location: Location::new(1, 16),
|
||||
end_location: Location::new(1, 23),
|
||||
},
|
||||
]);
|
||||
let (contents, fixed) = apply_fixes(diagnostics.iter(), &locator);
|
||||
let (contents, fixed) = apply_fixes(fixes.iter(), &locator);
|
||||
|
||||
assert_eq!(
|
||||
contents,
|
||||
@@ -214,6 +216,20 @@ class A:
|
||||
|
||||
#[test]
|
||||
fn ignore_overlapping_fixes() {
|
||||
let fixes: Vec<Diagnostic> = vec![
|
||||
Fix {
|
||||
content: String::new(),
|
||||
location: Location::new(1, 7),
|
||||
end_location: Location::new(1, 15),
|
||||
}
|
||||
.into(),
|
||||
Fix {
|
||||
content: "ignored".to_string(),
|
||||
location: Location::new(1, 9),
|
||||
end_location: Location::new(1, 11),
|
||||
}
|
||||
.into(),
|
||||
];
|
||||
let locator = Locator::new(
|
||||
r#"
|
||||
class A(object):
|
||||
@@ -221,19 +237,7 @@ class A(object):
|
||||
"#
|
||||
.trim(),
|
||||
);
|
||||
let diagnostics = create_diagnostics([
|
||||
Fix {
|
||||
content: String::new(),
|
||||
location: Location::new(1, 7),
|
||||
end_location: Location::new(1, 15),
|
||||
},
|
||||
Fix {
|
||||
content: "ignored".to_string(),
|
||||
location: Location::new(1, 9),
|
||||
end_location: Location::new(1, 11),
|
||||
},
|
||||
]);
|
||||
let (contents, fixed) = apply_fixes(diagnostics.iter(), &locator);
|
||||
let (contents, fixed) = apply_fixes(fixes.iter(), &locator);
|
||||
assert_eq!(
|
||||
contents,
|
||||
r#"
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
use rustpython_parser::ast::{Expr, Stmt};
|
||||
|
||||
use ruff_python_ast::types::Range;
|
||||
use ruff_python_ast::types::RefEquality;
|
||||
use ruff_python_ast::visibility::{Visibility, VisibleScope};
|
||||
|
||||
use crate::ast::types::RefEquality;
|
||||
use crate::checkers::ast::AnnotationContext;
|
||||
use crate::docstrings::definition::Definition;
|
||||
use crate::visibility::{Visibility, VisibleScope};
|
||||
use crate::Range;
|
||||
|
||||
type Context<'a> = (Vec<usize>, Vec<RefEquality<'a, Stmt>>);
|
||||
|
||||
|
||||
@@ -13,31 +13,23 @@ use rustpython_parser::ast::{
|
||||
Suite,
|
||||
};
|
||||
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
use ruff_python_ast::context::Context;
|
||||
use ruff_python_ast::helpers::{
|
||||
binding_range, extract_handled_exceptions, to_module_path, Exceptions,
|
||||
};
|
||||
use ruff_python_ast::operations::{extract_all_names, AllNamesFlags};
|
||||
use ruff_python_ast::relocate::relocate_expr;
|
||||
use ruff_python_ast::source_code::{Indexer, Locator, Stylist};
|
||||
use ruff_python_ast::types::{
|
||||
use ruff_python::builtins::{BUILTINS, MAGIC_GLOBALS};
|
||||
|
||||
use crate::ast::context::Context;
|
||||
use crate::ast::helpers::{binding_range, extract_handled_exceptions, to_module_path, Exceptions};
|
||||
use crate::ast::operations::{extract_all_names, AllNamesFlags};
|
||||
use crate::ast::relocate::relocate_expr;
|
||||
use crate::ast::types::{
|
||||
Binding, BindingKind, ClassDef, ExecutionContext, FunctionDef, Lambda, Node, Range,
|
||||
RefEquality, Scope, ScopeKind,
|
||||
};
|
||||
use ruff_python_ast::typing::{match_annotated_subscript, Callable, SubscriptKind};
|
||||
use ruff_python_ast::visitor::{walk_excepthandler, walk_pattern, Visitor};
|
||||
use ruff_python_ast::{
|
||||
branch_detection, cast, helpers, operations, str, typing, visibility, visitor,
|
||||
};
|
||||
use ruff_python_stdlib::builtins::{BUILTINS, MAGIC_GLOBALS};
|
||||
use ruff_python_stdlib::path::is_python_stub_file;
|
||||
|
||||
use crate::ast::typing::{match_annotated_subscript, Callable, SubscriptKind};
|
||||
use crate::ast::visitor::{walk_excepthandler, walk_pattern, Visitor};
|
||||
use crate::ast::{branch_detection, cast, helpers, operations, typing, visitor};
|
||||
use crate::checkers::ast::deferred::Deferred;
|
||||
use crate::docstrings::definition::{
|
||||
transition_scope, Definition, DefinitionKind, Docstring, Documentable,
|
||||
};
|
||||
use crate::registry::{AsRule, Rule};
|
||||
use crate::docstrings::definition::{Definition, DefinitionKind, Docstring, Documentable};
|
||||
use crate::registry::{Diagnostic, Rule};
|
||||
use crate::resolver::is_interface_definition_path;
|
||||
use crate::rules::{
|
||||
flake8_2020, flake8_annotations, flake8_bandit, flake8_blind_except, flake8_boolean_trap,
|
||||
flake8_bugbear, flake8_builtins, flake8_comprehensions, flake8_datetimez, flake8_debugger,
|
||||
@@ -49,7 +41,9 @@ use crate::rules::{
|
||||
};
|
||||
use crate::settings::types::PythonVersion;
|
||||
use crate::settings::{flags, Settings};
|
||||
use crate::{autofix, docstrings, noqa};
|
||||
use crate::source_code::{Indexer, Locator, Stylist};
|
||||
use crate::visibility::transition_scope;
|
||||
use crate::{autofix, docstrings, noqa, visibility};
|
||||
|
||||
mod deferred;
|
||||
|
||||
@@ -63,7 +57,7 @@ pub struct Checker<'a> {
|
||||
pub path: &'a Path,
|
||||
module_path: Option<Vec<String>>,
|
||||
package: Option<&'a Path>,
|
||||
is_stub: bool,
|
||||
is_interface_definition: bool,
|
||||
autofix: flags::Autofix,
|
||||
noqa: flags::Noqa,
|
||||
pub settings: &'a Settings,
|
||||
@@ -102,7 +96,7 @@ impl<'a> Checker<'a> {
|
||||
path,
|
||||
package,
|
||||
module_path: module_path.clone(),
|
||||
is_stub: is_python_stub_file(path),
|
||||
is_interface_definition: is_interface_definition_path(path),
|
||||
locator,
|
||||
stylist: style,
|
||||
indexer,
|
||||
@@ -199,7 +193,7 @@ where
|
||||
// Add the binding to the current scope.
|
||||
let context = self.ctx.execution_context();
|
||||
let scope = &mut self.ctx.scopes[scope_index];
|
||||
let usage = Some((scope.id, Range::from(stmt)));
|
||||
let usage = Some((scope.id, Range::from_located(stmt)));
|
||||
for (name, range) in names.iter().zip(ranges.iter()) {
|
||||
let index = self.ctx.bindings.len();
|
||||
self.ctx.bindings.push(Binding {
|
||||
@@ -228,7 +222,7 @@ where
|
||||
if scope_index != GLOBAL_SCOPE_INDEX {
|
||||
let context = self.ctx.execution_context();
|
||||
let scope = &mut self.ctx.scopes[scope_index];
|
||||
let usage = Some((scope.id, Range::from(stmt)));
|
||||
let usage = Some((scope.id, Range::from_located(stmt)));
|
||||
for (name, range) in names.iter().zip(ranges.iter()) {
|
||||
// Add a binding to the current scope.
|
||||
let index = self.ctx.bindings.len();
|
||||
@@ -382,7 +376,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
if self.is_stub {
|
||||
if self.is_interface_definition {
|
||||
if self.settings.rules.enabled(&Rule::PassStatementStubBody) {
|
||||
flake8_pyi::rules::pass_statement_stub_body(self, body);
|
||||
}
|
||||
@@ -669,7 +663,7 @@ where
|
||||
runtime_usage: None,
|
||||
synthetic_usage: None,
|
||||
typing_usage: None,
|
||||
range: Range::from(stmt),
|
||||
range: Range::from_located(stmt),
|
||||
source: Some(self.ctx.current_stmt().clone()),
|
||||
context,
|
||||
},
|
||||
@@ -760,7 +754,7 @@ where
|
||||
flake8_bugbear::rules::useless_expression(self, body);
|
||||
}
|
||||
|
||||
if !self.is_stub {
|
||||
if !self.is_interface_definition {
|
||||
if self
|
||||
.settings
|
||||
.rules
|
||||
@@ -775,7 +769,7 @@ where
|
||||
);
|
||||
}
|
||||
}
|
||||
if self.is_stub {
|
||||
if self.is_interface_definition {
|
||||
if self.settings.rules.enabled(&Rule::PassStatementStubBody) {
|
||||
flake8_pyi::rules::pass_statement_stub_body(self, body);
|
||||
}
|
||||
@@ -866,10 +860,10 @@ where
|
||||
.last()
|
||||
.expect("No current scope found"))]
|
||||
.id,
|
||||
Range::from(alias),
|
||||
Range::from_located(alias),
|
||||
)),
|
||||
typing_usage: None,
|
||||
range: Range::from(alias),
|
||||
range: Range::from_located(alias),
|
||||
source: Some(self.ctx.current_stmt().clone()),
|
||||
context: self.ctx.execution_context(),
|
||||
},
|
||||
@@ -880,7 +874,7 @@ where
|
||||
{
|
||||
self.diagnostics.push(Diagnostic::new(
|
||||
pyflakes::rules::LateFutureImport,
|
||||
Range::from(stmt),
|
||||
Range::from_located(stmt),
|
||||
));
|
||||
}
|
||||
} else if alias.node.name.contains('.') && alias.node.asname.is_none() {
|
||||
@@ -901,13 +895,13 @@ where
|
||||
.last()
|
||||
.expect("No current scope found"))]
|
||||
.id,
|
||||
Range::from(alias),
|
||||
Range::from_located(alias),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
typing_usage: None,
|
||||
range: Range::from(alias),
|
||||
range: Range::from_located(alias),
|
||||
source: Some(self.ctx.current_stmt().clone()),
|
||||
context: self.ctx.execution_context(),
|
||||
},
|
||||
@@ -939,13 +933,13 @@ where
|
||||
.last()
|
||||
.expect("No current scope found"))]
|
||||
.id,
|
||||
Range::from(alias),
|
||||
Range::from_located(alias),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
typing_usage: None,
|
||||
range: Range::from(alias),
|
||||
range: Range::from_located(alias),
|
||||
source: Some(self.ctx.current_stmt().clone()),
|
||||
context: self.ctx.execution_context(),
|
||||
},
|
||||
@@ -1138,8 +1132,8 @@ where
|
||||
if self.settings.rules.enabled(&Rule::RewriteCElementTree) {
|
||||
pyupgrade::rules::replace_c_element_tree(self, stmt);
|
||||
}
|
||||
if self.settings.rules.enabled(&Rule::DeprecatedImport) {
|
||||
pyupgrade::rules::deprecated_import(
|
||||
if self.settings.rules.enabled(&Rule::ImportReplacements) {
|
||||
pyupgrade::rules::import_replacements(
|
||||
self,
|
||||
stmt,
|
||||
names,
|
||||
@@ -1212,10 +1206,10 @@ where
|
||||
.last()
|
||||
.expect("No current scope found"))]
|
||||
.id,
|
||||
Range::from(alias),
|
||||
Range::from_located(alias),
|
||||
)),
|
||||
typing_usage: None,
|
||||
range: Range::from(alias),
|
||||
range: Range::from_located(alias),
|
||||
source: Some(self.ctx.current_stmt().clone()),
|
||||
context: self.ctx.execution_context(),
|
||||
},
|
||||
@@ -1234,7 +1228,7 @@ where
|
||||
{
|
||||
self.diagnostics.push(Diagnostic::new(
|
||||
pyflakes::rules::LateFutureImport,
|
||||
Range::from(stmt),
|
||||
Range::from_located(stmt),
|
||||
));
|
||||
}
|
||||
} else if alias.node.name == "*" {
|
||||
@@ -1251,13 +1245,13 @@ where
|
||||
.last()
|
||||
.expect("No current scope found"))]
|
||||
.id,
|
||||
Range::from(alias),
|
||||
Range::from_located(alias),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
typing_usage: None,
|
||||
range: Range::from(stmt),
|
||||
range: Range::from_located(stmt),
|
||||
source: Some(self.ctx.current_stmt().clone()),
|
||||
context: self.ctx.execution_context(),
|
||||
},
|
||||
@@ -1274,7 +1268,7 @@ where
|
||||
module.as_deref(),
|
||||
),
|
||||
},
|
||||
Range::from(stmt),
|
||||
Range::from_located(stmt),
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -1287,7 +1281,7 @@ where
|
||||
module.as_deref(),
|
||||
),
|
||||
},
|
||||
Range::from(stmt),
|
||||
Range::from_located(stmt),
|
||||
));
|
||||
}
|
||||
|
||||
@@ -1329,13 +1323,13 @@ where
|
||||
.last()
|
||||
.expect("No current scope found"))]
|
||||
.id,
|
||||
Range::from(alias),
|
||||
Range::from_located(alias),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
typing_usage: None,
|
||||
range: Range::from(alias),
|
||||
range: Range::from_located(alias),
|
||||
|
||||
source: Some(self.ctx.current_stmt().clone()),
|
||||
context: self.ctx.execution_context(),
|
||||
@@ -1505,7 +1499,7 @@ where
|
||||
}
|
||||
if self.settings.rules.enabled(&Rule::OSErrorAlias) {
|
||||
if let Some(item) = exc {
|
||||
pyupgrade::rules::os_error_alias_raise(self, item);
|
||||
pyupgrade::rules::os_error_alias(self, &item);
|
||||
}
|
||||
}
|
||||
if self.settings.rules.enabled(&Rule::RaiseVanillaClass) {
|
||||
@@ -1757,7 +1751,7 @@ where
|
||||
flake8_bugbear::rules::redundant_tuple_in_exception_handler(self, handlers);
|
||||
}
|
||||
if self.settings.rules.enabled(&Rule::OSErrorAlias) {
|
||||
pyupgrade::rules::os_error_alias_handlers(self, handlers);
|
||||
pyupgrade::rules::os_error_alias(self, &handlers);
|
||||
}
|
||||
if self.settings.rules.enabled(&Rule::AssertInExcept) {
|
||||
self.diagnostics.extend(
|
||||
@@ -1809,7 +1803,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
if self.is_stub {
|
||||
if self.is_interface_definition {
|
||||
if self.settings.rules.enabled(&Rule::PrefixTypeParams) {
|
||||
flake8_pyi::rules::prefix_type_params(self, value, targets);
|
||||
}
|
||||
@@ -1957,7 +1951,7 @@ where
|
||||
runtime_usage: None,
|
||||
synthetic_usage: None,
|
||||
typing_usage: None,
|
||||
range: Range::from(stmt),
|
||||
range: Range::from_located(stmt),
|
||||
source: Some(RefEquality(stmt)),
|
||||
context: self.ctx.execution_context(),
|
||||
});
|
||||
@@ -2022,7 +2016,7 @@ where
|
||||
runtime_usage: None,
|
||||
synthetic_usage: None,
|
||||
typing_usage: None,
|
||||
range: Range::from(*stmt),
|
||||
range: Range::from_located(stmt),
|
||||
source: Some(RefEquality(stmt)),
|
||||
context: self.ctx.execution_context(),
|
||||
});
|
||||
@@ -2095,7 +2089,7 @@ where
|
||||
let baseclasses = &self
|
||||
.settings
|
||||
.flake8_type_checking
|
||||
.runtime_evaluated_base_classes;
|
||||
.runtime_evaluated_baseclasses;
|
||||
let decorators = &self
|
||||
.settings
|
||||
.flake8_type_checking
|
||||
@@ -2132,7 +2126,7 @@ where
|
||||
StmtKind::If { test, body, orelse } => {
|
||||
self.visit_expr(test);
|
||||
|
||||
if flake8_type_checking::helpers::is_type_checking_block(&self.ctx, test) {
|
||||
if flake8_type_checking::helpers::is_type_checking_block(self, test) {
|
||||
if self.settings.rules.enabled(&Rule::EmptyTypeCheckingBlock) {
|
||||
flake8_type_checking::rules::empty_type_checking_block(self, stmt, body);
|
||||
}
|
||||
@@ -2165,7 +2159,7 @@ where
|
||||
runtime_usage: None,
|
||||
synthetic_usage: None,
|
||||
typing_usage: None,
|
||||
range: Range::from(stmt),
|
||||
range: Range::from_located(stmt),
|
||||
source: Some(self.ctx.current_stmt().clone()),
|
||||
context: self.ctx.execution_context(),
|
||||
},
|
||||
@@ -2195,7 +2189,7 @@ where
|
||||
} = &expr.node
|
||||
{
|
||||
self.deferred.string_type_definitions.push((
|
||||
Range::from(expr),
|
||||
Range::from_located(expr),
|
||||
value,
|
||||
(self.ctx.in_annotation, self.ctx.in_type_checking_block),
|
||||
(self.ctx.scope_stack.clone(), self.ctx.parents.clone()),
|
||||
@@ -2261,7 +2255,7 @@ where
|
||||
elts,
|
||||
check_too_many_expressions,
|
||||
check_two_starred_expressions,
|
||||
Range::from(expr),
|
||||
Range::from_located(expr),
|
||||
) {
|
||||
self.diagnostics.push(diagnostic);
|
||||
}
|
||||
@@ -2296,9 +2290,10 @@ where
|
||||
}
|
||||
ExprContext::Store => {
|
||||
if self.settings.rules.enabled(&Rule::AmbiguousVariableName) {
|
||||
if let Some(diagnostic) =
|
||||
pycodestyle::rules::ambiguous_variable_name(id, Range::from(expr))
|
||||
{
|
||||
if let Some(diagnostic) = pycodestyle::rules::ambiguous_variable_name(
|
||||
id,
|
||||
Range::from_located(expr),
|
||||
) {
|
||||
self.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
@@ -2383,7 +2378,7 @@ where
|
||||
{
|
||||
if attr == "format" {
|
||||
// "...".format(...) call
|
||||
let location = Range::from(expr);
|
||||
let location = Range::from_located(expr);
|
||||
match pyflakes::format::FormatSummary::try_from(value.as_ref()) {
|
||||
Err(e) => {
|
||||
if self
|
||||
@@ -2484,7 +2479,7 @@ where
|
||||
pyupgrade::rules::replace_stdout_stderr(self, expr, func, keywords);
|
||||
}
|
||||
if self.settings.rules.enabled(&Rule::OSErrorAlias) {
|
||||
pyupgrade::rules::os_error_alias_call(self, func);
|
||||
pyupgrade::rules::os_error_alias(self, &expr);
|
||||
}
|
||||
if self.settings.rules.enabled(&Rule::IsinstanceWithTuple)
|
||||
&& self.settings.target_version >= PythonVersion::Py310
|
||||
@@ -2779,14 +2774,22 @@ where
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
Range::from(expr),
|
||||
Range::from_located(expr),
|
||||
);
|
||||
}
|
||||
if self.settings.rules.enabled(&Rule::CallDatetimeToday) {
|
||||
flake8_datetimez::rules::call_datetime_today(self, func, Range::from(expr));
|
||||
flake8_datetimez::rules::call_datetime_today(
|
||||
self,
|
||||
func,
|
||||
Range::from_located(expr),
|
||||
);
|
||||
}
|
||||
if self.settings.rules.enabled(&Rule::CallDatetimeUtcnow) {
|
||||
flake8_datetimez::rules::call_datetime_utcnow(self, func, Range::from(expr));
|
||||
flake8_datetimez::rules::call_datetime_utcnow(
|
||||
self,
|
||||
func,
|
||||
Range::from_located(expr),
|
||||
);
|
||||
}
|
||||
if self
|
||||
.settings
|
||||
@@ -2796,7 +2799,7 @@ where
|
||||
flake8_datetimez::rules::call_datetime_utcfromtimestamp(
|
||||
self,
|
||||
func,
|
||||
Range::from(expr),
|
||||
Range::from_located(expr),
|
||||
);
|
||||
}
|
||||
if self
|
||||
@@ -2809,7 +2812,7 @@ where
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
Range::from(expr),
|
||||
Range::from_located(expr),
|
||||
);
|
||||
}
|
||||
if self
|
||||
@@ -2822,7 +2825,7 @@ where
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
Range::from(expr),
|
||||
Range::from_located(expr),
|
||||
);
|
||||
}
|
||||
if self
|
||||
@@ -2834,14 +2837,18 @@ where
|
||||
self,
|
||||
func,
|
||||
args,
|
||||
Range::from(expr),
|
||||
Range::from_located(expr),
|
||||
);
|
||||
}
|
||||
if self.settings.rules.enabled(&Rule::CallDateToday) {
|
||||
flake8_datetimez::rules::call_date_today(self, func, Range::from(expr));
|
||||
flake8_datetimez::rules::call_date_today(self, func, Range::from_located(expr));
|
||||
}
|
||||
if self.settings.rules.enabled(&Rule::CallDateFromtimestamp) {
|
||||
flake8_datetimez::rules::call_date_fromtimestamp(self, func, Range::from(expr));
|
||||
flake8_datetimez::rules::call_date_fromtimestamp(
|
||||
self,
|
||||
func,
|
||||
Range::from_located(expr),
|
||||
);
|
||||
}
|
||||
|
||||
// pygrep-hooks
|
||||
@@ -2866,12 +2873,6 @@ where
|
||||
if self.settings.rules.enabled(&Rule::BadStrStripCall) {
|
||||
pylint::rules::bad_str_strip_call(self, func, args);
|
||||
}
|
||||
if self.settings.rules.enabled(&Rule::InvalidEnvvarDefault) {
|
||||
pylint::rules::invalid_envvar_default(self, func, args, keywords);
|
||||
}
|
||||
if self.settings.rules.enabled(&Rule::InvalidEnvvarValue) {
|
||||
pylint::rules::invalid_envvar_value(self, func, args, keywords);
|
||||
}
|
||||
|
||||
// flake8-pytest-style
|
||||
if self.settings.rules.enabled(&Rule::PatchWithLambda) {
|
||||
@@ -3076,7 +3077,7 @@ where
|
||||
.rules
|
||||
.enabled(&Rule::PercentFormatUnsupportedFormatCharacter)
|
||||
{
|
||||
let location = Range::from(expr);
|
||||
let location = Range::from_located(expr);
|
||||
match pyflakes::cformat::CFormatSummary::try_from(value.as_str()) {
|
||||
Err(CFormatError {
|
||||
typ: CFormatErrorType::UnsupportedFormatChar(c),
|
||||
@@ -3265,7 +3266,7 @@ where
|
||||
left,
|
||||
ops,
|
||||
comparators,
|
||||
Range::from(expr),
|
||||
Range::from_located(expr),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3273,7 +3274,7 @@ where
|
||||
self.diagnostics.extend(pycodestyle::rules::type_comparison(
|
||||
ops,
|
||||
comparators,
|
||||
Range::from(expr),
|
||||
Range::from_located(expr),
|
||||
));
|
||||
}
|
||||
|
||||
@@ -3305,10 +3306,6 @@ where
|
||||
pylint::rules::comparison_of_constant(self, left, ops, comparators);
|
||||
}
|
||||
|
||||
if self.settings.rules.enabled(&Rule::CompareToEmptyString) {
|
||||
pylint::rules::compare_to_empty_string(self, left, ops, comparators);
|
||||
}
|
||||
|
||||
if self.settings.rules.enabled(&Rule::MagicValueComparison) {
|
||||
pylint::rules::magic_value_comparison(self, left, comparators);
|
||||
}
|
||||
@@ -3321,7 +3318,7 @@ where
|
||||
flake8_simplify::rules::yoda_conditions(self, expr, left, ops, comparators);
|
||||
}
|
||||
|
||||
if self.is_stub {
|
||||
if self.is_interface_definition {
|
||||
if self
|
||||
.settings
|
||||
.rules
|
||||
@@ -3354,7 +3351,7 @@ where
|
||||
} => {
|
||||
if self.ctx.in_type_definition && !self.ctx.in_literal {
|
||||
self.deferred.string_type_definitions.push((
|
||||
Range::from(expr),
|
||||
Range::from_located(expr),
|
||||
value,
|
||||
(self.ctx.in_annotation, self.ctx.in_type_checking_block),
|
||||
(self.ctx.scope_stack.clone(), self.ctx.parents.clone()),
|
||||
@@ -3367,7 +3364,7 @@ where
|
||||
{
|
||||
if let Some(diagnostic) = flake8_bandit::rules::hardcoded_bind_all_interfaces(
|
||||
value,
|
||||
&Range::from(expr),
|
||||
&Range::from_located(expr),
|
||||
) {
|
||||
self.diagnostics.push(diagnostic);
|
||||
}
|
||||
@@ -3441,7 +3438,7 @@ where
|
||||
pylint::rules::merge_isinstance(self, expr, op, values);
|
||||
}
|
||||
if self.settings.rules.enabled(&Rule::SingleStartsEndsWith) {
|
||||
flake8_pie::rules::single_starts_ends_with(self, expr);
|
||||
flake8_pie::rules::single_starts_ends_with(self, values, op);
|
||||
}
|
||||
if self.settings.rules.enabled(&Rule::DuplicateIsinstanceCall) {
|
||||
flake8_simplify::rules::duplicate_isinstance_call(self, expr);
|
||||
@@ -3777,13 +3774,6 @@ where
|
||||
if self.settings.rules.enabled(&Rule::ExceptWithEmptyTuple) {
|
||||
flake8_bugbear::rules::except_with_empty_tuple(self, excepthandler);
|
||||
}
|
||||
if self
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::ExceptWithNonExceptionClasses)
|
||||
{
|
||||
flake8_bugbear::rules::except_with_non_exception_classes(self, excepthandler);
|
||||
}
|
||||
if self.settings.rules.enabled(&Rule::ReraiseNoCause) {
|
||||
tryceratops::rules::reraise_no_cause(self, body);
|
||||
}
|
||||
@@ -3913,7 +3903,7 @@ where
|
||||
flake8_bugbear::rules::function_call_argument_default(self, arguments);
|
||||
}
|
||||
|
||||
if self.is_stub {
|
||||
if self.is_interface_definition {
|
||||
if self
|
||||
.settings
|
||||
.rules
|
||||
@@ -3922,7 +3912,7 @@ where
|
||||
flake8_pyi::rules::typed_argument_simple_defaults(self, arguments);
|
||||
}
|
||||
}
|
||||
if self.is_stub {
|
||||
if self.is_interface_definition {
|
||||
if self.settings.rules.enabled(&Rule::ArgumentSimpleDefaults) {
|
||||
flake8_pyi::rules::argument_simple_defaults(self, arguments);
|
||||
}
|
||||
@@ -3957,7 +3947,7 @@ where
|
||||
runtime_usage: None,
|
||||
synthetic_usage: None,
|
||||
typing_usage: None,
|
||||
range: Range::from(arg),
|
||||
range: Range::from_located(arg),
|
||||
source: Some(self.ctx.current_stmt().clone()),
|
||||
context: self.ctx.execution_context(),
|
||||
},
|
||||
@@ -3965,7 +3955,7 @@ where
|
||||
|
||||
if self.settings.rules.enabled(&Rule::AmbiguousVariableName) {
|
||||
if let Some(diagnostic) =
|
||||
pycodestyle::rules::ambiguous_variable_name(&arg.node.arg, Range::from(arg))
|
||||
pycodestyle::rules::ambiguous_variable_name(&arg.node.arg, Range::from_located(arg))
|
||||
{
|
||||
self.diagnostics.push(diagnostic);
|
||||
}
|
||||
@@ -4000,7 +3990,7 @@ where
|
||||
runtime_usage: None,
|
||||
synthetic_usage: None,
|
||||
typing_usage: None,
|
||||
range: Range::from(pattern),
|
||||
range: Range::from_located(pattern),
|
||||
source: Some(self.ctx.current_stmt().clone()),
|
||||
context: self.ctx.execution_context(),
|
||||
},
|
||||
@@ -4211,7 +4201,7 @@ impl<'a> Checker<'a> {
|
||||
if let Some(index) = scope.bindings.get(&id.as_str()) {
|
||||
// Mark the binding as used.
|
||||
let context = self.ctx.execution_context();
|
||||
self.ctx.bindings[*index].mark_used(scope_id, Range::from(expr), context);
|
||||
self.ctx.bindings[*index].mark_used(scope_id, Range::from_located(expr), context);
|
||||
|
||||
if self.ctx.bindings[*index].kind.is_annotation()
|
||||
&& !self.ctx.in_deferred_string_type_definition
|
||||
@@ -4241,7 +4231,7 @@ impl<'a> Checker<'a> {
|
||||
if let Some(index) = scope.bindings.get(full_name) {
|
||||
self.ctx.bindings[*index].mark_used(
|
||||
scope_id,
|
||||
Range::from(expr),
|
||||
Range::from_located(expr),
|
||||
context,
|
||||
);
|
||||
}
|
||||
@@ -4258,7 +4248,7 @@ impl<'a> Checker<'a> {
|
||||
if let Some(index) = scope.bindings.get(full_name.as_str()) {
|
||||
self.ctx.bindings[*index].mark_used(
|
||||
scope_id,
|
||||
Range::from(expr),
|
||||
Range::from_located(expr),
|
||||
context,
|
||||
);
|
||||
}
|
||||
@@ -4300,7 +4290,7 @@ impl<'a> Checker<'a> {
|
||||
name: id.to_string(),
|
||||
sources: from_list,
|
||||
},
|
||||
Range::from(expr),
|
||||
Range::from_located(expr),
|
||||
));
|
||||
}
|
||||
return;
|
||||
@@ -4331,7 +4321,7 @@ impl<'a> Checker<'a> {
|
||||
|
||||
self.diagnostics.push(Diagnostic::new(
|
||||
pyflakes::rules::UndefinedName { name: id.clone() },
|
||||
Range::from(expr),
|
||||
Range::from_located(expr),
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -4403,7 +4393,7 @@ impl<'a> Checker<'a> {
|
||||
runtime_usage: None,
|
||||
synthetic_usage: None,
|
||||
typing_usage: None,
|
||||
range: Range::from(expr),
|
||||
range: Range::from_located(expr),
|
||||
source: Some(self.ctx.current_stmt().clone()),
|
||||
context: self.ctx.execution_context(),
|
||||
},
|
||||
@@ -4423,7 +4413,7 @@ impl<'a> Checker<'a> {
|
||||
runtime_usage: None,
|
||||
synthetic_usage: None,
|
||||
typing_usage: None,
|
||||
range: Range::from(expr),
|
||||
range: Range::from_located(expr),
|
||||
source: Some(self.ctx.current_stmt().clone()),
|
||||
context: self.ctx.execution_context(),
|
||||
},
|
||||
@@ -4439,7 +4429,7 @@ impl<'a> Checker<'a> {
|
||||
runtime_usage: None,
|
||||
synthetic_usage: None,
|
||||
typing_usage: None,
|
||||
range: Range::from(expr),
|
||||
range: Range::from_located(expr),
|
||||
source: Some(self.ctx.current_stmt().clone()),
|
||||
context: self.ctx.execution_context(),
|
||||
},
|
||||
@@ -4504,7 +4494,7 @@ impl<'a> Checker<'a> {
|
||||
runtime_usage: None,
|
||||
synthetic_usage: None,
|
||||
typing_usage: None,
|
||||
range: Range::from(expr),
|
||||
range: Range::from_located(expr),
|
||||
source: Some(self.ctx.current_stmt().clone()),
|
||||
context: self.ctx.execution_context(),
|
||||
},
|
||||
@@ -4520,7 +4510,7 @@ impl<'a> Checker<'a> {
|
||||
runtime_usage: None,
|
||||
synthetic_usage: None,
|
||||
typing_usage: None,
|
||||
range: Range::from(expr),
|
||||
range: Range::from_located(expr),
|
||||
source: Some(self.ctx.current_stmt().clone()),
|
||||
context: self.ctx.execution_context(),
|
||||
},
|
||||
@@ -4551,7 +4541,7 @@ impl<'a> Checker<'a> {
|
||||
pyflakes::rules::UndefinedName {
|
||||
name: id.to_string(),
|
||||
},
|
||||
Range::from(expr),
|
||||
Range::from_located(expr),
|
||||
));
|
||||
}
|
||||
|
||||
@@ -4737,33 +4727,30 @@ impl<'a> Checker<'a> {
|
||||
}
|
||||
|
||||
fn check_dead_scopes(&mut self) {
|
||||
let enforce_typing_imports = !self.is_stub
|
||||
&& (self
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::GlobalVariableNotAssigned)
|
||||
|| self
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::RuntimeImportInTypeCheckingBlock)
|
||||
|| self
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::TypingOnlyFirstPartyImport)
|
||||
|| self
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::TypingOnlyThirdPartyImport)
|
||||
|| self
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::TypingOnlyStandardLibraryImport));
|
||||
|
||||
if !(self.settings.rules.enabled(&Rule::UnusedImport)
|
||||
|| self.settings.rules.enabled(&Rule::ImportStarUsage)
|
||||
|| self.settings.rules.enabled(&Rule::RedefinedWhileUnused)
|
||||
|| self.settings.rules.enabled(&Rule::UndefinedExport)
|
||||
|| enforce_typing_imports)
|
||||
|| self
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::GlobalVariableNotAssigned)
|
||||
|| self
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::RuntimeImportInTypeCheckingBlock)
|
||||
|| self
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::TypingOnlyFirstPartyImport)
|
||||
|| self
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::TypingOnlyThirdPartyImport)
|
||||
|| self
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::TypingOnlyStandardLibraryImport))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -4812,10 +4799,26 @@ impl<'a> Checker<'a> {
|
||||
// Identify any valid runtime imports. If a module is imported at runtime, and
|
||||
// used at runtime, then by default, we avoid flagging any other
|
||||
// imports from that model as typing-only.
|
||||
let runtime_imports: Vec<Vec<&Binding>> = if enforce_typing_imports {
|
||||
if self.settings.flake8_type_checking.strict {
|
||||
vec![]
|
||||
} else {
|
||||
let runtime_imports: Vec<Vec<&Binding>> = if self.settings.flake8_type_checking.strict {
|
||||
vec![]
|
||||
} else {
|
||||
if self
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::RuntimeImportInTypeCheckingBlock)
|
||||
|| self
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::TypingOnlyFirstPartyImport)
|
||||
|| self
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::TypingOnlyThirdPartyImport)
|
||||
|| self
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::TypingOnlyStandardLibraryImport)
|
||||
{
|
||||
self.ctx
|
||||
.scopes
|
||||
.iter()
|
||||
@@ -4830,9 +4833,9 @@ impl<'a> Checker<'a> {
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||
@@ -4954,7 +4957,23 @@ impl<'a> Checker<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
if enforce_typing_imports {
|
||||
if self
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::RuntimeImportInTypeCheckingBlock)
|
||||
|| self
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::TypingOnlyFirstPartyImport)
|
||||
|| self
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::TypingOnlyThirdPartyImport)
|
||||
|| self
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::TypingOnlyStandardLibraryImport)
|
||||
{
|
||||
let runtime_imports: Vec<&Binding> = if self.settings.flake8_type_checking.strict {
|
||||
vec![]
|
||||
} else {
|
||||
@@ -4971,9 +4990,7 @@ impl<'a> Checker<'a> {
|
||||
if let Some(diagnostic) =
|
||||
flake8_type_checking::rules::runtime_import_in_type_checking_block(binding)
|
||||
{
|
||||
if self.settings.rules.enabled(diagnostic.kind.rule()) {
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
if let Some(diagnostic) =
|
||||
flake8_type_checking::rules::typing_only_runtime_import(
|
||||
@@ -5270,7 +5287,7 @@ impl<'a> Checker<'a> {
|
||||
}
|
||||
overloaded_name = flake8_annotations::helpers::overloaded_name(self, &definition);
|
||||
}
|
||||
if self.is_stub {
|
||||
if self.is_interface_definition {
|
||||
if self.settings.rules.enabled(&Rule::DocstringInStub) {
|
||||
flake8_pyi::rules::docstring_in_stubs(self, definition.docstring);
|
||||
}
|
||||
@@ -5293,13 +5310,13 @@ impl<'a> Checker<'a> {
|
||||
|
||||
// Extract a `Docstring` from a `Definition`.
|
||||
let expr = definition.docstring.unwrap();
|
||||
let contents = self.locator.slice(expr);
|
||||
let indentation = self.locator.slice(Range::new(
|
||||
let contents = self.locator.slice(&Range::from_located(expr));
|
||||
let indentation = self.locator.slice(&Range::new(
|
||||
Location::new(expr.location.row(), 0),
|
||||
Location::new(expr.location.row(), expr.location.column()),
|
||||
));
|
||||
|
||||
let body = str::raw_contents(contents);
|
||||
let body = pydocstyle::helpers::raw_contents(contents);
|
||||
let docstring = Docstring {
|
||||
kind: definition.kind,
|
||||
expr,
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
use std::path::Path;
|
||||
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
|
||||
use crate::registry::Rule;
|
||||
use crate::registry::{Diagnostic, Rule};
|
||||
use crate::rules::flake8_no_pep420::rules::implicit_namespace_package;
|
||||
use crate::rules::pep8_naming::rules::invalid_module_name;
|
||||
use crate::settings::Settings;
|
||||
|
||||
@@ -4,15 +4,13 @@ use std::path::Path;
|
||||
|
||||
use rustpython_parser::ast::Suite;
|
||||
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
use ruff_python_ast::source_code::{Indexer, Locator, Stylist};
|
||||
use ruff_python_ast::visitor::Visitor;
|
||||
|
||||
use crate::ast::visitor::Visitor;
|
||||
use crate::directives::IsortDirectives;
|
||||
use crate::registry::Rule;
|
||||
use crate::registry::{Diagnostic, Rule};
|
||||
use crate::rules::isort;
|
||||
use crate::rules::isort::track::{Block, ImportTracker};
|
||||
use crate::settings::{flags, Settings};
|
||||
use crate::source_code::{Indexer, Locator, Stylist};
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn check_imports(
|
||||
|
||||
@@ -5,11 +5,8 @@ use itertools::Itertools;
|
||||
use rustpython_parser::ast::Location;
|
||||
use rustpython_parser::lexer::LexResult;
|
||||
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
use ruff_python_ast::source_code::{Locator, Stylist};
|
||||
use ruff_python_ast::types::Range;
|
||||
|
||||
use crate::registry::{AsRule, Rule};
|
||||
use crate::ast::types::Range;
|
||||
use crate::registry::{Diagnostic, Rule};
|
||||
use crate::rules::pycodestyle::logical_lines::{iter_logical_lines, TokenFlags};
|
||||
use crate::rules::pycodestyle::rules::{
|
||||
extraneous_whitespace, indentation, missing_whitespace, missing_whitespace_after_keyword,
|
||||
@@ -18,6 +15,7 @@ use crate::rules::pycodestyle::rules::{
|
||||
whitespace_before_parameters,
|
||||
};
|
||||
use crate::settings::{flags, Settings};
|
||||
use crate::source_code::{Locator, Stylist};
|
||||
|
||||
/// Return the amount of indentation, expanding tabs to the next multiple of 8.
|
||||
fn expand_indent(mut line: &str) -> usize {
|
||||
@@ -59,7 +57,7 @@ pub fn check_logical_lines(
|
||||
|
||||
// Extract the indentation level.
|
||||
let start_loc = line.mapping[0].1;
|
||||
let start_line = locator.slice(Range::new(Location::new(start_loc.row(), 0), start_loc));
|
||||
let start_line = locator.slice(&Range::new(Location::new(start_loc.row(), 0), start_loc));
|
||||
let indent_level = expand_indent(start_line);
|
||||
let indent_size = 4;
|
||||
|
||||
@@ -227,9 +225,8 @@ mod tests {
|
||||
use rustpython_parser::lexer::LexResult;
|
||||
use rustpython_parser::{lexer, Mode};
|
||||
|
||||
use ruff_python_ast::source_code::Locator;
|
||||
|
||||
use crate::checkers::logical_lines::iter_logical_lines;
|
||||
use crate::source_code::Locator;
|
||||
|
||||
#[test]
|
||||
fn split_logical_lines() {
|
||||
|
||||
@@ -4,14 +4,12 @@ use log::warn;
|
||||
use nohash_hasher::IntMap;
|
||||
use rustpython_parser::ast::Location;
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Fix};
|
||||
use ruff_python_ast::newlines::StrExt;
|
||||
use ruff_python_ast::types::Range;
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::codes::NoqaCode;
|
||||
use crate::fix::Fix;
|
||||
use crate::noqa;
|
||||
use crate::noqa::{extract_file_exemption, Directive, Exemption};
|
||||
use crate::registry::{AsRule, Rule};
|
||||
use crate::registry::{Diagnostic, DiagnosticKind, Rule};
|
||||
use crate::rule_redirects::get_redirect_target;
|
||||
use crate::rules::ruff::rules::{UnusedCodes, UnusedNOQA};
|
||||
use crate::settings::{flags, Settings};
|
||||
@@ -23,7 +21,7 @@ pub fn check_noqa(
|
||||
noqa_line_for: &IntMap<usize, usize>,
|
||||
settings: &Settings,
|
||||
autofix: flags::Autofix,
|
||||
) -> Vec<usize> {
|
||||
) {
|
||||
let enforce_noqa = settings.rules.enabled(&Rule::UnusedNOQA);
|
||||
|
||||
// Whether the file is exempted from all checks.
|
||||
@@ -39,7 +37,7 @@ pub fn check_noqa(
|
||||
// Indices of diagnostics that were ignored by a `noqa` directive.
|
||||
let mut ignored_diagnostics = vec![];
|
||||
|
||||
let lines: Vec<&str> = contents.universal_newlines().collect();
|
||||
let lines: Vec<&str> = contents.lines().collect();
|
||||
for lineno in commented_lines {
|
||||
match extract_file_exemption(lines[lineno - 1]) {
|
||||
Exemption::All => {
|
||||
@@ -67,7 +65,7 @@ pub fn check_noqa(
|
||||
|
||||
// Remove any ignored diagnostics.
|
||||
for (index, diagnostic) in diagnostics.iter().enumerate() {
|
||||
if matches!(diagnostic.kind.rule(), Rule::BlanketNOQA) {
|
||||
if matches!(diagnostic.kind, DiagnosticKind::BlanketNOQA(..)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -98,7 +96,7 @@ pub fn check_noqa(
|
||||
ignored_diagnostics.push(index);
|
||||
continue;
|
||||
}
|
||||
(Directive::Codes(.., codes, _), matches) => {
|
||||
(Directive::Codes(.., codes), matches) => {
|
||||
if noqa::includes(diagnostic.kind.rule(), codes) {
|
||||
matches.push(diagnostic.kind.rule().noqa_code());
|
||||
ignored_diagnostics.push(index);
|
||||
@@ -125,7 +123,7 @@ pub fn check_noqa(
|
||||
ignored_diagnostics.push(index);
|
||||
continue;
|
||||
}
|
||||
(Directive::Codes(.., codes, _), matches) => {
|
||||
(Directive::Codes(.., codes), matches) => {
|
||||
if noqa::includes(diagnostic.kind.rule(), codes) {
|
||||
matches.push(diagnostic.kind.rule().noqa_code());
|
||||
ignored_diagnostics.push(index);
|
||||
@@ -141,7 +139,7 @@ pub fn check_noqa(
|
||||
if enforce_noqa {
|
||||
for (row, (directive, matches)) in noqa_directives {
|
||||
match directive {
|
||||
Directive::All(leading_spaces, start_byte, end_byte, trailing_spaces) => {
|
||||
Directive::All(spaces, start_byte, end_byte) => {
|
||||
if matches.is_empty() {
|
||||
let start = lines[row][..start_byte].chars().count();
|
||||
let end = start + lines[row][start_byte..end_byte].chars().count();
|
||||
@@ -151,27 +149,15 @@ pub fn check_noqa(
|
||||
Range::new(Location::new(row + 1, start), Location::new(row + 1, end)),
|
||||
);
|
||||
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(Fix::deletion(
|
||||
Location::new(row + 1, start - spaces),
|
||||
Location::new(row + 1, lines[row].chars().count()),
|
||||
));
|
||||
}
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
Directive::Codes(leading_spaces, start_byte, end_byte, codes, trailing_spaces) => {
|
||||
Directive::Codes(spaces, start_byte, end_byte, codes) => {
|
||||
let mut disabled_codes = vec![];
|
||||
let mut unknown_codes = vec![];
|
||||
let mut unmatched_codes = vec![];
|
||||
@@ -231,28 +217,15 @@ pub fn check_noqa(
|
||||
);
|
||||
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(Fix::deletion(
|
||||
Location::new(row + 1, start - spaces),
|
||||
Location::new(row + 1, lines[row].chars().count()),
|
||||
));
|
||||
} else {
|
||||
diagnostic.amend(Fix::replacement(
|
||||
format!("# noqa: {}", valid_codes.join(", ")),
|
||||
Location::new(row + 1, start),
|
||||
Location::new(row + 1, end),
|
||||
Location::new(row + 1, lines[row].chars().count()),
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -265,5 +238,7 @@ pub fn check_noqa(
|
||||
}
|
||||
|
||||
ignored_diagnostics.sort_unstable();
|
||||
ignored_diagnostics
|
||||
for index in ignored_diagnostics.iter().rev() {
|
||||
diagnostics.swap_remove(*index);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,7 @@
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
use ruff_python_ast::newlines::StrExt;
|
||||
use ruff_python_ast::source_code::{Locator, Stylist};
|
||||
|
||||
use crate::registry::Rule;
|
||||
use crate::registry::{Diagnostic, Rule};
|
||||
use crate::rules::flake8_executable::helpers::{extract_shebang, ShebangDirective};
|
||||
use crate::rules::flake8_executable::rules::{
|
||||
shebang_missing, shebang_newline, shebang_not_executable, shebang_python, shebang_whitespace,
|
||||
@@ -19,11 +15,12 @@ use crate::rules::pygrep_hooks::rules::{blanket_noqa, blanket_type_ignore};
|
||||
use crate::rules::pylint;
|
||||
use crate::rules::pyupgrade::rules::unnecessary_coding_comment;
|
||||
use crate::settings::{flags, Settings};
|
||||
use crate::source_code::Stylist;
|
||||
|
||||
pub fn check_physical_lines(
|
||||
path: &Path,
|
||||
locator: &Locator,
|
||||
stylist: &Stylist,
|
||||
contents: &str,
|
||||
commented_lines: &[usize],
|
||||
doc_lines: &[usize],
|
||||
settings: &Settings,
|
||||
@@ -57,7 +54,7 @@ pub fn check_physical_lines(
|
||||
|
||||
let mut commented_lines_iter = commented_lines.iter().peekable();
|
||||
let mut doc_lines_iter = doc_lines.iter().peekable();
|
||||
for (index, line) in locator.contents().universal_newlines().enumerate() {
|
||||
for (index, line) in contents.lines().enumerate() {
|
||||
while commented_lines_iter
|
||||
.next_if(|lineno| &(index + 1) == *lineno)
|
||||
.is_some()
|
||||
@@ -163,8 +160,8 @@ pub fn check_physical_lines(
|
||||
|
||||
if enforce_no_newline_at_end_of_file {
|
||||
if let Some(diagnostic) = no_newline_at_end_of_file(
|
||||
locator,
|
||||
stylist,
|
||||
contents,
|
||||
autofix.into() && settings.rules.should_fix(&Rule::NoNewLineAtEndOfFile),
|
||||
) {
|
||||
diagnostics.push(diagnostic);
|
||||
@@ -182,14 +179,13 @@ pub fn check_physical_lines(
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
use ruff_python_ast::source_code::{Locator, Stylist};
|
||||
|
||||
use super::check_physical_lines;
|
||||
use crate::registry::Rule;
|
||||
use crate::settings::{flags, Settings};
|
||||
|
||||
use super::check_physical_lines;
|
||||
use crate::source_code::{Locator, Stylist};
|
||||
|
||||
#[test]
|
||||
fn e501_non_ascii_char() {
|
||||
@@ -200,8 +196,8 @@ mod tests {
|
||||
let check_with_max_line_length = |line_length: usize| {
|
||||
check_physical_lines(
|
||||
Path::new("foo.py"),
|
||||
&locator,
|
||||
&stylist,
|
||||
line,
|
||||
&[],
|
||||
&[],
|
||||
&Settings {
|
||||
|
||||
@@ -4,22 +4,21 @@ use rustpython_parser::lexer::LexResult;
|
||||
use rustpython_parser::Tok;
|
||||
|
||||
use crate::lex::docstring_detection::StateMachine;
|
||||
use crate::registry::{AsRule, Rule};
|
||||
use crate::registry::{Diagnostic, Rule};
|
||||
use crate::rules::ruff::rules::Context;
|
||||
use crate::rules::{
|
||||
eradicate, flake8_commas, flake8_implicit_str_concat, flake8_pyi, flake8_quotes, pycodestyle,
|
||||
pyupgrade, ruff,
|
||||
};
|
||||
use crate::settings::{flags, Settings};
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
use ruff_python_ast::source_code::Locator;
|
||||
use crate::source_code::Locator;
|
||||
|
||||
pub fn check_tokens(
|
||||
locator: &Locator,
|
||||
tokens: &[LexResult],
|
||||
settings: &Settings,
|
||||
autofix: flags::Autofix,
|
||||
is_stub: bool,
|
||||
is_interface_definition: bool,
|
||||
) -> Vec<Diagnostic> {
|
||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||
|
||||
@@ -165,7 +164,7 @@ pub fn check_tokens(
|
||||
}
|
||||
|
||||
// PYI033
|
||||
if enforce_type_comment_in_stub && is_stub {
|
||||
if enforce_type_comment_in_stub && is_interface_definition {
|
||||
diagnostics.extend(flake8_pyi::rules::type_comment_in_stub(tokens));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,23 +1,5 @@
|
||||
use crate::registry::{Linter, Rule};
|
||||
|
||||
#[derive(PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct NoqaCode(&'static str, &'static str);
|
||||
|
||||
impl std::fmt::Display for NoqaCode {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
write!(f, "{}{}", self.0, self.1)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&str> for NoqaCode {
|
||||
fn eq(&self, other: &&str) -> bool {
|
||||
match other.strip_prefix(self.0) {
|
||||
Some(suffix) => suffix == self.1,
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[ruff_macros::map_codes]
|
||||
pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
#[allow(clippy::enum_glob_use)]
|
||||
@@ -161,37 +143,34 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Pyflakes, "901") => Rule::RaiseNotImplemented,
|
||||
|
||||
// pylint
|
||||
(Pylint, "C0414") => Rule::UselessImportAlias,
|
||||
(Pylint, "C1901") => Rule::CompareToEmptyString,
|
||||
(Pylint, "C3002") => Rule::UnnecessaryDirectLambdaCall,
|
||||
(Pylint, "E0100") => Rule::YieldInInit,
|
||||
(Pylint, "E0101") => Rule::ReturnInInit,
|
||||
(Pylint, "E0117") => Rule::NonlocalWithoutBinding,
|
||||
(Pylint, "E0118") => Rule::UsedPriorGlobalDeclaration,
|
||||
(Pylint, "E0604") => Rule::InvalidAllObject,
|
||||
(Pylint, "E0605") => Rule::InvalidAllFormat,
|
||||
(Pylint, "W1508") => Rule::InvalidEnvvarDefault,
|
||||
(Pylint, "E1142") => Rule::AwaitOutsideAsync,
|
||||
(Pylint, "E1205") => Rule::LoggingTooManyArgs,
|
||||
(Pylint, "E1206") => Rule::LoggingTooFewArgs,
|
||||
(Pylint, "E1307") => Rule::BadStringFormatType,
|
||||
(Pylint, "E1310") => Rule::BadStrStripCall,
|
||||
(Pylint, "E1507") => Rule::InvalidEnvvarValue,
|
||||
(Pylint, "E2502") => Rule::BidirectionalUnicode,
|
||||
(Pylint, "R0133") => Rule::ComparisonOfConstant,
|
||||
(Pylint, "E1310") => Rule::BadStrStripCall,
|
||||
(Pylint, "C0414") => Rule::UselessImportAlias,
|
||||
(Pylint, "C3002") => Rule::UnnecessaryDirectLambdaCall,
|
||||
(Pylint, "E0117") => Rule::NonlocalWithoutBinding,
|
||||
(Pylint, "E0118") => Rule::UsedPriorGlobalDeclaration,
|
||||
(Pylint, "E1142") => Rule::AwaitOutsideAsync,
|
||||
(Pylint, "R0206") => Rule::PropertyWithParameters,
|
||||
(Pylint, "R0402") => Rule::ConsiderUsingFromImport,
|
||||
(Pylint, "R0911") => Rule::TooManyReturnStatements,
|
||||
(Pylint, "R0912") => Rule::TooManyBranches,
|
||||
(Pylint, "R0913") => Rule::TooManyArguments,
|
||||
(Pylint, "R0915") => Rule::TooManyStatements,
|
||||
(Pylint, "R0133") => Rule::ComparisonOfConstant,
|
||||
(Pylint, "R1701") => Rule::ConsiderMergingIsinstance,
|
||||
(Pylint, "R1722") => Rule::ConsiderUsingSysExit,
|
||||
(Pylint, "R2004") => Rule::MagicValueComparison,
|
||||
(Pylint, "R5501") => Rule::CollapsibleElseIf,
|
||||
(Pylint, "R2004") => Rule::MagicValueComparison,
|
||||
(Pylint, "W0120") => Rule::UselessElseOnLoop,
|
||||
(Pylint, "W0602") => Rule::GlobalVariableNotAssigned,
|
||||
(Pylint, "W0603") => Rule::GlobalStatement,
|
||||
(Pylint, "R0911") => Rule::TooManyReturnStatements,
|
||||
(Pylint, "R0913") => Rule::TooManyArguments,
|
||||
(Pylint, "R0912") => Rule::TooManyBranches,
|
||||
(Pylint, "R0915") => Rule::TooManyStatements,
|
||||
(Pylint, "W2901") => Rule::RedefinedLoopName,
|
||||
|
||||
// flake8-builtins
|
||||
@@ -227,7 +206,6 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Flake8Bugbear, "026") => Rule::StarArgUnpackingAfterKeywordArg,
|
||||
(Flake8Bugbear, "027") => Rule::EmptyMethodWithoutAbstractDecorator,
|
||||
(Flake8Bugbear, "029") => Rule::ExceptWithEmptyTuple,
|
||||
(Flake8Bugbear, "030") => Rule::ExceptWithNonExceptionClasses,
|
||||
(Flake8Bugbear, "032") => Rule::UnintentionalTypeAnnotation,
|
||||
(Flake8Bugbear, "904") => Rule::RaiseWithoutFromInsideExcept,
|
||||
(Flake8Bugbear, "905") => Rule::ZipWithoutExplicitStrict,
|
||||
@@ -375,7 +353,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Pyupgrade, "032") => Rule::FString,
|
||||
(Pyupgrade, "033") => Rule::FunctoolsCache,
|
||||
(Pyupgrade, "034") => Rule::ExtraneousParentheses,
|
||||
(Pyupgrade, "035") => Rule::DeprecatedImport,
|
||||
(Pyupgrade, "035") => Rule::ImportReplacements,
|
||||
(Pyupgrade, "036") => Rule::OutdatedVersionBlock,
|
||||
(Pyupgrade, "037") => Rule::QuotedAnnotation,
|
||||
(Pyupgrade, "038") => Rule::IsinstanceWithTuple,
|
||||
|
||||
@@ -7,8 +7,8 @@ use rustpython_parser::ast::{Constant, ExprKind, Stmt, StmtKind, Suite};
|
||||
use rustpython_parser::lexer::LexResult;
|
||||
use rustpython_parser::Tok;
|
||||
|
||||
use ruff_python_ast::visitor;
|
||||
use ruff_python_ast::visitor::Visitor;
|
||||
use crate::ast::visitor;
|
||||
use crate::ast::visitor::Visitor;
|
||||
|
||||
/// Extract doc lines (standalone comments) from a token sequence.
|
||||
pub fn doc_lines_from_tokens(lxr: &[LexResult]) -> DocLines {
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
use ruff_python_ast::visibility::{
|
||||
class_visibility, function_visibility, method_visibility, Modifier, Visibility, VisibleScope,
|
||||
};
|
||||
use rustpython_parser::ast::{Expr, Stmt};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -33,36 +30,3 @@ pub enum Documentable {
|
||||
Class,
|
||||
Function,
|
||||
}
|
||||
|
||||
pub fn transition_scope(scope: &VisibleScope, stmt: &Stmt, kind: &Documentable) -> VisibleScope {
|
||||
match kind {
|
||||
Documentable::Function => VisibleScope {
|
||||
modifier: Modifier::Function,
|
||||
visibility: match scope {
|
||||
VisibleScope {
|
||||
modifier: Modifier::Module,
|
||||
visibility: Visibility::Public,
|
||||
} => function_visibility(stmt),
|
||||
VisibleScope {
|
||||
modifier: Modifier::Class,
|
||||
visibility: Visibility::Public,
|
||||
} => method_visibility(stmt),
|
||||
_ => Visibility::Private,
|
||||
},
|
||||
},
|
||||
Documentable::Class => VisibleScope {
|
||||
modifier: Modifier::Class,
|
||||
visibility: match scope {
|
||||
VisibleScope {
|
||||
modifier: Modifier::Module,
|
||||
visibility: Visibility::Public,
|
||||
} => class_visibility(stmt),
|
||||
VisibleScope {
|
||||
modifier: Modifier::Class,
|
||||
visibility: Visibility::Public,
|
||||
} => class_visibility(stmt),
|
||||
_ => Visibility::Private,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
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::visibility::{Modifier, VisibleScope};
|
||||
|
||||
/// Extract a docstring from a function or class body.
|
||||
pub fn docstring_from(suite: &[Stmt]) -> Option<&Expr> {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use strum_macros::EnumIter;
|
||||
|
||||
use crate::ast::whitespace;
|
||||
use crate::docstrings::styles::SectionStyle;
|
||||
use ruff_python_ast::whitespace;
|
||||
|
||||
#[derive(EnumIter, PartialEq, Eq, Debug, Clone, Copy)]
|
||||
pub enum SectionKind {
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
use rustpython_parser::ast::Location;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Copy, Clone, Hash)]
|
||||
pub enum FixMode {
|
||||
Generate,
|
||||
@@ -15,3 +18,40 @@ impl From<bool> for FixMode {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct Fix {
|
||||
pub content: String,
|
||||
pub location: Location,
|
||||
pub end_location: Location,
|
||||
}
|
||||
|
||||
impl Fix {
|
||||
pub const fn deletion(start: Location, end: Location) -> Self {
|
||||
Self {
|
||||
content: String::new(),
|
||||
location: start,
|
||||
end_location: end,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn replacement(content: String, start: Location, end: Location) -> Self {
|
||||
debug_assert!(!content.is_empty(), "Prefer `Fix::deletion`");
|
||||
|
||||
Self {
|
||||
content,
|
||||
location: start,
|
||||
end_location: end,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insertion(content: String, at: Location) -> Self {
|
||||
debug_assert!(!content.is_empty(), "Insert content is empty");
|
||||
|
||||
Self {
|
||||
content,
|
||||
location: at,
|
||||
end_location: at,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ use crate::rules::{
|
||||
};
|
||||
use crate::settings::options::Options;
|
||||
use crate::settings::pyproject::Pyproject;
|
||||
use crate::settings::types::PythonVersion;
|
||||
use crate::warn_user;
|
||||
|
||||
const DEFAULT_SELECTORS: &[RuleSelector] = &[
|
||||
@@ -425,15 +424,6 @@ pub fn convert(
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(project) = &external_config.project {
|
||||
if let Some(requires_python) = &project.requires_python {
|
||||
if options.target_version.is_none() {
|
||||
options.target_version =
|
||||
PythonVersion::get_minimum_supported_version(requires_python);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create the pyproject.toml.
|
||||
Ok(Pyproject::new(options))
|
||||
}
|
||||
@@ -449,17 +439,13 @@ fn resolve_select(plugins: &[Plugin]) -> HashSet<RuleSelector> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
|
||||
use anyhow::Result;
|
||||
use itertools::Itertools;
|
||||
use pep440_rs::VersionSpecifiers;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use super::super::plugin::Plugin;
|
||||
use super::convert;
|
||||
use crate::flake8_to_ruff::converter::DEFAULT_SELECTORS;
|
||||
use crate::flake8_to_ruff::pep621::Project;
|
||||
use crate::flake8_to_ruff::ExternalConfig;
|
||||
use crate::registry::Linter;
|
||||
use crate::rule_selector::RuleSelector;
|
||||
@@ -467,7 +453,6 @@ mod tests {
|
||||
use crate::rules::{flake8_quotes, pydocstyle};
|
||||
use crate::settings::options::Options;
|
||||
use crate::settings::pyproject::Pyproject;
|
||||
use crate::settings::types::PythonVersion;
|
||||
|
||||
fn default_options(plugins: impl IntoIterator<Item = RuleSelector>) -> Options {
|
||||
Options {
|
||||
@@ -624,25 +609,4 @@ mod tests {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_converts_project_requires_python() -> Result<()> {
|
||||
let actual = convert(
|
||||
&HashMap::from([("flake8".to_string(), HashMap::default())]),
|
||||
&ExternalConfig {
|
||||
project: Some(&Project {
|
||||
requires_python: Some(VersionSpecifiers::from_str(">=3.8.16, <3.11")?),
|
||||
}),
|
||||
..ExternalConfig::default()
|
||||
},
|
||||
Some(vec![]),
|
||||
)?;
|
||||
let expected = Pyproject::new(Options {
|
||||
target_version: Some(PythonVersion::Py38),
|
||||
..default_options([])
|
||||
});
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
use super::black::Black;
|
||||
use super::isort::Isort;
|
||||
use super::pep621::Project;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ExternalConfig<'a> {
|
||||
pub black: Option<&'a Black>,
|
||||
pub isort: Option<&'a Isort>,
|
||||
pub project: Option<&'a Project>,
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ mod converter;
|
||||
mod external_config;
|
||||
mod isort;
|
||||
mod parser;
|
||||
pub mod pep621;
|
||||
mod plugin;
|
||||
mod pyproject;
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
//! Extract PEP 621 configuration settings from a pyproject.toml.
|
||||
|
||||
use pep440_rs::VersionSpecifiers;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
pub struct Project {
|
||||
#[serde(alias = "requires-python", alias = "requires_python")]
|
||||
pub requires_python: Option<VersionSpecifiers>,
|
||||
}
|
||||
@@ -5,7 +5,6 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::black::Black;
|
||||
use super::isort::Isort;
|
||||
use super::pep621::Project;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Tools {
|
||||
@@ -16,7 +15,6 @@ pub struct Tools {
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Pyproject {
|
||||
pub tool: Option<Tools>,
|
||||
pub project: Option<Project>,
|
||||
}
|
||||
|
||||
pub fn parse<P: AsRef<Path>>(path: P) -> Result<Pyproject> {
|
||||
|
||||
@@ -74,20 +74,10 @@ pub fn normalize_path_to<P: AsRef<Path>, R: AsRef<Path>>(path: P, project_root:
|
||||
}
|
||||
|
||||
/// Convert an absolute path to be relative to the current working directory.
|
||||
pub fn relativize_path<P: AsRef<Path>>(path: P) -> String {
|
||||
pub fn relativize_path(path: impl AsRef<Path>) -> String {
|
||||
let path = path.as_ref();
|
||||
if let Ok(path) = path.strip_prefix(&*path_dedot::CWD) {
|
||||
return format!("{}", path.display());
|
||||
}
|
||||
format!("{}", path.display())
|
||||
}
|
||||
|
||||
/// Convert an absolute path to be relative to the specified project root.
|
||||
pub fn relativize_path_to<P: AsRef<Path>, R: AsRef<Path>>(path: P, project_root: R) -> String {
|
||||
format!(
|
||||
"{}",
|
||||
pathdiff::diff_paths(&path, project_root)
|
||||
.expect("Could not diff paths")
|
||||
.display()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,16 +5,18 @@
|
||||
//!
|
||||
//! [Ruff]: https://github.com/charliermarsh/ruff
|
||||
|
||||
pub use ruff_python_ast::source_code::round_trip;
|
||||
pub use ruff_python_ast::types::Range;
|
||||
pub use ast::types::Range;
|
||||
use cfg_if::cfg_if;
|
||||
pub use rule_selector::RuleSelector;
|
||||
pub use rules::pycodestyle::rules::IOError;
|
||||
pub use violation::{AutofixKind, Availability as AutofixAvailability};
|
||||
|
||||
mod ast;
|
||||
mod autofix;
|
||||
mod checkers;
|
||||
mod codes;
|
||||
mod cst;
|
||||
pub mod directives;
|
||||
mod directives;
|
||||
mod doc_lines;
|
||||
mod docstrings;
|
||||
pub mod fix;
|
||||
@@ -25,13 +27,24 @@ pub mod linter;
|
||||
pub mod logging;
|
||||
pub mod message;
|
||||
mod noqa;
|
||||
pub mod packaging;
|
||||
pub mod registry;
|
||||
pub mod resolver;
|
||||
mod rule_redirects;
|
||||
mod rule_selector;
|
||||
pub mod rules;
|
||||
mod rules;
|
||||
pub mod settings;
|
||||
pub mod source_code;
|
||||
mod violation;
|
||||
mod visibility;
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(target_family = "wasm")] {
|
||||
mod lib_wasm;
|
||||
pub use lib_wasm::check;
|
||||
} else {
|
||||
pub mod packaging;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
||||
@@ -2,22 +2,22 @@ use std::path::Path;
|
||||
|
||||
use rustpython_parser::ast::Location;
|
||||
use rustpython_parser::lexer::LexResult;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde::Serialize;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
use ruff::directives;
|
||||
use ruff::linter::{check_path, LinterResult};
|
||||
use ruff::registry::AsRule;
|
||||
use ruff::rules::{
|
||||
use crate::directives;
|
||||
use crate::linter::{check_path, LinterResult};
|
||||
use crate::registry::Rule;
|
||||
use crate::rules::{
|
||||
flake8_annotations, flake8_bandit, flake8_bugbear, flake8_builtins, flake8_comprehensions,
|
||||
flake8_errmsg, flake8_implicit_str_concat, flake8_import_conventions, flake8_pytest_style,
|
||||
flake8_quotes, flake8_self, flake8_tidy_imports, flake8_type_checking, flake8_unused_arguments,
|
||||
isort, mccabe, pep8_naming, pycodestyle, pydocstyle, pylint, pyupgrade,
|
||||
};
|
||||
use ruff::settings::configuration::Configuration;
|
||||
use ruff::settings::options::Options;
|
||||
use ruff::settings::{defaults, flags, Settings};
|
||||
use ruff_python_ast::source_code::{Indexer, Locator, Stylist};
|
||||
use crate::settings::configuration::Configuration;
|
||||
use crate::settings::options::Options;
|
||||
use crate::settings::{defaults, flags, Settings};
|
||||
use crate::source_code::{Indexer, Locator, Stylist};
|
||||
|
||||
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
@@ -49,17 +49,34 @@ export interface Diagnostic {
|
||||
};
|
||||
"#;
|
||||
|
||||
#[derive(Serialize, Deserialize, Eq, PartialEq, Debug)]
|
||||
pub struct ExpandedMessage {
|
||||
pub code: String,
|
||||
pub message: String,
|
||||
pub location: Location,
|
||||
pub end_location: Location,
|
||||
pub fix: Option<ExpandedFix>,
|
||||
#[derive(Serialize)]
|
||||
struct ExpandedMessage {
|
||||
code: SerializeRuleAsCode,
|
||||
message: String,
|
||||
location: Location,
|
||||
end_location: Location,
|
||||
fix: Option<ExpandedFix>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Eq, PartialEq, Debug)]
|
||||
pub struct ExpandedFix {
|
||||
struct SerializeRuleAsCode(Rule);
|
||||
|
||||
impl Serialize for SerializeRuleAsCode {
|
||||
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
serializer.serialize_str(&self.0.noqa_code().to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Rule> for SerializeRuleAsCode {
|
||||
fn from(rule: Rule) -> Self {
|
||||
Self(rule)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct ExpandedFix {
|
||||
content: String,
|
||||
message: Option<String>,
|
||||
location: Location,
|
||||
@@ -69,16 +86,7 @@ pub struct ExpandedFix {
|
||||
#[wasm_bindgen(start)]
|
||||
pub fn run() {
|
||||
use log::Level;
|
||||
|
||||
// When the `console_error_panic_hook` feature is enabled, we can call the
|
||||
// `set_panic_hook` function at least once during initialization, and then
|
||||
// we will get better error messages if our code ever panics.
|
||||
//
|
||||
// For more details see
|
||||
// https://github.com/rustwasm/console_error_panic_hook#readme
|
||||
#[cfg(feature = "console_error_panic_hook")]
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
console_log::init_with_level(Level::Debug).expect("Initializing logger went wrong.");
|
||||
}
|
||||
|
||||
@@ -199,14 +207,14 @@ pub fn check(contents: &str, options: JsValue) -> Result<JsValue, JsValue> {
|
||||
|
||||
let messages: Vec<ExpandedMessage> = diagnostics
|
||||
.into_iter()
|
||||
.map(|message| ExpandedMessage {
|
||||
code: message.kind.rule().noqa_code().to_string(),
|
||||
message: message.kind.body,
|
||||
location: message.location,
|
||||
end_location: message.end_location,
|
||||
fix: message.fix.map(|fix| ExpandedFix {
|
||||
.map(|diagnostic| ExpandedMessage {
|
||||
code: diagnostic.kind.rule().clone().into(),
|
||||
message: diagnostic.kind.body(),
|
||||
location: diagnostic.location,
|
||||
end_location: diagnostic.end_location,
|
||||
fix: diagnostic.fix.map(|fix| ExpandedFix {
|
||||
content: fix.content,
|
||||
message: message.kind.suggestion,
|
||||
message: diagnostic.kind.commit(),
|
||||
location: fix.location,
|
||||
end_location: fix.end_location,
|
||||
}),
|
||||
@@ -215,3 +223,55 @@ pub fn check(contents: &str, options: JsValue) -> Result<JsValue, JsValue> {
|
||||
|
||||
Ok(serde_wasm_bindgen::to_value(&messages)?)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use js_sys;
|
||||
use wasm_bindgen_test::*;
|
||||
|
||||
use super::*;
|
||||
|
||||
macro_rules! check {
|
||||
($source:expr, $config:expr, $expected:expr) => {{
|
||||
let foo = js_sys::JSON::parse($config).unwrap();
|
||||
match check($source, foo) {
|
||||
Ok(output) => {
|
||||
let result: Vec<Message> = serde_wasm_bindgen::from_value(output).unwrap();
|
||||
assert_eq!(result, $expected);
|
||||
}
|
||||
Err(e) => assert!(false, "{:#?}", e),
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn empty_config() {
|
||||
check!(
|
||||
"if (1, 2): pass",
|
||||
r#"{}"#,
|
||||
[ExpandedMessage {
|
||||
code: Rule::IfTuple.into(),
|
||||
message: "If test is a tuple, which is always `True`".to_string(),
|
||||
location: Location::new(1, 0),
|
||||
end_location: Location::new(1, 15),
|
||||
fix: None,
|
||||
}]
|
||||
);
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn partial_config() {
|
||||
check!("if (1, 2): pass", r#"{"ignore": ["F"]}"#, []);
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn partial_nested_config() {
|
||||
let config = r#"{
|
||||
"select": ["Q"],
|
||||
"flake8-quotes": {
|
||||
"inline-quotes": "single"
|
||||
}
|
||||
}"#;
|
||||
check!(r#"print('hello world')"#, config, []);
|
||||
}
|
||||
}
|
||||
@@ -8,10 +8,6 @@ use rustc_hash::FxHashMap;
|
||||
use rustpython_parser::lexer::LexResult;
|
||||
use rustpython_parser::ParseError;
|
||||
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
use ruff_python_ast::source_code::{Indexer, Locator, Stylist};
|
||||
use ruff_python_stdlib::path::is_python_stub_file;
|
||||
|
||||
use crate::autofix::fix_file;
|
||||
use crate::checkers::ast::check_ast;
|
||||
use crate::checkers::filesystem::check_file_path;
|
||||
@@ -24,9 +20,11 @@ use crate::directives::Directives;
|
||||
use crate::doc_lines::{doc_lines_from_ast, doc_lines_from_tokens};
|
||||
use crate::message::{Message, Source};
|
||||
use crate::noqa::{add_noqa, rule_is_ignored};
|
||||
use crate::registry::{AsRule, Rule};
|
||||
use crate::registry::{Diagnostic, Rule};
|
||||
use crate::resolver::is_interface_definition_path;
|
||||
use crate::rules::pycodestyle;
|
||||
use crate::settings::{flags, Settings};
|
||||
use crate::source_code::{Indexer, Locator, Stylist};
|
||||
use crate::{directives, fs};
|
||||
|
||||
const CARGO_PKG_NAME: &str = env!("CARGO_PKG_NAME");
|
||||
@@ -86,8 +84,14 @@ pub fn check_path(
|
||||
.iter_enabled()
|
||||
.any(|rule_code| rule_code.lint_source().is_tokens())
|
||||
{
|
||||
let is_stub = is_python_stub_file(path);
|
||||
diagnostics.extend(check_tokens(locator, &tokens, settings, autofix, is_stub));
|
||||
let is_interface_definition = is_interface_definition_path(path);
|
||||
diagnostics.extend(check_tokens(
|
||||
locator,
|
||||
&tokens,
|
||||
settings,
|
||||
autofix,
|
||||
is_interface_definition,
|
||||
));
|
||||
}
|
||||
|
||||
// Run the filesystem-based rules.
|
||||
@@ -191,8 +195,8 @@ pub fn check_path(
|
||||
{
|
||||
diagnostics.extend(check_physical_lines(
|
||||
path,
|
||||
locator,
|
||||
stylist,
|
||||
contents,
|
||||
indexer.commented_lines(),
|
||||
&doc_lines,
|
||||
settings,
|
||||
@@ -204,7 +208,7 @@ pub fn check_path(
|
||||
if !diagnostics.is_empty() && !settings.per_file_ignores.is_empty() {
|
||||
let ignores = fs::ignores_from_path(path, &settings.per_file_ignores);
|
||||
if !ignores.is_empty() {
|
||||
diagnostics.retain(|diagnostic| !ignores.contains(diagnostic.kind.rule()));
|
||||
diagnostics.retain(|diagnostic| !ignores.contains(&diagnostic.kind.rule()));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -215,7 +219,7 @@ pub fn check_path(
|
||||
.iter_enabled()
|
||||
.any(|rule_code| rule_code.lint_source().is_noqa())
|
||||
{
|
||||
let ignored = check_noqa(
|
||||
check_noqa(
|
||||
&mut diagnostics,
|
||||
contents,
|
||||
indexer.commented_lines(),
|
||||
@@ -223,11 +227,6 @@ pub fn check_path(
|
||||
settings,
|
||||
error.as_ref().map_or(autofix, |_| flags::Autofix::Disabled),
|
||||
);
|
||||
if noqa.into() {
|
||||
for index in ignored.iter().rev() {
|
||||
diagnostics.swap_remove(*index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LinterResult::new(diagnostics, error)
|
||||
|
||||
@@ -3,9 +3,10 @@ use std::cmp::Ordering;
|
||||
pub use rustpython_parser::ast::Location;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, DiagnosticKind, Fix};
|
||||
use ruff_python_ast::source_code::Locator;
|
||||
use ruff_python_ast::types::Range;
|
||||
use crate::ast::types::Range;
|
||||
use crate::fix::Fix;
|
||||
use crate::registry::{Diagnostic, DiagnosticKind};
|
||||
use crate::source_code::Locator;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Message {
|
||||
@@ -73,9 +74,9 @@ impl Source {
|
||||
} else {
|
||||
Location::new(diagnostic.end_location.row() + 1, 0)
|
||||
};
|
||||
let source = locator.slice(Range::new(location, end_location));
|
||||
let source = locator.slice(&Range::new(location, end_location));
|
||||
let num_chars_in_range = locator
|
||||
.slice(Range::new(diagnostic.location, diagnostic.end_location))
|
||||
.slice(&Range::new(diagnostic.location, diagnostic.end_location))
|
||||
.chars()
|
||||
.count();
|
||||
Source {
|
||||
|
||||
@@ -11,18 +11,15 @@ use regex::Regex;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use rustpython_parser::ast::Location;
|
||||
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
use ruff_python_ast::newlines::StrExt;
|
||||
use ruff_python_ast::source_code::{LineEnding, Locator};
|
||||
use ruff_python_ast::types::Range;
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::codes::NoqaCode;
|
||||
use crate::registry::{AsRule, Rule};
|
||||
use crate::registry::{Diagnostic, Rule};
|
||||
use crate::rule_redirects::get_redirect_target;
|
||||
use crate::source_code::{LineEnding, Locator};
|
||||
|
||||
static NOQA_LINE_REGEX: Lazy<Regex> = Lazy::new(|| {
|
||||
Regex::new(
|
||||
r"(?P<leading_spaces>\s*)(?P<noqa>(?i:# noqa)(?::\s?(?P<codes>(?:[A-Z]+[0-9]+)(?:[,\s]+[A-Z]+[0-9]+)*))?)(?P<trailing_spaces>\s*)",
|
||||
r"(?P<spaces>\s*)(?P<noqa>(?i:# noqa)(?::\s?(?P<codes>([A-Z]+[0-9]+(?:[,\s]+)?)+))?)",
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
@@ -74,42 +71,35 @@ pub fn extract_file_exemption(line: &str) -> Exemption {
|
||||
#[derive(Debug)]
|
||||
pub enum Directive<'a> {
|
||||
None,
|
||||
All(usize, usize, usize, usize),
|
||||
Codes(usize, usize, usize, Vec<&'a str>, usize),
|
||||
All(usize, usize, usize),
|
||||
Codes(usize, usize, usize, Vec<&'a str>),
|
||||
}
|
||||
|
||||
/// Extract the noqa `Directive` from a line of Python source code.
|
||||
pub fn extract_noqa_directive(line: &str) -> Directive {
|
||||
match NOQA_LINE_REGEX.captures(line) {
|
||||
Some(caps) => match caps.name("leading_spaces") {
|
||||
Some(leading_spaces) => match caps.name("trailing_spaces") {
|
||||
Some(trailing_spaces) => match caps.name("noqa") {
|
||||
Some(noqa) => match caps.name("codes") {
|
||||
Some(codes) => {
|
||||
let codes: Vec<&str> = SPLIT_COMMA_REGEX
|
||||
.split(codes.as_str().trim())
|
||||
.map(str::trim)
|
||||
.filter(|code| !code.is_empty())
|
||||
.collect();
|
||||
if codes.is_empty() {
|
||||
warn!("Expected rule codes on `noqa` directive: \"{line}\"");
|
||||
}
|
||||
Directive::Codes(
|
||||
leading_spaces.as_str().chars().count(),
|
||||
noqa.start(),
|
||||
noqa.end(),
|
||||
codes,
|
||||
trailing_spaces.as_str().chars().count(),
|
||||
)
|
||||
Some(caps) => match caps.name("spaces") {
|
||||
Some(spaces) => match caps.name("noqa") {
|
||||
Some(noqa) => match caps.name("codes") {
|
||||
Some(codes) => {
|
||||
let codes: Vec<&str> = SPLIT_COMMA_REGEX
|
||||
.split(codes.as_str().trim())
|
||||
.map(str::trim)
|
||||
.filter(|code| !code.is_empty())
|
||||
.collect();
|
||||
if codes.is_empty() {
|
||||
warn!("Expected rule codes on `noqa` directive: \"{line}\"");
|
||||
}
|
||||
None => Directive::All(
|
||||
leading_spaces.as_str().chars().count(),
|
||||
Directive::Codes(
|
||||
spaces.as_str().chars().count(),
|
||||
noqa.start(),
|
||||
noqa.end(),
|
||||
trailing_spaces.as_str().chars().count(),
|
||||
),
|
||||
},
|
||||
None => Directive::None,
|
||||
codes,
|
||||
)
|
||||
}
|
||||
None => {
|
||||
Directive::All(spaces.as_str().chars().count(), noqa.start(), noqa.end())
|
||||
}
|
||||
},
|
||||
None => Directive::None,
|
||||
},
|
||||
@@ -136,14 +126,14 @@ pub fn rule_is_ignored(
|
||||
locator: &Locator,
|
||||
) -> bool {
|
||||
let noqa_lineno = noqa_line_for.get(&lineno).unwrap_or(&lineno);
|
||||
let line = locator.slice(Range::new(
|
||||
let line = locator.slice(&Range::new(
|
||||
Location::new(*noqa_lineno, 0),
|
||||
Location::new(noqa_lineno + 1, 0),
|
||||
));
|
||||
match extract_noqa_directive(line) {
|
||||
Directive::None => false,
|
||||
Directive::All(..) => true,
|
||||
Directive::Codes(.., codes, _) => includes(code, &codes),
|
||||
Directive::Codes(.., codes) => includes(code, &codes),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,7 +172,7 @@ fn add_noqa_inner(
|
||||
// Codes that are globally exempted (within the current file).
|
||||
let mut file_exemptions: Vec<NoqaCode> = vec![];
|
||||
|
||||
let lines: Vec<&str> = contents.universal_newlines().collect();
|
||||
let lines: Vec<&str> = contents.lines().collect();
|
||||
for lineno in commented_lines {
|
||||
match extract_file_exemption(lines[lineno - 1]) {
|
||||
Exemption::All => {
|
||||
@@ -224,7 +214,7 @@ fn add_noqa_inner(
|
||||
Directive::All(..) => {
|
||||
continue;
|
||||
}
|
||||
Directive::Codes(.., codes, _) => {
|
||||
Directive::Codes(.., codes) => {
|
||||
if includes(diagnostic.kind.rule(), &codes) {
|
||||
continue;
|
||||
}
|
||||
@@ -244,7 +234,7 @@ fn add_noqa_inner(
|
||||
Directive::All(..) => {
|
||||
continue;
|
||||
}
|
||||
Directive::Codes(.., codes, _) => {
|
||||
Directive::Codes(.., codes) => {
|
||||
if includes(diagnostic.kind.rule(), &codes) {
|
||||
continue;
|
||||
}
|
||||
@@ -264,7 +254,7 @@ fn add_noqa_inner(
|
||||
|
||||
let mut count: usize = 0;
|
||||
let mut output = String::new();
|
||||
for (lineno, line) in lines.into_iter().enumerate() {
|
||||
for (lineno, line) in contents.lines().enumerate() {
|
||||
match matches_by_line.get(&lineno) {
|
||||
None => {
|
||||
output.push_str(line);
|
||||
@@ -289,7 +279,7 @@ fn add_noqa_inner(
|
||||
output.push_str(line);
|
||||
output.push_str(line_ending);
|
||||
}
|
||||
Directive::Codes(_, start_byte, _, existing, _) => {
|
||||
Directive::Codes(_, start_byte, _, existing) => {
|
||||
// Reconstruct the line based on the preserved rule codes.
|
||||
// This enables us to tally the number of edits.
|
||||
let mut formatted = String::with_capacity(line.len());
|
||||
@@ -342,13 +332,12 @@ mod tests {
|
||||
use nohash_hasher::IntMap;
|
||||
use rustpython_parser::ast::Location;
|
||||
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
use ruff_python_ast::source_code::LineEnding;
|
||||
use ruff_python_ast::types::Range;
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::noqa::{add_noqa_inner, NOQA_LINE_REGEX};
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::rules::pycodestyle::rules::AmbiguousVariableName;
|
||||
use crate::rules::pyflakes;
|
||||
use crate::source_code::LineEnding;
|
||||
|
||||
#[test]
|
||||
fn regex() {
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
//! Registry of all [`Rule`] implementations.
|
||||
//! Registry of [`Rule`] to [`DiagnosticKind`] mappings.
|
||||
|
||||
use ruff_macros::RuleNamespace;
|
||||
use rustpython_parser::ast::Location;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum_macros::{AsRefStr, EnumIter};
|
||||
|
||||
use ruff_diagnostics::Violation;
|
||||
use ruff_macros::RuleNamespace;
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::codes::{self, RuleCodePrefix};
|
||||
use crate::fix::Fix;
|
||||
use crate::rules;
|
||||
use crate::violation::Violation;
|
||||
|
||||
ruff_macros::register_rules!(
|
||||
// pycodestyle errors
|
||||
@@ -146,8 +149,6 @@ ruff_macros::register_rules!(
|
||||
rules::pylint::rules::YieldInInit,
|
||||
rules::pylint::rules::InvalidAllObject,
|
||||
rules::pylint::rules::InvalidAllFormat,
|
||||
rules::pylint::rules::InvalidEnvvarDefault,
|
||||
rules::pylint::rules::InvalidEnvvarValue,
|
||||
rules::pylint::rules::BadStringFormatType,
|
||||
rules::pylint::rules::BidirectionalUnicode,
|
||||
rules::pylint::rules::BadStrStripCall,
|
||||
@@ -160,7 +161,6 @@ ruff_macros::register_rules!(
|
||||
rules::pylint::rules::PropertyWithParameters,
|
||||
rules::pylint::rules::ReturnInInit,
|
||||
rules::pylint::rules::ConsiderUsingFromImport,
|
||||
rules::pylint::rules::CompareToEmptyString,
|
||||
rules::pylint::rules::ComparisonOfConstant,
|
||||
rules::pylint::rules::ConsiderMergingIsinstance,
|
||||
rules::pylint::rules::ConsiderUsingSysExit,
|
||||
@@ -209,7 +209,6 @@ ruff_macros::register_rules!(
|
||||
rules::flake8_bugbear::rules::RaiseWithoutFromInsideExcept,
|
||||
rules::flake8_bugbear::rules::ZipWithoutExplicitStrict,
|
||||
rules::flake8_bugbear::rules::ExceptWithEmptyTuple,
|
||||
rules::flake8_bugbear::rules::ExceptWithNonExceptionClasses,
|
||||
rules::flake8_bugbear::rules::UnintentionalTypeAnnotation,
|
||||
// flake8-blind-except
|
||||
rules::flake8_blind_except::rules::BlindExcept,
|
||||
@@ -341,7 +340,7 @@ ruff_macros::register_rules!(
|
||||
rules::pyupgrade::rules::FString,
|
||||
rules::pyupgrade::rules::FunctoolsCache,
|
||||
rules::pyupgrade::rules::ExtraneousParentheses,
|
||||
rules::pyupgrade::rules::DeprecatedImport,
|
||||
rules::pyupgrade::rules::ImportReplacements,
|
||||
rules::pyupgrade::rules::OutdatedVersionBlock,
|
||||
rules::pyupgrade::rules::QuotedAnnotation,
|
||||
rules::pyupgrade::rules::IsinstanceWithTuple,
|
||||
@@ -610,20 +609,6 @@ ruff_macros::register_rules!(
|
||||
rules::flake8_django::rules::NonLeadingReceiverDecorator,
|
||||
);
|
||||
|
||||
impl Rule {
|
||||
pub fn from_code(code: &str) -> Result<Self, FromCodeError> {
|
||||
let (linter, code) = Linter::parse_code(code).ok_or(FromCodeError::Unknown)?;
|
||||
let prefix: RuleCodePrefix = RuleCodePrefix::parse(&linter, code)?;
|
||||
Ok(prefix.into_iter().next().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum FromCodeError {
|
||||
#[error("unknown rule code")]
|
||||
Unknown,
|
||||
}
|
||||
|
||||
#[derive(EnumIter, Debug, PartialEq, Eq, Clone, Hash, RuleNamespace)]
|
||||
pub enum Linter {
|
||||
/// [Pyflakes](https://pypi.org/project/pyflakes/)
|
||||
@@ -805,7 +790,7 @@ impl Linter {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(is_macro::Is, Copy, Clone)]
|
||||
#[derive(is_macro::Is)]
|
||||
pub enum LintSource {
|
||||
Ast,
|
||||
Io,
|
||||
@@ -820,9 +805,9 @@ pub enum LintSource {
|
||||
impl Rule {
|
||||
/// The source for the diagnostic (either the AST, the filesystem, or the
|
||||
/// physical lines).
|
||||
pub const fn lint_source(&self) -> LintSource {
|
||||
pub const fn lint_source(&self) -> &'static LintSource {
|
||||
match self {
|
||||
Rule::UnusedNOQA => LintSource::Noqa,
|
||||
Rule::UnusedNOQA => &LintSource::Noqa,
|
||||
Rule::BlanketNOQA
|
||||
| Rule::BlanketTypeIgnore
|
||||
| Rule::DocLineTooLong
|
||||
@@ -838,7 +823,7 @@ impl Rule {
|
||||
| Rule::ShebangWhitespace
|
||||
| Rule::TrailingWhitespace
|
||||
| Rule::IndentationContainsTabs
|
||||
| Rule::BlankLineContainsWhitespace => LintSource::PhysicalLines,
|
||||
| Rule::BlankLineContainsWhitespace => &LintSource::PhysicalLines,
|
||||
Rule::AmbiguousUnicodeCharacterComment
|
||||
| Rule::AmbiguousUnicodeCharacterDocstring
|
||||
| Rule::AmbiguousUnicodeCharacterString
|
||||
@@ -857,10 +842,10 @@ impl Rule {
|
||||
| Rule::UselessSemicolon
|
||||
| Rule::MultipleStatementsOnOneLineSemicolon
|
||||
| Rule::TrailingCommaProhibited
|
||||
| Rule::TypeCommentInStub => LintSource::Tokens,
|
||||
Rule::IOError => LintSource::Io,
|
||||
Rule::UnsortedImports | Rule::MissingRequiredImport => LintSource::Imports,
|
||||
Rule::ImplicitNamespacePackage | Rule::InvalidModuleName => LintSource::Filesystem,
|
||||
| Rule::TypeCommentInStub => &LintSource::Tokens,
|
||||
Rule::IOError => &LintSource::Io,
|
||||
Rule::UnsortedImports | Rule::MissingRequiredImport => &LintSource::Imports,
|
||||
Rule::ImplicitNamespacePackage | Rule::InvalidModuleName => &LintSource::Filesystem,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
Rule::IndentationWithInvalidMultiple
|
||||
| Rule::IndentationWithInvalidMultipleComment
|
||||
@@ -892,12 +877,43 @@ impl Rule {
|
||||
| Rule::WhitespaceAfterOpenBracket
|
||||
| Rule::WhitespaceBeforeCloseBracket
|
||||
| Rule::WhitespaceBeforeParameters
|
||||
| Rule::WhitespaceBeforePunctuation => LintSource::LogicalLines,
|
||||
_ => LintSource::Ast,
|
||||
| Rule::WhitespaceBeforePunctuation => &LintSource::LogicalLines,
|
||||
_ => &LintSource::Ast,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Diagnostic {
|
||||
pub kind: DiagnosticKind,
|
||||
pub location: Location,
|
||||
pub end_location: Location,
|
||||
pub fix: Option<Fix>,
|
||||
pub parent: Option<Location>,
|
||||
}
|
||||
|
||||
impl Diagnostic {
|
||||
pub fn new<K: Into<DiagnosticKind>>(kind: K, range: Range) -> Self {
|
||||
Self {
|
||||
kind: kind.into(),
|
||||
location: range.location,
|
||||
end_location: range.end_location,
|
||||
fix: None,
|
||||
parent: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn amend(&mut self, fix: Fix) -> &mut Self {
|
||||
self.fix = Some(fix);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn parent(&mut self, parent: Location) -> &mut Self {
|
||||
self.parent = Some(parent);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Pairs of checks that shouldn't be enabled together.
|
||||
pub const INCOMPATIBLE_CODES: &[(Rule, Rule, &str); 2] = &[
|
||||
(
|
||||
|
||||
@@ -10,7 +10,6 @@ use ignore::{DirEntry, WalkBuilder, WalkState};
|
||||
use itertools::Itertools;
|
||||
use log::debug;
|
||||
use path_absolutize::path_dedot;
|
||||
use ruff_python_stdlib::path::is_python_file;
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use crate::fs;
|
||||
@@ -127,8 +126,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))?;
|
||||
let options = pyproject::load_options(&path)?;
|
||||
let project_root = relativity.resolve(&path);
|
||||
let configuration = Configuration::from_options(options, &project_root)?;
|
||||
|
||||
@@ -193,9 +191,20 @@ 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 [`Path`] appears to be that of a Python file.
|
||||
fn is_python_path(path: &Path) -> bool {
|
||||
path.extension()
|
||||
.map_or(false, |ext| ext == "py" || ext == "pyi")
|
||||
}
|
||||
|
||||
/// Return `true` if the [`Path`] appears to be that of a Python interface definition file (`.pyi`).
|
||||
pub fn is_interface_definition_path(path: &Path) -> bool {
|
||||
path.extension().map_or(false, |ext| ext == "pyi")
|
||||
}
|
||||
|
||||
/// Return `true` if the [`DirEntry`] appears to be that of a Python file.
|
||||
pub fn is_python_entry(entry: &DirEntry) -> bool {
|
||||
is_python_file(entry.path())
|
||||
is_python_path(entry.path())
|
||||
&& !entry
|
||||
.file_type()
|
||||
.map_or(false, |file_type| file_type.is_dir())
|
||||
@@ -421,13 +430,28 @@ mod tests {
|
||||
|
||||
use crate::fs;
|
||||
use crate::resolver::{
|
||||
is_file_excluded, match_exclusion, resolve_settings_with_processor, NoOpProcessor,
|
||||
PyprojectDiscovery, Relativity, Resolver,
|
||||
is_file_excluded, is_python_path, match_exclusion, resolve_settings_with_processor,
|
||||
NoOpProcessor, PyprojectDiscovery, Relativity, Resolver,
|
||||
};
|
||||
use crate::settings::pyproject::find_settings_toml;
|
||||
use crate::settings::types::FilePattern;
|
||||
use crate::test::test_resource_path;
|
||||
|
||||
#[test]
|
||||
fn inclusions() {
|
||||
let path = Path::new("foo/bar/baz.py").absolutize().unwrap();
|
||||
assert!(is_python_path(&path));
|
||||
|
||||
let path = Path::new("foo/bar/baz.pyi").absolutize().unwrap();
|
||||
assert!(is_python_path(&path));
|
||||
|
||||
let path = Path::new("foo/bar/baz.js").absolutize().unwrap();
|
||||
assert!(!is_python_path(&path));
|
||||
|
||||
let path = Path::new("foo/bar/baz").absolutize().unwrap();
|
||||
assert!(!is_python_path(&path));
|
||||
}
|
||||
|
||||
fn make_exclusion(file_pattern: FilePattern) -> GlobSet {
|
||||
let mut builder = globset::GlobSetBuilder::new();
|
||||
file_pattern.add_to(&mut builder).unwrap();
|
||||
|
||||
@@ -18,8 +18,9 @@ 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"),
|
||||
("C", "C4"),
|
||||
("C9", "C90"),
|
||||
("T", "T10"),
|
||||
("T1", "T10"),
|
||||
("T2", "T20"),
|
||||
// TODO(charlie): Remove by 2023-02-01.
|
||||
|
||||
@@ -15,17 +15,9 @@ use crate::rule_redirects::get_redirect;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum RuleSelector {
|
||||
/// Select all rules.
|
||||
/// All rules
|
||||
All,
|
||||
/// Legacy category to select both the `mccabe` and `flake8-comprehensions` linters
|
||||
/// via a single selector.
|
||||
C,
|
||||
/// Legacy category to select both the `flake8-debugger` and `flake8-print` linters
|
||||
/// via a single selector.
|
||||
T,
|
||||
/// Select all rules for a given linter.
|
||||
Linter(Linter),
|
||||
/// Select all rules for a given linter with a given prefix.
|
||||
Prefix {
|
||||
prefix: RuleCodePrefix,
|
||||
redirected_from: Option<&'static str>,
|
||||
@@ -44,10 +36,6 @@ impl FromStr for RuleSelector {
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
if s == "ALL" {
|
||||
Ok(Self::All)
|
||||
} else if s == "C" {
|
||||
Ok(Self::C)
|
||||
} else if s == "T" {
|
||||
Ok(Self::T)
|
||||
} else {
|
||||
let (s, redirected_from) = match get_redirect(s) {
|
||||
Some((from, target)) => (target, Some(from)),
|
||||
@@ -63,7 +51,7 @@ impl FromStr for RuleSelector {
|
||||
|
||||
Ok(Self::Prefix {
|
||||
prefix: RuleCodePrefix::parse(&linter, code)
|
||||
.map_err(|_| ParseError::Unknown(s.to_string()))?,
|
||||
.map_err(|_| ParseError::Unknown(code.to_string()))?,
|
||||
redirected_from,
|
||||
})
|
||||
}
|
||||
@@ -72,7 +60,7 @@ impl FromStr for RuleSelector {
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum ParseError {
|
||||
#[error("Unknown rule selector: `{0}`")]
|
||||
#[error("Unknown rule selector `{0}`")]
|
||||
// TODO(martin): tell the user how to discover rule codes via the CLI once such a command is
|
||||
// implemented (but that should of course be done only in ruff_cli and not here)
|
||||
Unknown(String),
|
||||
@@ -82,8 +70,6 @@ impl RuleSelector {
|
||||
pub fn prefix_and_code(&self) -> (&'static str, &'static str) {
|
||||
match self {
|
||||
RuleSelector::All => ("", "ALL"),
|
||||
RuleSelector::C => ("", "C"),
|
||||
RuleSelector::T => ("", "T"),
|
||||
RuleSelector::Prefix { prefix, .. } => {
|
||||
(prefix.linter().common_prefix(), prefix.short_code())
|
||||
}
|
||||
@@ -152,16 +138,6 @@ impl IntoIterator for &RuleSelector {
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
match self {
|
||||
RuleSelector::All => RuleSelectorIter::All(Rule::iter()),
|
||||
RuleSelector::C => RuleSelectorIter::Chain(
|
||||
Linter::Flake8Comprehensions
|
||||
.into_iter()
|
||||
.chain(Linter::McCabe.into_iter()),
|
||||
),
|
||||
RuleSelector::T => RuleSelectorIter::Chain(
|
||||
Linter::Flake8Debugger
|
||||
.into_iter()
|
||||
.chain(Linter::Flake8Print.into_iter()),
|
||||
),
|
||||
RuleSelector::Linter(linter) => RuleSelectorIter::Vec(linter.into_iter()),
|
||||
RuleSelector::Prefix { prefix, .. } => RuleSelectorIter::Vec(prefix.into_iter()),
|
||||
}
|
||||
@@ -170,7 +146,6 @@ impl IntoIterator for &RuleSelector {
|
||||
|
||||
pub enum RuleSelectorIter {
|
||||
All(RuleIter),
|
||||
Chain(std::iter::Chain<std::vec::IntoIter<Rule>, std::vec::IntoIter<Rule>>),
|
||||
Vec(std::vec::IntoIter<Rule>),
|
||||
}
|
||||
|
||||
@@ -180,14 +155,13 @@ impl Iterator for RuleSelectorIter {
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self {
|
||||
RuleSelectorIter::All(iter) => iter.next(),
|
||||
RuleSelectorIter::Chain(iter) => iter.next(),
|
||||
RuleSelectorIter::Vec(iter) => iter.next(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A const alternative to the `impl From<RuleCodePrefix> for RuleSelector`
|
||||
/// to let us keep the fields of [`RuleSelector`] private.
|
||||
// to let us keep the fields of RuleSelector private.
|
||||
// Note that Rust doesn't yet support `impl const From<RuleCodePrefix> for
|
||||
// RuleSelector` (see https://github.com/rust-lang/rust/issues/67792).
|
||||
// TODO(martin): Remove once RuleSelector is an enum with Linter & Rule variants
|
||||
@@ -203,27 +177,13 @@ impl JsonSchema for RuleSelector {
|
||||
"RuleSelector".to_string()
|
||||
}
|
||||
|
||||
fn json_schema(_gen: &mut schemars::gen::SchemaGenerator) -> Schema {
|
||||
fn json_schema(_gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
|
||||
Schema::Object(SchemaObject {
|
||||
instance_type: Some(InstanceType::String.into()),
|
||||
enum_values: Some(
|
||||
std::iter::once("ALL".to_string())
|
||||
.chain(
|
||||
RuleCodePrefix::iter()
|
||||
.filter(|p| {
|
||||
// Once logical lines are active by default, please remove this.
|
||||
// This is here because generate-all output otherwise depends on
|
||||
// the feature sets which makes the test running with
|
||||
// `--all-features` fail
|
||||
!Rule::from_code(&format!(
|
||||
"{}{}",
|
||||
p.linter().common_prefix(),
|
||||
p.short_code()
|
||||
))
|
||||
.unwrap()
|
||||
.lint_source()
|
||||
.is_logical_lines()
|
||||
})
|
||||
.map(|p| {
|
||||
let prefix = p.linter().common_prefix();
|
||||
let code = p.short_code();
|
||||
@@ -247,8 +207,6 @@ impl RuleSelector {
|
||||
pub(crate) fn specificity(&self) -> Specificity {
|
||||
match self {
|
||||
RuleSelector::All => Specificity::All,
|
||||
RuleSelector::T => Specificity::LinterGroup,
|
||||
RuleSelector::C => Specificity::LinterGroup,
|
||||
RuleSelector::Linter(..) => Specificity::Linter,
|
||||
RuleSelector::Prefix { prefix, .. } => {
|
||||
let prefix: &'static str = prefix.short_code();
|
||||
@@ -268,7 +226,6 @@ impl RuleSelector {
|
||||
#[derive(EnumIter, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub(crate) enum Specificity {
|
||||
All,
|
||||
LinterGroup,
|
||||
Linter,
|
||||
Code1Char,
|
||||
Code2Chars,
|
||||
|
||||
@@ -1,29 +1,28 @@
|
||||
use ruff_macros::{define_violation, derive_message_formats};
|
||||
use rustpython_parser::ast::Location;
|
||||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Fix};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::source_code::Locator;
|
||||
use ruff_python_ast::types::Range;
|
||||
|
||||
use crate::registry::Rule;
|
||||
use crate::settings::{flags, Settings};
|
||||
|
||||
use super::detection::comment_contains_code;
|
||||
use crate::ast::types::Range;
|
||||
use crate::fix::Fix;
|
||||
use crate::registry::{Diagnostic, Rule};
|
||||
use crate::settings::{flags, Settings};
|
||||
use crate::source_code::Locator;
|
||||
use crate::violation::AlwaysAutofixableViolation;
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for commented-out Python code.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Commented-out code is dead code, and is often included inadvertently.
|
||||
/// It should be removed.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// # print('foo')
|
||||
/// ```
|
||||
#[violation]
|
||||
pub struct CommentedOutCode;
|
||||
|
||||
define_violation!(
|
||||
/// ## What it does
|
||||
/// Checks for commented-out Python code.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Commented-out code is dead code, and is often included inadvertently.
|
||||
/// It should be removed.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// # print('foo')
|
||||
/// ```
|
||||
pub struct CommentedOutCode;
|
||||
);
|
||||
impl AlwaysAutofixableViolation for CommentedOutCode {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
@@ -56,7 +55,7 @@ pub fn commented_out_code(
|
||||
) -> Option<Diagnostic> {
|
||||
let location = Location::new(start.row(), 0);
|
||||
let end_location = Location::new(end.row() + 1, 0);
|
||||
let line = locator.slice(Range::new(location, end_location));
|
||||
let line = locator.slice(&Range::new(location, end_location));
|
||||
|
||||
// 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[..]) {
|
||||
|
||||
@@ -3,10 +3,7 @@ source: crates/ruff/src/rules/eradicate/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: CommentedOutCode
|
||||
body: Found commented-out code
|
||||
suggestion: Remove commented-out code
|
||||
fixable: true
|
||||
CommentedOutCode: ~
|
||||
location:
|
||||
row: 1
|
||||
column: 0
|
||||
@@ -23,10 +20,7 @@ expression: diagnostics
|
||||
column: 0
|
||||
parent: ~
|
||||
- kind:
|
||||
name: CommentedOutCode
|
||||
body: Found commented-out code
|
||||
suggestion: Remove commented-out code
|
||||
fixable: true
|
||||
CommentedOutCode: ~
|
||||
location:
|
||||
row: 2
|
||||
column: 0
|
||||
@@ -43,10 +37,7 @@ expression: diagnostics
|
||||
column: 0
|
||||
parent: ~
|
||||
- kind:
|
||||
name: CommentedOutCode
|
||||
body: Found commented-out code
|
||||
suggestion: Remove commented-out code
|
||||
fixable: true
|
||||
CommentedOutCode: ~
|
||||
location:
|
||||
row: 3
|
||||
column: 0
|
||||
@@ -63,10 +54,7 @@ expression: diagnostics
|
||||
column: 0
|
||||
parent: ~
|
||||
- kind:
|
||||
name: CommentedOutCode
|
||||
body: Found commented-out code
|
||||
suggestion: Remove commented-out code
|
||||
fixable: true
|
||||
CommentedOutCode: ~
|
||||
location:
|
||||
row: 5
|
||||
column: 0
|
||||
@@ -83,10 +71,7 @@ expression: diagnostics
|
||||
column: 0
|
||||
parent: ~
|
||||
- kind:
|
||||
name: CommentedOutCode
|
||||
body: Found commented-out code
|
||||
suggestion: Remove commented-out code
|
||||
fixable: true
|
||||
CommentedOutCode: ~
|
||||
location:
|
||||
row: 12
|
||||
column: 4
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
use num_bigint::BigInt;
|
||||
use ruff_macros::{define_violation, derive_message_formats};
|
||||
use rustpython_parser::ast::{Cmpop, Constant, Expr, ExprKind, Located};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::types::Range;
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::Rule;
|
||||
|
||||
#[violation]
|
||||
pub struct SysVersionSlice3Referenced;
|
||||
use crate::registry::{Diagnostic, Rule};
|
||||
use crate::violation::Violation;
|
||||
|
||||
define_violation!(
|
||||
pub struct SysVersionSlice3Referenced;
|
||||
);
|
||||
impl Violation for SysVersionSlice3Referenced {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
@@ -18,9 +17,9 @@ impl Violation for SysVersionSlice3Referenced {
|
||||
}
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SysVersion2Referenced;
|
||||
|
||||
define_violation!(
|
||||
pub struct SysVersion2Referenced;
|
||||
);
|
||||
impl Violation for SysVersion2Referenced {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
@@ -28,9 +27,9 @@ impl Violation for SysVersion2Referenced {
|
||||
}
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SysVersionCmpStr3;
|
||||
|
||||
define_violation!(
|
||||
pub struct SysVersionCmpStr3;
|
||||
);
|
||||
impl Violation for SysVersionCmpStr3 {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
@@ -38,9 +37,9 @@ impl Violation for SysVersionCmpStr3 {
|
||||
}
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SysVersionInfo0Eq3Referenced;
|
||||
|
||||
define_violation!(
|
||||
pub struct SysVersionInfo0Eq3Referenced;
|
||||
);
|
||||
impl Violation for SysVersionInfo0Eq3Referenced {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
@@ -48,9 +47,9 @@ impl Violation for SysVersionInfo0Eq3Referenced {
|
||||
}
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SixPY3Referenced;
|
||||
|
||||
define_violation!(
|
||||
pub struct SixPY3Referenced;
|
||||
);
|
||||
impl Violation for SixPY3Referenced {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
@@ -58,9 +57,9 @@ impl Violation for SixPY3Referenced {
|
||||
}
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SysVersionInfo1CmpInt;
|
||||
|
||||
define_violation!(
|
||||
pub struct SysVersionInfo1CmpInt;
|
||||
);
|
||||
impl Violation for SysVersionInfo1CmpInt {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
@@ -71,9 +70,9 @@ impl Violation for SysVersionInfo1CmpInt {
|
||||
}
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SysVersionInfoMinorCmpInt;
|
||||
|
||||
define_violation!(
|
||||
pub struct SysVersionInfoMinorCmpInt;
|
||||
);
|
||||
impl Violation for SysVersionInfoMinorCmpInt {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
@@ -84,9 +83,9 @@ impl Violation for SysVersionInfoMinorCmpInt {
|
||||
}
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SysVersion0Referenced;
|
||||
|
||||
define_violation!(
|
||||
pub struct SysVersion0Referenced;
|
||||
);
|
||||
impl Violation for SysVersion0Referenced {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
@@ -94,9 +93,9 @@ impl Violation for SysVersion0Referenced {
|
||||
}
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SysVersionCmpStr10;
|
||||
|
||||
define_violation!(
|
||||
pub struct SysVersionCmpStr10;
|
||||
);
|
||||
impl Violation for SysVersionCmpStr10 {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
@@ -104,9 +103,9 @@ impl Violation for SysVersionCmpStr10 {
|
||||
}
|
||||
}
|
||||
|
||||
#[violation]
|
||||
pub struct SysVersionSlice1Referenced;
|
||||
|
||||
define_violation!(
|
||||
pub struct SysVersionSlice1Referenced;
|
||||
);
|
||||
impl Violation for SysVersionSlice1Referenced {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
@@ -144,7 +143,7 @@ pub fn subscript(checker: &mut Checker, value: &Expr, slice: &Expr) {
|
||||
{
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
SysVersionSlice1Referenced,
|
||||
Range::from(value),
|
||||
Range::from_located(value),
|
||||
));
|
||||
} else if *i == BigInt::from(3)
|
||||
&& checker
|
||||
@@ -154,7 +153,7 @@ pub fn subscript(checker: &mut Checker, value: &Expr, slice: &Expr) {
|
||||
{
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
SysVersionSlice3Referenced,
|
||||
Range::from(value),
|
||||
Range::from_located(value),
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -167,15 +166,17 @@ pub fn subscript(checker: &mut Checker, value: &Expr, slice: &Expr) {
|
||||
if *i == BigInt::from(2)
|
||||
&& checker.settings.rules.enabled(&Rule::SysVersion2Referenced)
|
||||
{
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(SysVersion2Referenced, Range::from(value)));
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
SysVersion2Referenced,
|
||||
Range::from_located(value),
|
||||
));
|
||||
} else if *i == BigInt::from(0)
|
||||
&& checker.settings.rules.enabled(&Rule::SysVersion0Referenced)
|
||||
{
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(SysVersion0Referenced, Range::from(value)));
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
SysVersion0Referenced,
|
||||
Range::from_located(value),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,7 +215,7 @@ pub fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], comparators: &
|
||||
{
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
SysVersionInfo0Eq3Referenced,
|
||||
Range::from(left),
|
||||
Range::from_located(left),
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -232,9 +233,10 @@ pub fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], comparators: &
|
||||
) = (ops, comparators)
|
||||
{
|
||||
if checker.settings.rules.enabled(&Rule::SysVersionInfo1CmpInt) {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(SysVersionInfo1CmpInt, Range::from(left)));
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
SysVersionInfo1CmpInt,
|
||||
Range::from_located(left),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -263,7 +265,7 @@ pub fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], comparators: &
|
||||
{
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
SysVersionInfoMinorCmpInt,
|
||||
Range::from(left),
|
||||
Range::from_located(left),
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -287,14 +289,16 @@ pub fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], comparators: &
|
||||
{
|
||||
if s.len() == 1 {
|
||||
if checker.settings.rules.enabled(&Rule::SysVersionCmpStr10) {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(SysVersionCmpStr10, Range::from(left)));
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
SysVersionCmpStr10,
|
||||
Range::from_located(left),
|
||||
));
|
||||
}
|
||||
} else if checker.settings.rules.enabled(&Rule::SysVersionCmpStr3) {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(SysVersionCmpStr3, Range::from(left)));
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
SysVersionCmpStr3,
|
||||
Range::from_located(left),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -309,6 +313,6 @@ pub fn name_or_attribute(checker: &mut Checker, expr: &Expr) {
|
||||
{
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(SixPY3Referenced, Range::from(expr)));
|
||||
.push(Diagnostic::new(SixPY3Referenced, Range::from_located(expr)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
---
|
||||
source: crates/ruff/src/rules/flake8_2020/mod.rs
|
||||
source: src/rules/flake8_2020/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: SysVersionSlice3Referenced
|
||||
body: "`sys.version[:3]` referenced (python3.10), use `sys.version_info`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
SysVersionSlice3Referenced: ~
|
||||
location:
|
||||
row: 6
|
||||
column: 6
|
||||
@@ -16,10 +13,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: SysVersionSlice3Referenced
|
||||
body: "`sys.version[:3]` referenced (python3.10), use `sys.version_info`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
SysVersionSlice3Referenced: ~
|
||||
location:
|
||||
row: 7
|
||||
column: 6
|
||||
@@ -29,10 +23,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: SysVersionSlice3Referenced
|
||||
body: "`sys.version[:3]` referenced (python3.10), use `sys.version_info`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
SysVersionSlice3Referenced: ~
|
||||
location:
|
||||
row: 8
|
||||
column: 6
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
---
|
||||
source: crates/ruff/src/rules/flake8_2020/mod.rs
|
||||
source: src/rules/flake8_2020/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: SysVersion2Referenced
|
||||
body: "`sys.version[2]` referenced (python3.10), use `sys.version_info`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
SysVersion2Referenced: ~
|
||||
location:
|
||||
row: 4
|
||||
column: 11
|
||||
@@ -16,10 +13,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: SysVersion2Referenced
|
||||
body: "`sys.version[2]` referenced (python3.10), use `sys.version_info`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
SysVersion2Referenced: ~
|
||||
location:
|
||||
row: 5
|
||||
column: 11
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
---
|
||||
source: crates/ruff/src/rules/flake8_2020/mod.rs
|
||||
source: src/rules/flake8_2020/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: SysVersionCmpStr3
|
||||
body: "`sys.version` compared to string (python3.10), use `sys.version_info`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
SysVersionCmpStr3: ~
|
||||
location:
|
||||
row: 4
|
||||
column: 0
|
||||
@@ -16,10 +13,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: SysVersionCmpStr3
|
||||
body: "`sys.version` compared to string (python3.10), use `sys.version_info`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
SysVersionCmpStr3: ~
|
||||
location:
|
||||
row: 5
|
||||
column: 0
|
||||
@@ -29,10 +23,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: SysVersionCmpStr3
|
||||
body: "`sys.version` compared to string (python3.10), use `sys.version_info`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
SysVersionCmpStr3: ~
|
||||
location:
|
||||
row: 6
|
||||
column: 0
|
||||
@@ -42,10 +33,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: SysVersionCmpStr3
|
||||
body: "`sys.version` compared to string (python3.10), use `sys.version_info`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
SysVersionCmpStr3: ~
|
||||
location:
|
||||
row: 7
|
||||
column: 0
|
||||
@@ -55,10 +43,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: SysVersionCmpStr3
|
||||
body: "`sys.version` compared to string (python3.10), use `sys.version_info`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
SysVersionCmpStr3: ~
|
||||
location:
|
||||
row: 8
|
||||
column: 0
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
---
|
||||
source: crates/ruff/src/rules/flake8_2020/mod.rs
|
||||
source: src/rules/flake8_2020/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: SysVersionInfo0Eq3Referenced
|
||||
body: "`sys.version_info[0] == 3` referenced (python4), use `>=`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
SysVersionInfo0Eq3Referenced: ~
|
||||
location:
|
||||
row: 7
|
||||
column: 6
|
||||
@@ -16,10 +13,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: SysVersionInfo0Eq3Referenced
|
||||
body: "`sys.version_info[0] == 3` referenced (python4), use `>=`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
SysVersionInfo0Eq3Referenced: ~
|
||||
location:
|
||||
row: 8
|
||||
column: 6
|
||||
@@ -29,10 +23,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: SysVersionInfo0Eq3Referenced
|
||||
body: "`sys.version_info[0] == 3` referenced (python4), use `>=`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
SysVersionInfo0Eq3Referenced: ~
|
||||
location:
|
||||
row: 9
|
||||
column: 6
|
||||
@@ -42,10 +33,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: SysVersionInfo0Eq3Referenced
|
||||
body: "`sys.version_info[0] == 3` referenced (python4), use `>=`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
SysVersionInfo0Eq3Referenced: ~
|
||||
location:
|
||||
row: 10
|
||||
column: 6
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
---
|
||||
source: crates/ruff/src/rules/flake8_2020/mod.rs
|
||||
source: src/rules/flake8_2020/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: SixPY3Referenced
|
||||
body: "`six.PY3` referenced (python4), use `not six.PY2`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
SixPY3Referenced: ~
|
||||
location:
|
||||
row: 4
|
||||
column: 3
|
||||
@@ -16,10 +13,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: SixPY3Referenced
|
||||
body: "`six.PY3` referenced (python4), use `not six.PY2`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
SixPY3Referenced: ~
|
||||
location:
|
||||
row: 6
|
||||
column: 3
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
---
|
||||
source: crates/ruff/src/rules/flake8_2020/mod.rs
|
||||
source: src/rules/flake8_2020/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: SysVersionInfo1CmpInt
|
||||
body: "`sys.version_info[1]` compared to integer (python4), compare `sys.version_info` to tuple"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
SysVersionInfo1CmpInt: ~
|
||||
location:
|
||||
row: 4
|
||||
column: 0
|
||||
@@ -16,10 +13,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: SysVersionInfo1CmpInt
|
||||
body: "`sys.version_info[1]` compared to integer (python4), compare `sys.version_info` to tuple"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
SysVersionInfo1CmpInt: ~
|
||||
location:
|
||||
row: 5
|
||||
column: 0
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
---
|
||||
source: crates/ruff/src/rules/flake8_2020/mod.rs
|
||||
source: src/rules/flake8_2020/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: SysVersionInfoMinorCmpInt
|
||||
body: "`sys.version_info.minor` compared to integer (python4), compare `sys.version_info` to tuple"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
SysVersionInfoMinorCmpInt: ~
|
||||
location:
|
||||
row: 4
|
||||
column: 0
|
||||
@@ -16,10 +13,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: SysVersionInfoMinorCmpInt
|
||||
body: "`sys.version_info.minor` compared to integer (python4), compare `sys.version_info` to tuple"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
SysVersionInfoMinorCmpInt: ~
|
||||
location:
|
||||
row: 5
|
||||
column: 0
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
---
|
||||
source: crates/ruff/src/rules/flake8_2020/mod.rs
|
||||
source: src/rules/flake8_2020/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: SysVersion0Referenced
|
||||
body: "`sys.version[0]` referenced (python10), use `sys.version_info`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
SysVersion0Referenced: ~
|
||||
location:
|
||||
row: 4
|
||||
column: 11
|
||||
@@ -16,10 +13,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: SysVersion0Referenced
|
||||
body: "`sys.version[0]` referenced (python10), use `sys.version_info`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
SysVersion0Referenced: ~
|
||||
location:
|
||||
row: 5
|
||||
column: 11
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
---
|
||||
source: crates/ruff/src/rules/flake8_2020/mod.rs
|
||||
source: src/rules/flake8_2020/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: SysVersionCmpStr10
|
||||
body: "`sys.version` compared to string (python10), use `sys.version_info`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
SysVersionCmpStr10: ~
|
||||
location:
|
||||
row: 4
|
||||
column: 0
|
||||
@@ -16,10 +13,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: SysVersionCmpStr10
|
||||
body: "`sys.version` compared to string (python10), use `sys.version_info`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
SysVersionCmpStr10: ~
|
||||
location:
|
||||
row: 5
|
||||
column: 0
|
||||
@@ -29,10 +23,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: SysVersionCmpStr10
|
||||
body: "`sys.version` compared to string (python10), use `sys.version_info`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
SysVersionCmpStr10: ~
|
||||
location:
|
||||
row: 6
|
||||
column: 0
|
||||
@@ -42,10 +33,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: SysVersionCmpStr10
|
||||
body: "`sys.version` compared to string (python10), use `sys.version_info`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
SysVersionCmpStr10: ~
|
||||
location:
|
||||
row: 7
|
||||
column: 0
|
||||
@@ -55,10 +43,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: SysVersionCmpStr10
|
||||
body: "`sys.version` compared to string (python10), use `sys.version_info`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
SysVersionCmpStr10: ~
|
||||
location:
|
||||
row: 8
|
||||
column: 0
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
---
|
||||
source: crates/ruff/src/rules/flake8_2020/mod.rs
|
||||
source: src/rules/flake8_2020/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: SysVersionSlice1Referenced
|
||||
body: "`sys.version[:1]` referenced (python10), use `sys.version_info`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
SysVersionSlice1Referenced: ~
|
||||
location:
|
||||
row: 4
|
||||
column: 6
|
||||
@@ -16,10 +13,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: SysVersionSlice1Referenced
|
||||
body: "`sys.version[:1]` referenced (python10), use `sys.version_info`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
SysVersionSlice1Referenced: ~
|
||||
location:
|
||||
row: 5
|
||||
column: 6
|
||||
|
||||
@@ -2,14 +2,14 @@ use anyhow::{bail, Result};
|
||||
use rustpython_parser::ast::Stmt;
|
||||
use rustpython_parser::{lexer, Mode, Tok};
|
||||
|
||||
use ruff_diagnostics::Fix;
|
||||
use ruff_python_ast::source_code::Locator;
|
||||
use ruff_python_ast::types::Range;
|
||||
use crate::ast::types::Range;
|
||||
use crate::fix::Fix;
|
||||
use crate::source_code::Locator;
|
||||
|
||||
/// ANN204
|
||||
pub fn add_return_none_annotation(locator: &Locator, stmt: &Stmt) -> Result<Fix> {
|
||||
let range = Range::from(stmt);
|
||||
let contents = locator.slice(range);
|
||||
let range = Range::from_located(stmt);
|
||||
let contents = locator.slice(&range);
|
||||
|
||||
// Find the colon (following the `def` keyword).
|
||||
let mut seen_lpar = false;
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
use rustpython_parser::ast::{Arguments, Expr, Stmt, StmtKind};
|
||||
|
||||
use ruff_python_ast::cast;
|
||||
use ruff_python_ast::visibility;
|
||||
|
||||
use crate::ast::cast;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::docstrings::definition::{Definition, DefinitionKind};
|
||||
use crate::visibility;
|
||||
|
||||
pub(super) fn match_function_def(
|
||||
stmt: &Stmt,
|
||||
|
||||
@@ -1,46 +1,44 @@
|
||||
use log::error;
|
||||
use ruff_macros::{define_violation, derive_message_formats};
|
||||
use rustpython_parser::ast::{Constant, Expr, ExprKind, Stmt};
|
||||
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::helpers::ReturnStatementVisitor;
|
||||
use ruff_python_ast::types::Range;
|
||||
use ruff_python_ast::visibility;
|
||||
use ruff_python_ast::visibility::Visibility;
|
||||
use ruff_python_ast::visitor::Visitor;
|
||||
use ruff_python_ast::{cast, helpers};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::docstrings::definition::{Definition, DefinitionKind};
|
||||
use crate::registry::{AsRule, Rule};
|
||||
|
||||
use super::fixes;
|
||||
use super::helpers::match_function_def;
|
||||
use crate::ast::helpers::ReturnStatementVisitor;
|
||||
use crate::ast::types::Range;
|
||||
use crate::ast::visitor::Visitor;
|
||||
use crate::ast::{cast, helpers};
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::docstrings::definition::{Definition, DefinitionKind};
|
||||
use crate::registry::{Diagnostic, Rule};
|
||||
use crate::violation::{AlwaysAutofixableViolation, Violation};
|
||||
use crate::visibility;
|
||||
use crate::visibility::Visibility;
|
||||
|
||||
/// ## What it does
|
||||
/// Checks that function arguments have type annotations.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Type annotations are a good way to document the types of function arguments. They also
|
||||
/// help catch bugs, when used alongside a type checker, by ensuring that the types of
|
||||
/// any provided arguments match expectation.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def foo(x):
|
||||
/// ...
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// def foo(x: int):
|
||||
/// ...
|
||||
/// ```
|
||||
#[violation]
|
||||
pub struct MissingTypeFunctionArgument {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
/// ## What it does
|
||||
/// Checks that function arguments have type annotations.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Type annotations are a good way to document the types of function arguments. They also
|
||||
/// help catch bugs, when used alongside a type checker, by ensuring that the types of
|
||||
/// any provided arguments match expectation.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def foo(x):
|
||||
/// ...
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// def foo(x: int):
|
||||
/// ...
|
||||
/// ```
|
||||
pub struct MissingTypeFunctionArgument {
|
||||
pub name: String,
|
||||
}
|
||||
);
|
||||
impl Violation for MissingTypeFunctionArgument {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
@@ -49,30 +47,30 @@ impl Violation for MissingTypeFunctionArgument {
|
||||
}
|
||||
}
|
||||
|
||||
/// ## What it does
|
||||
/// Checks that function `*args` arguments have type annotations.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Type annotations are a good way to document the types of function arguments. They also
|
||||
/// help catch bugs, when used alongside a type checker, by ensuring that the types of
|
||||
/// any provided arguments match expectation.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def foo(*args):
|
||||
/// ...
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// def foo(*args: int):
|
||||
/// ...
|
||||
/// ```
|
||||
#[violation]
|
||||
pub struct MissingTypeArgs {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
/// ## What it does
|
||||
/// Checks that function `*args` arguments have type annotations.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Type annotations are a good way to document the types of function arguments. They also
|
||||
/// help catch bugs, when used alongside a type checker, by ensuring that the types of
|
||||
/// any provided arguments match expectation.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def foo(*args):
|
||||
/// ...
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// def foo(*args: int):
|
||||
/// ...
|
||||
/// ```
|
||||
pub struct MissingTypeArgs {
|
||||
pub name: String,
|
||||
}
|
||||
);
|
||||
impl Violation for MissingTypeArgs {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
@@ -81,30 +79,30 @@ impl Violation for MissingTypeArgs {
|
||||
}
|
||||
}
|
||||
|
||||
/// ## What it does
|
||||
/// Checks that function `**kwargs` arguments have type annotations.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Type annotations are a good way to document the types of function arguments. They also
|
||||
/// help catch bugs, when used alongside a type checker, by ensuring that the types of
|
||||
/// any provided arguments match expectation.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def foo(**kwargs):
|
||||
/// ...
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// def foo(**kwargs: int):
|
||||
/// ...
|
||||
/// ```
|
||||
#[violation]
|
||||
pub struct MissingTypeKwargs {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
/// ## What it does
|
||||
/// Checks that function `**kwargs` arguments have type annotations.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Type annotations are a good way to document the types of function arguments. They also
|
||||
/// help catch bugs, when used alongside a type checker, by ensuring that the types of
|
||||
/// any provided arguments match expectation.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def foo(**kwargs):
|
||||
/// ...
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// def foo(**kwargs: int):
|
||||
/// ...
|
||||
/// ```
|
||||
pub struct MissingTypeKwargs {
|
||||
pub name: String,
|
||||
}
|
||||
);
|
||||
impl Violation for MissingTypeKwargs {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
@@ -113,35 +111,35 @@ impl Violation for MissingTypeKwargs {
|
||||
}
|
||||
}
|
||||
|
||||
/// ## What it does
|
||||
/// Checks that instance method `self` arguments have type annotations.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Type annotations are a good way to document the types of function arguments. They also
|
||||
/// help catch bugs, when used alongside a type checker, by ensuring that the types of
|
||||
/// any provided arguments match expectation.
|
||||
///
|
||||
/// Note that many type checkers will infer the type of `self` automatically, so this
|
||||
/// annotation is not strictly necessary.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// class Foo:
|
||||
/// def bar(self):
|
||||
/// ...
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// class Foo:
|
||||
/// def bar(self: "Foo"):
|
||||
/// ...
|
||||
/// ```
|
||||
#[violation]
|
||||
pub struct MissingTypeSelf {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
/// ## What it does
|
||||
/// Checks that instance method `self` arguments have type annotations.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Type annotations are a good way to document the types of function arguments. They also
|
||||
/// help catch bugs, when used alongside a type checker, by ensuring that the types of
|
||||
/// any provided arguments match expectation.
|
||||
///
|
||||
/// Note that many type checkers will infer the type of `self` automatically, so this
|
||||
/// annotation is not strictly necessary.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// class Foo:
|
||||
/// def bar(self):
|
||||
/// ...
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// class Foo:
|
||||
/// def bar(self: "Foo"):
|
||||
/// ...
|
||||
/// ```
|
||||
pub struct MissingTypeSelf {
|
||||
pub name: String,
|
||||
}
|
||||
);
|
||||
impl Violation for MissingTypeSelf {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
@@ -150,37 +148,37 @@ impl Violation for MissingTypeSelf {
|
||||
}
|
||||
}
|
||||
|
||||
/// ## What it does
|
||||
/// Checks that class method `cls` arguments have type annotations.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Type annotations are a good way to document the types of function arguments. They also
|
||||
/// help catch bugs, when used alongside a type checker, by ensuring that the types of
|
||||
/// any provided arguments match expectation.
|
||||
///
|
||||
/// Note that many type checkers will infer the type of `cls` automatically, so this
|
||||
/// annotation is not strictly necessary.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// class Foo:
|
||||
/// @classmethod
|
||||
/// def bar(cls):
|
||||
/// ...
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// class Foo:
|
||||
/// @classmethod
|
||||
/// def bar(cls: Type["Foo"]):
|
||||
/// ...
|
||||
/// ```
|
||||
#[violation]
|
||||
pub struct MissingTypeCls {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
/// ## What it does
|
||||
/// Checks that class method `cls` arguments have type annotations.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Type annotations are a good way to document the types of function arguments. They also
|
||||
/// help catch bugs, when used alongside a type checker, by ensuring that the types of
|
||||
/// any provided arguments match expectation.
|
||||
///
|
||||
/// Note that many type checkers will infer the type of `cls` automatically, so this
|
||||
/// annotation is not strictly necessary.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// class Foo:
|
||||
/// @classmethod
|
||||
/// def bar(cls):
|
||||
/// ...
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// class Foo:
|
||||
/// @classmethod
|
||||
/// def bar(cls: Type["Foo"]):
|
||||
/// ...
|
||||
/// ```
|
||||
pub struct MissingTypeCls {
|
||||
pub name: String,
|
||||
}
|
||||
);
|
||||
impl Violation for MissingTypeCls {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
@@ -189,30 +187,30 @@ impl Violation for MissingTypeCls {
|
||||
}
|
||||
}
|
||||
|
||||
/// ## What it does
|
||||
/// Checks that public functions and methods have return type annotations.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Type annotations are a good way to document the return types of functions. They also
|
||||
/// help catch bugs, when used alongside a type checker, by ensuring that the types of
|
||||
/// any returned values, and the types expected by callers, match expectation.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def add(a, b):
|
||||
/// return a + b
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// def add(a: int, b: int) -> int:
|
||||
/// return a + b
|
||||
/// ```
|
||||
#[violation]
|
||||
pub struct MissingReturnTypePublicFunction {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
/// ## What it does
|
||||
/// Checks that public functions and methods have return type annotations.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Type annotations are a good way to document the return types of functions. They also
|
||||
/// help catch bugs, when used alongside a type checker, by ensuring that the types of
|
||||
/// any returned values, and the types expected by callers, match expectation.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def add(a, b):
|
||||
/// return a + b
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// def add(a: int, b: int) -> int:
|
||||
/// return a + b
|
||||
/// ```
|
||||
pub struct MissingReturnTypePublicFunction {
|
||||
pub name: String,
|
||||
}
|
||||
);
|
||||
impl Violation for MissingReturnTypePublicFunction {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
@@ -221,30 +219,30 @@ impl Violation for MissingReturnTypePublicFunction {
|
||||
}
|
||||
}
|
||||
|
||||
/// ## What it does
|
||||
/// Checks that private functions and methods have return type annotations.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Type annotations are a good way to document the return types of functions. They also
|
||||
/// help catch bugs, when used alongside a type checker, by ensuring that the types of
|
||||
/// any returned values, and the types expected by callers, match expectation.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def _add(a, b):
|
||||
/// return a + b
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// def _add(a: int, b: int) -> int:
|
||||
/// return a + b
|
||||
/// ```
|
||||
#[violation]
|
||||
pub struct MissingReturnTypePrivateFunction {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
/// ## What it does
|
||||
/// Checks that private functions and methods have return type annotations.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Type annotations are a good way to document the return types of functions. They also
|
||||
/// help catch bugs, when used alongside a type checker, by ensuring that the types of
|
||||
/// any returned values, and the types expected by callers, match expectation.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def _add(a, b):
|
||||
/// return a + b
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// def _add(a: int, b: int) -> int:
|
||||
/// return a + b
|
||||
/// ```
|
||||
pub struct MissingReturnTypePrivateFunction {
|
||||
pub name: String,
|
||||
}
|
||||
);
|
||||
impl Violation for MissingReturnTypePrivateFunction {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
@@ -253,43 +251,43 @@ impl Violation for MissingReturnTypePrivateFunction {
|
||||
}
|
||||
}
|
||||
|
||||
/// ## What it does
|
||||
/// Checks that "special" methods, like `__init__`, `__new__`, and `__call__`, have
|
||||
/// return type annotations.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Type annotations are a good way to document the return types of functions. They also
|
||||
/// help catch bugs, when used alongside a type checker, by ensuring that the types of
|
||||
/// any returned values, and the types expected by callers, match expectation.
|
||||
///
|
||||
/// Note that type checkers often allow you to omit the return type annotation for
|
||||
/// `__init__` methods, as long as at least one argument has a type annotation. To
|
||||
/// opt-in to this behavior, use the `mypy-init-return` setting in your `pyproject.toml`
|
||||
/// or `ruff.toml` file:
|
||||
///
|
||||
/// ```toml
|
||||
/// [tool.ruff.flake8-annotations]
|
||||
/// mypy-init-return = true
|
||||
/// ```
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// class Foo:
|
||||
/// def __init__(self, x: int):
|
||||
/// self.x = x
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// class Foo:
|
||||
/// def __init__(self, x: int) -> None:
|
||||
/// self.x = x
|
||||
/// ```
|
||||
#[violation]
|
||||
pub struct MissingReturnTypeSpecialMethod {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
/// ## What it does
|
||||
/// Checks that "special" methods, like `__init__`, `__new__`, and `__call__`, have
|
||||
/// return type annotations.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Type annotations are a good way to document the return types of functions. They also
|
||||
/// help catch bugs, when used alongside a type checker, by ensuring that the types of
|
||||
/// any returned values, and the types expected by callers, match expectation.
|
||||
///
|
||||
/// Note that type checkers often allow you to omit the return type annotation for
|
||||
/// `__init__` methods, as long as at least one argument has a type annotation. To
|
||||
/// opt-in to this behavior, use the `mypy-init-return` setting in your `pyproject.toml`
|
||||
/// or `ruff.toml` file:
|
||||
///
|
||||
/// ```toml
|
||||
/// [tool.ruff.flake8-annotations]
|
||||
/// mypy-init-return = true
|
||||
/// ```
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// class Foo:
|
||||
/// def __init__(self, x: int):
|
||||
/// self.x = x
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// class Foo:
|
||||
/// def __init__(self, x: int) -> None:
|
||||
/// self.x = x
|
||||
/// ```
|
||||
pub struct MissingReturnTypeSpecialMethod {
|
||||
pub name: String,
|
||||
}
|
||||
);
|
||||
impl AlwaysAutofixableViolation for MissingReturnTypeSpecialMethod {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
@@ -302,34 +300,34 @@ impl AlwaysAutofixableViolation for MissingReturnTypeSpecialMethod {
|
||||
}
|
||||
}
|
||||
|
||||
/// ## What it does
|
||||
/// Checks that static methods have return type annotations.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Type annotations are a good way to document the return types of functions. They also
|
||||
/// help catch bugs, when used alongside a type checker, by ensuring that the types of
|
||||
/// any returned values, and the types expected by callers, match expectation.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// class Foo:
|
||||
/// @staticmethod
|
||||
/// def bar():
|
||||
/// return 1
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// class Foo:
|
||||
/// @staticmethod
|
||||
/// def bar() -> int:
|
||||
/// return 1
|
||||
/// ```
|
||||
#[violation]
|
||||
pub struct MissingReturnTypeStaticMethod {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
/// ## What it does
|
||||
/// Checks that static methods have return type annotations.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Type annotations are a good way to document the return types of functions. They also
|
||||
/// help catch bugs, when used alongside a type checker, by ensuring that the types of
|
||||
/// any returned values, and the types expected by callers, match expectation.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// class Foo:
|
||||
/// @staticmethod
|
||||
/// def bar():
|
||||
/// return 1
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// class Foo:
|
||||
/// @staticmethod
|
||||
/// def bar() -> int:
|
||||
/// return 1
|
||||
/// ```
|
||||
pub struct MissingReturnTypeStaticMethod {
|
||||
pub name: String,
|
||||
}
|
||||
);
|
||||
impl Violation for MissingReturnTypeStaticMethod {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
@@ -338,34 +336,34 @@ impl Violation for MissingReturnTypeStaticMethod {
|
||||
}
|
||||
}
|
||||
|
||||
/// ## What it does
|
||||
/// Checks that class methods have return type annotations.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Type annotations are a good way to document the return types of functions. They also
|
||||
/// help catch bugs, when used alongside a type checker, by ensuring that the types of
|
||||
/// any returned values, and the types expected by callers, match expectation.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// class Foo:
|
||||
/// @classmethod
|
||||
/// def bar(cls):
|
||||
/// return 1
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// class Foo:
|
||||
/// @classmethod
|
||||
/// def bar(cls) -> int:
|
||||
/// return 1
|
||||
/// ```
|
||||
#[violation]
|
||||
pub struct MissingReturnTypeClassMethod {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
/// ## What it does
|
||||
/// Checks that class methods have return type annotations.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Type annotations are a good way to document the return types of functions. They also
|
||||
/// help catch bugs, when used alongside a type checker, by ensuring that the types of
|
||||
/// any returned values, and the types expected by callers, match expectation.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// class Foo:
|
||||
/// @classmethod
|
||||
/// def bar(cls):
|
||||
/// return 1
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// class Foo:
|
||||
/// @classmethod
|
||||
/// def bar(cls) -> int:
|
||||
/// return 1
|
||||
/// ```
|
||||
pub struct MissingReturnTypeClassMethod {
|
||||
pub name: String,
|
||||
}
|
||||
);
|
||||
impl Violation for MissingReturnTypeClassMethod {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
@@ -374,39 +372,39 @@ impl Violation for MissingReturnTypeClassMethod {
|
||||
}
|
||||
}
|
||||
|
||||
/// ## What it does
|
||||
/// Checks that an expression is annotated with a more specific type than
|
||||
/// `Any`.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// `Any` is a special type indicating an unconstrained type. When an
|
||||
/// expression is annotated with type `Any`, type checkers will allow all
|
||||
/// operations on it.
|
||||
///
|
||||
/// It's better to be explicit about the type of an expression, and to use
|
||||
/// `Any` as an "escape hatch" only when it is really needed.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def foo(x: Any):
|
||||
/// ...
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// def foo(x: int):
|
||||
/// ...
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// - [PEP 484](https://www.python.org/dev/peps/pep-0484/#the-any-type)
|
||||
/// - [`typing.Any`](https://docs.python.org/3/library/typing.html#typing.Any)
|
||||
/// - [Mypy: The Any type](https://mypy.readthedocs.io/en/stable/kinds_of_types.html#the-any-type)
|
||||
#[violation]
|
||||
pub struct AnyType {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
/// ## What it does
|
||||
/// Checks that an expression is annotated with a more specific type than
|
||||
/// `Any`.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// `Any` is a special type indicating an unconstrained type. When an
|
||||
/// expression is annotated with type `Any`, type checkers will allow all
|
||||
/// operations on it.
|
||||
///
|
||||
/// It's better to be explicit about the type of an expression, and to use
|
||||
/// `Any` as an "escape hatch" only when it is really needed.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def foo(x: Any):
|
||||
/// ...
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// def foo(x: int):
|
||||
/// ...
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// - [PEP 484](https://www.python.org/dev/peps/pep-0484/#the-any-type)
|
||||
/// - [`typing.Any`](https://docs.python.org/3/library/typing.html#typing.Any)
|
||||
/// - [Mypy: The Any type](https://mypy.readthedocs.io/en/stable/kinds_of_types.html#the-any-type)
|
||||
pub struct AnyType {
|
||||
pub name: String,
|
||||
}
|
||||
);
|
||||
impl Violation for AnyType {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
@@ -446,7 +444,7 @@ fn check_dynamically_typed<F>(
|
||||
if checker.ctx.match_typing_expr(annotation, "Any") {
|
||||
diagnostics.push(Diagnostic::new(
|
||||
AnyType { name: func() },
|
||||
Range::from(annotation),
|
||||
Range::from_located(annotation),
|
||||
));
|
||||
};
|
||||
}
|
||||
@@ -513,7 +511,7 @@ pub fn definition(
|
||||
MissingTypeFunctionArgument {
|
||||
name: arg.node.arg.to_string(),
|
||||
},
|
||||
Range::from(arg),
|
||||
Range::from_located(arg),
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -544,7 +542,7 @@ pub fn definition(
|
||||
MissingTypeArgs {
|
||||
name: arg.node.arg.to_string(),
|
||||
},
|
||||
Range::from(arg),
|
||||
Range::from_located(arg),
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -575,7 +573,7 @@ pub fn definition(
|
||||
MissingTypeKwargs {
|
||||
name: arg.node.arg.to_string(),
|
||||
},
|
||||
Range::from(arg),
|
||||
Range::from_located(arg),
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -592,7 +590,7 @@ pub fn definition(
|
||||
MissingTypeCls {
|
||||
name: arg.node.arg.to_string(),
|
||||
},
|
||||
Range::from(arg),
|
||||
Range::from_located(arg),
|
||||
));
|
||||
}
|
||||
} else {
|
||||
@@ -601,7 +599,7 @@ pub fn definition(
|
||||
MissingTypeSelf {
|
||||
name: arg.node.arg.to_string(),
|
||||
},
|
||||
Range::from(arg),
|
||||
Range::from_located(arg),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
//! Settings for the `flake-annotations` plugin.
|
||||
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use ruff_macros::CacheKey;
|
||||
use ruff_macros::ConfigurationOptions;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(
|
||||
Debug, PartialEq, Eq, Default, Serialize, Deserialize, ConfigurationOptions, JsonSchema,
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
---
|
||||
source: crates/ruff/src/rules/flake8_annotations/mod.rs
|
||||
source: src/rules/flake8_annotations/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: MissingReturnTypePublicFunction
|
||||
body: "Missing return type annotation for public function `bar`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
MissingReturnTypePublicFunction:
|
||||
name: bar
|
||||
location:
|
||||
row: 29
|
||||
column: 8
|
||||
|
||||
@@ -3,10 +3,8 @@ source: crates/ruff/src/rules/flake8_annotations/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: AnyType
|
||||
body: "Dynamically typed expressions (typing.Any) are disallowed in `a`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
AnyType:
|
||||
name: a
|
||||
location:
|
||||
row: 10
|
||||
column: 11
|
||||
@@ -16,10 +14,8 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: AnyType
|
||||
body: "Dynamically typed expressions (typing.Any) are disallowed in `foo`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
AnyType:
|
||||
name: foo
|
||||
location:
|
||||
row: 15
|
||||
column: 46
|
||||
@@ -29,10 +25,8 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: AnyType
|
||||
body: "Dynamically typed expressions (typing.Any) are disallowed in `a`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
AnyType:
|
||||
name: a
|
||||
location:
|
||||
row: 40
|
||||
column: 28
|
||||
@@ -42,10 +36,8 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: AnyType
|
||||
body: "Dynamically typed expressions (typing.Any) are disallowed in `foo_method`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
AnyType:
|
||||
name: foo_method
|
||||
location:
|
||||
row: 44
|
||||
column: 66
|
||||
|
||||
@@ -3,10 +3,8 @@ source: crates/ruff/src/rules/flake8_annotations/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: MissingReturnTypePublicFunction
|
||||
body: "Missing return type annotation for public function `foo`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
MissingReturnTypePublicFunction:
|
||||
name: foo
|
||||
location:
|
||||
row: 4
|
||||
column: 4
|
||||
@@ -16,10 +14,8 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingTypeFunctionArgument
|
||||
body: "Missing type annotation for function argument `a`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
MissingTypeFunctionArgument:
|
||||
name: a
|
||||
location:
|
||||
row: 4
|
||||
column: 8
|
||||
@@ -29,10 +25,8 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingTypeFunctionArgument
|
||||
body: "Missing type annotation for function argument `b`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
MissingTypeFunctionArgument:
|
||||
name: b
|
||||
location:
|
||||
row: 4
|
||||
column: 11
|
||||
@@ -42,10 +36,8 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingReturnTypePublicFunction
|
||||
body: "Missing return type annotation for public function `foo`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
MissingReturnTypePublicFunction:
|
||||
name: foo
|
||||
location:
|
||||
row: 9
|
||||
column: 4
|
||||
@@ -55,10 +47,8 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingTypeFunctionArgument
|
||||
body: "Missing type annotation for function argument `b`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
MissingTypeFunctionArgument:
|
||||
name: b
|
||||
location:
|
||||
row: 9
|
||||
column: 16
|
||||
@@ -68,10 +58,8 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingTypeFunctionArgument
|
||||
body: "Missing type annotation for function argument `b`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
MissingTypeFunctionArgument:
|
||||
name: b
|
||||
location:
|
||||
row: 14
|
||||
column: 16
|
||||
@@ -81,10 +69,8 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingReturnTypePublicFunction
|
||||
body: "Missing return type annotation for public function `foo`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
MissingReturnTypePublicFunction:
|
||||
name: foo
|
||||
location:
|
||||
row: 19
|
||||
column: 4
|
||||
@@ -94,10 +80,8 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingReturnTypePublicFunction
|
||||
body: "Missing return type annotation for public function `foo`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
MissingReturnTypePublicFunction:
|
||||
name: foo
|
||||
location:
|
||||
row: 24
|
||||
column: 4
|
||||
@@ -107,10 +91,8 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: AnyType
|
||||
body: "Dynamically typed expressions (typing.Any) are disallowed in `a`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
AnyType:
|
||||
name: a
|
||||
location:
|
||||
row: 44
|
||||
column: 11
|
||||
@@ -120,10 +102,8 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: AnyType
|
||||
body: "Dynamically typed expressions (typing.Any) are disallowed in `foo`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
AnyType:
|
||||
name: foo
|
||||
location:
|
||||
row: 49
|
||||
column: 46
|
||||
@@ -133,10 +113,8 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: AnyType
|
||||
body: "Dynamically typed expressions (typing.Any) are disallowed in `*args`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
AnyType:
|
||||
name: "*args"
|
||||
location:
|
||||
row: 54
|
||||
column: 23
|
||||
@@ -146,10 +124,8 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: AnyType
|
||||
body: "Dynamically typed expressions (typing.Any) are disallowed in `**kwargs`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
AnyType:
|
||||
name: "**kwargs"
|
||||
location:
|
||||
row: 54
|
||||
column: 38
|
||||
@@ -159,10 +135,8 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: AnyType
|
||||
body: "Dynamically typed expressions (typing.Any) are disallowed in `*args`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
AnyType:
|
||||
name: "*args"
|
||||
location:
|
||||
row: 59
|
||||
column: 23
|
||||
@@ -172,10 +146,8 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: AnyType
|
||||
body: "Dynamically typed expressions (typing.Any) are disallowed in `**kwargs`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
AnyType:
|
||||
name: "**kwargs"
|
||||
location:
|
||||
row: 64
|
||||
column: 38
|
||||
@@ -185,10 +157,8 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingTypeSelf
|
||||
body: "Missing type annotation for `self` in method"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
MissingTypeSelf:
|
||||
name: self
|
||||
location:
|
||||
row: 74
|
||||
column: 12
|
||||
@@ -198,10 +168,8 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: AnyType
|
||||
body: "Dynamically typed expressions (typing.Any) are disallowed in `a`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
AnyType:
|
||||
name: a
|
||||
location:
|
||||
row: 78
|
||||
column: 28
|
||||
@@ -211,10 +179,8 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: AnyType
|
||||
body: "Dynamically typed expressions (typing.Any) are disallowed in `foo`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
AnyType:
|
||||
name: foo
|
||||
location:
|
||||
row: 82
|
||||
column: 66
|
||||
@@ -224,10 +190,8 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: AnyType
|
||||
body: "Dynamically typed expressions (typing.Any) are disallowed in `*params`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
AnyType:
|
||||
name: "*params"
|
||||
location:
|
||||
row: 86
|
||||
column: 42
|
||||
@@ -237,10 +201,8 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: AnyType
|
||||
body: "Dynamically typed expressions (typing.Any) are disallowed in `**options`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
AnyType:
|
||||
name: "**options"
|
||||
location:
|
||||
row: 86
|
||||
column: 58
|
||||
@@ -250,10 +212,8 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: AnyType
|
||||
body: "Dynamically typed expressions (typing.Any) are disallowed in `*params`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
AnyType:
|
||||
name: "*params"
|
||||
location:
|
||||
row: 90
|
||||
column: 42
|
||||
@@ -263,10 +223,8 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: AnyType
|
||||
body: "Dynamically typed expressions (typing.Any) are disallowed in `**options`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
AnyType:
|
||||
name: "**options"
|
||||
location:
|
||||
row: 94
|
||||
column: 58
|
||||
@@ -276,10 +234,8 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingTypeCls
|
||||
body: "Missing type annotation for `cls` in classmethod"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
MissingTypeCls:
|
||||
name: cls
|
||||
location:
|
||||
row: 104
|
||||
column: 12
|
||||
@@ -289,10 +245,8 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingTypeSelf
|
||||
body: "Missing type annotation for `self` in method"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
MissingTypeSelf:
|
||||
name: self
|
||||
location:
|
||||
row: 108
|
||||
column: 12
|
||||
|
||||
@@ -3,10 +3,8 @@ source: crates/ruff/src/rules/flake8_annotations/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: MissingReturnTypePublicFunction
|
||||
body: "Missing return type annotation for public function `error_partially_typed_1`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
MissingReturnTypePublicFunction:
|
||||
name: error_partially_typed_1
|
||||
location:
|
||||
row: 24
|
||||
column: 4
|
||||
@@ -16,10 +14,8 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingTypeFunctionArgument
|
||||
body: "Missing type annotation for function argument `b`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
MissingTypeFunctionArgument:
|
||||
name: b
|
||||
location:
|
||||
row: 24
|
||||
column: 36
|
||||
@@ -29,10 +25,8 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingTypeFunctionArgument
|
||||
body: "Missing type annotation for function argument `b`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
MissingTypeFunctionArgument:
|
||||
name: b
|
||||
location:
|
||||
row: 28
|
||||
column: 36
|
||||
@@ -42,10 +36,8 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingReturnTypePublicFunction
|
||||
body: "Missing return type annotation for public function `error_partially_typed_3`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
MissingReturnTypePublicFunction:
|
||||
name: error_partially_typed_3
|
||||
location:
|
||||
row: 32
|
||||
column: 4
|
||||
@@ -55,10 +47,8 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingReturnTypePublicFunction
|
||||
body: "Missing return type annotation for public function `error_typed_self`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
MissingReturnTypePublicFunction:
|
||||
name: error_typed_self
|
||||
location:
|
||||
row: 43
|
||||
column: 8
|
||||
|
||||
@@ -3,10 +3,8 @@ source: crates/ruff/src/rules/flake8_annotations/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: MissingReturnTypeSpecialMethod
|
||||
body: "Missing return type annotation for special method `__init__`"
|
||||
suggestion: "Add `None` return type"
|
||||
fixable: true
|
||||
MissingReturnTypeSpecialMethod:
|
||||
name: __init__
|
||||
location:
|
||||
row: 5
|
||||
column: 8
|
||||
@@ -23,10 +21,8 @@ expression: diagnostics
|
||||
column: 22
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingReturnTypeSpecialMethod
|
||||
body: "Missing return type annotation for special method `__init__`"
|
||||
suggestion: "Add `None` return type"
|
||||
fixable: true
|
||||
MissingReturnTypeSpecialMethod:
|
||||
name: __init__
|
||||
location:
|
||||
row: 11
|
||||
column: 8
|
||||
@@ -43,10 +39,8 @@ expression: diagnostics
|
||||
column: 27
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingReturnTypePrivateFunction
|
||||
body: "Missing return type annotation for private function `__init__`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
MissingReturnTypePrivateFunction:
|
||||
name: __init__
|
||||
location:
|
||||
row: 40
|
||||
column: 4
|
||||
@@ -56,10 +50,8 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingReturnTypeSpecialMethod
|
||||
body: "Missing return type annotation for special method `__init__`"
|
||||
suggestion: "Add `None` return type"
|
||||
fixable: true
|
||||
MissingReturnTypeSpecialMethod:
|
||||
name: __init__
|
||||
location:
|
||||
row: 47
|
||||
column: 8
|
||||
|
||||
@@ -3,10 +3,8 @@ source: crates/ruff/src/rules/flake8_annotations/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: MissingReturnTypePublicFunction
|
||||
body: "Missing return type annotation for public function `foo`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
MissingReturnTypePublicFunction:
|
||||
name: foo
|
||||
location:
|
||||
row: 45
|
||||
column: 4
|
||||
@@ -16,10 +14,8 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingReturnTypePublicFunction
|
||||
body: "Missing return type annotation for public function `foo`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
MissingReturnTypePublicFunction:
|
||||
name: foo
|
||||
location:
|
||||
row: 50
|
||||
column: 4
|
||||
@@ -29,10 +25,8 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: MissingTypeFunctionArgument
|
||||
body: "Missing type annotation for function argument `a`"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
MissingTypeFunctionArgument:
|
||||
name: a
|
||||
location:
|
||||
row: 59
|
||||
column: 8
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
use rustpython_parser::ast::Stmt;
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::types::Range;
|
||||
use ruff_macros::{define_violation, derive_message_formats};
|
||||
|
||||
#[violation]
|
||||
pub struct Assert;
|
||||
use crate::ast::types::Range;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::violation::Violation;
|
||||
|
||||
define_violation!(
|
||||
pub struct Assert;
|
||||
);
|
||||
impl Violation for Assert {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
use num_traits::ToPrimitive;
|
||||
use once_cell::sync::Lazy;
|
||||
use ruff_macros::{define_violation, derive_message_formats};
|
||||
use rustc_hash::FxHashMap;
|
||||
use rustpython_parser::ast::{Constant, Expr, ExprKind, Keyword, Operator};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::helpers::{compose_call_path, SimpleCallArgs};
|
||||
use ruff_python_ast::types::Range;
|
||||
|
||||
use crate::ast::helpers::{compose_call_path, SimpleCallArgs};
|
||||
use crate::ast::types::Range;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::violation::Violation;
|
||||
|
||||
#[violation]
|
||||
pub struct BadFilePermissions {
|
||||
pub mask: u16,
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
pub struct BadFilePermissions {
|
||||
pub mask: u16,
|
||||
}
|
||||
);
|
||||
impl Violation for BadFilePermissions {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
@@ -108,12 +108,12 @@ pub fn bad_file_permissions(
|
||||
.map_or(false, |call_path| call_path.as_slice() == ["os", "chmod"])
|
||||
{
|
||||
let call_args = SimpleCallArgs::new(args, keywords);
|
||||
if let Some(mode_arg) = call_args.argument("mode", 1) {
|
||||
if let Some(mode_arg) = call_args.get_argument("mode", Some(1)) {
|
||||
if let Some(int_value) = get_int_value(mode_arg) {
|
||||
if (int_value & WRITE_WORLD > 0) || (int_value & EXECUTE_GROUP > 0) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
BadFilePermissions { mask: int_value },
|
||||
Range::from(mode_arg),
|
||||
Range::from_located(mode_arg),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
use ruff_macros::{define_violation, derive_message_formats};
|
||||
use rustpython_parser::ast::{Expr, ExprKind};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::types::Range;
|
||||
|
||||
#[violation]
|
||||
pub struct ExecBuiltin;
|
||||
use crate::ast::types::Range;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::violation::Violation;
|
||||
|
||||
define_violation!(
|
||||
pub struct ExecBuiltin;
|
||||
);
|
||||
impl Violation for ExecBuiltin {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
@@ -22,5 +23,5 @@ pub fn exec_used(expr: &Expr, func: &Expr) -> Option<Diagnostic> {
|
||||
if id != "exec" {
|
||||
return None;
|
||||
}
|
||||
Some(Diagnostic::new(ExecBuiltin, Range::from(expr)))
|
||||
Some(Diagnostic::new(ExecBuiltin, Range::from_located(expr)))
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::types::Range;
|
||||
use ruff_macros::{define_violation, derive_message_formats};
|
||||
|
||||
#[violation]
|
||||
pub struct HardcodedBindAllInterfaces;
|
||||
use crate::ast::types::Range;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::violation::Violation;
|
||||
|
||||
define_violation!(
|
||||
pub struct HardcodedBindAllInterfaces;
|
||||
);
|
||||
impl Violation for HardcodedBindAllInterfaces {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user