Compare commits
34 Commits
v0.0.256
...
useless_re
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a7167520a | ||
|
|
41ab37e792 | ||
|
|
0b1806fdfa | ||
|
|
1dd3cbd047 | ||
|
|
bd935cbd49 | ||
|
|
babd0a05ac | ||
|
|
87fab4a2e1 | ||
|
|
2e21920adf | ||
|
|
dedf4cbdeb | ||
|
|
92179e6369 | ||
|
|
33d2457909 | ||
|
|
373a77e8c2 | ||
|
|
73df267635 | ||
|
|
f5e5caaa25 | ||
|
|
d9ed0aae69 | ||
|
|
e0df62b841 | ||
|
|
bbc87b7177 | ||
|
|
667130a4c3 | ||
|
|
72febf98b7 | ||
|
|
e99e1fae2b | ||
|
|
eff84442bc | ||
|
|
aa51ecedc5 | ||
|
|
9ae9cc9d2f | ||
|
|
de1106b95a | ||
|
|
d20474da87 | ||
|
|
b7df7ee370 | ||
|
|
d6f0d1fab2 | ||
|
|
c9bf979e61 | ||
|
|
e556fb4c77 | ||
|
|
02ae14037b | ||
|
|
385ccb2a50 | ||
|
|
ecacccbd5e | ||
|
|
bd7b472902 | ||
|
|
89b1b06dc7 |
133
.github/workflows/benchmark.yaml
vendored
Normal file
133
.github/workflows/benchmark.yaml
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
name: Benchmark
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.sha }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
run-benchmark:
|
||||
if: github.event_name == 'pull_request'
|
||||
name: "Run | ${{ matrix.os }}"
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- name: "PR - Checkout Branch"
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
- name: "PR - Install Rust toolchain"
|
||||
run: rustup show
|
||||
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
|
||||
- name: "PR - Build benchmarks"
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: bench
|
||||
args: -p ruff_benchmark --no-run
|
||||
|
||||
- name: "PR - Run benchmarks"
|
||||
run: cargo benchmark --save-baseline=pr
|
||||
|
||||
- name: "Main - Checkout Branch"
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
clean: false
|
||||
ref: main
|
||||
|
||||
- name: "Main - Install Rust toolchain"
|
||||
run: rustup show
|
||||
|
||||
- name: "Main - Build benchmarks"
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: bench
|
||||
args: -p ruff_benchmark --no-run
|
||||
|
||||
- name: "Main - Run benchmarks"
|
||||
run: cargo benchmark --save-baseline=main
|
||||
|
||||
- name: "Upload benchmark results"
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: benchmark-results-${{ matrix.os }}
|
||||
path: ./target/criterion
|
||||
|
||||
# Cleanup
|
||||
- name: Remove Criterion Artifact
|
||||
uses: JesseTG/rm@v1.0.3
|
||||
with:
|
||||
path: ./target/criterion
|
||||
|
||||
benchmark-compare:
|
||||
if: github.event_name == 'pull_request'
|
||||
runs-on: ubuntu-latest
|
||||
name: Compare
|
||||
needs:
|
||||
- run-benchmark
|
||||
|
||||
steps:
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup show
|
||||
|
||||
- name: "Install critcmp"
|
||||
# Use debug build: Building takes much longer than the "slowness" of using the debug build.
|
||||
run: cargo install --debug critcmp
|
||||
|
||||
- name: "Linux | Download PR benchmark results"
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: benchmark-results-ubuntu-latest
|
||||
path: ./target/criterion
|
||||
|
||||
- name: "Linux | Compare benchmark results"
|
||||
shell: bash
|
||||
run: |
|
||||
echo "### Benchmark" >> summary.md
|
||||
echo "#### Linux" >> summary.md
|
||||
echo "\`\`\`" >> summary.md
|
||||
critcmp main pr >> summary.md
|
||||
echo "\`\`\`" >> summary.md
|
||||
echo "" >> summary.md
|
||||
|
||||
- name: "Linux | Cleanup benchmark results"
|
||||
run: rm -rf ./target/criterion
|
||||
|
||||
- name: "Windows | Download PR benchmark results"
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: benchmark-results-windows-latest
|
||||
path: ./target/criterion
|
||||
|
||||
- name: "Windows | Compare benchmark results"
|
||||
shell: bash
|
||||
run: |
|
||||
echo "#### Windows" >> summary.md
|
||||
echo "\`\`\`" >> summary.md
|
||||
critcmp main pr >> summary.md
|
||||
echo "\`\`\`" >> summary.md
|
||||
echo "" >> summary.md
|
||||
|
||||
echo ${{ github.event.pull_request.number }} > pr-number
|
||||
|
||||
cat summary.md > $GITHUB_STEP_SUMMARY
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
name: Upload PR Number
|
||||
with:
|
||||
name: pr-number
|
||||
path: pr-number
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
name: Upload Summary
|
||||
with:
|
||||
name: summary
|
||||
path: summary.md
|
||||
19
.github/workflows/ci.yaml
vendored
19
.github/workflows/ci.yaml
vendored
@@ -80,6 +80,7 @@ jobs:
|
||||
# Setting RUSTDOCFLAGS because `cargo doc --check` isn't yet implemented (https://github.com/rust-lang/cargo/issues/10025).
|
||||
RUSTDOCFLAGS: "-D warnings"
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||
with:
|
||||
name: ruff
|
||||
path: target/debug/ruff
|
||||
@@ -139,27 +140,39 @@ jobs:
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.11"
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
name: Download Ruff binary
|
||||
id: ruff-target
|
||||
with:
|
||||
name: ruff
|
||||
path: target/debug
|
||||
|
||||
- uses: dawidd6/action-download-artifact@v2
|
||||
name: Download base results
|
||||
with:
|
||||
name: ruff
|
||||
branch: ${{ github.event.pull_request.base.ref }}
|
||||
check_artifacts: true
|
||||
|
||||
- name: Run ecosystem check
|
||||
run: |
|
||||
# Make executable, since artifact download doesn't preserve this
|
||||
chmod +x ruff ${{ steps.ruff-target.outputs.download-path }}/ruff
|
||||
|
||||
scripts/check_ecosystem.py ruff ${{ steps.ruff-target.outputs.download-path }}/ruff | tee ecosystem-result
|
||||
cat ecosystem-result > $GITHUB_STEP_SUMMARY
|
||||
|
||||
echo ${{ github.event.number }} > pr-number
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
name: Upload PR Number
|
||||
with:
|
||||
name: pr-number
|
||||
path: pr-number
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
name: Upload Results
|
||||
with:
|
||||
name: ecosystem-result
|
||||
path: |
|
||||
ecosystem-result
|
||||
pr-number
|
||||
path: ecosystem-result
|
||||
|
||||
31
.github/workflows/ecosystem-comment.yaml
vendored
31
.github/workflows/ecosystem-comment.yaml
vendored
@@ -1,31 +0,0 @@
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: [CI]
|
||||
types: [completed]
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
comment:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: dawidd6/action-download-artifact@v2
|
||||
id: download-result
|
||||
with:
|
||||
name: ecosystem-result
|
||||
workflow: ci.yaml
|
||||
run_id: ${{ github.event.workflow_run.id }}
|
||||
if_no_artifact_found: ignore
|
||||
- if: steps.download-result.outputs.found_artifact
|
||||
id: result
|
||||
run: |
|
||||
echo "pr-number=$(<pr-number)" >> $GITHUB_OUTPUT
|
||||
- name: Create comment
|
||||
if: steps.download-result.outputs.found_artifact
|
||||
uses: thollander/actions-comment-pull-request@v2
|
||||
with:
|
||||
pr_number: ${{ steps.result.outputs.pr-number }}
|
||||
filePath: ecosystem-result
|
||||
comment_tag: ecosystem-results
|
||||
83
.github/workflows/pr-comment.yaml
vendored
Normal file
83
.github/workflows/pr-comment.yaml
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
name: PR Check Comment
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: [CI, Benchmark]
|
||||
types: [completed]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
workflow_run_id:
|
||||
description: The ecosystem workflow that triggers the workflow run
|
||||
required: true
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
comment:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dawidd6/action-download-artifact@v2
|
||||
name: Download PR Number
|
||||
with:
|
||||
name: pr-number
|
||||
run_id: ${{ github.event.workflow_run.id || github.event.inputs.workflow_run_id }}
|
||||
if_no_artifact_found: ignore
|
||||
|
||||
- name: Extract PR Number
|
||||
id: pr-number
|
||||
run: |
|
||||
if [[ -f pr-number ]]
|
||||
then
|
||||
echo "pr-number=$(<pr-number)" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- uses: dawidd6/action-download-artifact@v2
|
||||
name: "Download Ecosystem Result"
|
||||
id: download-ecosystem-result
|
||||
if: steps.pr-number.outputs.pr-number
|
||||
with:
|
||||
name: ecosystem-result
|
||||
workflow: ci.yaml
|
||||
pr: ${{ steps.pr-number.outputs.pr-number }}
|
||||
path: pr/ecosystem
|
||||
if_no_artifact_found: ignore
|
||||
|
||||
- uses: dawidd6/action-download-artifact@v2
|
||||
name: "Download Benchmark Result"
|
||||
id: download-benchmark-result
|
||||
if: steps.pr-number.outputs.pr-number
|
||||
with:
|
||||
name: summary
|
||||
workflow: benchmark.yaml
|
||||
pr: ${{ steps.pr-number.outputs.pr-number }}
|
||||
path: pr/benchmark
|
||||
if_no_artifact_found: ignore
|
||||
|
||||
- name: Generate Comment
|
||||
id: generate-comment
|
||||
if: steps.download-ecosystem-result.outputs.found_artifact == 'true' || steps.download-benchmark-result.outputs.found_artifact == 'true'
|
||||
run: |
|
||||
echo 'comment<<EOF' >> $GITHUB_OUTPUT
|
||||
echo '## PR Check Results' >> $GITHUB_OUTPUT
|
||||
|
||||
if [[ -f pr/ecosystem/ecosystem-result ]]
|
||||
then
|
||||
echo "### Ecosystem" >> $GITHUB_OUTPUT
|
||||
cat pr/ecosystem/ecosystem-result >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
if [[ -f pr/benchmark/summary.md ]]
|
||||
then
|
||||
cat pr/benchmark/summary.md >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
echo 'EOF' >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Create or update comment
|
||||
if: steps.generate-comment.outputs.comment
|
||||
uses: thollander/actions-comment-pull-request@v2
|
||||
with:
|
||||
pr_number: ${{ steps.pr-number.outputs.pr-number }}
|
||||
message: ${{ steps.generate-comment.outputs.comment }}
|
||||
comment_tag: PR Check Results
|
||||
3
Cargo.lock
generated
3
Cargo.lock
generated
@@ -2041,7 +2041,10 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"criterion",
|
||||
"mimalloc",
|
||||
"once_cell",
|
||||
"ruff",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tikv-jemallocator",
|
||||
"ureq",
|
||||
"url",
|
||||
|
||||
@@ -309,6 +309,10 @@ Ruff is used in a number of major open-source projects, including:
|
||||
- [Starlite](https://github.com/starlite-api/starlite)
|
||||
- [telemetry-airflow (Mozilla)](https://github.com/mozilla/telemetry-airflow)
|
||||
- [Stable Baselines3](https://github.com/DLR-RM/stable-baselines3)
|
||||
- [PaddlePaddle](https://github.com/PaddlePaddle/Paddle)
|
||||
- [nox](https://github.com/wntrblm/nox)
|
||||
- [Neon](https://github.com/neondatabase/neon)
|
||||
- [The Algorithms](https://github.com/TheAlgorithms/Python)
|
||||
|
||||
## License
|
||||
|
||||
|
||||
11
crates/ruff/resources/test/fixtures/flake8_bugbear/B028.py
vendored
Normal file
11
crates/ruff/resources/test/fixtures/flake8_bugbear/B028.py
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
import warnings
|
||||
|
||||
"""
|
||||
Should emit:
|
||||
B028 - on lines 8 and 9
|
||||
"""
|
||||
|
||||
warnings.warn(DeprecationWarning("test"))
|
||||
warnings.warn(DeprecationWarning("test"), source=None)
|
||||
warnings.warn(DeprecationWarning("test"), source=None, stacklevel=2)
|
||||
warnings.warn(DeprecationWarning("test"), stacklevel=1)
|
||||
@@ -54,3 +54,7 @@ if type(a) != type(b) or type(a) == type(ccc):
|
||||
pass
|
||||
|
||||
assert type(res) == type(None)
|
||||
|
||||
types = StrEnum
|
||||
if x == types.X:
|
||||
pass
|
||||
|
||||
3
crates/ruff/resources/test/fixtures/pydocstyle/D209_D400.py
vendored
Normal file
3
crates/ruff/resources/test/fixtures/pydocstyle/D209_D400.py
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
def lorem():
|
||||
"""lorem ipsum dolor sit amet consectetur adipiscing elit
|
||||
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua"""
|
||||
@@ -58,6 +58,15 @@ def no_underline_and_no_description(): # noqa: D416
|
||||
"""
|
||||
|
||||
|
||||
@expect(_D213)
|
||||
@expect("D407: Missing dashed underline after section ('Returns')")
|
||||
@expect("D414: Section has no content ('Returns')")
|
||||
def no_underline_and_no_newline(): # noqa: D416
|
||||
"""Toggle the gizmo.
|
||||
|
||||
Returns"""
|
||||
|
||||
|
||||
@expect(_D213)
|
||||
@expect("D410: Missing blank line after section ('Returns')")
|
||||
@expect("D414: Section has no content ('Returns')")
|
||||
|
||||
@@ -17,3 +17,7 @@ def errors():
|
||||
def ok():
|
||||
if x and not y:
|
||||
print("x is not an empty string, but y is an empty string")
|
||||
|
||||
|
||||
data.loc[data["a"] != ""]
|
||||
data.loc[data["a"] != "", :]
|
||||
|
||||
95
crates/ruff/resources/test/fixtures/pylint/continue_in_finally.py
vendored
Normal file
95
crates/ruff/resources/test/fixtures/pylint/continue_in_finally.py
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
while True:
|
||||
try:
|
||||
pass
|
||||
finally:
|
||||
continue # [continue-in-finally]
|
||||
|
||||
while True:
|
||||
try:
|
||||
pass
|
||||
except Exception:
|
||||
continue
|
||||
finally:
|
||||
try:
|
||||
pass
|
||||
finally:
|
||||
continue # [continue-in-finally]
|
||||
pass
|
||||
|
||||
while True:
|
||||
try:
|
||||
pass
|
||||
finally:
|
||||
test = "aa"
|
||||
match test:
|
||||
case "aa":
|
||||
continue # [continue-in-finally]
|
||||
|
||||
while True:
|
||||
try:
|
||||
pass
|
||||
finally:
|
||||
with "aa" as f:
|
||||
continue # [continue-in-finally]
|
||||
|
||||
while True:
|
||||
try:
|
||||
pass
|
||||
finally:
|
||||
if True:
|
||||
continue # [continue-in-finally]
|
||||
continue # [continue-in-finally]
|
||||
|
||||
def test():
|
||||
while True:
|
||||
continue
|
||||
try:
|
||||
pass
|
||||
finally:
|
||||
continue # [continue-in-finally]
|
||||
|
||||
|
||||
while True:
|
||||
try:
|
||||
pass
|
||||
finally:
|
||||
continue # [continue-in-finally]
|
||||
|
||||
def test():
|
||||
while True:
|
||||
continue
|
||||
|
||||
|
||||
while True:
|
||||
try:
|
||||
pass
|
||||
finally:
|
||||
for i in range(12):
|
||||
continue
|
||||
continue # [continue-in-finally]
|
||||
|
||||
while True:
|
||||
pass
|
||||
else:
|
||||
continue # [continue-in-finally]
|
||||
|
||||
def test():
|
||||
continue
|
||||
while True:
|
||||
continue
|
||||
|
||||
|
||||
while True:
|
||||
try:
|
||||
pass
|
||||
finally:
|
||||
if True:
|
||||
pass
|
||||
elif False:
|
||||
continue # [continue-in-finally]
|
||||
else:
|
||||
continue # [continue-in-finally]
|
||||
for i in range(10):
|
||||
pass
|
||||
else:
|
||||
continue # [continue-in-finally]
|
||||
BIN
crates/ruff/resources/test/fixtures/pylint/invalid_characters.py
vendored
Normal file
BIN
crates/ruff/resources/test/fixtures/pylint/invalid_characters.py
vendored
Normal file
Binary file not shown.
39
crates/ruff/resources/test/fixtures/pylint/useless_return.py
vendored
Normal file
39
crates/ruff/resources/test/fixtures/pylint/useless_return.py
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
import sys
|
||||
|
||||
|
||||
def print_python_version():
|
||||
print(sys.version)
|
||||
return None # [useless-return]
|
||||
|
||||
|
||||
def print_python_version():
|
||||
print(sys.version)
|
||||
return None # [useless-return]
|
||||
|
||||
|
||||
def print_python_version():
|
||||
print(sys.version)
|
||||
return None # [useless-return]
|
||||
|
||||
|
||||
class SomeClass:
|
||||
def print_python_version(self):
|
||||
print(sys.version)
|
||||
return None # [useless-return]
|
||||
|
||||
|
||||
def print_python_version():
|
||||
if 2 * 2 == 4:
|
||||
return
|
||||
print(sys.version)
|
||||
|
||||
|
||||
def print_python_version():
|
||||
if 2 * 2 == 4:
|
||||
return None
|
||||
return
|
||||
|
||||
|
||||
def print_python_version():
|
||||
if 2 * 2 == 4:
|
||||
return None
|
||||
@@ -1,24 +1,29 @@
|
||||
# These should be changed
|
||||
# Error (`from unittest import mock`)
|
||||
if True:
|
||||
import mock
|
||||
|
||||
# Error (`from unittest import mock`)
|
||||
if True:
|
||||
import mock, sys
|
||||
|
||||
# This goes to from unitest import mock
|
||||
# Error (`from unittest.mock import *`)
|
||||
if True:
|
||||
from mock import *
|
||||
|
||||
# Error (`from unittest import mock`)
|
||||
import mock.mock
|
||||
|
||||
# Mock should go on a new line as `from unittest import mock`
|
||||
# Error (`from unittest import mock`)
|
||||
import contextlib, mock, sys
|
||||
|
||||
# Mock should go on a new line as `from unittest import mock`
|
||||
# Error (`from unittest import mock`)
|
||||
import mock, sys
|
||||
x = "This code should be preserved one line below the mock"
|
||||
|
||||
# Mock should go on a new line as `from unittest import mock`
|
||||
# Error (`from unittest import mock`)
|
||||
from mock import mock
|
||||
|
||||
# Should keep trailing comma
|
||||
# Error (keep trailing comma)
|
||||
from mock import (
|
||||
mock,
|
||||
a,
|
||||
@@ -32,7 +37,7 @@ from mock import (
|
||||
mock,
|
||||
)
|
||||
|
||||
# Should not get a trailing comma
|
||||
# Error (avoid trailing comma)
|
||||
from mock import (
|
||||
mock,
|
||||
a,
|
||||
@@ -57,16 +62,16 @@ if True:
|
||||
c
|
||||
)
|
||||
|
||||
# These should not change:
|
||||
# OK
|
||||
import os, io
|
||||
|
||||
# Mock should go on a new line as `from unittest import mock`
|
||||
# Error (`from unittest import mock`)
|
||||
import mock, mock
|
||||
|
||||
# Mock should go on a new line as `from unittest import mock as foo`
|
||||
# Error (`from unittest import mock as foo`)
|
||||
import mock as foo
|
||||
|
||||
# Mock should go on a new line as `from unittest import mock as foo`
|
||||
# Error (`from unittest import mock as foo`)
|
||||
from mock import mock as foo
|
||||
|
||||
if True:
|
||||
@@ -81,8 +86,8 @@ if True:
|
||||
from mock import mock as foo, mock as bar, mock
|
||||
|
||||
|
||||
# This should be unchanged.
|
||||
# OK.
|
||||
x = mock.Mock()
|
||||
|
||||
# This should change to `mock.Mock`().
|
||||
# Error (`mock.Mock()`).
|
||||
x = mock.mock.Mock()
|
||||
|
||||
19
crates/ruff/resources/test/fixtures/ruff/RUF007.py
vendored
Normal file
19
crates/ruff/resources/test/fixtures/ruff/RUF007.py
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
input = [1, 2, 3]
|
||||
otherInput = [2, 3, 4]
|
||||
|
||||
# OK
|
||||
zip(input, otherInput) # different inputs
|
||||
zip(input, otherInput[1:]) # different inputs
|
||||
zip(input, input[2:]) # not successive
|
||||
zip(input[:-1], input[2:]) # not successive
|
||||
list(zip(input, otherInput)) # nested call
|
||||
zip(input, input[1::2]) # not successive
|
||||
|
||||
# Errors
|
||||
zip(input, input[1:])
|
||||
zip(input, input[1::1])
|
||||
zip(input[:-1], input[1:])
|
||||
zip(input[1:], input[2:])
|
||||
zip(input[1:-1], input[2:])
|
||||
list(zip(input, input[1:]))
|
||||
list(zip(input[:-1], input[1:]))
|
||||
@@ -9,7 +9,7 @@ use ruff_python_ast::source_code::Locator;
|
||||
use ruff_python_ast::types::Range;
|
||||
|
||||
use crate::linter::FixTable;
|
||||
use crate::registry::AsRule;
|
||||
use crate::registry::{AsRule, Rule};
|
||||
|
||||
pub mod helpers;
|
||||
|
||||
@@ -39,7 +39,7 @@ fn apply_fixes<'a>(
|
||||
.as_ref()
|
||||
.map(|fix| (diagnostic.kind.rule(), fix))
|
||||
})
|
||||
.sorted_by_key(|(.., fix)| fix.location)
|
||||
.sorted_by(|(rule1, fix1), (rule2, fix2)| cmp_fix(*rule1, *rule2, fix1, fix2))
|
||||
{
|
||||
// If we already applied an identical fix as part of another correction, skip
|
||||
// any re-application.
|
||||
@@ -92,6 +92,18 @@ pub(crate) fn apply_fix(fix: &Fix, locator: &Locator) -> String {
|
||||
output
|
||||
}
|
||||
|
||||
/// Compare two fixes.
|
||||
fn cmp_fix(rule1: Rule, rule2: Rule, fix1: &Fix, fix2: &Fix) -> std::cmp::Ordering {
|
||||
fix1.location
|
||||
.cmp(&fix2.location)
|
||||
.then_with(|| match (&rule1, &rule2) {
|
||||
// Apply `EndsInPeriod` fixes before `NewLineAfterLastParagraph` fixes.
|
||||
(Rule::EndsInPeriod, Rule::NewLineAfterLastParagraph) => std::cmp::Ordering::Less,
|
||||
(Rule::NewLineAfterLastParagraph, Rule::EndsInPeriod) => std::cmp::Ordering::Greater,
|
||||
_ => std::cmp::Ordering::Equal,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use rustpython_parser::ast::Location;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use ruff_python_ast::scope::ScopeStack;
|
||||
use rustpython_parser::ast::{Expr, Stmt};
|
||||
|
||||
use ruff_python_ast::types::Range;
|
||||
@@ -7,7 +8,7 @@ use ruff_python_ast::visibility::{Visibility, VisibleScope};
|
||||
use crate::checkers::ast::AnnotationContext;
|
||||
use crate::docstrings::definition::Definition;
|
||||
|
||||
type Context<'a> = (Vec<usize>, Vec<RefEquality<'a, Stmt>>);
|
||||
type Context<'a> = (ScopeStack, Vec<RefEquality<'a, Stmt>>);
|
||||
|
||||
/// A collection of AST nodes that are deferred for later analysis.
|
||||
/// Used to, e.g., store functions, whose bodies shouldn't be analyzed until all
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -15,7 +15,7 @@ pub fn check_file_path(
|
||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||
|
||||
// flake8-no-pep420
|
||||
if settings.rules.enabled(&Rule::ImplicitNamespacePackage) {
|
||||
if settings.rules.enabled(Rule::ImplicitNamespacePackage) {
|
||||
if let Some(diagnostic) =
|
||||
implicit_namespace_package(path, package, &settings.project_root, &settings.src)
|
||||
{
|
||||
@@ -24,7 +24,7 @@ pub fn check_file_path(
|
||||
}
|
||||
|
||||
// pep8-naming
|
||||
if settings.rules.enabled(&Rule::InvalidModuleName) {
|
||||
if settings.rules.enabled(Rule::InvalidModuleName) {
|
||||
if let Some(diagnostic) = invalid_module_name(path, package) {
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ pub fn check_imports(
|
||||
|
||||
// Enforce import rules.
|
||||
let mut diagnostics = vec![];
|
||||
if settings.rules.enabled(&Rule::UnsortedImports) {
|
||||
if settings.rules.enabled(Rule::UnsortedImports) {
|
||||
for block in &blocks {
|
||||
if !block.imports.is_empty() {
|
||||
if let Some(diagnostic) = isort::rules::organize_imports(
|
||||
@@ -49,7 +49,7 @@ pub fn check_imports(
|
||||
}
|
||||
}
|
||||
}
|
||||
if settings.rules.enabled(&Rule::MissingRequiredImport) {
|
||||
if settings.rules.enabled(Rule::MissingRequiredImport) {
|
||||
diagnostics.extend(isort::rules::add_required_imports(
|
||||
&blocks, python_ast, locator, stylist, settings, autofix,
|
||||
));
|
||||
|
||||
@@ -166,7 +166,7 @@ pub fn check_logical_lines(
|
||||
}
|
||||
|
||||
#[cfg(feature = "logical_lines")]
|
||||
let should_fix = autofix.into() && settings.rules.should_fix(&Rule::MissingWhitespace);
|
||||
let should_fix = autofix.into() && settings.rules.should_fix(Rule::MissingWhitespace);
|
||||
|
||||
#[cfg(not(feature = "logical_lines"))]
|
||||
let should_fix = false;
|
||||
@@ -181,7 +181,7 @@ pub fn check_logical_lines(
|
||||
if line.flags.contains(TokenFlags::BRACKET) {
|
||||
#[cfg(feature = "logical_lines")]
|
||||
let should_fix =
|
||||
autofix.into() && settings.rules.should_fix(&Rule::WhitespaceBeforeParameters);
|
||||
autofix.into() && settings.rules.should_fix(Rule::WhitespaceBeforeParameters);
|
||||
|
||||
#[cfg(not(feature = "logical_lines"))]
|
||||
let should_fix = false;
|
||||
|
||||
@@ -24,7 +24,7 @@ pub fn check_noqa(
|
||||
settings: &Settings,
|
||||
autofix: flags::Autofix,
|
||||
) -> Vec<usize> {
|
||||
let enforce_noqa = settings.rules.enabled(&Rule::UnusedNOQA);
|
||||
let enforce_noqa = settings.rules.enabled(Rule::UnusedNOQA);
|
||||
|
||||
// Whether the file is exempted from all checks.
|
||||
let mut file_exempted = false;
|
||||
@@ -188,7 +188,7 @@ pub fn check_noqa(
|
||||
valid_codes.push(code);
|
||||
} else {
|
||||
if let Ok(rule) = Rule::from_code(code) {
|
||||
if settings.rules.enabled(&rule) {
|
||||
if settings.rules.enabled(rule) {
|
||||
unmatched_codes.push(code);
|
||||
} else {
|
||||
disabled_codes.push(code);
|
||||
|
||||
@@ -32,28 +32,28 @@ pub fn check_physical_lines(
|
||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||
let mut has_any_shebang = false;
|
||||
|
||||
let enforce_blanket_noqa = settings.rules.enabled(&Rule::BlanketNOQA);
|
||||
let enforce_shebang_not_executable = settings.rules.enabled(&Rule::ShebangNotExecutable);
|
||||
let enforce_shebang_missing = settings.rules.enabled(&Rule::ShebangMissingExecutableFile);
|
||||
let enforce_shebang_whitespace = settings.rules.enabled(&Rule::ShebangWhitespace);
|
||||
let enforce_shebang_newline = settings.rules.enabled(&Rule::ShebangNewline);
|
||||
let enforce_shebang_python = settings.rules.enabled(&Rule::ShebangPython);
|
||||
let enforce_blanket_type_ignore = settings.rules.enabled(&Rule::BlanketTypeIgnore);
|
||||
let enforce_doc_line_too_long = settings.rules.enabled(&Rule::DocLineTooLong);
|
||||
let enforce_line_too_long = settings.rules.enabled(&Rule::LineTooLong);
|
||||
let enforce_no_newline_at_end_of_file = settings.rules.enabled(&Rule::NoNewLineAtEndOfFile);
|
||||
let enforce_unnecessary_coding_comment = settings.rules.enabled(&Rule::UTF8EncodingDeclaration);
|
||||
let enforce_mixed_spaces_and_tabs = settings.rules.enabled(&Rule::MixedSpacesAndTabs);
|
||||
let enforce_bidirectional_unicode = settings.rules.enabled(&Rule::BidirectionalUnicode);
|
||||
let enforce_trailing_whitespace = settings.rules.enabled(&Rule::TrailingWhitespace);
|
||||
let enforce_blanket_noqa = settings.rules.enabled(Rule::BlanketNOQA);
|
||||
let enforce_shebang_not_executable = settings.rules.enabled(Rule::ShebangNotExecutable);
|
||||
let enforce_shebang_missing = settings.rules.enabled(Rule::ShebangMissingExecutableFile);
|
||||
let enforce_shebang_whitespace = settings.rules.enabled(Rule::ShebangWhitespace);
|
||||
let enforce_shebang_newline = settings.rules.enabled(Rule::ShebangNewline);
|
||||
let enforce_shebang_python = settings.rules.enabled(Rule::ShebangPython);
|
||||
let enforce_blanket_type_ignore = settings.rules.enabled(Rule::BlanketTypeIgnore);
|
||||
let enforce_doc_line_too_long = settings.rules.enabled(Rule::DocLineTooLong);
|
||||
let enforce_line_too_long = settings.rules.enabled(Rule::LineTooLong);
|
||||
let enforce_no_newline_at_end_of_file = settings.rules.enabled(Rule::NoNewLineAtEndOfFile);
|
||||
let enforce_unnecessary_coding_comment = settings.rules.enabled(Rule::UTF8EncodingDeclaration);
|
||||
let enforce_mixed_spaces_and_tabs = settings.rules.enabled(Rule::MixedSpacesAndTabs);
|
||||
let enforce_bidirectional_unicode = settings.rules.enabled(Rule::BidirectionalUnicode);
|
||||
let enforce_trailing_whitespace = settings.rules.enabled(Rule::TrailingWhitespace);
|
||||
let enforce_blank_line_contains_whitespace =
|
||||
settings.rules.enabled(&Rule::BlankLineContainsWhitespace);
|
||||
let enforce_indentation_contains_tabs = settings.rules.enabled(&Rule::IndentationContainsTabs);
|
||||
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);
|
||||
autofix.into() && settings.rules.should_fix(Rule::UTF8EncodingDeclaration);
|
||||
let fix_shebang_whitespace =
|
||||
autofix.into() && settings.rules.should_fix(&Rule::ShebangWhitespace);
|
||||
autofix.into() && settings.rules.should_fix(Rule::ShebangWhitespace);
|
||||
|
||||
let mut commented_lines_iter = commented_lines.iter().peekable();
|
||||
let mut doc_lines_iter = doc_lines.iter().peekable();
|
||||
@@ -165,7 +165,7 @@ pub fn check_physical_lines(
|
||||
if let Some(diagnostic) = no_newline_at_end_of_file(
|
||||
locator,
|
||||
stylist,
|
||||
autofix.into() && settings.rules.should_fix(&Rule::NoNewLineAtEndOfFile),
|
||||
autofix.into() && settings.rules.should_fix(Rule::NoNewLineAtEndOfFile),
|
||||
) {
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::registry::{AsRule, Rule};
|
||||
use crate::rules::ruff::rules::Context;
|
||||
use crate::rules::{
|
||||
eradicate, flake8_commas, flake8_implicit_str_concat, flake8_pyi, flake8_quotes, pycodestyle,
|
||||
pyupgrade, ruff,
|
||||
pylint, pyupgrade, ruff,
|
||||
};
|
||||
use crate::settings::{flags, Settings};
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
@@ -23,41 +23,43 @@ pub fn check_tokens(
|
||||
) -> Vec<Diagnostic> {
|
||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||
|
||||
let enforce_ambiguous_unicode_character = settings
|
||||
.rules
|
||||
.enabled(&Rule::AmbiguousUnicodeCharacterString)
|
||||
|| settings
|
||||
.rules
|
||||
.enabled(&Rule::AmbiguousUnicodeCharacterDocstring)
|
||||
|| settings
|
||||
.rules
|
||||
.enabled(&Rule::AmbiguousUnicodeCharacterComment);
|
||||
let enforce_quotes = settings.rules.enabled(&Rule::BadQuotesInlineString)
|
||||
|| settings.rules.enabled(&Rule::BadQuotesMultilineString)
|
||||
|| settings.rules.enabled(&Rule::BadQuotesDocstring)
|
||||
|| settings.rules.enabled(&Rule::AvoidableEscapedQuote);
|
||||
let enforce_commented_out_code = settings.rules.enabled(&Rule::CommentedOutCode);
|
||||
let enforce_compound_statements = settings
|
||||
.rules
|
||||
.enabled(&Rule::MultipleStatementsOnOneLineColon)
|
||||
|| settings
|
||||
.rules
|
||||
.enabled(&Rule::MultipleStatementsOnOneLineSemicolon)
|
||||
|| settings.rules.enabled(&Rule::UselessSemicolon);
|
||||
let enforce_invalid_escape_sequence = settings.rules.enabled(&Rule::InvalidEscapeSequence);
|
||||
let enforce_implicit_string_concatenation = settings
|
||||
.rules
|
||||
.enabled(&Rule::SingleLineImplicitStringConcatenation)
|
||||
|| settings
|
||||
.rules
|
||||
.enabled(&Rule::MultiLineImplicitStringConcatenation);
|
||||
let enforce_trailing_comma = settings.rules.enabled(&Rule::TrailingCommaMissing)
|
||||
|| settings
|
||||
.rules
|
||||
.enabled(&Rule::TrailingCommaOnBareTupleProhibited)
|
||||
|| settings.rules.enabled(&Rule::TrailingCommaProhibited);
|
||||
let enforce_extraneous_parenthesis = settings.rules.enabled(&Rule::ExtraneousParentheses);
|
||||
let enforce_type_comment_in_stub = settings.rules.enabled(&Rule::TypeCommentInStub);
|
||||
let enforce_ambiguous_unicode_character = settings.rules.any_enabled(&[
|
||||
Rule::AmbiguousUnicodeCharacterString,
|
||||
Rule::AmbiguousUnicodeCharacterDocstring,
|
||||
Rule::AmbiguousUnicodeCharacterComment,
|
||||
]);
|
||||
let enforce_invalid_string_character = settings.rules.any_enabled(&[
|
||||
Rule::InvalidCharacterBackspace,
|
||||
Rule::InvalidCharacterSub,
|
||||
Rule::InvalidCharacterEsc,
|
||||
Rule::InvalidCharacterNul,
|
||||
Rule::InvalidCharacterZeroWidthSpace,
|
||||
]);
|
||||
let enforce_quotes = settings.rules.any_enabled(&[
|
||||
Rule::BadQuotesInlineString,
|
||||
Rule::BadQuotesMultilineString,
|
||||
Rule::BadQuotesDocstring,
|
||||
Rule::AvoidableEscapedQuote,
|
||||
]);
|
||||
let enforce_commented_out_code = settings.rules.enabled(Rule::CommentedOutCode);
|
||||
let enforce_compound_statements = settings.rules.any_enabled(&[
|
||||
Rule::MultipleStatementsOnOneLineColon,
|
||||
Rule::MultipleStatementsOnOneLineSemicolon,
|
||||
Rule::UselessSemicolon,
|
||||
]);
|
||||
let enforce_invalid_escape_sequence = settings.rules.enabled(Rule::InvalidEscapeSequence);
|
||||
let enforce_implicit_string_concatenation = settings.rules.any_enabled(&[
|
||||
Rule::SingleLineImplicitStringConcatenation,
|
||||
Rule::MultiLineImplicitStringConcatenation,
|
||||
]);
|
||||
|
||||
let enforce_trailing_comma = settings.rules.any_enabled(&[
|
||||
Rule::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);
|
||||
|
||||
// RUF001, RUF002, RUF003
|
||||
if enforce_ambiguous_unicode_character {
|
||||
@@ -111,11 +113,23 @@ pub fn check_tokens(
|
||||
locator,
|
||||
*start,
|
||||
*end,
|
||||
autofix.into() && settings.rules.should_fix(&Rule::InvalidEscapeSequence),
|
||||
autofix.into() && settings.rules.should_fix(Rule::InvalidEscapeSequence),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
// PLE2510, PLE2512, PLE2513
|
||||
if enforce_invalid_string_character {
|
||||
for (start, tok, end) in tokens.iter().flatten() {
|
||||
if matches!(tok, Tok::String { .. }) {
|
||||
diagnostics.extend(
|
||||
pylint::rules::invalid_string_characters(locator, *start, *end, autofix.into())
|
||||
.into_iter()
|
||||
.filter(|diagnostic| settings.rules.enabled(diagnostic.kind.rule())),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// E701, E702, E703
|
||||
if enforce_compound_statements {
|
||||
|
||||
@@ -166,11 +166,11 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Pylint, "C3002") => Rule::UnnecessaryDirectLambdaCall,
|
||||
(Pylint, "E0100") => Rule::YieldInInit,
|
||||
(Pylint, "E0101") => Rule::ReturnInInit,
|
||||
(Pylint, "E0116") => Rule::ContinueInFinally,
|
||||
(Pylint, "E0117") => Rule::NonlocalWithoutBinding,
|
||||
(Pylint, "E0118") => Rule::UsedPriorGlobalDeclaration,
|
||||
(Pylint, "E0604") => Rule::InvalidAllObject,
|
||||
(Pylint, "E0605") => Rule::InvalidAllFormat,
|
||||
(Pylint, "W1508") => Rule::InvalidEnvvarDefault,
|
||||
(Pylint, "E1142") => Rule::AwaitOutsideAsync,
|
||||
(Pylint, "E1205") => Rule::LoggingTooManyArgs,
|
||||
(Pylint, "E1206") => Rule::LoggingTooFewArgs,
|
||||
@@ -178,6 +178,11 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Pylint, "E1310") => Rule::BadStrStripCall,
|
||||
(Pylint, "E1507") => Rule::InvalidEnvvarValue,
|
||||
(Pylint, "E2502") => Rule::BidirectionalUnicode,
|
||||
(Pylint, "E2510") => Rule::InvalidCharacterBackspace,
|
||||
(Pylint, "E2512") => Rule::InvalidCharacterSub,
|
||||
(Pylint, "E2513") => Rule::InvalidCharacterEsc,
|
||||
(Pylint, "E2514") => Rule::InvalidCharacterNul,
|
||||
(Pylint, "E2515") => Rule::InvalidCharacterZeroWidthSpace,
|
||||
(Pylint, "R0133") => Rule::ComparisonOfConstant,
|
||||
(Pylint, "R0206") => Rule::PropertyWithParameters,
|
||||
(Pylint, "R0402") => Rule::ConsiderUsingFromImport,
|
||||
@@ -186,12 +191,14 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Pylint, "R0913") => Rule::TooManyArguments,
|
||||
(Pylint, "R0915") => Rule::TooManyStatements,
|
||||
(Pylint, "R1701") => Rule::ConsiderMergingIsinstance,
|
||||
(Pylint, "R1711") => Rule::UselessReturn,
|
||||
(Pylint, "R1722") => Rule::ConsiderUsingSysExit,
|
||||
(Pylint, "R2004") => Rule::MagicValueComparison,
|
||||
(Pylint, "R5501") => Rule::CollapsibleElseIf,
|
||||
(Pylint, "W0120") => Rule::UselessElseOnLoop,
|
||||
(Pylint, "W0602") => Rule::GlobalVariableNotAssigned,
|
||||
(Pylint, "W0603") => Rule::GlobalStatement,
|
||||
(Pylint, "W1508") => Rule::InvalidEnvvarDefault,
|
||||
(Pylint, "W2901") => Rule::RedefinedLoopName,
|
||||
|
||||
// flake8-builtins
|
||||
@@ -226,6 +233,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Flake8Bugbear, "025") => Rule::DuplicateTryBlockException,
|
||||
(Flake8Bugbear, "026") => Rule::StarArgUnpackingAfterKeywordArg,
|
||||
(Flake8Bugbear, "027") => Rule::EmptyMethodWithoutAbstractDecorator,
|
||||
(Flake8Bugbear, "028") => Rule::NoExplicitStacklevel,
|
||||
(Flake8Bugbear, "029") => Rule::ExceptWithEmptyTuple,
|
||||
(Flake8Bugbear, "030") => Rule::ExceptWithNonExceptionClasses,
|
||||
(Flake8Bugbear, "032") => Rule::UnintentionalTypeAnnotation,
|
||||
@@ -660,6 +668,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
(Ruff, "003") => Rule::AmbiguousUnicodeCharacterComment,
|
||||
(Ruff, "005") => Rule::UnpackInsteadOfConcatenatingToCollectionLiteral,
|
||||
(Ruff, "006") => Rule::AsyncioDanglingTask,
|
||||
(Ruff, "007") => Rule::PairwiseOverZipped,
|
||||
(Ruff, "100") => Rule::UnusedNOQA,
|
||||
|
||||
// flake8-django
|
||||
|
||||
@@ -22,11 +22,12 @@ pub fn extract_path_names(path: &Path) -> Result<(&str, &str)> {
|
||||
}
|
||||
|
||||
/// Create a set with codes matching the pattern/code pairs.
|
||||
pub(crate) fn ignores_from_path<'a>(
|
||||
pub(crate) fn ignores_from_path(
|
||||
path: &Path,
|
||||
pattern_code_pairs: &'a [(GlobMatcher, GlobMatcher, FxHashSet<Rule>)],
|
||||
) -> FxHashSet<&'a Rule> {
|
||||
pattern_code_pairs: &[(GlobMatcher, GlobMatcher, FxHashSet<Rule>)],
|
||||
) -> FxHashSet<Rule> {
|
||||
let (file_path, file_basename) = extract_path_names(path).expect("Unable to parse filename");
|
||||
|
||||
pattern_code_pairs
|
||||
.iter()
|
||||
.filter_map(|(absolute, basename, codes)| {
|
||||
@@ -37,20 +38,21 @@ pub(crate) fn ignores_from_path<'a>(
|
||||
basename.glob().regex(),
|
||||
codes
|
||||
);
|
||||
return Some(codes.iter());
|
||||
}
|
||||
if absolute.is_match(file_path) {
|
||||
Some(codes)
|
||||
} else if absolute.is_match(file_path) {
|
||||
debug!(
|
||||
"Adding per-file ignores for {:?} due to absolute match on {:?}: {:?}",
|
||||
path,
|
||||
absolute.glob().regex(),
|
||||
codes
|
||||
);
|
||||
return Some(codes.iter());
|
||||
Some(codes)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
None
|
||||
})
|
||||
.flatten()
|
||||
.copied()
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ impl<T> LinterResult<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub type FixTable = FxHashMap<&'static Rule, usize>;
|
||||
pub type FixTable = FxHashMap<Rule, usize>;
|
||||
|
||||
/// Generate `Diagnostic`s from the source code contents at the
|
||||
/// given `Path`.
|
||||
@@ -74,7 +74,7 @@ pub fn check_path(
|
||||
|
||||
// Collect doc lines. This requires a rare mix of tokens (for comments) and AST
|
||||
// (for docstrings), which demands special-casing at this level.
|
||||
let use_doc_lines = settings.rules.enabled(&Rule::DocLineTooLong);
|
||||
let use_doc_lines = settings.rules.enabled(Rule::DocLineTooLong);
|
||||
let mut doc_lines = vec![];
|
||||
if use_doc_lines {
|
||||
doc_lines.extend(doc_lines_from_tokens(&tokens));
|
||||
@@ -159,14 +159,14 @@ pub fn check_path(
|
||||
}
|
||||
}
|
||||
Err(parse_error) => {
|
||||
if settings.rules.enabled(&Rule::SyntaxError) {
|
||||
if settings.rules.enabled(Rule::SyntaxError) {
|
||||
pycodestyle::rules::syntax_error(&mut diagnostics, &parse_error);
|
||||
}
|
||||
|
||||
// If the syntax error is ignored, suppress it (regardless of whether
|
||||
// `Rule::SyntaxError` is enabled).
|
||||
if !rule_is_ignored(
|
||||
&Rule::SyntaxError,
|
||||
Rule::SyntaxError,
|
||||
parse_error.location.row(),
|
||||
&directives.noqa_line_for,
|
||||
locator,
|
||||
@@ -204,7 +204,7 @@ pub fn check_path(
|
||||
if !diagnostics.is_empty() && !settings.per_file_ignores.is_empty() {
|
||||
let ignores = fs::ignores_from_path(path, &settings.per_file_ignores);
|
||||
if !ignores.is_empty() {
|
||||
diagnostics.retain(|diagnostic| !ignores.contains(diagnostic.kind.rule()));
|
||||
diagnostics.retain(|diagnostic| !ignores.contains(&diagnostic.kind.rule()));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ pub fn extract_noqa_directive(line: &str) -> Directive {
|
||||
|
||||
/// Returns `true` if the string list of `codes` includes `code` (or an alias
|
||||
/// thereof).
|
||||
pub fn includes(needle: &Rule, haystack: &[&str]) -> bool {
|
||||
pub fn includes(needle: Rule, haystack: &[&str]) -> bool {
|
||||
let needle = needle.noqa_code();
|
||||
haystack
|
||||
.iter()
|
||||
@@ -130,7 +130,7 @@ pub fn includes(needle: &Rule, haystack: &[&str]) -> bool {
|
||||
|
||||
/// Returns `true` if the given [`Rule`] is ignored at the specified `lineno`.
|
||||
pub fn rule_is_ignored(
|
||||
code: &Rule,
|
||||
code: Rule,
|
||||
lineno: usize,
|
||||
noqa_line_for: &IntMap<usize, usize>,
|
||||
locator: &Locator,
|
||||
@@ -174,7 +174,7 @@ fn add_noqa_inner(
|
||||
line_ending: &LineEnding,
|
||||
) -> (usize, String) {
|
||||
// Map of line number to set of (non-ignored) diagnostic codes that are triggered on that line.
|
||||
let mut matches_by_line: FxHashMap<usize, FxHashSet<&Rule>> = FxHashMap::default();
|
||||
let mut matches_by_line: FxHashMap<usize, FxHashSet<Rule>> = FxHashMap::default();
|
||||
|
||||
// Whether the file is exempted from all checks.
|
||||
let mut file_exempted = false;
|
||||
@@ -280,7 +280,7 @@ fn add_noqa_inner(
|
||||
output.push_str(" # noqa: ");
|
||||
|
||||
// Add codes.
|
||||
push_codes(&mut output, rules.iter().map(|r| r.noqa_code()));
|
||||
push_codes(&mut output, rules.iter().map(Rule::noqa_code));
|
||||
output.push_str(line_ending);
|
||||
count += 1;
|
||||
}
|
||||
|
||||
@@ -143,6 +143,7 @@ ruff_macros::register_rules!(
|
||||
rules::pyflakes::rules::UnusedAnnotation,
|
||||
rules::pyflakes::rules::RaiseNotImplemented,
|
||||
// pylint
|
||||
rules::pylint::rules::UselessReturn,
|
||||
rules::pylint::rules::YieldInInit,
|
||||
rules::pylint::rules::InvalidAllObject,
|
||||
rules::pylint::rules::InvalidAllFormat,
|
||||
@@ -150,8 +151,14 @@ ruff_macros::register_rules!(
|
||||
rules::pylint::rules::InvalidEnvvarValue,
|
||||
rules::pylint::rules::BadStringFormatType,
|
||||
rules::pylint::rules::BidirectionalUnicode,
|
||||
rules::pylint::rules::InvalidCharacterBackspace,
|
||||
rules::pylint::rules::InvalidCharacterSub,
|
||||
rules::pylint::rules::InvalidCharacterEsc,
|
||||
rules::pylint::rules::InvalidCharacterNul,
|
||||
rules::pylint::rules::InvalidCharacterZeroWidthSpace,
|
||||
rules::pylint::rules::BadStrStripCall,
|
||||
rules::pylint::rules::CollapsibleElseIf,
|
||||
rules::pylint::rules::ContinueInFinally,
|
||||
rules::pylint::rules::UselessImportAlias,
|
||||
rules::pylint::rules::UnnecessaryDirectLambdaCall,
|
||||
rules::pylint::rules::NonlocalWithoutBinding,
|
||||
@@ -185,6 +192,7 @@ ruff_macros::register_rules!(
|
||||
rules::flake8_bugbear::rules::UnreliableCallableCheck,
|
||||
rules::flake8_bugbear::rules::StripWithMultiCharacters,
|
||||
rules::flake8_bugbear::rules::MutableArgumentDefault,
|
||||
rules::flake8_bugbear::rules::NoExplicitStacklevel,
|
||||
rules::flake8_bugbear::rules::UnusedLoopControlVariable,
|
||||
rules::flake8_bugbear::rules::FunctionCallArgumentDefault,
|
||||
rules::flake8_bugbear::rules::GetAttrWithConstant,
|
||||
@@ -601,6 +609,7 @@ ruff_macros::register_rules!(
|
||||
rules::ruff::rules::UnpackInsteadOfConcatenatingToCollectionLiteral,
|
||||
rules::ruff::rules::AsyncioDanglingTask,
|
||||
rules::ruff::rules::UnusedNOQA,
|
||||
rules::ruff::rules::PairwiseOverZipped,
|
||||
// flake8-django
|
||||
rules::flake8_django::rules::NullableModelStringField,
|
||||
rules::flake8_django::rules::LocalsInRenderFunction,
|
||||
@@ -610,6 +619,10 @@ ruff_macros::register_rules!(
|
||||
rules::flake8_django::rules::NonLeadingReceiverDecorator,
|
||||
);
|
||||
|
||||
pub trait AsRule {
|
||||
fn rule(&self) -> Rule;
|
||||
}
|
||||
|
||||
impl Rule {
|
||||
pub fn from_code(code: &str) -> Result<Self, FromCodeError> {
|
||||
let (linter, code) = Linter::parse_code(code).ok_or(FromCodeError::Unknown)?;
|
||||
@@ -848,6 +861,11 @@ impl Rule {
|
||||
| Rule::BadQuotesMultilineString
|
||||
| Rule::CommentedOutCode
|
||||
| Rule::MultiLineImplicitStringConcatenation
|
||||
| Rule::InvalidCharacterBackspace
|
||||
| Rule::InvalidCharacterSub
|
||||
| Rule::InvalidCharacterEsc
|
||||
| Rule::InvalidCharacterNul
|
||||
| Rule::InvalidCharacterZeroWidthSpace
|
||||
| Rule::ExtraneousParentheses
|
||||
| Rule::InvalidEscapeSequence
|
||||
| Rule::SingleLineImplicitStringConcatenation
|
||||
@@ -916,6 +934,7 @@ pub const INCOMPATIBLE_CODES: &[(Rule, Rule, &str); 2] = &[
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::mem::size_of;
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use super::{Linter, Rule, RuleNamespace};
|
||||
@@ -961,4 +980,9 @@ mod tests {
|
||||
assert_eq!(code, format!("{}{rest}", linter.common_prefix()));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rule_size() {
|
||||
assert_eq!(2, size_of::<Rule>());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ pub fn commented_out_code(
|
||||
// Verify that the comment is on its own line, and that it contains code.
|
||||
if is_standalone_comment(line) && comment_contains_code(line, &settings.task_tags[..]) {
|
||||
let mut diagnostic = Diagnostic::new(CommentedOutCode, Range::new(start, end));
|
||||
if autofix.into() && settings.rules.should_fix(&Rule::CommentedOutCode) {
|
||||
if autofix.into() && settings.rules.should_fix(Rule::CommentedOutCode) {
|
||||
diagnostic.amend(Fix::deletion(location, end_location));
|
||||
}
|
||||
Some(diagnostic)
|
||||
|
||||
@@ -140,7 +140,7 @@ pub fn subscript(checker: &mut Checker, value: &Expr, slice: &Expr) {
|
||||
&& checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::SysVersionSlice1Referenced)
|
||||
.enabled(Rule::SysVersionSlice1Referenced)
|
||||
{
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
SysVersionSlice1Referenced,
|
||||
@@ -150,7 +150,7 @@ pub fn subscript(checker: &mut Checker, value: &Expr, slice: &Expr) {
|
||||
&& checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::SysVersionSlice3Referenced)
|
||||
.enabled(Rule::SysVersionSlice3Referenced)
|
||||
{
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
SysVersionSlice3Referenced,
|
||||
@@ -165,13 +165,13 @@ pub fn subscript(checker: &mut Checker, value: &Expr, slice: &Expr) {
|
||||
..
|
||||
} => {
|
||||
if *i == BigInt::from(2)
|
||||
&& checker.settings.rules.enabled(&Rule::SysVersion2Referenced)
|
||||
&& checker.settings.rules.enabled(Rule::SysVersion2Referenced)
|
||||
{
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(SysVersion2Referenced, Range::from(value)));
|
||||
} else if *i == BigInt::from(0)
|
||||
&& checker.settings.rules.enabled(&Rule::SysVersion0Referenced)
|
||||
&& checker.settings.rules.enabled(Rule::SysVersion0Referenced)
|
||||
{
|
||||
checker
|
||||
.diagnostics
|
||||
@@ -210,7 +210,7 @@ pub fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], comparators: &
|
||||
&& checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::SysVersionInfo0Eq3Referenced)
|
||||
.enabled(Rule::SysVersionInfo0Eq3Referenced)
|
||||
{
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
SysVersionInfo0Eq3Referenced,
|
||||
@@ -231,7 +231,7 @@ pub fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], comparators: &
|
||||
}],
|
||||
) = (ops, comparators)
|
||||
{
|
||||
if checker.settings.rules.enabled(&Rule::SysVersionInfo1CmpInt) {
|
||||
if checker.settings.rules.enabled(Rule::SysVersionInfo1CmpInt) {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(SysVersionInfo1CmpInt, Range::from(left)));
|
||||
@@ -259,7 +259,7 @@ pub fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], comparators: &
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::SysVersionInfoMinorCmpInt)
|
||||
.enabled(Rule::SysVersionInfoMinorCmpInt)
|
||||
{
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
SysVersionInfoMinorCmpInt,
|
||||
@@ -286,12 +286,12 @@ pub fn compare(checker: &mut Checker, left: &Expr, ops: &[Cmpop], comparators: &
|
||||
) = (ops, comparators)
|
||||
{
|
||||
if s.len() == 1 {
|
||||
if checker.settings.rules.enabled(&Rule::SysVersionCmpStr10) {
|
||||
if checker.settings.rules.enabled(Rule::SysVersionCmpStr10) {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(SysVersionCmpStr10, Range::from(left)));
|
||||
}
|
||||
} else if checker.settings.rules.enabled(&Rule::SysVersionCmpStr3) {
|
||||
} else if checker.settings.rules.enabled(Rule::SysVersionCmpStr3) {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(SysVersionCmpStr3, Range::from(left)));
|
||||
|
||||
@@ -492,7 +492,7 @@ pub fn definition(
|
||||
// ANN401 for dynamically typed arguments
|
||||
if let Some(annotation) = &arg.node.annotation {
|
||||
has_any_typed_arg = true;
|
||||
if checker.settings.rules.enabled(&Rule::AnyType) {
|
||||
if checker.settings.rules.enabled(Rule::AnyType) {
|
||||
check_dynamically_typed(
|
||||
checker,
|
||||
annotation,
|
||||
@@ -507,7 +507,7 @@ pub fn definition(
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::MissingTypeFunctionArgument)
|
||||
.enabled(Rule::MissingTypeFunctionArgument)
|
||||
{
|
||||
diagnostics.push(Diagnostic::new(
|
||||
MissingTypeFunctionArgument {
|
||||
@@ -525,7 +525,7 @@ pub fn definition(
|
||||
if let Some(expr) = &arg.node.annotation {
|
||||
has_any_typed_arg = true;
|
||||
if !checker.settings.flake8_annotations.allow_star_arg_any {
|
||||
if checker.settings.rules.enabled(&Rule::AnyType) {
|
||||
if checker.settings.rules.enabled(Rule::AnyType) {
|
||||
let name = &arg.node.arg;
|
||||
check_dynamically_typed(
|
||||
checker,
|
||||
@@ -539,7 +539,7 @@ pub fn definition(
|
||||
if !(checker.settings.flake8_annotations.suppress_dummy_args
|
||||
&& checker.settings.dummy_variable_rgx.is_match(&arg.node.arg))
|
||||
{
|
||||
if checker.settings.rules.enabled(&Rule::MissingTypeArgs) {
|
||||
if checker.settings.rules.enabled(Rule::MissingTypeArgs) {
|
||||
diagnostics.push(Diagnostic::new(
|
||||
MissingTypeArgs {
|
||||
name: arg.node.arg.to_string(),
|
||||
@@ -556,7 +556,7 @@ pub fn definition(
|
||||
if let Some(expr) = &arg.node.annotation {
|
||||
has_any_typed_arg = true;
|
||||
if !checker.settings.flake8_annotations.allow_star_arg_any {
|
||||
if checker.settings.rules.enabled(&Rule::AnyType) {
|
||||
if checker.settings.rules.enabled(Rule::AnyType) {
|
||||
let name = &arg.node.arg;
|
||||
check_dynamically_typed(
|
||||
checker,
|
||||
@@ -570,7 +570,7 @@ pub fn definition(
|
||||
if !(checker.settings.flake8_annotations.suppress_dummy_args
|
||||
&& checker.settings.dummy_variable_rgx.is_match(&arg.node.arg))
|
||||
{
|
||||
if checker.settings.rules.enabled(&Rule::MissingTypeKwargs) {
|
||||
if checker.settings.rules.enabled(Rule::MissingTypeKwargs) {
|
||||
diagnostics.push(Diagnostic::new(
|
||||
MissingTypeKwargs {
|
||||
name: arg.node.arg.to_string(),
|
||||
@@ -587,7 +587,7 @@ pub fn definition(
|
||||
if let Some(arg) = args.posonlyargs.first().or_else(|| args.args.first()) {
|
||||
if arg.node.annotation.is_none() {
|
||||
if visibility::is_classmethod(&checker.ctx, cast::decorator_list(stmt)) {
|
||||
if checker.settings.rules.enabled(&Rule::MissingTypeCls) {
|
||||
if checker.settings.rules.enabled(Rule::MissingTypeCls) {
|
||||
diagnostics.push(Diagnostic::new(
|
||||
MissingTypeCls {
|
||||
name: arg.node.arg.to_string(),
|
||||
@@ -596,7 +596,7 @@ pub fn definition(
|
||||
));
|
||||
}
|
||||
} else {
|
||||
if checker.settings.rules.enabled(&Rule::MissingTypeSelf) {
|
||||
if checker.settings.rules.enabled(Rule::MissingTypeSelf) {
|
||||
diagnostics.push(Diagnostic::new(
|
||||
MissingTypeSelf {
|
||||
name: arg.node.arg.to_string(),
|
||||
@@ -614,7 +614,7 @@ pub fn definition(
|
||||
// ANN201, ANN202, ANN401
|
||||
if let Some(expr) = &returns {
|
||||
has_typed_return = true;
|
||||
if checker.settings.rules.enabled(&Rule::AnyType) {
|
||||
if checker.settings.rules.enabled(Rule::AnyType) {
|
||||
check_dynamically_typed(checker, expr, || name.to_string(), &mut diagnostics);
|
||||
}
|
||||
} else if !(
|
||||
@@ -626,7 +626,7 @@ pub fn definition(
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::MissingReturnTypeClassMethod)
|
||||
.enabled(Rule::MissingReturnTypeClassMethod)
|
||||
{
|
||||
diagnostics.push(Diagnostic::new(
|
||||
MissingReturnTypeClassMethod {
|
||||
@@ -641,7 +641,7 @@ pub fn definition(
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::MissingReturnTypeStaticMethod)
|
||||
.enabled(Rule::MissingReturnTypeStaticMethod)
|
||||
{
|
||||
diagnostics.push(Diagnostic::new(
|
||||
MissingReturnTypeStaticMethod {
|
||||
@@ -656,7 +656,7 @@ pub fn definition(
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::MissingReturnTypeSpecialMethod)
|
||||
.enabled(Rule::MissingReturnTypeSpecialMethod)
|
||||
{
|
||||
if !(checker.settings.flake8_annotations.mypy_init_return && has_any_typed_arg)
|
||||
{
|
||||
@@ -681,7 +681,7 @@ pub fn definition(
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::MissingReturnTypeSpecialMethod)
|
||||
.enabled(Rule::MissingReturnTypeSpecialMethod)
|
||||
{
|
||||
diagnostics.push(Diagnostic::new(
|
||||
MissingReturnTypeSpecialMethod {
|
||||
@@ -696,7 +696,7 @@ pub fn definition(
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::MissingReturnTypePublicFunction)
|
||||
.enabled(Rule::MissingReturnTypePublicFunction)
|
||||
{
|
||||
diagnostics.push(Diagnostic::new(
|
||||
MissingReturnTypePublicFunction {
|
||||
@@ -710,7 +710,7 @@ pub fn definition(
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::MissingReturnTypePrivateFunction)
|
||||
.enabled(Rule::MissingReturnTypePrivateFunction)
|
||||
{
|
||||
diagnostics.push(Diagnostic::new(
|
||||
MissingReturnTypePrivateFunction {
|
||||
|
||||
@@ -41,6 +41,7 @@ mod tests {
|
||||
#[test_case(Rule::StarArgUnpackingAfterKeywordArg, Path::new("B026.py"); "B026")]
|
||||
#[test_case(Rule::EmptyMethodWithoutAbstractDecorator, Path::new("B027.py"); "B027")]
|
||||
#[test_case(Rule::EmptyMethodWithoutAbstractDecorator, Path::new("B027.pyi"); "B027_pyi")]
|
||||
#[test_case(Rule::NoExplicitStacklevel, Path::new("B028.py"); "B028")]
|
||||
#[test_case(Rule::ExceptWithEmptyTuple, Path::new("B029.py"); "B029")]
|
||||
#[test_case(Rule::ExceptWithNonExceptionClasses, Path::new("B030.py"); "B030")]
|
||||
#[test_case(Rule::UnintentionalTypeAnnotation, Path::new("B032.py"); "B032")]
|
||||
|
||||
@@ -115,7 +115,7 @@ pub fn abstract_base_class(
|
||||
if !checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::EmptyMethodWithoutAbstractDecorator)
|
||||
.enabled(Rule::EmptyMethodWithoutAbstractDecorator)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -135,7 +135,7 @@ pub fn abstract_base_class(
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::AbstractBaseClassWithoutAbstractMethod)
|
||||
.enabled(Rule::AbstractBaseClassWithoutAbstractMethod)
|
||||
{
|
||||
if !has_abstract_method {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
|
||||
@@ -2,7 +2,8 @@ use rustpython_parser::ast::{Expr, ExprKind};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::types::{Range, ScopeKind};
|
||||
use ruff_python_ast::scope::ScopeKind;
|
||||
use ruff_python_ast::types::Range;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
@@ -30,7 +31,7 @@ fn is_cache_func(checker: &Checker, expr: &Expr) -> bool {
|
||||
|
||||
/// B019
|
||||
pub fn cached_instance_method(checker: &mut Checker, decorator_list: &[Expr]) {
|
||||
if !matches!(checker.ctx.current_scope().kind, ScopeKind::Class(_)) {
|
||||
if !matches!(checker.ctx.scope().kind, ScopeKind::Class(_)) {
|
||||
return;
|
||||
}
|
||||
for decorator in decorator_list {
|
||||
|
||||
@@ -83,7 +83,7 @@ fn duplicate_handler_exceptions<'a>(
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::DuplicateHandlerException)
|
||||
.enabled(Rule::DuplicateHandlerException)
|
||||
{
|
||||
// TODO(charlie): Handle "BaseException" and redundant exception aliases.
|
||||
if !duplicates.is_empty() {
|
||||
@@ -149,7 +149,7 @@ pub fn duplicate_exceptions(checker: &mut Checker, handlers: &[Excepthandler]) {
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::DuplicateTryBlockException)
|
||||
.enabled(Rule::DuplicateTryBlockException)
|
||||
{
|
||||
for (name, exprs) in duplicates {
|
||||
for expr in exprs {
|
||||
|
||||
@@ -25,6 +25,7 @@ pub use loop_variable_overrides_iterator::{
|
||||
loop_variable_overrides_iterator, LoopVariableOverridesIterator,
|
||||
};
|
||||
pub use mutable_argument_default::{mutable_argument_default, MutableArgumentDefault};
|
||||
pub use no_explicit_stacklevel::{no_explicit_stacklevel, NoExplicitStacklevel};
|
||||
pub use raise_without_from_inside_except::{
|
||||
raise_without_from_inside_except, RaiseWithoutFromInsideExcept,
|
||||
};
|
||||
@@ -63,6 +64,7 @@ mod getattr_with_constant;
|
||||
mod jump_statement_in_finally;
|
||||
mod loop_variable_overrides_iterator;
|
||||
mod mutable_argument_default;
|
||||
mod no_explicit_stacklevel;
|
||||
mod raise_without_from_inside_except;
|
||||
mod redundant_tuple_in_exception_handler;
|
||||
mod setattr_with_constant;
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
use rustpython_parser::ast::{Expr, Keyword};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::helpers::SimpleCallArgs;
|
||||
use ruff_python_ast::types::Range;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for `warnings.warn` calls without an explicit `stacklevel` keyword
|
||||
/// argument.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// The `warnings.warn` method uses a `stacklevel` of 1 by default, which
|
||||
/// limits the rendered stack trace to that of the line on which the
|
||||
/// `warn` method is called.
|
||||
///
|
||||
/// It's recommended to use a `stacklevel` of 2 or higher, give the caller
|
||||
/// more context about the warning.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// warnings.warn("This is a warning")
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// warnings.warn("This is a warning", stacklevel=2)
|
||||
/// ```
|
||||
#[violation]
|
||||
pub struct NoExplicitStacklevel;
|
||||
|
||||
impl Violation for NoExplicitStacklevel {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("No explicit `stacklevel` keyword argument found")
|
||||
}
|
||||
}
|
||||
|
||||
/// B028
|
||||
pub fn no_explicit_stacklevel(
|
||||
checker: &mut Checker,
|
||||
func: &Expr,
|
||||
args: &[Expr],
|
||||
keywords: &[Keyword],
|
||||
) {
|
||||
if !checker
|
||||
.ctx
|
||||
.resolve_call_path(func)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["warnings", "warn"]
|
||||
})
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if SimpleCallArgs::new(args, keywords)
|
||||
.keyword_argument("stacklevel")
|
||||
.is_some()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(NoExplicitStacklevel, Range::from(func)));
|
||||
}
|
||||
@@ -163,9 +163,8 @@ pub fn unused_loop_control_variable(
|
||||
if let Some(rename) = rename {
|
||||
if certainty.into() && checker.patch(diagnostic.kind.rule()) {
|
||||
// Find the `BindingKind::LoopVar` corresponding to the name.
|
||||
let scope = checker.ctx.current_scope();
|
||||
let scope = checker.ctx.scope();
|
||||
let binding = scope
|
||||
.bindings
|
||||
.get(name)
|
||||
.into_iter()
|
||||
.chain(scope.rebounds.get(name).into_iter().flatten())
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
---
|
||||
source: crates/ruff/src/rules/flake8_bugbear/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: NoExplicitStacklevel
|
||||
body: "No explicit `stacklevel` keyword argument found"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
row: 8
|
||||
column: 0
|
||||
end_location:
|
||||
row: 8
|
||||
column: 13
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: NoExplicitStacklevel
|
||||
body: "No explicit `stacklevel` keyword argument found"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
row: 9
|
||||
column: 0
|
||||
end_location:
|
||||
row: 9
|
||||
column: 13
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
@@ -260,7 +260,7 @@ pub fn trailing_commas(
|
||||
end_location: comma.2,
|
||||
},
|
||||
);
|
||||
if autofix.into() && settings.rules.should_fix(&Rule::TrailingCommaProhibited) {
|
||||
if autofix.into() && settings.rules.should_fix(Rule::TrailingCommaProhibited) {
|
||||
diagnostic.amend(Fix::deletion(comma.0, comma.2));
|
||||
}
|
||||
diagnostics.push(diagnostic);
|
||||
@@ -304,7 +304,7 @@ pub fn trailing_commas(
|
||||
end_location: missing_comma.2,
|
||||
},
|
||||
);
|
||||
if autofix.into() && settings.rules.should_fix(&Rule::TrailingCommaMissing) {
|
||||
if autofix.into() && settings.rules.should_fix(Rule::TrailingCommaMissing) {
|
||||
// Create a replacement that includes the final bracket (or other token),
|
||||
// rather than just inserting a comma at the end. This prevents the UP034 autofix
|
||||
// removing any brackets in the same linter pass - doing both at the same time could
|
||||
|
||||
@@ -162,7 +162,7 @@ pub fn string_in_exception(checker: &mut Checker, exc: &Expr) {
|
||||
value: Constant::Str(string),
|
||||
..
|
||||
} => {
|
||||
if checker.settings.rules.enabled(&Rule::RawStringInException) {
|
||||
if checker.settings.rules.enabled(Rule::RawStringInException) {
|
||||
if string.len() > checker.settings.flake8_errmsg.max_string_length {
|
||||
checker
|
||||
.diagnostics
|
||||
@@ -172,7 +172,7 @@ pub fn string_in_exception(checker: &mut Checker, exc: &Expr) {
|
||||
}
|
||||
// Check for f-strings
|
||||
ExprKind::JoinedStr { .. } => {
|
||||
if checker.settings.rules.enabled(&Rule::FStringInException) {
|
||||
if checker.settings.rules.enabled(Rule::FStringInException) {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(FStringInException, Range::from(first)));
|
||||
@@ -180,7 +180,7 @@ pub fn string_in_exception(checker: &mut Checker, exc: &Expr) {
|
||||
}
|
||||
// Check for .format() calls
|
||||
ExprKind::Call { func, .. } => {
|
||||
if checker.settings.rules.enabled(&Rule::DotFormatInException) {
|
||||
if checker.settings.rules.enabled(Rule::DotFormatInException) {
|
||||
if let ExprKind::Attribute { value, attr, .. } = &func.node {
|
||||
if attr == "format" && matches!(value.node, ExprKind::Constant { .. }) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
|
||||
@@ -43,14 +43,14 @@ fn check_msg(checker: &mut Checker, msg: &Expr) {
|
||||
// Check for string concatenation and percent format.
|
||||
ExprKind::BinOp { op, .. } => match op {
|
||||
Operator::Add => {
|
||||
if checker.settings.rules.enabled(&Rule::LoggingStringConcat) {
|
||||
if checker.settings.rules.enabled(Rule::LoggingStringConcat) {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(LoggingStringConcat, Range::from(msg)));
|
||||
}
|
||||
}
|
||||
Operator::Mod => {
|
||||
if checker.settings.rules.enabled(&Rule::LoggingPercentFormat) {
|
||||
if checker.settings.rules.enabled(Rule::LoggingPercentFormat) {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(LoggingPercentFormat, Range::from(msg)));
|
||||
@@ -60,7 +60,7 @@ fn check_msg(checker: &mut Checker, msg: &Expr) {
|
||||
},
|
||||
// Check for f-strings.
|
||||
ExprKind::JoinedStr { .. } => {
|
||||
if checker.settings.rules.enabled(&Rule::LoggingFString) {
|
||||
if checker.settings.rules.enabled(Rule::LoggingFString) {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(LoggingFString, Range::from(msg)));
|
||||
@@ -68,7 +68,7 @@ fn check_msg(checker: &mut Checker, msg: &Expr) {
|
||||
}
|
||||
// Check for .format() calls.
|
||||
ExprKind::Call { func, .. } => {
|
||||
if checker.settings.rules.enabled(&Rule::LoggingStringFormat) {
|
||||
if checker.settings.rules.enabled(Rule::LoggingStringFormat) {
|
||||
if let ExprKind::Attribute { value, attr, .. } = &func.node {
|
||||
if attr == "format" && matches!(value.node, ExprKind::Constant { .. }) {
|
||||
checker
|
||||
@@ -151,7 +151,7 @@ pub fn logging_call(checker: &mut Checker, func: &Expr, args: &[Expr], keywords:
|
||||
}
|
||||
|
||||
// G010
|
||||
if checker.settings.rules.enabled(&Rule::LoggingWarn)
|
||||
if checker.settings.rules.enabled(Rule::LoggingWarn)
|
||||
&& matches!(logging_level, LoggingLevel::Warn)
|
||||
{
|
||||
let mut diagnostic = Diagnostic::new(LoggingWarn, level_call_range);
|
||||
@@ -166,18 +166,18 @@ pub fn logging_call(checker: &mut Checker, func: &Expr, args: &[Expr], keywords:
|
||||
}
|
||||
|
||||
// G101
|
||||
if checker.settings.rules.enabled(&Rule::LoggingExtraAttrClash) {
|
||||
if checker.settings.rules.enabled(Rule::LoggingExtraAttrClash) {
|
||||
if let Some(extra) = find_keyword(keywords, "extra") {
|
||||
check_log_record_attr_clash(checker, extra);
|
||||
}
|
||||
}
|
||||
|
||||
// G201, G202
|
||||
if checker.settings.rules.enabled(&Rule::LoggingExcInfo)
|
||||
if checker.settings.rules.enabled(Rule::LoggingExcInfo)
|
||||
|| checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::LoggingRedundantExcInfo)
|
||||
.enabled(Rule::LoggingRedundantExcInfo)
|
||||
{
|
||||
if !checker.ctx.in_exception_handler() {
|
||||
return;
|
||||
@@ -206,7 +206,7 @@ pub fn logging_call(checker: &mut Checker, func: &Expr, args: &[Expr], keywords:
|
||||
|
||||
match logging_level {
|
||||
LoggingLevel::Error => {
|
||||
if checker.settings.rules.enabled(&Rule::LoggingExcInfo) {
|
||||
if checker.settings.rules.enabled(Rule::LoggingExcInfo) {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(LoggingExcInfo, level_call_range));
|
||||
@@ -216,7 +216,7 @@ pub fn logging_call(checker: &mut Checker, func: &Expr, args: &[Expr], keywords:
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::LoggingRedundantExcInfo)
|
||||
.enabled(Rule::LoggingRedundantExcInfo)
|
||||
{
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
LoggingRedundantExcInfo,
|
||||
|
||||
@@ -118,7 +118,7 @@ pub fn unrecognized_platform(
|
||||
&& checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::UnrecognizedPlatformCheck)
|
||||
.enabled(Rule::UnrecognizedPlatformCheck)
|
||||
{
|
||||
checker
|
||||
.diagnostics
|
||||
@@ -137,7 +137,7 @@ pub fn unrecognized_platform(
|
||||
&& checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::UnrecognizedPlatformName)
|
||||
.enabled(Rule::UnrecognizedPlatformName)
|
||||
{
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
UnrecognizedPlatformName {
|
||||
@@ -151,7 +151,7 @@ pub fn unrecognized_platform(
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::UnrecognizedPlatformCheck)
|
||||
.enabled(Rule::UnrecognizedPlatformCheck)
|
||||
{
|
||||
checker
|
||||
.diagnostics
|
||||
|
||||
@@ -277,7 +277,7 @@ fn check_fixture_decorator(checker: &mut Checker, func_name: &str, decorator: &E
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::IncorrectFixtureParenthesesStyle)
|
||||
.enabled(Rule::IncorrectFixtureParenthesesStyle)
|
||||
&& !checker.settings.flake8_pytest_style.fixture_parentheses
|
||||
&& args.is_empty()
|
||||
&& keywords.is_empty()
|
||||
@@ -287,7 +287,7 @@ fn check_fixture_decorator(checker: &mut Checker, func_name: &str, decorator: &E
|
||||
pytest_fixture_parentheses(checker, decorator, fix, "", "()");
|
||||
}
|
||||
|
||||
if checker.settings.rules.enabled(&Rule::FixturePositionalArgs) && !args.is_empty() {
|
||||
if checker.settings.rules.enabled(Rule::FixturePositionalArgs) && !args.is_empty() {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
FixturePositionalArgs {
|
||||
function: func_name.to_string(),
|
||||
@@ -299,7 +299,7 @@ fn check_fixture_decorator(checker: &mut Checker, func_name: &str, decorator: &E
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::ExtraneousScopeFunction)
|
||||
.enabled(Rule::ExtraneousScopeFunction)
|
||||
{
|
||||
let scope_keyword = keywords
|
||||
.iter()
|
||||
@@ -333,7 +333,7 @@ fn check_fixture_decorator(checker: &mut Checker, func_name: &str, decorator: &E
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::IncorrectFixtureParenthesesStyle)
|
||||
.enabled(Rule::IncorrectFixtureParenthesesStyle)
|
||||
&& checker.settings.flake8_pytest_style.fixture_parentheses
|
||||
{
|
||||
let fix = Fix::insertion("()".to_string(), decorator.end_location.unwrap());
|
||||
@@ -354,7 +354,7 @@ fn check_fixture_returns(checker: &mut Checker, func: &Stmt, func_name: &str, bo
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::IncorrectFixtureNameUnderscore)
|
||||
.enabled(Rule::IncorrectFixtureNameUnderscore)
|
||||
&& visitor.has_return_with_value
|
||||
&& func_name.starts_with('_')
|
||||
{
|
||||
@@ -367,7 +367,7 @@ fn check_fixture_returns(checker: &mut Checker, func: &Stmt, func_name: &str, bo
|
||||
} else if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::MissingFixtureNameUnderscore)
|
||||
.enabled(Rule::MissingFixtureNameUnderscore)
|
||||
&& !visitor.has_return_with_value
|
||||
&& !visitor.has_yield_from
|
||||
&& !func_name.starts_with('_')
|
||||
@@ -380,7 +380,7 @@ fn check_fixture_returns(checker: &mut Checker, func: &Stmt, func_name: &str, bo
|
||||
));
|
||||
}
|
||||
|
||||
if checker.settings.rules.enabled(&Rule::UselessYieldFixture) {
|
||||
if checker.settings.rules.enabled(Rule::UselessYieldFixture) {
|
||||
if let Some(stmt) = body.last() {
|
||||
if let StmtKind::Expr { value, .. } = &stmt.node {
|
||||
if let ExprKind::Yield { .. } = value.node {
|
||||
@@ -462,7 +462,7 @@ fn check_fixture_marks(checker: &mut Checker, decorators: &[Expr]) {
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::UnnecessaryAsyncioMarkOnFixture)
|
||||
.enabled(Rule::UnnecessaryAsyncioMarkOnFixture)
|
||||
{
|
||||
if name == "asyncio" {
|
||||
let mut diagnostic =
|
||||
@@ -479,7 +479,7 @@ fn check_fixture_marks(checker: &mut Checker, decorators: &[Expr]) {
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::ErroneousUseFixturesOnFixture)
|
||||
.enabled(Rule::ErroneousUseFixturesOnFixture)
|
||||
{
|
||||
if name == "usefixtures" {
|
||||
let mut diagnostic =
|
||||
@@ -508,20 +508,17 @@ pub fn fixture(
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::IncorrectFixtureParenthesesStyle)
|
||||
|| checker.settings.rules.enabled(&Rule::FixturePositionalArgs)
|
||||
.enabled(Rule::IncorrectFixtureParenthesesStyle)
|
||||
|| checker.settings.rules.enabled(Rule::FixturePositionalArgs)
|
||||
|| checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::ExtraneousScopeFunction)
|
||||
.enabled(Rule::ExtraneousScopeFunction)
|
||||
{
|
||||
check_fixture_decorator(checker, func_name, decorator);
|
||||
}
|
||||
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::DeprecatedYieldFixture)
|
||||
if checker.settings.rules.enabled(Rule::DeprecatedYieldFixture)
|
||||
&& checker.settings.flake8_pytest_style.fixture_parentheses
|
||||
{
|
||||
check_fixture_decorator_name(checker, decorator);
|
||||
@@ -530,12 +527,12 @@ pub fn fixture(
|
||||
if (checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::MissingFixtureNameUnderscore)
|
||||
.enabled(Rule::MissingFixtureNameUnderscore)
|
||||
|| checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::IncorrectFixtureNameUnderscore)
|
||||
|| checker.settings.rules.enabled(&Rule::UselessYieldFixture))
|
||||
.enabled(Rule::IncorrectFixtureNameUnderscore)
|
||||
|| checker.settings.rules.enabled(Rule::UselessYieldFixture))
|
||||
&& !has_abstractmethod_decorator(decorators, checker)
|
||||
{
|
||||
check_fixture_returns(checker, func, func_name, body);
|
||||
@@ -544,7 +541,7 @@ pub fn fixture(
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::FixtureFinalizerCallback)
|
||||
.enabled(Rule::FixtureFinalizerCallback)
|
||||
{
|
||||
check_fixture_addfinalizer(checker, args, body);
|
||||
}
|
||||
@@ -552,11 +549,11 @@ pub fn fixture(
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::UnnecessaryAsyncioMarkOnFixture)
|
||||
.enabled(Rule::UnnecessaryAsyncioMarkOnFixture)
|
||||
|| checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::ErroneousUseFixturesOnFixture)
|
||||
.enabled(Rule::ErroneousUseFixturesOnFixture)
|
||||
{
|
||||
check_fixture_marks(checker, decorators);
|
||||
}
|
||||
@@ -565,7 +562,7 @@ pub fn fixture(
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::FixtureParamWithoutValue)
|
||||
.enabled(Rule::FixtureParamWithoutValue)
|
||||
&& func_name.starts_with("test_")
|
||||
{
|
||||
check_test_function_args(checker, args);
|
||||
|
||||
@@ -123,11 +123,11 @@ pub fn marks(checker: &mut Checker, decorators: &[Expr]) {
|
||||
let enforce_parentheses = checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::IncorrectMarkParenthesesStyle);
|
||||
.enabled(Rule::IncorrectMarkParenthesesStyle);
|
||||
let enforce_useless_usefixtures = checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::UseFixturesWithoutParameters);
|
||||
.enabled(Rule::UseFixturesWithoutParameters);
|
||||
|
||||
for mark in get_mark_decorators(decorators) {
|
||||
if enforce_parentheses {
|
||||
|
||||
@@ -380,7 +380,7 @@ pub fn parametrize(checker: &mut Checker, decorators: &[Expr]) {
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::ParametrizeNamesWrongType)
|
||||
.enabled(Rule::ParametrizeNamesWrongType)
|
||||
{
|
||||
if let Some(names) = args.get(0) {
|
||||
check_names(checker, names);
|
||||
@@ -389,7 +389,7 @@ pub fn parametrize(checker: &mut Checker, decorators: &[Expr]) {
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::ParametrizeValuesWrongType)
|
||||
.enabled(Rule::ParametrizeValuesWrongType)
|
||||
{
|
||||
if let Some(names) = args.get(0) {
|
||||
if let Some(values) = args.get(1) {
|
||||
|
||||
@@ -67,11 +67,7 @@ const fn is_non_trivial_with_body(body: &[Stmt]) -> bool {
|
||||
|
||||
pub fn raises_call(checker: &mut Checker, func: &Expr, args: &[Expr], keywords: &[Keyword]) {
|
||||
if is_pytest_raises(checker, func) {
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::RaisesWithoutException)
|
||||
{
|
||||
if checker.settings.rules.enabled(Rule::RaisesWithoutException) {
|
||||
if args.is_empty() && keywords.is_empty() {
|
||||
checker
|
||||
.diagnostics
|
||||
@@ -79,7 +75,7 @@ pub fn raises_call(checker: &mut Checker, func: &Expr, args: &[Expr], keywords:
|
||||
}
|
||||
}
|
||||
|
||||
if checker.settings.rules.enabled(&Rule::RaisesTooBroad) {
|
||||
if checker.settings.rules.enabled(Rule::RaisesTooBroad) {
|
||||
let match_keyword = keywords
|
||||
.iter()
|
||||
.find(|kw| kw.node.arg == Some("match".to_string()));
|
||||
|
||||
@@ -281,7 +281,7 @@ fn docstring(
|
||||
},
|
||||
Range::new(start, end),
|
||||
);
|
||||
if autofix.into() && settings.rules.should_fix(&Rule::BadQuotesDocstring) {
|
||||
if autofix.into() && settings.rules.should_fix(Rule::BadQuotesDocstring) {
|
||||
let quote_count = if trivia.is_multiline { 3 } else { 1 };
|
||||
let string_contents = &trivia.raw_text[quote_count..trivia.raw_text.len() - quote_count];
|
||||
let quote = good_docstring("es_settings.docstring_quotes).repeat(quote_count);
|
||||
@@ -356,7 +356,7 @@ fn strings(
|
||||
Range::new(*start, *end),
|
||||
);
|
||||
|
||||
if autofix.into() && settings.rules.should_fix(&Rule::BadQuotesMultilineString) {
|
||||
if autofix.into() && settings.rules.should_fix(Rule::BadQuotesMultilineString) {
|
||||
let string_contents = &trivia.raw_text[3..trivia.raw_text.len() - 3];
|
||||
let quote = good_multiline("es_settings.multiline_quotes);
|
||||
let mut fixed_contents = String::with_capacity(
|
||||
@@ -386,7 +386,7 @@ fn strings(
|
||||
{
|
||||
let mut diagnostic =
|
||||
Diagnostic::new(AvoidableEscapedQuote, Range::new(*start, *end));
|
||||
if autofix.into() && settings.rules.should_fix(&Rule::AvoidableEscapedQuote) {
|
||||
if autofix.into() && settings.rules.should_fix(Rule::AvoidableEscapedQuote) {
|
||||
let quote = bad_single("es_settings.inline_quotes);
|
||||
|
||||
let mut fixed_contents =
|
||||
@@ -445,7 +445,7 @@ fn strings(
|
||||
},
|
||||
Range::new(*start, *end),
|
||||
);
|
||||
if autofix.into() && settings.rules.should_fix(&Rule::BadQuotesInlineString) {
|
||||
if autofix.into() && settings.rules.should_fix(Rule::BadQuotesInlineString) {
|
||||
let quote = good_single("es_settings.inline_quotes);
|
||||
let mut fixed_contents =
|
||||
String::with_capacity(trivia.prefix.len() + string_contents.len() + 2);
|
||||
|
||||
@@ -514,13 +514,13 @@ pub fn function(checker: &mut Checker, body: &[Stmt]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if checker.settings.rules.enabled(&Rule::SuperfluousElseReturn)
|
||||
|| checker.settings.rules.enabled(&Rule::SuperfluousElseRaise)
|
||||
if checker.settings.rules.enabled(Rule::SuperfluousElseReturn)
|
||||
|| checker.settings.rules.enabled(Rule::SuperfluousElseRaise)
|
||||
|| checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::SuperfluousElseContinue)
|
||||
|| checker.settings.rules.enabled(&Rule::SuperfluousElseBreak)
|
||||
.enabled(Rule::SuperfluousElseContinue)
|
||||
|| checker.settings.rules.enabled(Rule::SuperfluousElseBreak)
|
||||
{
|
||||
if superfluous_elif(checker, &stack) {
|
||||
return;
|
||||
@@ -536,20 +536,20 @@ pub fn function(checker: &mut Checker, body: &[Stmt]) {
|
||||
}
|
||||
|
||||
if !result_exists(&stack.returns) {
|
||||
if checker.settings.rules.enabled(&Rule::UnnecessaryReturnNone) {
|
||||
if checker.settings.rules.enabled(Rule::UnnecessaryReturnNone) {
|
||||
unnecessary_return_none(checker, &stack);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if checker.settings.rules.enabled(&Rule::ImplicitReturnValue) {
|
||||
if checker.settings.rules.enabled(Rule::ImplicitReturnValue) {
|
||||
implicit_return_value(checker, &stack);
|
||||
}
|
||||
if checker.settings.rules.enabled(&Rule::ImplicitReturn) {
|
||||
if checker.settings.rules.enabled(Rule::ImplicitReturn) {
|
||||
implicit_return(checker, last_stmt);
|
||||
}
|
||||
|
||||
if checker.settings.rules.enabled(&Rule::UnnecessaryAssign) {
|
||||
if checker.settings.rules.enabled(Rule::UnnecessaryAssign) {
|
||||
for (_, expr) in &stack.returns {
|
||||
if let Some(expr) = expr {
|
||||
unnecessary_assign(checker, &stack, expr);
|
||||
|
||||
@@ -3,7 +3,8 @@ use rustpython_parser::ast::{Expr, ExprKind};
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::helpers::collect_call_path;
|
||||
use ruff_python_ast::types::{Range, ScopeKind};
|
||||
use ruff_python_ast::scope::ScopeKind;
|
||||
use ruff_python_ast::types::Range;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
|
||||
@@ -3,7 +3,8 @@ use rustpython_parser::ast::{Cmpop, Expr, ExprKind, Stmt, StmtKind, Unaryop};
|
||||
use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic, Fix};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::helpers::{create_expr, unparse_expr};
|
||||
use ruff_python_ast::types::{Range, ScopeKind};
|
||||
use ruff_python_ast::scope::ScopeKind;
|
||||
use ruff_python_ast::types::Range;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::AsRule;
|
||||
@@ -93,7 +94,7 @@ pub fn negation_with_equal_op(checker: &mut Checker, expr: &Expr, op: &Unaryop,
|
||||
}
|
||||
|
||||
// Avoid flagging issues in dunder implementations.
|
||||
if let ScopeKind::Function(def) = &checker.ctx.current_scope().kind {
|
||||
if let ScopeKind::Function(def) = &checker.ctx.scope().kind {
|
||||
if DUNDER_METHODS.contains(&def.name) {
|
||||
return;
|
||||
}
|
||||
@@ -144,7 +145,7 @@ pub fn negation_with_not_equal_op(
|
||||
}
|
||||
|
||||
// Avoid flagging issues in dunder implementations.
|
||||
if let ScopeKind::Function(def) = &checker.ctx.current_scope().kind {
|
||||
if let ScopeKind::Function(def) = &checker.ctx.scope().kind {
|
||||
if DUNDER_METHODS.contains(&def.name) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -201,7 +201,7 @@ pub fn convert_for_loop_to_any_all(checker: &mut Checker, stmt: &Stmt, sibling:
|
||||
.or_else(|| sibling.and_then(|sibling| return_values_for_siblings(stmt, sibling)))
|
||||
{
|
||||
if loop_info.return_value && !loop_info.next_return_value {
|
||||
if checker.settings.rules.enabled(&Rule::ReimplementedBuiltin) {
|
||||
if checker.settings.rules.enabled(Rule::ReimplementedBuiltin) {
|
||||
let contents = return_stmt(
|
||||
"any",
|
||||
loop_info.test,
|
||||
@@ -233,7 +233,7 @@ pub fn convert_for_loop_to_any_all(checker: &mut Checker, stmt: &Stmt, sibling:
|
||||
}
|
||||
|
||||
if !loop_info.return_value && loop_info.next_return_value {
|
||||
if checker.settings.rules.enabled(&Rule::ReimplementedBuiltin) {
|
||||
if checker.settings.rules.enabled(Rule::ReimplementedBuiltin) {
|
||||
// Invert the condition.
|
||||
let test = {
|
||||
if let ExprKind::UnaryOp {
|
||||
|
||||
@@ -3,7 +3,7 @@ use rustpython_parser::ast::{Constant, Expr, ExprKind};
|
||||
|
||||
use ruff_python_ast::context::Context;
|
||||
use ruff_python_ast::helpers::{map_callable, to_call_path};
|
||||
use ruff_python_ast::types::{Binding, BindingKind, ExecutionContext, ScopeKind};
|
||||
use ruff_python_ast::scope::{Binding, BindingKind, ExecutionContext, ScopeKind};
|
||||
|
||||
/// Return `true` if [`Expr`] is a guard for a type-checking block.
|
||||
pub fn is_type_checking_block(context: &Context, test: &Expr) -> bool {
|
||||
@@ -71,7 +71,7 @@ pub fn runtime_evaluated(
|
||||
}
|
||||
|
||||
fn runtime_evaluated_base_class(context: &Context, base_classes: &[String]) -> bool {
|
||||
if let ScopeKind::Class(class_def) = &context.current_scope().kind {
|
||||
if let ScopeKind::Class(class_def) = &context.scope().kind {
|
||||
for base in class_def.bases.iter() {
|
||||
if let Some(call_path) = context.resolve_call_path(base) {
|
||||
if base_classes
|
||||
@@ -87,7 +87,7 @@ fn runtime_evaluated_base_class(context: &Context, base_classes: &[String]) -> b
|
||||
}
|
||||
|
||||
fn runtime_evaluated_decorators(context: &Context, decorators: &[String]) -> bool {
|
||||
if let ScopeKind::Class(class_def) = &context.current_scope().kind {
|
||||
if let ScopeKind::Class(class_def) = &context.scope().kind {
|
||||
for decorator in class_def.decorator_list.iter() {
|
||||
if let Some(call_path) = context.resolve_call_path(map_callable(decorator)) {
|
||||
if decorators
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::types::{Binding, BindingKind, ExecutionContext};
|
||||
use ruff_python_ast::scope::{Binding, BindingKind, ExecutionContext};
|
||||
|
||||
#[violation]
|
||||
pub struct RuntimeImportInTypeCheckingBlock {
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::path::Path;
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::types::{Binding, BindingKind, ExecutionContext};
|
||||
use ruff_python_ast::scope::{Binding, BindingKind, ExecutionContext};
|
||||
|
||||
use crate::rules::isort::{categorize, ImportType};
|
||||
use crate::settings::Settings;
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
use std::iter;
|
||||
|
||||
use regex::Regex;
|
||||
use rustc_hash::FxHashMap;
|
||||
use rustpython_parser::ast::{Arg, Arguments};
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::function_type;
|
||||
use ruff_python_ast::function_type::FunctionType;
|
||||
use ruff_python_ast::types::{Binding, FunctionDef, Lambda, Scope, ScopeKind};
|
||||
use ruff_python_ast::scope::{Bindings, FunctionDef, Lambda, Scope, ScopeKind};
|
||||
use ruff_python_ast::visibility;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
@@ -85,8 +84,8 @@ impl Violation for UnusedLambdaArgument {
|
||||
fn function(
|
||||
argumentable: &Argumentable,
|
||||
args: &Arguments,
|
||||
values: &FxHashMap<&str, usize>,
|
||||
bindings: &[Binding],
|
||||
values: &Scope,
|
||||
bindings: &Bindings,
|
||||
dummy_variable_rgx: &Regex,
|
||||
ignore_variadic_names: bool,
|
||||
) -> Vec<Diagnostic> {
|
||||
@@ -112,8 +111,8 @@ fn function(
|
||||
fn method(
|
||||
argumentable: &Argumentable,
|
||||
args: &Arguments,
|
||||
values: &FxHashMap<&str, usize>,
|
||||
bindings: &[Binding],
|
||||
values: &Scope,
|
||||
bindings: &Bindings,
|
||||
dummy_variable_rgx: &Regex,
|
||||
ignore_variadic_names: bool,
|
||||
) -> Vec<Diagnostic> {
|
||||
@@ -139,14 +138,14 @@ fn method(
|
||||
fn call<'a>(
|
||||
argumentable: &Argumentable,
|
||||
args: impl Iterator<Item = &'a Arg>,
|
||||
values: &FxHashMap<&str, usize>,
|
||||
bindings: &[Binding],
|
||||
values: &Scope,
|
||||
bindings: &Bindings,
|
||||
dummy_variable_rgx: &Regex,
|
||||
) -> Vec<Diagnostic> {
|
||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||
for arg in args {
|
||||
if let Some(binding) = values
|
||||
.get(&arg.node.arg.as_str())
|
||||
.get(arg.node.arg.as_str())
|
||||
.map(|index| &bindings[*index])
|
||||
{
|
||||
if !binding.used()
|
||||
@@ -168,7 +167,7 @@ pub fn unused_arguments(
|
||||
checker: &Checker,
|
||||
parent: &Scope,
|
||||
scope: &Scope,
|
||||
bindings: &[Binding],
|
||||
bindings: &Bindings,
|
||||
) -> Vec<Diagnostic> {
|
||||
match &scope.kind {
|
||||
ScopeKind::Function(FunctionDef {
|
||||
@@ -196,7 +195,7 @@ pub fn unused_arguments(
|
||||
function(
|
||||
&Argumentable::Function,
|
||||
args,
|
||||
&scope.bindings,
|
||||
scope,
|
||||
bindings,
|
||||
&checker.settings.dummy_variable_rgx,
|
||||
checker
|
||||
@@ -225,7 +224,7 @@ pub fn unused_arguments(
|
||||
method(
|
||||
&Argumentable::Method,
|
||||
args,
|
||||
&scope.bindings,
|
||||
scope,
|
||||
bindings,
|
||||
&checker.settings.dummy_variable_rgx,
|
||||
checker
|
||||
@@ -254,7 +253,7 @@ pub fn unused_arguments(
|
||||
method(
|
||||
&Argumentable::ClassMethod,
|
||||
args,
|
||||
&scope.bindings,
|
||||
scope,
|
||||
bindings,
|
||||
&checker.settings.dummy_variable_rgx,
|
||||
checker
|
||||
@@ -283,7 +282,7 @@ pub fn unused_arguments(
|
||||
function(
|
||||
&Argumentable::StaticMethod,
|
||||
args,
|
||||
&scope.bindings,
|
||||
scope,
|
||||
bindings,
|
||||
&checker.settings.dummy_variable_rgx,
|
||||
checker
|
||||
@@ -306,7 +305,7 @@ pub fn unused_arguments(
|
||||
function(
|
||||
&Argumentable::Lambda,
|
||||
args,
|
||||
&scope.bindings,
|
||||
scope,
|
||||
bindings,
|
||||
&checker.settings.dummy_variable_rgx,
|
||||
checker
|
||||
|
||||
@@ -24,13 +24,13 @@ impl Argumentable {
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn rule_code(&self) -> &Rule {
|
||||
pub const fn rule_code(&self) -> Rule {
|
||||
match self {
|
||||
Self::Function => &Rule::UnusedFunctionArgument,
|
||||
Self::Method => &Rule::UnusedMethodArgument,
|
||||
Self::ClassMethod => &Rule::UnusedClassMethodArgument,
|
||||
Self::StaticMethod => &Rule::UnusedStaticMethodArgument,
|
||||
Self::Lambda => &Rule::UnusedLambdaArgument,
|
||||
Self::Function => Rule::UnusedFunctionArgument,
|
||||
Self::Method => Rule::UnusedMethodArgument,
|
||||
Self::ClassMethod => Rule::UnusedClassMethodArgument,
|
||||
Self::StaticMethod => Rule::UnusedStaticMethodArgument,
|
||||
Self::Lambda => Rule::UnusedLambdaArgument,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,7 +168,7 @@ fn add_required_import(
|
||||
MissingRequiredImport(required_import.clone()),
|
||||
Range::new(Location::default(), Location::default()),
|
||||
);
|
||||
if autofix.into() && settings.rules.should_fix(&Rule::MissingRequiredImport) {
|
||||
if autofix.into() && settings.rules.should_fix(Rule::MissingRequiredImport) {
|
||||
// Determine the location at which the import should be inserted.
|
||||
let splice = helpers::find_splice_location(python_ast, locator);
|
||||
|
||||
|
||||
@@ -50,13 +50,18 @@ use ruff_python_ast::source_code::Locator;
|
||||
pub struct ComplexStructure {
|
||||
pub name: String,
|
||||
pub complexity: usize,
|
||||
pub max_complexity: usize,
|
||||
}
|
||||
|
||||
impl Violation for ComplexStructure {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let ComplexStructure { name, complexity } = self;
|
||||
format!("`{name}` is too complex ({complexity})")
|
||||
let ComplexStructure {
|
||||
name,
|
||||
complexity,
|
||||
max_complexity,
|
||||
} = self;
|
||||
format!("`{name}` is too complex ({complexity} > {max_complexity})")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,6 +140,7 @@ pub fn function_is_too_complex(
|
||||
ComplexStructure {
|
||||
name: name.to_string(),
|
||||
complexity,
|
||||
max_complexity,
|
||||
},
|
||||
identifier_range(stmt, locator),
|
||||
))
|
||||
|
||||
@@ -4,7 +4,7 @@ expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: ComplexStructure
|
||||
body: "`trivial` is too complex (1)"
|
||||
body: "`trivial` is too complex (1 > 0)"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
@@ -17,7 +17,7 @@ expression: diagnostics
|
||||
parent: ~
|
||||
- kind:
|
||||
name: ComplexStructure
|
||||
body: "`expr_as_statement` is too complex (1)"
|
||||
body: "`expr_as_statement` is too complex (1 > 0)"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
@@ -30,7 +30,7 @@ expression: diagnostics
|
||||
parent: ~
|
||||
- kind:
|
||||
name: ComplexStructure
|
||||
body: "`sequential` is too complex (1)"
|
||||
body: "`sequential` is too complex (1 > 0)"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
@@ -43,7 +43,7 @@ expression: diagnostics
|
||||
parent: ~
|
||||
- kind:
|
||||
name: ComplexStructure
|
||||
body: "`if_elif_else_dead_path` is too complex (3)"
|
||||
body: "`if_elif_else_dead_path` is too complex (3 > 0)"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
@@ -56,7 +56,7 @@ expression: diagnostics
|
||||
parent: ~
|
||||
- kind:
|
||||
name: ComplexStructure
|
||||
body: "`nested_ifs` is too complex (3)"
|
||||
body: "`nested_ifs` is too complex (3 > 0)"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
@@ -69,7 +69,7 @@ expression: diagnostics
|
||||
parent: ~
|
||||
- kind:
|
||||
name: ComplexStructure
|
||||
body: "`for_loop` is too complex (2)"
|
||||
body: "`for_loop` is too complex (2 > 0)"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
@@ -82,7 +82,7 @@ expression: diagnostics
|
||||
parent: ~
|
||||
- kind:
|
||||
name: ComplexStructure
|
||||
body: "`for_else` is too complex (2)"
|
||||
body: "`for_else` is too complex (2 > 0)"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
@@ -95,7 +95,7 @@ expression: diagnostics
|
||||
parent: ~
|
||||
- kind:
|
||||
name: ComplexStructure
|
||||
body: "`recursive` is too complex (2)"
|
||||
body: "`recursive` is too complex (2 > 0)"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
@@ -108,7 +108,7 @@ expression: diagnostics
|
||||
parent: ~
|
||||
- kind:
|
||||
name: ComplexStructure
|
||||
body: "`nested_functions` is too complex (3)"
|
||||
body: "`nested_functions` is too complex (3 > 0)"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
@@ -121,7 +121,7 @@ expression: diagnostics
|
||||
parent: ~
|
||||
- kind:
|
||||
name: ComplexStructure
|
||||
body: "`a` is too complex (2)"
|
||||
body: "`a` is too complex (2 > 0)"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
@@ -134,7 +134,7 @@ expression: diagnostics
|
||||
parent: ~
|
||||
- kind:
|
||||
name: ComplexStructure
|
||||
body: "`b` is too complex (1)"
|
||||
body: "`b` is too complex (1 > 0)"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
@@ -147,7 +147,7 @@ expression: diagnostics
|
||||
parent: ~
|
||||
- kind:
|
||||
name: ComplexStructure
|
||||
body: "`try_else` is too complex (4)"
|
||||
body: "`try_else` is too complex (4 > 0)"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
@@ -160,7 +160,7 @@ expression: diagnostics
|
||||
parent: ~
|
||||
- kind:
|
||||
name: ComplexStructure
|
||||
body: "`nested_try_finally` is too complex (1)"
|
||||
body: "`nested_try_finally` is too complex (1 > 0)"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
@@ -173,7 +173,7 @@ expression: diagnostics
|
||||
parent: ~
|
||||
- kind:
|
||||
name: ComplexStructure
|
||||
body: "`foobar` is too complex (3)"
|
||||
body: "`foobar` is too complex (3 > 0)"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
@@ -186,7 +186,7 @@ expression: diagnostics
|
||||
parent: ~
|
||||
- kind:
|
||||
name: ComplexStructure
|
||||
body: "`annotated_assign` is too complex (1)"
|
||||
body: "`annotated_assign` is too complex (1 > 0)"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
@@ -199,7 +199,7 @@ expression: diagnostics
|
||||
parent: ~
|
||||
- kind:
|
||||
name: ComplexStructure
|
||||
body: "`handle` is too complex (9)"
|
||||
body: "`handle` is too complex (9 > 0)"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
@@ -212,7 +212,7 @@ expression: diagnostics
|
||||
parent: ~
|
||||
- kind:
|
||||
name: ComplexStructure
|
||||
body: "`a` is too complex (1)"
|
||||
body: "`a` is too complex (1 > 0)"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
@@ -225,7 +225,7 @@ expression: diagnostics
|
||||
parent: ~
|
||||
- kind:
|
||||
name: ComplexStructure
|
||||
body: "`b` is too complex (2)"
|
||||
body: "`b` is too complex (2 > 0)"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
@@ -238,7 +238,7 @@ expression: diagnostics
|
||||
parent: ~
|
||||
- kind:
|
||||
name: ComplexStructure
|
||||
body: "`c` is too complex (1)"
|
||||
body: "`c` is too complex (1 > 0)"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
@@ -251,7 +251,7 @@ expression: diagnostics
|
||||
parent: ~
|
||||
- kind:
|
||||
name: ComplexStructure
|
||||
body: "`error` is too complex (1)"
|
||||
body: "`error` is too complex (1 > 0)"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
@@ -264,7 +264,7 @@ expression: diagnostics
|
||||
parent: ~
|
||||
- kind:
|
||||
name: ComplexStructure
|
||||
body: "`info` is too complex (1)"
|
||||
body: "`info` is too complex (1 > 0)"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
@@ -277,7 +277,7 @@ expression: diagnostics
|
||||
parent: ~
|
||||
- kind:
|
||||
name: ComplexStructure
|
||||
body: "`exception` is too complex (1)"
|
||||
body: "`exception` is too complex (1 > 0)"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
|
||||
@@ -4,7 +4,7 @@ expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: ComplexStructure
|
||||
body: "`try_else` is too complex (4)"
|
||||
body: "`try_else` is too complex (4 > 3)"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
@@ -17,7 +17,7 @@ expression: diagnostics
|
||||
parent: ~
|
||||
- kind:
|
||||
name: ComplexStructure
|
||||
body: "`handle` is too complex (9)"
|
||||
body: "`handle` is too complex (9 > 3)"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
|
||||
@@ -47,7 +47,7 @@ mod tests {
|
||||
);
|
||||
let actual: Vec<Rule> = diagnostics
|
||||
.into_iter()
|
||||
.map(|diagnostic| diagnostic.kind.rule().clone())
|
||||
.map(|diagnostic| diagnostic.kind.rule())
|
||||
.collect();
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,8 @@ use rustpython_parser::ast::{Expr, ExprKind};
|
||||
use ruff_diagnostics::Violation;
|
||||
use ruff_diagnostics::{Diagnostic, DiagnosticKind};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::types::{BindingKind, Range};
|
||||
use ruff_python_ast::scope::BindingKind;
|
||||
use ruff_python_ast::types::Range;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::Rule;
|
||||
@@ -52,10 +53,10 @@ impl Violation for UseOfDotValues {
|
||||
pub fn check_attr(checker: &mut Checker, attr: &str, value: &Expr, attr_expr: &Expr) {
|
||||
let rules = &checker.settings.rules;
|
||||
let violation: DiagnosticKind = match attr {
|
||||
"ix" if rules.enabled(&Rule::UseOfDotIx) => UseOfDotIx.into(),
|
||||
"at" if rules.enabled(&Rule::UseOfDotAt) => UseOfDotAt.into(),
|
||||
"iat" if rules.enabled(&Rule::UseOfDotIat) => UseOfDotIat.into(),
|
||||
"values" if rules.enabled(&Rule::UseOfDotValues) => UseOfDotValues.into(),
|
||||
"ix" if rules.enabled(Rule::UseOfDotIx) => UseOfDotIx.into(),
|
||||
"at" if rules.enabled(Rule::UseOfDotAt) => UseOfDotAt.into(),
|
||||
"iat" if rules.enabled(Rule::UseOfDotIat) => UseOfDotIat.into(),
|
||||
"values" if rules.enabled(Rule::UseOfDotValues) => UseOfDotValues.into(),
|
||||
_ => return,
|
||||
};
|
||||
|
||||
|
||||
@@ -3,7 +3,8 @@ use rustpython_parser::ast::{Expr, ExprKind};
|
||||
use ruff_diagnostics::Violation;
|
||||
use ruff_diagnostics::{Diagnostic, DiagnosticKind};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::types::{BindingKind, Range};
|
||||
use ruff_python_ast::scope::BindingKind;
|
||||
use ruff_python_ast::types::Range;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::Rule;
|
||||
@@ -65,13 +66,13 @@ pub fn check_call(checker: &mut Checker, func: &Expr) {
|
||||
let rules = &checker.settings.rules;
|
||||
let ExprKind::Attribute { value, attr, .. } = &func.node else {return};
|
||||
let violation: DiagnosticKind = match attr.as_str() {
|
||||
"isnull" if rules.enabled(&Rule::UseOfDotIsNull) => UseOfDotIsNull.into(),
|
||||
"notnull" if rules.enabled(&Rule::UseOfDotNotNull) => UseOfDotNotNull.into(),
|
||||
"pivot" | "unstack" if rules.enabled(&Rule::UseOfDotPivotOrUnstack) => {
|
||||
"isnull" if rules.enabled(Rule::UseOfDotIsNull) => UseOfDotIsNull.into(),
|
||||
"notnull" if rules.enabled(Rule::UseOfDotNotNull) => UseOfDotNotNull.into(),
|
||||
"pivot" | "unstack" if rules.enabled(Rule::UseOfDotPivotOrUnstack) => {
|
||||
UseOfDotPivotOrUnstack.into()
|
||||
}
|
||||
"read_table" if rules.enabled(&Rule::UseOfDotReadTable) => UseOfDotReadTable.into(),
|
||||
"stack" if rules.enabled(&Rule::UseOfDotStack) => UseOfDotStack.into(),
|
||||
"read_table" if rules.enabled(Rule::UseOfDotReadTable) => UseOfDotReadTable.into(),
|
||||
"stack" if rules.enabled(Rule::UseOfDotStack) => UseOfDotStack.into(),
|
||||
_ => return,
|
||||
};
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@ use rustpython_parser::ast::Stmt;
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::helpers::identifier_range;
|
||||
use ruff_python_ast::scope::{Scope, ScopeKind};
|
||||
use ruff_python_ast::source_code::Locator;
|
||||
use ruff_python_ast::types::{Scope, ScopeKind};
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for functions with "dunder" names (that is, names with two
|
||||
|
||||
@@ -3,7 +3,8 @@ use rustpython_parser::ast::{Arguments, Expr};
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::function_type;
|
||||
use ruff_python_ast::types::{Range, Scope};
|
||||
use ruff_python_ast::scope::Scope;
|
||||
use ruff_python_ast::types::Range;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
|
||||
@@ -3,7 +3,8 @@ use rustpython_parser::ast::{Arguments, Expr};
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::function_type;
|
||||
use ruff_python_ast::types::{Range, Scope};
|
||||
use ruff_python_ast::scope::Scope;
|
||||
use ruff_python_ast::types::Range;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
|
||||
@@ -162,7 +162,7 @@ pub fn compound_statements(
|
||||
Tok::Newline => {
|
||||
if let Some((start, end)) = semi {
|
||||
let mut diagnostic = Diagnostic::new(UselessSemicolon, Range::new(start, end));
|
||||
if autofix.into() && settings.rules.should_fix(&Rule::UselessSemicolon) {
|
||||
if autofix.into() && settings.rules.should_fix(Rule::UselessSemicolon) {
|
||||
diagnostic.amend(Fix::deletion(start, end));
|
||||
};
|
||||
diagnostics.push(diagnostic);
|
||||
|
||||
@@ -4,8 +4,9 @@ use ruff_diagnostics::{AutofixKind, Availability, Diagnostic, Fix, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::helpers::{match_leading_content, match_trailing_content, unparse_stmt};
|
||||
use ruff_python_ast::newlines::StrExt;
|
||||
use ruff_python_ast::scope::ScopeKind;
|
||||
use ruff_python_ast::source_code::Stylist;
|
||||
use ruff_python_ast::types::{Range, ScopeKind};
|
||||
use ruff_python_ast::types::Range;
|
||||
use ruff_python_ast::whitespace::leading_space;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
@@ -65,7 +66,7 @@ pub fn lambda_assignment(checker: &mut Checker, target: &Expr, value: &Expr, stm
|
||||
// package like dataclasses, which wouldn't consider the
|
||||
// rewritten function definition to be equivalent.
|
||||
// See https://github.com/charliermarsh/ruff/issues/3046
|
||||
let fixable = !matches!(checker.ctx.current_scope().kind, ScopeKind::Class(_));
|
||||
let fixable = !matches!(checker.ctx.scope().kind, ScopeKind::Class(_));
|
||||
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
LambdaAssignment {
|
||||
|
||||
@@ -88,22 +88,20 @@ pub fn trailing_whitespace(
|
||||
let end = Location::new(lineno + 1, line_char_count);
|
||||
|
||||
if whitespace_count == line_char_count {
|
||||
if settings.rules.enabled(&Rule::BlankLineContainsWhitespace) {
|
||||
if settings.rules.enabled(Rule::BlankLineContainsWhitespace) {
|
||||
let mut diagnostic =
|
||||
Diagnostic::new(BlankLineContainsWhitespace, Range::new(start, end));
|
||||
if matches!(autofix, flags::Autofix::Enabled)
|
||||
&& settings
|
||||
.rules
|
||||
.should_fix(&Rule::BlankLineContainsWhitespace)
|
||||
&& settings.rules.should_fix(Rule::BlankLineContainsWhitespace)
|
||||
{
|
||||
diagnostic.amend(Fix::deletion(start, end));
|
||||
}
|
||||
return Some(diagnostic);
|
||||
}
|
||||
} else if settings.rules.enabled(&Rule::TrailingWhitespace) {
|
||||
} else if settings.rules.enabled(Rule::TrailingWhitespace) {
|
||||
let mut diagnostic = Diagnostic::new(TrailingWhitespace, Range::new(start, end));
|
||||
if matches!(autofix, flags::Autofix::Enabled)
|
||||
&& settings.rules.should_fix(&Rule::TrailingWhitespace)
|
||||
&& settings.rules.should_fix(Rule::TrailingWhitespace)
|
||||
{
|
||||
diagnostic.amend(Fix::deletion(start, end));
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use itertools::izip;
|
||||
use rustpython_parser::ast::{Cmpop, Constant, Expr, ExprKind};
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::types::Range;
|
||||
@@ -34,9 +35,7 @@ impl Violation for TypeComparison {
|
||||
}
|
||||
|
||||
/// E721
|
||||
pub fn type_comparison(ops: &[Cmpop], comparators: &[Expr], location: Range) -> Vec<Diagnostic> {
|
||||
let mut diagnostics: Vec<Diagnostic> = vec![];
|
||||
|
||||
pub fn type_comparison(checker: &mut Checker, expr: &Expr, ops: &[Cmpop], comparators: &[Expr]) {
|
||||
for (op, right) in izip!(ops, comparators) {
|
||||
if !matches!(op, Cmpop::Is | Cmpop::IsNot | Cmpop::Eq | Cmpop::NotEq) {
|
||||
continue;
|
||||
@@ -44,8 +43,8 @@ pub fn type_comparison(ops: &[Cmpop], comparators: &[Expr], location: Range) ->
|
||||
match &right.node {
|
||||
ExprKind::Call { func, args, .. } => {
|
||||
if let ExprKind::Name { id, .. } = &func.node {
|
||||
// Ex) type(False)
|
||||
if id == "type" {
|
||||
// Ex) `type(False)`
|
||||
if id == "type" && checker.ctx.is_builtin("type") {
|
||||
if let Some(arg) = args.first() {
|
||||
// Allow comparison for types which are not obvious.
|
||||
if !matches!(
|
||||
@@ -56,7 +55,9 @@ pub fn type_comparison(ops: &[Cmpop], comparators: &[Expr], location: Range) ->
|
||||
kind: None
|
||||
}
|
||||
) {
|
||||
diagnostics.push(Diagnostic::new(TypeComparison, location));
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(TypeComparison, Range::from(expr)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,15 +65,22 @@ pub fn type_comparison(ops: &[Cmpop], comparators: &[Expr], location: Range) ->
|
||||
}
|
||||
ExprKind::Attribute { value, .. } => {
|
||||
if let ExprKind::Name { id, .. } = &value.node {
|
||||
// Ex) types.IntType
|
||||
if id == "types" {
|
||||
diagnostics.push(Diagnostic::new(TypeComparison, location));
|
||||
// Ex) `types.NoneType`
|
||||
if id == "types"
|
||||
&& checker
|
||||
.ctx
|
||||
.resolve_call_path(value)
|
||||
.map_or(false, |call_path| {
|
||||
call_path.first().map_or(false, |module| *module == "types")
|
||||
})
|
||||
{
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(TypeComparison, Range::from(expr)));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
diagnostics
|
||||
}
|
||||
|
||||
@@ -153,4 +153,14 @@ mod tests {
|
||||
assert_yaml_snapshot!(diagnostics);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn d209_d400() -> Result<()> {
|
||||
let diagnostics = test_path(
|
||||
Path::new("pydocstyle/D209_D400.py"),
|
||||
&settings::Settings::for_rules([Rule::NewLineAfterLastParagraph, Rule::EndsInPeriod]),
|
||||
)?;
|
||||
assert_yaml_snapshot!(diagnostics);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,11 +65,8 @@ pub fn blank_before_after_class(checker: &mut Checker, docstring: &Docstring) {
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::OneBlankLineBeforeClass)
|
||||
|| checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::NoBlankLineBeforeClass)
|
||||
.enabled(Rule::OneBlankLineBeforeClass)
|
||||
|| checker.settings.rules.enabled(Rule::NoBlankLineBeforeClass)
|
||||
{
|
||||
let before = checker
|
||||
.locator
|
||||
@@ -81,11 +78,7 @@ pub fn blank_before_after_class(checker: &mut Checker, docstring: &Docstring) {
|
||||
.skip(1)
|
||||
.take_while(|line| line.trim().is_empty())
|
||||
.count();
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::NoBlankLineBeforeClass)
|
||||
{
|
||||
if checker.settings.rules.enabled(Rule::NoBlankLineBeforeClass) {
|
||||
if blank_lines_before != 0 {
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
NoBlankLineBeforeClass {
|
||||
@@ -106,7 +99,7 @@ pub fn blank_before_after_class(checker: &mut Checker, docstring: &Docstring) {
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::OneBlankLineBeforeClass)
|
||||
.enabled(Rule::OneBlankLineBeforeClass)
|
||||
{
|
||||
if blank_lines_before != 1 {
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
@@ -128,11 +121,7 @@ pub fn blank_before_after_class(checker: &mut Checker, docstring: &Docstring) {
|
||||
}
|
||||
}
|
||||
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::OneBlankLineAfterClass)
|
||||
{
|
||||
if checker.settings.rules.enabled(Rule::OneBlankLineAfterClass) {
|
||||
let after = checker.locator.slice(Range::new(
|
||||
docstring.expr.end_location.unwrap(),
|
||||
parent.end_location.unwrap(),
|
||||
|
||||
@@ -61,7 +61,7 @@ pub fn blank_before_after_function(checker: &mut Checker, docstring: &Docstring)
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::NoBlankLineBeforeFunction)
|
||||
.enabled(Rule::NoBlankLineBeforeFunction)
|
||||
{
|
||||
let before = checker
|
||||
.locator
|
||||
@@ -94,7 +94,7 @@ pub fn blank_before_after_function(checker: &mut Checker, docstring: &Docstring)
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::NoBlankLineAfterFunction)
|
||||
.enabled(Rule::NoBlankLineAfterFunction)
|
||||
{
|
||||
let after = checker.locator.slice(Range::new(
|
||||
docstring.expr.end_location.unwrap(),
|
||||
|
||||
@@ -80,7 +80,7 @@ pub fn indent(checker: &mut Checker, docstring: &Docstring) {
|
||||
// yet.
|
||||
has_seen_tab = has_seen_tab || line_indent.contains('\t');
|
||||
|
||||
if checker.settings.rules.enabled(&Rule::NoUnderIndentation) {
|
||||
if checker.settings.rules.enabled(Rule::NoUnderIndentation) {
|
||||
// We report under-indentation on every line. This isn't great, but enables
|
||||
// autofix.
|
||||
if (i == lines.len() - 1 || !is_blank)
|
||||
@@ -119,7 +119,7 @@ pub fn indent(checker: &mut Checker, docstring: &Docstring) {
|
||||
}
|
||||
}
|
||||
|
||||
if checker.settings.rules.enabled(&Rule::IndentWithSpaces) {
|
||||
if checker.settings.rules.enabled(Rule::IndentWithSpaces) {
|
||||
if has_seen_tab {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
IndentWithSpaces,
|
||||
@@ -128,7 +128,7 @@ pub fn indent(checker: &mut Checker, docstring: &Docstring) {
|
||||
}
|
||||
}
|
||||
|
||||
if checker.settings.rules.enabled(&Rule::NoOverIndentation) {
|
||||
if checker.settings.rules.enabled(Rule::NoOverIndentation) {
|
||||
// If every line (except the last) is over-indented...
|
||||
if is_over_indented {
|
||||
for i in over_indented_lines {
|
||||
|
||||
@@ -56,7 +56,7 @@ pub fn multi_line_summary_start(checker: &mut Checker, docstring: &Docstring) {
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::MultiLineSummaryFirstLine)
|
||||
.enabled(Rule::MultiLineSummaryFirstLine)
|
||||
{
|
||||
let mut diagnostic =
|
||||
Diagnostic::new(MultiLineSummaryFirstLine, Range::from(docstring.expr));
|
||||
@@ -81,7 +81,7 @@ pub fn multi_line_summary_start(checker: &mut Checker, docstring: &Docstring) {
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::MultiLineSummarySecondLine)
|
||||
.enabled(Rule::MultiLineSummarySecondLine)
|
||||
{
|
||||
let mut diagnostic =
|
||||
Diagnostic::new(MultiLineSummarySecondLine, Range::from(docstring.expr));
|
||||
|
||||
@@ -22,7 +22,7 @@ pub fn not_empty(checker: &mut Checker, docstring: &Docstring) -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
if checker.settings.rules.enabled(&Rule::EmptyDocstring) {
|
||||
if checker.settings.rules.enabled(Rule::EmptyDocstring) {
|
||||
checker
|
||||
.diagnostics
|
||||
.push(Diagnostic::new(EmptyDocstring, Range::from(docstring.expr)));
|
||||
|
||||
@@ -104,7 +104,7 @@ pub fn not_missing(
|
||||
|
||||
match definition.kind {
|
||||
DefinitionKind::Module => {
|
||||
if checker.settings.rules.enabled(&Rule::PublicModule) {
|
||||
if checker.settings.rules.enabled(Rule::PublicModule) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
PublicModule,
|
||||
Range::new(Location::new(1, 0), Location::new(1, 0)),
|
||||
@@ -113,7 +113,7 @@ pub fn not_missing(
|
||||
false
|
||||
}
|
||||
DefinitionKind::Package => {
|
||||
if checker.settings.rules.enabled(&Rule::PublicPackage) {
|
||||
if checker.settings.rules.enabled(Rule::PublicPackage) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
PublicPackage,
|
||||
Range::new(Location::new(1, 0), Location::new(1, 0)),
|
||||
@@ -122,7 +122,7 @@ pub fn not_missing(
|
||||
false
|
||||
}
|
||||
DefinitionKind::Class(stmt) => {
|
||||
if checker.settings.rules.enabled(&Rule::PublicClass) {
|
||||
if checker.settings.rules.enabled(Rule::PublicClass) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
PublicClass,
|
||||
identifier_range(stmt, checker.locator),
|
||||
@@ -131,7 +131,7 @@ pub fn not_missing(
|
||||
false
|
||||
}
|
||||
DefinitionKind::NestedClass(stmt) => {
|
||||
if checker.settings.rules.enabled(&Rule::PublicNestedClass) {
|
||||
if checker.settings.rules.enabled(Rule::PublicNestedClass) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
PublicNestedClass,
|
||||
identifier_range(stmt, checker.locator),
|
||||
@@ -143,7 +143,7 @@ pub fn not_missing(
|
||||
if is_overload(&checker.ctx, cast::decorator_list(stmt)) {
|
||||
true
|
||||
} else {
|
||||
if checker.settings.rules.enabled(&Rule::PublicFunction) {
|
||||
if checker.settings.rules.enabled(Rule::PublicFunction) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
PublicFunction,
|
||||
identifier_range(stmt, checker.locator),
|
||||
@@ -158,7 +158,7 @@ pub fn not_missing(
|
||||
{
|
||||
true
|
||||
} else if is_init(cast::name(stmt)) {
|
||||
if checker.settings.rules.enabled(&Rule::PublicInit) {
|
||||
if checker.settings.rules.enabled(Rule::PublicInit) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
PublicInit,
|
||||
identifier_range(stmt, checker.locator),
|
||||
@@ -166,7 +166,7 @@ pub fn not_missing(
|
||||
}
|
||||
true
|
||||
} else if is_new(cast::name(stmt)) || is_call(cast::name(stmt)) {
|
||||
if checker.settings.rules.enabled(&Rule::PublicMethod) {
|
||||
if checker.settings.rules.enabled(Rule::PublicMethod) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
PublicMethod,
|
||||
identifier_range(stmt, checker.locator),
|
||||
@@ -174,7 +174,7 @@ pub fn not_missing(
|
||||
}
|
||||
true
|
||||
} else if is_magic(cast::name(stmt)) {
|
||||
if checker.settings.rules.enabled(&Rule::MagicMethod) {
|
||||
if checker.settings.rules.enabled(Rule::MagicMethod) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
MagicMethod,
|
||||
identifier_range(stmt, checker.locator),
|
||||
@@ -182,7 +182,7 @@ pub fn not_missing(
|
||||
}
|
||||
true
|
||||
} else {
|
||||
if checker.settings.rules.enabled(&Rule::PublicMethod) {
|
||||
if checker.settings.rules.enabled(Rule::PublicMethod) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
PublicMethod,
|
||||
identifier_range(stmt, checker.locator),
|
||||
|
||||
@@ -353,7 +353,7 @@ fn blanks_and_section_underline(
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::DashedUnderlineAfterSection)
|
||||
.enabled(Rule::DashedUnderlineAfterSection)
|
||||
{
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
DashedUnderlineAfterSection {
|
||||
@@ -365,21 +365,21 @@ fn blanks_and_section_underline(
|
||||
// Add a dashed line (of the appropriate length) under the section header.
|
||||
let content = format!(
|
||||
"{}{}{}",
|
||||
checker.stylist.line_ending().as_str(),
|
||||
whitespace::clean(docstring.indentation),
|
||||
"-".repeat(context.section_name.len()),
|
||||
checker.stylist.line_ending().as_str()
|
||||
);
|
||||
diagnostic.amend(Fix::insertion(
|
||||
content,
|
||||
Location::new(
|
||||
docstring.expr.location.row() + context.original_index + 1,
|
||||
0,
|
||||
docstring.expr.location.row() + context.original_index,
|
||||
context.line.trim_end().chars().count(),
|
||||
),
|
||||
));
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
if checker.settings.rules.enabled(&Rule::EmptyDocstringSection) {
|
||||
if checker.settings.rules.enabled(Rule::EmptyDocstringSection) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
EmptyDocstringSection {
|
||||
name: context.section_name.to_string(),
|
||||
@@ -400,7 +400,7 @@ fn blanks_and_section_underline(
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::SectionUnderlineAfterName)
|
||||
.enabled(Rule::SectionUnderlineAfterName)
|
||||
{
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
SectionUnderlineAfterName {
|
||||
@@ -438,7 +438,7 @@ fn blanks_and_section_underline(
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::SectionUnderlineMatchesSectionLength)
|
||||
.enabled(Rule::SectionUnderlineMatchesSectionLength)
|
||||
{
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
SectionUnderlineMatchesSectionLength {
|
||||
@@ -480,7 +480,7 @@ fn blanks_and_section_underline(
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::SectionUnderlineNotOverIndented)
|
||||
.enabled(Rule::SectionUnderlineNotOverIndented)
|
||||
{
|
||||
let leading_space = whitespace::leading_space(non_empty_line);
|
||||
if leading_space.len() > docstring.indentation.len() {
|
||||
@@ -525,7 +525,7 @@ fn blanks_and_section_underline(
|
||||
.take_while(|line| line.trim().is_empty())
|
||||
.count();
|
||||
if blank_lines_after_dashes == rest_of_lines.len() {
|
||||
if checker.settings.rules.enabled(&Rule::EmptyDocstringSection) {
|
||||
if checker.settings.rules.enabled(Rule::EmptyDocstringSection) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
EmptyDocstringSection {
|
||||
name: context.section_name.to_string(),
|
||||
@@ -537,7 +537,7 @@ fn blanks_and_section_underline(
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::NoBlankLinesBetweenHeaderAndContent)
|
||||
.enabled(Rule::NoBlankLinesBetweenHeaderAndContent)
|
||||
{
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
NoBlankLinesBetweenHeaderAndContent {
|
||||
@@ -570,7 +570,7 @@ fn blanks_and_section_underline(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if checker.settings.rules.enabled(&Rule::EmptyDocstringSection) {
|
||||
if checker.settings.rules.enabled(Rule::EmptyDocstringSection) {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
EmptyDocstringSection {
|
||||
name: context.section_name.to_string(),
|
||||
@@ -583,7 +583,7 @@ fn blanks_and_section_underline(
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::DashedUnderlineAfterSection)
|
||||
.enabled(Rule::DashedUnderlineAfterSection)
|
||||
{
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
DashedUnderlineAfterSection {
|
||||
@@ -595,15 +595,15 @@ fn blanks_and_section_underline(
|
||||
// Add a dashed line (of the appropriate length) under the section header.
|
||||
let content = format!(
|
||||
"{}{}{}",
|
||||
checker.stylist.line_ending().as_str(),
|
||||
whitespace::clean(docstring.indentation),
|
||||
"-".repeat(context.section_name.len()),
|
||||
checker.stylist.line_ending().as_str()
|
||||
);
|
||||
diagnostic.amend(Fix::insertion(
|
||||
content,
|
||||
Location::new(
|
||||
docstring.expr.location.row() + context.original_index + 1,
|
||||
0,
|
||||
docstring.expr.location.row() + context.original_index,
|
||||
context.line.trim_end().chars().count(),
|
||||
),
|
||||
));
|
||||
}
|
||||
@@ -613,7 +613,7 @@ fn blanks_and_section_underline(
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::NoBlankLinesBetweenHeaderAndContent)
|
||||
.enabled(Rule::NoBlankLinesBetweenHeaderAndContent)
|
||||
{
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
NoBlankLinesBetweenHeaderAndContent {
|
||||
@@ -644,7 +644,7 @@ fn blanks_and_section_underline(
|
||||
}
|
||||
|
||||
fn common_section(checker: &mut Checker, docstring: &Docstring, context: &SectionContext) {
|
||||
if checker.settings.rules.enabled(&Rule::CapitalizeSectionName) {
|
||||
if checker.settings.rules.enabled(Rule::CapitalizeSectionName) {
|
||||
let capitalized_section_name = context.kind.as_str();
|
||||
if context.section_name != capitalized_section_name {
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
@@ -677,11 +677,7 @@ fn common_section(checker: &mut Checker, docstring: &Docstring, context: &Sectio
|
||||
}
|
||||
}
|
||||
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::SectionNotOverIndented)
|
||||
{
|
||||
if checker.settings.rules.enabled(Rule::SectionNotOverIndented) {
|
||||
let leading_space = whitespace::leading_space(context.line);
|
||||
if leading_space.len() > docstring.indentation.len() {
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
@@ -715,7 +711,7 @@ fn common_section(checker: &mut Checker, docstring: &Docstring, context: &Sectio
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::BlankLineAfterLastSection)
|
||||
.enabled(Rule::BlankLineAfterLastSection)
|
||||
{
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
BlankLineAfterLastSection {
|
||||
@@ -725,21 +721,21 @@ fn common_section(checker: &mut Checker, docstring: &Docstring, context: &Sectio
|
||||
);
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
// Add a newline after the section.
|
||||
let line = context.following_lines.last().unwrap_or(&context.line);
|
||||
diagnostic.amend(Fix::insertion(
|
||||
line_end.to_string(),
|
||||
format!("{}{}", line_end, docstring.indentation),
|
||||
Location::new(
|
||||
docstring.expr.location.row()
|
||||
+ context.original_index
|
||||
+ 1
|
||||
+ context.following_lines.len(),
|
||||
0,
|
||||
line.trim_end().chars().count(),
|
||||
),
|
||||
));
|
||||
}
|
||||
checker.diagnostics.push(diagnostic);
|
||||
}
|
||||
} else {
|
||||
if checker.settings.rules.enabled(&Rule::BlankLineAfterSection) {
|
||||
if checker.settings.rules.enabled(Rule::BlankLineAfterSection) {
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
BlankLineAfterSection {
|
||||
name: context.section_name.to_string(),
|
||||
@@ -748,14 +744,14 @@ fn common_section(checker: &mut Checker, docstring: &Docstring, context: &Sectio
|
||||
);
|
||||
if checker.patch(diagnostic.kind.rule()) {
|
||||
// Add a newline after the section.
|
||||
let line = context.following_lines.last().unwrap_or(&context.line);
|
||||
diagnostic.amend(Fix::insertion(
|
||||
line_end.to_string(),
|
||||
Location::new(
|
||||
docstring.expr.location.row()
|
||||
+ context.original_index
|
||||
+ 1
|
||||
+ context.following_lines.len(),
|
||||
0,
|
||||
line.trim_end().chars().count(),
|
||||
),
|
||||
));
|
||||
}
|
||||
@@ -764,11 +760,7 @@ fn common_section(checker: &mut Checker, docstring: &Docstring, context: &Sectio
|
||||
}
|
||||
}
|
||||
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::BlankLineBeforeSection)
|
||||
{
|
||||
if checker.settings.rules.enabled(Rule::BlankLineBeforeSection) {
|
||||
if !context.previous_line.is_empty() {
|
||||
let mut diagnostic = Diagnostic::new(
|
||||
BlankLineBeforeSection {
|
||||
@@ -959,7 +951,7 @@ fn numpy_section(checker: &mut Checker, docstring: &Docstring, context: &Section
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::NewLineAfterSectionName)
|
||||
.enabled(Rule::NewLineAfterSectionName)
|
||||
{
|
||||
let suffix = context
|
||||
.line
|
||||
@@ -997,7 +989,7 @@ fn numpy_section(checker: &mut Checker, docstring: &Docstring, context: &Section
|
||||
}
|
||||
}
|
||||
|
||||
if checker.settings.rules.enabled(&Rule::UndocumentedParam) {
|
||||
if checker.settings.rules.enabled(Rule::UndocumentedParam) {
|
||||
if matches!(context.kind, SectionKind::Parameters) {
|
||||
parameters_section(checker, docstring, context);
|
||||
}
|
||||
@@ -1007,11 +999,7 @@ fn numpy_section(checker: &mut Checker, docstring: &Docstring, context: &Section
|
||||
fn google_section(checker: &mut Checker, docstring: &Docstring, context: &SectionContext) {
|
||||
common_section(checker, docstring, context);
|
||||
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::SectionNameEndsInColon)
|
||||
{
|
||||
if checker.settings.rules.enabled(Rule::SectionNameEndsInColon) {
|
||||
let suffix = context
|
||||
.line
|
||||
.trim()
|
||||
@@ -1049,7 +1037,7 @@ fn google_section(checker: &mut Checker, docstring: &Docstring, context: &Sectio
|
||||
}
|
||||
}
|
||||
|
||||
if checker.settings.rules.enabled(&Rule::UndocumentedParam) {
|
||||
if checker.settings.rules.enabled(Rule::UndocumentedParam) {
|
||||
if matches!(context.kind, SectionKind::Args | SectionKind::Arguments) {
|
||||
args_section(checker, docstring, context);
|
||||
}
|
||||
|
||||
@@ -8,18 +8,18 @@ expression: diagnostics
|
||||
suggestion: "Remove over-indentation from \"Returns\""
|
||||
fixable: true
|
||||
location:
|
||||
row: 135
|
||||
row: 144
|
||||
column: 4
|
||||
end_location:
|
||||
row: 141
|
||||
row: 150
|
||||
column: 7
|
||||
fix:
|
||||
content: " "
|
||||
location:
|
||||
row: 137
|
||||
row: 146
|
||||
column: 0
|
||||
end_location:
|
||||
row: 137
|
||||
row: 146
|
||||
column: 8
|
||||
parent: ~
|
||||
|
||||
|
||||
@@ -8,18 +8,18 @@ expression: diagnostics
|
||||
suggestion: "Remove over-indentation from \"Returns\" underline"
|
||||
fixable: true
|
||||
location:
|
||||
row: 147
|
||||
row: 156
|
||||
column: 4
|
||||
end_location:
|
||||
row: 153
|
||||
row: 162
|
||||
column: 7
|
||||
fix:
|
||||
content: " "
|
||||
location:
|
||||
row: 150
|
||||
row: 159
|
||||
column: 0
|
||||
end_location:
|
||||
row: 150
|
||||
row: 159
|
||||
column: 9
|
||||
parent: ~
|
||||
- kind:
|
||||
@@ -28,18 +28,18 @@ expression: diagnostics
|
||||
suggestion: "Remove over-indentation from \"Returns\" underline"
|
||||
fixable: true
|
||||
location:
|
||||
row: 161
|
||||
row: 170
|
||||
column: 4
|
||||
end_location:
|
||||
row: 165
|
||||
row: 174
|
||||
column: 7
|
||||
fix:
|
||||
content: " "
|
||||
location:
|
||||
row: 164
|
||||
row: 173
|
||||
column: 0
|
||||
end_location:
|
||||
row: 164
|
||||
row: 173
|
||||
column: 9
|
||||
parent: ~
|
||||
|
||||
|
||||
@@ -28,18 +28,18 @@ expression: diagnostics
|
||||
suggestion: "Capitalize \"Short summary\""
|
||||
fixable: true
|
||||
location:
|
||||
row: 207
|
||||
row: 216
|
||||
column: 4
|
||||
end_location:
|
||||
row: 221
|
||||
row: 230
|
||||
column: 7
|
||||
fix:
|
||||
content: Short Summary
|
||||
location:
|
||||
row: 209
|
||||
row: 218
|
||||
column: 4
|
||||
end_location:
|
||||
row: 209
|
||||
row: 218
|
||||
column: 17
|
||||
parent: ~
|
||||
|
||||
|
||||
@@ -28,18 +28,18 @@ expression: diagnostics
|
||||
suggestion: "Add newline after \"Raises\""
|
||||
fixable: true
|
||||
location:
|
||||
row: 207
|
||||
row: 216
|
||||
column: 4
|
||||
end_location:
|
||||
row: 221
|
||||
row: 230
|
||||
column: 7
|
||||
fix:
|
||||
content: ""
|
||||
location:
|
||||
row: 218
|
||||
row: 227
|
||||
column: 10
|
||||
end_location:
|
||||
row: 218
|
||||
row: 227
|
||||
column: 11
|
||||
parent: ~
|
||||
|
||||
|
||||
@@ -14,13 +14,13 @@ expression: diagnostics
|
||||
row: 47
|
||||
column: 7
|
||||
fix:
|
||||
content: " -------\n"
|
||||
content: "\n -------"
|
||||
location:
|
||||
row: 45
|
||||
column: 0
|
||||
row: 44
|
||||
column: 11
|
||||
end_location:
|
||||
row: 45
|
||||
column: 0
|
||||
row: 44
|
||||
column: 11
|
||||
parent: ~
|
||||
- kind:
|
||||
name: DashedUnderlineAfterSection
|
||||
@@ -34,53 +34,13 @@ expression: diagnostics
|
||||
row: 58
|
||||
column: 7
|
||||
fix:
|
||||
content: " -------\n"
|
||||
content: "\n -------"
|
||||
location:
|
||||
row: 57
|
||||
column: 0
|
||||
row: 56
|
||||
column: 11
|
||||
end_location:
|
||||
row: 57
|
||||
column: 0
|
||||
parent: ~
|
||||
- kind:
|
||||
name: DashedUnderlineAfterSection
|
||||
body: "Missing dashed underline after section (\"Raises\")"
|
||||
suggestion: "Add dashed line under \"Raises\""
|
||||
fixable: true
|
||||
location:
|
||||
row: 207
|
||||
column: 4
|
||||
end_location:
|
||||
row: 221
|
||||
column: 7
|
||||
fix:
|
||||
content: " ------\n"
|
||||
location:
|
||||
row: 219
|
||||
column: 0
|
||||
end_location:
|
||||
row: 219
|
||||
column: 0
|
||||
parent: ~
|
||||
- kind:
|
||||
name: DashedUnderlineAfterSection
|
||||
body: "Missing dashed underline after section (\"Args\")"
|
||||
suggestion: "Add dashed line under \"Args\""
|
||||
fixable: true
|
||||
location:
|
||||
row: 252
|
||||
column: 4
|
||||
end_location:
|
||||
row: 262
|
||||
column: 7
|
||||
fix:
|
||||
content: " ----\n"
|
||||
location:
|
||||
row: 255
|
||||
column: 0
|
||||
end_location:
|
||||
row: 255
|
||||
column: 0
|
||||
row: 56
|
||||
column: 11
|
||||
parent: ~
|
||||
- kind:
|
||||
name: DashedUnderlineAfterSection
|
||||
@@ -88,19 +48,19 @@ expression: diagnostics
|
||||
suggestion: "Add dashed line under \"Returns\""
|
||||
fixable: true
|
||||
location:
|
||||
row: 252
|
||||
row: 65
|
||||
column: 4
|
||||
end_location:
|
||||
row: 262
|
||||
column: 7
|
||||
row: 67
|
||||
column: 14
|
||||
fix:
|
||||
content: " -------\n"
|
||||
content: "\n -------"
|
||||
location:
|
||||
row: 258
|
||||
column: 0
|
||||
row: 67
|
||||
column: 11
|
||||
end_location:
|
||||
row: 258
|
||||
column: 0
|
||||
row: 67
|
||||
column: 11
|
||||
parent: ~
|
||||
- kind:
|
||||
name: DashedUnderlineAfterSection
|
||||
@@ -108,19 +68,19 @@ expression: diagnostics
|
||||
suggestion: "Add dashed line under \"Raises\""
|
||||
fixable: true
|
||||
location:
|
||||
row: 252
|
||||
row: 216
|
||||
column: 4
|
||||
end_location:
|
||||
row: 262
|
||||
row: 230
|
||||
column: 7
|
||||
fix:
|
||||
content: " ------\n"
|
||||
content: "\n ------"
|
||||
location:
|
||||
row: 260
|
||||
column: 0
|
||||
row: 227
|
||||
column: 11
|
||||
end_location:
|
||||
row: 260
|
||||
column: 0
|
||||
row: 227
|
||||
column: 11
|
||||
parent: ~
|
||||
- kind:
|
||||
name: DashedUnderlineAfterSection
|
||||
@@ -128,19 +88,59 @@ expression: diagnostics
|
||||
suggestion: "Add dashed line under \"Args\""
|
||||
fixable: true
|
||||
location:
|
||||
row: 269
|
||||
row: 261
|
||||
column: 4
|
||||
end_location:
|
||||
row: 274
|
||||
row: 271
|
||||
column: 7
|
||||
fix:
|
||||
content: " ----\n"
|
||||
content: "\n ----"
|
||||
location:
|
||||
row: 272
|
||||
column: 0
|
||||
row: 263
|
||||
column: 9
|
||||
end_location:
|
||||
row: 272
|
||||
column: 0
|
||||
row: 263
|
||||
column: 9
|
||||
parent: ~
|
||||
- kind:
|
||||
name: DashedUnderlineAfterSection
|
||||
body: "Missing dashed underline after section (\"Returns\")"
|
||||
suggestion: "Add dashed line under \"Returns\""
|
||||
fixable: true
|
||||
location:
|
||||
row: 261
|
||||
column: 4
|
||||
end_location:
|
||||
row: 271
|
||||
column: 7
|
||||
fix:
|
||||
content: "\n -------"
|
||||
location:
|
||||
row: 266
|
||||
column: 12
|
||||
end_location:
|
||||
row: 266
|
||||
column: 12
|
||||
parent: ~
|
||||
- kind:
|
||||
name: DashedUnderlineAfterSection
|
||||
body: "Missing dashed underline after section (\"Raises\")"
|
||||
suggestion: "Add dashed line under \"Raises\""
|
||||
fixable: true
|
||||
location:
|
||||
row: 261
|
||||
column: 4
|
||||
end_location:
|
||||
row: 271
|
||||
column: 7
|
||||
fix:
|
||||
content: "\n ------"
|
||||
location:
|
||||
row: 268
|
||||
column: 11
|
||||
end_location:
|
||||
row: 268
|
||||
column: 11
|
||||
parent: ~
|
||||
- kind:
|
||||
name: DashedUnderlineAfterSection
|
||||
@@ -148,39 +148,59 @@ expression: diagnostics
|
||||
suggestion: "Add dashed line under \"Args\""
|
||||
fixable: true
|
||||
location:
|
||||
row: 284
|
||||
row: 278
|
||||
column: 4
|
||||
end_location:
|
||||
row: 283
|
||||
column: 7
|
||||
fix:
|
||||
content: "\n ----"
|
||||
location:
|
||||
row: 280
|
||||
column: 8
|
||||
end_location:
|
||||
row: 280
|
||||
column: 8
|
||||
parent: ~
|
||||
- kind:
|
||||
name: DashedUnderlineAfterSection
|
||||
body: "Missing dashed underline after section (\"Args\")"
|
||||
suggestion: "Add dashed line under \"Args\""
|
||||
fixable: true
|
||||
location:
|
||||
row: 293
|
||||
column: 8
|
||||
end_location:
|
||||
row: 292
|
||||
column: 11
|
||||
fix:
|
||||
content: " ----\n"
|
||||
location:
|
||||
row: 289
|
||||
column: 0
|
||||
end_location:
|
||||
row: 289
|
||||
column: 0
|
||||
parent: ~
|
||||
- kind:
|
||||
name: DashedUnderlineAfterSection
|
||||
body: "Missing dashed underline after section (\"Args\")"
|
||||
suggestion: "Add dashed line under \"Args\""
|
||||
fixable: true
|
||||
location:
|
||||
row: 301
|
||||
column: 11
|
||||
fix:
|
||||
content: "\n ----"
|
||||
location:
|
||||
row: 297
|
||||
column: 13
|
||||
end_location:
|
||||
row: 297
|
||||
column: 13
|
||||
parent: ~
|
||||
- kind:
|
||||
name: DashedUnderlineAfterSection
|
||||
body: "Missing dashed underline after section (\"Args\")"
|
||||
suggestion: "Add dashed line under \"Args\""
|
||||
fixable: true
|
||||
location:
|
||||
row: 310
|
||||
column: 4
|
||||
end_location:
|
||||
row: 306
|
||||
row: 315
|
||||
column: 7
|
||||
fix:
|
||||
content: " ----\n"
|
||||
content: "\n ----"
|
||||
location:
|
||||
row: 304
|
||||
column: 0
|
||||
row: 312
|
||||
column: 9
|
||||
end_location:
|
||||
row: 304
|
||||
column: 0
|
||||
row: 312
|
||||
column: 9
|
||||
parent: ~
|
||||
- kind:
|
||||
name: DashedUnderlineAfterSection
|
||||
@@ -188,19 +208,19 @@ expression: diagnostics
|
||||
suggestion: "Add dashed line under \"Args\""
|
||||
fixable: true
|
||||
location:
|
||||
row: 313
|
||||
row: 322
|
||||
column: 8
|
||||
end_location:
|
||||
row: 319
|
||||
row: 328
|
||||
column: 11
|
||||
fix:
|
||||
content: " ----\n"
|
||||
content: "\n ----"
|
||||
location:
|
||||
row: 316
|
||||
column: 0
|
||||
row: 324
|
||||
column: 13
|
||||
end_location:
|
||||
row: 316
|
||||
column: 0
|
||||
row: 324
|
||||
column: 13
|
||||
parent: ~
|
||||
- kind:
|
||||
name: DashedUnderlineAfterSection
|
||||
@@ -208,19 +228,19 @@ expression: diagnostics
|
||||
suggestion: "Add dashed line under \"Args\""
|
||||
fixable: true
|
||||
location:
|
||||
row: 325
|
||||
row: 334
|
||||
column: 8
|
||||
end_location:
|
||||
row: 330
|
||||
row: 339
|
||||
column: 11
|
||||
fix:
|
||||
content: " ----\n"
|
||||
content: "\n ----"
|
||||
location:
|
||||
row: 328
|
||||
column: 0
|
||||
row: 336
|
||||
column: 13
|
||||
end_location:
|
||||
row: 328
|
||||
column: 0
|
||||
row: 336
|
||||
column: 13
|
||||
parent: ~
|
||||
- kind:
|
||||
name: DashedUnderlineAfterSection
|
||||
@@ -228,19 +248,19 @@ expression: diagnostics
|
||||
suggestion: "Add dashed line under \"Args\""
|
||||
fixable: true
|
||||
location:
|
||||
row: 337
|
||||
row: 346
|
||||
column: 8
|
||||
end_location:
|
||||
row: 343
|
||||
row: 352
|
||||
column: 11
|
||||
fix:
|
||||
content: " ----\n"
|
||||
content: "\n ----"
|
||||
location:
|
||||
row: 340
|
||||
column: 0
|
||||
row: 348
|
||||
column: 13
|
||||
end_location:
|
||||
row: 340
|
||||
column: 0
|
||||
row: 348
|
||||
column: 13
|
||||
parent: ~
|
||||
- kind:
|
||||
name: DashedUnderlineAfterSection
|
||||
@@ -248,39 +268,19 @@ expression: diagnostics
|
||||
suggestion: "Add dashed line under \"Args\""
|
||||
fixable: true
|
||||
location:
|
||||
row: 350
|
||||
row: 359
|
||||
column: 8
|
||||
end_location:
|
||||
row: 355
|
||||
row: 364
|
||||
column: 11
|
||||
fix:
|
||||
content: " ----\n"
|
||||
content: "\n ----"
|
||||
location:
|
||||
row: 353
|
||||
column: 0
|
||||
row: 361
|
||||
column: 13
|
||||
end_location:
|
||||
row: 353
|
||||
column: 0
|
||||
parent: ~
|
||||
- kind:
|
||||
name: DashedUnderlineAfterSection
|
||||
body: "Missing dashed underline after section (\"Args\")"
|
||||
suggestion: "Add dashed line under \"Args\""
|
||||
fixable: true
|
||||
location:
|
||||
row: 362
|
||||
column: 8
|
||||
end_location:
|
||||
row: 367
|
||||
column: 11
|
||||
fix:
|
||||
content: " ----\n"
|
||||
location:
|
||||
row: 365
|
||||
column: 0
|
||||
end_location:
|
||||
row: 365
|
||||
column: 0
|
||||
row: 361
|
||||
column: 13
|
||||
parent: ~
|
||||
- kind:
|
||||
name: DashedUnderlineAfterSection
|
||||
@@ -291,16 +291,16 @@ expression: diagnostics
|
||||
row: 371
|
||||
column: 8
|
||||
end_location:
|
||||
row: 382
|
||||
row: 376
|
||||
column: 11
|
||||
fix:
|
||||
content: " ----\n"
|
||||
content: "\n ----"
|
||||
location:
|
||||
row: 374
|
||||
column: 0
|
||||
row: 373
|
||||
column: 13
|
||||
end_location:
|
||||
row: 374
|
||||
column: 0
|
||||
row: 373
|
||||
column: 13
|
||||
parent: ~
|
||||
- kind:
|
||||
name: DashedUnderlineAfterSection
|
||||
@@ -308,18 +308,38 @@ expression: diagnostics
|
||||
suggestion: "Add dashed line under \"Args\""
|
||||
fixable: true
|
||||
location:
|
||||
row: 490
|
||||
row: 380
|
||||
column: 8
|
||||
end_location:
|
||||
row: 497
|
||||
row: 391
|
||||
column: 11
|
||||
fix:
|
||||
content: " ----\n"
|
||||
content: "\n ----"
|
||||
location:
|
||||
row: 495
|
||||
column: 0
|
||||
row: 382
|
||||
column: 13
|
||||
end_location:
|
||||
row: 495
|
||||
column: 0
|
||||
row: 382
|
||||
column: 13
|
||||
parent: ~
|
||||
- kind:
|
||||
name: DashedUnderlineAfterSection
|
||||
body: "Missing dashed underline after section (\"Args\")"
|
||||
suggestion: "Add dashed line under \"Args\""
|
||||
fixable: true
|
||||
location:
|
||||
row: 499
|
||||
column: 8
|
||||
end_location:
|
||||
row: 506
|
||||
column: 11
|
||||
fix:
|
||||
content: "\n ----"
|
||||
location:
|
||||
row: 503
|
||||
column: 13
|
||||
end_location:
|
||||
row: 503
|
||||
column: 13
|
||||
parent: ~
|
||||
|
||||
|
||||
@@ -8,18 +8,18 @@ expression: diagnostics
|
||||
suggestion: "Add underline to \"Returns\""
|
||||
fixable: true
|
||||
location:
|
||||
row: 85
|
||||
row: 94
|
||||
column: 4
|
||||
end_location:
|
||||
row: 92
|
||||
row: 101
|
||||
column: 7
|
||||
fix:
|
||||
content: ""
|
||||
location:
|
||||
row: 88
|
||||
row: 97
|
||||
column: 0
|
||||
end_location:
|
||||
row: 89
|
||||
row: 98
|
||||
column: 0
|
||||
parent: ~
|
||||
|
||||
|
||||
@@ -8,18 +8,18 @@ expression: diagnostics
|
||||
suggestion: "Adjust underline length to match \"Returns\""
|
||||
fixable: true
|
||||
location:
|
||||
row: 99
|
||||
row: 108
|
||||
column: 4
|
||||
end_location:
|
||||
row: 105
|
||||
row: 114
|
||||
column: 7
|
||||
fix:
|
||||
content: " -------\n"
|
||||
location:
|
||||
row: 102
|
||||
row: 111
|
||||
column: 0
|
||||
end_location:
|
||||
row: 103
|
||||
row: 112
|
||||
column: 0
|
||||
parent: ~
|
||||
- kind:
|
||||
@@ -28,18 +28,18 @@ expression: diagnostics
|
||||
suggestion: "Adjust underline length to match \"Returns\""
|
||||
fixable: true
|
||||
location:
|
||||
row: 207
|
||||
row: 216
|
||||
column: 4
|
||||
end_location:
|
||||
row: 221
|
||||
row: 230
|
||||
column: 7
|
||||
fix:
|
||||
content: " -------\n"
|
||||
location:
|
||||
row: 216
|
||||
row: 225
|
||||
column: 0
|
||||
end_location:
|
||||
row: 217
|
||||
row: 226
|
||||
column: 0
|
||||
parent: ~
|
||||
|
||||
|
||||
@@ -8,19 +8,19 @@ expression: diagnostics
|
||||
suggestion: "Add blank line after \"Returns\""
|
||||
fixable: true
|
||||
location:
|
||||
row: 67
|
||||
row: 76
|
||||
column: 4
|
||||
end_location:
|
||||
row: 78
|
||||
row: 87
|
||||
column: 7
|
||||
fix:
|
||||
content: "\n"
|
||||
location:
|
||||
row: 71
|
||||
column: 0
|
||||
row: 79
|
||||
column: 11
|
||||
end_location:
|
||||
row: 71
|
||||
column: 0
|
||||
row: 79
|
||||
column: 11
|
||||
parent: ~
|
||||
- kind:
|
||||
name: BlankLineAfterSection
|
||||
@@ -28,18 +28,18 @@ expression: diagnostics
|
||||
suggestion: "Add blank line after \"Returns\""
|
||||
fixable: true
|
||||
location:
|
||||
row: 207
|
||||
row: 216
|
||||
column: 4
|
||||
end_location:
|
||||
row: 221
|
||||
row: 230
|
||||
column: 7
|
||||
fix:
|
||||
content: "\n"
|
||||
location:
|
||||
row: 218
|
||||
column: 0
|
||||
row: 226
|
||||
column: 31
|
||||
end_location:
|
||||
row: 218
|
||||
column: 0
|
||||
row: 226
|
||||
column: 31
|
||||
parent: ~
|
||||
|
||||
|
||||
@@ -8,18 +8,18 @@ expression: diagnostics
|
||||
suggestion: "Add blank line before \"Yields\""
|
||||
fixable: true
|
||||
location:
|
||||
row: 67
|
||||
row: 76
|
||||
column: 4
|
||||
end_location:
|
||||
row: 78
|
||||
row: 87
|
||||
column: 7
|
||||
fix:
|
||||
content: "\n"
|
||||
location:
|
||||
row: 71
|
||||
row: 80
|
||||
column: 0
|
||||
end_location:
|
||||
row: 71
|
||||
row: 80
|
||||
column: 0
|
||||
parent: ~
|
||||
- kind:
|
||||
@@ -28,18 +28,18 @@ expression: diagnostics
|
||||
suggestion: "Add blank line before \"Returns\""
|
||||
fixable: true
|
||||
location:
|
||||
row: 122
|
||||
row: 131
|
||||
column: 4
|
||||
end_location:
|
||||
row: 129
|
||||
row: 138
|
||||
column: 7
|
||||
fix:
|
||||
content: "\n"
|
||||
location:
|
||||
row: 125
|
||||
row: 134
|
||||
column: 0
|
||||
end_location:
|
||||
row: 125
|
||||
row: 134
|
||||
column: 0
|
||||
parent: ~
|
||||
- kind:
|
||||
@@ -48,18 +48,18 @@ expression: diagnostics
|
||||
suggestion: "Add blank line before \"Raises\""
|
||||
fixable: true
|
||||
location:
|
||||
row: 207
|
||||
row: 216
|
||||
column: 4
|
||||
end_location:
|
||||
row: 221
|
||||
row: 230
|
||||
column: 7
|
||||
fix:
|
||||
content: "\n"
|
||||
location:
|
||||
row: 218
|
||||
row: 227
|
||||
column: 0
|
||||
end_location:
|
||||
row: 218
|
||||
row: 227
|
||||
column: 0
|
||||
parent: ~
|
||||
|
||||
|
||||
@@ -8,18 +8,18 @@ expression: diagnostics
|
||||
suggestion: Remove blank line(s)
|
||||
fixable: true
|
||||
location:
|
||||
row: 207
|
||||
row: 216
|
||||
column: 4
|
||||
end_location:
|
||||
row: 221
|
||||
row: 230
|
||||
column: 7
|
||||
fix:
|
||||
content: ""
|
||||
location:
|
||||
row: 211
|
||||
row: 220
|
||||
column: 0
|
||||
end_location:
|
||||
row: 212
|
||||
row: 221
|
||||
column: 0
|
||||
parent: ~
|
||||
|
||||
|
||||
@@ -1,6 +1,25 @@
|
||||
---
|
||||
source: src/rules/pydocstyle/mod.rs
|
||||
source: crates/ruff/src/rules/pydocstyle/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
[]
|
||||
- kind:
|
||||
name: BlankLineAfterLastSection
|
||||
body: "Missing blank line after last section (\"Returns\")"
|
||||
suggestion: "Add blank line after \"Returns\""
|
||||
fixable: true
|
||||
location:
|
||||
row: 65
|
||||
column: 4
|
||||
end_location:
|
||||
row: 67
|
||||
column: 14
|
||||
fix:
|
||||
content: "\n "
|
||||
location:
|
||||
row: 67
|
||||
column: 11
|
||||
end_location:
|
||||
row: 67
|
||||
column: 11
|
||||
parent: ~
|
||||
|
||||
|
||||
@@ -21,10 +21,23 @@ expression: diagnostics
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
row: 67
|
||||
row: 65
|
||||
column: 4
|
||||
end_location:
|
||||
row: 78
|
||||
row: 67
|
||||
column: 14
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
name: EmptyDocstringSection
|
||||
body: "Section has no content (\"Returns\")"
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
row: 76
|
||||
column: 4
|
||||
end_location:
|
||||
row: 87
|
||||
column: 7
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -34,10 +47,10 @@ expression: diagnostics
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
row: 67
|
||||
row: 76
|
||||
column: 4
|
||||
end_location:
|
||||
row: 78
|
||||
row: 87
|
||||
column: 7
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -47,10 +60,10 @@ expression: diagnostics
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
row: 161
|
||||
row: 170
|
||||
column: 4
|
||||
end_location:
|
||||
row: 165
|
||||
row: 174
|
||||
column: 7
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -60,10 +73,10 @@ expression: diagnostics
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
row: 252
|
||||
row: 261
|
||||
column: 4
|
||||
end_location:
|
||||
row: 262
|
||||
row: 271
|
||||
column: 7
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
@@ -8,10 +8,10 @@ expression: diagnostics
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
row: 283
|
||||
row: 292
|
||||
column: 8
|
||||
end_location:
|
||||
row: 283
|
||||
row: 292
|
||||
column: 11
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -21,10 +21,10 @@ expression: diagnostics
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
row: 300
|
||||
row: 309
|
||||
column: 4
|
||||
end_location:
|
||||
row: 300
|
||||
row: 309
|
||||
column: 28
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -34,10 +34,10 @@ expression: diagnostics
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
row: 324
|
||||
row: 333
|
||||
column: 8
|
||||
end_location:
|
||||
row: 324
|
||||
row: 333
|
||||
column: 25
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -47,10 +47,10 @@ expression: diagnostics
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
row: 336
|
||||
row: 345
|
||||
column: 8
|
||||
end_location:
|
||||
row: 336
|
||||
row: 345
|
||||
column: 38
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -60,10 +60,10 @@ expression: diagnostics
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
row: 349
|
||||
row: 358
|
||||
column: 8
|
||||
end_location:
|
||||
row: 349
|
||||
row: 358
|
||||
column: 39
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -73,10 +73,10 @@ expression: diagnostics
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
row: 361
|
||||
row: 370
|
||||
column: 8
|
||||
end_location:
|
||||
row: 361
|
||||
row: 370
|
||||
column: 30
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -86,10 +86,10 @@ expression: diagnostics
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
row: 389
|
||||
row: 398
|
||||
column: 4
|
||||
end_location:
|
||||
row: 389
|
||||
row: 398
|
||||
column: 27
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -99,10 +99,10 @@ expression: diagnostics
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
row: 425
|
||||
row: 434
|
||||
column: 8
|
||||
end_location:
|
||||
row: 425
|
||||
row: 434
|
||||
column: 25
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -112,10 +112,10 @@ expression: diagnostics
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
row: 440
|
||||
row: 449
|
||||
column: 8
|
||||
end_location:
|
||||
row: 440
|
||||
row: 449
|
||||
column: 38
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -125,10 +125,10 @@ expression: diagnostics
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
row: 459
|
||||
row: 468
|
||||
column: 8
|
||||
end_location:
|
||||
row: 459
|
||||
row: 468
|
||||
column: 39
|
||||
fix: ~
|
||||
parent: ~
|
||||
@@ -138,10 +138,10 @@ expression: diagnostics
|
||||
suggestion: ~
|
||||
fixable: false
|
||||
location:
|
||||
row: 489
|
||||
row: 498
|
||||
column: 8
|
||||
end_location:
|
||||
row: 489
|
||||
row: 498
|
||||
column: 29
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
source: crates/ruff/src/rules/pydocstyle/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
name: NewLineAfterLastParagraph
|
||||
body: Multi-line docstring closing quotes should be on a separate line
|
||||
suggestion: Move closing quotes to new line
|
||||
fixable: true
|
||||
location:
|
||||
row: 2
|
||||
column: 4
|
||||
end_location:
|
||||
row: 3
|
||||
column: 72
|
||||
fix:
|
||||
content: "\n "
|
||||
location:
|
||||
row: 3
|
||||
column: 69
|
||||
end_location:
|
||||
row: 3
|
||||
column: 69
|
||||
parent: ~
|
||||
- kind:
|
||||
name: EndsInPeriod
|
||||
body: First line should end with a period
|
||||
suggestion: Add period
|
||||
fixable: true
|
||||
location:
|
||||
row: 2
|
||||
column: 4
|
||||
end_location:
|
||||
row: 3
|
||||
column: 72
|
||||
fix:
|
||||
content: "."
|
||||
location:
|
||||
row: 3
|
||||
column: 69
|
||||
end_location:
|
||||
row: 3
|
||||
column: 69
|
||||
parent: ~
|
||||
|
||||
@@ -272,7 +272,7 @@ mod tests {
|
||||
diagnostics.sort_by_key(|diagnostic| diagnostic.location);
|
||||
let actual = diagnostics
|
||||
.iter()
|
||||
.map(|diagnostic| diagnostic.kind.rule().clone())
|
||||
.map(|diagnostic| diagnostic.kind.rule())
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ pub fn repeated_keys(checker: &mut Checker, keys: &[Option<Expr>], values: &[Exp
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::MultiValueRepeatedKeyLiteral)
|
||||
.enabled(Rule::MultiValueRepeatedKeyLiteral)
|
||||
{
|
||||
let comparable_value: ComparableExpr = (&values[i]).into();
|
||||
let is_duplicate_value = seen_values.contains(&comparable_value);
|
||||
@@ -125,7 +125,7 @@ pub fn repeated_keys(checker: &mut Checker, keys: &[Option<Expr>], values: &[Exp
|
||||
if checker
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::MultiValueRepeatedKeyVariable)
|
||||
.enabled(Rule::MultiValueRepeatedKeyVariable)
|
||||
{
|
||||
let comparable_value: ComparableExpr = (&values[i]).into();
|
||||
let is_duplicate_value = seen_values.contains(&comparable_value);
|
||||
|
||||
@@ -2,7 +2,8 @@ use rustpython_parser::ast::Stmt;
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::types::{Range, ScopeKind};
|
||||
use ruff_python_ast::scope::ScopeKind;
|
||||
use ruff_python_ast::types::Range;
|
||||
|
||||
use crate::checkers::ast::Checker;
|
||||
|
||||
@@ -17,7 +18,7 @@ impl Violation for ReturnOutsideFunction {
|
||||
}
|
||||
|
||||
pub fn return_outside_function(checker: &mut Checker, stmt: &Stmt) {
|
||||
if let Some(&index) = checker.ctx.scope_stack.last() {
|
||||
if let Some(index) = checker.ctx.scope_stack.top() {
|
||||
if matches!(
|
||||
checker.ctx.scopes[index].kind,
|
||||
ScopeKind::Class(_) | ScopeKind::Module
|
||||
|
||||
@@ -2,7 +2,8 @@ use std::path::Path;
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::types::{Range, Scope};
|
||||
use ruff_python_ast::scope::Scope;
|
||||
use ruff_python_ast::types::Range;
|
||||
|
||||
#[violation]
|
||||
pub struct UndefinedExport {
|
||||
@@ -27,7 +28,7 @@ pub fn undefined_export(
|
||||
let mut diagnostics = Vec::new();
|
||||
if !scope.import_starred && !path.ends_with("__init__.py") {
|
||||
for name in names {
|
||||
if !scope.bindings.contains_key(name) {
|
||||
if !scope.defines(name) {
|
||||
diagnostics.push(Diagnostic::new(
|
||||
UndefinedExport {
|
||||
name: (*name).to_string(),
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::string::ToString;
|
||||
|
||||
use ruff_diagnostics::{Diagnostic, Violation};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::types::{Binding, Scope, ScopeKind};
|
||||
use ruff_python_ast::scope::{Bindings, Scope, ScopeKind};
|
||||
|
||||
#[violation]
|
||||
pub struct UndefinedLocal {
|
||||
@@ -18,12 +18,12 @@ impl Violation for UndefinedLocal {
|
||||
}
|
||||
|
||||
/// F821
|
||||
pub fn undefined_local(name: &str, scopes: &[&Scope], bindings: &[Binding]) -> Option<Diagnostic> {
|
||||
pub fn undefined_local(name: &str, scopes: &[&Scope], bindings: &Bindings) -> Option<Diagnostic> {
|
||||
let current = &scopes.last().expect("No current scope found");
|
||||
if matches!(current.kind, ScopeKind::Function(_)) && !current.bindings.contains_key(name) {
|
||||
if matches!(current.kind, ScopeKind::Function(_)) && !current.defines(name) {
|
||||
for scope in scopes.iter().rev().skip(1) {
|
||||
if matches!(scope.kind, ScopeKind::Function(_) | ScopeKind::Module) {
|
||||
if let Some(binding) = scope.bindings.get(name).map(|index| &bindings[*index]) {
|
||||
if let Some(binding) = scope.get(name).map(|index| &bindings[*index]) {
|
||||
if let Some((scope_id, location)) = binding.runtime_usage {
|
||||
if scope_id == current.id {
|
||||
return Some(Diagnostic::new(
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user