Compare commits
13 Commits
v0.0.260
...
useless_re
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a7167520a | ||
|
|
41ab37e792 | ||
|
|
0b1806fdfa | ||
|
|
d20474da87 | ||
|
|
b7df7ee370 | ||
|
|
d6f0d1fab2 | ||
|
|
c9bf979e61 | ||
|
|
e556fb4c77 | ||
|
|
02ae14037b | ||
|
|
385ccb2a50 | ||
|
|
ecacccbd5e | ||
|
|
bd7b472902 | ||
|
|
89b1b06dc7 |
@@ -26,11 +26,4 @@ rustflags = [
|
||||
"-Wclippy::print_stdout",
|
||||
"-Wclippy::print_stderr",
|
||||
"-Wclippy::dbg_macro",
|
||||
"-Wclippy::empty_drop",
|
||||
"-Wclippy::empty_structs_with_brackets",
|
||||
"-Wclippy::exit",
|
||||
"-Wclippy::get_unwrap",
|
||||
"-Wclippy::rc_buffer",
|
||||
"-Wclippy::rc_mutex",
|
||||
"-Wclippy::rest_pat_in_fully_bound_structs",
|
||||
]
|
||||
|
||||
96
.github/workflows/benchmark.yaml
vendored
96
.github/workflows/benchmark.yaml
vendored
@@ -26,7 +26,7 @@ jobs:
|
||||
- name: "PR - Install Rust toolchain"
|
||||
run: rustup show
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
|
||||
- name: "PR - Build benchmarks"
|
||||
uses: actions-rs/cargo@v1
|
||||
@@ -75,61 +75,59 @@ jobs:
|
||||
- run-benchmark
|
||||
|
||||
steps:
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup show
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup show
|
||||
|
||||
- name: "Install cargo-binstall"
|
||||
uses: taiki-e/install-action@cargo-binstall
|
||||
- name: "Install critcmp"
|
||||
# Use debug build: Building takes much longer than the "slowness" of using the debug build.
|
||||
run: cargo install --debug critcmp
|
||||
|
||||
- name: "Install critcmp"
|
||||
run: cargo binstall critcmp -y
|
||||
- name: "Linux | Download PR benchmark results"
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: benchmark-results-ubuntu-latest
|
||||
path: ./target/criterion
|
||||
|
||||
- name: "Linux | Download PR benchmark results"
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: benchmark-results-ubuntu-latest
|
||||
path: ./target/criterion
|
||||
- name: "Linux | Compare benchmark results"
|
||||
shell: bash
|
||||
run: |
|
||||
echo "### Benchmark" >> summary.md
|
||||
echo "#### Linux" >> summary.md
|
||||
echo "\`\`\`" >> summary.md
|
||||
critcmp main pr >> summary.md
|
||||
echo "\`\`\`" >> summary.md
|
||||
echo "" >> summary.md
|
||||
|
||||
- name: "Linux | Compare benchmark results"
|
||||
shell: bash
|
||||
run: |
|
||||
echo "### Benchmark" >> summary.md
|
||||
echo "#### Linux" >> summary.md
|
||||
echo "\`\`\`" >> summary.md
|
||||
critcmp main pr >> summary.md
|
||||
echo "\`\`\`" >> summary.md
|
||||
echo "" >> summary.md
|
||||
- name: "Linux | Cleanup benchmark results"
|
||||
run: rm -rf ./target/criterion
|
||||
|
||||
- name: "Linux | Cleanup benchmark results"
|
||||
run: rm -rf ./target/criterion
|
||||
- name: "Windows | Download PR benchmark results"
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: benchmark-results-windows-latest
|
||||
path: ./target/criterion
|
||||
|
||||
- name: "Windows | Download PR benchmark results"
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: benchmark-results-windows-latest
|
||||
path: ./target/criterion
|
||||
- name: "Windows | Compare benchmark results"
|
||||
shell: bash
|
||||
run: |
|
||||
echo "#### Windows" >> summary.md
|
||||
echo "\`\`\`" >> summary.md
|
||||
critcmp main pr >> summary.md
|
||||
echo "\`\`\`" >> summary.md
|
||||
echo "" >> summary.md
|
||||
|
||||
- name: "Windows | Compare benchmark results"
|
||||
shell: bash
|
||||
run: |
|
||||
echo "#### Windows" >> summary.md
|
||||
echo "\`\`\`" >> summary.md
|
||||
critcmp main pr >> summary.md
|
||||
echo "\`\`\`" >> summary.md
|
||||
echo "" >> summary.md
|
||||
echo ${{ github.event.pull_request.number }} > pr-number
|
||||
|
||||
echo ${{ github.event.pull_request.number }} > pr-number
|
||||
cat summary.md > $GITHUB_STEP_SUMMARY
|
||||
|
||||
cat summary.md > $GITHUB_STEP_SUMMARY
|
||||
- uses: actions/upload-artifact@v3
|
||||
name: Upload PR Number
|
||||
with:
|
||||
name: pr-number
|
||||
path: pr-number
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
name: Upload PR Number
|
||||
with:
|
||||
name: pr-number
|
||||
path: pr-number
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
name: Upload Summary
|
||||
with:
|
||||
name: summary
|
||||
path: summary.md
|
||||
- uses: actions/upload-artifact@v3
|
||||
name: Upload Summary
|
||||
with:
|
||||
name: summary
|
||||
path: summary.md
|
||||
|
||||
58
.github/workflows/ci.yaml
vendored
58
.github/workflows/ci.yaml
vendored
@@ -85,6 +85,7 @@ jobs:
|
||||
name: ruff
|
||||
path: target/debug/ruff
|
||||
|
||||
|
||||
cargo-test-wasm:
|
||||
runs-on: ubuntu-latest
|
||||
name: "cargo test (wasm)"
|
||||
@@ -110,16 +111,14 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup component add rustfmt
|
||||
run: rustup show
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- run: ./scripts/add_rule.py --name DoTheThing --prefix PL --code C0999 --linter pylint
|
||||
- run: ./scripts/add_rule.py --name DoTheThing --code PLC999 --linter pylint
|
||||
- run: cargo check
|
||||
- run: cargo fmt --all --check
|
||||
- run: |
|
||||
./scripts/add_plugin.py test --url https://pypi.org/project/-test/0.1.0/ --prefix TST
|
||||
./scripts/add_rule.py --name FirstRule --prefix TST --code 001 --linter test
|
||||
./scripts/add_rule.py --name FirstRule --code TST001 --linter test
|
||||
- run: cargo check
|
||||
- run: cargo fmt --all --check
|
||||
|
||||
typos:
|
||||
name: "spell check"
|
||||
@@ -177,52 +176,3 @@ jobs:
|
||||
with:
|
||||
name: ecosystem-result
|
||||
path: ecosystem-result
|
||||
|
||||
cargo-udeps:
|
||||
name: "cargo udeps"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup toolchain install nightly
|
||||
- name: "Install cargo-udeps"
|
||||
uses: taiki-e/install-action@cargo-udeps
|
||||
- name: "Run cargo-udeps"
|
||||
run: |
|
||||
unused_dependencies=$(cargo +nightly udeps > unused.txt && cat unused.txt | cut -d $'\n' -f 2-)
|
||||
if [ -z "$unused_dependencies" ]; then
|
||||
echo "No unused dependencies found" > $GITHUB_STEP_SUMMARY
|
||||
exit 0
|
||||
else
|
||||
echo "Unused dependencies found" > $GITHUB_STEP_SUMMARY
|
||||
echo '```console' >> $GITHUB_STEP_SUMMARY
|
||||
echo "$unused_dependencies" >> $GITHUB_STEP_SUMMARY
|
||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||
exit 1
|
||||
fi
|
||||
|
||||
pre-commit:
|
||||
name: "pre-commit"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.11"
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup show
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- name: "Install pre-commit"
|
||||
run: pip install pre-commit
|
||||
- name: "Cache pre-commit"
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cache/pre-commit
|
||||
key: pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
|
||||
- name: "Run pre-commit"
|
||||
run: |
|
||||
echo '```console' > $GITHUB_STEP_SUMMARY
|
||||
# Enable color output for pre-commit and remove it for the summary
|
||||
SKIP=cargo-fmt,clippy,dev-generate-all pre-commit run --all-files --show-diff-on-failure --color=always | \
|
||||
tee >(sed -E 's/\x1B\[([0-9]{1,2}(;[0-9]{1,2})*)?[mGK]//g' >> $GITHUB_STEP_SUMMARY) >&1
|
||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
1
.github/workflows/pr-comment.yaml
vendored
1
.github/workflows/pr-comment.yaml
vendored
@@ -65,7 +65,6 @@ jobs:
|
||||
then
|
||||
echo "### Ecosystem" >> $GITHUB_OUTPUT
|
||||
cat pr/ecosystem/ecosystem-result >> $GITHUB_OUTPUT
|
||||
echo "" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
if [[ -f pr/benchmark/summary.md ]]
|
||||
|
||||
@@ -28,17 +28,17 @@ repos:
|
||||
- id: cargo-fmt
|
||||
name: cargo fmt
|
||||
entry: cargo fmt --
|
||||
language: system
|
||||
language: rust
|
||||
types: [rust]
|
||||
- id: clippy
|
||||
name: clippy
|
||||
entry: cargo clippy --workspace --all-targets --all-features -- -D warnings
|
||||
language: system
|
||||
language: rust
|
||||
pass_filenames: false
|
||||
- id: ruff
|
||||
name: ruff
|
||||
entry: cargo run -p ruff_cli -- check --no-cache --force-exclude --fix --exit-non-zero-on-fix
|
||||
language: system
|
||||
language: rust
|
||||
types_or: [python, pyi]
|
||||
require_serial: true
|
||||
exclude: |
|
||||
@@ -49,7 +49,7 @@ repos:
|
||||
- id: dev-generate-all
|
||||
name: dev-generate-all
|
||||
entry: cargo dev generate-all
|
||||
language: system
|
||||
language: rust
|
||||
pass_filenames: false
|
||||
exclude: target
|
||||
|
||||
|
||||
@@ -145,4 +145,4 @@ default.
|
||||
`pyproject.toml` files are now resolved hierarchically, such that for each Python file, we find
|
||||
the first `pyproject.toml` file in its path, and use that to determine its lint settings.
|
||||
|
||||
See the [documentation](https://beta.ruff.rs/docs/configuration/#python-file-discovery) for more.
|
||||
See the [README](https://github.com/charliermarsh/ruff#pyprojecttoml-discovery) for more.
|
||||
|
||||
39
Cargo.lock
generated
39
Cargo.lock
generated
@@ -132,6 +132,12 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bisection"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "021e079a1bab0ecce6cf4b4b74c0c37afa4a697136eb3b127875c84a8f04a8c3"
|
||||
|
||||
[[package]]
|
||||
name = "bit-set"
|
||||
version = "0.5.3"
|
||||
@@ -774,7 +780,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.260"
|
||||
version = "0.0.256"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.1.8",
|
||||
@@ -1976,13 +1982,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.260"
|
||||
version = "0.0.256"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bisection",
|
||||
"bitflags",
|
||||
"chrono",
|
||||
"clap 4.1.8",
|
||||
"colored",
|
||||
"criterion",
|
||||
"dirs",
|
||||
"fern",
|
||||
"glob",
|
||||
@@ -2017,7 +2025,6 @@ dependencies = [
|
||||
"schemars",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"shellexpand",
|
||||
"smallvec",
|
||||
"strum",
|
||||
@@ -2026,8 +2033,6 @@ dependencies = [
|
||||
"textwrap",
|
||||
"thiserror",
|
||||
"toml",
|
||||
"typed-arena",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2058,7 +2063,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_cli"
|
||||
version = "0.0.260"
|
||||
version = "0.0.256"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.9.1",
|
||||
"anyhow",
|
||||
@@ -2086,7 +2091,6 @@ dependencies = [
|
||||
"ruff",
|
||||
"ruff_cache",
|
||||
"ruff_diagnostics",
|
||||
"ruff_python_stdlib",
|
||||
"rustc-hash",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -2097,7 +2101,6 @@ dependencies = [
|
||||
"tikv-jemallocator",
|
||||
"ureq",
|
||||
"walkdir",
|
||||
"wild",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2127,8 +2130,6 @@ dependencies = [
|
||||
name = "ruff_diagnostics"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"log",
|
||||
"ruff_python_ast",
|
||||
"rustpython-parser",
|
||||
"serde",
|
||||
@@ -2209,6 +2210,7 @@ name = "ruff_python_stdlib"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
]
|
||||
|
||||
@@ -2252,7 +2254,6 @@ dependencies = [
|
||||
"js-sys",
|
||||
"log",
|
||||
"ruff",
|
||||
"ruff_diagnostics",
|
||||
"ruff_python_ast",
|
||||
"ruff_rustpython",
|
||||
"rustpython-parser",
|
||||
@@ -2504,7 +2505,6 @@ version = "1.0.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
@@ -2915,12 +2915,6 @@ dependencies = [
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typed-arena"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a"
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.16.0"
|
||||
@@ -3267,15 +3261,6 @@ version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17882f045410753661207383517a6f62ec3dbeb6a4ed2acce01f0728238d1983"
|
||||
|
||||
[[package]]
|
||||
name = "wild"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05b116685a6be0c52f5a103334cbff26db643826c7b3735fc0a3ba9871310a74"
|
||||
dependencies = [
|
||||
"glob",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
|
||||
@@ -37,7 +37,7 @@ rustpython-parser = { features = [
|
||||
], git = "https://github.com/RustPython/RustPython.git", rev = "c15f670f2c30cfae6b41a1874893590148c74bc4" }
|
||||
schemars = { version = "0.8.12" }
|
||||
serde = { version = "1.0.152", features = ["derive"] }
|
||||
serde_json = { version = "1.0.93", features = ["preserve_order"] }
|
||||
serde_json = { version = "1.0.93" }
|
||||
shellexpand = { version = "3.0.0" }
|
||||
similar = { version = "2.2.1" }
|
||||
strum = { version = "0.24.1", features = ["strum_macros"] }
|
||||
@@ -48,7 +48,10 @@ textwrap = { version = "0.16.0" }
|
||||
toml = { version = "0.7.2" }
|
||||
|
||||
[profile.release]
|
||||
lto = "fat"
|
||||
panic = "abort"
|
||||
lto = "thin"
|
||||
codegen-units = 1
|
||||
opt-level = 3
|
||||
|
||||
[profile.dev.package.insta]
|
||||
opt-level = 3
|
||||
|
||||
35
LICENSE
35
LICENSE
@@ -195,15 +195,6 @@ are:
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
"""
|
||||
|
||||
- flake8-gettext, licensed as follows:
|
||||
"""
|
||||
BSD Zero Clause License
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
"""
|
||||
|
||||
- flake8-implicit-str-concat, licensed as follows:
|
||||
"""
|
||||
The MIT License (MIT)
|
||||
@@ -402,6 +393,7 @@ are:
|
||||
THE SOFTWARE.
|
||||
"""
|
||||
|
||||
|
||||
- autoflake, licensed as follows:
|
||||
"""
|
||||
Copyright (C) 2012-2018 Steven Myint
|
||||
@@ -425,31 +417,6 @@ are:
|
||||
SOFTWARE.
|
||||
"""
|
||||
|
||||
- autotyping, licensed as follows:
|
||||
"""
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Jelle Zijlstra
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
"""
|
||||
|
||||
- Flake8, licensed as follows:
|
||||
"""
|
||||
== Flake8 License (MIT) ==
|
||||
|
||||
54
README.md
54
README.md
@@ -137,7 +137,7 @@ Ruff can also be used as a [pre-commit](https://pre-commit.com) hook:
|
||||
```yaml
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: 'v0.0.260'
|
||||
rev: 'v0.0.256'
|
||||
hooks:
|
||||
- id: ruff
|
||||
```
|
||||
@@ -160,7 +160,7 @@ select = ["E", "F"]
|
||||
ignore = []
|
||||
|
||||
# Allow autofix for all enabled rules (when `--fix`) is provided.
|
||||
fixable = ["A", "B", "C", "D", "E", "F", "G", "I", "N", "Q", "S", "T", "W", "ANN", "ARG", "BLE", "COM", "DJ", "DTZ", "EM", "ERA", "EXE", "FBT", "ICN", "INP", "ISC", "NPY", "PD", "PGH", "PIE", "PL", "PT", "PTH", "PYI", "RET", "RSE", "RUF", "SIM", "SLF", "TCH", "TID", "TRY", "UP", "YTT"]
|
||||
fixable = ["A", "B", "C", "D", "E", "F", "..."]
|
||||
unfixable = []
|
||||
|
||||
# Exclude a variety of commonly ignored directories.
|
||||
@@ -227,55 +227,6 @@ stylistic rules made obsolete by the use of an autoformatter, like
|
||||
If you're just getting started with Ruff, **the default rule set is a great place to start**: it
|
||||
catches a wide variety of common errors (like unused imports) with zero configuration.
|
||||
|
||||
Beyond the defaults, Ruff re-implements some of the most popular Flake8 plugins and related code
|
||||
quality tools, including:
|
||||
|
||||
- [autoflake](https://pypi.org/project/autoflake/)
|
||||
- [eradicate](https://pypi.org/project/eradicate/)
|
||||
- [flake8-2020](https://pypi.org/project/flake8-2020/)
|
||||
- [flake8-annotations](https://pypi.org/project/flake8-annotations/)
|
||||
- [flake8-bandit](https://pypi.org/project/flake8-bandit/) ([#1646](https://github.com/charliermarsh/ruff/issues/1646))
|
||||
- [flake8-blind-except](https://pypi.org/project/flake8-blind-except/)
|
||||
- [flake8-boolean-trap](https://pypi.org/project/flake8-boolean-trap/)
|
||||
- [flake8-bugbear](https://pypi.org/project/flake8-bugbear/)
|
||||
- [flake8-builtins](https://pypi.org/project/flake8-builtins/)
|
||||
- [flake8-commas](https://pypi.org/project/flake8-commas/)
|
||||
- [flake8-comprehensions](https://pypi.org/project/flake8-comprehensions/)
|
||||
- [flake8-datetimez](https://pypi.org/project/flake8-datetimez/)
|
||||
- [flake8-debugger](https://pypi.org/project/flake8-debugger/)
|
||||
- [flake8-django](https://pypi.org/project/flake8-django/)
|
||||
- [flake8-docstrings](https://pypi.org/project/flake8-docstrings/)
|
||||
- [flake8-eradicate](https://pypi.org/project/flake8-eradicate/)
|
||||
- [flake8-errmsg](https://pypi.org/project/flake8-errmsg/)
|
||||
- [flake8-executable](https://pypi.org/project/flake8-executable/)
|
||||
- [flake8-gettext](https://pypi.org/project/flake8-gettext/)
|
||||
- [flake8-implicit-str-concat](https://pypi.org/project/flake8-implicit-str-concat/)
|
||||
- [flake8-import-conventions](https://github.com/joaopalmeiro/flake8-import-conventions)
|
||||
- [flake8-logging-format](https://pypi.org/project/flake8-logging-format/)
|
||||
- [flake8-no-pep420](https://pypi.org/project/flake8-no-pep420)
|
||||
- [flake8-pie](https://pypi.org/project/flake8-pie/)
|
||||
- [flake8-print](https://pypi.org/project/flake8-print/)
|
||||
- [flake8-pyi](https://pypi.org/project/flake8-pyi/)
|
||||
- [flake8-pytest-style](https://pypi.org/project/flake8-pytest-style/)
|
||||
- [flake8-quotes](https://pypi.org/project/flake8-quotes/)
|
||||
- [flake8-raise](https://pypi.org/project/flake8-raise/)
|
||||
- [flake8-return](https://pypi.org/project/flake8-return/)
|
||||
- [flake8-self](https://pypi.org/project/flake8-self/)
|
||||
- [flake8-simplify](https://pypi.org/project/flake8-simplify/)
|
||||
- [flake8-super](https://pypi.org/project/flake8-super/)
|
||||
- [flake8-tidy-imports](https://pypi.org/project/flake8-tidy-imports/)
|
||||
- [flake8-type-checking](https://pypi.org/project/flake8-type-checking/)
|
||||
- [flake8-use-pathlib](https://pypi.org/project/flake8-use-pathlib/)
|
||||
- [isort](https://pypi.org/project/isort/)
|
||||
- [mccabe](https://pypi.org/project/mccabe/)
|
||||
- [pandas-vet](https://pypi.org/project/pandas-vet/)
|
||||
- [pep8-naming](https://pypi.org/project/pep8-naming/)
|
||||
- [pydocstyle](https://pypi.org/project/pydocstyle/)
|
||||
- [pygrep-hooks](https://github.com/pre-commit/pygrep-hooks) ([#980](https://github.com/charliermarsh/ruff/issues/980))
|
||||
- [pyupgrade](https://pypi.org/project/pyupgrade/)
|
||||
- [tryceratops](https://pypi.org/project/tryceratops/)
|
||||
- [yesqa](https://pypi.org/project/yesqa/)
|
||||
|
||||
<!-- End section: Rules -->
|
||||
|
||||
For a complete enumeration of the supported rules, see [_Rules_](https://beta.ruff.rs/docs/rules/).
|
||||
@@ -329,7 +280,6 @@ Ruff is used in a number of major open-source projects, including:
|
||||
- [Zulip](https://github.com/zulip/zulip)
|
||||
- [Bokeh](https://github.com/bokeh/bokeh)
|
||||
- [Pydantic](https://github.com/pydantic/pydantic)
|
||||
- [PostHog](https://github.com/PostHog/posthog)
|
||||
- [Dagster](https://github.com/dagster-io/dagster)
|
||||
- [Dagger](https://github.com/dagger/dagger)
|
||||
- [Sphinx](https://github.com/sphinx-doc/sphinx)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.260"
|
||||
version = "0.0.256"
|
||||
edition = { workspace = true }
|
||||
rust-version = { workspace = true }
|
||||
|
||||
|
||||
@@ -85,9 +85,8 @@ flake8-to-ruff path/to/.flake8 --plugin flake8-builtins --plugin flake8-quotes
|
||||
ignore unsupported options in the `.flake8` file (or equivalent). (Similarly, Ruff has a few
|
||||
configuration options that don't exist in Flake8.)
|
||||
1. Ruff will omit any rule codes that are unimplemented or unsupported by Ruff, including rule
|
||||
codes from unsupported plugins. (See the
|
||||
[documentation](https://beta.ruff.rs/docs/faq/#how-does-ruff-compare-to-flake8) for the complete
|
||||
list of supported plugins.)
|
||||
codes from unsupported plugins. (See the [Ruff README](https://github.com/charliermarsh/ruff#user-content-how-does-ruff-compare-to-flake8)
|
||||
for the complete list of supported plugins.)
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff"
|
||||
version = "0.0.260"
|
||||
version = "0.0.256"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
@@ -22,6 +22,7 @@ ruff_python_stdlib = { path = "../ruff_python_stdlib" }
|
||||
ruff_rustpython = { path = "../ruff_rustpython" }
|
||||
|
||||
anyhow = { workspace = true }
|
||||
bisection = { version = "0.1.0" }
|
||||
bitflags = { workspace = true }
|
||||
chrono = { workspace = true }
|
||||
clap = { workspace = true, features = ["derive", "string"], optional = true }
|
||||
@@ -57,7 +58,6 @@ rustpython-parser = { workspace = true }
|
||||
schemars = { workspace = true }
|
||||
semver = { version = "1.0.16" }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
shellexpand = { workspace = true }
|
||||
smallvec = { version = "1.10.0" }
|
||||
strum = { workspace = true }
|
||||
@@ -65,10 +65,9 @@ strum_macros = { workspace = true }
|
||||
textwrap = { workspace = true }
|
||||
thiserror = { version = "1.0.38" }
|
||||
toml = { workspace = true }
|
||||
typed-arena = { version = "2.0.2" }
|
||||
unicode-width = {version ="0.1.10"}
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = { version = "0.4.0" }
|
||||
insta = { workspace = true, features = ["yaml", "redactions"] }
|
||||
pretty_assertions = "1.3.0"
|
||||
test-case = { workspace = true }
|
||||
@@ -76,4 +75,3 @@ test-case = { workspace = true }
|
||||
[features]
|
||||
default = []
|
||||
logical_lines = []
|
||||
jupyter_notebook = []
|
||||
|
||||
@@ -2,7 +2,3 @@ avoid-*
|
||||
do-not-*
|
||||
uses-*
|
||||
*-used
|
||||
rewrite-*
|
||||
prefer-*
|
||||
consider-*
|
||||
use-*
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
class Foo:
|
||||
def __str__(self):
|
||||
...
|
||||
|
||||
def __repr__(self):
|
||||
...
|
||||
|
||||
def __len__(self):
|
||||
...
|
||||
|
||||
def __length_hint__(self):
|
||||
...
|
||||
|
||||
def __init__(self):
|
||||
...
|
||||
|
||||
def __del__(self):
|
||||
...
|
||||
|
||||
def __bool__(self):
|
||||
...
|
||||
|
||||
def __bytes__(self):
|
||||
...
|
||||
|
||||
def __format__(self, format_spec):
|
||||
...
|
||||
|
||||
def __contains__(self, item):
|
||||
...
|
||||
|
||||
def __complex__(self):
|
||||
...
|
||||
|
||||
def __int__(self):
|
||||
...
|
||||
|
||||
def __float__(self):
|
||||
...
|
||||
|
||||
def __index__(self):
|
||||
...
|
||||
@@ -1,3 +0,0 @@
|
||||
import pickle
|
||||
|
||||
pickle.loads()
|
||||
@@ -1,3 +0,0 @@
|
||||
from telnetlib import Telnet
|
||||
|
||||
Telnet("localhost", 23)
|
||||
@@ -1,9 +1,7 @@
|
||||
import collections
|
||||
import datetime as dt
|
||||
from decimal import Decimal
|
||||
import logging
|
||||
import operator
|
||||
from pathlib import Path
|
||||
import random
|
||||
import re
|
||||
import time
|
||||
@@ -167,26 +165,6 @@ def float_str_not_inf_or_nan_is_wrong(value=float("3.14")):
|
||||
pass
|
||||
|
||||
|
||||
# Allow decimals
|
||||
def decimal_okay(value=Decimal("0.1")):
|
||||
pass
|
||||
|
||||
# Allow dates
|
||||
def date_okay(value=dt.date(2023, 3, 27)):
|
||||
pass
|
||||
|
||||
# Allow datetimes
|
||||
def datetime_okay(value=dt.datetime(2023, 3, 27, 13, 51, 59)):
|
||||
pass
|
||||
|
||||
# Allow timedeltas
|
||||
def timedelta_okay(value=dt.timedelta(hours=1)):
|
||||
pass
|
||||
|
||||
# Allow paths
|
||||
def path_okay(value=Path(".")):
|
||||
pass
|
||||
|
||||
# B006 and B008
|
||||
# We should handle arbitrary nesting of these B008.
|
||||
def nested_combo(a=[float(3), dt.datetime.now()]):
|
||||
|
||||
@@ -57,9 +57,3 @@ def foo3():
|
||||
|
||||
def foo4():
|
||||
...
|
||||
|
||||
|
||||
def foo5():
|
||||
foo.bar # Attribute (raise)
|
||||
object().__class__ # Attribute (raise)
|
||||
"foo" + "bar" # BinOp (raise)
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
import itertools
|
||||
from itertools import groupby
|
||||
|
||||
shoppers = ["Jane", "Joe", "Sarah"]
|
||||
items = [
|
||||
("lettuce", "greens"),
|
||||
("tomatoes", "greens"),
|
||||
("cucumber", "greens"),
|
||||
("chicken breast", "meats & fish"),
|
||||
("salmon", "meats & fish"),
|
||||
("ice cream", "frozen items"),
|
||||
]
|
||||
|
||||
carts = {shopper: [] for shopper in shoppers}
|
||||
|
||||
|
||||
def collect_shop_items(shopper, items):
|
||||
# Imagine this an expensive database query or calculation that is
|
||||
# advantageous to batch.
|
||||
carts[shopper] += items
|
||||
|
||||
|
||||
# Invoking the `groupby` function directly
|
||||
for _section, section_items in groupby(items, key=lambda p: p[1]):
|
||||
for shopper in shoppers:
|
||||
shopper = shopper.title()
|
||||
collect_shop_items(shopper, section_items) # B031
|
||||
# We're outside the nested loop and used the group again.
|
||||
collect_shop_items(shopper, section_items) # B031
|
||||
|
||||
for _section, section_items in groupby(items, key=lambda p: p[1]):
|
||||
collect_shop_items("Jane", section_items)
|
||||
collect_shop_items("Joe", section_items) # B031
|
||||
|
||||
|
||||
# Make sure to detect in other loop constructs as well - `while` loop
|
||||
for _section, section_items in groupby(items, key=lambda p: p[1]):
|
||||
countdown = 3
|
||||
while countdown > 0:
|
||||
collect_shop_items(shopper, section_items) # B031
|
||||
countdown -= 1
|
||||
|
||||
# Make sure to detect in other loop constructs as well - `list` comprehension
|
||||
collection = []
|
||||
for _section, section_items in groupby(items, key=lambda p: p[1]):
|
||||
collection.append([list(section_items) for _ in range(3)]) # B031
|
||||
|
||||
unique_items = set()
|
||||
another_set = set()
|
||||
for _section, section_items in groupby(items, key=lambda p: p[1]):
|
||||
# For nested loops, it should not flag the usage of the name
|
||||
for item in section_items:
|
||||
unique_items.add(item)
|
||||
|
||||
# But it should be detected when used again
|
||||
for item in section_items: # B031
|
||||
another_set.add(item)
|
||||
|
||||
for _section, section_items in groupby(items, key=lambda p: p[1]):
|
||||
# Variable has been overridden, skip checking
|
||||
section_items = list(unique_items)
|
||||
collect_shop_items("Jane", section_items)
|
||||
collect_shop_items("Jane", section_items)
|
||||
|
||||
for _section, section_items in groupby(items, key=lambda p: p[1]):
|
||||
# Variable has been overridden, skip checking
|
||||
# Not a realistic situation, just for testing purpose
|
||||
(section_items := list(unique_items))
|
||||
collect_shop_items("Jane", section_items)
|
||||
collect_shop_items("Jane", section_items)
|
||||
|
||||
for _section, section_items in groupby(items, key=lambda p: p[1]):
|
||||
# This is ok
|
||||
collect_shop_items("Jane", section_items)
|
||||
|
||||
# Invocation via the `itertools` module
|
||||
for _section, section_items in itertools.groupby(items, key=lambda p: p[1]):
|
||||
for shopper in shoppers:
|
||||
collect_shop_items(shopper, section_items) # B031
|
||||
|
||||
for group in groupby(items, key=lambda p: p[1]):
|
||||
# This is bad, but not detected currently
|
||||
collect_shop_items("Jane", group[1])
|
||||
collect_shop_items("Joe", group[1])
|
||||
|
||||
|
||||
# Make sure we ignore - but don't fail on more complicated invocations
|
||||
for _key, (_value1, _value2) in groupby(
|
||||
[("a", (1, 2)), ("b", (3, 4)), ("a", (5, 6))], key=lambda p: p[1]
|
||||
):
|
||||
collect_shop_items("Jane", group[1])
|
||||
collect_shop_items("Joe", group[1])
|
||||
|
||||
# Make sure we ignore - but don't fail on more complicated invocations
|
||||
for (_key1, _key2), (_value1, _value2) in groupby(
|
||||
[(("a", "a"), (1, 2)), (("b", "b"), (3, 4)), (("a", "a"), (5, 6))],
|
||||
key=lambda p: p[1],
|
||||
):
|
||||
collect_shop_items("Jane", group[1])
|
||||
collect_shop_items("Joe", group[1])
|
||||
|
||||
|
||||
# Let's redefine the `groupby` function to make sure we pick up the correct one.
|
||||
# NOTE: This should always be at the end of the file.
|
||||
def groupby(data, key=None):
|
||||
pass
|
||||
|
||||
|
||||
for name, group in groupby(items):
|
||||
collect_shop_items("Jane", items)
|
||||
# This shouldn't be flagged as the `groupby` function is different
|
||||
collect_shop_items("Joe", items)
|
||||
@@ -1,19 +1,6 @@
|
||||
x = [1, 2, 3]
|
||||
y = [("a", 1), ("b", 2), ("c", 3)]
|
||||
z = [(1,), (2,), (3,)]
|
||||
d = {"a": 1, "b": 2, "c": 3}
|
||||
|
||||
[i for i in x]
|
||||
{i for i in x}
|
||||
{k: v for k, v in y}
|
||||
{k: v for k, v in d.items()}
|
||||
|
||||
[i for i, in z]
|
||||
[i for i, j in y]
|
||||
[i for i in x if i > 1]
|
||||
[i for i in x for j in x]
|
||||
|
||||
{v: k for k, v in y}
|
||||
{k.foo: k for k in y}
|
||||
{k["foo"]: k for k in y}
|
||||
{k: v if v else None for k, v in y}
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
from django.db import models
|
||||
from django.db.models import Model
|
||||
|
||||
|
||||
class StrBeforeRandomField(models.Model):
|
||||
"""Model with `__str__` before a random property."""
|
||||
|
||||
class Meta:
|
||||
verbose_name = "test"
|
||||
verbose_name_plural = "tests"
|
||||
|
||||
def __str__(self):
|
||||
return ""
|
||||
|
||||
random_property = "foo"
|
||||
|
||||
|
||||
class StrBeforeFieldModel(models.Model):
|
||||
"""Model with `__str__` before fields."""
|
||||
|
||||
class Meta:
|
||||
verbose_name = "test"
|
||||
verbose_name_plural = "tests"
|
||||
|
||||
def __str__(self):
|
||||
return "foobar"
|
||||
|
||||
first_name = models.CharField(max_length=32)
|
||||
|
||||
|
||||
class ManagerBeforeField(models.Model):
|
||||
"""Model with manager before fields."""
|
||||
|
||||
objects = "manager"
|
||||
|
||||
class Meta:
|
||||
verbose_name = "test"
|
||||
verbose_name_plural = "tests"
|
||||
|
||||
def __str__(self):
|
||||
return "foobar"
|
||||
|
||||
first_name = models.CharField(max_length=32)
|
||||
|
||||
|
||||
class CustomMethodBeforeStr(models.Model):
|
||||
"""Model with a custom method before `__str__`."""
|
||||
|
||||
class Meta:
|
||||
verbose_name = "test"
|
||||
verbose_name_plural = "tests"
|
||||
|
||||
def my_method(self):
|
||||
pass
|
||||
|
||||
def __str__(self):
|
||||
return "foobar"
|
||||
|
||||
|
||||
class GetAbsoluteUrlBeforeSave(Model):
|
||||
"""Model with `get_absolute_url` method before `save` method.
|
||||
|
||||
Subclass this directly using the `Model` class.
|
||||
"""
|
||||
|
||||
def get_absolute_url(self):
|
||||
pass
|
||||
|
||||
def save(self):
|
||||
pass
|
||||
|
||||
|
||||
class ConstantsAreNotFields(models.Model):
|
||||
"""Model with an assignment to a constant after `__str__`."""
|
||||
|
||||
first_name = models.CharField(max_length=32)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "test"
|
||||
verbose_name_plural = "tests"
|
||||
|
||||
def __str__(self):
|
||||
pass
|
||||
|
||||
MY_CONSTANT = id(1)
|
||||
|
||||
|
||||
class PerfectlyFine(models.Model):
|
||||
"""Model which has everything in perfect order."""
|
||||
|
||||
first_name = models.CharField(max_length=32)
|
||||
last_name = models.CharField(max_length=32)
|
||||
objects = "manager"
|
||||
|
||||
class Meta:
|
||||
verbose_name = "test"
|
||||
verbose_name_plural = "tests"
|
||||
|
||||
def __str__(self):
|
||||
return "Perfectly fine!"
|
||||
|
||||
def save(self, **kwargs):
|
||||
super(PerfectlyFine, self).save(**kwargs)
|
||||
|
||||
def get_absolute_url(self):
|
||||
return "http://%s" % self
|
||||
|
||||
def my_method(self):
|
||||
pass
|
||||
|
||||
@property
|
||||
def random_property(self):
|
||||
return "%s" % self
|
||||
@@ -1 +0,0 @@
|
||||
_(f"{'value'}")
|
||||
@@ -1 +0,0 @@
|
||||
_("{}".format("line"))
|
||||
@@ -1 +0,0 @@
|
||||
_("%s" % "line")
|
||||
@@ -1,9 +1,3 @@
|
||||
import logging
|
||||
import logging as foo
|
||||
|
||||
logging.info("Hello {}".format("World!"))
|
||||
logging.log(logging.INFO, "Hello {}".format("World!"))
|
||||
foo.info("Hello {}".format("World!"))
|
||||
logging.log(logging.INFO, msg="Hello {}".format("World!"))
|
||||
logging.log(level=logging.INFO, msg="Hello {}".format("World!"))
|
||||
logging.log(msg="Hello {}".format("World!"), level=logging.INFO)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import logging
|
||||
|
||||
logging.info("Hello %s" % "World!")
|
||||
logging.log(logging.INFO, "Hello %s" % "World!")
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import logging
|
||||
|
||||
logging.info("Hello" + " " + "World!")
|
||||
logging.log(logging.INFO, "Hello" + " " + "World!")
|
||||
|
||||
@@ -2,4 +2,3 @@ import logging
|
||||
|
||||
name = "world"
|
||||
logging.info(f"Hello {name}")
|
||||
logging.log(logging.INFO, f"Hello {name}")
|
||||
|
||||
@@ -1,161 +1,79 @@
|
||||
import math
|
||||
import os
|
||||
import sys
|
||||
from math import inf
|
||||
|
||||
import numpy as np
|
||||
|
||||
def f12(
|
||||
x,
|
||||
y: str = os.pathsep, # OK
|
||||
) -> None: ...
|
||||
def f11(*, x: str = "x") -> None: ... # OK
|
||||
) -> None:
|
||||
...
|
||||
|
||||
|
||||
def f11(*, x: str = "x") -> None: # OK
|
||||
...
|
||||
|
||||
|
||||
def f13(
|
||||
x: list[str] = [ # OK
|
||||
x: list[str] = [
|
||||
"foo",
|
||||
"bar",
|
||||
"baz",
|
||||
]
|
||||
) -> None: ...
|
||||
] # OK
|
||||
) -> None:
|
||||
...
|
||||
|
||||
|
||||
def f14(
|
||||
x: tuple[str, ...] = ( # OK
|
||||
x: tuple[str, ...] = (
|
||||
"foo",
|
||||
"bar",
|
||||
"baz",
|
||||
)
|
||||
) -> None: ...
|
||||
) # OK
|
||||
) -> None:
|
||||
...
|
||||
|
||||
|
||||
def f15(
|
||||
x: set[str] = { # OK
|
||||
x: set[str] = {
|
||||
"foo",
|
||||
"bar",
|
||||
"baz",
|
||||
}
|
||||
) -> None: ...
|
||||
def f151(x: dict[int, int] = {1: 2}) -> None: ... # Ok
|
||||
def f152(
|
||||
x: dict[
|
||||
int, int
|
||||
] = { # OK
|
||||
1: 2,
|
||||
**{3: 4},
|
||||
}
|
||||
) -> None: ...
|
||||
def f153(
|
||||
x: list[
|
||||
int
|
||||
] = [ # OK
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
]
|
||||
) -> None: ...
|
||||
def f154(
|
||||
x: tuple[
|
||||
str, tuple[str, ...]
|
||||
] = ( # OK
|
||||
"foo",
|
||||
("bar", "baz"),
|
||||
)
|
||||
) -> None: ...
|
||||
def f141(
|
||||
x: list[
|
||||
int
|
||||
] = [ # OK
|
||||
*range(10)
|
||||
],
|
||||
) -> None: ...
|
||||
def f142(
|
||||
x: list[
|
||||
int
|
||||
] = list( # OK
|
||||
range(10)
|
||||
),
|
||||
) -> None: ...
|
||||
def f16(
|
||||
x: frozenset[
|
||||
bytes
|
||||
] = frozenset( # OK
|
||||
{b"foo", b"bar", b"baz"}
|
||||
)
|
||||
) -> None: ...
|
||||
} # OK
|
||||
) -> None:
|
||||
...
|
||||
|
||||
|
||||
def f16(x: frozenset[bytes] = frozenset({b"foo", b"bar", b"baz"})) -> None: # OK
|
||||
...
|
||||
|
||||
|
||||
def f17(
|
||||
x: str = "foo" # OK
|
||||
+ "bar",
|
||||
) -> None: ...
|
||||
x: str = "foo" + "bar", # OK
|
||||
) -> None:
|
||||
...
|
||||
|
||||
|
||||
def f18(
|
||||
x: str = b"foo" # OK
|
||||
+ b"bar",
|
||||
) -> None: ...
|
||||
x: str = b"foo" + b"bar", # OK
|
||||
) -> None:
|
||||
...
|
||||
|
||||
|
||||
def f19(
|
||||
x: object = "foo" # OK
|
||||
+ 4,
|
||||
) -> None: ...
|
||||
x: object = "foo" + 4, # OK
|
||||
) -> None:
|
||||
...
|
||||
|
||||
|
||||
def f20(
|
||||
x: int = 5
|
||||
+ 5, # OK
|
||||
) -> None: ...
|
||||
x: int = 5 + 5, # OK
|
||||
) -> None:
|
||||
...
|
||||
|
||||
|
||||
def f21(
|
||||
x: complex = 3j
|
||||
- 3j, # OK
|
||||
) -> None: ...
|
||||
x: complex = 3j - 3j, # OK
|
||||
) -> None:
|
||||
...
|
||||
|
||||
|
||||
def f22(
|
||||
x: complex = -42.5j # OK
|
||||
+ 4.3j,
|
||||
) -> None: ...
|
||||
def f23(
|
||||
x: bool = True, # OK
|
||||
) -> None: ...
|
||||
def f24(
|
||||
x: float = 3.14, # OK
|
||||
) -> None: ...
|
||||
def f25(
|
||||
x: float = -3.14, # OK
|
||||
) -> None: ...
|
||||
def f26(
|
||||
x: complex = -3.14j, # OK
|
||||
) -> None: ...
|
||||
def f27(
|
||||
x: complex = -3 - 3.14j, # OK
|
||||
) -> None: ...
|
||||
def f28(
|
||||
x: float = math.tau, # OK
|
||||
) -> None: ...
|
||||
def f29(
|
||||
x: float = math.inf, # OK
|
||||
) -> None: ...
|
||||
def f30(
|
||||
x: float = -math.inf, # OK
|
||||
) -> None: ...
|
||||
def f31(
|
||||
x: float = inf, # OK
|
||||
) -> None: ...
|
||||
def f32(
|
||||
x: float = np.inf, # OK
|
||||
) -> None: ...
|
||||
def f33(
|
||||
x: float = math.nan, # OK
|
||||
) -> None: ...
|
||||
def f34(
|
||||
x: float = -math.nan, # OK
|
||||
) -> None: ...
|
||||
def f35(
|
||||
x: complex = math.inf # OK
|
||||
+ 1j,
|
||||
) -> None: ...
|
||||
def f36(
|
||||
*,
|
||||
x: str = sys.version, # OK
|
||||
) -> None: ...
|
||||
def f37(
|
||||
*,
|
||||
x: str = "" # OK
|
||||
+ "",
|
||||
) -> None: ...
|
||||
x: complex = -42.5j + 4.3j, # OK
|
||||
) -> None:
|
||||
...
|
||||
|
||||
@@ -11,74 +11,32 @@ def f12(
|
||||
) -> None: ...
|
||||
def f11(*, x: str = "x") -> None: ... # OK
|
||||
def f13(
|
||||
x: list[str] = [ # OK
|
||||
x: list[
|
||||
str
|
||||
] = [ # Error PYI011 Only simple default values allowed for typed arguments
|
||||
"foo",
|
||||
"bar",
|
||||
"baz",
|
||||
]
|
||||
) -> None: ...
|
||||
def f14(
|
||||
x: tuple[str, ...] = ( # OK
|
||||
x: tuple[
|
||||
str, ...
|
||||
] = ( # Error PYI011 Only simple default values allowed for typed arguments
|
||||
"foo",
|
||||
"bar",
|
||||
"baz",
|
||||
)
|
||||
) -> None: ...
|
||||
def f15(
|
||||
x: set[str] = { # OK
|
||||
x: set[
|
||||
str
|
||||
] = { # Error PYI011 Only simple default values allowed for typed arguments
|
||||
"foo",
|
||||
"bar",
|
||||
"baz",
|
||||
}
|
||||
) -> None: ...
|
||||
def f151(x: dict[int, int] = {1: 2}) -> None: ... # Ok
|
||||
def f152(
|
||||
x: dict[
|
||||
int, int
|
||||
] = { # Error PYI011 Only simple default values allowed for typed arguments
|
||||
1: 2,
|
||||
**{3: 4},
|
||||
}
|
||||
) -> None: ...
|
||||
def f153(
|
||||
x: list[
|
||||
int
|
||||
] = [ # Error PYI011 Only simple default values allowed for typed arguments
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
]
|
||||
) -> None: ...
|
||||
def f154(
|
||||
x: tuple[
|
||||
str, tuple[str, ...]
|
||||
] = ( # Error PYI011 Only simple default values allowed for typed arguments
|
||||
"foo",
|
||||
("bar", "baz"),
|
||||
)
|
||||
) -> None: ...
|
||||
def f141(
|
||||
x: list[
|
||||
int
|
||||
] = [ # Error PYI011 Only simple default values allowed for typed arguments
|
||||
*range(10)
|
||||
],
|
||||
) -> None: ...
|
||||
def f142(
|
||||
x: list[
|
||||
int
|
||||
] = list( # Error PYI011 Only simple default values allowed for typed arguments
|
||||
range(10)
|
||||
),
|
||||
) -> None: ...
|
||||
def f16(
|
||||
x: frozenset[
|
||||
bytes
|
||||
@@ -151,11 +109,8 @@ def f35(
|
||||
+ 1j,
|
||||
) -> None: ...
|
||||
def f36(
|
||||
*,
|
||||
x: str = sys.version, # OK
|
||||
*, x: str = sys.version, # OK
|
||||
) -> None: ...
|
||||
def f37(
|
||||
*,
|
||||
x: str = "" # Error PYI011 Only simple default values allowed for typed arguments
|
||||
+ "",
|
||||
*, x: str = "" + "", # Error PYI011 Only simple default values allowed for typed arguments
|
||||
) -> None: ...
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
# Violations of PYI012
|
||||
|
||||
|
||||
class OneAttributeClass:
|
||||
value: int
|
||||
pass # PYI012 Class body must not contain `pass`
|
||||
|
||||
|
||||
class OneAttributeClassRev:
|
||||
pass # PYI012 Class body must not contain `pass`
|
||||
value: int
|
||||
|
||||
|
||||
class DocstringClass:
|
||||
"""
|
||||
My body only contains pass.
|
||||
"""
|
||||
|
||||
pass # PYI012 Class body must not contain `pass`
|
||||
|
||||
|
||||
class NonEmptyChild(Exception):
|
||||
value: int
|
||||
pass # PYI012 Class body must not contain `pass`
|
||||
|
||||
|
||||
class NonEmptyChild2(Exception):
|
||||
pass # PYI012 Class body must not contain `pass`
|
||||
value: int
|
||||
|
||||
|
||||
class NonEmptyWithInit:
|
||||
value: int
|
||||
pass # PYI012 Class body must not contain `pass`
|
||||
|
||||
def __init__():
|
||||
pass
|
||||
|
||||
|
||||
# Not violations (of PYI012)
|
||||
|
||||
|
||||
class EmptyClass:
|
||||
pass # Y009 Empty body should contain `...`, not `pass`
|
||||
|
||||
|
||||
class EmptyOneLine:
|
||||
pass # Y009 Empty body should contain `...`, not `pass`
|
||||
|
||||
|
||||
class Dog:
|
||||
eyes: int = 2
|
||||
|
||||
|
||||
class EmptyEllipsis:
|
||||
...
|
||||
|
||||
|
||||
class NonEmptyEllipsis:
|
||||
value: int
|
||||
... # Y013 Non-empty class body must not contain `...`
|
||||
|
||||
|
||||
class WithInit:
|
||||
value: int = 0
|
||||
|
||||
def __init__():
|
||||
pass
|
||||
|
||||
|
||||
def function():
|
||||
pass
|
||||
|
||||
|
||||
pass
|
||||
@@ -1,59 +0,0 @@
|
||||
# Violations of PYI012
|
||||
|
||||
class OneAttributeClass:
|
||||
value: int
|
||||
pass # PYI012 Class body must not contain `pass`
|
||||
|
||||
class OneAttributeClassRev:
|
||||
pass # PYI012 Class body must not contain `pass`
|
||||
value: int
|
||||
|
||||
class DocstringClass:
|
||||
"""
|
||||
My body only contains pass.
|
||||
"""
|
||||
|
||||
pass # PYI012 Class body must not contain `pass`
|
||||
|
||||
class NonEmptyChild(Exception):
|
||||
value: int
|
||||
pass # PYI012 Class body must not contain `pass`
|
||||
|
||||
class NonEmptyChild2(Exception):
|
||||
pass # PYI012 Class body must not contain `pass`
|
||||
value: int
|
||||
|
||||
class NonEmptyWithInit:
|
||||
value: int
|
||||
pass # PYI012 Class body must not contain `pass`
|
||||
|
||||
def __init__():
|
||||
pass
|
||||
|
||||
# Not violations (of PYI012)
|
||||
|
||||
class EmptyClass:
|
||||
pass # Y009 Empty body should contain `...`, not `pass`
|
||||
|
||||
class EmptyOneLine:
|
||||
pass # Y009 Empty body should contain `...`, not `pass`
|
||||
|
||||
class Dog:
|
||||
eyes: int = 2
|
||||
|
||||
class EmptyEllipsis: ...
|
||||
|
||||
class NonEmptyEllipsis:
|
||||
value: int
|
||||
... # Y013 Non-empty class body must not contain `...`
|
||||
|
||||
class WithInit:
|
||||
value: int = 0
|
||||
|
||||
def __init__():
|
||||
pass
|
||||
|
||||
def function():
|
||||
pass
|
||||
|
||||
pass
|
||||
@@ -39,58 +39,6 @@ def f15(
|
||||
...
|
||||
|
||||
|
||||
def f151(x={1: 2}) -> None: # Ok
|
||||
...
|
||||
|
||||
|
||||
def f152(
|
||||
x={ # OK
|
||||
1: 2,
|
||||
**{3: 4},
|
||||
}
|
||||
) -> None:
|
||||
...
|
||||
|
||||
|
||||
def f153(
|
||||
x=[ # OK
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
]
|
||||
) -> None:
|
||||
...
|
||||
|
||||
|
||||
def f154(
|
||||
x=( # OK
|
||||
"foo",
|
||||
("bar", "baz"),
|
||||
)
|
||||
) -> None:
|
||||
...
|
||||
|
||||
|
||||
def f141(
|
||||
x=[*range(10)], # OK
|
||||
) -> None:
|
||||
...
|
||||
|
||||
|
||||
def f142(
|
||||
x=list(range(10)), # OK
|
||||
) -> None:
|
||||
...
|
||||
|
||||
|
||||
def f16(x=frozenset({b"foo", b"bar", b"baz"})) -> None:
|
||||
... # OK
|
||||
|
||||
|
||||
@@ -4,60 +4,26 @@ def f12(
|
||||
) -> None: ...
|
||||
def f11(*, x="x") -> None: ... # OK
|
||||
def f13(
|
||||
x=[ # OK
|
||||
x=[ # Error PYI014
|
||||
"foo",
|
||||
"bar",
|
||||
"baz",
|
||||
]
|
||||
) -> None: ...
|
||||
def f14(
|
||||
x=( # OK
|
||||
x=( # Error PYI014
|
||||
"foo",
|
||||
"bar",
|
||||
"baz",
|
||||
)
|
||||
) -> None: ...
|
||||
def f15(
|
||||
x={ # OK
|
||||
x={ # Error PYI014
|
||||
"foo",
|
||||
"bar",
|
||||
"baz",
|
||||
}
|
||||
) -> None: ...
|
||||
def f151(x={1: 2}) -> None: ...
|
||||
def f152(
|
||||
x={ # Error PYI014
|
||||
1: 2,
|
||||
**{3: 4},
|
||||
}
|
||||
) -> None: ...
|
||||
def f153(
|
||||
x=[ # Error PYI014
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
]
|
||||
) -> None: ...
|
||||
def f154(
|
||||
x=( # Error PYI014
|
||||
"foo",
|
||||
("bar", "baz"),
|
||||
)
|
||||
) -> None: ...
|
||||
def f141(
|
||||
x=[*range(10)], # Error PYI014
|
||||
) -> None: ...
|
||||
def f142(
|
||||
x=list(range(10)), # Error PYI014
|
||||
) -> None: ...
|
||||
def f16(x=frozenset({b"foo", b"bar", b"baz"})) -> None: ... # Error PYI014
|
||||
def f17(
|
||||
x="foo" + "bar", # Error PYI014
|
||||
@@ -78,5 +44,5 @@ def f22(
|
||||
x=-42.5j + 4.3j, # Error PYI014
|
||||
) -> None: ...
|
||||
def f23(
|
||||
x=True, # OK
|
||||
x=True, # OK
|
||||
) -> None: ...
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
import builtins
|
||||
import typing
|
||||
from typing import TypeAlias, Final
|
||||
|
||||
field1: int
|
||||
field2: int = ...
|
||||
field3 = ... # type: int # Y033 Do not use type comments in stubs (e.g. use "x: int" instead of "x = ... # type: int")
|
||||
field4: int = 0
|
||||
field41: int = 0xFFFFFFFF
|
||||
field42: int = 1234567890
|
||||
field43: int = -0xFFFFFFFF
|
||||
field44: int = -1234567890
|
||||
field5 = 0 # type: int # Y033 Do not use type comments in stubs (e.g. use "x: int" instead of "x = ... # type: int") # Y052 Need type annotation for "field5"
|
||||
field6 = 0 # Y052 Need type annotation for "field6"
|
||||
field7 = b"" # Y052 Need type annotation for "field7"
|
||||
field71 = "foo" # Y052 Need type annotation for "field71"
|
||||
field72: str = "foo"
|
||||
field8 = False # Y052 Need type annotation for "field8"
|
||||
field81 = -1 # Y052 Need type annotation for "field81"
|
||||
field82: float = -98.43
|
||||
field83 = -42j # Y052 Need type annotation for "field83"
|
||||
field84 = 5 + 42j # Y052 Need type annotation for "field84"
|
||||
field85 = -5 - 42j # Y052 Need type annotation for "field85"
|
||||
field9 = None # Y026 Use typing_extensions.TypeAlias for type aliases, e.g. "field9: TypeAlias = None"
|
||||
Field95: TypeAlias = None
|
||||
Field96: TypeAlias = int | None
|
||||
Field97: TypeAlias = None | typing.SupportsInt | builtins.str | float | bool
|
||||
field19 = [1, 2, 3] # Y052 Need type annotation for "field19"
|
||||
field191: list[int] = [1, 2, 3]
|
||||
field20 = (1, 2, 3) # Y052 Need type annotation for "field20"
|
||||
field201: tuple[int, ...] = (1, 2, 3)
|
||||
field21 = {1, 2, 3} # Y052 Need type annotation for "field21"
|
||||
field211: set[int] = {1, 2, 3}
|
||||
field212 = {"foo": "bar"} # Y052 Need type annotation for "field212"
|
||||
field213: dict[str, str] = {"foo": "bar"}
|
||||
field22: Final = {"foo": 5}
|
||||
field221: list[int] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] # Y015 Only simple default values are allowed for assignments
|
||||
field223: list[int] = [*range(10)] # Y015 Only simple default values are allowed for assignments
|
||||
field224: list[int] = list(range(10)) # Y015 Only simple default values are allowed for assignments
|
||||
field225: list[object] = [{}, 1, 2] # Y015 Only simple default values are allowed for assignments
|
||||
field226: tuple[str | tuple[str, ...], ...] = ("foo", ("foo", "bar")) # Y015 Only simple default values are allowed for assignments
|
||||
field227: dict[str, object] = {"foo": {"foo": "bar"}} # Y015 Only simple default values are allowed for assignments
|
||||
field228: dict[str, list[object]] = {"foo": []} # Y015 Only simple default values are allowed for assignments
|
||||
# When parsed, this case results in `None` being placed in the `.keys` list for the `ast.Dict` node
|
||||
field229: dict[int, int] = {1: 2, **{3: 4}} # Y015 Only simple default values are allowed for assignments
|
||||
field23 = "foo" + "bar" # Y015 Only simple default values are allowed for assignments
|
||||
field24 = b"foo" + b"bar" # Y015 Only simple default values are allowed for assignments
|
||||
field25 = 5 * 5 # Y015 Only simple default values are allowed for assignments
|
||||
@@ -1,51 +0,0 @@
|
||||
import builtins
|
||||
import typing
|
||||
from typing import TypeAlias, Final
|
||||
|
||||
# We shouldn't emit Y015 for simple default values
|
||||
field1: int
|
||||
field2: int = ...
|
||||
field3 = ... # type: int # Y033 Do not use type comments in stubs (e.g. use "x: int" instead of "x = ... # type: int")
|
||||
field4: int = 0
|
||||
field41: int = 0xFFFFFFFF
|
||||
field42: int = 1234567890
|
||||
field43: int = -0xFFFFFFFF
|
||||
field44: int = -1234567890
|
||||
field5 = 0 # type: int # Y033 Do not use type comments in stubs (e.g. use "x: int" instead of "x = ... # type: int") # Y052 Need type annotation for "field5"
|
||||
field6 = 0 # Y052 Need type annotation for "field6"
|
||||
field7 = b"" # Y052 Need type annotation for "field7"
|
||||
field71 = "foo" # Y052 Need type annotation for "field71"
|
||||
field72: str = "foo"
|
||||
field8 = False # Y052 Need type annotation for "field8"
|
||||
field81 = -1 # Y052 Need type annotation for "field81"
|
||||
field82: float = -98.43
|
||||
field83 = -42j # Y052 Need type annotation for "field83"
|
||||
field84 = 5 + 42j # Y052 Need type annotation for "field84"
|
||||
field85 = -5 - 42j # Y052 Need type annotation for "field85"
|
||||
field9 = None # Y026 Use typing_extensions.TypeAlias for type aliases, e.g. "field9: TypeAlias = None"
|
||||
Field95: TypeAlias = None
|
||||
Field96: TypeAlias = int | None
|
||||
Field97: TypeAlias = None | typing.SupportsInt | builtins.str | float | bool
|
||||
field19 = [1, 2, 3] # Y052 Need type annotation for "field19"
|
||||
field191: list[int] = [1, 2, 3]
|
||||
field20 = (1, 2, 3) # Y052 Need type annotation for "field20"
|
||||
field201: tuple[int, ...] = (1, 2, 3)
|
||||
field21 = {1, 2, 3} # Y052 Need type annotation for "field21"
|
||||
field211: set[int] = {1, 2, 3}
|
||||
field212 = {"foo": "bar"} # Y052 Need type annotation for "field212"
|
||||
field213: dict[str, str] = {"foo": "bar"}
|
||||
field22: Final = {"foo": 5}
|
||||
|
||||
# We *should* emit Y015 for more complex default values
|
||||
field221: list[int] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] # Y015 Only simple default values are allowed for assignments
|
||||
field223: list[int] = [*range(10)] # Y015 Only simple default values are allowed for assignments
|
||||
field224: list[int] = list(range(10)) # Y015 Only simple default values are allowed for assignments
|
||||
field225: list[object] = [{}, 1, 2] # Y015 Only simple default values are allowed for assignments
|
||||
field226: tuple[str | tuple[str, ...], ...] = ("foo", ("foo", "bar")) # Y015 Only simple default values are allowed for assignments
|
||||
field227: dict[str, object] = {"foo": {"foo": "bar"}} # Y015 Only simple default values are allowed for assignments
|
||||
field228: dict[str, list[object]] = {"foo": []} # Y015 Only simple default values are allowed for assignments
|
||||
# When parsed, this case results in `None` being placed in the `.keys` list for the `ast.Dict` node
|
||||
field229: dict[int, int] = {1: 2, **{3: 4}} # Y015 Only simple default values are allowed for assignments
|
||||
field23 = "foo" + "bar" # Y015 Only simple default values are allowed for assignments
|
||||
field24 = b"foo" + b"bar" # Y015 Only simple default values are allowed for assignments
|
||||
field25 = 5 * 5 # Y015 Only simple default values are allowed for assignments
|
||||
@@ -2,13 +2,3 @@ def x(y):
|
||||
if not y:
|
||||
return
|
||||
return None # error
|
||||
|
||||
|
||||
class BaseCache:
|
||||
def get(self, key: str) -> str | None:
|
||||
print(f"{key} not found")
|
||||
return None
|
||||
|
||||
def get(self, key: str) -> None:
|
||||
print(f"{key} not found")
|
||||
return None
|
||||
|
||||
@@ -20,5 +20,3 @@ for key in list(obj.keys()):
|
||||
{k: k for k in obj.keys()} # SIM118
|
||||
|
||||
(k for k in obj.keys()) # SIM118
|
||||
|
||||
key in (obj or {}).keys() # SIM118
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
if a or True: # SIM222
|
||||
if a or True: # SIM223
|
||||
pass
|
||||
|
||||
if (a or b) or True: # SIM222
|
||||
if (a or b) or True: # SIM223
|
||||
pass
|
||||
|
||||
if a or (b or True): # SIM222
|
||||
if a or (b or True): # SIM223
|
||||
pass
|
||||
|
||||
if a and True: # OK
|
||||
@@ -16,16 +16,3 @@ if True: # OK
|
||||
|
||||
def validate(self, value):
|
||||
return json.loads(value) or True # OK
|
||||
|
||||
|
||||
if a or f() or b or g() or True: # OK
|
||||
pass
|
||||
|
||||
if a or f() or True or g() or b: # SIM222
|
||||
pass
|
||||
|
||||
if True or f() or a or g() or b: # SIM222
|
||||
pass
|
||||
|
||||
if a or True or f() or b or g(): # SIM222
|
||||
pass
|
||||
|
||||
@@ -12,15 +12,3 @@ if a or False:
|
||||
|
||||
if False:
|
||||
pass
|
||||
|
||||
if a and f() and b and g() and False: # OK
|
||||
pass
|
||||
|
||||
if a and f() and False and g() and b: # SIM222
|
||||
pass
|
||||
|
||||
if False and f() and a and g() and b: # SIM222
|
||||
pass
|
||||
|
||||
if a and False and f() and b and g(): # SIM222
|
||||
pass
|
||||
|
||||
@@ -7,4 +7,3 @@ from ..protocol import commands, definitions, responses
|
||||
from ..server import example
|
||||
from .. import server
|
||||
from . import logger, models
|
||||
from ..protocol.UpperCaseModule import some_function
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
def some_function():
|
||||
pass
|
||||
@@ -2,9 +2,7 @@ from a import a1 # import_from
|
||||
from c import * # import_from_star
|
||||
import a # import
|
||||
import c.d
|
||||
from z import z1
|
||||
import b as b1 # import_as
|
||||
import z
|
||||
|
||||
from ..parent import *
|
||||
from .my import fn
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
import sys
|
||||
import baz
|
||||
from foo import bar, baz
|
||||
from foo.bar import blah, blub
|
||||
from foo.bar.baz import something
|
||||
import foo
|
||||
import foo.bar
|
||||
import foo.bar.baz
|
||||
@@ -1,32 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(paste(\"Hello\",\"WoRld\"))\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "R",
|
||||
"language": "R",
|
||||
"name": "ir"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": "r",
|
||||
"file_extension": ".r",
|
||||
"mimetype": "text/x-r-source",
|
||||
"name": "R",
|
||||
"pygments_lexer": "r",
|
||||
"version": "3.2.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
# In[1]:
|
||||
|
||||
|
||||
def unused_variable():
|
||||
x = 1
|
||||
y = 2
|
||||
print(f"cell one: {y}")
|
||||
|
||||
unused_variable()
|
||||
|
||||
|
||||
# Let's do another mistake
|
||||
|
||||
# In[2]:
|
||||
|
||||
|
||||
def mutable_argument(z=set()):
|
||||
print(f"cell two: {z}")
|
||||
|
||||
mutable_argument()
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
broken "§=($/=(")
|
||||
@@ -1,88 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"cell one: 2\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def unused_variable():\n",
|
||||
" x = 1\n",
|
||||
" y = 2\n",
|
||||
" print(f\"cell one: {y}\")\n",
|
||||
"\n",
|
||||
"unused_variable()"
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false,
|
||||
"ExecuteTime": {
|
||||
"start_time": "2023-03-08T23:01:09.705831Z",
|
||||
"end_time": "2023-03-08T23:01:09.782916Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Let's do another mistake"
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"collapsed": true,
|
||||
"ExecuteTime": {
|
||||
"start_time": "2023-03-08T23:01:09.733809Z",
|
||||
"end_time": "2023-03-08T23:01:09.915760Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"cell two: set()\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def mutable_argument(z=set()):\n",
|
||||
" print(f\"cell two: {z}\")\n",
|
||||
"\n",
|
||||
"mutable_argument()\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 2
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython2",
|
||||
"version": "2.7.6"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{}
|
||||
@@ -13,8 +13,3 @@ result = {
|
||||
'key1': 'value',
|
||||
'key2': 'value',
|
||||
}
|
||||
|
||||
def foo() -> None:
|
||||
#: E231
|
||||
if (1,2):
|
||||
pass
|
||||
|
||||
@@ -56,29 +56,7 @@ sit amet consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labor
|
||||
# OK
|
||||
# https://loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong.url.com
|
||||
|
||||
# OK
|
||||
# Not OK
|
||||
_ = """
|
||||
Source: https://github.com/PyCQA/pycodestyle/pull/258/files#diff-841c622497a8033d10152bfdfb15b20b92437ecdea21a260944ea86b77b51533
|
||||
"""
|
||||
|
||||
# OK
|
||||
_ = """
|
||||
[this-is-ok](https://github.com/PyCQA/pycodestyle/pull/258/files#diff-841c622497a8033d10152bfdfb15b20b92437ecdea21a260944ea86b77b51533)
|
||||
[this is ok](https://github.com/PyCQA/pycodestyle/pull/258/files#diff-841c622497a8033d10152bfdfb15b20b92437ecdea21a260944ea86b77b51533)
|
||||
"""
|
||||
|
||||
|
||||
# OK
|
||||
class Foo:
|
||||
"""
|
||||
@see https://looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong.url.com
|
||||
|
||||
:param dynamodb_scan_kwargs: kwargs pass to <https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#DynamoDB.Table.scan>
|
||||
"""
|
||||
|
||||
|
||||
# Error
|
||||
class Bar:
|
||||
"""
|
||||
This is a long sentence that ends with a shortened URL and, therefore, could easily be broken across multiple lines ([source](https://ruff.rs))
|
||||
"""
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
def bad_function():
|
||||
"""this docstring is not capitalized"""
|
||||
|
||||
def good_function():
|
||||
"""This docstring is capitalized."""
|
||||
|
||||
def other_function():
|
||||
"""
|
||||
This docstring is capitalized."""
|
||||
|
||||
def another_function():
|
||||
""" This docstring is capitalized."""
|
||||
|
||||
def utf8_function():
|
||||
"""éste docstring is capitalized."""
|
||||
@@ -113,13 +113,3 @@ def f(x, *args, **kwargs):
|
||||
**kwargs: keyword arguments
|
||||
"""
|
||||
return x
|
||||
|
||||
|
||||
class Test:
|
||||
def f(self, /, arg1: int) -> None:
|
||||
"""
|
||||
Some beauty description.
|
||||
|
||||
Args:
|
||||
arg1: some description of arg
|
||||
"""
|
||||
|
||||
@@ -504,12 +504,3 @@ Testing this incorrectly indented docstring.
|
||||
x: Test argument.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def implicit_string_concatenation():
|
||||
"""Toggle the gizmo.
|
||||
|
||||
Returns
|
||||
A value of some sort.
|
||||
|
||||
""""Extra content"
|
||||
|
||||
@@ -1,19 +1,10 @@
|
||||
"""Test: imports within `ModuleNotFoundError` and `ImportError` handlers."""
|
||||
"""Test: imports within `ModuleNotFoundError` handlers."""
|
||||
|
||||
|
||||
def module_not_found_error():
|
||||
def check_orjson():
|
||||
try:
|
||||
import orjson
|
||||
|
||||
return True
|
||||
except ModuleNotFoundError:
|
||||
return False
|
||||
|
||||
|
||||
def import_error():
|
||||
try:
|
||||
import orjson
|
||||
|
||||
return True
|
||||
except ImportError:
|
||||
return False
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
"""Test: parsing of nested string annotations."""
|
||||
|
||||
from typing import List
|
||||
from pathlib import Path, PurePath
|
||||
|
||||
|
||||
x: """List['Path']""" = []
|
||||
@@ -4,7 +4,6 @@
|
||||
"{1:{0}}".format(1, 2) # No issues
|
||||
"{1:{0}}".format(1, 2, 3) # F523
|
||||
"{0}{2}".format(1, 2) # F523, # F524
|
||||
"{1.arg[1]!r:0{2['arg']}{1}}".format(1, 2, 3, 4) # F523
|
||||
|
||||
# With no indexes
|
||||
"{}".format(1, 2) # F523
|
||||
|
||||
@@ -8,6 +8,3 @@ def f() -> "A":
|
||||
|
||||
def g() -> "///":
|
||||
pass
|
||||
|
||||
|
||||
X: """List[int]"""'☃' = []
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
"""Test case: ForwardRef."""
|
||||
|
||||
from typing import ForwardRef, TypeVar
|
||||
|
||||
X = ForwardRef("List[int]")
|
||||
Y: ForwardRef("List[int]")
|
||||
|
||||
Z = TypeVar("X", "List[int]", "int")
|
||||
@@ -1,7 +0,0 @@
|
||||
"""Test case: f-strings in type annotations."""
|
||||
|
||||
from typing import List
|
||||
|
||||
x = 1
|
||||
|
||||
x: List[f"i{x}nt"] = []
|
||||
@@ -1,9 +0,0 @@
|
||||
"""Test case: f-strings in future type annotations."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import List
|
||||
|
||||
x = 1
|
||||
|
||||
x: List[f"i{x}nt"] = []
|
||||
@@ -1,24 +0,0 @@
|
||||
def test_division():
|
||||
a = 9 / 3
|
||||
assert "No ZeroDivisionError were raised" # [assert-on-string-literal]
|
||||
|
||||
|
||||
def test_division():
|
||||
a = 9 / 3
|
||||
assert a == 3
|
||||
|
||||
|
||||
try:
|
||||
assert "bad" # [assert-on-string-literal]
|
||||
except:
|
||||
assert "bad again" # [assert-on-string-literal]
|
||||
|
||||
a = 12
|
||||
assert f"hello {a}" # [assert-on-string-literal]
|
||||
assert f"{a}" # [assert-on-string-literal]
|
||||
assert f"" # [assert-on-string-literal]
|
||||
assert "" # [assert-on-string-literal]
|
||||
assert b"hello" # [assert-on-string-literal]
|
||||
assert "", b"hi" # [assert-on-string-literal]
|
||||
assert "WhyNotHere?", "HereIsOk" # [assert-on-string-literal]
|
||||
assert 12, "ok here"
|
||||
@@ -1,14 +0,0 @@
|
||||
try:
|
||||
1 / 0
|
||||
except ZeroDivisionError or ValueError as e: # [binary-op-exception]
|
||||
pass
|
||||
|
||||
try:
|
||||
raise ValueError
|
||||
except ZeroDivisionError and ValueError as e: # [binary-op-exception]
|
||||
print(e)
|
||||
|
||||
try:
|
||||
pass
|
||||
except (ValueError, Exception, IOError):
|
||||
pass
|
||||
@@ -37,24 +37,3 @@ def print_python_version():
|
||||
def print_python_version():
|
||||
if 2 * 2 == 4:
|
||||
return None
|
||||
|
||||
|
||||
def print_python_version():
|
||||
"""This function returns None."""
|
||||
return None
|
||||
|
||||
|
||||
def print_python_version():
|
||||
"""This function returns None."""
|
||||
print(sys.version)
|
||||
return None # [useless-return]
|
||||
|
||||
|
||||
class BaseCache:
|
||||
def get(self, key: str) -> str | None:
|
||||
print(f"{key} not found")
|
||||
return None
|
||||
|
||||
def get(self, key: str) -> None:
|
||||
print(f"{key} not found")
|
||||
return None
|
||||
|
||||
@@ -30,29 +30,8 @@ def f(x: "List[str]") -> None:
|
||||
...
|
||||
|
||||
|
||||
def f(x: r"List[str]") -> None:
|
||||
...
|
||||
|
||||
|
||||
def f(x: "List[str]") -> None:
|
||||
...
|
||||
|
||||
|
||||
def f(x: """List[str]""") -> None:
|
||||
...
|
||||
|
||||
|
||||
def f(x: "Li" "st[str]") -> None:
|
||||
...
|
||||
|
||||
|
||||
def f(x: "List['List[str]']") -> None:
|
||||
...
|
||||
|
||||
|
||||
def f(x: "List['Li' 'st[str]']") -> None:
|
||||
...
|
||||
|
||||
|
||||
def f(x: "Li" "st['List[str]']") -> None:
|
||||
list = "abc"
|
||||
|
||||
|
||||
def f(x: List[str]) -> None:
|
||||
...
|
||||
|
||||
@@ -46,8 +46,3 @@ def f(x: Union[("str", "int"), float]) -> None:
|
||||
def f() -> None:
|
||||
x: Optional[str]
|
||||
x = Optional[str]
|
||||
|
||||
x = Union[str, int]
|
||||
x = Union["str", "int"]
|
||||
x: Union[str, int]
|
||||
x: Union["str", "int"]
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import io
|
||||
|
||||
with io.open("f.txt", mode="r", buffering=-1, **kwargs) as f:
|
||||
print(f.read())
|
||||
|
||||
from io import open
|
||||
|
||||
with open("f.txt") as f:
|
||||
print(f.read())
|
||||
|
||||
import io
|
||||
|
||||
with io.open("f.txt", mode="r", buffering=-1, **kwargs) as f:
|
||||
print(f.read())
|
||||
|
||||
@@ -73,13 +73,3 @@ print("%s \N{snowman}" % (a,))
|
||||
print("%(foo)s \N{snowman}" % {"foo": 1})
|
||||
|
||||
print(("foo %s " "bar %s") % (x, y))
|
||||
|
||||
# Single-value expressions
|
||||
print('Hello %s' % "World")
|
||||
print('Hello %s' % f"World")
|
||||
print('Hello %s (%s)' % bar)
|
||||
print('Hello %s (%s)' % bar.baz)
|
||||
print('Hello %s (%s)' % bar['bop'])
|
||||
print('Hello %(arg)s' % bar)
|
||||
print('Hello %(arg)s' % bar.baz)
|
||||
print('Hello %(arg)s' % bar['bop'])
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
# OK
|
||||
"%s" % unknown_type
|
||||
|
||||
b"%s" % (b"bytestring",)
|
||||
|
||||
"%*s" % (5, "hi")
|
||||
@@ -55,9 +57,3 @@ pytest.param('"%8s" % (None,)', id="unsafe width-string conversion"),
|
||||
"""
|
||||
% (x,)
|
||||
)
|
||||
|
||||
'Hello %s' % bar
|
||||
|
||||
'Hello %s' % bar.baz
|
||||
|
||||
'Hello %s' % bar['bop']
|
||||
|
||||
@@ -86,14 +86,3 @@ async def c():
|
||||
|
||||
async def c():
|
||||
return "{}".format(1 + await 3)
|
||||
|
||||
|
||||
def d(osname, version, release):
|
||||
return"{}-{}.{}".format(osname, version, release)
|
||||
|
||||
|
||||
def e():
|
||||
yield"{}".format(1)
|
||||
|
||||
|
||||
assert"{}".format(1)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
input = [1, 2, 3]
|
||||
otherInput = [2, 3, 4]
|
||||
foo = [1, 2, 3, 4]
|
||||
|
||||
# OK
|
||||
zip(input, otherInput) # different inputs
|
||||
@@ -9,8 +8,6 @@ zip(input, input[2:]) # not successive
|
||||
zip(input[:-1], input[2:]) # not successive
|
||||
list(zip(input, otherInput)) # nested call
|
||||
zip(input, input[1::2]) # not successive
|
||||
zip(foo[:-1], foo[1:], foo, strict=False) # more than 2 inputs
|
||||
zip(foo[:-1], foo[1:], foo, strict=True) # more than 2 inputs
|
||||
|
||||
# Errors
|
||||
zip(input, input[1:])
|
||||
@@ -20,6 +17,3 @@ zip(input[1:], input[2:])
|
||||
zip(input[1:-1], input[2:])
|
||||
list(zip(input, input[1:]))
|
||||
list(zip(input[:-1], input[1:]))
|
||||
zip(foo[:-1], foo[1:], strict=True)
|
||||
zip(foo[:-1], foo[1:], strict=False)
|
||||
zip(foo[:-1], foo[1:], strict=bool(foo))
|
||||
|
||||
@@ -2,24 +2,12 @@
|
||||
# noqa # comment
|
||||
print() # noqa
|
||||
print() # noqa # comment
|
||||
print() # noqa # comment
|
||||
print() # noqa comment
|
||||
print() # noqa comment
|
||||
print(a) # noqa
|
||||
print(a) # noqa # comment
|
||||
print(a) # noqa # comment
|
||||
print(a) # noqa comment
|
||||
print(a) # noqa comment
|
||||
|
||||
# noqa: E501, F821
|
||||
# noqa: E501, F821 # comment
|
||||
print() # noqa: E501, F821
|
||||
print() # noqa: E501, F821 # comment
|
||||
print() # noqa: E501, F821 # comment
|
||||
print() # noqa: E501, F821 comment
|
||||
print() # noqa: E501, F821 comment
|
||||
print(a) # noqa: E501, F821
|
||||
print(a) # noqa: E501, F821 # comment
|
||||
print(a) # noqa: E501, F821 # comment
|
||||
print(a) # noqa: E501, F821 comment
|
||||
print(a) # noqa: E501, F821 comment
|
||||
|
||||
@@ -40,16 +40,8 @@ def noreturn():
|
||||
logger.exception("process failed")
|
||||
|
||||
|
||||
def good_return_with_side_effects():
|
||||
def still_good():
|
||||
try:
|
||||
pass
|
||||
return process()
|
||||
except MyException:
|
||||
logger.exception("process failed")
|
||||
|
||||
def good_noexcept():
|
||||
try:
|
||||
pass
|
||||
return process()
|
||||
finally:
|
||||
logger.exception("process failed")
|
||||
|
||||
@@ -9,30 +9,30 @@ Running from the repo root should pick up and enforce the appropriate settings f
|
||||
|
||||
```console
|
||||
∴ cargo run -p ruff_cli -- check crates/ruff/resources/test/project/
|
||||
crates/ruff/resources/test/project/examples/.dotfiles/script.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||
crates/ruff/resources/test/project/examples/.dotfiles/script.py:1:8: F401 [*] `numpy` imported but unused
|
||||
crates/ruff/resources/test/project/examples/.dotfiles/script.py:2:17: F401 [*] `app.app_file` imported but unused
|
||||
crates/ruff/resources/test/project/examples/docs/docs/file.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||
crates/ruff/resources/test/project/examples/docs/docs/file.py:8:5: F841 [*] Local variable `x` is assigned to but never used
|
||||
crates/ruff/resources/test/project/project/file.py:1:8: F401 [*] `os` imported but unused
|
||||
crates/ruff/resources/test/project/project/import_file.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||
crates/ruff/resources/test/project/examples/.dotfiles/script.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
crates/ruff/resources/test/project/examples/.dotfiles/script.py:1:8: F401 `numpy` imported but unused
|
||||
crates/ruff/resources/test/project/examples/.dotfiles/script.py:2:17: F401 `app.app_file` imported but unused
|
||||
crates/ruff/resources/test/project/examples/docs/docs/file.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
crates/ruff/resources/test/project/examples/docs/docs/file.py:8:5: F841 Local variable `x` is assigned to but never used
|
||||
crates/ruff/resources/test/project/project/file.py:1:8: F401 `os` imported but unused
|
||||
crates/ruff/resources/test/project/project/import_file.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
Found 7 errors.
|
||||
[*] 7 potentially fixable with the --fix option.
|
||||
7 potentially fixable with the --fix option.
|
||||
```
|
||||
|
||||
Running from the project directory itself should exhibit the same behavior:
|
||||
|
||||
```console
|
||||
∴ (cd crates/ruff/resources/test/project/ && cargo run -p ruff_cli -- check .)
|
||||
examples/.dotfiles/script.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||
examples/.dotfiles/script.py:1:8: F401 [*] `numpy` imported but unused
|
||||
examples/.dotfiles/script.py:2:17: F401 [*] `app.app_file` imported but unused
|
||||
examples/docs/docs/file.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||
examples/docs/docs/file.py:8:5: F841 [*] Local variable `x` is assigned to but never used
|
||||
project/file.py:1:8: F401 [*] `os` imported but unused
|
||||
project/import_file.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||
examples/.dotfiles/script.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
examples/.dotfiles/script.py:1:8: F401 `numpy` imported but unused
|
||||
examples/.dotfiles/script.py:2:17: F401 `app.app_file` imported but unused
|
||||
examples/docs/docs/file.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
examples/docs/docs/file.py:8:5: F841 Local variable `x` is assigned to but never used
|
||||
project/file.py:1:8: F401 `os` imported but unused
|
||||
project/import_file.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
Found 7 errors.
|
||||
[*] 7 potentially fixable with the --fix option.
|
||||
7 potentially fixable with the --fix option.
|
||||
```
|
||||
|
||||
Running from the sub-package directory should exhibit the same behavior, but omit the top-level
|
||||
@@ -40,10 +40,10 @@ files:
|
||||
|
||||
```console
|
||||
∴ (cd crates/ruff/resources/test/project/examples/docs && cargo run -p ruff_cli -- check .)
|
||||
docs/file.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||
docs/file.py:8:5: F841 [*] Local variable `x` is assigned to but never used
|
||||
docs/file.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
docs/file.py:8:5: F841 Local variable `x` is assigned to but never used
|
||||
Found 2 errors.
|
||||
[*] 2 potentially fixable with the --fix option.
|
||||
2 potentially fixable with the --fix option.
|
||||
```
|
||||
|
||||
`--config` should force Ruff to use the specified `pyproject.toml` for all files, and resolve
|
||||
@@ -51,17 +51,17 @@ file paths from the current working directory:
|
||||
|
||||
```console
|
||||
∴ (cargo run -p ruff_cli -- check --config=crates/ruff/resources/test/project/pyproject.toml crates/ruff/resources/test/project/)
|
||||
crates/ruff/resources/test/project/examples/.dotfiles/script.py:1:8: F401 [*] `numpy` imported but unused
|
||||
crates/ruff/resources/test/project/examples/.dotfiles/script.py:2:17: F401 [*] `app.app_file` imported but unused
|
||||
crates/ruff/resources/test/project/examples/docs/docs/concepts/file.py:1:8: F401 [*] `os` imported but unused
|
||||
crates/ruff/resources/test/project/examples/docs/docs/file.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||
crates/ruff/resources/test/project/examples/docs/docs/file.py:1:8: F401 [*] `os` imported but unused
|
||||
crates/ruff/resources/test/project/examples/docs/docs/file.py:3:8: F401 [*] `numpy` imported but unused
|
||||
crates/ruff/resources/test/project/examples/docs/docs/file.py:4:27: F401 [*] `docs.concepts.file` imported but unused
|
||||
crates/ruff/resources/test/project/examples/excluded/script.py:1:8: F401 [*] `os` imported but unused
|
||||
crates/ruff/resources/test/project/project/file.py:1:8: F401 [*] `os` imported but unused
|
||||
crates/ruff/resources/test/project/examples/.dotfiles/script.py:1:8: F401 `numpy` imported but unused
|
||||
crates/ruff/resources/test/project/examples/.dotfiles/script.py:2:17: F401 `app.app_file` imported but unused
|
||||
crates/ruff/resources/test/project/examples/docs/docs/concepts/file.py:1:8: F401 `os` imported but unused
|
||||
crates/ruff/resources/test/project/examples/docs/docs/file.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
crates/ruff/resources/test/project/examples/docs/docs/file.py:1:8: F401 `os` imported but unused
|
||||
crates/ruff/resources/test/project/examples/docs/docs/file.py:3:8: F401 `numpy` imported but unused
|
||||
crates/ruff/resources/test/project/examples/docs/docs/file.py:4:27: F401 `docs.concepts.file` imported but unused
|
||||
crates/ruff/resources/test/project/examples/excluded/script.py:1:8: F401 `os` imported but unused
|
||||
crates/ruff/resources/test/project/project/file.py:1:8: F401 `os` imported but unused
|
||||
Found 9 errors.
|
||||
[*] 9 potentially fixable with the --fix option.
|
||||
9 potentially fixable with the --fix option.
|
||||
```
|
||||
|
||||
Running from a parent directory should "ignore" the `exclude` (hence, `concepts/file.py` gets
|
||||
@@ -69,21 +69,21 @@ included in the output):
|
||||
|
||||
```console
|
||||
∴ (cd crates/ruff/resources/test/project/examples && cargo run -p ruff_cli -- check --config=docs/ruff.toml .)
|
||||
docs/docs/concepts/file.py:5:5: F841 [*] Local variable `x` is assigned to but never used
|
||||
docs/docs/file.py:1:1: I001 [*] Import block is un-sorted or un-formatted
|
||||
docs/docs/file.py:8:5: F841 [*] Local variable `x` is assigned to but never used
|
||||
excluded/script.py:5:5: F841 [*] Local variable `x` is assigned to but never used
|
||||
docs/docs/concepts/file.py:5:5: F841 Local variable `x` is assigned to but never used
|
||||
docs/docs/file.py:1:1: I001 Import block is un-sorted or un-formatted
|
||||
docs/docs/file.py:8:5: F841 Local variable `x` is assigned to but never used
|
||||
excluded/script.py:5:5: F841 Local variable `x` is assigned to but never used
|
||||
Found 4 errors.
|
||||
[*] 4 potentially fixable with the --fix option.
|
||||
4 potentially fixable with the --fix option.
|
||||
```
|
||||
|
||||
Passing an excluded directory directly should report errors in the contained files:
|
||||
|
||||
```console
|
||||
∴ cargo run -p ruff_cli -- check crates/ruff/resources/test/project/examples/excluded/
|
||||
crates/ruff/resources/test/project/examples/excluded/script.py:1:8: F401 [*] `os` imported but unused
|
||||
crates/ruff/resources/test/project/examples/excluded/script.py:1:8: F401 `os` imported but unused
|
||||
Found 1 error.
|
||||
[*] 1 potentially fixable with the --fix option.
|
||||
1 potentially fixable with the --fix option.
|
||||
```
|
||||
|
||||
Unless we `--force-exclude`:
|
||||
|
||||
@@ -6,7 +6,7 @@ use libcst_native::{
|
||||
use rustpython_parser::ast::{ExcepthandlerKind, Expr, Keyword, Location, Stmt, StmtKind};
|
||||
use rustpython_parser::{lexer, Mode, Tok};
|
||||
|
||||
use ruff_diagnostics::Edit;
|
||||
use ruff_diagnostics::Fix;
|
||||
use ruff_python_ast::helpers;
|
||||
use ruff_python_ast::helpers::to_absolute;
|
||||
use ruff_python_ast::newlines::NewlineWithTrailingNewline;
|
||||
@@ -178,7 +178,7 @@ pub fn delete_stmt(
|
||||
locator: &Locator,
|
||||
indexer: &Indexer,
|
||||
stylist: &Stylist,
|
||||
) -> Result<Edit> {
|
||||
) -> Result<Fix> {
|
||||
if parent
|
||||
.map(|parent| is_lone_child(stmt, parent, deleted))
|
||||
.map_or(Ok(None), |v| v.map(Some))?
|
||||
@@ -186,7 +186,7 @@ pub fn delete_stmt(
|
||||
{
|
||||
// If removing this node would lead to an invalid syntax tree, replace
|
||||
// it with a `pass`.
|
||||
Ok(Edit::replacement(
|
||||
Ok(Fix::replacement(
|
||||
"pass".to_string(),
|
||||
stmt.location,
|
||||
stmt.end_location.unwrap(),
|
||||
@@ -194,22 +194,22 @@ pub fn delete_stmt(
|
||||
} else {
|
||||
Ok(if let Some(semicolon) = trailing_semicolon(stmt, locator) {
|
||||
let next = next_stmt_break(semicolon, locator);
|
||||
Edit::deletion(stmt.location, next)
|
||||
Fix::deletion(stmt.location, next)
|
||||
} else if helpers::match_leading_content(stmt, locator) {
|
||||
Edit::deletion(stmt.location, stmt.end_location.unwrap())
|
||||
Fix::deletion(stmt.location, stmt.end_location.unwrap())
|
||||
} else if helpers::preceded_by_continuation(stmt, indexer) {
|
||||
if is_end_of_file(stmt, locator) && stmt.location.column() == 0 {
|
||||
// Special-case: a file can't end in a continuation.
|
||||
Edit::replacement(
|
||||
Fix::replacement(
|
||||
stylist.line_ending().to_string(),
|
||||
stmt.location,
|
||||
stmt.end_location.unwrap(),
|
||||
)
|
||||
} else {
|
||||
Edit::deletion(stmt.location, stmt.end_location.unwrap())
|
||||
Fix::deletion(stmt.location, stmt.end_location.unwrap())
|
||||
}
|
||||
} else {
|
||||
Edit::deletion(
|
||||
Fix::deletion(
|
||||
Location::new(stmt.location.row(), 0),
|
||||
Location::new(stmt.end_location.unwrap().row() + 1, 0),
|
||||
)
|
||||
@@ -226,7 +226,7 @@ pub fn remove_unused_imports<'a>(
|
||||
locator: &Locator,
|
||||
indexer: &Indexer,
|
||||
stylist: &Stylist,
|
||||
) -> Result<Edit> {
|
||||
) -> Result<Fix> {
|
||||
let module_text = locator.slice(stmt);
|
||||
let mut tree = match_module(module_text)?;
|
||||
|
||||
@@ -327,13 +327,13 @@ pub fn remove_unused_imports<'a>(
|
||||
delete_stmt(stmt, parent, deleted, locator, indexer, stylist)
|
||||
} else {
|
||||
let mut state = CodegenState {
|
||||
default_newline: &stylist.line_ending(),
|
||||
default_newline: stylist.line_ending(),
|
||||
default_indent: stylist.indentation(),
|
||||
..CodegenState::default()
|
||||
};
|
||||
tree.codegen(&mut state);
|
||||
|
||||
Ok(Edit::replacement(
|
||||
Ok(Fix::replacement(
|
||||
state.to_string(),
|
||||
stmt.location,
|
||||
stmt.end_location.unwrap(),
|
||||
@@ -355,7 +355,7 @@ pub fn remove_argument(
|
||||
args: &[Expr],
|
||||
keywords: &[Keyword],
|
||||
remove_parentheses: bool,
|
||||
) -> Result<Edit> {
|
||||
) -> Result<Fix> {
|
||||
// TODO(sbrugman): Preserve trailing comments.
|
||||
let contents = locator.skip(stmt_at);
|
||||
|
||||
@@ -437,7 +437,7 @@ pub fn remove_argument(
|
||||
}
|
||||
|
||||
match (fix_start, fix_end) {
|
||||
(Some(start), Some(end)) => Ok(Edit::deletion(start, end)),
|
||||
(Some(start), Some(end)) => Ok(Fix::deletion(start, end)),
|
||||
_ => {
|
||||
bail!("No fix could be constructed")
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ use itertools::Itertools;
|
||||
use rustc_hash::FxHashMap;
|
||||
use rustpython_parser::ast::Location;
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Edit, Fix};
|
||||
use ruff_diagnostics::{Diagnostic, Fix};
|
||||
use ruff_python_ast::source_code::Locator;
|
||||
use ruff_python_ast::types::Range;
|
||||
|
||||
@@ -15,7 +15,7 @@ pub mod helpers;
|
||||
|
||||
/// Auto-fix errors in a file, and write the fixed source code to disk.
|
||||
pub fn fix_file(diagnostics: &[Diagnostic], locator: &Locator) -> Option<(String, FixTable)> {
|
||||
if diagnostics.iter().all(|check| check.fix.is_empty()) {
|
||||
if diagnostics.iter().all(|check| check.fix.is_none()) {
|
||||
None
|
||||
} else {
|
||||
Some(apply_fixes(diagnostics.iter(), locator))
|
||||
@@ -28,61 +28,54 @@ fn apply_fixes<'a>(
|
||||
locator: &'a Locator<'a>,
|
||||
) -> (String, FixTable) {
|
||||
let mut output = String::with_capacity(locator.len());
|
||||
let mut last_pos: Option<Location> = None;
|
||||
let mut applied: BTreeSet<&Edit> = BTreeSet::default();
|
||||
let mut last_pos: Location = Location::new(1, 0);
|
||||
let mut applied: BTreeSet<&Fix> = BTreeSet::default();
|
||||
let mut fixed = FxHashMap::default();
|
||||
|
||||
for (rule, fix) in diagnostics
|
||||
.filter_map(|diagnostic| {
|
||||
if diagnostic.fix.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some((diagnostic.kind.rule(), &diagnostic.fix))
|
||||
}
|
||||
diagnostic
|
||||
.fix
|
||||
.as_ref()
|
||||
.map(|fix| (diagnostic.kind.rule(), fix))
|
||||
})
|
||||
.sorted_by(|(rule1, fix1), (rule2, fix2)| cmp_fix(*rule1, *rule2, fix1, fix2))
|
||||
{
|
||||
// If we already applied an identical fix as part of another correction, skip
|
||||
// any re-application.
|
||||
if fix.edits().iter().all(|edit| applied.contains(edit)) {
|
||||
if applied.contains(&fix) {
|
||||
*fixed.entry(rule).or_default() += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Best-effort approach: if this fix overlaps with a fix we've already applied,
|
||||
// skip it.
|
||||
if last_pos.map_or(false, |last_pos| {
|
||||
fix.location()
|
||||
.map_or(false, |fix_location| last_pos >= fix_location)
|
||||
}) {
|
||||
if last_pos > fix.location {
|
||||
continue;
|
||||
}
|
||||
|
||||
for edit in fix.edits() {
|
||||
// Add all contents from `last_pos` to `fix.location`.
|
||||
let slice = locator.slice(Range::new(last_pos.unwrap_or_default(), edit.location));
|
||||
output.push_str(slice);
|
||||
// Add all contents from `last_pos` to `fix.location`.
|
||||
let slice = locator.slice(Range::new(last_pos, fix.location));
|
||||
output.push_str(slice);
|
||||
|
||||
// Add the patch itself.
|
||||
output.push_str(&edit.content);
|
||||
|
||||
// Track that the edit was applied.
|
||||
last_pos = Some(edit.end_location);
|
||||
applied.insert(edit);
|
||||
}
|
||||
// Add the patch itself.
|
||||
output.push_str(&fix.content);
|
||||
|
||||
// Track that the fix was applied.
|
||||
last_pos = fix.end_location;
|
||||
applied.insert(fix);
|
||||
*fixed.entry(rule).or_default() += 1;
|
||||
}
|
||||
|
||||
// Add the remaining content.
|
||||
let slice = locator.skip(last_pos.unwrap_or_default());
|
||||
let slice = locator.skip(last_pos);
|
||||
output.push_str(slice);
|
||||
|
||||
(output, fixed)
|
||||
}
|
||||
|
||||
/// Apply a single fix.
|
||||
pub(crate) fn apply_fix(fix: &Edit, locator: &Locator) -> String {
|
||||
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`.
|
||||
@@ -101,8 +94,8 @@ pub(crate) fn apply_fix(fix: &Edit, locator: &Locator) -> String {
|
||||
|
||||
/// Compare two fixes.
|
||||
fn cmp_fix(rule1: Rule, rule2: Rule, fix1: &Fix, fix2: &Fix) -> std::cmp::Ordering {
|
||||
fix1.location()
|
||||
.cmp(&fix2.location())
|
||||
fix1.location
|
||||
.cmp(&fix2.location)
|
||||
.then_with(|| match (&rule1, &rule2) {
|
||||
// Apply `EndsInPeriod` fixes before `NewLineAfterLastParagraph` fixes.
|
||||
(Rule::EndsInPeriod, Rule::NewLineAfterLastParagraph) => std::cmp::Ordering::Less,
|
||||
@@ -116,20 +109,21 @@ mod tests {
|
||||
use rustpython_parser::ast::Location;
|
||||
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
use ruff_diagnostics::Edit;
|
||||
use ruff_diagnostics::Fix;
|
||||
use ruff_python_ast::source_code::Locator;
|
||||
|
||||
use crate::autofix::{apply_fix, apply_fixes};
|
||||
use crate::rules::pycodestyle::rules::MissingNewlineAtEndOfFile;
|
||||
use crate::rules::pycodestyle::rules::NoNewLineAtEndOfFile;
|
||||
|
||||
fn create_diagnostics(edit: impl IntoIterator<Item = Edit>) -> Vec<Diagnostic> {
|
||||
edit.into_iter()
|
||||
.map(|edit| Diagnostic {
|
||||
fn create_diagnostics(fixes: impl IntoIterator<Item = Fix>) -> Vec<Diagnostic> {
|
||||
fixes
|
||||
.into_iter()
|
||||
.map(|fix| Diagnostic {
|
||||
// The choice of rule here is arbitrary.
|
||||
kind: MissingNewlineAtEndOfFile.into(),
|
||||
location: edit.location,
|
||||
end_location: edit.end_location,
|
||||
fix: edit.into(),
|
||||
kind: NoNewLineAtEndOfFile.into(),
|
||||
location: fix.location,
|
||||
end_location: fix.end_location,
|
||||
fix: Some(fix),
|
||||
parent: None,
|
||||
})
|
||||
.collect()
|
||||
@@ -153,7 +147,7 @@ class A(object):
|
||||
"#
|
||||
.trim(),
|
||||
);
|
||||
let diagnostics = create_diagnostics([Edit {
|
||||
let diagnostics = create_diagnostics([Fix {
|
||||
content: "Bar".to_string(),
|
||||
location: Location::new(1, 8),
|
||||
end_location: Location::new(1, 14),
|
||||
@@ -179,7 +173,7 @@ class A(object):
|
||||
"#
|
||||
.trim(),
|
||||
);
|
||||
let diagnostics = create_diagnostics([Edit {
|
||||
let diagnostics = create_diagnostics([Fix {
|
||||
content: String::new(),
|
||||
location: Location::new(1, 7),
|
||||
end_location: Location::new(1, 15),
|
||||
@@ -200,21 +194,21 @@ class A:
|
||||
fn apply_two_removals() {
|
||||
let locator = Locator::new(
|
||||
r#"
|
||||
class A(object, object, object):
|
||||
class A(object, object):
|
||||
...
|
||||
"#
|
||||
.trim(),
|
||||
);
|
||||
let diagnostics = create_diagnostics([
|
||||
Edit {
|
||||
Fix {
|
||||
content: String::new(),
|
||||
location: Location::new(1, 8),
|
||||
location: Location::new(1, 7),
|
||||
end_location: Location::new(1, 16),
|
||||
},
|
||||
Edit {
|
||||
Fix {
|
||||
content: String::new(),
|
||||
location: Location::new(1, 22),
|
||||
end_location: Location::new(1, 30),
|
||||
location: Location::new(1, 16),
|
||||
end_location: Location::new(1, 23),
|
||||
},
|
||||
]);
|
||||
let (contents, fixed) = apply_fixes(diagnostics.iter(), &locator);
|
||||
@@ -222,7 +216,7 @@ class A(object, object, object):
|
||||
assert_eq!(
|
||||
contents,
|
||||
r#"
|
||||
class A(object):
|
||||
class A:
|
||||
...
|
||||
"#
|
||||
.trim()
|
||||
@@ -240,12 +234,12 @@ class A(object):
|
||||
.trim(),
|
||||
);
|
||||
let diagnostics = create_diagnostics([
|
||||
Edit {
|
||||
Fix {
|
||||
content: String::new(),
|
||||
location: Location::new(1, 7),
|
||||
end_location: Location::new(1, 15),
|
||||
},
|
||||
Edit {
|
||||
Fix {
|
||||
content: "ignored".to_string(),
|
||||
location: Location::new(1, 9),
|
||||
end_location: Location::new(1, 11),
|
||||
@@ -273,7 +267,7 @@ class A(object):
|
||||
.trim(),
|
||||
);
|
||||
let contents = apply_fix(
|
||||
&Edit {
|
||||
&Fix {
|
||||
content: String::new(),
|
||||
location: Location::new(1, 7),
|
||||
end_location: Location::new(1, 15),
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -29,7 +29,9 @@ pub fn check_imports(
|
||||
// Extract all imports from the AST.
|
||||
let tracker = {
|
||||
let mut tracker = ImportTracker::new(locator, directives, path);
|
||||
tracker.visit_body(python_ast);
|
||||
for stmt in python_ast {
|
||||
tracker.visit_stmt(stmt);
|
||||
}
|
||||
tracker
|
||||
};
|
||||
let blocks: Vec<&Block> = tracker.iter().collect();
|
||||
|
||||
@@ -1,32 +1,42 @@
|
||||
#![allow(dead_code, unused_imports, unused_variables)]
|
||||
|
||||
use bisection::bisect_left;
|
||||
use itertools::Itertools;
|
||||
use rustpython_parser::ast::Location;
|
||||
use rustpython_parser::lexer::LexResult;
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Fix};
|
||||
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::rules::pycodestyle::rules::logical_lines::{
|
||||
use crate::rules::pycodestyle::logical_lines::{iter_logical_lines, TokenFlags};
|
||||
use crate::rules::pycodestyle::rules::{
|
||||
extraneous_whitespace, indentation, missing_whitespace, missing_whitespace_after_keyword,
|
||||
missing_whitespace_around_operator, space_around_operator, whitespace_around_keywords,
|
||||
whitespace_around_named_parameter_equals, whitespace_before_comment,
|
||||
whitespace_before_parameters, LogicalLines, TokenFlags,
|
||||
whitespace_before_parameters,
|
||||
};
|
||||
use crate::settings::{flags, Settings};
|
||||
|
||||
/// Return the amount of indentation, expanding tabs to the next multiple of 8.
|
||||
fn expand_indent(line: &str) -> usize {
|
||||
let line = line.trim_end_matches(['\n', '\r']);
|
||||
|
||||
fn expand_indent(mut line: &str) -> usize {
|
||||
while line.ends_with("\n\r") {
|
||||
line = &line[..line.len() - 2];
|
||||
}
|
||||
if !line.contains('\t') {
|
||||
return line.len() - line.trim_start().len();
|
||||
}
|
||||
let mut indent = 0;
|
||||
for c in line.bytes() {
|
||||
match c {
|
||||
b'\t' => indent = (indent / 8) * 8 + 8,
|
||||
b' ' => indent += 1,
|
||||
_ => break,
|
||||
for c in line.chars() {
|
||||
if c == '\t' {
|
||||
indent = (indent / 8) * 8 + 8;
|
||||
} else if c == ' ' {
|
||||
indent += 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
indent
|
||||
}
|
||||
|
||||
@@ -39,140 +49,151 @@ pub fn check_logical_lines(
|
||||
) -> Vec<Diagnostic> {
|
||||
let mut diagnostics = vec![];
|
||||
|
||||
#[cfg(feature = "logical_lines")]
|
||||
let should_fix_missing_whitespace =
|
||||
autofix.into() && settings.rules.should_fix(Rule::MissingWhitespace);
|
||||
|
||||
#[cfg(not(feature = "logical_lines"))]
|
||||
let should_fix_missing_whitespace = false;
|
||||
|
||||
#[cfg(feature = "logical_lines")]
|
||||
let should_fix_whitespace_before_parameters =
|
||||
autofix.into() && settings.rules.should_fix(Rule::WhitespaceBeforeParameters);
|
||||
|
||||
#[cfg(not(feature = "logical_lines"))]
|
||||
let should_fix_whitespace_before_parameters = false;
|
||||
|
||||
let indent_char = stylist.indentation().as_char();
|
||||
let mut prev_line = None;
|
||||
let mut prev_indent_level = None;
|
||||
let indent_char = stylist.indentation().as_char();
|
||||
for line in iter_logical_lines(tokens, locator) {
|
||||
if line.mapping.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
for line in &LogicalLines::from_tokens(tokens, locator) {
|
||||
if line.flags().contains(TokenFlags::OPERATOR) {
|
||||
for (location, kind) in space_around_operator(&line) {
|
||||
// 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 indent_level = expand_indent(start_line);
|
||||
let indent_size = 4;
|
||||
|
||||
// Generate mapping from logical to physical offsets.
|
||||
let mapping_offsets = line.mapping.iter().map(|(offset, _)| *offset).collect_vec();
|
||||
|
||||
if line.flags.contains(TokenFlags::OPERATOR) {
|
||||
for (index, kind) in space_around_operator(&line.text) {
|
||||
let (token_offset, pos) = line.mapping[bisect_left(&mapping_offsets, &index)];
|
||||
let location = Location::new(pos.row(), pos.column() + index - token_offset);
|
||||
if settings.rules.enabled(kind.rule()) {
|
||||
diagnostics.push(Diagnostic {
|
||||
kind,
|
||||
location,
|
||||
end_location: location,
|
||||
fix: Fix::empty(),
|
||||
fix: None,
|
||||
parent: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for (location, kind) in whitespace_around_named_parameter_equals(&line.tokens()) {
|
||||
if settings.rules.enabled(kind.rule()) {
|
||||
diagnostics.push(Diagnostic {
|
||||
kind,
|
||||
location,
|
||||
end_location: location,
|
||||
fix: Fix::empty(),
|
||||
parent: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
for (location, kind) in missing_whitespace_around_operator(&line.tokens()) {
|
||||
if settings.rules.enabled(kind.rule()) {
|
||||
diagnostics.push(Diagnostic {
|
||||
kind,
|
||||
location,
|
||||
end_location: location,
|
||||
fix: Fix::empty(),
|
||||
parent: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for diagnostic in missing_whitespace(&line, should_fix_missing_whitespace) {
|
||||
if settings.rules.enabled(diagnostic.kind.rule()) {
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
}
|
||||
if line
|
||||
.flags()
|
||||
.flags
|
||||
.contains(TokenFlags::OPERATOR | TokenFlags::PUNCTUATION)
|
||||
{
|
||||
for (location, kind) in extraneous_whitespace(&line) {
|
||||
for (index, kind) in extraneous_whitespace(&line.text) {
|
||||
let (token_offset, pos) = line.mapping[bisect_left(&mapping_offsets, &index)];
|
||||
let location = Location::new(pos.row(), pos.column() + index - token_offset);
|
||||
if settings.rules.enabled(kind.rule()) {
|
||||
diagnostics.push(Diagnostic {
|
||||
kind,
|
||||
location,
|
||||
end_location: location,
|
||||
fix: Fix::empty(),
|
||||
fix: None,
|
||||
parent: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
if line.flags().contains(TokenFlags::KEYWORD) {
|
||||
for (location, kind) in whitespace_around_keywords(&line) {
|
||||
if line.flags.contains(TokenFlags::KEYWORD) {
|
||||
for (index, kind) in whitespace_around_keywords(&line.text) {
|
||||
let (token_offset, pos) = line.mapping[bisect_left(&mapping_offsets, &index)];
|
||||
let location = Location::new(pos.row(), pos.column() + index - token_offset);
|
||||
if settings.rules.enabled(kind.rule()) {
|
||||
diagnostics.push(Diagnostic {
|
||||
kind,
|
||||
location,
|
||||
end_location: location,
|
||||
fix: Fix::empty(),
|
||||
fix: None,
|
||||
parent: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for (location, kind) in missing_whitespace_after_keyword(&line.tokens()) {
|
||||
for (location, kind) in missing_whitespace_after_keyword(&line.tokens) {
|
||||
if settings.rules.enabled(kind.rule()) {
|
||||
diagnostics.push(Diagnostic {
|
||||
kind,
|
||||
location,
|
||||
end_location: location,
|
||||
fix: Fix::empty(),
|
||||
fix: None,
|
||||
parent: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
if line.flags().contains(TokenFlags::COMMENT) {
|
||||
for (range, kind) in whitespace_before_comment(&line.tokens(), locator) {
|
||||
if line.flags.contains(TokenFlags::COMMENT) {
|
||||
for (range, kind) in whitespace_before_comment(&line.tokens, locator) {
|
||||
if settings.rules.enabled(kind.rule()) {
|
||||
diagnostics.push(Diagnostic {
|
||||
kind,
|
||||
location: range.location,
|
||||
end_location: range.end_location,
|
||||
fix: Fix::empty(),
|
||||
fix: None,
|
||||
parent: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
if line.flags.contains(TokenFlags::OPERATOR) {
|
||||
for (location, kind) in
|
||||
whitespace_around_named_parameter_equals(&line.tokens, &line.text)
|
||||
{
|
||||
if settings.rules.enabled(kind.rule()) {
|
||||
diagnostics.push(Diagnostic {
|
||||
kind,
|
||||
location,
|
||||
end_location: location,
|
||||
fix: None,
|
||||
parent: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
for (location, kind) in missing_whitespace_around_operator(&line.tokens) {
|
||||
if settings.rules.enabled(kind.rule()) {
|
||||
diagnostics.push(Diagnostic {
|
||||
kind,
|
||||
location,
|
||||
end_location: location,
|
||||
fix: None,
|
||||
parent: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if line.flags().contains(TokenFlags::BRACKET) {
|
||||
for diagnostic in whitespace_before_parameters(
|
||||
&line.tokens(),
|
||||
should_fix_whitespace_before_parameters,
|
||||
) {
|
||||
#[cfg(feature = "logical_lines")]
|
||||
let should_fix = autofix.into() && settings.rules.should_fix(Rule::MissingWhitespace);
|
||||
|
||||
#[cfg(not(feature = "logical_lines"))]
|
||||
let should_fix = false;
|
||||
|
||||
for diagnostic in missing_whitespace(&line.text, start_loc.row(), should_fix) {
|
||||
if settings.rules.enabled(diagnostic.kind.rule()) {
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Extract the indentation level.
|
||||
let Some(start_loc) = line.first_token_location() else { continue; };
|
||||
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;
|
||||
if line.flags.contains(TokenFlags::BRACKET) {
|
||||
#[cfg(feature = "logical_lines")]
|
||||
let should_fix =
|
||||
autofix.into() && settings.rules.should_fix(Rule::WhitespaceBeforeParameters);
|
||||
|
||||
for (location, kind) in indentation(
|
||||
#[cfg(not(feature = "logical_lines"))]
|
||||
let should_fix = false;
|
||||
|
||||
for diagnostic in whitespace_before_parameters(&line.tokens, should_fix) {
|
||||
if settings.rules.enabled(diagnostic.kind.rule()) {
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (index, kind) in indentation(
|
||||
&line,
|
||||
prev_line.as_ref(),
|
||||
indent_char,
|
||||
@@ -180,18 +201,20 @@ pub fn check_logical_lines(
|
||||
prev_indent_level,
|
||||
indent_size,
|
||||
) {
|
||||
let (token_offset, pos) = line.mapping[bisect_left(&mapping_offsets, &index)];
|
||||
let location = Location::new(pos.row(), pos.column() + index - token_offset);
|
||||
if settings.rules.enabled(kind.rule()) {
|
||||
diagnostics.push(Diagnostic {
|
||||
kind,
|
||||
location,
|
||||
end_location: location,
|
||||
fix: Fix::empty(),
|
||||
fix: None,
|
||||
parent: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if !line.is_comment_only() {
|
||||
if !line.is_comment() {
|
||||
prev_line = Some(line);
|
||||
prev_indent_level = Some(indent_level);
|
||||
}
|
||||
@@ -204,9 +227,10 @@ mod tests {
|
||||
use rustpython_parser::lexer::LexResult;
|
||||
use rustpython_parser::{lexer, Mode};
|
||||
|
||||
use crate::rules::pycodestyle::rules::logical_lines::LogicalLines;
|
||||
use ruff_python_ast::source_code::Locator;
|
||||
|
||||
use crate::checkers::logical_lines::iter_logical_lines;
|
||||
|
||||
#[test]
|
||||
fn split_logical_lines() {
|
||||
let contents = r#"
|
||||
@@ -215,9 +239,9 @@ y = 2
|
||||
z = x + 1"#;
|
||||
let lxr: Vec<LexResult> = lexer::lex(contents, Mode::Module).collect();
|
||||
let locator = Locator::new(contents);
|
||||
let actual: Vec<String> = LogicalLines::from_tokens(&lxr, &locator)
|
||||
let actual: Vec<String> = iter_logical_lines(&lxr, &locator)
|
||||
.into_iter()
|
||||
.map(|line| line.text_trimmed().to_string())
|
||||
.map(|line| line.text)
|
||||
.collect();
|
||||
let expected = vec![
|
||||
"x = 1".to_string(),
|
||||
@@ -236,12 +260,12 @@ y = 2
|
||||
z = x + 1"#;
|
||||
let lxr: Vec<LexResult> = lexer::lex(contents, Mode::Module).collect();
|
||||
let locator = Locator::new(contents);
|
||||
let actual: Vec<String> = LogicalLines::from_tokens(&lxr, &locator)
|
||||
let actual: Vec<String> = iter_logical_lines(&lxr, &locator)
|
||||
.into_iter()
|
||||
.map(|line| line.text_trimmed().to_string())
|
||||
.map(|line| line.text)
|
||||
.collect();
|
||||
let expected = vec![
|
||||
"x = [\n 1,\n 2,\n 3,\n]".to_string(),
|
||||
"x = [1, 2, 3, ]".to_string(),
|
||||
"y = 2".to_string(),
|
||||
"z = x + 1".to_string(),
|
||||
];
|
||||
@@ -250,11 +274,11 @@ z = x + 1"#;
|
||||
let contents = "x = 'abc'";
|
||||
let lxr: Vec<LexResult> = lexer::lex(contents, Mode::Module).collect();
|
||||
let locator = Locator::new(contents);
|
||||
let actual: Vec<String> = LogicalLines::from_tokens(&lxr, &locator)
|
||||
let actual: Vec<String> = iter_logical_lines(&lxr, &locator)
|
||||
.into_iter()
|
||||
.map(|line| line.text_trimmed().to_string())
|
||||
.map(|line| line.text)
|
||||
.collect();
|
||||
let expected = vec!["x = 'abc'".to_string()];
|
||||
let expected = vec!["x = \"xxx\"".to_string()];
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
let contents = r#"
|
||||
@@ -263,9 +287,9 @@ def f():
|
||||
f()"#;
|
||||
let lxr: Vec<LexResult> = lexer::lex(contents, Mode::Module).collect();
|
||||
let locator = Locator::new(contents);
|
||||
let actual: Vec<String> = LogicalLines::from_tokens(&lxr, &locator)
|
||||
let actual: Vec<String> = iter_logical_lines(&lxr, &locator)
|
||||
.into_iter()
|
||||
.map(|line| line.text_trimmed().to_string())
|
||||
.map(|line| line.text)
|
||||
.collect();
|
||||
let expected = vec!["def f():", "x = 1", "f()"];
|
||||
assert_eq!(actual, expected);
|
||||
@@ -278,17 +302,11 @@ def f():
|
||||
f()"#;
|
||||
let lxr: Vec<LexResult> = lexer::lex(contents, Mode::Module).collect();
|
||||
let locator = Locator::new(contents);
|
||||
let actual: Vec<String> = LogicalLines::from_tokens(&lxr, &locator)
|
||||
let actual: Vec<String> = iter_logical_lines(&lxr, &locator)
|
||||
.into_iter()
|
||||
.map(|line| line.text_trimmed().to_string())
|
||||
.map(|line| line.text)
|
||||
.collect();
|
||||
let expected = vec![
|
||||
"def f():",
|
||||
"\"\"\"Docstring goes here.\"\"\"",
|
||||
"",
|
||||
"x = 1",
|
||||
"f()",
|
||||
];
|
||||
let expected = vec!["def f():", "\"xxxxxxxxxxxxxxxxxxxx\"", "", "x = 1", "f()"];
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
pub mod ast;
|
||||
pub mod filesystem;
|
||||
pub mod imports;
|
||||
#[cfg(feature = "logical_lines")]
|
||||
pub(crate) mod logical_lines;
|
||||
pub mod logical_lines;
|
||||
pub mod noqa;
|
||||
pub mod physical_lines;
|
||||
pub mod tokens;
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
//! `NoQA` enforcement and validation.
|
||||
|
||||
use log::warn;
|
||||
use nohash_hasher::IntMap;
|
||||
use rustpython_parser::ast::Location;
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Edit};
|
||||
use ruff_diagnostics::{Diagnostic, Fix};
|
||||
use ruff_python_ast::newlines::StrExt;
|
||||
use ruff_python_ast::types::Range;
|
||||
|
||||
use crate::codes::NoqaCode;
|
||||
use crate::noqa;
|
||||
use crate::noqa::{Directive, FileExemption};
|
||||
use crate::noqa::{extract_file_exemption, Directive, Exemption};
|
||||
use crate::registry::{AsRule, Rule};
|
||||
use crate::rule_redirects::get_redirect_target;
|
||||
use crate::rules::ruff::rules::{UnusedCodes, UnusedNOQA};
|
||||
@@ -25,79 +26,92 @@ pub fn check_noqa(
|
||||
) -> Vec<usize> {
|
||||
let enforce_noqa = settings.rules.enabled(Rule::UnusedNOQA);
|
||||
|
||||
let lines: Vec<&str> = contents.universal_newlines().collect();
|
||||
// Whether the file is exempted from all checks.
|
||||
let mut file_exempted = false;
|
||||
|
||||
// Identify any codes that are globally exempted (within the current file).
|
||||
let exemption = noqa::file_exemption(&lines, commented_lines);
|
||||
// Codes that are globally exempted (within the current file).
|
||||
let mut file_exemptions: Vec<NoqaCode> = vec![];
|
||||
|
||||
// Map from line number to `noqa` directive on that line, along with any codes
|
||||
// that were matched by the directive.
|
||||
let mut noqa_directives: IntMap<usize, (Directive, Vec<NoqaCode>)> = IntMap::default();
|
||||
|
||||
// Extract all `noqa` directives.
|
||||
if enforce_noqa {
|
||||
for lineno in commented_lines {
|
||||
// Indices of diagnostics that were ignored by a `noqa` directive.
|
||||
let mut ignored_diagnostics = vec![];
|
||||
|
||||
let lines: Vec<&str> = contents.universal_newlines().collect();
|
||||
for lineno in commented_lines {
|
||||
match extract_file_exemption(lines[lineno - 1]) {
|
||||
Exemption::All => {
|
||||
file_exempted = true;
|
||||
}
|
||||
Exemption::Codes(codes) => {
|
||||
file_exemptions.extend(codes.into_iter().filter_map(|code| {
|
||||
if let Ok(rule) = Rule::from_code(get_redirect_target(code).unwrap_or(code)) {
|
||||
Some(rule.noqa_code())
|
||||
} else {
|
||||
warn!("Invalid code provided to `# ruff: noqa`: {}", code);
|
||||
None
|
||||
}
|
||||
}));
|
||||
}
|
||||
Exemption::None => {}
|
||||
}
|
||||
|
||||
if enforce_noqa {
|
||||
noqa_directives
|
||||
.entry(lineno - 1)
|
||||
.or_insert_with(|| (noqa::extract_noqa_directive(lines[lineno - 1]), vec![]));
|
||||
}
|
||||
}
|
||||
|
||||
// Indices of diagnostics that were ignored by a `noqa` directive.
|
||||
let mut ignored_diagnostics = vec![];
|
||||
|
||||
// Remove any ignored diagnostics.
|
||||
for (index, diagnostic) in diagnostics.iter().enumerate() {
|
||||
if matches!(diagnostic.kind.rule(), Rule::BlanketNOQA) {
|
||||
continue;
|
||||
}
|
||||
|
||||
match &exemption {
|
||||
FileExemption::All => {
|
||||
// If the file is exempted, ignore all diagnostics.
|
||||
// If the file is exempted, ignore all diagnostics.
|
||||
if file_exempted {
|
||||
ignored_diagnostics.push(index);
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the diagnostic is ignored by a global exemption, ignore it.
|
||||
if !file_exemptions.is_empty() {
|
||||
if file_exemptions.contains(&diagnostic.kind.rule().noqa_code()) {
|
||||
ignored_diagnostics.push(index);
|
||||
continue;
|
||||
}
|
||||
FileExemption::Codes(codes) => {
|
||||
// If the diagnostic is ignored by a global exemption, ignore it.
|
||||
if codes.contains(&diagnostic.kind.rule().noqa_code()) {
|
||||
ignored_diagnostics.push(index);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
FileExemption::None => {}
|
||||
}
|
||||
|
||||
let diagnostic_lineno = diagnostic.location.row();
|
||||
|
||||
// Is the violation ignored by a `noqa` directive on the parent line?
|
||||
if let Some(parent_lineno) = diagnostic.parent.map(|location| location.row()) {
|
||||
if parent_lineno != diagnostic_lineno {
|
||||
let noqa_lineno = noqa_line_for.get(&parent_lineno).unwrap_or(&parent_lineno);
|
||||
if commented_lines.contains(noqa_lineno) {
|
||||
let noqa = noqa_directives.entry(noqa_lineno - 1).or_insert_with(|| {
|
||||
(noqa::extract_noqa_directive(lines[noqa_lineno - 1]), vec![])
|
||||
});
|
||||
match noqa {
|
||||
(Directive::All(..), matches) => {
|
||||
let noqa_lineno = noqa_line_for.get(&parent_lineno).unwrap_or(&parent_lineno);
|
||||
if commented_lines.contains(noqa_lineno) {
|
||||
let noqa = noqa_directives.entry(noqa_lineno - 1).or_insert_with(|| {
|
||||
(noqa::extract_noqa_directive(lines[noqa_lineno - 1]), vec![])
|
||||
});
|
||||
match noqa {
|
||||
(Directive::All(..), matches) => {
|
||||
matches.push(diagnostic.kind.rule().noqa_code());
|
||||
ignored_diagnostics.push(index);
|
||||
continue;
|
||||
}
|
||||
(Directive::Codes(.., codes, _), matches) => {
|
||||
if noqa::includes(diagnostic.kind.rule(), codes) {
|
||||
matches.push(diagnostic.kind.rule().noqa_code());
|
||||
ignored_diagnostics.push(index);
|
||||
continue;
|
||||
}
|
||||
(Directive::Codes(.., codes, _), matches) => {
|
||||
if noqa::includes(diagnostic.kind.rule(), codes) {
|
||||
matches.push(diagnostic.kind.rule().noqa_code());
|
||||
ignored_diagnostics.push(index);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
(Directive::None, ..) => {}
|
||||
}
|
||||
(Directive::None, ..) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Is the diagnostic ignored by a `noqa` directive on the same line?
|
||||
let diagnostic_lineno = diagnostic.location.row();
|
||||
let noqa_lineno = noqa_line_for
|
||||
.get(&diagnostic_lineno)
|
||||
.unwrap_or(&diagnostic_lineno);
|
||||
@@ -129,26 +143,30 @@ pub fn check_noqa(
|
||||
match directive {
|
||||
Directive::All(leading_spaces, start_byte, end_byte, trailing_spaces) => {
|
||||
if matches.is_empty() {
|
||||
let start_char = lines[row][..start_byte].chars().count();
|
||||
let end_char =
|
||||
start_char + lines[row][start_byte..end_byte].chars().count();
|
||||
let start = lines[row][..start_byte].chars().count();
|
||||
let end = start + lines[row][start_byte..end_byte].chars().count();
|
||||
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
UnusedNOQA { codes: None },
|
||||
Range::new(
|
||||
Location::new(row + 1, start_char),
|
||||
Location::new(row + 1, end_char),
|
||||
),
|
||||
Range::new(Location::new(row + 1, start), Location::new(row + 1, end)),
|
||||
);
|
||||
if autofix.into() && settings.rules.should_fix(diagnostic.kind.rule()) {
|
||||
diagnostic.set_fix(delete_noqa(
|
||||
row,
|
||||
lines[row],
|
||||
leading_spaces,
|
||||
start_byte,
|
||||
end_byte,
|
||||
trailing_spaces,
|
||||
));
|
||||
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),
|
||||
));
|
||||
}
|
||||
}
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
@@ -189,9 +207,8 @@ pub fn check_noqa(
|
||||
&& unknown_codes.is_empty()
|
||||
&& unmatched_codes.is_empty())
|
||||
{
|
||||
let start_char = lines[row][..start_byte].chars().count();
|
||||
let end_char =
|
||||
start_char + lines[row][start_byte..end_byte].chars().count();
|
||||
let start = lines[row][..start_byte].chars().count();
|
||||
let end = start + lines[row][start_byte..end_byte].chars().count();
|
||||
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
UnusedNOQA {
|
||||
@@ -210,26 +227,32 @@ pub fn check_noqa(
|
||||
.collect(),
|
||||
}),
|
||||
},
|
||||
Range::new(
|
||||
Location::new(row + 1, start_char),
|
||||
Location::new(row + 1, end_char),
|
||||
),
|
||||
Range::new(Location::new(row + 1, start), Location::new(row + 1, end)),
|
||||
);
|
||||
if autofix.into() && settings.rules.should_fix(diagnostic.kind.rule()) {
|
||||
if valid_codes.is_empty() {
|
||||
diagnostic.set_fix(delete_noqa(
|
||||
row,
|
||||
lines[row],
|
||||
leading_spaces,
|
||||
start_byte,
|
||||
end_byte,
|
||||
trailing_spaces,
|
||||
));
|
||||
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),
|
||||
));
|
||||
}
|
||||
} else {
|
||||
diagnostic.set_fix(Edit::replacement(
|
||||
diagnostic.amend(Fix::replacement(
|
||||
format!("# noqa: {}", valid_codes.join(", ")),
|
||||
Location::new(row + 1, start_char),
|
||||
Location::new(row + 1, end_char),
|
||||
Location::new(row + 1, start),
|
||||
Location::new(row + 1, end),
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -244,42 +267,3 @@ pub fn check_noqa(
|
||||
ignored_diagnostics.sort_unstable();
|
||||
ignored_diagnostics
|
||||
}
|
||||
|
||||
/// Generate a [`Edit`] to delete a `noqa` directive.
|
||||
fn delete_noqa(
|
||||
row: usize,
|
||||
line: &str,
|
||||
leading_spaces: usize,
|
||||
start_byte: usize,
|
||||
end_byte: usize,
|
||||
trailing_spaces: usize,
|
||||
) -> Edit {
|
||||
if start_byte - leading_spaces == 0 && end_byte == line.len() {
|
||||
// Ex) `# noqa`
|
||||
Edit::deletion(Location::new(row + 1, 0), Location::new(row + 2, 0))
|
||||
} else if end_byte == line.len() {
|
||||
// Ex) `x = 1 # noqa`
|
||||
let start_char = line[..start_byte].chars().count();
|
||||
let end_char = start_char + line[start_byte..end_byte].chars().count();
|
||||
Edit::deletion(
|
||||
Location::new(row + 1, start_char - leading_spaces),
|
||||
Location::new(row + 1, end_char + trailing_spaces),
|
||||
)
|
||||
} else if line[end_byte..].trim_start().starts_with('#') {
|
||||
// Ex) `x = 1 # noqa # type: ignore`
|
||||
let start_char = line[..start_byte].chars().count();
|
||||
let end_char = start_char + line[start_byte..end_byte].chars().count();
|
||||
Edit::deletion(
|
||||
Location::new(row + 1, start_char),
|
||||
Location::new(row + 1, end_char + trailing_spaces),
|
||||
)
|
||||
} else {
|
||||
// Ex) `x = 1 # noqa here`
|
||||
let start_char = line[..start_byte].chars().count();
|
||||
let end_char = start_char + line[start_byte..end_byte].chars().count();
|
||||
Edit::deletion(
|
||||
Location::new(row + 1, start_char + 1 + 1),
|
||||
Location::new(row + 1, end_char + trailing_spaces),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,8 +12,8 @@ use crate::rules::flake8_executable::rules::{
|
||||
shebang_missing, shebang_newline, shebang_not_executable, shebang_python, shebang_whitespace,
|
||||
};
|
||||
use crate::rules::pycodestyle::rules::{
|
||||
doc_line_too_long, line_too_long, mixed_spaces_and_tabs, no_newline_at_end_of_file,
|
||||
tab_indentation, trailing_whitespace,
|
||||
doc_line_too_long, indentation_contains_tabs, line_too_long, mixed_spaces_and_tabs,
|
||||
no_newline_at_end_of_file, trailing_whitespace,
|
||||
};
|
||||
use crate::rules::pygrep_hooks::rules::{blanket_noqa, blanket_type_ignore};
|
||||
use crate::rules::pylint;
|
||||
@@ -35,25 +35,25 @@ pub fn check_physical_lines(
|
||||
let enforce_blanket_noqa = settings.rules.enabled(Rule::BlanketNOQA);
|
||||
let enforce_shebang_not_executable = settings.rules.enabled(Rule::ShebangNotExecutable);
|
||||
let enforce_shebang_missing = settings.rules.enabled(Rule::ShebangMissingExecutableFile);
|
||||
let enforce_shebang_whitespace = settings.rules.enabled(Rule::ShebangLeadingWhitespace);
|
||||
let enforce_shebang_newline = settings.rules.enabled(Rule::ShebangNotFirstLine);
|
||||
let enforce_shebang_python = settings.rules.enabled(Rule::ShebangMissingPython);
|
||||
let enforce_shebang_whitespace = settings.rules.enabled(Rule::ShebangWhitespace);
|
||||
let enforce_shebang_newline = settings.rules.enabled(Rule::ShebangNewline);
|
||||
let enforce_shebang_python = settings.rules.enabled(Rule::ShebangPython);
|
||||
let enforce_blanket_type_ignore = settings.rules.enabled(Rule::BlanketTypeIgnore);
|
||||
let enforce_doc_line_too_long = settings.rules.enabled(Rule::DocLineTooLong);
|
||||
let enforce_line_too_long = settings.rules.enabled(Rule::LineTooLong);
|
||||
let enforce_no_newline_at_end_of_file = settings.rules.enabled(Rule::MissingNewlineAtEndOfFile);
|
||||
let enforce_no_newline_at_end_of_file = settings.rules.enabled(Rule::NoNewLineAtEndOfFile);
|
||||
let enforce_unnecessary_coding_comment = settings.rules.enabled(Rule::UTF8EncodingDeclaration);
|
||||
let enforce_mixed_spaces_and_tabs = settings.rules.enabled(Rule::MixedSpacesAndTabs);
|
||||
let enforce_bidirectional_unicode = settings.rules.enabled(Rule::BidirectionalUnicode);
|
||||
let enforce_trailing_whitespace = settings.rules.enabled(Rule::TrailingWhitespace);
|
||||
let enforce_blank_line_contains_whitespace =
|
||||
settings.rules.enabled(Rule::BlankLineWithWhitespace);
|
||||
let enforce_tab_indentation = settings.rules.enabled(Rule::TabIndentation);
|
||||
settings.rules.enabled(Rule::BlankLineContainsWhitespace);
|
||||
let enforce_indentation_contains_tabs = settings.rules.enabled(Rule::IndentationContainsTabs);
|
||||
|
||||
let fix_unnecessary_coding_comment =
|
||||
autofix.into() && settings.rules.should_fix(Rule::UTF8EncodingDeclaration);
|
||||
let fix_shebang_whitespace =
|
||||
autofix.into() && settings.rules.should_fix(Rule::ShebangLeadingWhitespace);
|
||||
autofix.into() && settings.rules.should_fix(Rule::ShebangWhitespace);
|
||||
|
||||
let mut commented_lines_iter = commented_lines.iter().peekable();
|
||||
let mut doc_lines_iter = doc_lines.iter().peekable();
|
||||
@@ -154,8 +154,8 @@ pub fn check_physical_lines(
|
||||
}
|
||||
}
|
||||
|
||||
if enforce_tab_indentation {
|
||||
if let Some(diagnostic) = tab_indentation(index, line) {
|
||||
if enforce_indentation_contains_tabs {
|
||||
if let Some(diagnostic) = indentation_contains_tabs(index, line) {
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
@@ -165,7 +165,7 @@ pub fn check_physical_lines(
|
||||
if let Some(diagnostic) = no_newline_at_end_of_file(
|
||||
locator,
|
||||
stylist,
|
||||
autofix.into() && settings.rules.should_fix(Rule::MissingNewlineAtEndOfFile),
|
||||
autofix.into() && settings.rules.should_fix(Rule::NoNewLineAtEndOfFile),
|
||||
) {
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
@@ -182,8 +182,6 @@ pub fn check_physical_lines(
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use rustpython_parser::lexer::lex;
|
||||
use rustpython_parser::Mode;
|
||||
use std::path::Path;
|
||||
|
||||
use ruff_python_ast::source_code::{Locator, Stylist};
|
||||
@@ -197,8 +195,7 @@ mod tests {
|
||||
fn e501_non_ascii_char() {
|
||||
let line = "'\u{4e9c}' * 2"; // 7 in UTF-32, 9 in UTF-8.
|
||||
let locator = Locator::new(line);
|
||||
let tokens: Vec<_> = lex(line, Mode::Module).collect();
|
||||
let stylist = Stylist::from_tokens(&tokens, &locator);
|
||||
let stylist = Stylist::from_contents(line, &locator);
|
||||
|
||||
let check_with_max_line_length = |line_length: usize| {
|
||||
check_physical_lines(
|
||||
@@ -214,7 +211,7 @@ mod tests {
|
||||
flags::Autofix::Enabled,
|
||||
)
|
||||
};
|
||||
assert_eq!(check_with_max_line_length(8), vec![]);
|
||||
assert_eq!(check_with_max_line_length(8), vec![]);
|
||||
assert!(!check_with_max_line_length(6).is_empty());
|
||||
assert!(check_with_max_line_length(7).is_empty());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,9 +54,9 @@ pub fn check_tokens(
|
||||
]);
|
||||
|
||||
let enforce_trailing_comma = settings.rules.any_enabled(&[
|
||||
Rule::MissingTrailingComma,
|
||||
Rule::TrailingCommaOnBareTuple,
|
||||
Rule::ProhibitedTrailingComma,
|
||||
Rule::TrailingCommaMissing,
|
||||
Rule::TrailingCommaOnBareTupleProhibited,
|
||||
Rule::TrailingCommaProhibited,
|
||||
]);
|
||||
let enforce_extraneous_parenthesis = settings.rules.enabled(Rule::ExtraneousParentheses);
|
||||
let enforce_type_comment_in_stub = settings.rules.enabled(Rule::TypeCommentInStub);
|
||||
|
||||
@@ -108,20 +108,20 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Pycodestyle, "E999") => Rule::SyntaxError,
|
||||
|
||||
// pycodestyle warnings
|
||||
(Pycodestyle, "W191") => Rule::TabIndentation,
|
||||
(Pycodestyle, "W191") => Rule::IndentationContainsTabs,
|
||||
(Pycodestyle, "W291") => Rule::TrailingWhitespace,
|
||||
(Pycodestyle, "W292") => Rule::MissingNewlineAtEndOfFile,
|
||||
(Pycodestyle, "W293") => Rule::BlankLineWithWhitespace,
|
||||
(Pycodestyle, "W292") => Rule::NoNewLineAtEndOfFile,
|
||||
(Pycodestyle, "W293") => Rule::BlankLineContainsWhitespace,
|
||||
(Pycodestyle, "W505") => Rule::DocLineTooLong,
|
||||
(Pycodestyle, "W605") => Rule::InvalidEscapeSequence,
|
||||
|
||||
// pyflakes
|
||||
(Pyflakes, "401") => Rule::UnusedImport,
|
||||
(Pyflakes, "402") => Rule::ImportShadowedByLoopVar,
|
||||
(Pyflakes, "403") => Rule::UndefinedLocalWithImportStar,
|
||||
(Pyflakes, "403") => Rule::ImportStar,
|
||||
(Pyflakes, "404") => Rule::LateFutureImport,
|
||||
(Pyflakes, "405") => Rule::UndefinedLocalWithImportStarUsage,
|
||||
(Pyflakes, "406") => Rule::UndefinedLocalWithNestedImportStarUsage,
|
||||
(Pyflakes, "405") => Rule::ImportStarUsage,
|
||||
(Pyflakes, "406") => Rule::ImportStarNotPermitted,
|
||||
(Pyflakes, "407") => Rule::FutureFeatureNotDefined,
|
||||
(Pyflakes, "501") => Rule::PercentFormatInvalidFormat,
|
||||
(Pyflakes, "502") => Rule::PercentFormatExpectedMapping,
|
||||
@@ -141,7 +141,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Pyflakes, "601") => Rule::MultiValueRepeatedKeyLiteral,
|
||||
(Pyflakes, "602") => Rule::MultiValueRepeatedKeyVariable,
|
||||
(Pyflakes, "621") => Rule::ExpressionsInStarAssignment,
|
||||
(Pyflakes, "622") => Rule::MultipleStarredExpressions,
|
||||
(Pyflakes, "622") => Rule::TwoStarredExpressions,
|
||||
(Pyflakes, "631") => Rule::AssertTuple,
|
||||
(Pyflakes, "632") => Rule::IsLiteral,
|
||||
(Pyflakes, "633") => Rule::InvalidPrintSyntax,
|
||||
@@ -168,7 +168,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Pylint, "E0101") => Rule::ReturnInInit,
|
||||
(Pylint, "E0116") => Rule::ContinueInFinally,
|
||||
(Pylint, "E0117") => Rule::NonlocalWithoutBinding,
|
||||
(Pylint, "E0118") => Rule::LoadBeforeGlobalDeclaration,
|
||||
(Pylint, "E0118") => Rule::UsedPriorGlobalDeclaration,
|
||||
(Pylint, "E0604") => Rule::InvalidAllObject,
|
||||
(Pylint, "E0605") => Rule::InvalidAllFormat,
|
||||
(Pylint, "E1142") => Rule::AwaitOutsideAsync,
|
||||
@@ -185,21 +185,19 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Pylint, "E2515") => Rule::InvalidCharacterZeroWidthSpace,
|
||||
(Pylint, "R0133") => Rule::ComparisonOfConstant,
|
||||
(Pylint, "R0206") => Rule::PropertyWithParameters,
|
||||
(Pylint, "R0402") => Rule::ManualFromImport,
|
||||
(Pylint, "R0402") => Rule::ConsiderUsingFromImport,
|
||||
(Pylint, "R0911") => Rule::TooManyReturnStatements,
|
||||
(Pylint, "R0912") => Rule::TooManyBranches,
|
||||
(Pylint, "R0913") => Rule::TooManyArguments,
|
||||
(Pylint, "R0915") => Rule::TooManyStatements,
|
||||
(Pylint, "R1701") => Rule::RepeatedIsinstanceCalls,
|
||||
(Pylint, "R1701") => Rule::ConsiderMergingIsinstance,
|
||||
(Pylint, "R1711") => Rule::UselessReturn,
|
||||
(Pylint, "R1722") => Rule::SysExitAlias,
|
||||
(Pylint, "R1722") => Rule::ConsiderUsingSysExit,
|
||||
(Pylint, "R2004") => Rule::MagicValueComparison,
|
||||
(Pylint, "R5501") => Rule::CollapsibleElseIf,
|
||||
(Pylint, "W0120") => Rule::UselessElseOnLoop,
|
||||
(Pylint, "W0129") => Rule::AssertOnStringLiteral,
|
||||
(Pylint, "W0602") => Rule::GlobalVariableNotAssigned,
|
||||
(Pylint, "W0603") => Rule::GlobalStatement,
|
||||
(Pylint, "W0711") => Rule::BinaryOpException,
|
||||
(Pylint, "W1508") => Rule::InvalidEnvvarDefault,
|
||||
(Pylint, "W2901") => Rule::RedefinedLoopName,
|
||||
|
||||
@@ -215,7 +213,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Flake8Bugbear, "005") => Rule::StripWithMultiCharacters,
|
||||
(Flake8Bugbear, "006") => Rule::MutableArgumentDefault,
|
||||
(Flake8Bugbear, "007") => Rule::UnusedLoopControlVariable,
|
||||
(Flake8Bugbear, "008") => Rule::FunctionCallInDefaultArgument,
|
||||
(Flake8Bugbear, "008") => Rule::FunctionCallArgumentDefault,
|
||||
(Flake8Bugbear, "009") => Rule::GetAttrWithConstant,
|
||||
(Flake8Bugbear, "010") => Rule::SetAttrWithConstant,
|
||||
(Flake8Bugbear, "011") => Rule::AssertFalse,
|
||||
@@ -238,7 +236,6 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Flake8Bugbear, "028") => Rule::NoExplicitStacklevel,
|
||||
(Flake8Bugbear, "029") => Rule::ExceptWithEmptyTuple,
|
||||
(Flake8Bugbear, "030") => Rule::ExceptWithNonExceptionClasses,
|
||||
(Flake8Bugbear, "031") => Rule::ReuseOfGroupbyGenerator,
|
||||
(Flake8Bugbear, "032") => Rule::UnintentionalTypeAnnotation,
|
||||
(Flake8Bugbear, "904") => Rule::RaiseWithoutFromInsideExcept,
|
||||
(Flake8Bugbear, "905") => Rule::ZipWithoutExplicitStrict,
|
||||
@@ -284,19 +281,14 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Flake8Return, "507") => Rule::SuperfluousElseContinue,
|
||||
(Flake8Return, "508") => Rule::SuperfluousElseBreak,
|
||||
|
||||
// flake8-gettext
|
||||
(Flake8GetText, "001") => Rule::FStringInGetTextFuncCall,
|
||||
(Flake8GetText, "002") => Rule::FormatInGetTextFuncCall,
|
||||
(Flake8GetText, "003") => Rule::PrintfInGetTextFuncCall,
|
||||
|
||||
// flake8-implicit-str-concat
|
||||
(Flake8ImplicitStrConcat, "001") => Rule::SingleLineImplicitStringConcatenation,
|
||||
(Flake8ImplicitStrConcat, "002") => Rule::MultiLineImplicitStringConcatenation,
|
||||
(Flake8ImplicitStrConcat, "003") => Rule::ExplicitStringConcatenation,
|
||||
|
||||
// flake8-print
|
||||
(Flake8Print, "1") => Rule::Print,
|
||||
(Flake8Print, "3") => Rule::PPrint,
|
||||
(Flake8Print, "1") => Rule::PrintFound,
|
||||
(Flake8Print, "3") => Rule::PPrintFound,
|
||||
|
||||
// flake8-quotes
|
||||
(Flake8Quotes, "000") => Rule::BadQuotesInlineString,
|
||||
@@ -310,7 +302,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Flake8Annotations, "003") => Rule::MissingTypeKwargs,
|
||||
(Flake8Annotations, "101") => Rule::MissingTypeSelf,
|
||||
(Flake8Annotations, "102") => Rule::MissingTypeCls,
|
||||
(Flake8Annotations, "201") => Rule::MissingReturnTypeUndocumentedPublicFunction,
|
||||
(Flake8Annotations, "201") => Rule::MissingReturnTypePublicFunction,
|
||||
(Flake8Annotations, "202") => Rule::MissingReturnTypePrivateFunction,
|
||||
(Flake8Annotations, "204") => Rule::MissingReturnTypeSpecialMethod,
|
||||
(Flake8Annotations, "205") => Rule::MissingReturnTypeStaticMethod,
|
||||
@@ -318,32 +310,33 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Flake8Annotations, "401") => Rule::AnyType,
|
||||
|
||||
// flake8-2020
|
||||
(Flake82020, "101") => Rule::SysVersionSlice3,
|
||||
(Flake82020, "102") => Rule::SysVersion2,
|
||||
(Flake82020, "101") => Rule::SysVersionSlice3Referenced,
|
||||
(Flake82020, "102") => Rule::SysVersion2Referenced,
|
||||
(Flake82020, "103") => Rule::SysVersionCmpStr3,
|
||||
(Flake82020, "201") => Rule::SysVersionInfo0Eq3,
|
||||
(Flake82020, "202") => Rule::SixPY3,
|
||||
(Flake82020, "201") => Rule::SysVersionInfo0Eq3Referenced,
|
||||
(Flake82020, "202") => Rule::SixPY3Referenced,
|
||||
(Flake82020, "203") => Rule::SysVersionInfo1CmpInt,
|
||||
(Flake82020, "204") => Rule::SysVersionInfoMinorCmpInt,
|
||||
(Flake82020, "301") => Rule::SysVersion0,
|
||||
(Flake82020, "301") => Rule::SysVersion0Referenced,
|
||||
(Flake82020, "302") => Rule::SysVersionCmpStr10,
|
||||
(Flake82020, "303") => Rule::SysVersionSlice1,
|
||||
(Flake82020, "303") => Rule::SysVersionSlice1Referenced,
|
||||
|
||||
// flake8-simplify
|
||||
(Flake8Simplify, "101") => Rule::DuplicateIsinstanceCall,
|
||||
(Flake8Simplify, "102") => Rule::CollapsibleIf,
|
||||
(Flake8Simplify, "103") => Rule::NeedlessBool,
|
||||
(Flake8Simplify, "105") => Rule::SuppressibleException,
|
||||
(Flake8Simplify, "105") => Rule::UseContextlibSuppress,
|
||||
(Flake8Simplify, "107") => Rule::ReturnInTryExceptFinally,
|
||||
(Flake8Simplify, "108") => Rule::IfElseBlockInsteadOfIfExp,
|
||||
(Flake8Simplify, "108") => Rule::UseTernaryOperator,
|
||||
(Flake8Simplify, "109") => Rule::CompareWithTuple,
|
||||
(Flake8Simplify, "110") => Rule::ReimplementedBuiltin,
|
||||
(Flake8Simplify, "112") => Rule::UncapitalizedEnvironmentVariables,
|
||||
// (Flake8Simplify, "111") => Rule::ReimplementedBuiltin,
|
||||
(Flake8Simplify, "112") => Rule::UseCapitalEnvironmentVariables,
|
||||
(Flake8Simplify, "114") => Rule::IfWithSameArms,
|
||||
(Flake8Simplify, "115") => Rule::OpenFileWithContextHandler,
|
||||
(Flake8Simplify, "116") => Rule::IfElseBlockInsteadOfDictLookup,
|
||||
(Flake8Simplify, "116") => Rule::ManualDictLookup,
|
||||
(Flake8Simplify, "117") => Rule::MultipleWithStatements,
|
||||
(Flake8Simplify, "118") => Rule::InDictKeys,
|
||||
(Flake8Simplify, "118") => Rule::KeyInDict,
|
||||
(Flake8Simplify, "201") => Rule::NegateEqualOp,
|
||||
(Flake8Simplify, "202") => Rule::NegateNotEqualOp,
|
||||
(Flake8Simplify, "208") => Rule::DoubleNegation,
|
||||
@@ -355,15 +348,15 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Flake8Simplify, "222") => Rule::ExprOrTrue,
|
||||
(Flake8Simplify, "223") => Rule::ExprAndFalse,
|
||||
(Flake8Simplify, "300") => Rule::YodaConditions,
|
||||
(Flake8Simplify, "401") => Rule::IfElseBlockInsteadOfDictGet,
|
||||
(Flake8Simplify, "401") => Rule::DictGetWithDefault,
|
||||
|
||||
// pyupgrade
|
||||
(Pyupgrade, "001") => Rule::UselessMetaclassType,
|
||||
(Pyupgrade, "003") => Rule::TypeOfPrimitive,
|
||||
(Pyupgrade, "004") => Rule::UselessObjectInheritance,
|
||||
(Pyupgrade, "005") => Rule::DeprecatedUnittestAlias,
|
||||
(Pyupgrade, "006") => Rule::NonPEP585Annotation,
|
||||
(Pyupgrade, "007") => Rule::NonPEP604Annotation,
|
||||
(Pyupgrade, "006") => Rule::DeprecatedCollectionType,
|
||||
(Pyupgrade, "007") => Rule::TypingUnion,
|
||||
(Pyupgrade, "008") => Rule::SuperCallWithParameters,
|
||||
(Pyupgrade, "009") => Rule::UTF8EncodingDeclaration,
|
||||
(Pyupgrade, "010") => Rule::UnnecessaryFutureImport,
|
||||
@@ -378,32 +371,32 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Pyupgrade, "020") => Rule::OpenAlias,
|
||||
(Pyupgrade, "021") => Rule::ReplaceUniversalNewlines,
|
||||
(Pyupgrade, "022") => Rule::ReplaceStdoutStderr,
|
||||
(Pyupgrade, "023") => Rule::DeprecatedCElementTree,
|
||||
(Pyupgrade, "023") => Rule::RewriteCElementTree,
|
||||
(Pyupgrade, "024") => Rule::OSErrorAlias,
|
||||
(Pyupgrade, "025") => Rule::UnicodeKindPrefix,
|
||||
(Pyupgrade, "026") => Rule::DeprecatedMockImport,
|
||||
(Pyupgrade, "027") => Rule::UnpackedListComprehension,
|
||||
(Pyupgrade, "028") => Rule::YieldInForLoop,
|
||||
(Pyupgrade, "025") => Rule::RewriteUnicodeLiteral,
|
||||
(Pyupgrade, "026") => Rule::RewriteMockImport,
|
||||
(Pyupgrade, "027") => Rule::RewriteListComprehension,
|
||||
(Pyupgrade, "028") => Rule::RewriteYieldFrom,
|
||||
(Pyupgrade, "029") => Rule::UnnecessaryBuiltinImport,
|
||||
(Pyupgrade, "030") => Rule::FormatLiterals,
|
||||
(Pyupgrade, "031") => Rule::PrintfStringFormatting,
|
||||
(Pyupgrade, "032") => Rule::FString,
|
||||
(Pyupgrade, "033") => Rule::LRUCacheWithMaxsizeNone,
|
||||
(Pyupgrade, "033") => Rule::FunctoolsCache,
|
||||
(Pyupgrade, "034") => Rule::ExtraneousParentheses,
|
||||
(Pyupgrade, "035") => Rule::DeprecatedImport,
|
||||
(Pyupgrade, "036") => Rule::OutdatedVersionBlock,
|
||||
(Pyupgrade, "037") => Rule::QuotedAnnotation,
|
||||
(Pyupgrade, "038") => Rule::NonPEP604Isinstance,
|
||||
(Pyupgrade, "038") => Rule::IsinstanceWithTuple,
|
||||
|
||||
// pydocstyle
|
||||
(Pydocstyle, "100") => Rule::UndocumentedPublicModule,
|
||||
(Pydocstyle, "101") => Rule::UndocumentedPublicClass,
|
||||
(Pydocstyle, "102") => Rule::UndocumentedPublicMethod,
|
||||
(Pydocstyle, "103") => Rule::UndocumentedPublicFunction,
|
||||
(Pydocstyle, "104") => Rule::UndocumentedPublicPackage,
|
||||
(Pydocstyle, "105") => Rule::UndocumentedMagicMethod,
|
||||
(Pydocstyle, "106") => Rule::UndocumentedPublicNestedClass,
|
||||
(Pydocstyle, "107") => Rule::UndocumentedPublicInit,
|
||||
(Pydocstyle, "100") => Rule::PublicModule,
|
||||
(Pydocstyle, "101") => Rule::PublicClass,
|
||||
(Pydocstyle, "102") => Rule::PublicMethod,
|
||||
(Pydocstyle, "103") => Rule::PublicFunction,
|
||||
(Pydocstyle, "104") => Rule::PublicPackage,
|
||||
(Pydocstyle, "105") => Rule::MagicMethod,
|
||||
(Pydocstyle, "106") => Rule::PublicNestedClass,
|
||||
(Pydocstyle, "107") => Rule::PublicInit,
|
||||
(Pydocstyle, "200") => Rule::FitsOnOneLine,
|
||||
(Pydocstyle, "201") => Rule::NoBlankLineBeforeFunction,
|
||||
(Pydocstyle, "202") => Rule::NoBlankLineAfterFunction,
|
||||
@@ -411,11 +404,11 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Pydocstyle, "204") => Rule::OneBlankLineAfterClass,
|
||||
(Pydocstyle, "205") => Rule::BlankLineAfterSummary,
|
||||
(Pydocstyle, "206") => Rule::IndentWithSpaces,
|
||||
(Pydocstyle, "207") => Rule::UnderIndentation,
|
||||
(Pydocstyle, "208") => Rule::OverIndentation,
|
||||
(Pydocstyle, "207") => Rule::NoUnderIndentation,
|
||||
(Pydocstyle, "208") => Rule::NoOverIndentation,
|
||||
(Pydocstyle, "209") => Rule::NewLineAfterLastParagraph,
|
||||
(Pydocstyle, "210") => Rule::SurroundingWhitespace,
|
||||
(Pydocstyle, "211") => Rule::BlankLineBeforeClass,
|
||||
(Pydocstyle, "210") => Rule::NoSurroundingWhitespace,
|
||||
(Pydocstyle, "211") => Rule::NoBlankLineBeforeClass,
|
||||
(Pydocstyle, "212") => Rule::MultiLineSummaryFirstLine,
|
||||
(Pydocstyle, "213") => Rule::MultiLineSummarySecondLine,
|
||||
(Pydocstyle, "214") => Rule::SectionNotOverIndented,
|
||||
@@ -432,9 +425,9 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Pydocstyle, "407") => Rule::DashedUnderlineAfterSection,
|
||||
(Pydocstyle, "408") => Rule::SectionUnderlineAfterName,
|
||||
(Pydocstyle, "409") => Rule::SectionUnderlineMatchesSectionLength,
|
||||
(Pydocstyle, "410") => Rule::NoBlankLineAfterSection,
|
||||
(Pydocstyle, "411") => Rule::NoBlankLineBeforeSection,
|
||||
(Pydocstyle, "412") => Rule::BlankLinesBetweenHeaderAndContent,
|
||||
(Pydocstyle, "410") => Rule::BlankLineAfterSection,
|
||||
(Pydocstyle, "411") => Rule::BlankLineBeforeSection,
|
||||
(Pydocstyle, "412") => Rule::NoBlankLinesBetweenHeaderAndContent,
|
||||
(Pydocstyle, "413") => Rule::BlankLineAfterLastSection,
|
||||
(Pydocstyle, "414") => Rule::EmptyDocstringSection,
|
||||
(Pydocstyle, "415") => Rule::EndsInPunctuation,
|
||||
@@ -476,37 +469,16 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Flake8Bandit, "105") => Rule::HardcodedPasswordString,
|
||||
(Flake8Bandit, "106") => Rule::HardcodedPasswordFuncArg,
|
||||
(Flake8Bandit, "107") => Rule::HardcodedPasswordDefault,
|
||||
(Flake8Bandit, "608") => Rule::HardcodedSQLExpression,
|
||||
(Flake8Bandit, "108") => Rule::HardcodedTempFile,
|
||||
(Flake8Bandit, "110") => Rule::TryExceptPass,
|
||||
(Flake8Bandit, "112") => Rule::TryExceptContinue,
|
||||
(Flake8Bandit, "113") => Rule::RequestWithoutTimeout,
|
||||
(Flake8Bandit, "301") => Rule::SuspiciousPickleUsage,
|
||||
(Flake8Bandit, "302") => Rule::SuspiciousMarshalUsage,
|
||||
(Flake8Bandit, "303") => Rule::SuspiciousInsecureHashUsage,
|
||||
(Flake8Bandit, "304") => Rule::SuspiciousInsecureCipherUsage,
|
||||
(Flake8Bandit, "305") => Rule::SuspiciousInsecureCipherModeUsage,
|
||||
(Flake8Bandit, "306") => Rule::SuspiciousMktempUsage,
|
||||
(Flake8Bandit, "307") => Rule::SuspiciousEvalUsage,
|
||||
(Flake8Bandit, "308") => Rule::SuspiciousMarkSafeUsage,
|
||||
(Flake8Bandit, "310") => Rule::SuspiciousURLOpenUsage,
|
||||
(Flake8Bandit, "311") => Rule::SuspiciousNonCryptographicRandomUsage,
|
||||
(Flake8Bandit, "312") => Rule::SuspiciousTelnetUsage,
|
||||
(Flake8Bandit, "313") => Rule::SuspiciousXMLCElementTreeUsage,
|
||||
(Flake8Bandit, "314") => Rule::SuspiciousXMLElementTreeUsage,
|
||||
(Flake8Bandit, "315") => Rule::SuspiciousXMLExpatReaderUsage,
|
||||
(Flake8Bandit, "316") => Rule::SuspiciousXMLExpatBuilderUsage,
|
||||
(Flake8Bandit, "317") => Rule::SuspiciousXMLSaxUsage,
|
||||
(Flake8Bandit, "318") => Rule::SuspiciousXMLMiniDOMUsage,
|
||||
(Flake8Bandit, "319") => Rule::SuspiciousXMLPullDOMUsage,
|
||||
(Flake8Bandit, "320") => Rule::SuspiciousXMLETreeUsage,
|
||||
(Flake8Bandit, "321") => Rule::SuspiciousFTPLibUsage,
|
||||
(Flake8Bandit, "323") => Rule::SuspiciousUnverifiedContextUsage,
|
||||
(Flake8Bandit, "324") => Rule::HashlibInsecureHashFunction,
|
||||
(Flake8Bandit, "501") => Rule::RequestWithNoCertValidation,
|
||||
(Flake8Bandit, "506") => Rule::UnsafeYAMLLoad,
|
||||
(Flake8Bandit, "508") => Rule::SnmpInsecureVersion,
|
||||
(Flake8Bandit, "509") => Rule::SnmpWeakCryptography,
|
||||
(Flake8Bandit, "608") => Rule::HardcodedSQLExpression,
|
||||
(Flake8Bandit, "612") => Rule::LoggingConfigInsecureListen,
|
||||
(Flake8Bandit, "701") => Rule::Jinja2AutoescapeFalse,
|
||||
|
||||
@@ -537,24 +509,24 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Flake8Datetimez, "012") => Rule::CallDateFromtimestamp,
|
||||
|
||||
// pygrep-hooks
|
||||
(PygrepHooks, "001") => Rule::Eval,
|
||||
(PygrepHooks, "001") => Rule::NoEval,
|
||||
(PygrepHooks, "002") => Rule::DeprecatedLogWarn,
|
||||
(PygrepHooks, "003") => Rule::BlanketTypeIgnore,
|
||||
(PygrepHooks, "004") => Rule::BlanketNOQA,
|
||||
|
||||
// pandas-vet
|
||||
(PandasVet, "002") => Rule::PandasUseOfInplaceArgument,
|
||||
(PandasVet, "003") => Rule::PandasUseOfDotIsNull,
|
||||
(PandasVet, "004") => Rule::PandasUseOfDotNotNull,
|
||||
(PandasVet, "007") => Rule::PandasUseOfDotIx,
|
||||
(PandasVet, "008") => Rule::PandasUseOfDotAt,
|
||||
(PandasVet, "009") => Rule::PandasUseOfDotIat,
|
||||
(PandasVet, "010") => Rule::PandasUseOfDotPivotOrUnstack,
|
||||
(PandasVet, "011") => Rule::PandasUseOfDotValues,
|
||||
(PandasVet, "012") => Rule::PandasUseOfDotReadTable,
|
||||
(PandasVet, "013") => Rule::PandasUseOfDotStack,
|
||||
(PandasVet, "015") => Rule::PandasUseOfPdMerge,
|
||||
(PandasVet, "901") => Rule::PandasDfVariableName,
|
||||
(PandasVet, "002") => Rule::UseOfInplaceArgument,
|
||||
(PandasVet, "003") => Rule::UseOfDotIsNull,
|
||||
(PandasVet, "004") => Rule::UseOfDotNotNull,
|
||||
(PandasVet, "007") => Rule::UseOfDotIx,
|
||||
(PandasVet, "008") => Rule::UseOfDotAt,
|
||||
(PandasVet, "009") => Rule::UseOfDotIat,
|
||||
(PandasVet, "010") => Rule::UseOfDotPivotOrUnstack,
|
||||
(PandasVet, "011") => Rule::UseOfDotValues,
|
||||
(PandasVet, "012") => Rule::UseOfDotReadTable,
|
||||
(PandasVet, "013") => Rule::UseOfDotStack,
|
||||
(PandasVet, "015") => Rule::UseOfPdMerge,
|
||||
(PandasVet, "901") => Rule::DfIsABadVariableName,
|
||||
|
||||
// flake8-errmsg
|
||||
(Flake8ErrMsg, "101") => Rule::RawStringInException,
|
||||
@@ -562,60 +534,58 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Flake8ErrMsg, "103") => Rule::DotFormatInException,
|
||||
|
||||
// flake8-pyi
|
||||
(Flake8Pyi, "001") => Rule::UnprefixedTypeParam,
|
||||
(Flake8Pyi, "001") => Rule::PrefixTypeParams,
|
||||
(Flake8Pyi, "006") => Rule::BadVersionInfoComparison,
|
||||
(Flake8Pyi, "007") => Rule::UnrecognizedPlatformCheck,
|
||||
(Flake8Pyi, "008") => Rule::UnrecognizedPlatformName,
|
||||
(Flake8Pyi, "009") => Rule::PassStatementStubBody,
|
||||
(Flake8Pyi, "010") => Rule::NonEmptyStubBody,
|
||||
(Flake8Pyi, "011") => Rule::TypedArgumentDefaultInStub,
|
||||
(Flake8Pyi, "012") => Rule::PassInClassBody,
|
||||
(Flake8Pyi, "014") => Rule::ArgumentDefaultInStub,
|
||||
(Flake8Pyi, "015") => Rule::AssignmentDefaultInStub,
|
||||
(Flake8Pyi, "011") => Rule::TypedArgumentSimpleDefaults,
|
||||
(Flake8Pyi, "014") => Rule::ArgumentSimpleDefaults,
|
||||
(Flake8Pyi, "021") => Rule::DocstringInStub,
|
||||
(Flake8Pyi, "033") => Rule::TypeCommentInStub,
|
||||
|
||||
// flake8-pytest-style
|
||||
(Flake8PytestStyle, "001") => Rule::PytestFixtureIncorrectParenthesesStyle,
|
||||
(Flake8PytestStyle, "002") => Rule::PytestFixturePositionalArgs,
|
||||
(Flake8PytestStyle, "003") => Rule::PytestExtraneousScopeFunction,
|
||||
(Flake8PytestStyle, "004") => Rule::PytestMissingFixtureNameUnderscore,
|
||||
(Flake8PytestStyle, "005") => Rule::PytestIncorrectFixtureNameUnderscore,
|
||||
(Flake8PytestStyle, "006") => Rule::PytestParametrizeNamesWrongType,
|
||||
(Flake8PytestStyle, "007") => Rule::PytestParametrizeValuesWrongType,
|
||||
(Flake8PytestStyle, "008") => Rule::PytestPatchWithLambda,
|
||||
(Flake8PytestStyle, "009") => Rule::PytestUnittestAssertion,
|
||||
(Flake8PytestStyle, "010") => Rule::PytestRaisesWithoutException,
|
||||
(Flake8PytestStyle, "011") => Rule::PytestRaisesTooBroad,
|
||||
(Flake8PytestStyle, "012") => Rule::PytestRaisesWithMultipleStatements,
|
||||
(Flake8PytestStyle, "013") => Rule::PytestIncorrectPytestImport,
|
||||
(Flake8PytestStyle, "015") => Rule::PytestAssertAlwaysFalse,
|
||||
(Flake8PytestStyle, "016") => Rule::PytestFailWithoutMessage,
|
||||
(Flake8PytestStyle, "017") => Rule::PytestAssertInExcept,
|
||||
(Flake8PytestStyle, "018") => Rule::PytestCompositeAssertion,
|
||||
(Flake8PytestStyle, "019") => Rule::PytestFixtureParamWithoutValue,
|
||||
(Flake8PytestStyle, "020") => Rule::PytestDeprecatedYieldFixture,
|
||||
(Flake8PytestStyle, "021") => Rule::PytestFixtureFinalizerCallback,
|
||||
(Flake8PytestStyle, "022") => Rule::PytestUselessYieldFixture,
|
||||
(Flake8PytestStyle, "023") => Rule::PytestIncorrectMarkParenthesesStyle,
|
||||
(Flake8PytestStyle, "024") => Rule::PytestUnnecessaryAsyncioMarkOnFixture,
|
||||
(Flake8PytestStyle, "025") => Rule::PytestErroneousUseFixturesOnFixture,
|
||||
(Flake8PytestStyle, "026") => Rule::PytestUseFixturesWithoutParameters,
|
||||
(Flake8PytestStyle, "001") => Rule::IncorrectFixtureParenthesesStyle,
|
||||
(Flake8PytestStyle, "002") => Rule::FixturePositionalArgs,
|
||||
(Flake8PytestStyle, "003") => Rule::ExtraneousScopeFunction,
|
||||
(Flake8PytestStyle, "004") => Rule::MissingFixtureNameUnderscore,
|
||||
(Flake8PytestStyle, "005") => Rule::IncorrectFixtureNameUnderscore,
|
||||
(Flake8PytestStyle, "006") => Rule::ParametrizeNamesWrongType,
|
||||
(Flake8PytestStyle, "007") => Rule::ParametrizeValuesWrongType,
|
||||
(Flake8PytestStyle, "008") => Rule::PatchWithLambda,
|
||||
(Flake8PytestStyle, "009") => Rule::UnittestAssertion,
|
||||
(Flake8PytestStyle, "010") => Rule::RaisesWithoutException,
|
||||
(Flake8PytestStyle, "011") => Rule::RaisesTooBroad,
|
||||
(Flake8PytestStyle, "012") => Rule::RaisesWithMultipleStatements,
|
||||
(Flake8PytestStyle, "013") => Rule::IncorrectPytestImport,
|
||||
(Flake8PytestStyle, "015") => Rule::AssertAlwaysFalse,
|
||||
(Flake8PytestStyle, "016") => Rule::FailWithoutMessage,
|
||||
(Flake8PytestStyle, "017") => Rule::AssertInExcept,
|
||||
(Flake8PytestStyle, "018") => Rule::CompositeAssertion,
|
||||
(Flake8PytestStyle, "019") => Rule::FixtureParamWithoutValue,
|
||||
(Flake8PytestStyle, "020") => Rule::DeprecatedYieldFixture,
|
||||
(Flake8PytestStyle, "021") => Rule::FixtureFinalizerCallback,
|
||||
(Flake8PytestStyle, "022") => Rule::UselessYieldFixture,
|
||||
(Flake8PytestStyle, "023") => Rule::IncorrectMarkParenthesesStyle,
|
||||
(Flake8PytestStyle, "024") => Rule::UnnecessaryAsyncioMarkOnFixture,
|
||||
(Flake8PytestStyle, "025") => Rule::ErroneousUseFixturesOnFixture,
|
||||
(Flake8PytestStyle, "026") => Rule::UseFixturesWithoutParameters,
|
||||
|
||||
// flake8-pie
|
||||
(Flake8Pie, "790") => Rule::UnnecessaryPass,
|
||||
(Flake8Pie, "794") => Rule::DuplicateClassFieldDefinition,
|
||||
(Flake8Pie, "796") => Rule::NonUniqueEnums,
|
||||
(Flake8Pie, "794") => Rule::DupeClassFieldDefinitions,
|
||||
(Flake8Pie, "796") => Rule::PreferUniqueEnums,
|
||||
(Flake8Pie, "800") => Rule::UnnecessarySpread,
|
||||
(Flake8Pie, "802") => Rule::UnnecessaryComprehensionAnyAll,
|
||||
(Flake8Pie, "804") => Rule::UnnecessaryDictKwargs,
|
||||
(Flake8Pie, "807") => Rule::ReimplementedListBuiltin,
|
||||
(Flake8Pie, "810") => Rule::MultipleStartsEndsWith,
|
||||
(Flake8Pie, "807") => Rule::PreferListBuiltin,
|
||||
(Flake8Pie, "810") => Rule::SingleStartsEndsWith,
|
||||
|
||||
// flake8-commas
|
||||
(Flake8Commas, "812") => Rule::MissingTrailingComma,
|
||||
(Flake8Commas, "818") => Rule::TrailingCommaOnBareTuple,
|
||||
(Flake8Commas, "819") => Rule::ProhibitedTrailingComma,
|
||||
(Flake8Commas, "812") => Rule::TrailingCommaMissing,
|
||||
(Flake8Commas, "818") => Rule::TrailingCommaOnBareTupleProhibited,
|
||||
(Flake8Commas, "819") => Rule::TrailingCommaProhibited,
|
||||
|
||||
// flake8-no-pep420
|
||||
(Flake8NoPep420, "001") => Rule::ImplicitNamespacePackage,
|
||||
@@ -623,9 +593,9 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
// flake8-executable
|
||||
(Flake8Executable, "001") => Rule::ShebangNotExecutable,
|
||||
(Flake8Executable, "002") => Rule::ShebangMissingExecutableFile,
|
||||
(Flake8Executable, "003") => Rule::ShebangMissingPython,
|
||||
(Flake8Executable, "004") => Rule::ShebangLeadingWhitespace,
|
||||
(Flake8Executable, "005") => Rule::ShebangNotFirstLine,
|
||||
(Flake8Executable, "003") => Rule::ShebangPython,
|
||||
(Flake8Executable, "004") => Rule::ShebangWhitespace,
|
||||
(Flake8Executable, "005") => Rule::ShebangNewline,
|
||||
|
||||
// flake8-type-checking
|
||||
(Flake8TypeChecking, "001") => Rule::TypingOnlyFirstPartyImport,
|
||||
@@ -637,7 +607,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
// tryceratops
|
||||
(Tryceratops, "002") => Rule::RaiseVanillaClass,
|
||||
(Tryceratops, "003") => Rule::RaiseVanillaArgs,
|
||||
(Tryceratops, "004") => Rule::TypeCheckWithoutTypeError,
|
||||
(Tryceratops, "004") => Rule::PreferTypeError,
|
||||
(Tryceratops, "200") => Rule::ReraiseNoCause,
|
||||
(Tryceratops, "201") => Rule::VerboseRaise,
|
||||
(Tryceratops, "300") => Rule::TryConsiderElse,
|
||||
@@ -646,31 +616,31 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Tryceratops, "401") => Rule::VerboseLogMessage,
|
||||
|
||||
// flake8-use-pathlib
|
||||
(Flake8UsePathlib, "100") => Rule::OsPathAbspath,
|
||||
(Flake8UsePathlib, "101") => Rule::OsChmod,
|
||||
(Flake8UsePathlib, "102") => Rule::OsMkdir,
|
||||
(Flake8UsePathlib, "103") => Rule::OsMakedirs,
|
||||
(Flake8UsePathlib, "104") => Rule::OsRename,
|
||||
(Flake8UsePathlib, "100") => Rule::PathlibAbspath,
|
||||
(Flake8UsePathlib, "101") => Rule::PathlibChmod,
|
||||
(Flake8UsePathlib, "102") => Rule::PathlibMkdir,
|
||||
(Flake8UsePathlib, "103") => Rule::PathlibMakedirs,
|
||||
(Flake8UsePathlib, "104") => Rule::PathlibRename,
|
||||
(Flake8UsePathlib, "105") => Rule::PathlibReplace,
|
||||
(Flake8UsePathlib, "106") => Rule::OsRmdir,
|
||||
(Flake8UsePathlib, "107") => Rule::OsRemove,
|
||||
(Flake8UsePathlib, "108") => Rule::OsUnlink,
|
||||
(Flake8UsePathlib, "109") => Rule::OsGetcwd,
|
||||
(Flake8UsePathlib, "110") => Rule::OsPathExists,
|
||||
(Flake8UsePathlib, "111") => Rule::OsPathExpanduser,
|
||||
(Flake8UsePathlib, "112") => Rule::OsPathIsdir,
|
||||
(Flake8UsePathlib, "113") => Rule::OsPathIsfile,
|
||||
(Flake8UsePathlib, "114") => Rule::OsPathIslink,
|
||||
(Flake8UsePathlib, "115") => Rule::OsReadlink,
|
||||
(Flake8UsePathlib, "116") => Rule::OsStat,
|
||||
(Flake8UsePathlib, "117") => Rule::OsPathIsabs,
|
||||
(Flake8UsePathlib, "118") => Rule::OsPathJoin,
|
||||
(Flake8UsePathlib, "119") => Rule::OsPathBasename,
|
||||
(Flake8UsePathlib, "120") => Rule::OsPathDirname,
|
||||
(Flake8UsePathlib, "121") => Rule::OsPathSamefile,
|
||||
(Flake8UsePathlib, "122") => Rule::OsPathSplitext,
|
||||
(Flake8UsePathlib, "123") => Rule::BuiltinOpen,
|
||||
(Flake8UsePathlib, "124") => Rule::PyPath,
|
||||
(Flake8UsePathlib, "106") => Rule::PathlibRmdir,
|
||||
(Flake8UsePathlib, "107") => Rule::PathlibRemove,
|
||||
(Flake8UsePathlib, "108") => Rule::PathlibUnlink,
|
||||
(Flake8UsePathlib, "109") => Rule::PathlibGetcwd,
|
||||
(Flake8UsePathlib, "110") => Rule::PathlibExists,
|
||||
(Flake8UsePathlib, "111") => Rule::PathlibExpanduser,
|
||||
(Flake8UsePathlib, "112") => Rule::PathlibIsDir,
|
||||
(Flake8UsePathlib, "113") => Rule::PathlibIsFile,
|
||||
(Flake8UsePathlib, "114") => Rule::PathlibIsLink,
|
||||
(Flake8UsePathlib, "115") => Rule::PathlibReadlink,
|
||||
(Flake8UsePathlib, "116") => Rule::PathlibStat,
|
||||
(Flake8UsePathlib, "117") => Rule::PathlibIsAbs,
|
||||
(Flake8UsePathlib, "118") => Rule::PathlibJoin,
|
||||
(Flake8UsePathlib, "119") => Rule::PathlibBasename,
|
||||
(Flake8UsePathlib, "120") => Rule::PathlibDirname,
|
||||
(Flake8UsePathlib, "121") => Rule::PathlibSamefile,
|
||||
(Flake8UsePathlib, "122") => Rule::PathlibSplitext,
|
||||
(Flake8UsePathlib, "123") => Rule::PathlibOpen,
|
||||
(Flake8UsePathlib, "124") => Rule::PathlibPyPath,
|
||||
|
||||
// flake8-logging-format
|
||||
(Flake8LoggingFormat, "001") => Rule::LoggingStringFormat,
|
||||
@@ -696,19 +666,18 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Ruff, "001") => Rule::AmbiguousUnicodeCharacterString,
|
||||
(Ruff, "002") => Rule::AmbiguousUnicodeCharacterDocstring,
|
||||
(Ruff, "003") => Rule::AmbiguousUnicodeCharacterComment,
|
||||
(Ruff, "005") => Rule::CollectionLiteralConcatenation,
|
||||
(Ruff, "005") => Rule::UnpackInsteadOfConcatenatingToCollectionLiteral,
|
||||
(Ruff, "006") => Rule::AsyncioDanglingTask,
|
||||
(Ruff, "007") => Rule::PairwiseOverZipped,
|
||||
(Ruff, "100") => Rule::UnusedNOQA,
|
||||
|
||||
// flake8-django
|
||||
(Flake8Django, "001") => Rule::DjangoNullableModelStringField,
|
||||
(Flake8Django, "003") => Rule::DjangoLocalsInRenderFunction,
|
||||
(Flake8Django, "006") => Rule::DjangoExcludeWithModelForm,
|
||||
(Flake8Django, "007") => Rule::DjangoAllWithModelForm,
|
||||
(Flake8Django, "008") => Rule::DjangoModelWithoutDunderStr,
|
||||
(Flake8Django, "012") => Rule::DjangoUnorderedBodyContentInModel,
|
||||
(Flake8Django, "013") => Rule::DjangoNonLeadingReceiverDecorator,
|
||||
(Flake8Django, "001") => Rule::NullableModelStringField,
|
||||
(Flake8Django, "003") => Rule::LocalsInRenderFunction,
|
||||
(Flake8Django, "006") => Rule::ExcludeWithModelForm,
|
||||
(Flake8Django, "007") => Rule::AllWithModelForm,
|
||||
(Flake8Django, "008") => Rule::ModelWithoutDunderStr,
|
||||
(Flake8Django, "013") => Rule::NonLeadingReceiverDecorator,
|
||||
|
||||
_ => return None,
|
||||
})
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use anyhow::{bail, Result};
|
||||
use libcst_native::{
|
||||
Attribute, Call, Comparison, Dict, Expr, Expression, Import, ImportFrom, Module, SimpleString,
|
||||
SmallStatement, Statement,
|
||||
Call, Comparison, Expr, Expression, Import, ImportFrom, Module, SmallStatement, Statement,
|
||||
};
|
||||
|
||||
pub fn match_module(module_text: &str) -> Result<Module> {
|
||||
@@ -71,31 +70,3 @@ pub fn match_comparison<'a, 'b>(
|
||||
bail!("Expected Expression::Comparison")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn match_dict<'a, 'b>(expression: &'a mut Expression<'b>) -> Result<&'a mut Dict<'b>> {
|
||||
if let Expression::Dict(dict) = expression {
|
||||
Ok(dict)
|
||||
} else {
|
||||
bail!("Expected Expression::Dict")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn match_attribute<'a, 'b>(
|
||||
expression: &'a mut Expression<'b>,
|
||||
) -> Result<&'a mut Attribute<'b>> {
|
||||
if let Expression::Attribute(attribute) = expression {
|
||||
Ok(attribute)
|
||||
} else {
|
||||
bail!("Expected Expression::Attribute")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn match_simple_string<'a, 'b>(
|
||||
expression: &'a mut Expression<'b>,
|
||||
) -> Result<&'a mut SimpleString<'b>> {
|
||||
if let Expression::SimpleString(simple_string) = expression {
|
||||
Ok(simple_string)
|
||||
} else {
|
||||
bail!("Expected Expression::SimpleString")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,13 +29,12 @@ pub struct Docstring<'a> {
|
||||
pub indentation: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum Documentable {
|
||||
Class,
|
||||
Function,
|
||||
}
|
||||
|
||||
pub fn transition_scope(scope: VisibleScope, stmt: &Stmt, kind: Documentable) -> VisibleScope {
|
||||
pub fn transition_scope(scope: &VisibleScope, stmt: &Stmt, kind: &Documentable) -> VisibleScope {
|
||||
match kind {
|
||||
Documentable::Function => VisibleScope {
|
||||
modifier: Modifier::Function,
|
||||
|
||||
@@ -2,18 +2,15 @@
|
||||
|
||||
use rustpython_parser::ast::{Constant, Expr, ExprKind, Stmt, StmtKind};
|
||||
|
||||
use ruff_python_ast::visibility::{Modifier, VisibleScope};
|
||||
|
||||
use crate::docstrings::definition::{Definition, DefinitionKind, Documentable};
|
||||
use ruff_python_ast::visibility::{Modifier, VisibleScope};
|
||||
|
||||
/// Extract a docstring from a function or class body.
|
||||
pub fn docstring_from(suite: &[Stmt]) -> Option<&Expr> {
|
||||
let stmt = suite.first()?;
|
||||
// Require the docstring to be a standalone expression.
|
||||
let StmtKind::Expr { value } = &stmt.node else {
|
||||
return None;
|
||||
};
|
||||
// Only match strings.
|
||||
if !matches!(
|
||||
&value.node,
|
||||
ExprKind::Constant {
|
||||
@@ -28,10 +25,10 @@ pub fn docstring_from(suite: &[Stmt]) -> Option<&Expr> {
|
||||
|
||||
/// Extract a `Definition` from the AST node defined by a `Stmt`.
|
||||
pub fn extract<'a>(
|
||||
scope: VisibleScope,
|
||||
scope: &VisibleScope,
|
||||
stmt: &'a Stmt,
|
||||
body: &'a [Stmt],
|
||||
kind: Documentable,
|
||||
kind: &Documentable,
|
||||
) -> Definition<'a> {
|
||||
let expr = docstring_from(body);
|
||||
match kind {
|
||||
|
||||
@@ -129,7 +129,7 @@ pub(crate) struct SectionContext<'a> {
|
||||
pub(crate) original_index: usize,
|
||||
}
|
||||
|
||||
fn suspected_as_section(line: &str, style: SectionStyle) -> Option<SectionKind> {
|
||||
fn suspected_as_section(line: &str, style: &SectionStyle) -> Option<SectionKind> {
|
||||
if let Some(kind) = SectionKind::from_str(whitespace::leading_words(line)) {
|
||||
if style.sections().contains(&kind) {
|
||||
return Some(kind);
|
||||
@@ -168,7 +168,7 @@ fn is_docstring_section(context: &SectionContext) -> bool {
|
||||
/// Extract all `SectionContext` values from a docstring.
|
||||
pub(crate) fn section_contexts<'a>(
|
||||
lines: &'a [&'a str],
|
||||
style: SectionStyle,
|
||||
style: &SectionStyle,
|
||||
) -> Vec<SectionContext<'a>> {
|
||||
let mut contexts = vec![];
|
||||
for (kind, lineno) in lines
|
||||
|
||||
@@ -2,7 +2,6 @@ use crate::docstrings::google::GOOGLE_SECTIONS;
|
||||
use crate::docstrings::numpy::NUMPY_SECTIONS;
|
||||
use crate::docstrings::sections::SectionKind;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub(crate) enum SectionStyle {
|
||||
Numpy,
|
||||
Google,
|
||||
|
||||
17
crates/ruff/src/fix.rs
Normal file
17
crates/ruff/src/fix.rs
Normal file
@@ -0,0 +1,17 @@
|
||||
#[derive(Debug, Copy, Clone, Hash)]
|
||||
pub enum FixMode {
|
||||
Generate,
|
||||
Apply,
|
||||
Diff,
|
||||
None,
|
||||
}
|
||||
|
||||
impl From<bool> for FixMode {
|
||||
fn from(value: bool) -> Self {
|
||||
if value {
|
||||
Self::Apply
|
||||
} else {
|
||||
Self::None
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user