Compare commits
131 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
41e77bb01d | ||
|
|
2ff3dd5fbe | ||
|
|
0f0e7a521a | ||
|
|
b75663be6d | ||
|
|
4d3d04ee61 | ||
|
|
87422ba362 | ||
|
|
c1d2976fff | ||
|
|
13281cd9ca | ||
|
|
e53652779d | ||
|
|
db4c611c6f | ||
|
|
c25be31eb1 | ||
|
|
a7c533634d | ||
|
|
cfa6883431 | ||
|
|
216aa929af | ||
|
|
9e45424ed6 | ||
|
|
db7f16e276 | ||
|
|
a10a500a26 | ||
|
|
b9fef7cef7 | ||
|
|
34294ccc00 | ||
|
|
a934d01bdb | ||
|
|
0dd590f137 | ||
|
|
909a5c3253 | ||
|
|
5c987874c4 | ||
|
|
0cfe4f9c69 | ||
|
|
6a369e4a30 | ||
|
|
6f97e2c457 | ||
|
|
bebd412469 | ||
|
|
cd1f57b713 | ||
|
|
a0912deb2b | ||
|
|
50ee14a418 | ||
|
|
f5adbbebc5 | ||
|
|
c88e05dc1b | ||
|
|
d658bfc024 | ||
|
|
b0d72c47b4 | ||
|
|
8195873cdf | ||
|
|
bf8108469f | ||
|
|
a2277cfeba | ||
|
|
180541a924 | ||
|
|
34664a0ca0 | ||
|
|
e081455b06 | ||
|
|
4f18fa6733 | ||
|
|
6088a36cd3 | ||
|
|
66a162fa40 | ||
|
|
e6722f92ed | ||
|
|
750c28868f | ||
|
|
5157f584ab | ||
|
|
1c01ec21cb | ||
|
|
879512742f | ||
|
|
a919041dda | ||
|
|
059601d968 | ||
|
|
2ec1701543 | ||
|
|
370c3a5daf | ||
|
|
fdcb78fd8c | ||
|
|
2a744d24e5 | ||
|
|
cc30738148 | ||
|
|
147c6ff1db | ||
|
|
036380e6a8 | ||
|
|
b6587e51ee | ||
|
|
1bc37110d4 | ||
|
|
28acdb76cf | ||
|
|
7b09972c97 | ||
|
|
f8d46d09ef | ||
|
|
294cd95c54 | ||
|
|
d8e709648d | ||
|
|
52cc4d6537 | ||
|
|
08e9d12137 | ||
|
|
39fdc71b49 | ||
|
|
6b0736cf4b | ||
|
|
58269a918a | ||
|
|
9168a12679 | ||
|
|
cb971d3a48 | ||
|
|
57a5071b4e | ||
|
|
976fe364d4 | ||
|
|
028c7855b2 | ||
|
|
e5179f67fd | ||
|
|
c9c199dbca | ||
|
|
70e378b736 | ||
|
|
ca49b00e55 | ||
|
|
f661c90bd7 | ||
|
|
5a84df293f | ||
|
|
23d9309111 | ||
|
|
98ea94fdb7 | ||
|
|
746e1d3436 | ||
|
|
016ff01a04 | ||
|
|
298498e934 | ||
|
|
3ef1c2e303 | ||
|
|
ac028cd9f8 | ||
|
|
c0eb5c28d1 | ||
|
|
a77b4566e4 | ||
|
|
860993187e | ||
|
|
58d4e00604 | ||
|
|
2d95912699 | ||
|
|
4f927fbacc | ||
|
|
2e41301520 | ||
|
|
3179fc110d | ||
|
|
03ae0118b7 | ||
|
|
05176890ee | ||
|
|
849b947b3e | ||
|
|
c314e10e54 | ||
|
|
9eda286dcd | ||
|
|
65a3461519 | ||
|
|
1b8d2df3bf | ||
|
|
179ead0157 | ||
|
|
d451c7a506 | ||
|
|
502ce80c91 | ||
|
|
49d22d8fe2 | ||
|
|
08e0b76587 | ||
|
|
f7515739ac | ||
|
|
53e810ed3e | ||
|
|
66a195f805 | ||
|
|
b8483975a4 | ||
|
|
4dd2032687 | ||
|
|
c6c15d5cf9 | ||
|
|
2bf7b35268 | ||
|
|
6d1adc85fc | ||
|
|
02285c18d1 | ||
|
|
8120d7c974 | ||
|
|
c858804ed4 | ||
|
|
b9d075c252 | ||
|
|
7627e840c9 | ||
|
|
3c03e2cb2e | ||
|
|
aeae63b7ea | ||
|
|
7be17c5f1e | ||
|
|
6128346b08 | ||
|
|
1705574e75 | ||
|
|
15f65fa8d6 | ||
|
|
d1cf0ee52b | ||
|
|
32520ff07f | ||
|
|
3659236580 | ||
|
|
dde69d50b5 | ||
|
|
67198ce7b3 |
3
.github/workflows/docs.yaml
vendored
3
.github/workflows/docs.yaml
vendored
@@ -13,6 +13,9 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup show
|
||||
- uses: Swatinem/rust-cache@v1
|
||||
- name: "Install dependencies"
|
||||
run: |
|
||||
pip install -r docs/requirements.txt
|
||||
|
||||
49
.github/workflows/flake8-to-ruff.yaml
vendored
49
.github/workflows/flake8-to-ruff.yaml
vendored
@@ -27,7 +27,7 @@ jobs:
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup show
|
||||
- name: "Build wheels - x86_64"
|
||||
uses: messense/maturin-action@v1
|
||||
uses: PyO3/maturin-action@v1
|
||||
with:
|
||||
target: x86_64
|
||||
args: --release --out dist --sdist -m ./${{ env.CRATE_NAME }}/Cargo.toml
|
||||
@@ -50,7 +50,7 @@ jobs:
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup show
|
||||
- name: "Build wheels - universal2"
|
||||
uses: messense/maturin-action@v1
|
||||
uses: PyO3/maturin-action@v1
|
||||
with:
|
||||
args: --release --universal2 --out dist -m ./${{ env.CRATE_NAME }}/Cargo.toml
|
||||
- name: "Install built wheel - universal2"
|
||||
@@ -76,7 +76,7 @@ jobs:
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup show
|
||||
- name: "Build wheels"
|
||||
uses: messense/maturin-action@v1
|
||||
uses: PyO3/maturin-action@v1
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
args: --release --out dist -m ./${{ env.CRATE_NAME }}/Cargo.toml
|
||||
@@ -102,7 +102,7 @@ jobs:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
architecture: x64
|
||||
- name: "Build wheels"
|
||||
uses: messense/maturin-action@v1
|
||||
uses: PyO3/maturin-action@v1
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
manylinux: auto
|
||||
@@ -128,7 +128,7 @@ jobs:
|
||||
with:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
- name: "Build wheels"
|
||||
uses: messense/maturin-action@v1
|
||||
uses: PyO3/maturin-action@v1
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
manylinux: auto
|
||||
@@ -166,7 +166,7 @@ jobs:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
architecture: x64
|
||||
- name: "Build wheels"
|
||||
uses: messense/maturin-action@v1
|
||||
uses: PyO3/maturin-action@v1
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
manylinux: musllinux_1_2
|
||||
@@ -201,7 +201,7 @@ jobs:
|
||||
with:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
- name: "Build wheels"
|
||||
uses: messense/maturin-action@v1
|
||||
uses: PyO3/maturin-action@v1
|
||||
with:
|
||||
target: ${{ matrix.platform.target }}
|
||||
manylinux: musllinux_1_2
|
||||
@@ -222,40 +222,6 @@ jobs:
|
||||
name: wheels
|
||||
path: dist
|
||||
|
||||
pypy:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
target: [x86_64, aarch64]
|
||||
python-version:
|
||||
- "3.7"
|
||||
- "3.8"
|
||||
- "3.9"
|
||||
exclude:
|
||||
- os: macos-latest
|
||||
target: aarch64
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: pypy${{ matrix.python-version }}
|
||||
- name: "Build wheels"
|
||||
uses: messense/maturin-action@v1
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
manylinux: auto
|
||||
args: --release --out dist -i pypy${{ matrix.python-version }} -m ./${{ env.CRATE_NAME }}/Cargo.toml
|
||||
- name: "Install built wheel"
|
||||
if: matrix.target == 'x86_64'
|
||||
run: |
|
||||
pip install dist/${{ env.CRATE_NAME }}-*.whl --force-reinstall
|
||||
- name: "Upload wheels"
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: wheels
|
||||
path: dist
|
||||
|
||||
release:
|
||||
name: Release
|
||||
runs-on: ubuntu-latest
|
||||
@@ -267,7 +233,6 @@ jobs:
|
||||
- linux-cross
|
||||
- musllinux
|
||||
- musllinux-cross
|
||||
- pypy
|
||||
steps:
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
|
||||
181
.github/workflows/ruff.yaml
vendored
181
.github/workflows/ruff.yaml
vendored
@@ -2,9 +2,8 @@ name: "[ruff] Release"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
tags:
|
||||
- '**'
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
@@ -30,7 +29,7 @@ jobs:
|
||||
- name: "Prep README.md"
|
||||
run: python scripts/transform_readme.py --target pypi
|
||||
- name: "Build wheels - x86_64"
|
||||
uses: messense/maturin-action@v1
|
||||
uses: PyO3/maturin-action@v1
|
||||
with:
|
||||
target: x86_64
|
||||
args: --release --out dist --sdist
|
||||
@@ -42,6 +41,19 @@ jobs:
|
||||
with:
|
||||
name: wheels
|
||||
path: dist
|
||||
- name: "Archive binary"
|
||||
run: |
|
||||
ARCHIVE_FILE=ruff-x86_64-apple-darwin.tar.gz
|
||||
tar czvf $ARCHIVE_FILE -C target/x86_64-apple-darwin/release ruff
|
||||
shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
|
||||
- name: "Upload binary"
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: binaries
|
||||
path: |
|
||||
*.tar.gz
|
||||
*.sha256
|
||||
|
||||
macos-universal:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
@@ -53,7 +65,7 @@ jobs:
|
||||
- name: "Prep README.md"
|
||||
run: python scripts/transform_readme.py --target pypi
|
||||
- name: "Build wheels - universal2"
|
||||
uses: messense/maturin-action@v1
|
||||
uses: PyO3/maturin-action@v1
|
||||
with:
|
||||
args: --release --universal2 --out dist
|
||||
- name: "Install built wheel - universal2"
|
||||
@@ -64,26 +76,45 @@ jobs:
|
||||
with:
|
||||
name: wheels
|
||||
path: dist
|
||||
- name: "Archive binary"
|
||||
run: |
|
||||
ARCHIVE_FILE=ruff-aarch64-apple-darwin.tar.gz
|
||||
tar czvf $ARCHIVE_FILE -C target/aarch64-apple-darwin/release ruff
|
||||
shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
|
||||
- name: "Upload binary"
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: binaries
|
||||
path: |
|
||||
*.tar.gz
|
||||
*.sha256
|
||||
|
||||
windows:
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
matrix:
|
||||
target: [x64, x86]
|
||||
platform:
|
||||
- target: x86_64-pc-windows-msvc
|
||||
arch: x64
|
||||
- target: i686-pc-windows-msvc
|
||||
arch: x86
|
||||
- target: aarch64-pc-windows-msvc
|
||||
arch: x64
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
architecture: ${{ matrix.target }}
|
||||
architecture: ${{ matrix.platform.arch }}
|
||||
- name: "Prep README.md"
|
||||
run: python scripts/transform_readme.py --target pypi
|
||||
- name: "Build wheels"
|
||||
uses: messense/maturin-action@v1
|
||||
uses: PyO3/maturin-action@v1
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
target: ${{ matrix.platform.target }}
|
||||
args: --release --out dist
|
||||
- name: "Install built wheel"
|
||||
if: ${{ !startsWith(matrix.platform.target, 'aarch64') }}
|
||||
shell: bash
|
||||
run: |
|
||||
python -m pip install dist/${{ env.PACKAGE_NAME }}-*.whl --force-reinstall
|
||||
@@ -92,12 +123,27 @@ jobs:
|
||||
with:
|
||||
name: wheels
|
||||
path: dist
|
||||
- name: "Archive binary"
|
||||
shell: bash
|
||||
run: |
|
||||
ARCHIVE_FILE=ruff-${{ matrix.platform.target }}.zip
|
||||
7z a $ARCHIVE_FILE ./target/${{ matrix.platform.target }}/release/ruff.exe
|
||||
sha256sum $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
|
||||
- name: "Upload binary"
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: binaries
|
||||
path: |
|
||||
*.zip
|
||||
*.sha256
|
||||
|
||||
linux:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
target: [x86_64, i686]
|
||||
target:
|
||||
- x86_64-unknown-linux-gnu
|
||||
- i686-unknown-linux-gnu
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
@@ -107,13 +153,13 @@ jobs:
|
||||
- name: "Prep README.md"
|
||||
run: python scripts/transform_readme.py --target pypi
|
||||
- name: "Build wheels"
|
||||
uses: messense/maturin-action@v1
|
||||
uses: PyO3/maturin-action@v1
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
manylinux: auto
|
||||
args: --release --out dist
|
||||
- name: "Install built wheel"
|
||||
if: matrix.target == 'x86_64'
|
||||
if: ${{ startsWith(matrix.target, 'x86_64') }}
|
||||
run: |
|
||||
pip install dist/${{ env.PACKAGE_NAME }}-*.whl --force-reinstall
|
||||
- name: "Upload wheels"
|
||||
@@ -121,12 +167,34 @@ jobs:
|
||||
with:
|
||||
name: wheels
|
||||
path: dist
|
||||
- name: "Archive binary"
|
||||
run: |
|
||||
ARCHIVE_FILE=ruff-${{ matrix.target }}.tar.gz
|
||||
tar czvf $ARCHIVE_FILE -C target/${{ matrix.target }}/release ruff
|
||||
shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
|
||||
- name: "Upload binary"
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: binaries
|
||||
path: |
|
||||
*.tar.gz
|
||||
*.sha256
|
||||
|
||||
linux-cross:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
target: [aarch64, armv7, s390x, ppc64le, ppc64]
|
||||
platform:
|
||||
- target: aarch64-unknown-linux-gnu
|
||||
arch: aarch64
|
||||
- target: armv7-unknown-linux-gnueabihf
|
||||
arch: armv7
|
||||
- target: s390x-unknown-linux-gnu
|
||||
arch: s390x
|
||||
- target: powerpc64le-unknown-linux-gnu
|
||||
arch: ppc64le
|
||||
- target: powerpc64-unknown-linux-gnu
|
||||
arch: ppc64
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
@@ -135,16 +203,16 @@ jobs:
|
||||
- name: "Prep README.md"
|
||||
run: python scripts/transform_readme.py --target pypi
|
||||
- name: "Build wheels"
|
||||
uses: messense/maturin-action@v1
|
||||
uses: PyO3/maturin-action@v1
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
target: ${{ matrix.platform.target }}
|
||||
manylinux: auto
|
||||
args: --release --out dist
|
||||
- uses: uraimo/run-on-arch-action@v2.5.0
|
||||
if: matrix.target != 'ppc64'
|
||||
if: matrix.platform.arch != 'ppc64'
|
||||
name: Install built wheel
|
||||
with:
|
||||
arch: ${{ matrix.target }}
|
||||
arch: ${{ matrix.platform.arch }}
|
||||
distro: ubuntu20.04
|
||||
githubToken: ${{ github.token }}
|
||||
install: |
|
||||
@@ -158,6 +226,18 @@ jobs:
|
||||
with:
|
||||
name: wheels
|
||||
path: dist
|
||||
- name: "Archive binary"
|
||||
run: |
|
||||
ARCHIVE_FILE=ruff-${{ matrix.platform.target }}.tar.gz
|
||||
tar czvf $ARCHIVE_FILE -C target/${{ matrix.platform.target }}/release ruff
|
||||
shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
|
||||
- name: "Upload binary"
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: binaries
|
||||
path: |
|
||||
*.tar.gz
|
||||
*.sha256
|
||||
|
||||
musllinux:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -175,7 +255,7 @@ jobs:
|
||||
- name: "Prep README.md"
|
||||
run: python scripts/transform_readme.py --target pypi
|
||||
- name: "Build wheels"
|
||||
uses: messense/maturin-action@v1
|
||||
uses: PyO3/maturin-action@v1
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
manylinux: musllinux_1_2
|
||||
@@ -194,6 +274,18 @@ jobs:
|
||||
with:
|
||||
name: wheels
|
||||
path: dist
|
||||
- name: "Archive binary"
|
||||
run: |
|
||||
ARCHIVE_FILE=ruff-${{ matrix.target }}.tar.gz
|
||||
tar czvf $ARCHIVE_FILE -C target/${{ matrix.target }}/release ruff
|
||||
shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
|
||||
- name: "Upload binary"
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: binaries
|
||||
path: |
|
||||
*.tar.gz
|
||||
*.sha256
|
||||
|
||||
musllinux-cross:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -212,7 +304,7 @@ jobs:
|
||||
- name: "Prep README.md"
|
||||
run: python scripts/transform_readme.py --target pypi
|
||||
- name: "Build wheels"
|
||||
uses: messense/maturin-action@v1
|
||||
uses: PyO3/maturin-action@v1
|
||||
with:
|
||||
target: ${{ matrix.platform.target }}
|
||||
manylinux: musllinux_1_2
|
||||
@@ -232,42 +324,18 @@ jobs:
|
||||
with:
|
||||
name: wheels
|
||||
path: dist
|
||||
|
||||
pypy:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
target: [x86_64, aarch64]
|
||||
python-version:
|
||||
- "3.7"
|
||||
- "3.8"
|
||||
- "3.9"
|
||||
exclude:
|
||||
- os: macos-latest
|
||||
target: aarch64
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: pypy${{ matrix.python-version }}
|
||||
- name: "Prep README.md"
|
||||
run: python scripts/transform_readme.py --target pypi
|
||||
- name: "Build wheels"
|
||||
uses: messense/maturin-action@v1
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
manylinux: auto
|
||||
args: --release --out dist -i pypy${{ matrix.python-version }}
|
||||
- name: "Install built wheel"
|
||||
if: matrix.target == 'x86_64'
|
||||
- name: "Archive binary"
|
||||
run: |
|
||||
pip install dist/${{ env.PACKAGE_NAME }}-*.whl --force-reinstall
|
||||
- name: "Upload wheels"
|
||||
ARCHIVE_FILE=ruff-${{ matrix.platform.target }}.tar.gz
|
||||
tar czvf $ARCHIVE_FILE -C target/${{ matrix.platform.target }}/release ruff
|
||||
shasum -a 256 $ARCHIVE_FILE > $ARCHIVE_FILE.sha256
|
||||
- name: "Upload binary"
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: wheels
|
||||
path: dist
|
||||
name: binaries
|
||||
path: |
|
||||
*.tar.gz
|
||||
*.sha256
|
||||
|
||||
release:
|
||||
name: Release
|
||||
@@ -280,7 +348,6 @@ jobs:
|
||||
- linux-cross
|
||||
- musllinux
|
||||
- musllinux-cross
|
||||
- pypy
|
||||
if: "startsWith(github.ref, 'refs/tags/')"
|
||||
steps:
|
||||
- uses: actions/download-artifact@v3
|
||||
@@ -297,3 +364,11 @@ jobs:
|
||||
- name: "Update pre-commit mirror"
|
||||
run: |
|
||||
curl -X POST -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ${{ secrets.RUFF_PRE_COMMIT_PAT }}" -H "X-GitHub-Api-Version: 2022-11-28" https://api.github.com/repos/charliermarsh/ruff-pre-commit/dispatches --data '{"event_type": "pypi_release"}'
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: binaries
|
||||
path: binaries
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
files: binaries/*
|
||||
|
||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -1,10 +1,6 @@
|
||||
# Local cache
|
||||
.ruff_cache
|
||||
crates/ruff/resources/test/cpython
|
||||
docs/*
|
||||
!docs/rules
|
||||
!docs/assets
|
||||
!docs/requirements.txt
|
||||
mkdocs.yml
|
||||
.overrides
|
||||
|
||||
@@ -191,3 +187,7 @@ cython_debug/
|
||||
|
||||
# Visual Studio Code
|
||||
.vscode/
|
||||
|
||||
# VIM
|
||||
.*.sw?
|
||||
.sw?
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
fail_fast: true
|
||||
repos:
|
||||
- repo: https://github.com/abravalheri/validate-pyproject
|
||||
rev: v0.10.1
|
||||
@@ -12,6 +13,7 @@ repos:
|
||||
- --disable
|
||||
- MD013 # line-length
|
||||
- MD033 # no-inline-html
|
||||
- MD041 # first-line-h1
|
||||
- --
|
||||
|
||||
- repo: local
|
||||
@@ -32,7 +34,11 @@ repos:
|
||||
language: rust
|
||||
types_or: [python, pyi]
|
||||
require_serial: true
|
||||
exclude: ^crates/ruff/resources
|
||||
exclude: |
|
||||
(?x)^(
|
||||
crates/ruff/resources/.*|
|
||||
crates/ruff_python_formatter/resources/.*
|
||||
)$
|
||||
- id: dev-generate-all
|
||||
name: dev-generate-all
|
||||
entry: cargo dev generate-all
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
- [Our Pledge](#our-pledge)
|
||||
- [Our Standards](#our-standards)
|
||||
- [Enforcement Responsibilities](#enforcement-responsibilities)
|
||||
- [Scope](#scope)
|
||||
- [Enforcement](#enforcement)
|
||||
- [Enforcement Guidelines](#enforcement-guidelines)
|
||||
- [1. Correction](#1-correction)
|
||||
- [2. Warning](#2-warning)
|
||||
- [3. Temporary Ban](#3-temporary-ban)
|
||||
- [4. Permanent Ban](#4-permanent-ban)
|
||||
- [Attribution](#attribution)
|
||||
* [Our Pledge](#our-pledge)
|
||||
* [Our Standards](#our-standards)
|
||||
* [Enforcement Responsibilities](#enforcement-responsibilities)
|
||||
* [Scope](#scope)
|
||||
* [Enforcement](#enforcement)
|
||||
* [Enforcement Guidelines](#enforcement-guidelines)
|
||||
* [1. Correction](#1-correction)
|
||||
* [2. Warning](#2-warning)
|
||||
* [3. Temporary Ban](#3-temporary-ban)
|
||||
* [4. Permanent Ban](#4-permanent-ban)
|
||||
* [Attribution](#attribution)
|
||||
|
||||
## Our Pledge
|
||||
|
||||
|
||||
@@ -2,16 +2,16 @@
|
||||
|
||||
Welcome! We're happy to have you here. Thank you in advance for your contribution to Ruff.
|
||||
|
||||
- [The Basics](#the-basics)
|
||||
- [Prerequisites](#prerequisites)
|
||||
- [Development](#development)
|
||||
- [Project Structure](#project-structure)
|
||||
- [Example: Adding a new lint rule](#example-adding-a-new-lint-rule)
|
||||
- [Rule naming convention](#rule-naming-convention)
|
||||
- [Example: Adding a new configuration option](#example-adding-a-new-configuration-option)
|
||||
- [MkDocs](#mkdocs)
|
||||
- [Release Process](#release-process)
|
||||
- [Benchmarks](#benchmarks)
|
||||
* [The Basics](#the-basics)
|
||||
* [Prerequisites](#prerequisites)
|
||||
* [Development](#development)
|
||||
* [Project Structure](#project-structure)
|
||||
* [Example: Adding a new lint rule](#example-adding-a-new-lint-rule)
|
||||
* [Rule naming convention](#rule-naming-convention)
|
||||
* [Example: Adding a new configuration option](#example-adding-a-new-configuration-option)
|
||||
* [MkDocs](#mkdocs)
|
||||
* [Release Process](#release-process)
|
||||
* [Benchmarks](#benchmarks)
|
||||
|
||||
## The Basics
|
||||
|
||||
@@ -94,12 +94,12 @@ The vast majority of the code, including all lint rules, lives in the `ruff` cra
|
||||
|
||||
At time of writing, the repository includes the following crates:
|
||||
|
||||
- `crates/ruff`: library crate containing all lint rules and the core logic for running them.
|
||||
- `crates/ruff_cli`: binary crate containing Ruff's command-line interface.
|
||||
- `crates/ruff_dev`: binary crate containing utilities used in the development of Ruff itself (e.g., `cargo dev generate-all`).
|
||||
- `crates/ruff_macros`: library crate containing macros used by Ruff.
|
||||
- `crates/ruff_python`: library crate implementing Python-specific functionality (e.g., lists of standard library modules by versionb).
|
||||
- `crates/flake8_to_ruff`: binary crate for generating Ruff configuration from Flake8 configuration.
|
||||
* `crates/ruff`: library crate containing all lint rules and the core logic for running them.
|
||||
* `crates/ruff_cli`: binary crate containing Ruff's command-line interface.
|
||||
* `crates/ruff_dev`: binary crate containing utilities used in the development of Ruff itself (e.g., `cargo dev generate-all`).
|
||||
* `crates/ruff_macros`: library crate containing macros used by Ruff.
|
||||
* `crates/ruff_python`: library crate implementing Python-specific functionality (e.g., lists of standard library modules by versionb).
|
||||
* `crates/flake8_to_ruff`: binary crate for generating Ruff configuration from Flake8 configuration.
|
||||
|
||||
### Example: Adding a new lint rule
|
||||
|
||||
@@ -146,7 +146,7 @@ Finally, regenerate the documentation and generated code with `cargo dev generat
|
||||
|
||||
#### Rule naming convention
|
||||
|
||||
The rule name should make sense when read as "allow *rule-name*" or "allow *rule-name* items".
|
||||
The rule name should make sense when read as "allow _rule-name_" or "allow _rule-name_ items".
|
||||
|
||||
This implies that rule names:
|
||||
|
||||
@@ -186,14 +186,19 @@ Finally, regenerate the documentation and generated code with `cargo dev generat
|
||||
To preview any changes to the documentation locally:
|
||||
|
||||
1. Install MkDocs and Material for MkDocs with:
|
||||
|
||||
```shell
|
||||
pip install -r docs/requirements.txt
|
||||
```
|
||||
|
||||
2. Generate the MkDocs site with:
|
||||
|
||||
```shell
|
||||
python scripts/generate_mkdocs.py
|
||||
```
|
||||
|
||||
3. Run the development server with:
|
||||
|
||||
```shell
|
||||
mkdocs serve
|
||||
```
|
||||
|
||||
888
Cargo.lock
generated
888
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
17
Cargo.toml
17
Cargo.toml
@@ -1,11 +1,26 @@
|
||||
[workspace]
|
||||
members = ["crates/*"]
|
||||
default-members = ["crates/ruff", "crates/ruff_cli"]
|
||||
|
||||
[workspace.package]
|
||||
edition = "2021"
|
||||
rust-version = "1.65.0"
|
||||
|
||||
[workspace.dependencies]
|
||||
anyhow = { version = "1.0.66" }
|
||||
clap = { version = "4.0.1", features = ["derive"] }
|
||||
itertools = { version = "0.10.5" }
|
||||
libcst = { git = "https://github.com/charliermarsh/LibCST", rev = "f2f0b7a487a8725d161fe8b3ed73a6758b21e177" }
|
||||
once_cell = { version = "1.16.0" }
|
||||
regex = { version = "1.6.0" }
|
||||
rustc-hash = { version = "1.1.0" }
|
||||
rustpython-common = { git = "https://github.com/RustPython/RustPython.git", rev = "61b48f108982d865524f86624a9d5bc2ae3bccef" }
|
||||
rustpython-parser = { features = ["lalrpop"], git = "https://github.com/RustPython/RustPython.git", rev = "61b48f108982d865524f86624a9d5bc2ae3bccef" }
|
||||
schemars = { version = "0.8.11" }
|
||||
serde = { version = "1.0.147", features = ["derive"] }
|
||||
serde_json = { version = "1.0.87" }
|
||||
strum = { version = "0.24.1", features = ["strum_macros"] }
|
||||
strum_macros = { version = "0.24.3" }
|
||||
toml = { version = "0.6.0" }
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
|
||||
52
LICENSE
52
LICENSE
@@ -1062,3 +1062,55 @@ are:
|
||||
"""
|
||||
|
||||
- flake8-django, licensed under the GPL license.
|
||||
|
||||
- rust-analyzer/text-size, licensed under the MIT license:
|
||||
"""
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
"""
|
||||
|
||||
- rome/tools, licensed under the MIT license:
|
||||
"""
|
||||
MIT License
|
||||
|
||||
Copyright (c) Rome Tools, Inc. and its affiliates.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
"""
|
||||
|
||||
@@ -1,2 +1,7 @@
|
||||
[files]
|
||||
extend-exclude = ["snapshots"]
|
||||
extend-exclude = ["snapshots", "black"]
|
||||
|
||||
[default.extend-words]
|
||||
trivias = "trivias"
|
||||
hel = "hel"
|
||||
whos = "whos"
|
||||
|
||||
7
clippy.toml
Normal file
7
clippy.toml
Normal file
@@ -0,0 +1,7 @@
|
||||
doc-valid-idents = [
|
||||
"StackOverflow",
|
||||
"CodeQL",
|
||||
"IPython",
|
||||
"NumPy",
|
||||
"..",
|
||||
]
|
||||
@@ -1,19 +1,20 @@
|
||||
[package]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.246"
|
||||
edition = "2021"
|
||||
version = "0.0.248"
|
||||
edition = { workspace = true }
|
||||
rust-version = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
anyhow = { version = "1.0.66" }
|
||||
clap = { version = "4.0.1", features = ["derive"] }
|
||||
anyhow = { workspace = true }
|
||||
clap = { workspace = true }
|
||||
colored = { version = "2.0.0" }
|
||||
configparser = { version = "3.0.2" }
|
||||
once_cell = { version = "1.16.0" }
|
||||
regex = { version = "1.6.0" }
|
||||
once_cell = { workspace = true }
|
||||
regex = { workspace = true }
|
||||
ruff = { path = "../ruff", default-features = false }
|
||||
rustc-hash = { version = "1.1.0" }
|
||||
serde = { version = "1.0.147", features = ["derive"] }
|
||||
serde_json = { version = "1.0.87" }
|
||||
strum = { version = "0.24.1", features = ["strum_macros"] }
|
||||
strum_macros = { version = "0.24.3" }
|
||||
toml = { version = "0.6.0" }
|
||||
rustc-hash = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
strum = { workspace = true }
|
||||
strum_macros = { workspace = true }
|
||||
toml = { workspace = true }
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
[package]
|
||||
name = "ruff"
|
||||
version = "0.0.246"
|
||||
version = "0.0.248"
|
||||
authors = ["Charlie Marsh <charlie.r.marsh@gmail.com>"]
|
||||
edition = "2021"
|
||||
rust-version = "1.65.0"
|
||||
edition = { workspace = true }
|
||||
rust-version = { workspace = true }
|
||||
documentation = "https://github.com/charliermarsh/ruff"
|
||||
homepage = "https://github.com/charliermarsh/ruff"
|
||||
repository = "https://github.com/charliermarsh/ruff"
|
||||
@@ -16,12 +16,12 @@ crate-type = ["cdylib", "rlib"]
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
anyhow = { version = "1.0.66" }
|
||||
anyhow = { workspace = true }
|
||||
bisection = { version = "0.1.0" }
|
||||
bitflags = { version = "1.3.2" }
|
||||
cfg-if = { version = "1.0.0" }
|
||||
chrono = { version = "0.4.21", default-features = false, features = ["clock"] }
|
||||
clap = { version = "4.0.1", features = ["derive", "env"] }
|
||||
clap = { workspace = true, features = ["derive", "env", "string"] }
|
||||
colored = { version = "2.0.0" }
|
||||
dirs = { version = "4.0.0" }
|
||||
fern = { version = "0.6.1" }
|
||||
@@ -29,32 +29,32 @@ glob = { version = "0.3.0" }
|
||||
globset = { version = "0.4.9" }
|
||||
ignore = { version = "0.4.18" }
|
||||
imperative = { version = "1.0.3" }
|
||||
itertools = { version = "0.10.5" }
|
||||
itertools = { workspace = true }
|
||||
libcst = { workspace = true }
|
||||
log = { version = "0.4.17" }
|
||||
natord = { version = "1.0.9" }
|
||||
nohash-hasher = { version = "0.2.0" }
|
||||
num-bigint = { version = "0.4.3" }
|
||||
num-traits = "0.2.15"
|
||||
once_cell = { version = "1.16.0" }
|
||||
once_cell = { workspace = true }
|
||||
path-absolutize = { version = "3.0.14", features = ["once_cell_cache", "use_unix_paths_on_wasm"] }
|
||||
regex = { version = "1.6.0" }
|
||||
ruff_macros = { version = "0.0.246", path = "../ruff_macros" }
|
||||
ruff_python = { version = "0.0.246", path = "../ruff_python" }
|
||||
rustc-hash = { version = "1.1.0" }
|
||||
regex = { workspace = true }
|
||||
ruff_macros = { path = "../ruff_macros" }
|
||||
ruff_python = { path = "../ruff_python" }
|
||||
rustc-hash = { workspace = true }
|
||||
rustpython-common = { workspace = true }
|
||||
rustpython-parser = { workspace = true }
|
||||
schemars = { version = "0.8.11" }
|
||||
schemars = { workspace = true }
|
||||
semver = { version = "1.0.16" }
|
||||
serde = { version = "1.0.147", features = ["derive"] }
|
||||
serde = { workspace = true }
|
||||
shellexpand = { version = "3.0.0" }
|
||||
smallvec = { version = "1.10.0" }
|
||||
strum = { version = "0.24.1", features = ["strum_macros"] }
|
||||
strum_macros = { version = "0.24.3" }
|
||||
strum = { workspace = true }
|
||||
strum_macros = { workspace = true }
|
||||
textwrap = { version = "0.16.0" }
|
||||
thiserror = { version = "1.0" }
|
||||
titlecase = { version = "2.2.1" }
|
||||
toml = { version = "0.6.0" }
|
||||
toml = { workspace = true }
|
||||
|
||||
# https://docs.rs/getrandom/0.2.7/getrandom/#webassembly-support
|
||||
# For (future) wasm-pack support
|
||||
|
||||
@@ -103,3 +103,7 @@ class Foo:
|
||||
@classmethod
|
||||
def foo(cls, a: int, b: int) -> int:
|
||||
pass
|
||||
|
||||
# ANN101
|
||||
def foo(self, /, a: int, b: int) -> int:
|
||||
pass
|
||||
|
||||
@@ -17,6 +17,11 @@ s.rstrip(".facebook.com") # warning
|
||||
s.rstrip("e") # no warning
|
||||
s.rstrip("\n\t ") # no warning
|
||||
s.rstrip(r"\n\t ") # warning
|
||||
s.strip("a") # no warning
|
||||
s.strip("あ") # no warning
|
||||
s.strip("ああ") # warning
|
||||
s.strip("\ufeff") # no warning
|
||||
s.strip("\u0074\u0065\u0073\u0074") # warning
|
||||
|
||||
from somewhere import other_type, strip
|
||||
|
||||
|
||||
101
crates/ruff/resources/test/fixtures/flake8_bugbear/B027.pyi
vendored
Normal file
101
crates/ruff/resources/test/fixtures/flake8_bugbear/B027.pyi
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
"""
|
||||
Should emit:
|
||||
B027 - on lines 13, 16, 19, 23
|
||||
"""
|
||||
import abc
|
||||
from abc import ABC
|
||||
from abc import abstractmethod, abstractproperty
|
||||
from abc import abstractmethod as notabstract
|
||||
from abc import abstractproperty as notabstract_property
|
||||
|
||||
|
||||
class AbstractClass(ABC):
|
||||
def empty_1(self): # error
|
||||
...
|
||||
|
||||
def empty_2(self): # error
|
||||
pass
|
||||
|
||||
def empty_3(self): # error
|
||||
"""docstring"""
|
||||
...
|
||||
|
||||
def empty_4(self): # error
|
||||
"""multiple ellipsis/pass"""
|
||||
...
|
||||
pass
|
||||
...
|
||||
pass
|
||||
|
||||
@notabstract
|
||||
def abstract_0(self):
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
def abstract_1(self):
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
def abstract_2(self):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def abstract_3(self):
|
||||
...
|
||||
|
||||
@abc.abstractproperty
|
||||
def abstract_4(self):
|
||||
...
|
||||
|
||||
@abstractproperty
|
||||
def abstract_5(self):
|
||||
...
|
||||
|
||||
@notabstract_property
|
||||
def abstract_6(self):
|
||||
...
|
||||
|
||||
def body_1(self):
|
||||
print("foo")
|
||||
...
|
||||
|
||||
def body_2(self):
|
||||
self.body_1()
|
||||
|
||||
|
||||
class NonAbstractClass:
|
||||
def empty_1(self): # safe
|
||||
...
|
||||
|
||||
def empty_2(self): # safe
|
||||
pass
|
||||
|
||||
|
||||
# ignore @overload, fixes issue #304
|
||||
# ignore overload with other imports, fixes #308
|
||||
import typing
|
||||
import typing as t
|
||||
import typing as anything
|
||||
from typing import Union, overload
|
||||
|
||||
|
||||
class AbstractClass(ABC):
|
||||
@overload
|
||||
def empty_1(self, foo: str):
|
||||
...
|
||||
|
||||
@typing.overload
|
||||
def empty_1(self, foo: int):
|
||||
...
|
||||
|
||||
@t.overload
|
||||
def empty_1(self, foo: list):
|
||||
...
|
||||
|
||||
@anything.overload
|
||||
def empty_1(self, foo: float):
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
def empty_1(self, foo: Union[str, int, list, float]):
|
||||
...
|
||||
@@ -1,6 +1,6 @@
|
||||
"""
|
||||
Should emit:
|
||||
B904 - on lines 10, 11 and 16
|
||||
B904 - on lines 10, 11, 16, 62, and 64
|
||||
"""
|
||||
|
||||
try:
|
||||
@@ -53,3 +53,12 @@ except ImportError:
|
||||
raise ValueError
|
||||
except ValueError:
|
||||
raise
|
||||
|
||||
|
||||
try:
|
||||
...
|
||||
except Exception as e:
|
||||
if ...:
|
||||
raise RuntimeError("boom!")
|
||||
else:
|
||||
raise RuntimeError("bang!")
|
||||
|
||||
@@ -12,7 +12,16 @@ class IncorrectModel(models.Model):
|
||||
urlfield = models.URLField(max_length=255, null=True)
|
||||
|
||||
|
||||
class IncorrectModelWithAliasedBase(DjangoModel):
|
||||
class IncorrectModelWithAlias(DjangoModel):
|
||||
charfield = DjangoModel.CharField(max_length=255, null=True)
|
||||
textfield = SmthCharField(max_length=255, null=True)
|
||||
slugfield = models.SlugField(max_length=255, null=True)
|
||||
emailfield = models.EmailField(max_length=255, null=True)
|
||||
filepathfield = models.FilePathField(max_length=255, null=True)
|
||||
urlfield = models.URLField(max_length=255, null=True)
|
||||
|
||||
|
||||
class IncorrectModelWithoutSuperclass:
|
||||
charfield = DjangoModel.CharField(max_length=255, null=True)
|
||||
textfield = SmthCharField(max_length=255, null=True)
|
||||
slugfield = models.SlugField(max_length=255, null=True)
|
||||
|
||||
@@ -15,3 +15,23 @@ def correct_pre_save_handler():
|
||||
@receiver(pre_save, sender=MyModel)
|
||||
def incorrect_pre_save_handler():
|
||||
pass
|
||||
|
||||
|
||||
@receiver(pre_save, sender=MyModel)
|
||||
@receiver(pre_save, sender=MyModel)
|
||||
@test_decorator
|
||||
def correct_multiple():
|
||||
pass
|
||||
|
||||
|
||||
@receiver(pre_save, sender=MyModel)
|
||||
@receiver(pre_save, sender=MyModel)
|
||||
def correct_multiple():
|
||||
pass
|
||||
|
||||
|
||||
@receiver(pre_save, sender=MyModel)
|
||||
@test_decorator
|
||||
@receiver(pre_save, sender=MyModel)
|
||||
def incorrect_multiple():
|
||||
pass
|
||||
|
||||
@@ -6,13 +6,24 @@ def test_ok():
|
||||
assert something or something_else
|
||||
assert something or something_else and something_third
|
||||
assert not (something and something_else)
|
||||
|
||||
assert something, "something message"
|
||||
assert something or something_else and something_third, "another message"
|
||||
|
||||
def test_error():
|
||||
assert something and something_else
|
||||
assert something and something_else and something_third
|
||||
assert something and not something_else
|
||||
assert something and (something_else or something_third)
|
||||
assert not something and something_else
|
||||
assert not (something or something_else)
|
||||
assert not (something or something_else or something_third)
|
||||
|
||||
# recursive case
|
||||
assert not (a or not (b or c))
|
||||
assert not (a or not (b and c)) # note that we only reduce once here
|
||||
|
||||
# detected, but no autofix for messages
|
||||
assert something and something_else, "error message"
|
||||
assert not (something or something_else and something_third), "with message"
|
||||
# detected, but no autofix for mixed conditions (e.g. `a or b and c`)
|
||||
assert not (something or something_else and something_third)
|
||||
|
||||
@@ -251,3 +251,11 @@ def noreturn_pytest_xfail_2():
|
||||
if x > 0:
|
||||
return 1
|
||||
py_xfail("oof")
|
||||
|
||||
|
||||
def nested(values):
|
||||
if not values:
|
||||
return False
|
||||
|
||||
for value in values:
|
||||
print(value)
|
||||
|
||||
@@ -136,3 +136,24 @@ def nested2(x, y, z):
|
||||
break
|
||||
else:
|
||||
a = z
|
||||
|
||||
|
||||
def elif1(x, y, w, z):
|
||||
for i in x:
|
||||
if i > y:
|
||||
a = z
|
||||
elif i > w:
|
||||
break
|
||||
else:
|
||||
a = z
|
||||
|
||||
|
||||
def elif2(x, y, w, z):
|
||||
for i in x:
|
||||
if i > y:
|
||||
a = z
|
||||
else:
|
||||
if i > w:
|
||||
break
|
||||
else:
|
||||
a = z
|
||||
|
||||
@@ -35,6 +35,13 @@ class Foo(metaclass=BazMeta):
|
||||
return None
|
||||
if self.bar()._private: # SLF001
|
||||
return None
|
||||
if Bar._private_thing: # SLF001
|
||||
return None
|
||||
if Foo._private_thing:
|
||||
return None
|
||||
Foo = Bar()
|
||||
if Foo._private_thing: # SLF001
|
||||
return None
|
||||
return self.bar
|
||||
|
||||
def public_func(self):
|
||||
@@ -49,15 +56,17 @@ class Foo(metaclass=BazMeta):
|
||||
|
||||
foo = Foo()
|
||||
|
||||
print(foo.public_thing)
|
||||
print(foo.public_func())
|
||||
print(foo.__dict__)
|
||||
print(foo.__str__())
|
||||
print(foo().__class__)
|
||||
|
||||
print(foo._private_thing) # SLF001
|
||||
print(foo.__really_private_thing) # SLF001
|
||||
print(foo._private_func()) # SLF001
|
||||
print(foo.__really_private_func(1)) # SLF001
|
||||
print(foo.bar._private) # SLF001
|
||||
print(foo()._private_thing) # SLF001
|
||||
print(foo()._private_thing__) # SLF001
|
||||
|
||||
print(foo.public_thing)
|
||||
print(foo.public_func())
|
||||
print(foo.__dict__)
|
||||
print(foo.__str__())
|
||||
print(foo().__class__)
|
||||
print(foo._asdict())
|
||||
|
||||
@@ -18,8 +18,6 @@ from \
|
||||
..parent\
|
||||
import \
|
||||
world_hello
|
||||
|
||||
# TID252 (without autofix; too many levels up)
|
||||
from ..... import ultragrantparent
|
||||
from ...... import ultragrantparent
|
||||
from ....... import ultragrantparent
|
||||
|
||||
0
crates/ruff/resources/test/fixtures/flake8_tidy_imports/TID252/my_package/__init__.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/flake8_tidy_imports/TID252/my_package/__init__.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/flake8_tidy_imports/TID252/my_package/sublib/__init__.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/flake8_tidy_imports/TID252/my_package/sublib/__init__.py
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
from typing import TYPE_CHECKING, Any, ClassVar
|
||||
|
||||
import attrs
|
||||
|
||||
from ..protocol import commands, definitions, responses
|
||||
from ..server import example
|
||||
from .. import server
|
||||
from . import logger, models
|
||||
10
crates/ruff/resources/test/fixtures/flake8_type_checking/TCH004_13.py
vendored
Normal file
10
crates/ruff/resources/test/fixtures/flake8_type_checking/TCH004_13.py
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Final, Literal, TypeAlias
|
||||
|
||||
RatingKey: TypeAlias = Literal["good", "fair", "poor"]
|
||||
|
||||
RATING_KEYS: Final[tuple[RatingKey, ...]] = ("good", "fair", "poor")
|
||||
23
crates/ruff/resources/test/fixtures/isort/force_to_top.py
vendored
Normal file
23
crates/ruff/resources/test/fixtures/isort/force_to_top.py
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
import lib6
|
||||
import lib2
|
||||
import lib5
|
||||
import lib1
|
||||
import lib3
|
||||
import lib4
|
||||
|
||||
import foo
|
||||
import z
|
||||
from foo import bar
|
||||
from lib1 import foo
|
||||
from lib2 import foo
|
||||
from lib1.lib2 import foo
|
||||
from foo.lib1.bar import baz
|
||||
from lib4 import lib1
|
||||
from lib5 import lib2
|
||||
from lib4 import lib2
|
||||
from lib5 import lib1
|
||||
|
||||
import lib3.lib4
|
||||
import lib3.lib4.lib5
|
||||
from lib3.lib4 import foo
|
||||
from lib3.lib4.lib5 import foo
|
||||
@@ -5,3 +5,4 @@ line-length = 88
|
||||
lines-after-imports = 3
|
||||
lines-between-types = 2
|
||||
known-local-folder = ["ruff"]
|
||||
force-to-top = ["lib1", "lib3", "lib5", "lib3.lib4", "z"]
|
||||
|
||||
4
crates/ruff/resources/test/fixtures/isort/required_imports/multiline_docstring.py
vendored
Normal file
4
crates/ruff/resources/test/fixtures/isort/required_imports/multiline_docstring.py
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
"""a
|
||||
b"""
|
||||
# b
|
||||
import os
|
||||
20
crates/ruff/resources/test/fixtures/numpy/NPY001.py
vendored
Normal file
20
crates/ruff/resources/test/fixtures/numpy/NPY001.py
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
import numpy as npy
|
||||
import numpy as np
|
||||
import numpy
|
||||
|
||||
# Error
|
||||
npy.bool
|
||||
npy.int
|
||||
|
||||
if dtype == np.object:
|
||||
...
|
||||
|
||||
result = result.select_dtypes([np.byte, np.ubyte, np.short, np.ushort, np.int, np.long])
|
||||
|
||||
pdf = pd.DataFrame(
|
||||
data=[[1, 2, 3]],
|
||||
columns=["a", "b", "c"],
|
||||
dtype=numpy.object,
|
||||
)
|
||||
|
||||
_ = arr.astype(np.int)
|
||||
62
crates/ruff/resources/test/fixtures/numpy/NPY002.py
vendored
Normal file
62
crates/ruff/resources/test/fixtures/numpy/NPY002.py
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
# Do this (new version)
|
||||
from numpy.random import default_rng
|
||||
rng = default_rng()
|
||||
vals = rng.standard_normal(10)
|
||||
more_vals = rng.standard_normal(10)
|
||||
numbers = rng.integers(high, size=5)
|
||||
|
||||
# instead of this (legacy version)
|
||||
from numpy import random
|
||||
vals = random.standard_normal(10)
|
||||
more_vals = random.standard_normal(10)
|
||||
numbers = random.integers(high, size=5)
|
||||
|
||||
import numpy
|
||||
numpy.random.seed()
|
||||
numpy.random.get_state()
|
||||
numpy.random.set_state()
|
||||
numpy.random.rand()
|
||||
numpy.random.randn()
|
||||
numpy.random.randint()
|
||||
numpy.random.random_integers()
|
||||
numpy.random.random_sample()
|
||||
numpy.random.choice()
|
||||
numpy.random.bytes()
|
||||
numpy.random.shuffle()
|
||||
numpy.random.permutation()
|
||||
numpy.random.beta()
|
||||
numpy.random.binomial()
|
||||
numpy.random.chisquare()
|
||||
numpy.random.dirichlet()
|
||||
numpy.random.exponential()
|
||||
numpy.random.f()
|
||||
numpy.random.gamma()
|
||||
numpy.random.geometric()
|
||||
numpy.random.get_state()
|
||||
numpy.random.gumbel()
|
||||
numpy.random.hypergeometric()
|
||||
numpy.random.laplace()
|
||||
numpy.random.logistic()
|
||||
numpy.random.lognormal()
|
||||
numpy.random.logseries()
|
||||
numpy.random.multinomial()
|
||||
numpy.random.multivariate_normal()
|
||||
numpy.random.negative_binomial()
|
||||
numpy.random.noncentral_chisquare()
|
||||
numpy.random.noncentral_f()
|
||||
numpy.random.normal()
|
||||
numpy.random.pareto()
|
||||
numpy.random.poisson()
|
||||
numpy.random.power()
|
||||
numpy.random.rayleigh()
|
||||
numpy.random.standard_cauchy()
|
||||
numpy.random.standard_exponential()
|
||||
numpy.random.standard_gamma()
|
||||
numpy.random.standard_normal()
|
||||
numpy.random.standard_t()
|
||||
numpy.random.triangular()
|
||||
numpy.random.uniform()
|
||||
numpy.random.vonmises()
|
||||
numpy.random.wald()
|
||||
numpy.random.weibull()
|
||||
numpy.random.zipf()
|
||||
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/MODULE/__init__.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/MODULE/__init__.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/MODULE/file.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/MODULE/file.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/flake9/__init__.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/flake9/__init__.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/mod with spaces/__init__.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/mod with spaces/__init__.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/mod with spaces/file.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/mod with spaces/file.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/mod with spaces/file2.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/mod with spaces/file2.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/mod-with-dashes/__init__.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/mod-with-dashes/__init__.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/no_module/test.txt
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/no_module/test.txt
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/valid_name/__init__.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/valid_name/__init__.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/valid_name/file-with-dashes.py
vendored
Normal file
0
crates/ruff/resources/test/fixtures/pep8_naming/N999/module/valid_name/file-with-dashes.py
vendored
Normal file
@@ -4,3 +4,5 @@ from __future__ import absolute_import
|
||||
from collections import namedtuple
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import __future__
|
||||
|
||||
@@ -33,3 +33,11 @@ f"{f'{v:0.2f}'}"
|
||||
# Errors
|
||||
f"{v:{f'0.2f'}}"
|
||||
f"{f''}"
|
||||
f"{{test}}"
|
||||
f'{{ 40 }}'
|
||||
f"{{a {{x}}"
|
||||
f"{{{{x}}}}"
|
||||
|
||||
# To be fixed
|
||||
# Error: f-string: single '}' is not allowed at line 41 column 8
|
||||
# f"\{{x}}"
|
||||
|
||||
41
crates/ruff/resources/test/fixtures/pylint/return_in_init.py
vendored
Normal file
41
crates/ruff/resources/test/fixtures/pylint/return_in_init.py
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
def a():
|
||||
return
|
||||
|
||||
def __init__():
|
||||
return
|
||||
|
||||
class A:
|
||||
def __init__(self):
|
||||
return
|
||||
|
||||
|
||||
class B:
|
||||
def __init__(self):
|
||||
return 3
|
||||
|
||||
def gen(self):
|
||||
return 5
|
||||
|
||||
class MyClass:
|
||||
|
||||
def __init__(self):
|
||||
return 1
|
||||
|
||||
class MyClass2:
|
||||
"""dummy class"""
|
||||
|
||||
def __init__(self):
|
||||
return
|
||||
|
||||
|
||||
class MyClass3:
|
||||
"""dummy class"""
|
||||
|
||||
def __init__(self):
|
||||
return None
|
||||
|
||||
class MyClass5:
|
||||
"""dummy class"""
|
||||
|
||||
def __init__(self):
|
||||
self.callable = lambda: (yield None)
|
||||
@@ -113,3 +113,14 @@ def test_break_in_if_orelse():
|
||||
else:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def test_break_in_with():
|
||||
"""no false positive for break in with"""
|
||||
for name in ["demo"]:
|
||||
with open(__file__) as f:
|
||||
if name in f.read():
|
||||
break
|
||||
else:
|
||||
return True
|
||||
return False
|
||||
|
||||
73
crates/ruff/resources/test/fixtures/ruff/RUF006.py
vendored
Normal file
73
crates/ruff/resources/test/fixtures/ruff/RUF006.py
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
import asyncio
|
||||
|
||||
|
||||
# Error
|
||||
def f():
|
||||
asyncio.create_task(coordinator.ws_connect()) # Error
|
||||
|
||||
|
||||
# Error
|
||||
def f():
|
||||
asyncio.ensure_future(coordinator.ws_connect()) # Error
|
||||
|
||||
|
||||
# OK
|
||||
def f():
|
||||
background_tasks = set()
|
||||
|
||||
for i in range(10):
|
||||
task = asyncio.create_task(some_coro(param=i))
|
||||
|
||||
# Add task to the set. This creates a strong reference.
|
||||
background_tasks.add(task)
|
||||
|
||||
# To prevent keeping references to finished tasks forever,
|
||||
# make each task remove its own reference from the set after
|
||||
# completion:
|
||||
task.add_done_callback(background_tasks.discard)
|
||||
|
||||
|
||||
# OK
|
||||
def f():
|
||||
background_tasks = set()
|
||||
|
||||
for i in range(10):
|
||||
task = asyncio.ensure_future(some_coro(param=i))
|
||||
|
||||
# Add task to the set. This creates a strong reference.
|
||||
background_tasks.add(task)
|
||||
|
||||
# To prevent keeping references to finished tasks forever,
|
||||
# make each task remove its own reference from the set after
|
||||
# completion:
|
||||
task.add_done_callback(background_tasks.discard)
|
||||
|
||||
|
||||
# OK
|
||||
def f():
|
||||
ctx.task = asyncio.create_task(make_request())
|
||||
|
||||
|
||||
# OK
|
||||
def f():
|
||||
tasks.append(asyncio.create_task(self._populate_collection(coll, coll_info)))
|
||||
|
||||
|
||||
# OK
|
||||
def f():
|
||||
asyncio.wait([asyncio.create_task(client.close()) for client in clients.values()])
|
||||
|
||||
|
||||
# OK
|
||||
def f():
|
||||
tasks = [asyncio.create_task(task) for task in tasks]
|
||||
|
||||
|
||||
# Ok (false negative)
|
||||
def f():
|
||||
task = asyncio.create_task(coordinator.ws_connect())
|
||||
|
||||
|
||||
# Ok (potential false negative)
|
||||
def f():
|
||||
do_nothing_with_the_task(asyncio.create_task(coordinator.ws_connect()))
|
||||
8
crates/ruff/resources/test/fixtures/ruff/ruff_targeted_noqa.py
vendored
Normal file
8
crates/ruff/resources/test/fixtures/ruff/ruff_targeted_noqa.py
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# ruff: noqa: F401
|
||||
|
||||
import os
|
||||
import foo
|
||||
|
||||
|
||||
def f():
|
||||
x = 1
|
||||
@@ -596,7 +596,7 @@ pub fn has_comments<T>(located: &Located<T>, locator: &Locator) -> bool {
|
||||
|
||||
/// Returns `true` if a [`Range`] includes at least one comment.
|
||||
pub fn has_comments_in(range: Range, locator: &Locator) -> bool {
|
||||
for tok in lexer::make_tokenizer(locator.slice_source_code_range(&range)) {
|
||||
for tok in lexer::make_tokenizer(locator.slice(&range)) {
|
||||
match tok {
|
||||
Ok((_, tok, _)) => {
|
||||
if matches!(tok, Tok::Comment(..)) {
|
||||
@@ -723,7 +723,7 @@ where
|
||||
StmtKind::FunctionDef { .. } | StmtKind::AsyncFunctionDef { .. } => {
|
||||
// Don't recurse.
|
||||
}
|
||||
StmtKind::Return { value } => self.returns.push(value.as_ref().map(|expr| &**expr)),
|
||||
StmtKind::Return { value } => self.returns.push(value.as_deref()),
|
||||
_ => visitor::walk_stmt(self, stmt),
|
||||
}
|
||||
}
|
||||
@@ -756,7 +756,7 @@ pub fn to_relative(absolute: Location, base: Location) -> Location {
|
||||
/// Return `true` if a [`Located`] has leading content.
|
||||
pub fn match_leading_content<T>(located: &Located<T>, locator: &Locator) -> bool {
|
||||
let range = Range::new(Location::new(located.location.row(), 0), located.location);
|
||||
let prefix = locator.slice_source_code_range(&range);
|
||||
let prefix = locator.slice(&range);
|
||||
prefix.chars().any(|char| !char.is_whitespace())
|
||||
}
|
||||
|
||||
@@ -766,7 +766,7 @@ pub fn match_trailing_content<T>(located: &Located<T>, locator: &Locator) -> boo
|
||||
located.end_location.unwrap(),
|
||||
Location::new(located.end_location.unwrap().row() + 1, 0),
|
||||
);
|
||||
let suffix = locator.slice_source_code_range(&range);
|
||||
let suffix = locator.slice(&range);
|
||||
for char in suffix.chars() {
|
||||
if char == '#' {
|
||||
return false;
|
||||
@@ -784,7 +784,7 @@ pub fn match_trailing_comment<T>(located: &Located<T>, locator: &Locator) -> Opt
|
||||
located.end_location.unwrap(),
|
||||
Location::new(located.end_location.unwrap().row() + 1, 0),
|
||||
);
|
||||
let suffix = locator.slice_source_code_range(&range);
|
||||
let suffix = locator.slice(&range);
|
||||
for (i, char) in suffix.chars().enumerate() {
|
||||
if char == '#' {
|
||||
return Some(i);
|
||||
@@ -798,8 +798,7 @@ pub fn match_trailing_comment<T>(located: &Located<T>, locator: &Locator) -> Opt
|
||||
|
||||
/// Return the number of trailing empty lines following a statement.
|
||||
pub fn count_trailing_lines(stmt: &Stmt, locator: &Locator) -> usize {
|
||||
let suffix =
|
||||
locator.slice_source_code_at(Location::new(stmt.end_location.unwrap().row() + 1, 0));
|
||||
let suffix = locator.skip(Location::new(stmt.end_location.unwrap().row() + 1, 0));
|
||||
suffix
|
||||
.lines()
|
||||
.take_while(|line| line.trim().is_empty())
|
||||
@@ -808,7 +807,7 @@ pub fn count_trailing_lines(stmt: &Stmt, locator: &Locator) -> usize {
|
||||
|
||||
/// Return the range of the first parenthesis pair after a given [`Location`].
|
||||
pub fn match_parens(start: Location, locator: &Locator) -> Option<Range> {
|
||||
let contents = locator.slice_source_code_at(start);
|
||||
let contents = locator.skip(start);
|
||||
let mut fix_start = None;
|
||||
let mut fix_end = None;
|
||||
let mut count: usize = 0;
|
||||
@@ -843,7 +842,7 @@ pub fn identifier_range(stmt: &Stmt, locator: &Locator) -> Range {
|
||||
| StmtKind::FunctionDef { .. }
|
||||
| StmtKind::AsyncFunctionDef { .. }
|
||||
) {
|
||||
let contents = locator.slice_source_code_range(&Range::from_located(stmt));
|
||||
let contents = locator.slice(&Range::from_located(stmt));
|
||||
for (start, tok, end) in lexer::make_tokenizer_located(contents, stmt.location).flatten() {
|
||||
if matches!(tok, Tok::Name { .. }) {
|
||||
return Range::new(start, end);
|
||||
@@ -871,7 +870,7 @@ pub fn binding_range(binding: &Binding, locator: &Locator) -> Range {
|
||||
|
||||
// Return the ranges of `Name` tokens within a specified node.
|
||||
pub fn find_names<T>(located: &Located<T>, locator: &Locator) -> Vec<Range> {
|
||||
let contents = locator.slice_source_code_range(&Range::from_located(located));
|
||||
let contents = locator.slice(&Range::from_located(located));
|
||||
lexer::make_tokenizer_located(contents, located.location)
|
||||
.flatten()
|
||||
.filter(|(_, tok, _)| matches!(tok, Tok::Name { .. }))
|
||||
@@ -890,8 +889,7 @@ pub fn excepthandler_name_range(handler: &Excepthandler, locator: &Locator) -> O
|
||||
match (name, type_) {
|
||||
(Some(_), Some(type_)) => {
|
||||
let type_end_location = type_.end_location.unwrap();
|
||||
let contents =
|
||||
locator.slice_source_code_range(&Range::new(type_end_location, body[0].location));
|
||||
let contents = locator.slice(&Range::new(type_end_location, body[0].location));
|
||||
let range = lexer::make_tokenizer_located(contents, type_end_location)
|
||||
.flatten()
|
||||
.tuple_windows()
|
||||
@@ -915,7 +913,7 @@ pub fn except_range(handler: &Excepthandler, locator: &Locator) -> Range {
|
||||
.expect("Expected body to be non-empty")
|
||||
.location
|
||||
};
|
||||
let contents = locator.slice_source_code_range(&Range {
|
||||
let contents = locator.slice(&Range {
|
||||
location: handler.location,
|
||||
end_location: end,
|
||||
});
|
||||
@@ -932,7 +930,7 @@ pub fn except_range(handler: &Excepthandler, locator: &Locator) -> Range {
|
||||
|
||||
/// Find f-strings that don't contain any formatted values in a `JoinedStr`.
|
||||
pub fn find_useless_f_strings(expr: &Expr, locator: &Locator) -> Vec<(Range, Range)> {
|
||||
let contents = locator.slice_source_code_range(&Range::from_located(expr));
|
||||
let contents = locator.slice(&Range::from_located(expr));
|
||||
lexer::make_tokenizer_located(contents, expr.location)
|
||||
.flatten()
|
||||
.filter_map(|(location, tok, end_location)| match tok {
|
||||
@@ -940,7 +938,7 @@ pub fn find_useless_f_strings(expr: &Expr, locator: &Locator) -> Vec<(Range, Ran
|
||||
kind: StringKind::FString | StringKind::RawFString,
|
||||
..
|
||||
} => {
|
||||
let first_char = locator.slice_source_code_range(&Range {
|
||||
let first_char = locator.slice(&Range {
|
||||
location,
|
||||
end_location: Location::new(location.row(), location.column() + 1),
|
||||
});
|
||||
@@ -980,7 +978,7 @@ pub fn else_range(stmt: &Stmt, locator: &Locator) -> Option<Range> {
|
||||
.expect("Expected body to be non-empty")
|
||||
.end_location
|
||||
.unwrap();
|
||||
let contents = locator.slice_source_code_range(&Range {
|
||||
let contents = locator.slice(&Range {
|
||||
location: body_end,
|
||||
end_location: orelse
|
||||
.first()
|
||||
@@ -1002,7 +1000,7 @@ pub fn else_range(stmt: &Stmt, locator: &Locator) -> Option<Range> {
|
||||
|
||||
/// Return the `Range` of the first `Tok::Colon` token in a `Range`.
|
||||
pub fn first_colon_range(range: Range, locator: &Locator) -> Option<Range> {
|
||||
let contents = locator.slice_source_code_range(&range);
|
||||
let contents = locator.slice(&range);
|
||||
let range = lexer::make_tokenizer_located(contents, range.location)
|
||||
.flatten()
|
||||
.find(|(_, kind, _)| matches!(kind, Tok::Colon))
|
||||
@@ -1032,7 +1030,7 @@ pub fn elif_else_range(stmt: &Stmt, locator: &Locator) -> Option<Range> {
|
||||
[stmt, ..] => stmt.location,
|
||||
_ => return None,
|
||||
};
|
||||
let contents = locator.slice_source_code_range(&Range::new(start, end));
|
||||
let contents = locator.slice(&Range::new(start, end));
|
||||
let range = lexer::make_tokenizer_located(contents, start)
|
||||
.flatten()
|
||||
.find(|(_, kind, _)| matches!(kind, Tok::Elif | Tok::Else))
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::source_code::Locator;
|
||||
/// Extract the leading indentation from a line.
|
||||
pub fn indentation<'a, T>(locator: &'a Locator, located: &'a Located<T>) -> Option<&'a str> {
|
||||
let range = Range::from_located(located);
|
||||
let indentation = locator.slice_source_code_range(&Range::new(
|
||||
let indentation = locator.slice(&Range::new(
|
||||
Location::new(range.location.row(), 0),
|
||||
Location::new(range.location.row(), range.location.column()),
|
||||
));
|
||||
|
||||
@@ -81,7 +81,7 @@ fn is_lone_child(child: &Stmt, parent: &Stmt, deleted: &[&Stmt]) -> Result<bool>
|
||||
/// Return the location of a trailing semicolon following a `Stmt`, if it's part
|
||||
/// of a multi-statement line.
|
||||
fn trailing_semicolon(stmt: &Stmt, locator: &Locator) -> Option<Location> {
|
||||
let contents = locator.slice_source_code_at(stmt.end_location.unwrap());
|
||||
let contents = locator.skip(stmt.end_location.unwrap());
|
||||
for (row, line) in LinesWithTrailingNewline::from(contents).enumerate() {
|
||||
let trimmed = line.trim();
|
||||
if trimmed.starts_with(';') {
|
||||
@@ -104,7 +104,7 @@ fn trailing_semicolon(stmt: &Stmt, locator: &Locator) -> Option<Location> {
|
||||
/// Find the next valid break for a `Stmt` after a semicolon.
|
||||
fn next_stmt_break(semicolon: Location, locator: &Locator) -> Location {
|
||||
let start_location = Location::new(semicolon.row(), semicolon.column() + 1);
|
||||
let contents = locator.slice_source_code_at(start_location);
|
||||
let contents = locator.skip(start_location);
|
||||
for (row, line) in LinesWithTrailingNewline::from(contents).enumerate() {
|
||||
let trimmed = line.trim();
|
||||
// Skip past any continuations.
|
||||
@@ -136,7 +136,7 @@ fn next_stmt_break(semicolon: Location, locator: &Locator) -> Location {
|
||||
|
||||
/// Return `true` if a `Stmt` occurs at the end of a file.
|
||||
fn is_end_of_file(stmt: &Stmt, locator: &Locator) -> bool {
|
||||
let contents = locator.slice_source_code_at(stmt.end_location.unwrap());
|
||||
let contents = locator.skip(stmt.end_location.unwrap());
|
||||
contents.is_empty()
|
||||
}
|
||||
|
||||
@@ -209,7 +209,7 @@ pub fn remove_unused_imports<'a>(
|
||||
indexer: &Indexer,
|
||||
stylist: &Stylist,
|
||||
) -> Result<Fix> {
|
||||
let module_text = locator.slice_source_code_range(&Range::from_located(stmt));
|
||||
let module_text = locator.slice(&Range::from_located(stmt));
|
||||
let mut tree = match_module(module_text)?;
|
||||
|
||||
let Some(Statement::Simple(body)) = tree.body.first_mut() else {
|
||||
@@ -339,7 +339,7 @@ pub fn remove_argument(
|
||||
remove_parentheses: bool,
|
||||
) -> Result<Fix> {
|
||||
// TODO(sbrugman): Preserve trailing comments.
|
||||
let contents = locator.slice_source_code_at(stmt_at);
|
||||
let contents = locator.skip(stmt_at);
|
||||
|
||||
let mut fix_start = None;
|
||||
let mut fix_end = None;
|
||||
|
||||
@@ -54,7 +54,7 @@ fn apply_fixes<'a>(
|
||||
}
|
||||
|
||||
// Add all contents from `last_pos` to `fix.location`.
|
||||
let slice = locator.slice_source_code_range(&Range::new(last_pos, fix.location));
|
||||
let slice = locator.slice(&Range::new(last_pos, fix.location));
|
||||
output.push_str(slice);
|
||||
|
||||
// Add the patch itself.
|
||||
@@ -67,7 +67,7 @@ fn apply_fixes<'a>(
|
||||
}
|
||||
|
||||
// Add the remaining content.
|
||||
let slice = locator.slice_source_code_at(last_pos);
|
||||
let slice = locator.skip(last_pos);
|
||||
output.push_str(slice);
|
||||
|
||||
(output, fixed)
|
||||
@@ -78,14 +78,14 @@ pub(crate) fn apply_fix(fix: &Fix, locator: &Locator) -> String {
|
||||
let mut output = String::with_capacity(locator.len());
|
||||
|
||||
// Add all contents from `last_pos` to `fix.location`.
|
||||
let slice = locator.slice_source_code_range(&Range::new(Location::new(1, 0), fix.location));
|
||||
let slice = locator.slice(&Range::new(Location::new(1, 0), fix.location));
|
||||
output.push_str(slice);
|
||||
|
||||
// Add the patch itself.
|
||||
output.push_str(&fix.content);
|
||||
|
||||
// Add the remaining content.
|
||||
let slice = locator.slice_source_code_at(fix.end_location);
|
||||
let slice = locator.skip(fix.end_location);
|
||||
output.push_str(slice);
|
||||
|
||||
output
|
||||
|
||||
@@ -32,14 +32,15 @@ use crate::ast::visitor::{walk_excepthandler, Visitor};
|
||||
use crate::ast::{branch_detection, cast, helpers, operations, typing, visitor};
|
||||
use crate::docstrings::definition::{Definition, DefinitionKind, Docstring, Documentable};
|
||||
use crate::registry::{Diagnostic, Rule};
|
||||
use crate::resolver::is_interface_definition_path;
|
||||
use crate::rules::{
|
||||
flake8_2020, flake8_annotations, flake8_bandit, flake8_blind_except, flake8_boolean_trap,
|
||||
flake8_bugbear, flake8_builtins, flake8_comprehensions, flake8_datetimez, flake8_debugger,
|
||||
flake8_django, flake8_errmsg, flake8_implicit_str_concat, flake8_import_conventions,
|
||||
flake8_logging_format, flake8_pie, flake8_print, flake8_pyi, flake8_pytest_style, flake8_raise,
|
||||
flake8_return, flake8_self, flake8_simplify, flake8_tidy_imports, flake8_type_checking,
|
||||
flake8_unused_arguments, flake8_use_pathlib, mccabe, pandas_vet, pep8_naming, pycodestyle,
|
||||
pydocstyle, pyflakes, pygrep_hooks, pylint, pyupgrade, ruff, tryceratops,
|
||||
flake8_unused_arguments, flake8_use_pathlib, mccabe, numpy, pandas_vet, pep8_naming,
|
||||
pycodestyle, pydocstyle, pyflakes, pygrep_hooks, pylint, pyupgrade, ruff, tryceratops,
|
||||
};
|
||||
use crate::settings::types::PythonVersion;
|
||||
use crate::settings::{flags, Settings};
|
||||
@@ -50,6 +51,7 @@ use crate::{autofix, docstrings, noqa, visibility};
|
||||
const GLOBAL_SCOPE_INDEX: usize = 0;
|
||||
|
||||
type DeferralContext<'a> = (Vec<usize>, Vec<RefEquality<'a, Stmt>>);
|
||||
type AnnotationContext = (bool, bool);
|
||||
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
pub struct Checker<'a> {
|
||||
@@ -57,6 +59,7 @@ pub struct Checker<'a> {
|
||||
pub(crate) path: &'a Path,
|
||||
module_path: Option<Vec<String>>,
|
||||
package: Option<&'a Path>,
|
||||
is_interface_definition: bool,
|
||||
autofix: flags::Autofix,
|
||||
noqa: flags::Noqa,
|
||||
pub(crate) settings: &'a Settings,
|
||||
@@ -84,8 +87,8 @@ pub struct Checker<'a> {
|
||||
pub(crate) scopes: Vec<Scope<'a>>,
|
||||
pub(crate) scope_stack: Vec<usize>,
|
||||
pub(crate) dead_scopes: Vec<(usize, Vec<usize>)>,
|
||||
deferred_string_type_definitions: Vec<(Range, &'a str, bool, DeferralContext<'a>)>,
|
||||
deferred_type_definitions: Vec<(&'a Expr, bool, DeferralContext<'a>)>,
|
||||
deferred_string_type_definitions: Vec<(Range, &'a str, AnnotationContext, DeferralContext<'a>)>,
|
||||
deferred_type_definitions: Vec<(&'a Expr, AnnotationContext, DeferralContext<'a>)>,
|
||||
deferred_functions: Vec<(&'a Stmt, DeferralContext<'a>, VisibleScope)>,
|
||||
deferred_lambdas: Vec<(&'a Expr, DeferralContext<'a>)>,
|
||||
deferred_for_loops: Vec<(&'a Stmt, DeferralContext<'a>)>,
|
||||
@@ -125,6 +128,7 @@ impl<'a> Checker<'a> {
|
||||
style: &'a Stylist,
|
||||
indexer: &'a Indexer,
|
||||
) -> Checker<'a> {
|
||||
let is_interface_definition = is_interface_definition_path(path);
|
||||
Checker {
|
||||
settings,
|
||||
noqa_line_for,
|
||||
@@ -133,6 +137,7 @@ impl<'a> Checker<'a> {
|
||||
path,
|
||||
package,
|
||||
module_path,
|
||||
is_interface_definition,
|
||||
locator,
|
||||
stylist: style,
|
||||
indexer,
|
||||
@@ -172,7 +177,7 @@ impl<'a> Checker<'a> {
|
||||
in_type_checking_block: false,
|
||||
seen_import_boundary: false,
|
||||
futures_allowed: true,
|
||||
annotations_future_enabled: path.extension().map_or(false, |ext| ext == "pyi"),
|
||||
annotations_future_enabled: is_interface_definition,
|
||||
except_handlers: vec![],
|
||||
// Check-specific state.
|
||||
flake8_bugbear_seen: vec![],
|
||||
@@ -464,14 +469,16 @@ where
|
||||
body,
|
||||
..
|
||||
} => {
|
||||
if self.settings.rules.enabled(&Rule::ReceiverDecoratorChecker) {
|
||||
if let Some(diagnostic) =
|
||||
flake8_django::rules::receiver_decorator_checker(decorator_list, |expr| {
|
||||
self.resolve_call_path(expr)
|
||||
})
|
||||
{
|
||||
self.diagnostics.push(diagnostic);
|
||||
}
|
||||
if self
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::NonLeadingReceiverDecorator)
|
||||
{
|
||||
self.diagnostics
|
||||
.extend(flake8_django::rules::non_leading_receiver_decorator(
|
||||
decorator_list,
|
||||
|expr| self.resolve_call_path(expr),
|
||||
));
|
||||
}
|
||||
if self.settings.rules.enabled(&Rule::AmbiguousFunctionName) {
|
||||
if let Some(diagnostic) =
|
||||
@@ -772,6 +779,9 @@ where
|
||||
if self.settings.rules.enabled(&Rule::ReturnOutsideFunction) {
|
||||
pyflakes::rules::return_outside_function(self, stmt);
|
||||
}
|
||||
if self.settings.rules.enabled(&Rule::ReturnInInit) {
|
||||
pylint::rules::return_in_init(self, stmt);
|
||||
}
|
||||
}
|
||||
StmtKind::ClassDef {
|
||||
name,
|
||||
@@ -780,15 +790,15 @@ where
|
||||
decorator_list,
|
||||
body,
|
||||
} => {
|
||||
if self.settings.rules.enabled(&Rule::ModelStringFieldNullable) {
|
||||
if self.settings.rules.enabled(&Rule::NullableModelStringField) {
|
||||
self.diagnostics
|
||||
.extend(flake8_django::rules::model_string_field_nullable(
|
||||
self, bases, body,
|
||||
.extend(flake8_django::rules::nullable_model_string_field(
|
||||
self, body,
|
||||
));
|
||||
}
|
||||
if self.settings.rules.enabled(&Rule::ModelDunderStr) {
|
||||
if self.settings.rules.enabled(&Rule::ModelWithoutDunderStr) {
|
||||
if let Some(diagnostic) =
|
||||
flake8_django::rules::model_dunder_str(self, bases, body, stmt)
|
||||
flake8_django::rules::model_without_dunder_str(self, bases, body, stmt)
|
||||
{
|
||||
self.diagnostics.push(diagnostic);
|
||||
}
|
||||
@@ -832,18 +842,20 @@ where
|
||||
flake8_bugbear::rules::useless_expression(self, body);
|
||||
}
|
||||
|
||||
if self
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::AbstractBaseClassWithoutAbstractMethod)
|
||||
|| self
|
||||
if !self.is_interface_definition {
|
||||
if self
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::EmptyMethodWithoutAbstractDecorator)
|
||||
{
|
||||
flake8_bugbear::rules::abstract_base_class(
|
||||
self, stmt, name, bases, keywords, body,
|
||||
);
|
||||
.enabled(&Rule::AbstractBaseClassWithoutAbstractMethod)
|
||||
|| self
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::EmptyMethodWithoutAbstractDecorator)
|
||||
{
|
||||
flake8_bugbear::rules::abstract_base_class(
|
||||
self, stmt, name, bases, keywords, body,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if self
|
||||
@@ -897,7 +909,38 @@ where
|
||||
}
|
||||
|
||||
for alias in names {
|
||||
if alias.node.name.contains('.') && alias.node.asname.is_none() {
|
||||
if alias.node.name == "__future__" {
|
||||
let name = alias.node.asname.as_ref().unwrap_or(&alias.node.name);
|
||||
self.add_binding(
|
||||
name,
|
||||
Binding {
|
||||
kind: BindingKind::FutureImportation,
|
||||
runtime_usage: None,
|
||||
// Always mark `__future__` imports as used.
|
||||
synthetic_usage: Some((
|
||||
self.scopes[*(self
|
||||
.scope_stack
|
||||
.last()
|
||||
.expect("No current scope found"))]
|
||||
.id,
|
||||
Range::from_located(alias),
|
||||
)),
|
||||
typing_usage: None,
|
||||
range: Range::from_located(alias),
|
||||
source: Some(self.current_stmt().clone()),
|
||||
context: self.execution_context(),
|
||||
},
|
||||
);
|
||||
|
||||
if self.settings.rules.enabled(&Rule::LateFutureImport)
|
||||
&& !self.futures_allowed
|
||||
{
|
||||
self.diagnostics.push(Diagnostic::new(
|
||||
pyflakes::rules::LateFutureImport,
|
||||
Range::from_located(stmt),
|
||||
));
|
||||
}
|
||||
} else if alias.node.name.contains('.') && alias.node.asname.is_none() {
|
||||
// Given `import foo.bar`, `name` would be "foo", and `full_name` would be
|
||||
// "foo.bar".
|
||||
let name = alias.node.name.split('.').next().unwrap();
|
||||
@@ -915,10 +958,6 @@ where
|
||||
},
|
||||
);
|
||||
} else {
|
||||
if let Some(asname) = &alias.node.asname {
|
||||
self.check_builtin_shadowing(asname, stmt, false);
|
||||
}
|
||||
|
||||
// Given `import foo`, `name` and `full_name` would both be `foo`.
|
||||
// Given `import foo as bar`, `name` would be `bar` and `full_name` would
|
||||
// be `foo`.
|
||||
@@ -954,6 +993,10 @@ where
|
||||
context: self.execution_context(),
|
||||
},
|
||||
);
|
||||
|
||||
if let Some(asname) = &alias.node.asname {
|
||||
self.check_builtin_shadowing(asname, stmt, false);
|
||||
}
|
||||
}
|
||||
|
||||
// flake8-debugger
|
||||
@@ -1317,8 +1360,8 @@ where
|
||||
stmt,
|
||||
level.as_ref(),
|
||||
module.as_deref(),
|
||||
self.module_path.as_ref(),
|
||||
&self.settings.flake8_tidy_imports.ban_relative_imports,
|
||||
self.path,
|
||||
)
|
||||
{
|
||||
self.diagnostics.push(diagnostic);
|
||||
@@ -1557,12 +1600,7 @@ where
|
||||
pyflakes::rules::assert_tuple(self, stmt, test);
|
||||
}
|
||||
if self.settings.rules.enabled(&Rule::AssertFalse) {
|
||||
flake8_bugbear::rules::assert_false(
|
||||
self,
|
||||
stmt,
|
||||
test,
|
||||
msg.as_ref().map(|expr| &**expr),
|
||||
);
|
||||
flake8_bugbear::rules::assert_false(self, stmt, test, msg.as_deref());
|
||||
}
|
||||
if self.settings.rules.enabled(&Rule::Assert) {
|
||||
self.diagnostics
|
||||
@@ -1574,11 +1612,12 @@ where
|
||||
}
|
||||
}
|
||||
if self.settings.rules.enabled(&Rule::CompositeAssertion) {
|
||||
if let Some(diagnostic) =
|
||||
flake8_pytest_style::rules::composite_condition(stmt, test)
|
||||
{
|
||||
self.diagnostics.push(diagnostic);
|
||||
}
|
||||
flake8_pytest_style::rules::composite_condition(
|
||||
self,
|
||||
stmt,
|
||||
test,
|
||||
msg.as_deref(),
|
||||
);
|
||||
}
|
||||
}
|
||||
StmtKind::With { items, body, .. } => {
|
||||
@@ -1645,9 +1684,7 @@ where
|
||||
pylint::rules::useless_else_on_loop(self, stmt, body, orelse);
|
||||
}
|
||||
if matches!(stmt.node, StmtKind::For { .. }) {
|
||||
if self.settings.rules.enabled(&Rule::ConvertLoopToAny)
|
||||
|| self.settings.rules.enabled(&Rule::ConvertLoopToAll)
|
||||
{
|
||||
if self.settings.rules.enabled(&Rule::ReimplementedBuiltin) {
|
||||
flake8_simplify::rules::convert_for_loop_to_any_all(
|
||||
self,
|
||||
stmt,
|
||||
@@ -1741,8 +1778,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
if self.settings.rules.enabled(&Rule::PrefixTypeParams) {
|
||||
if self.path.extension().map_or(false, |ext| ext == "pyi") {
|
||||
if self.is_interface_definition {
|
||||
if self.settings.rules.enabled(&Rule::PrefixTypeParams) {
|
||||
flake8_pyi::rules::prefix_type_params(self, value, targets);
|
||||
}
|
||||
}
|
||||
@@ -1797,6 +1834,13 @@ where
|
||||
{
|
||||
flake8_simplify::rules::use_capital_environment_variables(self, value);
|
||||
}
|
||||
if self.settings.rules.enabled(&Rule::AsyncioDanglingTask) {
|
||||
if let Some(diagnostic) = ruff::rules::asyncio_dangling_task(value, |expr| {
|
||||
self.resolve_call_path(expr)
|
||||
}) {
|
||||
self.diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@@ -2067,13 +2111,13 @@ where
|
||||
self.deferred_string_type_definitions.push((
|
||||
Range::from_located(expr),
|
||||
value,
|
||||
self.in_annotation,
|
||||
(self.in_annotation, self.in_type_checking_block),
|
||||
(self.scope_stack.clone(), self.parents.clone()),
|
||||
));
|
||||
} else {
|
||||
self.deferred_type_definitions.push((
|
||||
expr,
|
||||
self.in_annotation,
|
||||
(self.in_annotation, self.in_type_checking_block),
|
||||
(self.scope_stack.clone(), self.parents.clone()),
|
||||
));
|
||||
}
|
||||
@@ -2142,6 +2186,9 @@ where
|
||||
if self.settings.rules.enabled(&Rule::TypingTextStrAlias) {
|
||||
pyupgrade::rules::typing_text_str_alias(self, expr);
|
||||
}
|
||||
if self.settings.rules.enabled(&Rule::NumpyDeprecatedTypeAlias) {
|
||||
numpy::rules::deprecated_type_alias(self, expr);
|
||||
}
|
||||
|
||||
// Ex) List[...]
|
||||
if !self.in_deferred_string_type_definition
|
||||
@@ -2208,6 +2255,9 @@ where
|
||||
if self.settings.rules.enabled(&Rule::TypingTextStrAlias) {
|
||||
pyupgrade::rules::typing_text_str_alias(self, expr);
|
||||
}
|
||||
if self.settings.rules.enabled(&Rule::NumpyDeprecatedTypeAlias) {
|
||||
numpy::rules::deprecated_type_alias(self, expr);
|
||||
}
|
||||
if self.settings.rules.enabled(&Rule::RewriteMockImport) {
|
||||
pyupgrade::rules::rewrite_mock_attribute(self, expr);
|
||||
}
|
||||
@@ -2515,7 +2565,12 @@ where
|
||||
.enabled(&Rule::UnnecessaryCollectionCall)
|
||||
{
|
||||
flake8_comprehensions::rules::unnecessary_collection_call(
|
||||
self, expr, func, args, keywords,
|
||||
self,
|
||||
expr,
|
||||
func,
|
||||
args,
|
||||
keywords,
|
||||
&self.settings.flake8_comprehensions,
|
||||
);
|
||||
}
|
||||
if self
|
||||
@@ -2800,6 +2855,11 @@ where
|
||||
flake8_use_pathlib::helpers::replaceable_by_pathlib(self, func);
|
||||
}
|
||||
|
||||
// numpy
|
||||
if self.settings.rules.enabled(&Rule::NumpyLegacyRandom) {
|
||||
numpy::rules::numpy_legacy_random(self, func);
|
||||
}
|
||||
|
||||
// flake8-logging-format
|
||||
if self.settings.rules.enabled(&Rule::LoggingStringFormat)
|
||||
|| self.settings.rules.enabled(&Rule::LoggingPercentFormat)
|
||||
@@ -3163,13 +3223,13 @@ where
|
||||
flake8_simplify::rules::yoda_conditions(self, expr, left, ops, comparators);
|
||||
}
|
||||
|
||||
if self
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::UnrecognizedPlatformCheck)
|
||||
|| self.settings.rules.enabled(&Rule::UnrecognizedPlatformName)
|
||||
{
|
||||
if self.path.extension().map_or(false, |ext| ext == "pyi") {
|
||||
if self.is_interface_definition {
|
||||
if self
|
||||
.settings
|
||||
.rules
|
||||
.enabled(&Rule::UnrecognizedPlatformCheck)
|
||||
|| self.settings.rules.enabled(&Rule::UnrecognizedPlatformName)
|
||||
{
|
||||
flake8_pyi::rules::unrecognized_platform(
|
||||
self,
|
||||
expr,
|
||||
@@ -3188,7 +3248,7 @@ where
|
||||
self.deferred_string_type_definitions.push((
|
||||
Range::from_located(expr),
|
||||
value,
|
||||
self.in_annotation,
|
||||
(self.in_annotation, self.in_type_checking_block),
|
||||
(self.scope_stack.clone(), self.parents.clone()),
|
||||
));
|
||||
}
|
||||
@@ -4493,12 +4553,13 @@ impl<'a> Checker<'a> {
|
||||
|
||||
fn check_deferred_type_definitions(&mut self) {
|
||||
self.deferred_type_definitions.reverse();
|
||||
while let Some((expr, in_annotation, (scopes, parents))) =
|
||||
while let Some((expr, (in_annotation, in_type_checking_block), (scopes, parents))) =
|
||||
self.deferred_type_definitions.pop()
|
||||
{
|
||||
self.scope_stack = scopes;
|
||||
self.parents = parents;
|
||||
self.in_annotation = in_annotation;
|
||||
self.in_type_checking_block = in_type_checking_block;
|
||||
self.in_type_definition = true;
|
||||
self.in_deferred_type_definition = true;
|
||||
self.visit_expr(expr);
|
||||
@@ -4513,7 +4574,7 @@ impl<'a> Checker<'a> {
|
||||
{
|
||||
let mut stacks = vec![];
|
||||
self.deferred_string_type_definitions.reverse();
|
||||
while let Some((range, expression, in_annotation, context)) =
|
||||
while let Some((range, expression, (in_annotation, in_type_checking_block), deferral)) =
|
||||
self.deferred_string_type_definitions.pop()
|
||||
{
|
||||
if let Ok(mut expr) = parser::parse_expression(expression, "<filename>") {
|
||||
@@ -4524,7 +4585,7 @@ impl<'a> Checker<'a> {
|
||||
}
|
||||
relocate_expr(&mut expr, range);
|
||||
allocator.push(expr);
|
||||
stacks.push((in_annotation, context));
|
||||
stacks.push(((in_annotation, in_type_checking_block), deferral));
|
||||
} else {
|
||||
if self
|
||||
.settings
|
||||
@@ -4540,10 +4601,13 @@ impl<'a> Checker<'a> {
|
||||
}
|
||||
}
|
||||
}
|
||||
for (expr, (in_annotation, (scopes, parents))) in allocator.iter().zip(stacks) {
|
||||
for (expr, ((in_annotation, in_type_checking_block), (scopes, parents))) in
|
||||
allocator.iter().zip(stacks)
|
||||
{
|
||||
self.scope_stack = scopes;
|
||||
self.parents = parents;
|
||||
self.in_annotation = in_annotation;
|
||||
self.in_type_checking_block = in_type_checking_block;
|
||||
self.in_type_definition = true;
|
||||
self.in_deferred_string_type_definition = true;
|
||||
self.visit_expr(expr);
|
||||
@@ -5213,10 +5277,8 @@ impl<'a> Checker<'a> {
|
||||
|
||||
// Extract a `Docstring` from a `Definition`.
|
||||
let expr = definition.docstring.unwrap();
|
||||
let contents = self
|
||||
.locator
|
||||
.slice_source_code_range(&Range::from_located(expr));
|
||||
let indentation = self.locator.slice_source_code_range(&Range::new(
|
||||
let contents = self.locator.slice(&Range::from_located(expr));
|
||||
let indentation = self.locator.slice(&Range::new(
|
||||
Location::new(expr.location.row(), 0),
|
||||
Location::new(expr.location.row(), expr.location.column()),
|
||||
));
|
||||
|
||||
@@ -2,6 +2,7 @@ use std::path::Path;
|
||||
|
||||
use crate::registry::{Diagnostic, Rule};
|
||||
use crate::rules::flake8_no_pep420::rules::implicit_namespace_package;
|
||||
use crate::rules::pep8_naming::rules::invalid_module_name;
|
||||
use crate::settings::Settings;
|
||||
|
||||
pub fn check_file_path(
|
||||
@@ -20,5 +21,12 @@ pub fn check_file_path(
|
||||
}
|
||||
}
|
||||
|
||||
// pep8-naming
|
||||
if settings.rules.enabled(&Rule::InvalidModuleName) {
|
||||
if let Some(diagnostic) = invalid_module_name(path, package) {
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
}
|
||||
|
||||
diagnostics
|
||||
}
|
||||
|
||||
@@ -52,8 +52,7 @@ pub fn check_logical_lines(
|
||||
|
||||
// Extract the indentation level.
|
||||
let start_loc = line.mapping[0].1;
|
||||
let start_line = locator
|
||||
.slice_source_code_range(&Range::new(Location::new(start_loc.row(), 0), start_loc));
|
||||
let start_line = locator.slice(&Range::new(Location::new(start_loc.row(), 0), start_loc));
|
||||
let indent_level = expand_indent(start_line);
|
||||
let indent_size = 4;
|
||||
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
//! `NoQA` enforcement and validation.
|
||||
|
||||
use log::warn;
|
||||
use nohash_hasher::IntMap;
|
||||
use rustpython_parser::ast::Location;
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::codes::NoqaCode;
|
||||
use crate::fix::Fix;
|
||||
use crate::noqa;
|
||||
use crate::noqa::{is_file_exempt, Directive};
|
||||
use crate::noqa::{extract_file_exemption, Directive, Exemption};
|
||||
use crate::registry::{Diagnostic, DiagnosticKind, Rule};
|
||||
use crate::rule_redirects::get_redirect_target;
|
||||
use crate::rules::ruff::rules::{UnusedCodes, UnusedNOQA};
|
||||
@@ -20,17 +22,38 @@ pub fn check_noqa(
|
||||
settings: &Settings,
|
||||
autofix: flags::Autofix,
|
||||
) {
|
||||
let mut noqa_directives: IntMap<usize, (Directive, Vec<&str>)> = IntMap::default();
|
||||
let mut ignored = vec![];
|
||||
|
||||
let enforce_noqa = settings.rules.enabled(&Rule::UnusedNOQA);
|
||||
|
||||
// Whether the file is exempted from all checks.
|
||||
let mut file_exempted = false;
|
||||
|
||||
// Codes that are globally exempted (within the current file).
|
||||
let mut file_exemptions: Vec<NoqaCode> = vec![];
|
||||
|
||||
// Map from line number to `noqa` directive on that line, along with any codes
|
||||
// that were matched by the directive.
|
||||
let mut noqa_directives: IntMap<usize, (Directive, Vec<NoqaCode>)> = IntMap::default();
|
||||
|
||||
// Indices of diagnostics that were ignored by a `noqa` directive.
|
||||
let mut ignored_diagnostics = vec![];
|
||||
|
||||
let lines: Vec<&str> = contents.lines().collect();
|
||||
for lineno in commented_lines {
|
||||
// If we hit an exemption for the entire file, bail.
|
||||
if is_file_exempt(lines[lineno - 1]) {
|
||||
diagnostics.drain(..);
|
||||
return;
|
||||
match extract_file_exemption(lines[lineno - 1]) {
|
||||
Exemption::All => {
|
||||
file_exempted = true;
|
||||
}
|
||||
Exemption::Codes(codes) => {
|
||||
file_exemptions.extend(codes.into_iter().filter_map(|code| {
|
||||
if let Ok(rule) = Rule::from_code(get_redirect_target(code).unwrap_or(code)) {
|
||||
Some(rule.noqa_code())
|
||||
} else {
|
||||
warn!("Invalid code provided to `# ruff: noqa`: {}", code);
|
||||
None
|
||||
}
|
||||
}));
|
||||
}
|
||||
Exemption::None => {}
|
||||
}
|
||||
|
||||
if enforce_noqa {
|
||||
@@ -46,6 +69,20 @@ pub fn check_noqa(
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the file is exempted, ignore all diagnostics.
|
||||
if file_exempted {
|
||||
ignored_diagnostics.push(index);
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the diagnostic is ignored by a global exemption, ignore it.
|
||||
if !file_exemptions.is_empty() {
|
||||
if file_exemptions.contains(&diagnostic.kind.rule().noqa_code()) {
|
||||
ignored_diagnostics.push(index);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Is the violation ignored by a `noqa` directive on the parent line?
|
||||
if let Some(parent_lineno) = diagnostic.parent.map(|location| location.row()) {
|
||||
let noqa_lineno = noqa_line_for.get(&parent_lineno).unwrap_or(&parent_lineno);
|
||||
@@ -55,14 +92,14 @@ pub fn check_noqa(
|
||||
});
|
||||
match noqa {
|
||||
(Directive::All(..), matches) => {
|
||||
matches.push(diagnostic.kind.rule().code());
|
||||
ignored.push(index);
|
||||
matches.push(diagnostic.kind.rule().noqa_code());
|
||||
ignored_diagnostics.push(index);
|
||||
continue;
|
||||
}
|
||||
(Directive::Codes(.., codes), matches) => {
|
||||
if noqa::includes(diagnostic.kind.rule(), codes) {
|
||||
matches.push(diagnostic.kind.rule().code());
|
||||
ignored.push(index);
|
||||
matches.push(diagnostic.kind.rule().noqa_code());
|
||||
ignored_diagnostics.push(index);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -82,13 +119,15 @@ pub fn check_noqa(
|
||||
.or_insert_with(|| (noqa::extract_noqa_directive(lines[noqa_lineno - 1]), vec![]));
|
||||
match noqa {
|
||||
(Directive::All(..), matches) => {
|
||||
matches.push(diagnostic.kind.rule().code());
|
||||
ignored.push(index);
|
||||
matches.push(diagnostic.kind.rule().noqa_code());
|
||||
ignored_diagnostics.push(index);
|
||||
continue;
|
||||
}
|
||||
(Directive::Codes(.., codes), matches) => {
|
||||
if noqa::includes(diagnostic.kind.rule(), codes) {
|
||||
matches.push(diagnostic.kind.rule().code());
|
||||
ignored.push(index);
|
||||
matches.push(diagnostic.kind.rule().noqa_code());
|
||||
ignored_diagnostics.push(index);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
(Directive::None, ..) => {}
|
||||
@@ -128,12 +167,12 @@ pub fn check_noqa(
|
||||
let mut self_ignore = false;
|
||||
for code in codes {
|
||||
let code = get_redirect_target(code).unwrap_or(code);
|
||||
if code == Rule::UnusedNOQA.code() {
|
||||
if Rule::UnusedNOQA.noqa_code() == code {
|
||||
self_ignore = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if matches.contains(&code) || settings.external.contains(code) {
|
||||
if matches.iter().any(|m| *m == code) || settings.external.contains(code) {
|
||||
valid_codes.push(code);
|
||||
} else {
|
||||
if let Ok(rule) = Rule::from_code(code) {
|
||||
@@ -202,8 +241,8 @@ pub fn check_noqa(
|
||||
}
|
||||
}
|
||||
|
||||
ignored.sort_unstable();
|
||||
for index in ignored.iter().rev() {
|
||||
ignored_diagnostics.sort_unstable();
|
||||
for index in ignored_diagnostics.iter().rev() {
|
||||
diagnostics.swap_remove(*index);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ pub fn check_tokens(
|
||||
// E701, E702, E703
|
||||
if enforce_compound_statements {
|
||||
diagnostics.extend(
|
||||
pycodestyle::rules::compound_statements(tokens)
|
||||
pycodestyle::rules::compound_statements(tokens, settings, autofix)
|
||||
.into_iter()
|
||||
.filter(|diagnostic| settings.rules.enabled(diagnostic.kind.rule())),
|
||||
);
|
||||
|
||||
612
crates/ruff/src/codes.rs
Normal file
612
crates/ruff/src/codes.rs
Normal file
@@ -0,0 +1,612 @@
|
||||
use crate::registry::{Linter, Rule};
|
||||
|
||||
#[ruff_macros::map_codes]
|
||||
pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||
#[allow(clippy::enum_glob_use)]
|
||||
use Linter::*;
|
||||
|
||||
Some(match (linter, code) {
|
||||
// pycodestyle errors
|
||||
(Pycodestyle, "E101") => Rule::MixedSpacesAndTabs,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E111") => Rule::IndentationWithInvalidMultiple,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E112") => Rule::NoIndentedBlock,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E113") => Rule::UnexpectedIndentation,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E114") => Rule::IndentationWithInvalidMultipleComment,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E115") => Rule::NoIndentedBlockComment,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E116") => Rule::UnexpectedIndentationComment,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E117") => Rule::OverIndented,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E201") => Rule::WhitespaceAfterOpenBracket,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E202") => Rule::WhitespaceBeforeCloseBracket,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E203") => Rule::WhitespaceBeforePunctuation,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E221") => Rule::MultipleSpacesBeforeOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E222") => Rule::MultipleSpacesAfterOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E223") => Rule::TabBeforeOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E224") => Rule::TabAfterOperator,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E261") => Rule::TooFewSpacesBeforeInlineComment,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E262") => Rule::NoSpaceAfterInlineComment,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E265") => Rule::NoSpaceAfterBlockComment,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E266") => Rule::MultipleLeadingHashesForBlockComment,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E271") => Rule::MultipleSpacesAfterKeyword,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E272") => Rule::MultipleSpacesBeforeKeyword,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E273") => Rule::TabAfterKeyword,
|
||||
#[cfg(feature = "logical_lines")]
|
||||
(Pycodestyle, "E274") => Rule::TabBeforeKeyword,
|
||||
(Pycodestyle, "E401") => Rule::MultipleImportsOnOneLine,
|
||||
(Pycodestyle, "E402") => Rule::ModuleImportNotAtTopOfFile,
|
||||
(Pycodestyle, "E501") => Rule::LineTooLong,
|
||||
(Pycodestyle, "E701") => Rule::MultipleStatementsOnOneLineColon,
|
||||
(Pycodestyle, "E702") => Rule::MultipleStatementsOnOneLineSemicolon,
|
||||
(Pycodestyle, "E703") => Rule::UselessSemicolon,
|
||||
(Pycodestyle, "E711") => Rule::NoneComparison,
|
||||
(Pycodestyle, "E712") => Rule::TrueFalseComparison,
|
||||
(Pycodestyle, "E713") => Rule::NotInTest,
|
||||
(Pycodestyle, "E714") => Rule::NotIsTest,
|
||||
(Pycodestyle, "E721") => Rule::TypeComparison,
|
||||
(Pycodestyle, "E722") => Rule::BareExcept,
|
||||
(Pycodestyle, "E731") => Rule::LambdaAssignment,
|
||||
(Pycodestyle, "E741") => Rule::AmbiguousVariableName,
|
||||
(Pycodestyle, "E742") => Rule::AmbiguousClassName,
|
||||
(Pycodestyle, "E743") => Rule::AmbiguousFunctionName,
|
||||
(Pycodestyle, "E902") => Rule::IOError,
|
||||
(Pycodestyle, "E999") => Rule::SyntaxError,
|
||||
|
||||
// pycodestyle warnings
|
||||
(Pycodestyle, "W292") => Rule::NoNewLineAtEndOfFile,
|
||||
(Pycodestyle, "W505") => Rule::DocLineTooLong,
|
||||
(Pycodestyle, "W605") => Rule::InvalidEscapeSequence,
|
||||
|
||||
// pyflakes
|
||||
(Pyflakes, "401") => Rule::UnusedImport,
|
||||
(Pyflakes, "402") => Rule::ImportShadowedByLoopVar,
|
||||
(Pyflakes, "403") => Rule::ImportStar,
|
||||
(Pyflakes, "404") => Rule::LateFutureImport,
|
||||
(Pyflakes, "405") => Rule::ImportStarUsage,
|
||||
(Pyflakes, "406") => Rule::ImportStarNotPermitted,
|
||||
(Pyflakes, "407") => Rule::FutureFeatureNotDefined,
|
||||
(Pyflakes, "501") => Rule::PercentFormatInvalidFormat,
|
||||
(Pyflakes, "502") => Rule::PercentFormatExpectedMapping,
|
||||
(Pyflakes, "503") => Rule::PercentFormatExpectedSequence,
|
||||
(Pyflakes, "504") => Rule::PercentFormatExtraNamedArguments,
|
||||
(Pyflakes, "505") => Rule::PercentFormatMissingArgument,
|
||||
(Pyflakes, "506") => Rule::PercentFormatMixedPositionalAndNamed,
|
||||
(Pyflakes, "507") => Rule::PercentFormatPositionalCountMismatch,
|
||||
(Pyflakes, "508") => Rule::PercentFormatStarRequiresSequence,
|
||||
(Pyflakes, "509") => Rule::PercentFormatUnsupportedFormatCharacter,
|
||||
(Pyflakes, "521") => Rule::StringDotFormatInvalidFormat,
|
||||
(Pyflakes, "522") => Rule::StringDotFormatExtraNamedArguments,
|
||||
(Pyflakes, "523") => Rule::StringDotFormatExtraPositionalArguments,
|
||||
(Pyflakes, "524") => Rule::StringDotFormatMissingArguments,
|
||||
(Pyflakes, "525") => Rule::StringDotFormatMixingAutomatic,
|
||||
(Pyflakes, "541") => Rule::FStringMissingPlaceholders,
|
||||
(Pyflakes, "601") => Rule::MultiValueRepeatedKeyLiteral,
|
||||
(Pyflakes, "602") => Rule::MultiValueRepeatedKeyVariable,
|
||||
(Pyflakes, "621") => Rule::ExpressionsInStarAssignment,
|
||||
(Pyflakes, "622") => Rule::TwoStarredExpressions,
|
||||
(Pyflakes, "631") => Rule::AssertTuple,
|
||||
(Pyflakes, "632") => Rule::IsLiteral,
|
||||
(Pyflakes, "633") => Rule::InvalidPrintSyntax,
|
||||
(Pyflakes, "634") => Rule::IfTuple,
|
||||
(Pyflakes, "701") => Rule::BreakOutsideLoop,
|
||||
(Pyflakes, "702") => Rule::ContinueOutsideLoop,
|
||||
(Pyflakes, "704") => Rule::YieldOutsideFunction,
|
||||
(Pyflakes, "706") => Rule::ReturnOutsideFunction,
|
||||
(Pyflakes, "707") => Rule::DefaultExceptNotLast,
|
||||
(Pyflakes, "722") => Rule::ForwardAnnotationSyntaxError,
|
||||
(Pyflakes, "811") => Rule::RedefinedWhileUnused,
|
||||
(Pyflakes, "821") => Rule::UndefinedName,
|
||||
(Pyflakes, "822") => Rule::UndefinedExport,
|
||||
(Pyflakes, "823") => Rule::UndefinedLocal,
|
||||
(Pyflakes, "841") => Rule::UnusedVariable,
|
||||
(Pyflakes, "842") => Rule::UnusedAnnotation,
|
||||
(Pyflakes, "901") => Rule::RaiseNotImplemented,
|
||||
|
||||
// pylint
|
||||
(Pylint, "E0100") => Rule::YieldInInit,
|
||||
(Pylint, "E0101") => Rule::ReturnInInit,
|
||||
(Pylint, "E0604") => Rule::InvalidAllObject,
|
||||
(Pylint, "E0605") => Rule::InvalidAllFormat,
|
||||
(Pylint, "E1307") => Rule::BadStringFormatType,
|
||||
(Pylint, "E2502") => Rule::BidirectionalUnicode,
|
||||
(Pylint, "E1310") => Rule::BadStrStripCall,
|
||||
(Pylint, "C0414") => Rule::UselessImportAlias,
|
||||
(Pylint, "C3002") => Rule::UnnecessaryDirectLambdaCall,
|
||||
(Pylint, "E0117") => Rule::NonlocalWithoutBinding,
|
||||
(Pylint, "E0118") => Rule::UsedPriorGlobalDeclaration,
|
||||
(Pylint, "E1142") => Rule::AwaitOutsideAsync,
|
||||
(Pylint, "R0206") => Rule::PropertyWithParameters,
|
||||
(Pylint, "R0402") => Rule::ConsiderUsingFromImport,
|
||||
(Pylint, "R0133") => Rule::ComparisonOfConstant,
|
||||
(Pylint, "R1701") => Rule::ConsiderMergingIsinstance,
|
||||
(Pylint, "R1722") => Rule::ConsiderUsingSysExit,
|
||||
(Pylint, "R2004") => Rule::MagicValueComparison,
|
||||
(Pylint, "W0120") => Rule::UselessElseOnLoop,
|
||||
(Pylint, "W0602") => Rule::GlobalVariableNotAssigned,
|
||||
(Pylint, "R0911") => Rule::TooManyReturnStatements,
|
||||
(Pylint, "R0913") => Rule::TooManyArguments,
|
||||
(Pylint, "R0912") => Rule::TooManyBranches,
|
||||
(Pylint, "R0915") => Rule::TooManyStatements,
|
||||
|
||||
// flake8-builtins
|
||||
(Flake8Builtins, "001") => Rule::BuiltinVariableShadowing,
|
||||
(Flake8Builtins, "002") => Rule::BuiltinArgumentShadowing,
|
||||
(Flake8Builtins, "003") => Rule::BuiltinAttributeShadowing,
|
||||
|
||||
// flake8-bugbear
|
||||
(Flake8Bugbear, "002") => Rule::UnaryPrefixIncrement,
|
||||
(Flake8Bugbear, "003") => Rule::AssignmentToOsEnviron,
|
||||
(Flake8Bugbear, "004") => Rule::UnreliableCallableCheck,
|
||||
(Flake8Bugbear, "005") => Rule::StripWithMultiCharacters,
|
||||
(Flake8Bugbear, "006") => Rule::MutableArgumentDefault,
|
||||
(Flake8Bugbear, "007") => Rule::UnusedLoopControlVariable,
|
||||
(Flake8Bugbear, "008") => Rule::FunctionCallArgumentDefault,
|
||||
(Flake8Bugbear, "009") => Rule::GetAttrWithConstant,
|
||||
(Flake8Bugbear, "010") => Rule::SetAttrWithConstant,
|
||||
(Flake8Bugbear, "011") => Rule::AssertFalse,
|
||||
(Flake8Bugbear, "012") => Rule::JumpStatementInFinally,
|
||||
(Flake8Bugbear, "013") => Rule::RedundantTupleInExceptionHandler,
|
||||
(Flake8Bugbear, "014") => Rule::DuplicateHandlerException,
|
||||
(Flake8Bugbear, "015") => Rule::UselessComparison,
|
||||
(Flake8Bugbear, "016") => Rule::CannotRaiseLiteral,
|
||||
(Flake8Bugbear, "017") => Rule::AssertRaisesException,
|
||||
(Flake8Bugbear, "018") => Rule::UselessExpression,
|
||||
(Flake8Bugbear, "019") => Rule::CachedInstanceMethod,
|
||||
(Flake8Bugbear, "020") => Rule::LoopVariableOverridesIterator,
|
||||
(Flake8Bugbear, "021") => Rule::FStringDocstring,
|
||||
(Flake8Bugbear, "022") => Rule::UselessContextlibSuppress,
|
||||
(Flake8Bugbear, "023") => Rule::FunctionUsesLoopVariable,
|
||||
(Flake8Bugbear, "024") => Rule::AbstractBaseClassWithoutAbstractMethod,
|
||||
(Flake8Bugbear, "025") => Rule::DuplicateTryBlockException,
|
||||
(Flake8Bugbear, "026") => Rule::StarArgUnpackingAfterKeywordArg,
|
||||
(Flake8Bugbear, "027") => Rule::EmptyMethodWithoutAbstractDecorator,
|
||||
(Flake8Bugbear, "904") => Rule::RaiseWithoutFromInsideExcept,
|
||||
(Flake8Bugbear, "905") => Rule::ZipWithoutExplicitStrict,
|
||||
|
||||
// flake8-blind-except
|
||||
(Flake8BlindExcept, "001") => Rule::BlindExcept,
|
||||
|
||||
// flake8-comprehensions
|
||||
(Flake8Comprehensions, "00") => Rule::UnnecessaryGeneratorList,
|
||||
(Flake8Comprehensions, "01") => Rule::UnnecessaryGeneratorSet,
|
||||
(Flake8Comprehensions, "02") => Rule::UnnecessaryGeneratorDict,
|
||||
(Flake8Comprehensions, "03") => Rule::UnnecessaryListComprehensionSet,
|
||||
(Flake8Comprehensions, "04") => Rule::UnnecessaryListComprehensionDict,
|
||||
(Flake8Comprehensions, "05") => Rule::UnnecessaryLiteralSet,
|
||||
(Flake8Comprehensions, "06") => Rule::UnnecessaryLiteralDict,
|
||||
(Flake8Comprehensions, "08") => Rule::UnnecessaryCollectionCall,
|
||||
(Flake8Comprehensions, "09") => Rule::UnnecessaryLiteralWithinTupleCall,
|
||||
(Flake8Comprehensions, "10") => Rule::UnnecessaryLiteralWithinListCall,
|
||||
(Flake8Comprehensions, "11") => Rule::UnnecessaryListCall,
|
||||
(Flake8Comprehensions, "13") => Rule::UnnecessaryCallAroundSorted,
|
||||
(Flake8Comprehensions, "14") => Rule::UnnecessaryDoubleCastOrProcess,
|
||||
(Flake8Comprehensions, "15") => Rule::UnnecessarySubscriptReversal,
|
||||
(Flake8Comprehensions, "16") => Rule::UnnecessaryComprehension,
|
||||
(Flake8Comprehensions, "17") => Rule::UnnecessaryMap,
|
||||
|
||||
// flake8-debugger
|
||||
(Flake8Debugger, "0") => Rule::Debugger,
|
||||
|
||||
// mccabe
|
||||
(McCabe, "1") => Rule::ComplexStructure,
|
||||
|
||||
// flake8-tidy-imports
|
||||
(Flake8TidyImports, "251") => Rule::BannedApi,
|
||||
(Flake8TidyImports, "252") => Rule::RelativeImports,
|
||||
|
||||
// flake8-return
|
||||
(Flake8Return, "501") => Rule::UnnecessaryReturnNone,
|
||||
(Flake8Return, "502") => Rule::ImplicitReturnValue,
|
||||
(Flake8Return, "503") => Rule::ImplicitReturn,
|
||||
(Flake8Return, "504") => Rule::UnnecessaryAssign,
|
||||
(Flake8Return, "505") => Rule::SuperfluousElseReturn,
|
||||
(Flake8Return, "506") => Rule::SuperfluousElseRaise,
|
||||
(Flake8Return, "507") => Rule::SuperfluousElseContinue,
|
||||
(Flake8Return, "508") => Rule::SuperfluousElseBreak,
|
||||
|
||||
// flake8-implicit-str-concat
|
||||
(Flake8ImplicitStrConcat, "001") => Rule::SingleLineImplicitStringConcatenation,
|
||||
(Flake8ImplicitStrConcat, "002") => Rule::MultiLineImplicitStringConcatenation,
|
||||
(Flake8ImplicitStrConcat, "003") => Rule::ExplicitStringConcatenation,
|
||||
|
||||
// flake8-print
|
||||
(Flake8Print, "1") => Rule::PrintFound,
|
||||
(Flake8Print, "3") => Rule::PPrintFound,
|
||||
|
||||
// flake8-quotes
|
||||
(Flake8Quotes, "000") => Rule::BadQuotesInlineString,
|
||||
(Flake8Quotes, "001") => Rule::BadQuotesMultilineString,
|
||||
(Flake8Quotes, "002") => Rule::BadQuotesDocstring,
|
||||
(Flake8Quotes, "003") => Rule::AvoidableEscapedQuote,
|
||||
|
||||
// flake8-annotations
|
||||
(Flake8Annotations, "001") => Rule::MissingTypeFunctionArgument,
|
||||
(Flake8Annotations, "002") => Rule::MissingTypeArgs,
|
||||
(Flake8Annotations, "003") => Rule::MissingTypeKwargs,
|
||||
(Flake8Annotations, "101") => Rule::MissingTypeSelf,
|
||||
(Flake8Annotations, "102") => Rule::MissingTypeCls,
|
||||
(Flake8Annotations, "201") => Rule::MissingReturnTypePublicFunction,
|
||||
(Flake8Annotations, "202") => Rule::MissingReturnTypePrivateFunction,
|
||||
(Flake8Annotations, "204") => Rule::MissingReturnTypeSpecialMethod,
|
||||
(Flake8Annotations, "205") => Rule::MissingReturnTypeStaticMethod,
|
||||
(Flake8Annotations, "206") => Rule::MissingReturnTypeClassMethod,
|
||||
(Flake8Annotations, "401") => Rule::AnyType,
|
||||
|
||||
// flake8-2020
|
||||
(Flake82020, "101") => Rule::SysVersionSlice3Referenced,
|
||||
(Flake82020, "102") => Rule::SysVersion2Referenced,
|
||||
(Flake82020, "103") => Rule::SysVersionCmpStr3,
|
||||
(Flake82020, "201") => Rule::SysVersionInfo0Eq3Referenced,
|
||||
(Flake82020, "202") => Rule::SixPY3Referenced,
|
||||
(Flake82020, "203") => Rule::SysVersionInfo1CmpInt,
|
||||
(Flake82020, "204") => Rule::SysVersionInfoMinorCmpInt,
|
||||
(Flake82020, "301") => Rule::SysVersion0Referenced,
|
||||
(Flake82020, "302") => Rule::SysVersionCmpStr10,
|
||||
(Flake82020, "303") => Rule::SysVersionSlice1Referenced,
|
||||
|
||||
// flake8-simplify
|
||||
(Flake8Simplify, "101") => Rule::DuplicateIsinstanceCall,
|
||||
(Flake8Simplify, "102") => Rule::CollapsibleIf,
|
||||
(Flake8Simplify, "103") => Rule::NeedlessBool,
|
||||
(Flake8Simplify, "105") => Rule::UseContextlibSuppress,
|
||||
(Flake8Simplify, "107") => Rule::ReturnInTryExceptFinally,
|
||||
(Flake8Simplify, "108") => Rule::UseTernaryOperator,
|
||||
(Flake8Simplify, "109") => Rule::CompareWithTuple,
|
||||
(Flake8Simplify, "110") => Rule::ReimplementedBuiltin,
|
||||
// (Flake8Simplify, "111") => Rule::ReimplementedBuiltin,
|
||||
(Flake8Simplify, "112") => Rule::UseCapitalEnvironmentVariables,
|
||||
(Flake8Simplify, "114") => Rule::IfWithSameArms,
|
||||
(Flake8Simplify, "115") => Rule::OpenFileWithContextHandler,
|
||||
(Flake8Simplify, "117") => Rule::MultipleWithStatements,
|
||||
(Flake8Simplify, "118") => Rule::KeyInDict,
|
||||
(Flake8Simplify, "201") => Rule::NegateEqualOp,
|
||||
(Flake8Simplify, "202") => Rule::NegateNotEqualOp,
|
||||
(Flake8Simplify, "208") => Rule::DoubleNegation,
|
||||
(Flake8Simplify, "210") => Rule::IfExprWithTrueFalse,
|
||||
(Flake8Simplify, "211") => Rule::IfExprWithFalseTrue,
|
||||
(Flake8Simplify, "212") => Rule::IfExprWithTwistedArms,
|
||||
(Flake8Simplify, "220") => Rule::AAndNotA,
|
||||
(Flake8Simplify, "221") => Rule::AOrNotA,
|
||||
(Flake8Simplify, "222") => Rule::OrTrue,
|
||||
(Flake8Simplify, "223") => Rule::AndFalse,
|
||||
(Flake8Simplify, "300") => Rule::YodaConditions,
|
||||
(Flake8Simplify, "401") => Rule::DictGetWithDefault,
|
||||
|
||||
// pyupgrade
|
||||
(Pyupgrade, "001") => Rule::UselessMetaclassType,
|
||||
(Pyupgrade, "003") => Rule::TypeOfPrimitive,
|
||||
(Pyupgrade, "004") => Rule::UselessObjectInheritance,
|
||||
(Pyupgrade, "005") => Rule::DeprecatedUnittestAlias,
|
||||
(Pyupgrade, "006") => Rule::DeprecatedCollectionType,
|
||||
(Pyupgrade, "007") => Rule::TypingUnion,
|
||||
(Pyupgrade, "008") => Rule::SuperCallWithParameters,
|
||||
(Pyupgrade, "009") => Rule::UTF8EncodingDeclaration,
|
||||
(Pyupgrade, "010") => Rule::UnnecessaryFutureImport,
|
||||
(Pyupgrade, "011") => Rule::LRUCacheWithoutParameters,
|
||||
(Pyupgrade, "012") => Rule::UnnecessaryEncodeUTF8,
|
||||
(Pyupgrade, "013") => Rule::ConvertTypedDictFunctionalToClass,
|
||||
(Pyupgrade, "014") => Rule::ConvertNamedTupleFunctionalToClass,
|
||||
(Pyupgrade, "015") => Rule::RedundantOpenModes,
|
||||
(Pyupgrade, "017") => Rule::DatetimeTimezoneUTC,
|
||||
(Pyupgrade, "018") => Rule::NativeLiterals,
|
||||
(Pyupgrade, "019") => Rule::TypingTextStrAlias,
|
||||
(Pyupgrade, "020") => Rule::OpenAlias,
|
||||
(Pyupgrade, "021") => Rule::ReplaceUniversalNewlines,
|
||||
(Pyupgrade, "022") => Rule::ReplaceStdoutStderr,
|
||||
(Pyupgrade, "023") => Rule::RewriteCElementTree,
|
||||
(Pyupgrade, "024") => Rule::OSErrorAlias,
|
||||
(Pyupgrade, "025") => Rule::RewriteUnicodeLiteral,
|
||||
(Pyupgrade, "026") => Rule::RewriteMockImport,
|
||||
(Pyupgrade, "027") => Rule::RewriteListComprehension,
|
||||
(Pyupgrade, "028") => Rule::RewriteYieldFrom,
|
||||
(Pyupgrade, "029") => Rule::UnnecessaryBuiltinImport,
|
||||
(Pyupgrade, "030") => Rule::FormatLiterals,
|
||||
(Pyupgrade, "031") => Rule::PrintfStringFormatting,
|
||||
(Pyupgrade, "032") => Rule::FString,
|
||||
(Pyupgrade, "033") => Rule::FunctoolsCache,
|
||||
(Pyupgrade, "034") => Rule::ExtraneousParentheses,
|
||||
(Pyupgrade, "035") => Rule::ImportReplacements,
|
||||
(Pyupgrade, "036") => Rule::OutdatedVersionBlock,
|
||||
(Pyupgrade, "037") => Rule::QuotedAnnotation,
|
||||
|
||||
// pydocstyle
|
||||
(Pydocstyle, "100") => Rule::PublicModule,
|
||||
(Pydocstyle, "101") => Rule::PublicClass,
|
||||
(Pydocstyle, "102") => Rule::PublicMethod,
|
||||
(Pydocstyle, "103") => Rule::PublicFunction,
|
||||
(Pydocstyle, "104") => Rule::PublicPackage,
|
||||
(Pydocstyle, "105") => Rule::MagicMethod,
|
||||
(Pydocstyle, "106") => Rule::PublicNestedClass,
|
||||
(Pydocstyle, "107") => Rule::PublicInit,
|
||||
(Pydocstyle, "200") => Rule::FitsOnOneLine,
|
||||
(Pydocstyle, "201") => Rule::NoBlankLineBeforeFunction,
|
||||
(Pydocstyle, "202") => Rule::NoBlankLineAfterFunction,
|
||||
(Pydocstyle, "203") => Rule::OneBlankLineBeforeClass,
|
||||
(Pydocstyle, "204") => Rule::OneBlankLineAfterClass,
|
||||
(Pydocstyle, "205") => Rule::BlankLineAfterSummary,
|
||||
(Pydocstyle, "206") => Rule::IndentWithSpaces,
|
||||
(Pydocstyle, "207") => Rule::NoUnderIndentation,
|
||||
(Pydocstyle, "208") => Rule::NoOverIndentation,
|
||||
(Pydocstyle, "209") => Rule::NewLineAfterLastParagraph,
|
||||
(Pydocstyle, "210") => Rule::NoSurroundingWhitespace,
|
||||
(Pydocstyle, "211") => Rule::NoBlankLineBeforeClass,
|
||||
(Pydocstyle, "212") => Rule::MultiLineSummaryFirstLine,
|
||||
(Pydocstyle, "213") => Rule::MultiLineSummarySecondLine,
|
||||
(Pydocstyle, "214") => Rule::SectionNotOverIndented,
|
||||
(Pydocstyle, "215") => Rule::SectionUnderlineNotOverIndented,
|
||||
(Pydocstyle, "300") => Rule::TripleSingleQuotes,
|
||||
(Pydocstyle, "301") => Rule::EscapeSequenceInDocstring,
|
||||
(Pydocstyle, "400") => Rule::EndsInPeriod,
|
||||
(Pydocstyle, "401") => Rule::NonImperativeMood,
|
||||
(Pydocstyle, "402") => Rule::NoSignature,
|
||||
(Pydocstyle, "403") => Rule::FirstLineCapitalized,
|
||||
(Pydocstyle, "404") => Rule::DocstringStartsWithThis,
|
||||
(Pydocstyle, "405") => Rule::CapitalizeSectionName,
|
||||
(Pydocstyle, "406") => Rule::NewLineAfterSectionName,
|
||||
(Pydocstyle, "407") => Rule::DashedUnderlineAfterSection,
|
||||
(Pydocstyle, "408") => Rule::SectionUnderlineAfterName,
|
||||
(Pydocstyle, "409") => Rule::SectionUnderlineMatchesSectionLength,
|
||||
(Pydocstyle, "410") => Rule::BlankLineAfterSection,
|
||||
(Pydocstyle, "411") => Rule::BlankLineBeforeSection,
|
||||
(Pydocstyle, "412") => Rule::NoBlankLinesBetweenHeaderAndContent,
|
||||
(Pydocstyle, "413") => Rule::BlankLineAfterLastSection,
|
||||
(Pydocstyle, "414") => Rule::EmptyDocstringSection,
|
||||
(Pydocstyle, "415") => Rule::EndsInPunctuation,
|
||||
(Pydocstyle, "416") => Rule::SectionNameEndsInColon,
|
||||
(Pydocstyle, "417") => Rule::UndocumentedParam,
|
||||
(Pydocstyle, "418") => Rule::OverloadWithDocstring,
|
||||
(Pydocstyle, "419") => Rule::EmptyDocstring,
|
||||
|
||||
// pep8-naming
|
||||
(PEP8Naming, "801") => Rule::InvalidClassName,
|
||||
(PEP8Naming, "802") => Rule::InvalidFunctionName,
|
||||
(PEP8Naming, "803") => Rule::InvalidArgumentName,
|
||||
(PEP8Naming, "804") => Rule::InvalidFirstArgumentNameForClassMethod,
|
||||
(PEP8Naming, "805") => Rule::InvalidFirstArgumentNameForMethod,
|
||||
(PEP8Naming, "806") => Rule::NonLowercaseVariableInFunction,
|
||||
(PEP8Naming, "807") => Rule::DunderFunctionName,
|
||||
(PEP8Naming, "811") => Rule::ConstantImportedAsNonConstant,
|
||||
(PEP8Naming, "812") => Rule::LowercaseImportedAsNonLowercase,
|
||||
(PEP8Naming, "813") => Rule::CamelcaseImportedAsLowercase,
|
||||
(PEP8Naming, "814") => Rule::CamelcaseImportedAsConstant,
|
||||
(PEP8Naming, "815") => Rule::MixedCaseVariableInClassScope,
|
||||
(PEP8Naming, "816") => Rule::MixedCaseVariableInGlobalScope,
|
||||
(PEP8Naming, "817") => Rule::CamelcaseImportedAsAcronym,
|
||||
(PEP8Naming, "818") => Rule::ErrorSuffixOnExceptionName,
|
||||
(PEP8Naming, "999") => Rule::InvalidModuleName,
|
||||
|
||||
// isort
|
||||
(Isort, "001") => Rule::UnsortedImports,
|
||||
(Isort, "002") => Rule::MissingRequiredImport,
|
||||
|
||||
// eradicate
|
||||
(Eradicate, "001") => Rule::CommentedOutCode,
|
||||
|
||||
// flake8-bandit
|
||||
(Flake8Bandit, "101") => Rule::Assert,
|
||||
(Flake8Bandit, "102") => Rule::ExecBuiltin,
|
||||
(Flake8Bandit, "103") => Rule::BadFilePermissions,
|
||||
(Flake8Bandit, "104") => Rule::HardcodedBindAllInterfaces,
|
||||
(Flake8Bandit, "105") => Rule::HardcodedPasswordString,
|
||||
(Flake8Bandit, "106") => Rule::HardcodedPasswordFuncArg,
|
||||
(Flake8Bandit, "107") => Rule::HardcodedPasswordDefault,
|
||||
(Flake8Bandit, "608") => Rule::HardcodedSQLExpression,
|
||||
(Flake8Bandit, "108") => Rule::HardcodedTempFile,
|
||||
(Flake8Bandit, "110") => Rule::TryExceptPass,
|
||||
(Flake8Bandit, "112") => Rule::TryExceptContinue,
|
||||
(Flake8Bandit, "113") => Rule::RequestWithoutTimeout,
|
||||
(Flake8Bandit, "324") => Rule::HashlibInsecureHashFunction,
|
||||
(Flake8Bandit, "501") => Rule::RequestWithNoCertValidation,
|
||||
(Flake8Bandit, "506") => Rule::UnsafeYAMLLoad,
|
||||
(Flake8Bandit, "508") => Rule::SnmpInsecureVersion,
|
||||
(Flake8Bandit, "509") => Rule::SnmpWeakCryptography,
|
||||
(Flake8Bandit, "612") => Rule::LoggingConfigInsecureListen,
|
||||
(Flake8Bandit, "701") => Rule::Jinja2AutoescapeFalse,
|
||||
|
||||
// flake8-boolean-trap
|
||||
(Flake8BooleanTrap, "001") => Rule::BooleanPositionalArgInFunctionDefinition,
|
||||
(Flake8BooleanTrap, "002") => Rule::BooleanDefaultValueInFunctionDefinition,
|
||||
(Flake8BooleanTrap, "003") => Rule::BooleanPositionalValueInFunctionCall,
|
||||
|
||||
// flake8-unused-arguments
|
||||
(Flake8UnusedArguments, "001") => Rule::UnusedFunctionArgument,
|
||||
(Flake8UnusedArguments, "002") => Rule::UnusedMethodArgument,
|
||||
(Flake8UnusedArguments, "003") => Rule::UnusedClassMethodArgument,
|
||||
(Flake8UnusedArguments, "004") => Rule::UnusedStaticMethodArgument,
|
||||
(Flake8UnusedArguments, "005") => Rule::UnusedLambdaArgument,
|
||||
|
||||
// flake8-import-conventions
|
||||
(Flake8ImportConventions, "001") => Rule::UnconventionalImportAlias,
|
||||
|
||||
// flake8-datetimez
|
||||
(Flake8Datetimez, "001") => Rule::CallDatetimeWithoutTzinfo,
|
||||
(Flake8Datetimez, "002") => Rule::CallDatetimeToday,
|
||||
(Flake8Datetimez, "003") => Rule::CallDatetimeUtcnow,
|
||||
(Flake8Datetimez, "004") => Rule::CallDatetimeUtcfromtimestamp,
|
||||
(Flake8Datetimez, "005") => Rule::CallDatetimeNowWithoutTzinfo,
|
||||
(Flake8Datetimez, "006") => Rule::CallDatetimeFromtimestamp,
|
||||
(Flake8Datetimez, "007") => Rule::CallDatetimeStrptimeWithoutZone,
|
||||
(Flake8Datetimez, "011") => Rule::CallDateToday,
|
||||
(Flake8Datetimez, "012") => Rule::CallDateFromtimestamp,
|
||||
|
||||
// pygrep-hooks
|
||||
(PygrepHooks, "001") => Rule::NoEval,
|
||||
(PygrepHooks, "002") => Rule::DeprecatedLogWarn,
|
||||
(PygrepHooks, "003") => Rule::BlanketTypeIgnore,
|
||||
(PygrepHooks, "004") => Rule::BlanketNOQA,
|
||||
|
||||
// pandas-vet
|
||||
(PandasVet, "002") => Rule::UseOfInplaceArgument,
|
||||
(PandasVet, "003") => Rule::UseOfDotIsNull,
|
||||
(PandasVet, "004") => Rule::UseOfDotNotNull,
|
||||
(PandasVet, "007") => Rule::UseOfDotIx,
|
||||
(PandasVet, "008") => Rule::UseOfDotAt,
|
||||
(PandasVet, "009") => Rule::UseOfDotIat,
|
||||
(PandasVet, "010") => Rule::UseOfDotPivotOrUnstack,
|
||||
(PandasVet, "011") => Rule::UseOfDotValues,
|
||||
(PandasVet, "012") => Rule::UseOfDotReadTable,
|
||||
(PandasVet, "013") => Rule::UseOfDotStack,
|
||||
(PandasVet, "015") => Rule::UseOfPdMerge,
|
||||
(PandasVet, "901") => Rule::DfIsABadVariableName,
|
||||
|
||||
// flake8-errmsg
|
||||
(Flake8ErrMsg, "101") => Rule::RawStringInException,
|
||||
(Flake8ErrMsg, "102") => Rule::FStringInException,
|
||||
(Flake8ErrMsg, "103") => Rule::DotFormatInException,
|
||||
|
||||
// flake8-pyi
|
||||
(Flake8Pyi, "001") => Rule::PrefixTypeParams,
|
||||
(Flake8Pyi, "007") => Rule::UnrecognizedPlatformCheck,
|
||||
(Flake8Pyi, "008") => Rule::UnrecognizedPlatformName,
|
||||
|
||||
// flake8-pytest-style
|
||||
(Flake8PytestStyle, "001") => Rule::IncorrectFixtureParenthesesStyle,
|
||||
(Flake8PytestStyle, "002") => Rule::FixturePositionalArgs,
|
||||
(Flake8PytestStyle, "003") => Rule::ExtraneousScopeFunction,
|
||||
(Flake8PytestStyle, "004") => Rule::MissingFixtureNameUnderscore,
|
||||
(Flake8PytestStyle, "005") => Rule::IncorrectFixtureNameUnderscore,
|
||||
(Flake8PytestStyle, "006") => Rule::ParametrizeNamesWrongType,
|
||||
(Flake8PytestStyle, "007") => Rule::ParametrizeValuesWrongType,
|
||||
(Flake8PytestStyle, "008") => Rule::PatchWithLambda,
|
||||
(Flake8PytestStyle, "009") => Rule::UnittestAssertion,
|
||||
(Flake8PytestStyle, "010") => Rule::RaisesWithoutException,
|
||||
(Flake8PytestStyle, "011") => Rule::RaisesTooBroad,
|
||||
(Flake8PytestStyle, "012") => Rule::RaisesWithMultipleStatements,
|
||||
(Flake8PytestStyle, "013") => Rule::IncorrectPytestImport,
|
||||
(Flake8PytestStyle, "015") => Rule::AssertAlwaysFalse,
|
||||
(Flake8PytestStyle, "016") => Rule::FailWithoutMessage,
|
||||
(Flake8PytestStyle, "017") => Rule::AssertInExcept,
|
||||
(Flake8PytestStyle, "018") => Rule::CompositeAssertion,
|
||||
(Flake8PytestStyle, "019") => Rule::FixtureParamWithoutValue,
|
||||
(Flake8PytestStyle, "020") => Rule::DeprecatedYieldFixture,
|
||||
(Flake8PytestStyle, "021") => Rule::FixtureFinalizerCallback,
|
||||
(Flake8PytestStyle, "022") => Rule::UselessYieldFixture,
|
||||
(Flake8PytestStyle, "023") => Rule::IncorrectMarkParenthesesStyle,
|
||||
(Flake8PytestStyle, "024") => Rule::UnnecessaryAsyncioMarkOnFixture,
|
||||
(Flake8PytestStyle, "025") => Rule::ErroneousUseFixturesOnFixture,
|
||||
(Flake8PytestStyle, "026") => Rule::UseFixturesWithoutParameters,
|
||||
|
||||
// flake8-pie
|
||||
(Flake8Pie, "790") => Rule::UnnecessaryPass,
|
||||
(Flake8Pie, "794") => Rule::DupeClassFieldDefinitions,
|
||||
(Flake8Pie, "796") => Rule::PreferUniqueEnums,
|
||||
(Flake8Pie, "800") => Rule::UnnecessarySpread,
|
||||
(Flake8Pie, "804") => Rule::UnnecessaryDictKwargs,
|
||||
(Flake8Pie, "807") => Rule::PreferListBuiltin,
|
||||
(Flake8Pie, "810") => Rule::SingleStartsEndsWith,
|
||||
|
||||
// flake8-commas
|
||||
(Flake8Commas, "812") => Rule::TrailingCommaMissing,
|
||||
(Flake8Commas, "818") => Rule::TrailingCommaOnBareTupleProhibited,
|
||||
(Flake8Commas, "819") => Rule::TrailingCommaProhibited,
|
||||
|
||||
// flake8-no-pep420
|
||||
(Flake8NoPep420, "001") => Rule::ImplicitNamespacePackage,
|
||||
|
||||
// flake8-executable
|
||||
(Flake8Executable, "001") => Rule::ShebangNotExecutable,
|
||||
(Flake8Executable, "002") => Rule::ShebangMissingExecutableFile,
|
||||
(Flake8Executable, "003") => Rule::ShebangPython,
|
||||
(Flake8Executable, "004") => Rule::ShebangWhitespace,
|
||||
(Flake8Executable, "005") => Rule::ShebangNewline,
|
||||
|
||||
// flake8-type-checking
|
||||
(Flake8TypeChecking, "001") => Rule::TypingOnlyFirstPartyImport,
|
||||
(Flake8TypeChecking, "002") => Rule::TypingOnlyThirdPartyImport,
|
||||
(Flake8TypeChecking, "003") => Rule::TypingOnlyStandardLibraryImport,
|
||||
(Flake8TypeChecking, "004") => Rule::RuntimeImportInTypeCheckingBlock,
|
||||
(Flake8TypeChecking, "005") => Rule::EmptyTypeCheckingBlock,
|
||||
|
||||
// tryceratops
|
||||
(Tryceratops, "002") => Rule::RaiseVanillaClass,
|
||||
(Tryceratops, "003") => Rule::RaiseVanillaArgs,
|
||||
(Tryceratops, "004") => Rule::PreferTypeError,
|
||||
(Tryceratops, "200") => Rule::ReraiseNoCause,
|
||||
(Tryceratops, "201") => Rule::VerboseRaise,
|
||||
(Tryceratops, "300") => Rule::TryConsiderElse,
|
||||
(Tryceratops, "301") => Rule::RaiseWithinTry,
|
||||
(Tryceratops, "400") => Rule::ErrorInsteadOfException,
|
||||
|
||||
// flake8-use-pathlib
|
||||
(Flake8UsePathlib, "100") => Rule::PathlibAbspath,
|
||||
(Flake8UsePathlib, "101") => Rule::PathlibChmod,
|
||||
(Flake8UsePathlib, "102") => Rule::PathlibMkdir,
|
||||
(Flake8UsePathlib, "103") => Rule::PathlibMakedirs,
|
||||
(Flake8UsePathlib, "104") => Rule::PathlibRename,
|
||||
(Flake8UsePathlib, "105") => Rule::PathlibReplace,
|
||||
(Flake8UsePathlib, "106") => Rule::PathlibRmdir,
|
||||
(Flake8UsePathlib, "107") => Rule::PathlibRemove,
|
||||
(Flake8UsePathlib, "108") => Rule::PathlibUnlink,
|
||||
(Flake8UsePathlib, "109") => Rule::PathlibGetcwd,
|
||||
(Flake8UsePathlib, "110") => Rule::PathlibExists,
|
||||
(Flake8UsePathlib, "111") => Rule::PathlibExpanduser,
|
||||
(Flake8UsePathlib, "112") => Rule::PathlibIsDir,
|
||||
(Flake8UsePathlib, "113") => Rule::PathlibIsFile,
|
||||
(Flake8UsePathlib, "114") => Rule::PathlibIsLink,
|
||||
(Flake8UsePathlib, "115") => Rule::PathlibReadlink,
|
||||
(Flake8UsePathlib, "116") => Rule::PathlibStat,
|
||||
(Flake8UsePathlib, "117") => Rule::PathlibIsAbs,
|
||||
(Flake8UsePathlib, "118") => Rule::PathlibJoin,
|
||||
(Flake8UsePathlib, "119") => Rule::PathlibBasename,
|
||||
(Flake8UsePathlib, "120") => Rule::PathlibDirname,
|
||||
(Flake8UsePathlib, "121") => Rule::PathlibSamefile,
|
||||
(Flake8UsePathlib, "122") => Rule::PathlibSplitext,
|
||||
(Flake8UsePathlib, "123") => Rule::PathlibOpen,
|
||||
(Flake8UsePathlib, "124") => Rule::PathlibPyPath,
|
||||
|
||||
// flake8-logging-format
|
||||
(Flake8LoggingFormat, "001") => Rule::LoggingStringFormat,
|
||||
(Flake8LoggingFormat, "002") => Rule::LoggingPercentFormat,
|
||||
(Flake8LoggingFormat, "003") => Rule::LoggingStringConcat,
|
||||
(Flake8LoggingFormat, "004") => Rule::LoggingFString,
|
||||
(Flake8LoggingFormat, "010") => Rule::LoggingWarn,
|
||||
(Flake8LoggingFormat, "101") => Rule::LoggingExtraAttrClash,
|
||||
(Flake8LoggingFormat, "201") => Rule::LoggingExcInfo,
|
||||
(Flake8LoggingFormat, "202") => Rule::LoggingRedundantExcInfo,
|
||||
|
||||
// flake8-raise
|
||||
(Flake8Raise, "102") => Rule::UnnecessaryParenOnRaiseException,
|
||||
|
||||
// flake8-self
|
||||
(Flake8Self, "001") => Rule::PrivateMemberAccess,
|
||||
|
||||
// numpy
|
||||
(Numpy, "001") => Rule::NumpyDeprecatedTypeAlias,
|
||||
(Numpy, "002") => Rule::NumpyLegacyRandom,
|
||||
|
||||
// ruff
|
||||
(Ruff, "001") => Rule::AmbiguousUnicodeCharacterString,
|
||||
(Ruff, "002") => Rule::AmbiguousUnicodeCharacterDocstring,
|
||||
(Ruff, "003") => Rule::AmbiguousUnicodeCharacterComment,
|
||||
(Ruff, "004") => Rule::KeywordArgumentBeforeStarArgument,
|
||||
(Ruff, "005") => Rule::UnpackInsteadOfConcatenatingToCollectionLiteral,
|
||||
(Ruff, "006") => Rule::AsyncioDanglingTask,
|
||||
(Ruff, "100") => Rule::UnusedNOQA,
|
||||
|
||||
// flake8-django
|
||||
(Flake8Django, "001") => Rule::NullableModelStringField,
|
||||
(Flake8Django, "008") => Rule::ModelWithoutDunderStr,
|
||||
(Flake8Django, "013") => Rule::NonLeadingReceiverDecorator,
|
||||
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
@@ -6,8 +6,8 @@ use itertools::Itertools;
|
||||
use super::external_config::ExternalConfig;
|
||||
use super::plugin::Plugin;
|
||||
use super::{parser, plugin};
|
||||
use crate::registry::RuleCodePrefix;
|
||||
use crate::rule_selector::{prefix_to_selector, RuleSelector};
|
||||
use crate::registry::Linter;
|
||||
use crate::rule_selector::RuleSelector;
|
||||
use crate::rules::flake8_pytest_style::types::{
|
||||
ParametrizeNameType, ParametrizeValuesRowType, ParametrizeValuesType,
|
||||
};
|
||||
@@ -23,9 +23,8 @@ use crate::settings::pyproject::Pyproject;
|
||||
use crate::warn_user;
|
||||
|
||||
const DEFAULT_SELECTORS: &[RuleSelector] = &[
|
||||
prefix_to_selector(RuleCodePrefix::F),
|
||||
prefix_to_selector(RuleCodePrefix::E),
|
||||
prefix_to_selector(RuleCodePrefix::W),
|
||||
RuleSelector::Linter(Linter::Pyflakes),
|
||||
RuleSelector::Linter(Linter::Pycodestyle),
|
||||
];
|
||||
|
||||
pub fn convert(
|
||||
@@ -359,13 +358,13 @@ pub fn convert(
|
||||
options.select = Some(
|
||||
select
|
||||
.into_iter()
|
||||
.sorted_by_key(RuleSelector::short_code)
|
||||
.sorted_by_key(RuleSelector::prefix_and_code)
|
||||
.collect(),
|
||||
);
|
||||
options.ignore = Some(
|
||||
ignore
|
||||
.into_iter()
|
||||
.sorted_by_key(RuleSelector::short_code)
|
||||
.sorted_by_key(RuleSelector::prefix_and_code)
|
||||
.collect(),
|
||||
);
|
||||
if flake8_annotations != flake8_annotations::settings::Options::default() {
|
||||
@@ -433,7 +432,7 @@ pub fn convert(
|
||||
/// plugins.
|
||||
fn resolve_select(plugins: &[Plugin]) -> HashSet<RuleSelector> {
|
||||
let mut select: HashSet<_> = DEFAULT_SELECTORS.iter().cloned().collect();
|
||||
select.extend(plugins.iter().map(Plugin::selector));
|
||||
select.extend(plugins.iter().map(|p| Linter::from(p).into()));
|
||||
select
|
||||
}
|
||||
|
||||
@@ -448,7 +447,7 @@ mod tests {
|
||||
use super::convert;
|
||||
use crate::flake8_to_ruff::converter::DEFAULT_SELECTORS;
|
||||
use crate::flake8_to_ruff::ExternalConfig;
|
||||
use crate::registry::RuleCodePrefix;
|
||||
use crate::registry::Linter;
|
||||
use crate::rule_selector::RuleSelector;
|
||||
use crate::rules::pydocstyle::settings::Convention;
|
||||
use crate::rules::{flake8_quotes, pydocstyle};
|
||||
@@ -463,7 +462,7 @@ mod tests {
|
||||
.iter()
|
||||
.cloned()
|
||||
.chain(plugins)
|
||||
.sorted_by_key(RuleSelector::short_code)
|
||||
.sorted_by_key(RuleSelector::prefix_and_code)
|
||||
.collect(),
|
||||
),
|
||||
..Options::default()
|
||||
@@ -578,7 +577,7 @@ mod tests {
|
||||
pydocstyle: Some(pydocstyle::settings::Options {
|
||||
convention: Some(Convention::Numpy),
|
||||
}),
|
||||
..default_options([RuleCodePrefix::D.into()])
|
||||
..default_options([Linter::Pydocstyle.into()])
|
||||
});
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
@@ -602,7 +601,7 @@ mod tests {
|
||||
docstring_quotes: None,
|
||||
avoid_escape: None,
|
||||
}),
|
||||
..default_options([RuleCodePrefix::Q.into()])
|
||||
..default_options([Linter::Flake8Quotes.into()])
|
||||
});
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
|
||||
@@ -196,7 +196,8 @@ mod tests {
|
||||
use anyhow::Result;
|
||||
|
||||
use super::{parse_files_to_codes_mapping, parse_prefix_codes, parse_strings};
|
||||
use crate::registry::RuleCodePrefix;
|
||||
use crate::codes;
|
||||
use crate::registry::Linter;
|
||||
use crate::rule_selector::RuleSelector;
|
||||
use crate::settings::types::PatternPrefixPair;
|
||||
|
||||
@@ -211,19 +212,25 @@ mod tests {
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
let actual = parse_prefix_codes("F401");
|
||||
let expected = vec![RuleCodePrefix::F401.into()];
|
||||
let expected = vec![codes::Pyflakes::_401.into()];
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
let actual = parse_prefix_codes("F401,");
|
||||
let expected = vec![RuleCodePrefix::F401.into()];
|
||||
let expected = vec![codes::Pyflakes::_401.into()];
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
let actual = parse_prefix_codes("F401,E501");
|
||||
let expected = vec![RuleCodePrefix::F401.into(), RuleCodePrefix::E501.into()];
|
||||
let expected = vec![
|
||||
codes::Pyflakes::_401.into(),
|
||||
codes::Pycodestyle::E501.into(),
|
||||
];
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
let actual = parse_prefix_codes("F401, E501");
|
||||
let expected = vec![RuleCodePrefix::F401.into(), RuleCodePrefix::E501.into()];
|
||||
let expected = vec![
|
||||
codes::Pyflakes::_401.into(),
|
||||
codes::Pycodestyle::E501.into(),
|
||||
];
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
@@ -276,11 +283,11 @@ mod tests {
|
||||
let expected: Vec<PatternPrefixPair> = vec![
|
||||
PatternPrefixPair {
|
||||
pattern: "locust/test/*".to_string(),
|
||||
prefix: RuleCodePrefix::F841.into(),
|
||||
prefix: codes::Pyflakes::_841.into(),
|
||||
},
|
||||
PatternPrefixPair {
|
||||
pattern: "examples/*".to_string(),
|
||||
prefix: RuleCodePrefix::F841.into(),
|
||||
prefix: codes::Pyflakes::_841.into(),
|
||||
},
|
||||
];
|
||||
assert_eq!(actual, expected);
|
||||
@@ -296,23 +303,23 @@ mod tests {
|
||||
let expected: Vec<PatternPrefixPair> = vec![
|
||||
PatternPrefixPair {
|
||||
pattern: "t/*".to_string(),
|
||||
prefix: RuleCodePrefix::D.into(),
|
||||
prefix: Linter::Pydocstyle.into(),
|
||||
},
|
||||
PatternPrefixPair {
|
||||
pattern: "setup.py".to_string(),
|
||||
prefix: RuleCodePrefix::D.into(),
|
||||
prefix: Linter::Pydocstyle.into(),
|
||||
},
|
||||
PatternPrefixPair {
|
||||
pattern: "examples/*".to_string(),
|
||||
prefix: RuleCodePrefix::D.into(),
|
||||
prefix: Linter::Pydocstyle.into(),
|
||||
},
|
||||
PatternPrefixPair {
|
||||
pattern: "docs/*".to_string(),
|
||||
prefix: RuleCodePrefix::D.into(),
|
||||
prefix: Linter::Pydocstyle.into(),
|
||||
},
|
||||
PatternPrefixPair {
|
||||
pattern: "extra/*".to_string(),
|
||||
prefix: RuleCodePrefix::D.into(),
|
||||
prefix: Linter::Pydocstyle.into(),
|
||||
},
|
||||
];
|
||||
assert_eq!(actual, expected);
|
||||
@@ -334,47 +341,47 @@ mod tests {
|
||||
let expected: Vec<PatternPrefixPair> = vec![
|
||||
PatternPrefixPair {
|
||||
pattern: "scrapy/__init__.py".to_string(),
|
||||
prefix: RuleCodePrefix::E402.into(),
|
||||
prefix: codes::Pycodestyle::E402.into(),
|
||||
},
|
||||
PatternPrefixPair {
|
||||
pattern: "scrapy/core/downloader/handlers/http.py".to_string(),
|
||||
prefix: RuleCodePrefix::F401.into(),
|
||||
prefix: codes::Pyflakes::_401.into(),
|
||||
},
|
||||
PatternPrefixPair {
|
||||
pattern: "scrapy/http/__init__.py".to_string(),
|
||||
prefix: RuleCodePrefix::F401.into(),
|
||||
prefix: codes::Pyflakes::_401.into(),
|
||||
},
|
||||
PatternPrefixPair {
|
||||
pattern: "scrapy/linkextractors/__init__.py".to_string(),
|
||||
prefix: RuleCodePrefix::E402.into(),
|
||||
prefix: codes::Pycodestyle::E402.into(),
|
||||
},
|
||||
PatternPrefixPair {
|
||||
pattern: "scrapy/linkextractors/__init__.py".to_string(),
|
||||
prefix: RuleCodePrefix::F401.into(),
|
||||
prefix: codes::Pyflakes::_401.into(),
|
||||
},
|
||||
PatternPrefixPair {
|
||||
pattern: "scrapy/selector/__init__.py".to_string(),
|
||||
prefix: RuleCodePrefix::F401.into(),
|
||||
prefix: codes::Pyflakes::_401.into(),
|
||||
},
|
||||
PatternPrefixPair {
|
||||
pattern: "scrapy/spiders/__init__.py".to_string(),
|
||||
prefix: RuleCodePrefix::E402.into(),
|
||||
prefix: codes::Pycodestyle::E402.into(),
|
||||
},
|
||||
PatternPrefixPair {
|
||||
pattern: "scrapy/spiders/__init__.py".to_string(),
|
||||
prefix: RuleCodePrefix::F401.into(),
|
||||
prefix: codes::Pyflakes::_401.into(),
|
||||
},
|
||||
PatternPrefixPair {
|
||||
pattern: "scrapy/utils/url.py".to_string(),
|
||||
prefix: RuleCodePrefix::F403.into(),
|
||||
prefix: codes::Pyflakes::_403.into(),
|
||||
},
|
||||
PatternPrefixPair {
|
||||
pattern: "scrapy/utils/url.py".to_string(),
|
||||
prefix: RuleCodePrefix::F405.into(),
|
||||
prefix: codes::Pyflakes::_405.into(),
|
||||
},
|
||||
PatternPrefixPair {
|
||||
pattern: "tests/test_loader.py".to_string(),
|
||||
prefix: RuleCodePrefix::E741.into(),
|
||||
prefix: codes::Pycodestyle::E741.into(),
|
||||
},
|
||||
];
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
@@ -4,7 +4,7 @@ use std::str::FromStr;
|
||||
|
||||
use anyhow::anyhow;
|
||||
|
||||
use crate::registry::RuleCodePrefix;
|
||||
use crate::registry::Linter;
|
||||
use crate::rule_selector::RuleSelector;
|
||||
|
||||
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
|
||||
@@ -131,43 +131,42 @@ impl fmt::Debug for Plugin {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(martin): Convert into `impl From<Plugin> for Linter`
|
||||
impl Plugin {
|
||||
pub fn selector(&self) -> RuleSelector {
|
||||
match self {
|
||||
Plugin::Flake82020 => RuleCodePrefix::YTT.into(),
|
||||
Plugin::Flake8Annotations => RuleCodePrefix::ANN.into(),
|
||||
Plugin::Flake8Bandit => RuleCodePrefix::S.into(),
|
||||
Plugin::Flake8BlindExcept => RuleCodePrefix::BLE.into(),
|
||||
Plugin::Flake8BooleanTrap => RuleCodePrefix::FBT.into(),
|
||||
Plugin::Flake8Bugbear => RuleCodePrefix::B.into(),
|
||||
Plugin::Flake8Builtins => RuleCodePrefix::A.into(),
|
||||
Plugin::Flake8Commas => RuleCodePrefix::COM.into(),
|
||||
Plugin::Flake8Comprehensions => RuleCodePrefix::C4.into(),
|
||||
Plugin::Flake8Datetimez => RuleCodePrefix::DTZ.into(),
|
||||
Plugin::Flake8Debugger => RuleCodePrefix::T1.into(),
|
||||
Plugin::Flake8Docstrings => RuleCodePrefix::D.into(),
|
||||
Plugin::Flake8Eradicate => RuleCodePrefix::ERA.into(),
|
||||
Plugin::Flake8ErrMsg => RuleCodePrefix::EM.into(),
|
||||
Plugin::Flake8Executable => RuleCodePrefix::EXE.into(),
|
||||
Plugin::Flake8ImplicitStrConcat => RuleCodePrefix::ISC.into(),
|
||||
Plugin::Flake8ImportConventions => RuleCodePrefix::ICN.into(),
|
||||
Plugin::Flake8NoPep420 => RuleCodePrefix::INP.into(),
|
||||
Plugin::Flake8Pie => RuleCodePrefix::PIE.into(),
|
||||
Plugin::Flake8Print => RuleCodePrefix::T2.into(),
|
||||
Plugin::Flake8PytestStyle => RuleCodePrefix::PT.into(),
|
||||
Plugin::Flake8Quotes => RuleCodePrefix::Q.into(),
|
||||
Plugin::Flake8Return => RuleCodePrefix::RET.into(),
|
||||
Plugin::Flake8Simplify => RuleCodePrefix::SIM.into(),
|
||||
Plugin::Flake8TidyImports => RuleCodePrefix::TID.into(),
|
||||
Plugin::Flake8TypeChecking => RuleCodePrefix::TCH.into(),
|
||||
Plugin::Flake8UnusedArguments => RuleCodePrefix::ARG.into(),
|
||||
Plugin::Flake8UsePathlib => RuleCodePrefix::PTH.into(),
|
||||
Plugin::McCabe => RuleCodePrefix::C9.into(),
|
||||
Plugin::PEP8Naming => RuleCodePrefix::N.into(),
|
||||
Plugin::PandasVet => RuleCodePrefix::PD.into(),
|
||||
Plugin::Pyupgrade => RuleCodePrefix::UP.into(),
|
||||
Plugin::Tryceratops => RuleCodePrefix::TRY.into(),
|
||||
impl From<&Plugin> for Linter {
|
||||
fn from(plugin: &Plugin) -> Self {
|
||||
match plugin {
|
||||
Plugin::Flake82020 => Linter::Flake82020,
|
||||
Plugin::Flake8Annotations => Linter::Flake8Annotations,
|
||||
Plugin::Flake8Bandit => Linter::Flake8Bandit,
|
||||
Plugin::Flake8BlindExcept => Linter::Flake8BlindExcept,
|
||||
Plugin::Flake8BooleanTrap => Linter::Flake8BooleanTrap,
|
||||
Plugin::Flake8Bugbear => Linter::Flake8Bugbear,
|
||||
Plugin::Flake8Builtins => Linter::Flake8Builtins,
|
||||
Plugin::Flake8Commas => Linter::Flake8Commas,
|
||||
Plugin::Flake8Comprehensions => Linter::Flake8Comprehensions,
|
||||
Plugin::Flake8Datetimez => Linter::Flake8Datetimez,
|
||||
Plugin::Flake8Debugger => Linter::Flake8Debugger,
|
||||
Plugin::Flake8Docstrings => Linter::Pydocstyle,
|
||||
Plugin::Flake8Eradicate => Linter::Eradicate,
|
||||
Plugin::Flake8ErrMsg => Linter::Flake8ErrMsg,
|
||||
Plugin::Flake8Executable => Linter::Flake8Executable,
|
||||
Plugin::Flake8ImplicitStrConcat => Linter::Flake8ImplicitStrConcat,
|
||||
Plugin::Flake8ImportConventions => Linter::Flake8ImportConventions,
|
||||
Plugin::Flake8NoPep420 => Linter::Flake8NoPep420,
|
||||
Plugin::Flake8Pie => Linter::Flake8Pie,
|
||||
Plugin::Flake8Print => Linter::Flake8Print,
|
||||
Plugin::Flake8PytestStyle => Linter::Flake8PytestStyle,
|
||||
Plugin::Flake8Quotes => Linter::Flake8Quotes,
|
||||
Plugin::Flake8Return => Linter::Flake8Return,
|
||||
Plugin::Flake8Simplify => Linter::Flake8Simplify,
|
||||
Plugin::Flake8TidyImports => Linter::Flake8TidyImports,
|
||||
Plugin::Flake8TypeChecking => Linter::Flake8TypeChecking,
|
||||
Plugin::Flake8UnusedArguments => Linter::Flake8UnusedArguments,
|
||||
Plugin::Flake8UsePathlib => Linter::Flake8UsePathlib,
|
||||
Plugin::McCabe => Linter::McCabe,
|
||||
Plugin::PEP8Naming => Linter::PEP8Naming,
|
||||
Plugin::PandasVet => Linter::PandasVet,
|
||||
Plugin::Pyupgrade => Linter::Pyupgrade,
|
||||
Plugin::Tryceratops => Linter::Tryceratops,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -334,7 +333,7 @@ pub fn infer_plugins_from_codes(selectors: &HashSet<RuleSelector>) -> Vec<Plugin
|
||||
for selector in selectors {
|
||||
if selector
|
||||
.into_iter()
|
||||
.any(|rule| plugin.selector().into_iter().any(|r| r == rule))
|
||||
.any(|rule| Linter::from(plugin).into_iter().any(|r| r == rule))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
//!
|
||||
//! [Ruff]: https://github.com/charliermarsh/ruff
|
||||
|
||||
pub use ast::types::Range;
|
||||
use cfg_if::cfg_if;
|
||||
pub use rule_selector::RuleSelector;
|
||||
pub use rules::pycodestyle::rules::IOError;
|
||||
@@ -15,6 +16,7 @@ mod ast;
|
||||
mod autofix;
|
||||
pub mod cache;
|
||||
mod checkers;
|
||||
mod codes;
|
||||
mod cst;
|
||||
mod directives;
|
||||
mod doc_lines;
|
||||
|
||||
@@ -9,10 +9,10 @@ use crate::directives;
|
||||
use crate::linter::{check_path, LinterResult};
|
||||
use crate::registry::Rule;
|
||||
use crate::rules::{
|
||||
flake8_annotations, flake8_bandit, flake8_bugbear, flake8_builtins, flake8_errmsg,
|
||||
flake8_implicit_str_concat, flake8_import_conventions, flake8_pytest_style, flake8_quotes,
|
||||
flake8_tidy_imports, flake8_type_checking, flake8_unused_arguments, isort, mccabe, pep8_naming,
|
||||
pycodestyle, pydocstyle, pylint, pyupgrade,
|
||||
flake8_annotations, flake8_bandit, flake8_bugbear, flake8_builtins, flake8_comprehensions,
|
||||
flake8_errmsg, flake8_implicit_str_concat, flake8_import_conventions, flake8_pytest_style,
|
||||
flake8_quotes, flake8_self, flake8_tidy_imports, flake8_type_checking, flake8_unused_arguments,
|
||||
isort, mccabe, pep8_naming, pycodestyle, pydocstyle, pylint, pyupgrade,
|
||||
};
|
||||
use crate::rustpython_helpers::tokenize;
|
||||
use crate::settings::configuration::Configuration;
|
||||
@@ -66,7 +66,7 @@ impl Serialize for SerializeRuleAsCode {
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
serializer.serialize_str(self.0.code())
|
||||
serializer.serialize_str(&self.0.noqa_code().to_string())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,9 +139,11 @@ pub fn defaultSettings() -> Result<JsValue, JsValue> {
|
||||
flake8_bandit: Some(flake8_bandit::settings::Settings::default().into()),
|
||||
flake8_bugbear: Some(flake8_bugbear::settings::Settings::default().into()),
|
||||
flake8_builtins: Some(flake8_builtins::settings::Settings::default().into()),
|
||||
flake8_comprehensions: Some(flake8_comprehensions::settings::Settings::default().into()),
|
||||
flake8_errmsg: Some(flake8_errmsg::settings::Settings::default().into()),
|
||||
flake8_pytest_style: Some(flake8_pytest_style::settings::Settings::default().into()),
|
||||
flake8_quotes: Some(flake8_quotes::settings::Settings::default().into()),
|
||||
flake8_self: Some(flake8_self::settings::Settings::default().into()),
|
||||
flake8_implicit_str_concat: Some(
|
||||
flake8_implicit_str_concat::settings::Settings::default().into(),
|
||||
),
|
||||
|
||||
@@ -211,7 +211,7 @@ pub fn check_path(
|
||||
indexer.commented_lines(),
|
||||
&directives.noqa_line_for,
|
||||
settings,
|
||||
autofix,
|
||||
error.as_ref().map_or(autofix, |_| flags::Autofix::Disabled),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -71,9 +71,9 @@ impl Source {
|
||||
} else {
|
||||
Location::new(diagnostic.end_location.row() + 1, 0)
|
||||
};
|
||||
let source = locator.slice_source_code_range(&Range::new(location, end_location));
|
||||
let source = locator.slice(&Range::new(location, end_location));
|
||||
let num_chars_in_range = locator
|
||||
.slice_source_code_range(&Range::new(diagnostic.location, diagnostic.end_location))
|
||||
.slice(&Range::new(diagnostic.location, diagnostic.end_location))
|
||||
.chars()
|
||||
.count();
|
||||
Source {
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
use std::fmt::{Display, Write};
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::Result;
|
||||
use itertools::Itertools;
|
||||
use log::warn;
|
||||
use nohash_hasher::IntMap;
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
@@ -10,6 +12,7 @@ use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use rustpython_parser::ast::Location;
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::codes::NoqaCode;
|
||||
use crate::registry::{Diagnostic, Rule};
|
||||
use crate::rule_redirects::get_redirect_target;
|
||||
use crate::source_code::{LineEnding, Locator};
|
||||
@@ -22,16 +25,47 @@ static NOQA_LINE_REGEX: Lazy<Regex> = Lazy::new(|| {
|
||||
});
|
||||
static SPLIT_COMMA_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"[,\s]").unwrap());
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Exemption<'a> {
|
||||
None,
|
||||
All,
|
||||
Codes(Vec<&'a str>),
|
||||
}
|
||||
|
||||
/// Return `true` if a file is exempt from checking based on the contents of the
|
||||
/// given line.
|
||||
pub fn is_file_exempt(line: &str) -> bool {
|
||||
pub fn extract_file_exemption(line: &str) -> Exemption {
|
||||
let line = line.trim_start();
|
||||
line.starts_with("# flake8: noqa")
|
||||
|
||||
if line.starts_with("# flake8: noqa")
|
||||
|| line.starts_with("# flake8: NOQA")
|
||||
|| line.starts_with("# flake8: NoQA")
|
||||
|| line.starts_with("# ruff: noqa")
|
||||
|| line.starts_with("# ruff: NOQA")
|
||||
|| line.starts_with("# ruff: NoQA")
|
||||
{
|
||||
return Exemption::All;
|
||||
}
|
||||
|
||||
if let Some(remainder) = line
|
||||
.strip_prefix("# ruff: noqa")
|
||||
.or_else(|| line.strip_prefix("# ruff: NOQA"))
|
||||
.or_else(|| line.strip_prefix("# ruff: NoQA"))
|
||||
{
|
||||
if remainder.is_empty() {
|
||||
return Exemption::All;
|
||||
} else if let Some(codes) = remainder.strip_prefix(':') {
|
||||
let codes: Vec<&str> = SPLIT_COMMA_REGEX
|
||||
.split(codes.trim())
|
||||
.map(str::trim)
|
||||
.filter(|code| !code.is_empty())
|
||||
.collect();
|
||||
if codes.is_empty() {
|
||||
warn!("Expected rule codes on `noqa` directive: \"{line}\"");
|
||||
}
|
||||
return Exemption::Codes(codes);
|
||||
}
|
||||
warn!("Unexpected suffix on `noqa` directive: \"{line}\"");
|
||||
}
|
||||
|
||||
Exemption::None
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -47,16 +81,22 @@ pub fn extract_noqa_directive(line: &str) -> Directive {
|
||||
Some(caps) => match caps.name("spaces") {
|
||||
Some(spaces) => match caps.name("noqa") {
|
||||
Some(noqa) => match caps.name("codes") {
|
||||
Some(codes) => Directive::Codes(
|
||||
spaces.as_str().chars().count(),
|
||||
noqa.start(),
|
||||
noqa.end(),
|
||||
SPLIT_COMMA_REGEX
|
||||
.split(codes.as_str())
|
||||
Some(codes) => {
|
||||
let codes: Vec<&str> = SPLIT_COMMA_REGEX
|
||||
.split(codes.as_str().trim())
|
||||
.map(str::trim)
|
||||
.filter(|code| !code.is_empty())
|
||||
.collect(),
|
||||
),
|
||||
.collect();
|
||||
if codes.is_empty() {
|
||||
warn!("Expected rule codes on `noqa` directive: \"{line}\"");
|
||||
}
|
||||
Directive::Codes(
|
||||
spaces.as_str().chars().count(),
|
||||
noqa.start(),
|
||||
noqa.end(),
|
||||
codes,
|
||||
)
|
||||
}
|
||||
None => {
|
||||
Directive::All(spaces.as_str().chars().count(), noqa.start(), noqa.end())
|
||||
}
|
||||
@@ -72,7 +112,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 {
|
||||
let needle: &str = needle.code();
|
||||
let needle = needle.noqa_code();
|
||||
haystack
|
||||
.iter()
|
||||
.any(|candidate| needle == get_redirect_target(candidate).unwrap_or(candidate))
|
||||
@@ -86,7 +126,7 @@ pub fn rule_is_ignored(
|
||||
locator: &Locator,
|
||||
) -> bool {
|
||||
let noqa_lineno = noqa_line_for.get(&lineno).unwrap_or(&lineno);
|
||||
let line = locator.slice_source_code_range(&Range::new(
|
||||
let line = locator.slice(&Range::new(
|
||||
Location::new(*noqa_lineno, 0),
|
||||
Location::new(noqa_lineno + 1, 0),
|
||||
));
|
||||
@@ -123,68 +163,93 @@ fn add_noqa_inner(
|
||||
noqa_line_for: &IntMap<usize, usize>,
|
||||
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();
|
||||
|
||||
// Whether the file is exempted from all checks.
|
||||
let mut file_exempted = false;
|
||||
|
||||
// Codes that are globally exempted (within the current file).
|
||||
let mut file_exemptions: Vec<NoqaCode> = vec![];
|
||||
|
||||
let lines: Vec<&str> = contents.lines().collect();
|
||||
for (lineno, line) in lines.iter().enumerate() {
|
||||
// If we hit an exemption for the entire file, bail.
|
||||
if is_file_exempt(line) {
|
||||
return (0, contents.to_string());
|
||||
for lineno in commented_lines {
|
||||
match extract_file_exemption(lines[lineno - 1]) {
|
||||
Exemption::All => {
|
||||
file_exempted = true;
|
||||
}
|
||||
Exemption::Codes(codes) => {
|
||||
file_exemptions.extend(codes.into_iter().filter_map(|code| {
|
||||
if let Ok(rule) = Rule::from_code(get_redirect_target(code).unwrap_or(code)) {
|
||||
Some(rule.noqa_code())
|
||||
} else {
|
||||
warn!("Invalid code provided to `# ruff: noqa`: {}", code);
|
||||
None
|
||||
}
|
||||
}));
|
||||
}
|
||||
Exemption::None => {}
|
||||
}
|
||||
}
|
||||
|
||||
// Mark any non-ignored diagnostics.
|
||||
for diagnostic in diagnostics {
|
||||
// If the file is exempted, don't add any noqa directives.
|
||||
if file_exempted {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Grab the noqa (logical) line number for the current (physical) line.
|
||||
let noqa_lineno = noqa_line_for.get(&(lineno + 1)).unwrap_or(&(lineno + 1)) - 1;
|
||||
|
||||
let mut codes: FxHashSet<&Rule> = FxHashSet::default();
|
||||
for diagnostic in diagnostics {
|
||||
if diagnostic.location.row() == lineno + 1 {
|
||||
// Is the violation ignored by a `noqa` directive on the parent line?
|
||||
if let Some(parent_lineno) = diagnostic.parent.map(|location| location.row()) {
|
||||
let noqa_lineno = noqa_line_for.get(&parent_lineno).unwrap_or(&parent_lineno);
|
||||
if commented_lines.contains(noqa_lineno) {
|
||||
match extract_noqa_directive(lines[noqa_lineno - 1]) {
|
||||
Directive::All(..) => {
|
||||
continue;
|
||||
}
|
||||
Directive::Codes(.., codes) => {
|
||||
if includes(diagnostic.kind.rule(), &codes) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Directive::None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Is the diagnostic ignored by a `noqa` directive on the same line?
|
||||
let diagnostic_lineno = diagnostic.location.row();
|
||||
let noqa_lineno = noqa_line_for
|
||||
.get(&diagnostic_lineno)
|
||||
.unwrap_or(&diagnostic_lineno);
|
||||
if commented_lines.contains(noqa_lineno) {
|
||||
match extract_noqa_directive(lines[noqa_lineno - 1]) {
|
||||
Directive::All(..) => {
|
||||
continue;
|
||||
}
|
||||
Directive::Codes(.., codes) => {
|
||||
if includes(diagnostic.kind.rule(), &codes) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Directive::None => {}
|
||||
}
|
||||
}
|
||||
|
||||
// The diagnostic is not ignored by any `noqa` directive; add it to the list.
|
||||
codes.insert(diagnostic.kind.rule());
|
||||
// If the diagnostic is ignored by a global exemption, don't add a noqa directive.
|
||||
if !file_exemptions.is_empty() {
|
||||
if file_exemptions.contains(&diagnostic.kind.rule().noqa_code()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if !codes.is_empty() {
|
||||
matches_by_line
|
||||
.entry(noqa_lineno)
|
||||
.or_default()
|
||||
.extend(codes);
|
||||
// Is the violation ignored by a `noqa` directive on the parent line?
|
||||
if let Some(parent_lineno) = diagnostic.parent.map(|location| location.row()) {
|
||||
let noqa_lineno = noqa_line_for.get(&parent_lineno).unwrap_or(&parent_lineno);
|
||||
if commented_lines.contains(noqa_lineno) {
|
||||
match extract_noqa_directive(lines[noqa_lineno - 1]) {
|
||||
Directive::All(..) => {
|
||||
continue;
|
||||
}
|
||||
Directive::Codes(.., codes) => {
|
||||
if includes(diagnostic.kind.rule(), &codes) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Directive::None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Is the diagnostic ignored by a `noqa` directive on the same line?
|
||||
let diagnostic_lineno = diagnostic.location.row();
|
||||
let noqa_lineno = noqa_line_for
|
||||
.get(&diagnostic_lineno)
|
||||
.unwrap_or(&diagnostic_lineno);
|
||||
if commented_lines.contains(noqa_lineno) {
|
||||
match extract_noqa_directive(lines[noqa_lineno - 1]) {
|
||||
Directive::All(..) => {
|
||||
continue;
|
||||
}
|
||||
Directive::Codes(.., codes) => {
|
||||
if includes(diagnostic.kind.rule(), &codes) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Directive::None => {}
|
||||
}
|
||||
}
|
||||
|
||||
// The diagnostic is not ignored by any `noqa` directive; add it to the list.
|
||||
let lineno = diagnostic.location.row() - 1;
|
||||
let noqa_lineno = noqa_line_for.get(&(lineno + 1)).unwrap_or(&(lineno + 1)) - 1;
|
||||
matches_by_line
|
||||
.entry(noqa_lineno)
|
||||
.or_default()
|
||||
.insert(diagnostic.kind.rule());
|
||||
}
|
||||
|
||||
let mut count: usize = 0;
|
||||
@@ -205,9 +270,7 @@ fn add_noqa_inner(
|
||||
output.push_str(" # noqa: ");
|
||||
|
||||
// Add codes.
|
||||
let codes: Vec<&str> = rules.iter().map(|r| r.code()).collect();
|
||||
let suffix = codes.join(", ");
|
||||
output.push_str(&suffix);
|
||||
push_codes(&mut output, rules.iter().map(|r| r.noqa_code()));
|
||||
output.push_str(line_ending);
|
||||
count += 1;
|
||||
}
|
||||
@@ -228,14 +291,14 @@ fn add_noqa_inner(
|
||||
formatted.push_str(" # noqa: ");
|
||||
|
||||
// Add codes.
|
||||
let codes: Vec<&str> = rules
|
||||
.iter()
|
||||
.map(|r| r.code())
|
||||
.chain(existing.into_iter())
|
||||
.sorted_unstable()
|
||||
.collect();
|
||||
let suffix = codes.join(", ");
|
||||
formatted.push_str(&suffix);
|
||||
push_codes(
|
||||
&mut formatted,
|
||||
rules
|
||||
.iter()
|
||||
.map(|r| r.noqa_code().to_string())
|
||||
.chain(existing.into_iter().map(ToString::to_string))
|
||||
.sorted_unstable(),
|
||||
);
|
||||
|
||||
output.push_str(&formatted);
|
||||
output.push_str(line_ending);
|
||||
@@ -253,6 +316,17 @@ fn add_noqa_inner(
|
||||
(count, output)
|
||||
}
|
||||
|
||||
fn push_codes<I: Display>(str: &mut String, codes: impl Iterator<Item = I>) {
|
||||
let mut first = true;
|
||||
for code in codes {
|
||||
if !first {
|
||||
str.push_str(", ");
|
||||
}
|
||||
let _ = write!(str, "{}", code);
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use nohash_hasher::IntMap;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,6 +7,7 @@ use std::sync::RwLock;
|
||||
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use ignore::{DirEntry, WalkBuilder, WalkState};
|
||||
use itertools::Itertools;
|
||||
use log::debug;
|
||||
use path_absolutize::path_dedot;
|
||||
use rustc_hash::FxHashSet;
|
||||
@@ -202,6 +203,11 @@ fn is_python_path(path: &Path) -> bool {
|
||||
.map_or(false, |ext| ext == "py" || ext == "pyi")
|
||||
}
|
||||
|
||||
/// Return `true` if the `Path` appears to be that of a Python interface definition file (`.pyi`).
|
||||
pub fn is_interface_definition_path(path: &Path) -> bool {
|
||||
path.extension().map_or(false, |ext| ext == "pyi")
|
||||
}
|
||||
|
||||
/// Return `true` if the `Entry` appears to be that of a Python file.
|
||||
pub fn is_python_entry(entry: &DirEntry) -> bool {
|
||||
is_python_path(entry.path())
|
||||
@@ -217,7 +223,7 @@ pub fn python_files_in_path(
|
||||
processor: impl ConfigProcessor,
|
||||
) -> Result<(Vec<Result<DirEntry, ignore::Error>>, Resolver)> {
|
||||
// Normalize every path (e.g., convert from relative to absolute).
|
||||
let mut paths: Vec<PathBuf> = paths.iter().map(fs::normalize_path).collect();
|
||||
let mut paths: Vec<PathBuf> = paths.iter().map(fs::normalize_path).unique().collect();
|
||||
|
||||
// Search for `pyproject.toml` files in all parent directories.
|
||||
let mut resolver = Resolver::default();
|
||||
|
||||
@@ -15,6 +15,14 @@ pub(crate) fn get_redirect(code: &str) -> Option<(&'static str, &'static str)> {
|
||||
|
||||
static REDIRECTS: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| {
|
||||
HashMap::from_iter([
|
||||
// The following are here because we don't yet have the many-to-one mapping enabled.
|
||||
("SIM111", "SIM110"),
|
||||
// The following are deprecated.
|
||||
("C", "C4"),
|
||||
("C9", "C90"),
|
||||
("T", "T10"),
|
||||
("T1", "T10"),
|
||||
("T2", "T20"),
|
||||
// TODO(charlie): Remove by 2023-02-01.
|
||||
("R", "RET"),
|
||||
("R5", "RET5"),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use itertools::Itertools;
|
||||
use schemars::_serde_json::Value;
|
||||
use schemars::schema::{InstanceType, Schema, SchemaObject};
|
||||
use schemars::JsonSchema;
|
||||
@@ -8,19 +9,27 @@ use serde::{Deserialize, Serialize};
|
||||
use strum::IntoEnumIterator;
|
||||
use strum_macros::EnumIter;
|
||||
|
||||
use crate::registry::{Rule, RuleCodePrefix, RuleIter};
|
||||
use crate::codes::RuleCodePrefix;
|
||||
use crate::registry::{Linter, Rule, RuleIter, RuleNamespace};
|
||||
use crate::rule_redirects::get_redirect;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum RuleSelector {
|
||||
/// All rules
|
||||
All,
|
||||
Linter(Linter),
|
||||
Prefix {
|
||||
prefix: RuleCodePrefix,
|
||||
redirected_from: Option<&'static str>,
|
||||
},
|
||||
}
|
||||
|
||||
impl From<Linter> for RuleSelector {
|
||||
fn from(linter: Linter) -> Self {
|
||||
Self::Linter(linter)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for RuleSelector {
|
||||
type Err = ParseError;
|
||||
|
||||
@@ -32,9 +41,17 @@ impl FromStr for RuleSelector {
|
||||
Some((from, target)) => (target, Some(from)),
|
||||
None => (s, None),
|
||||
};
|
||||
|
||||
let (linter, code) =
|
||||
Linter::parse_code(s).ok_or_else(|| ParseError::Unknown(s.to_string()))?;
|
||||
|
||||
if code.is_empty() {
|
||||
return Ok(Self::Linter(linter));
|
||||
}
|
||||
|
||||
Ok(Self::Prefix {
|
||||
prefix: RuleCodePrefix::from_str(s)
|
||||
.map_err(|_| ParseError::Unknown(s.to_string()))?,
|
||||
prefix: RuleCodePrefix::parse(&linter, code)
|
||||
.map_err(|_| ParseError::Unknown(code.to_string()))?,
|
||||
redirected_from,
|
||||
})
|
||||
}
|
||||
@@ -50,10 +67,13 @@ pub enum ParseError {
|
||||
}
|
||||
|
||||
impl RuleSelector {
|
||||
pub fn short_code(&self) -> &'static str {
|
||||
pub fn prefix_and_code(&self) -> (&'static str, &'static str) {
|
||||
match self {
|
||||
RuleSelector::All => "ALL",
|
||||
RuleSelector::Prefix { prefix, .. } => prefix.into(),
|
||||
RuleSelector::All => ("", "ALL"),
|
||||
RuleSelector::Prefix { prefix, .. } => {
|
||||
(prefix.linter().common_prefix(), prefix.short_code())
|
||||
}
|
||||
RuleSelector::Linter(l) => (l.common_prefix(), ""),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -63,7 +83,8 @@ impl Serialize for RuleSelector {
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
serializer.serialize_str(self.short_code())
|
||||
let (prefix, code) = self.prefix_and_code();
|
||||
serializer.serialize_str(&format!("{prefix}{code}"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,14 +138,15 @@ impl IntoIterator for &RuleSelector {
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
match self {
|
||||
RuleSelector::All => RuleSelectorIter::All(Rule::iter()),
|
||||
RuleSelector::Prefix { prefix, .. } => RuleSelectorIter::Prefix(prefix.into_iter()),
|
||||
RuleSelector::Linter(linter) => RuleSelectorIter::Vec(linter.into_iter()),
|
||||
RuleSelector::Prefix { prefix, .. } => RuleSelectorIter::Vec(prefix.into_iter()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum RuleSelectorIter {
|
||||
All(RuleIter),
|
||||
Prefix(std::vec::IntoIter<Rule>),
|
||||
Vec(std::vec::IntoIter<Rule>),
|
||||
}
|
||||
|
||||
impl Iterator for RuleSelectorIter {
|
||||
@@ -133,7 +155,7 @@ impl Iterator for RuleSelectorIter {
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self {
|
||||
RuleSelectorIter::All(iter) => iter.next(),
|
||||
RuleSelectorIter::Prefix(iter) => iter.next(),
|
||||
RuleSelectorIter::Vec(iter) => iter.next(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -160,7 +182,19 @@ impl JsonSchema for RuleSelector {
|
||||
instance_type: Some(InstanceType::String.into()),
|
||||
enum_values: Some(
|
||||
std::iter::once("ALL".to_string())
|
||||
.chain(RuleCodePrefix::iter().map(|s| s.as_ref().to_string()))
|
||||
.chain(
|
||||
RuleCodePrefix::iter()
|
||||
.map(|p| {
|
||||
let prefix = p.linter().common_prefix();
|
||||
let code = p.short_code();
|
||||
format!("{prefix}{code}")
|
||||
})
|
||||
.chain(Linter::iter().filter_map(|l| {
|
||||
let prefix = l.common_prefix();
|
||||
(!prefix.is_empty()).then(|| prefix.to_string())
|
||||
}))
|
||||
.sorted(),
|
||||
)
|
||||
.map(Value::String)
|
||||
.collect(),
|
||||
),
|
||||
@@ -173,7 +207,18 @@ impl RuleSelector {
|
||||
pub(crate) fn specificity(&self) -> Specificity {
|
||||
match self {
|
||||
RuleSelector::All => Specificity::All,
|
||||
RuleSelector::Prefix { prefix, .. } => prefix.specificity(),
|
||||
RuleSelector::Linter(..) => Specificity::Linter,
|
||||
RuleSelector::Prefix { prefix, .. } => {
|
||||
let prefix: &'static str = prefix.short_code();
|
||||
match prefix.len() {
|
||||
1 => Specificity::Code1Char,
|
||||
2 => Specificity::Code2Chars,
|
||||
3 => Specificity::Code3Chars,
|
||||
4 => Specificity::Code4Chars,
|
||||
5 => Specificity::Code5Chars,
|
||||
_ => panic!("RuleSelector::specificity doesn't yet support codes with so many characters"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -188,3 +233,76 @@ pub(crate) enum Specificity {
|
||||
Code4Chars,
|
||||
Code5Chars,
|
||||
}
|
||||
|
||||
mod clap_completion {
|
||||
use clap::builder::{PossibleValue, TypedValueParser, ValueParserFactory};
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use crate::{
|
||||
codes::RuleCodePrefix,
|
||||
registry::{Linter, RuleNamespace},
|
||||
RuleSelector,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct RuleSelectorParser;
|
||||
|
||||
impl ValueParserFactory for RuleSelector {
|
||||
type Parser = RuleSelectorParser;
|
||||
|
||||
fn value_parser() -> Self::Parser {
|
||||
RuleSelectorParser
|
||||
}
|
||||
}
|
||||
|
||||
impl TypedValueParser for RuleSelectorParser {
|
||||
type Value = RuleSelector;
|
||||
|
||||
fn parse_ref(
|
||||
&self,
|
||||
_cmd: &clap::Command,
|
||||
_arg: Option<&clap::Arg>,
|
||||
value: &std::ffi::OsStr,
|
||||
) -> Result<Self::Value, clap::Error> {
|
||||
let value = value
|
||||
.to_str()
|
||||
.ok_or_else(|| clap::Error::new(clap::error::ErrorKind::InvalidUtf8))?;
|
||||
|
||||
value
|
||||
.parse()
|
||||
.map_err(|e| clap::Error::raw(clap::error::ErrorKind::InvalidValue, e))
|
||||
}
|
||||
|
||||
fn possible_values(
|
||||
&self,
|
||||
) -> Option<Box<dyn Iterator<Item = clap::builder::PossibleValue> + '_>> {
|
||||
Some(Box::new(
|
||||
std::iter::once(PossibleValue::new("ALL").help("all rules")).chain(
|
||||
Linter::iter()
|
||||
.filter_map(|l| {
|
||||
let prefix = l.common_prefix();
|
||||
(!prefix.is_empty()).then(|| PossibleValue::new(prefix).help(l.name()))
|
||||
})
|
||||
.chain(RuleCodePrefix::iter().map(|p| {
|
||||
let prefix = p.linter().common_prefix();
|
||||
let code = p.short_code();
|
||||
|
||||
let mut rules_iter = p.into_iter();
|
||||
let rule1 = rules_iter.next();
|
||||
let rule2 = rules_iter.next();
|
||||
|
||||
let value = PossibleValue::new(format!("{prefix}{code}"));
|
||||
|
||||
if rule2.is_none() {
|
||||
let rule1 = rule1.unwrap();
|
||||
let name: &'static str = rule1.into();
|
||||
value.help(name)
|
||||
} else {
|
||||
value
|
||||
}
|
||||
})),
|
||||
),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ mod tests {
|
||||
|
||||
#[test_case(Rule::CommentedOutCode, Path::new("ERA001.py"); "ERA001")]
|
||||
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
|
||||
let snapshot = format!("{}_{}", rule_code.code(), path.to_string_lossy());
|
||||
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
|
||||
let diagnostics = test_path(
|
||||
Path::new("eradicate").join(path).as_path(),
|
||||
&settings::Settings::for_rule(rule_code),
|
||||
|
||||
@@ -55,7 +55,7 @@ pub fn commented_out_code(
|
||||
) -> Option<Diagnostic> {
|
||||
let location = Location::new(start.row(), 0);
|
||||
let end_location = Location::new(end.row() + 1, 0);
|
||||
let line = locator.slice_source_code_range(&Range::new(location, end_location));
|
||||
let line = locator.slice(&Range::new(location, end_location));
|
||||
|
||||
// Verify that the comment is on its own line, and that it contains code.
|
||||
if is_standalone_comment(line) && comment_contains_code(line, &settings.task_tags[..]) {
|
||||
|
||||
@@ -23,7 +23,7 @@ mod tests {
|
||||
#[test_case(Rule::SysVersionCmpStr10, Path::new("YTT302.py"); "YTT302")]
|
||||
#[test_case(Rule::SysVersionSlice1Referenced, Path::new("YTT303.py"); "YTT303")]
|
||||
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
|
||||
let snapshot = format!("{}_{}", rule_code.code(), path.to_string_lossy());
|
||||
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
|
||||
let diagnostics = test_path(
|
||||
Path::new("flake8_2020").join(path).as_path(),
|
||||
&settings::Settings::for_rule(rule_code),
|
||||
|
||||
@@ -10,7 +10,7 @@ use crate::source_code::Locator;
|
||||
/// ANN204
|
||||
pub fn add_return_none_annotation(locator: &Locator, stmt: &Stmt) -> Result<Fix> {
|
||||
let range = Range::from_located(stmt);
|
||||
let contents = locator.slice_source_code_range(&range);
|
||||
let contents = locator.slice(&range);
|
||||
|
||||
// Find the colon (following the `def` keyword).
|
||||
let mut seen_lpar = false;
|
||||
|
||||
@@ -475,9 +475,9 @@ pub fn definition(
|
||||
|
||||
// ANN001, ANN401
|
||||
for arg in args
|
||||
.args
|
||||
.posonlyargs
|
||||
.iter()
|
||||
.chain(args.posonlyargs.iter())
|
||||
.chain(args.args.iter())
|
||||
.chain(args.kwonlyargs.iter())
|
||||
.skip(
|
||||
// If this is a non-static method, skip `cls` or `self`.
|
||||
@@ -581,7 +581,7 @@ pub fn definition(
|
||||
|
||||
// ANN101, ANN102
|
||||
if is_method && !visibility::is_staticmethod(checker, cast::decorator_list(stmt)) {
|
||||
if let Some(arg) = args.args.first() {
|
||||
if let Some(arg) = args.posonlyargs.first().or_else(|| args.args.first()) {
|
||||
if arg.node.annotation.is_none() {
|
||||
if visibility::is_classmethod(checker, cast::decorator_list(stmt)) {
|
||||
if checker.settings.rules.enabled(&Rule::MissingTypeCls) {
|
||||
|
||||
@@ -244,4 +244,15 @@ expression: diagnostics
|
||||
column: 15
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
MissingTypeSelf:
|
||||
name: self
|
||||
location:
|
||||
row: 108
|
||||
column: 12
|
||||
end_location:
|
||||
row: 108
|
||||
column: 16
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ mod tests {
|
||||
#[test_case(Rule::TryExceptPass, Path::new("S110.py"); "S110")]
|
||||
#[test_case(Rule::TryExceptContinue, Path::new("S112.py"); "S112")]
|
||||
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
|
||||
let snapshot = format!("{}_{}", rule_code.code(), path.to_string_lossy());
|
||||
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
|
||||
let diagnostics = test_path(
|
||||
Path::new("flake8_bandit").join(path).as_path(),
|
||||
&Settings::for_rule(rule_code),
|
||||
|
||||
@@ -17,10 +17,7 @@ impl Violation for HashlibInsecureHashFunction {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let HashlibInsecureHashFunction { string } = self;
|
||||
format!(
|
||||
"Probable use of insecure hash functions in `hashlib`: \"{}\"",
|
||||
string.escape_debug()
|
||||
)
|
||||
format!("Probable use of insecure hash functions in `hashlib`: `{string}`")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ mod tests {
|
||||
|
||||
#[test_case(Rule::BlindExcept, Path::new("BLE.py"); "BLE001")]
|
||||
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
|
||||
let snapshot = format!("{}_{}", rule_code.code(), path.to_string_lossy());
|
||||
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
|
||||
let diagnostics = test_path(
|
||||
Path::new("flake8_blind_except").join(path).as_path(),
|
||||
&settings::Settings::for_rule(rule_code),
|
||||
|
||||
@@ -16,7 +16,7 @@ mod tests {
|
||||
#[test_case(Rule::BooleanDefaultValueInFunctionDefinition, Path::new("FBT.py"); "FBT002")]
|
||||
#[test_case(Rule::BooleanPositionalValueInFunctionCall, Path::new("FBT.py"); "FBT003")]
|
||||
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
|
||||
let snapshot = format!("{}_{}", rule_code.code(), path.to_string_lossy());
|
||||
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
|
||||
let diagnostics = test_path(
|
||||
Path::new("flake8_boolean_trap").join(path).as_path(),
|
||||
&settings::Settings::for_rule(rule_code),
|
||||
|
||||
@@ -40,10 +40,11 @@ mod tests {
|
||||
#[test_case(Rule::DuplicateTryBlockException, Path::new("B025.py"); "B025")]
|
||||
#[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::RaiseWithoutFromInsideExcept, Path::new("B904.py"); "B904")]
|
||||
#[test_case(Rule::ZipWithoutExplicitStrict, Path::new("B905.py"); "B905")]
|
||||
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
|
||||
let snapshot = format!("{}_{}", rule_code.code(), path.to_string_lossy());
|
||||
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
|
||||
let diagnostics = test_path(
|
||||
Path::new("flake8_bugbear").join(path).as_path(),
|
||||
&Settings::for_rule(rule_code),
|
||||
|
||||
@@ -3,6 +3,7 @@ use ruff_python::string::is_lower;
|
||||
use rustpython_parser::ast::{ExprKind, Stmt, StmtKind};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::ast::visitor;
|
||||
use crate::ast::visitor::Visitor;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::Diagnostic;
|
||||
@@ -44,15 +45,16 @@ impl<'a> Visitor<'a> for RaiseVisitor {
|
||||
| StmtKind::FunctionDef { .. }
|
||||
| StmtKind::AsyncFunctionDef { .. }
|
||||
| StmtKind::Try { .. } => {}
|
||||
StmtKind::If { body, .. }
|
||||
| StmtKind::While { body, .. }
|
||||
StmtKind::If { body, orelse, .. } => {
|
||||
visitor::walk_body(self, body);
|
||||
visitor::walk_body(self, orelse);
|
||||
}
|
||||
StmtKind::While { body, .. }
|
||||
| StmtKind::With { body, .. }
|
||||
| StmtKind::AsyncWith { body, .. }
|
||||
| StmtKind::For { body, .. }
|
||||
| StmtKind::AsyncFor { body, .. } => {
|
||||
for stmt in body {
|
||||
self.visit_stmt(stmt);
|
||||
}
|
||||
visitor::walk_body(self, body);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@@ -63,8 +65,6 @@ pub fn raise_without_from_inside_except(checker: &mut Checker, body: &[Stmt]) {
|
||||
let mut visitor = RaiseVisitor {
|
||||
diagnostics: vec![],
|
||||
};
|
||||
for stmt in body {
|
||||
visitor.visit_stmt(stmt);
|
||||
}
|
||||
visitor::walk_body(&mut visitor, body);
|
||||
checker.diagnostics.extend(visitor.diagnostics);
|
||||
}
|
||||
|
||||
@@ -36,7 +36,8 @@ pub fn strip_with_multi_characters(checker: &mut Checker, expr: &Expr, func: &Ex
|
||||
return;
|
||||
};
|
||||
|
||||
if value.len() > 1 && value.chars().unique().count() != value.len() {
|
||||
let num_chars = value.chars().count();
|
||||
if num_chars > 1 && num_chars != value.chars().unique().count() {
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
StripWithMultiCharacters,
|
||||
Range::from_located(expr),
|
||||
|
||||
@@ -13,7 +13,7 @@ impl Violation for UnreliableCallableCheck {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!(
|
||||
" Using `hasattr(x, '__call__')` to test if x is callable is unreliable. Use \
|
||||
"Using `hasattr(x, '__call__')` to test if x is callable is unreliable. Use \
|
||||
`callable(x)` for consistent results."
|
||||
)
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ impl Violation for UnusedLoopControlVariable {
|
||||
if matches!(certainty, Certainty::Certain) && rename.is_some() {
|
||||
Some(|UnusedLoopControlVariable { name, rename, .. }| {
|
||||
let rename = rename.as_ref().unwrap();
|
||||
format!("Rename unused `{name}` to `_{rename}`")
|
||||
format!("Rename unused `{name}` to `{rename}`")
|
||||
})
|
||||
} else {
|
||||
None
|
||||
|
||||
@@ -19,7 +19,7 @@ impl Violation for UselessContextlibSuppress {
|
||||
}
|
||||
}
|
||||
|
||||
/// B005
|
||||
/// B022
|
||||
pub fn useless_contextlib_suppress(checker: &mut Checker, expr: &Expr, func: &Expr, args: &[Expr]) {
|
||||
if args.is_empty()
|
||||
&& checker.resolve_call_path(func).map_or(false, |call_path| {
|
||||
|
||||
@@ -16,7 +16,7 @@ impl Violation for UselessExpression {
|
||||
}
|
||||
}
|
||||
|
||||
// B018
|
||||
/// B018
|
||||
pub fn useless_expression(checker: &mut Checker, body: &[Stmt]) {
|
||||
for stmt in body {
|
||||
if let StmtKind::Expr { value } = &stmt.node {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
source: src/rules/flake8_bugbear/mod.rs
|
||||
source: crates/ruff/src/rules/flake8_bugbear/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
@@ -62,4 +62,24 @@ expression: diagnostics
|
||||
column: 18
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
StripWithMultiCharacters: ~
|
||||
location:
|
||||
row: 22
|
||||
column: 0
|
||||
end_location:
|
||||
row: 22
|
||||
column: 13
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
StripWithMultiCharacters: ~
|
||||
location:
|
||||
row: 24
|
||||
column: 0
|
||||
end_location:
|
||||
row: 24
|
||||
column: 35
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user