Compare commits
70 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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?
|
||||
|
||||
137
Cargo.lock
generated
137
Cargo.lock
generated
@@ -378,9 +378,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.1.4"
|
||||
version = "4.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76"
|
||||
checksum = "ec0b0588d44d4d63a87dbd75c136c166bbfd9a86a31cb89e09906521c7d3f5e3"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"clap_derive",
|
||||
@@ -397,7 +397,7 @@ version = "4.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d6540eedc41f8a5a76cf3d8d458057dcdf817be4158a55b5f861f7a5483de75"
|
||||
dependencies = [
|
||||
"clap 4.1.4",
|
||||
"clap 4.1.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -406,7 +406,7 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4160b4a4f72ef58bd766bad27c09e6ef1cc9d82a22f6a0f55d152985a4a48e31"
|
||||
dependencies = [
|
||||
"clap 4.1.4",
|
||||
"clap 4.1.6",
|
||||
"clap_complete",
|
||||
"clap_complete_fig",
|
||||
]
|
||||
@@ -417,7 +417,7 @@ version = "4.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf0c76d8fcf782a1102ccfcd10ca8246e7fdd609c1cd6deddbb96cb638e9bb5c"
|
||||
dependencies = [
|
||||
"clap 4.1.4",
|
||||
"clap 4.1.6",
|
||||
"clap_complete",
|
||||
]
|
||||
|
||||
@@ -762,6 +762,12 @@ version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
|
||||
|
||||
[[package]]
|
||||
name = "drop_bomb"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9bda8e21c04aca2ae33ffc2fd8c23134f3cac46db123ba97bd9d3f3b8a4a85e1"
|
||||
|
||||
[[package]]
|
||||
name = "dyn-clone"
|
||||
version = "1.0.10"
|
||||
@@ -857,9 +863,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.8.0"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499"
|
||||
checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
|
||||
dependencies = [
|
||||
"instant",
|
||||
]
|
||||
@@ -893,10 +899,10 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.246"
|
||||
version = "0.0.247"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.1.4",
|
||||
"clap 4.1.6",
|
||||
"colored",
|
||||
"configparser",
|
||||
"once_cell",
|
||||
@@ -1539,6 +1545,16 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libmimalloc-sys"
|
||||
version = "0.1.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8c7cbf8b89019683667e347572e6d55a7df7ea36b0c4ce69961b0cde67b174"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "link-cplusplus"
|
||||
version = "1.0.8"
|
||||
@@ -1612,7 +1628,7 @@ dependencies = [
|
||||
"ansi_term",
|
||||
"anyhow",
|
||||
"base64 0.20.0",
|
||||
"clap 4.1.4",
|
||||
"clap 4.1.6",
|
||||
"clap_complete",
|
||||
"env_proxy",
|
||||
"gethostname",
|
||||
@@ -1645,6 +1661,15 @@ dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mimalloc"
|
||||
version = "0.1.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9dcb174b18635f7561a0c6c9fc2ce57218ac7523cf72c50af80e2d79ab8f3ba1"
|
||||
dependencies = [
|
||||
"libmimalloc-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
version = "0.3.16"
|
||||
@@ -2421,14 +2446,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.0.246"
|
||||
version = "0.0.247"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bisection",
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"chrono",
|
||||
"clap 4.1.4",
|
||||
"clap 4.1.6",
|
||||
"colored",
|
||||
"console_error_panic_hook",
|
||||
"console_log",
|
||||
@@ -2477,7 +2502,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_cli"
|
||||
version = "0.0.246"
|
||||
version = "0.0.247"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.9.1",
|
||||
"anyhow",
|
||||
@@ -2487,7 +2512,7 @@ dependencies = [
|
||||
"bitflags",
|
||||
"cachedir",
|
||||
"chrono",
|
||||
"clap 4.1.4",
|
||||
"clap 4.1.6",
|
||||
"clap_complete_command",
|
||||
"clearscreen",
|
||||
"colored",
|
||||
@@ -2497,6 +2522,7 @@ dependencies = [
|
||||
"itertools",
|
||||
"log",
|
||||
"mdcat",
|
||||
"mimalloc",
|
||||
"notify",
|
||||
"path-absolutize",
|
||||
"pulldown-cmark",
|
||||
@@ -2511,19 +2537,21 @@ dependencies = [
|
||||
"strum",
|
||||
"syntect",
|
||||
"textwrap",
|
||||
"tikv-jemallocator",
|
||||
"ureq",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff_dev"
|
||||
version = "0.0.246"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.1.4",
|
||||
"clap 4.1.6",
|
||||
"itertools",
|
||||
"libcst",
|
||||
"once_cell",
|
||||
"regex",
|
||||
"ruff",
|
||||
"ruff_cli",
|
||||
"rustpython-common",
|
||||
@@ -2535,9 +2563,23 @@ dependencies = [
|
||||
"textwrap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff_formatter"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"drop_bomb",
|
||||
"insta",
|
||||
"ruff_text_size",
|
||||
"rustc-hash",
|
||||
"schemars",
|
||||
"serde",
|
||||
"tracing",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff_macros"
|
||||
version = "0.0.246"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"proc-macro2",
|
||||
@@ -2548,13 +2590,39 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_python"
|
||||
version = "0.0.246"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff_python_formatter"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.1.6",
|
||||
"insta",
|
||||
"once_cell",
|
||||
"ruff_formatter",
|
||||
"ruff_text_size",
|
||||
"rustc-hash",
|
||||
"rustpython-common",
|
||||
"rustpython-parser",
|
||||
"test-case",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff_text_size"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_test",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-stemmers"
|
||||
version = "1.2.0"
|
||||
@@ -2820,6 +2888,15 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_test"
|
||||
version = "1.0.152"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3611210d2d67e3513204742004d6ac6f589e521861dabb0f649b070eea8bed9e"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_urlencoded"
|
||||
version = "0.7.1"
|
||||
@@ -3156,6 +3233,26 @@ dependencies = [
|
||||
"weezl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tikv-jemalloc-sys"
|
||||
version = "0.5.3+5.3.0-patched"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a678df20055b43e57ef8cddde41cdfda9a3c1a060b67f4c5836dfb1d78543ba8"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tikv-jemallocator"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20612db8a13a6c06d57ec83953694185a367e16945f66565e8028d2c0bd76979"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"tikv-jemalloc-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.45"
|
||||
@@ -3892,9 +3989,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zune-inflate"
|
||||
version = "0.2.42"
|
||||
version = "0.2.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c473377c11c4a3ac6a2758f944cd336678e9c977aa0abf54f6450cf77e902d6d"
|
||||
checksum = "589245df6230839c305984dcc0a8385cc72af1fd223f360ffd5d65efa4216d40"
|
||||
dependencies = [
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
12
Cargo.toml
12
Cargo.toml
@@ -3,9 +3,21 @@ members = ["crates/*"]
|
||||
default-members = ["crates/ruff", "crates/ruff_cli"]
|
||||
|
||||
[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.
|
||||
"""
|
||||
|
||||
263
README.md
263
README.md
@@ -7,7 +7,6 @@
|
||||
[](https://pypi.python.org/pypi/ruff)
|
||||
[](https://pypi.python.org/pypi/ruff)
|
||||
[](https://github.com/charliermarsh/ruff/actions)
|
||||
[](https://info.jetbrains.com/PyCharm-Webinar-February14-2023.html)
|
||||
|
||||
[**Discord**](https://discord.gg/c9MhzV8aU5) | [**Docs**](https://beta.ruff.rs/docs/) | [**Playground**](https://play.ruff.rs/)
|
||||
|
||||
@@ -27,7 +26,6 @@ An extremely fast Python linter, written in Rust.
|
||||
|
||||
* ⚡️ 10-100x faster than existing linters
|
||||
* 🐍 Installable via `pip`
|
||||
* 🤝 Python 3.11 compatibility
|
||||
* 🛠️ `pyproject.toml` support
|
||||
* 📦 Built-in caching, to avoid re-analyzing unchanged files
|
||||
* 🔧 Autofix support, for automatic error correction (e.g., automatically remove unused imports)
|
||||
@@ -49,10 +47,11 @@ Ruff is extremely actively developed and used in major open-source projects like
|
||||
|
||||
* [pandas](https://github.com/pandas-dev/pandas)
|
||||
* [FastAPI](https://github.com/tiangolo/fastapi)
|
||||
* [Transformers (Hugging Face)](https://github.com/huggingface/transformers)
|
||||
* [Apache Airflow](https://github.com/apache/airflow)
|
||||
* [SciPy](https://github.com/scipy/scipy)
|
||||
* [Bokeh](https://github.com/bokeh/bokeh)
|
||||
* [Zulip](https://github.com/zulip/zulip)
|
||||
* [Bokeh](https://github.com/bokeh/bokeh)
|
||||
* [Pydantic](https://github.com/pydantic/pydantic)
|
||||
* [Dagster](https://github.com/dagster-io/dagster)
|
||||
* [Dagger](https://github.com/dagger/dagger)
|
||||
@@ -149,7 +148,9 @@ This README is also available as [documentation](https://beta.ruff.rs/docs/).
|
||||
1. [flake8-pyi (PYI)](#flake8-pyi-pyi)
|
||||
1. [flake8-pytest-style (PT)](#flake8-pytest-style-pt)
|
||||
1. [flake8-quotes (Q)](#flake8-quotes-q)
|
||||
1. [flake8-raise (RSE)](#flake8-raise-rse)
|
||||
1. [flake8-return (RET)](#flake8-return-ret)
|
||||
1. [flake8-self (SLF)](#flake8-self-slf)
|
||||
1. [flake8-simplify (SIM)](#flake8-simplify-sim)
|
||||
1. [flake8-tidy-imports (TID)](#flake8-tidy-imports-tid)
|
||||
1. [flake8-type-checking (TCH)](#flake8-type-checking-tch)
|
||||
@@ -160,14 +161,14 @@ This README is also available as [documentation](https://beta.ruff.rs/docs/).
|
||||
1. [pygrep-hooks (PGH)](#pygrep-hooks-pgh)
|
||||
1. [Pylint (PL)](#pylint-pl)
|
||||
1. [tryceratops (TRY)](#tryceratops-try)
|
||||
1. [flake8-raise (RSE)](#flake8-raise-rse)
|
||||
1. [flake8-self (SLF)](#flake8-self-slf)
|
||||
1. [NumPy-specific rules (NPY)](#numpy-specific-rules-npy)
|
||||
1. [Ruff-specific rules (RUF)](#ruff-specific-rules-ruf)<!-- End auto-generated table of contents. -->
|
||||
1. [Editor Integrations](#editor-integrations)
|
||||
1. [FAQ](#faq)
|
||||
1. [Contributing](#contributing)
|
||||
1. [Support](#support)
|
||||
1. [Reference](#reference)
|
||||
1. [Acknowledgements](#acknowledgements)
|
||||
1. [License](#license)
|
||||
|
||||
## Installation and Usage
|
||||
@@ -232,7 +233,7 @@ Ruff also works with [pre-commit](https://pre-commit.com):
|
||||
```yaml
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: 'v0.0.246'
|
||||
rev: 'v0.0.247'
|
||||
hooks:
|
||||
- id: ruff
|
||||
```
|
||||
@@ -242,7 +243,7 @@ Or, to enable autofix:
|
||||
```yaml
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: 'v0.0.246'
|
||||
rev: 'v0.0.247'
|
||||
hooks:
|
||||
- id: ruff
|
||||
args: [--fix, --exit-non-zero-on-fix]
|
||||
@@ -254,9 +255,11 @@ Or, to enable autofix:
|
||||
|
||||
<!-- Begin section: Configuration -->
|
||||
|
||||
Ruff is configurable both via `pyproject.toml` and the command line. For a full list of configurable
|
||||
Ruff is configurable both via `pyproject.toml`, `ruff.toml`, and the command line. For a full list of configurable
|
||||
options, see the [API reference](#reference).
|
||||
|
||||
### Configure via `pyproject.toml`
|
||||
|
||||
If left unspecified, the default configuration is equivalent to:
|
||||
|
||||
```toml
|
||||
@@ -362,6 +365,8 @@ If you're wondering how to configure Ruff, here are some **recommended guideline
|
||||
* By default, Ruff's autofix is aggressive. If you find that it's too aggressive for your liking,
|
||||
consider turning off autofix for specific rules or categories (see: [FAQ](#ruff-tried-to-fix-something-but-it-broke-my-code-what-should-i-do)).
|
||||
|
||||
### Configure via `ruff.toml`
|
||||
|
||||
As an alternative to `pyproject.toml`, Ruff will also respect a `ruff.toml` file, which implements
|
||||
an equivalent schema (though the `[tool.ruff]` hierarchy can be omitted). For example, the
|
||||
`pyproject.toml` described above would be represented via the following `ruff.toml`:
|
||||
@@ -437,19 +442,34 @@ Arguments:
|
||||
[FILES]... List of files or directories to check
|
||||
|
||||
Options:
|
||||
--fix Attempt to automatically fix lint violations
|
||||
--show-source Show violations with source code
|
||||
--show-fixes Show an enumeration of all autofixed lint violations
|
||||
--diff Avoid writing any fixed files back; instead, output a diff for each changed file to stdout
|
||||
-w, --watch Run in watch mode by re-running whenever files change
|
||||
--fix-only Fix any fixable lint violations, but don't report on leftover violations. Implies `--fix`
|
||||
--format <FORMAT> Output serialization format for violations [env: RUFF_FORMAT=] [possible values: text, json, junit, grouped, github, gitlab, pylint]
|
||||
--config <CONFIG> Path to the `pyproject.toml` or `ruff.toml` file to use for configuration
|
||||
--statistics Show counts for every rule with at least one violation
|
||||
--add-noqa Enable automatic additions of `noqa` directives to failing lines
|
||||
--show-files See the files Ruff will be run against with the current settings
|
||||
--show-settings See the settings Ruff will use to lint a given Python file
|
||||
-h, --help Print help
|
||||
--fix
|
||||
Attempt to automatically fix lint violations
|
||||
--show-source
|
||||
Show violations with source code
|
||||
--show-fixes
|
||||
Show an enumeration of all autofixed lint violations
|
||||
--diff
|
||||
Avoid writing any fixed files back; instead, output a diff for each changed file to stdout
|
||||
-w, --watch
|
||||
Run in watch mode by re-running whenever files change
|
||||
--fix-only
|
||||
Fix any fixable lint violations, but don't report on leftover violations. Implies `--fix`
|
||||
--format <FORMAT>
|
||||
Output serialization format for violations [env: RUFF_FORMAT=] [possible values: text, json, junit, grouped, github, gitlab, pylint]
|
||||
--target-version <TARGET_VERSION>
|
||||
The minimum Python version that should be supported
|
||||
--config <CONFIG>
|
||||
Path to the `pyproject.toml` or `ruff.toml` file to use for configuration
|
||||
--statistics
|
||||
Show counts for every rule with at least one violation
|
||||
--add-noqa
|
||||
Enable automatic additions of `noqa` directives to failing lines
|
||||
--show-files
|
||||
See the files Ruff will be run against with the current settings
|
||||
--show-settings
|
||||
See the settings Ruff will use to lint a given Python file
|
||||
-h, --help
|
||||
Print help
|
||||
|
||||
Rule selection:
|
||||
--select <RULE_CODE>
|
||||
@@ -656,7 +676,7 @@ Ruff supports two command-line flags that alter its exit code behavior:
|
||||
### Autocompletion
|
||||
|
||||
Ruff supports autocompletion for most shells. A shell-specific completion script can be generated
|
||||
by `ruff completion <SHELL>`, where `<SHELL>` is one of `bash`, `elvish`, `fig`, `fish`,
|
||||
by `ruff generate-shell-completion <SHELL>`, where `<SHELL>` is one of `bash`, `elvish`, `fig`, `fish`,
|
||||
`powershell`, or `zsh`.
|
||||
|
||||
The exact steps required to enable autocompletion will vary by shell. For example instructions,
|
||||
@@ -710,13 +730,13 @@ For more, see [Pyflakes](https://pypi.org/project/pyflakes/) on PyPI.
|
||||
| F506 | percent-format-mixed-positional-and-named | `%`-format string has mixed positional and named placeholders | |
|
||||
| F507 | percent-format-positional-count-mismatch | `%`-format string has {wanted} placeholder(s) but {got} substitution(s) | |
|
||||
| F508 | percent-format-star-requires-sequence | `%`-format string `*` specifier requires sequence | |
|
||||
| F509 | percent-format-unsupported-format-character | `%`-format string has unsupported format character '{char}' | |
|
||||
| F509 | percent-format-unsupported-format-character | `%`-format string has unsupported format character `{char}` | |
|
||||
| F521 | string-dot-format-invalid-format | `.format` call has invalid format string: {message} | |
|
||||
| F522 | string-dot-format-extra-named-arguments | `.format` call has unused named argument(s): {message} | 🛠 |
|
||||
| F523 | string-dot-format-extra-positional-arguments | `.format` call has unused arguments at position(s): {message} | |
|
||||
| F524 | string-dot-format-missing-arguments | `.format` call is missing argument(s) for placeholder(s): {message} | |
|
||||
| F525 | string-dot-format-mixing-automatic | `.format` string mixes automatic and manual numbering | |
|
||||
| F541 | [f-string-missing-placeholders](https://github.com/charliermarsh/ruff/blob/main/docs/rules/f-string-missing-placeholders.md) | f-string without any placeholders | 🛠 |
|
||||
| F541 | [f-string-missing-placeholders](https://beta.ruff.rs/docs/rules/f-string-missing-placeholders/) | f-string without any placeholders | 🛠 |
|
||||
| F601 | multi-value-repeated-key-literal | Dictionary key literal `{name}` repeated | 🛠 |
|
||||
| F602 | multi-value-repeated-key-variable | Dictionary key `{name}` repeated | 🛠 |
|
||||
| F621 | expressions-in-star-assignment | Too many expressions in star-unpacking assignment | |
|
||||
@@ -735,7 +755,7 @@ For more, see [Pyflakes](https://pypi.org/project/pyflakes/) on PyPI.
|
||||
| F821 | undefined-name | Undefined name `{name}` | |
|
||||
| F822 | undefined-export | Undefined name `{name}` in `__all__` | |
|
||||
| F823 | undefined-local | Local variable `{name}` referenced before assignment | |
|
||||
| F841 | [unused-variable](https://github.com/charliermarsh/ruff/blob/main/docs/rules/unused-variable.md) | Local variable `{name}` is assigned to but never used | 🛠 |
|
||||
| F841 | [unused-variable](https://beta.ruff.rs/docs/rules/unused-variable/) | Local variable `{name}` is assigned to but never used | 🛠 |
|
||||
| F842 | unused-annotation | Local variable `{name}` is annotated but never used | |
|
||||
| F901 | raise-not-implemented | `raise NotImplemented` should be `raise NotImplementedError` | 🛠 |
|
||||
|
||||
@@ -759,7 +779,7 @@ For more, see [pycodestyle](https://pypi.org/project/pycodestyle/) on PyPI.
|
||||
| E713 | not-in-test | Test for membership should be `not in` | 🛠 |
|
||||
| E714 | not-is-test | Test for object identity should be `is not` | 🛠 |
|
||||
| E721 | type-comparison | Do not compare types, use `isinstance()` | |
|
||||
| E722 | [bare-except](https://github.com/charliermarsh/ruff/blob/main/docs/rules/bare-except.md) | Do not use bare `except` | |
|
||||
| E722 | [bare-except](https://beta.ruff.rs/docs/rules/bare-except/) | Do not use bare `except` | |
|
||||
| E731 | lambda-assignment | Do not assign a `lambda` expression, use a `def` | 🛠 |
|
||||
| E741 | ambiguous-variable-name | Ambiguous variable name: `{name}` | |
|
||||
| E742 | ambiguous-class-name | Ambiguous class name: `{name}` | |
|
||||
@@ -773,7 +793,7 @@ For more, see [pycodestyle](https://pypi.org/project/pycodestyle/) on PyPI.
|
||||
| ---- | ---- | ------- | --- |
|
||||
| W292 | no-new-line-at-end-of-file | No newline at end of file | 🛠 |
|
||||
| W505 | doc-line-too-long | Doc line too long ({length} > {limit} characters) | |
|
||||
| W605 | invalid-escape-sequence | Invalid escape sequence: '\{char}' | 🛠 |
|
||||
| W605 | invalid-escape-sequence | Invalid escape sequence: `\{char}` | 🛠 |
|
||||
|
||||
### mccabe (C90)
|
||||
|
||||
@@ -781,7 +801,7 @@ For more, see [mccabe](https://pypi.org/project/mccabe/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| C901 | [complex-structure](https://github.com/charliermarsh/ruff/blob/main/docs/rules/complex-structure.md) | `{name}` is too complex ({complexity}) | |
|
||||
| C901 | [complex-structure](https://beta.ruff.rs/docs/rules/complex-structure/) | `{name}` is too complex ({complexity}) | |
|
||||
|
||||
### isort (I)
|
||||
|
||||
@@ -789,8 +809,8 @@ For more, see [isort](https://pypi.org/project/isort/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| I001 | [unsorted-imports](https://github.com/charliermarsh/ruff/blob/main/docs/rules/unsorted-imports.md) | Import block is un-sorted or un-formatted | 🛠 |
|
||||
| I002 | [missing-required-import](https://github.com/charliermarsh/ruff/blob/main/docs/rules/missing-required-import.md) | Missing required import: `{name}` | 🛠 |
|
||||
| I001 | [unsorted-imports](https://beta.ruff.rs/docs/rules/unsorted-imports/) | Import block is un-sorted or un-formatted | 🛠 |
|
||||
| I002 | [missing-required-import](https://beta.ruff.rs/docs/rules/missing-required-import/) | Missing required import: `{name}` | 🛠 |
|
||||
|
||||
### pep8-naming (N)
|
||||
|
||||
@@ -844,8 +864,8 @@ For more, see [pydocstyle](https://pypi.org/project/pydocstyle/) on PyPI.
|
||||
| D213 | multi-line-summary-second-line | Multi-line docstring summary should start at the second line | 🛠 |
|
||||
| D214 | section-not-over-indented | Section is over-indented ("{name}") | 🛠 |
|
||||
| D215 | section-underline-not-over-indented | Section underline is over-indented ("{name}") | 🛠 |
|
||||
| D300 | triple-single-quotes | Use """triple double quotes""" | |
|
||||
| D301 | escape-sequence-in-docstring | Use r""" if any backslashes in a docstring | |
|
||||
| D300 | triple-single-quotes | Use triple double quotes `"""` | |
|
||||
| D301 | escape-sequence-in-docstring | Use `r"""` if any backslashes in a docstring | |
|
||||
| D400 | ends-in-period | First line should end with a period | 🛠 |
|
||||
| D401 | non-imperative-mood | First line of docstring should be in imperative mood: "{first_line}" | |
|
||||
| D402 | no-signature | First line should not be the function's signature | |
|
||||
@@ -932,17 +952,17 @@ For more, see [flake8-annotations](https://pypi.org/project/flake8-annotations/)
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| ANN001 | [missing-type-function-argument](https://github.com/charliermarsh/ruff/blob/main/docs/rules/missing-type-function-argument.md) | Missing type annotation for function argument `{name}` | |
|
||||
| ANN002 | [missing-type-args](https://github.com/charliermarsh/ruff/blob/main/docs/rules/missing-type-args.md) | Missing type annotation for `*{name}` | |
|
||||
| ANN003 | [missing-type-kwargs](https://github.com/charliermarsh/ruff/blob/main/docs/rules/missing-type-kwargs.md) | Missing type annotation for `**{name}` | |
|
||||
| ANN101 | [missing-type-self](https://github.com/charliermarsh/ruff/blob/main/docs/rules/missing-type-self.md) | Missing type annotation for `{name}` in method | |
|
||||
| ANN102 | [missing-type-cls](https://github.com/charliermarsh/ruff/blob/main/docs/rules/missing-type-cls.md) | Missing type annotation for `{name}` in classmethod | |
|
||||
| ANN201 | [missing-return-type-public-function](https://github.com/charliermarsh/ruff/blob/main/docs/rules/missing-return-type-public-function.md) | Missing return type annotation for public function `{name}` | |
|
||||
| ANN202 | [missing-return-type-private-function](https://github.com/charliermarsh/ruff/blob/main/docs/rules/missing-return-type-private-function.md) | Missing return type annotation for private function `{name}` | |
|
||||
| ANN204 | [missing-return-type-special-method](https://github.com/charliermarsh/ruff/blob/main/docs/rules/missing-return-type-special-method.md) | Missing return type annotation for special method `{name}` | 🛠 |
|
||||
| ANN205 | [missing-return-type-static-method](https://github.com/charliermarsh/ruff/blob/main/docs/rules/missing-return-type-static-method.md) | Missing return type annotation for staticmethod `{name}` | |
|
||||
| ANN206 | [missing-return-type-class-method](https://github.com/charliermarsh/ruff/blob/main/docs/rules/missing-return-type-class-method.md) | Missing return type annotation for classmethod `{name}` | |
|
||||
| ANN401 | [any-type](https://github.com/charliermarsh/ruff/blob/main/docs/rules/any-type.md) | Dynamically typed expressions (typing.Any) are disallowed in `{name}` | |
|
||||
| ANN001 | [missing-type-function-argument](https://beta.ruff.rs/docs/rules/missing-type-function-argument/) | Missing type annotation for function argument `{name}` | |
|
||||
| ANN002 | [missing-type-args](https://beta.ruff.rs/docs/rules/missing-type-args/) | Missing type annotation for `*{name}` | |
|
||||
| ANN003 | [missing-type-kwargs](https://beta.ruff.rs/docs/rules/missing-type-kwargs/) | Missing type annotation for `**{name}` | |
|
||||
| ANN101 | [missing-type-self](https://beta.ruff.rs/docs/rules/missing-type-self/) | Missing type annotation for `{name}` in method | |
|
||||
| ANN102 | [missing-type-cls](https://beta.ruff.rs/docs/rules/missing-type-cls/) | Missing type annotation for `{name}` in classmethod | |
|
||||
| ANN201 | [missing-return-type-public-function](https://beta.ruff.rs/docs/rules/missing-return-type-public-function/) | Missing return type annotation for public function `{name}` | |
|
||||
| ANN202 | [missing-return-type-private-function](https://beta.ruff.rs/docs/rules/missing-return-type-private-function/) | Missing return type annotation for private function `{name}` | |
|
||||
| ANN204 | [missing-return-type-special-method](https://beta.ruff.rs/docs/rules/missing-return-type-special-method/) | Missing return type annotation for special method `{name}` | 🛠 |
|
||||
| ANN205 | [missing-return-type-static-method](https://beta.ruff.rs/docs/rules/missing-return-type-static-method/) | Missing return type annotation for staticmethod `{name}` | |
|
||||
| ANN206 | [missing-return-type-class-method](https://beta.ruff.rs/docs/rules/missing-return-type-class-method/) | Missing return type annotation for classmethod `{name}` | |
|
||||
| ANN401 | [any-type](https://beta.ruff.rs/docs/rules/any-type/) | Dynamically typed expressions (typing.Any) are disallowed in `{name}` | |
|
||||
|
||||
### flake8-bandit (S)
|
||||
|
||||
@@ -961,12 +981,12 @@ For more, see [flake8-bandit](https://pypi.org/project/flake8-bandit/) on PyPI.
|
||||
| S110 | try-except-pass | `try`-`except`-`pass` detected, consider logging the exception | |
|
||||
| S112 | try-except-continue | `try`-`except`-`continue` detected, consider logging the exception | |
|
||||
| S113 | request-without-timeout | Probable use of requests call with timeout set to `{value}` | |
|
||||
| S324 | hashlib-insecure-hash-function | Probable use of insecure hash functions in `hashlib`: "{}" | |
|
||||
| S324 | hashlib-insecure-hash-function | Probable use of insecure hash functions in `hashlib`: `{string}` | |
|
||||
| S501 | request-with-no-cert-validation | Probable use of `{string}` call with `verify=False` disabling SSL certificate checks | |
|
||||
| S506 | unsafe-yaml-load | Probable use of unsafe loader `{name}` with `yaml.load`. Allows instantiation of arbitrary objects. Consider `yaml.safe_load`. | |
|
||||
| S508 | snmp-insecure-version | The use of SNMPv1 and SNMPv2 is insecure. Use SNMPv3 if able. | |
|
||||
| S509 | snmp-weak-cryptography | You should not use SNMPv3 without encryption. `noAuthNoPriv` & `authNoPriv` is insecure. | |
|
||||
| S608 | [hardcoded-sql-expression](https://github.com/charliermarsh/ruff/blob/main/docs/rules/hardcoded-sql-expression.md) | Possible SQL injection vector through string-based query construction | |
|
||||
| S608 | [hardcoded-sql-expression](https://beta.ruff.rs/docs/rules/hardcoded-sql-expression/) | Possible SQL injection vector through string-based query construction | |
|
||||
| S612 | logging-config-insecure-listen | Use of insecure `logging.config.listen` detected | |
|
||||
| S701 | jinja2-autoescape-false | Using jinja2 templates with `autoescape=False` is dangerous and can lead to XSS. Ensure `autoescape=True` or use the `select_autoescape` function. | |
|
||||
|
||||
@@ -1009,7 +1029,7 @@ For more, see [flake8-bugbear](https://pypi.org/project/flake8-bugbear/) on PyPI
|
||||
| B014 | duplicate-handler-exception | Exception handler with duplicate exception: `{name}` | 🛠 |
|
||||
| B015 | useless-comparison | Pointless comparison. This comparison does nothing but waste CPU instructions. Either prepend `assert` or remove it. | |
|
||||
| B016 | cannot-raise-literal | Cannot raise a literal. Did you intend to return it or raise an Exception? | |
|
||||
| B017 | [assert-raises-exception](https://github.com/charliermarsh/ruff/blob/main/docs/rules/assert-raises-exception.md) | `assertRaises(Exception)` should be considered evil | |
|
||||
| B017 | [assert-raises-exception](https://beta.ruff.rs/docs/rules/assert-raises-exception/) | `assertRaises(Exception)` should be considered evil | |
|
||||
| B018 | useless-expression | Found useless expression. Either assign it to a variable or remove it. | |
|
||||
| B019 | cached-instance-method | Use of `functools.lru_cache` or `functools.cache` on methods can lead to memory leaks | |
|
||||
| B020 | loop-variable-overrides-iterator | Loop control variable `{name}` overrides iterable it iterates | |
|
||||
@@ -1029,9 +1049,9 @@ For more, see [flake8-builtins](https://pypi.org/project/flake8-builtins/) on Py
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| A001 | builtin-variable-shadowing | Variable `{name}` is shadowing a python builtin | |
|
||||
| A002 | builtin-argument-shadowing | Argument `{name}` is shadowing a python builtin | |
|
||||
| A003 | builtin-attribute-shadowing | Class attribute `{name}` is shadowing a python builtin | |
|
||||
| A001 | [builtin-variable-shadowing](https://beta.ruff.rs/docs/rules/builtin-variable-shadowing/) | Variable `{name}` is shadowing a python builtin | |
|
||||
| A002 | [builtin-argument-shadowing](https://beta.ruff.rs/docs/rules/builtin-argument-shadowing/) | Argument `{name}` is shadowing a python builtin | |
|
||||
| A003 | [builtin-attribute-shadowing](https://beta.ruff.rs/docs/rules/builtin-attribute-shadowing/) | Class attribute `{name}` is shadowing a python builtin | |
|
||||
|
||||
### flake8-commas (COM)
|
||||
|
||||
@@ -1049,9 +1069,9 @@ For more, see [flake8-comprehensions](https://pypi.org/project/flake8-comprehens
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| C400 | [unnecessary-generator-list](https://github.com/charliermarsh/ruff/blob/main/docs/rules/unnecessary-generator-list.md) | Unnecessary generator (rewrite as a `list` comprehension) | 🛠 |
|
||||
| C401 | [unnecessary-generator-set](https://github.com/charliermarsh/ruff/blob/main/docs/rules/unnecessary-generator-set.md) | Unnecessary generator (rewrite as a `set` comprehension) | 🛠 |
|
||||
| C402 | [unnecessary-generator-dict](https://github.com/charliermarsh/ruff/blob/main/docs/rules/unnecessary-generator-dict.md) | Unnecessary generator (rewrite as a `dict` comprehension) | 🛠 |
|
||||
| C400 | [unnecessary-generator-list](https://beta.ruff.rs/docs/rules/unnecessary-generator-list/) | Unnecessary generator (rewrite as a `list` comprehension) | 🛠 |
|
||||
| C401 | [unnecessary-generator-set](https://beta.ruff.rs/docs/rules/unnecessary-generator-set/) | Unnecessary generator (rewrite as a `set` comprehension) | 🛠 |
|
||||
| C402 | [unnecessary-generator-dict](https://beta.ruff.rs/docs/rules/unnecessary-generator-dict/) | Unnecessary generator (rewrite as a `dict` comprehension) | 🛠 |
|
||||
| C403 | unnecessary-list-comprehension-set | Unnecessary `list` comprehension (rewrite as a `set` comprehension) | 🛠 |
|
||||
| C404 | unnecessary-list-comprehension-dict | Unnecessary `list` comprehension (rewrite as a `dict` comprehension) | 🛠 |
|
||||
| C405 | unnecessary-literal-set | Unnecessary `{obj_type}` literal (rewrite as a `set` literal) | 🛠 |
|
||||
@@ -1060,11 +1080,11 @@ For more, see [flake8-comprehensions](https://pypi.org/project/flake8-comprehens
|
||||
| C409 | unnecessary-literal-within-tuple-call | Unnecessary `{literal}` literal passed to `tuple()` (rewrite as a `tuple` literal) | 🛠 |
|
||||
| C410 | unnecessary-literal-within-list-call | Unnecessary `{literal}` literal passed to `list()` (remove the outer call to `list()`) | 🛠 |
|
||||
| C411 | unnecessary-list-call | Unnecessary `list` call (remove the outer call to `list()`) | 🛠 |
|
||||
| C413 | [unnecessary-call-around-sorted](https://github.com/charliermarsh/ruff/blob/main/docs/rules/unnecessary-call-around-sorted.md) | Unnecessary `{func}` call around `sorted()` | 🛠 |
|
||||
| C414 | [unnecessary-double-cast-or-process](https://github.com/charliermarsh/ruff/blob/main/docs/rules/unnecessary-double-cast-or-process.md) | Unnecessary `{inner}` call within `{outer}()` | 🛠 |
|
||||
| C413 | [unnecessary-call-around-sorted](https://beta.ruff.rs/docs/rules/unnecessary-call-around-sorted/) | Unnecessary `{func}` call around `sorted()` | 🛠 |
|
||||
| C414 | [unnecessary-double-cast-or-process](https://beta.ruff.rs/docs/rules/unnecessary-double-cast-or-process/) | Unnecessary `{inner}` call within `{outer}()` | 🛠 |
|
||||
| C415 | unnecessary-subscript-reversal | Unnecessary subscript reversal of iterable within `{func}()` | |
|
||||
| C416 | unnecessary-comprehension | Unnecessary `{obj_type}` comprehension (rewrite using `{obj_type}()`) | 🛠 |
|
||||
| C417 | [unnecessary-map](https://github.com/charliermarsh/ruff/blob/main/docs/rules/unnecessary-map.md) | Unnecessary `map` usage (rewrite using a generator expression) | 🛠 |
|
||||
| C417 | [unnecessary-map](https://beta.ruff.rs/docs/rules/unnecessary-map/) | Unnecessary `map` usage (rewrite using a generator expression) | 🛠 |
|
||||
|
||||
### flake8-datetimez (DTZ)
|
||||
|
||||
@@ -1096,9 +1116,9 @@ For more, see [flake8-django](https://pypi.org/project/flake8-django/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| DJ001 | [model-string-field-nullable](https://github.com/charliermarsh/ruff/blob/main/docs/rules/model-string-field-nullable.md) | Avoid using `null=True` on string-based fields such as {field_name} | |
|
||||
| DJ008 | [model-dunder-str](https://github.com/charliermarsh/ruff/blob/main/docs/rules/model-dunder-str.md) | Model does not define `__str__` method | |
|
||||
| DJ013 | [receiver-decorator-checker](https://github.com/charliermarsh/ruff/blob/main/docs/rules/receiver-decorator-checker.md) | `@receiver` decorator must be on top of all the other decorators | |
|
||||
| DJ001 | [nullable-model-string-field](https://beta.ruff.rs/docs/rules/nullable-model-string-field/) | Avoid using `null=True` on string-based fields such as {field_name} | |
|
||||
| DJ008 | [model-without-dunder-str](https://beta.ruff.rs/docs/rules/model-without-dunder-str/) | Model does not define `__str__` method | |
|
||||
| DJ013 | [non-leading-receiver-decorator](https://beta.ruff.rs/docs/rules/non-leading-receiver-decorator/) | `@receiver` decorator must be on top of all the other decorators | |
|
||||
|
||||
### flake8-errmsg (EM)
|
||||
|
||||
@@ -1106,9 +1126,9 @@ For more, see [flake8-errmsg](https://pypi.org/project/flake8-errmsg/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| EM101 | raw-string-in-exception | Exception must not use a string literal, assign to variable first | |
|
||||
| EM102 | f-string-in-exception | Exception must not use an f-string literal, assign to variable first | |
|
||||
| EM103 | dot-format-in-exception | Exception must not use a `.format()` string directly, assign to variable first | |
|
||||
| EM101 | [raw-string-in-exception](https://beta.ruff.rs/docs/rules/raw-string-in-exception/) | Exception must not use a string literal, assign to variable first | |
|
||||
| EM102 | [f-string-in-exception](https://beta.ruff.rs/docs/rules/f-string-in-exception/) | Exception must not use an f-string literal, assign to variable first | |
|
||||
| EM103 | [dot-format-in-exception](https://beta.ruff.rs/docs/rules/dot-format-in-exception/) | Exception must not use a `.format()` string directly, assign to variable first | |
|
||||
|
||||
### flake8-executable (EXE)
|
||||
|
||||
@@ -1118,7 +1138,7 @@ For more, see [flake8-executable](https://pypi.org/project/flake8-executable/) o
|
||||
| ---- | ---- | ------- | --- |
|
||||
| EXE001 | shebang-not-executable | Shebang is present but file is not executable | |
|
||||
| EXE002 | shebang-missing-executable-file | The file is executable but no shebang is present | |
|
||||
| EXE003 | shebang-python | Shebang should contain "python" | |
|
||||
| EXE003 | shebang-python | Shebang should contain `python` | |
|
||||
| EXE004 | shebang-whitespace | Avoid whitespace before shebang | 🛠 |
|
||||
| EXE005 | shebang-newline | Shebang should be at the beginning of the file | |
|
||||
|
||||
@@ -1138,7 +1158,7 @@ For more, see [flake8-import-conventions](https://github.com/joaopalmeiro/flake8
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| ICN001 | [unconventional-import-alias](https://github.com/charliermarsh/ruff/blob/main/docs/rules/unconventional-import-alias.md) | `{name}` should be imported as `{asname}` | |
|
||||
| ICN001 | [unconventional-import-alias](https://beta.ruff.rs/docs/rules/unconventional-import-alias/) | `{name}` should be imported as `{asname}` | |
|
||||
|
||||
### flake8-logging-format (G)
|
||||
|
||||
@@ -1161,7 +1181,7 @@ For more, see [flake8-no-pep420](https://pypi.org/project/flake8-no-pep420/) on
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| INP001 | [implicit-namespace-package](https://github.com/charliermarsh/ruff/blob/main/docs/rules/implicit-namespace-package.md) | File `{filename}` is part of an implicit namespace package. Add an `__init__.py`. | |
|
||||
| INP001 | [implicit-namespace-package](https://beta.ruff.rs/docs/rules/implicit-namespace-package/) | File `{filename}` is part of an implicit namespace package. Add an `__init__.py`. | |
|
||||
|
||||
### flake8-pie (PIE)
|
||||
|
||||
@@ -1192,9 +1212,9 @@ For more, see [flake8-pyi](https://pypi.org/project/flake8-pyi/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| PYI001 | [prefix-type-params](https://github.com/charliermarsh/ruff/blob/main/docs/rules/prefix-type-params.md) | Name of private `{kind}` must start with _ | |
|
||||
| PYI007 | [unrecognized-platform-check](https://github.com/charliermarsh/ruff/blob/main/docs/rules/unrecognized-platform-check.md) | Unrecognized sys.platform check | |
|
||||
| PYI008 | [unrecognized-platform-name](https://github.com/charliermarsh/ruff/blob/main/docs/rules/unrecognized-platform-name.md) | Unrecognized platform `{platform}` | |
|
||||
| PYI001 | [prefix-type-params](https://beta.ruff.rs/docs/rules/prefix-type-params/) | Name of private `{kind}` must start with `_` | |
|
||||
| PYI007 | [unrecognized-platform-check](https://beta.ruff.rs/docs/rules/unrecognized-platform-check/) | Unrecognized `sys.platform` check | |
|
||||
| PYI008 | [unrecognized-platform-name](https://beta.ruff.rs/docs/rules/unrecognized-platform-name/) | Unrecognized platform `{platform}` | |
|
||||
|
||||
### flake8-pytest-style (PT)
|
||||
|
||||
@@ -1234,10 +1254,18 @@ For more, see [flake8-quotes](https://pypi.org/project/flake8-quotes/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| Q000 | [bad-quotes-inline-string](https://github.com/charliermarsh/ruff/blob/main/docs/rules/bad-quotes-inline-string.md) | Double quotes found but single quotes preferred | 🛠 |
|
||||
| Q001 | [bad-quotes-multiline-string](https://github.com/charliermarsh/ruff/blob/main/docs/rules/bad-quotes-multiline-string.md) | Double quote multiline found but single quotes preferred | 🛠 |
|
||||
| Q002 | [bad-quotes-docstring](https://github.com/charliermarsh/ruff/blob/main/docs/rules/bad-quotes-docstring.md) | Double quote docstring found but single quotes preferred | 🛠 |
|
||||
| Q003 | [avoidable-escaped-quote](https://github.com/charliermarsh/ruff/blob/main/docs/rules/avoidable-escaped-quote.md) | Change outer quotes to avoid escaping inner quotes | 🛠 |
|
||||
| Q000 | [bad-quotes-inline-string](https://beta.ruff.rs/docs/rules/bad-quotes-inline-string/) | Double quotes found but single quotes preferred | 🛠 |
|
||||
| Q001 | [bad-quotes-multiline-string](https://beta.ruff.rs/docs/rules/bad-quotes-multiline-string/) | Double quote multiline found but single quotes preferred | 🛠 |
|
||||
| Q002 | [bad-quotes-docstring](https://beta.ruff.rs/docs/rules/bad-quotes-docstring/) | Double quote docstring found but single quotes preferred | 🛠 |
|
||||
| Q003 | [avoidable-escaped-quote](https://beta.ruff.rs/docs/rules/avoidable-escaped-quote/) | Change outer quotes to avoid escaping inner quotes | 🛠 |
|
||||
|
||||
### flake8-raise (RSE)
|
||||
|
||||
For more, see [flake8-raise](https://pypi.org/project/flake8-raise/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| RSE102 | unnecessary-paren-on-raise-exception | Unnecessary parentheses on raised exception | 🛠 |
|
||||
|
||||
### flake8-return (RET)
|
||||
|
||||
@@ -1254,6 +1282,14 @@ For more, see [flake8-return](https://pypi.org/project/flake8-return/) on PyPI.
|
||||
| RET507 | superfluous-else-continue | Unnecessary `{branch}` after `continue` statement | |
|
||||
| RET508 | superfluous-else-break | Unnecessary `{branch}` after `break` statement | |
|
||||
|
||||
### flake8-self (SLF)
|
||||
|
||||
For more, see [flake8-self](https://pypi.org/project/flake8-self/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| SLF001 | [private-member-access](https://beta.ruff.rs/docs/rules/private-member-access/) | Private member accessed: `{access}` | |
|
||||
|
||||
### flake8-simplify (SIM)
|
||||
|
||||
For more, see [flake8-simplify](https://pypi.org/project/flake8-simplify/) on PyPI.
|
||||
@@ -1270,7 +1306,7 @@ For more, see [flake8-simplify](https://pypi.org/project/flake8-simplify/) on Py
|
||||
| SIM110 | convert-loop-to-any | Use `{any}` instead of `for` loop | 🛠 |
|
||||
| SIM111 | convert-loop-to-all | Use `{all}` instead of `for` loop | 🛠 |
|
||||
| SIM112 | use-capital-environment-variables | Use capitalized environment variable `{expected}` instead of `{original}` | 🛠 |
|
||||
| SIM114 | [if-with-same-arms](https://github.com/charliermarsh/ruff/blob/main/docs/rules/if-with-same-arms.md) | Combine `if` branches using logical `or` operator | |
|
||||
| SIM114 | [if-with-same-arms](https://beta.ruff.rs/docs/rules/if-with-same-arms/) | Combine `if` branches using logical `or` operator | |
|
||||
| SIM115 | open-file-with-context-handler | Use context handler for opening files | |
|
||||
| SIM117 | multiple-with-statements | Use a single `with` statement with multiple contexts instead of nested `with` statements | 🛠 |
|
||||
| SIM118 | key-in-dict | Use `{key} in {dict}` instead of `{key} in {dict}.keys()` | 🛠 |
|
||||
@@ -1293,8 +1329,8 @@ For more, see [flake8-tidy-imports](https://pypi.org/project/flake8-tidy-imports
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| TID251 | [banned-api](https://github.com/charliermarsh/ruff/blob/main/docs/rules/banned-api.md) | `{name}` is banned: {message} | |
|
||||
| TID252 | [relative-imports](https://github.com/charliermarsh/ruff/blob/main/docs/rules/relative-imports.md) | Relative imports from parent modules are banned | 🛠 |
|
||||
| TID251 | [banned-api](https://beta.ruff.rs/docs/rules/banned-api/) | `{name}` is banned: {message} | |
|
||||
| TID252 | [relative-imports](https://beta.ruff.rs/docs/rules/relative-imports/) | Relative imports from parent modules are banned | 🛠 |
|
||||
|
||||
### flake8-type-checking (TCH)
|
||||
|
||||
@@ -1358,7 +1394,7 @@ For more, see [eradicate](https://pypi.org/project/eradicate/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| ERA001 | [commented-out-code](https://github.com/charliermarsh/ruff/blob/main/docs/rules/commented-out-code.md) | Found commented-out code | 🛠 |
|
||||
| ERA001 | [commented-out-code](https://beta.ruff.rs/docs/rules/commented-out-code/) | Found commented-out code | 🛠 |
|
||||
|
||||
### pandas-vet (PD)
|
||||
|
||||
@@ -1366,7 +1402,7 @@ For more, see [pandas-vet](https://pypi.org/project/pandas-vet/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| PD002 | [use-of-inplace-argument](https://github.com/charliermarsh/ruff/blob/main/docs/rules/use-of-inplace-argument.md) | `inplace=True` should be avoided; it has inconsistent behavior | 🛠 |
|
||||
| PD002 | [use-of-inplace-argument](https://beta.ruff.rs/docs/rules/use-of-inplace-argument/) | `inplace=True` should be avoided; it has inconsistent behavior | 🛠 |
|
||||
| PD003 | use-of-dot-is-null | `.isna` is preferred to `.isnull`; functionality is equivalent | |
|
||||
| PD004 | use-of-dot-not-null | `.notna` is preferred to `.notnull`; functionality is equivalent | |
|
||||
| PD007 | use-of-dot-ix | `.ix` is deprecated; use more explicit `.loc` or `.iloc` | |
|
||||
@@ -1405,13 +1441,13 @@ For more, see [Pylint](https://pypi.org/project/pylint/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| PLE0100 | [yield-in-init](https://github.com/charliermarsh/ruff/blob/main/docs/rules/yield-in-init.md) | `__init__` method is a generator | |
|
||||
| PLE0100 | [yield-in-init](https://beta.ruff.rs/docs/rules/yield-in-init/) | `__init__` method is a generator | |
|
||||
| PLE0117 | nonlocal-without-binding | Nonlocal name `{name}` found without binding | |
|
||||
| PLE0118 | used-prior-global-declaration | Name `{name}` is used prior to global declaration on line {line} | |
|
||||
| PLE0604 | invalid-all-object | Invalid object in `__all__`, must contain only strings | |
|
||||
| PLE0605 | invalid-all-format | Invalid format for `__all__`, must be `tuple` or `list` | |
|
||||
| PLE1142 | await-outside-async | `await` should be used within an async function | |
|
||||
| PLE1307 | [bad-string-format-type](https://github.com/charliermarsh/ruff/blob/main/docs/rules/bad-string-format-type.md) | Format type does not match argument type | |
|
||||
| PLE1307 | [bad-string-format-type](https://beta.ruff.rs/docs/rules/bad-string-format-type/) | Format type does not match argument type | |
|
||||
| PLE1310 | bad-str-strip-call | String `{strip}` call contains duplicate characters (did you mean `{removal}`?) | |
|
||||
| PLE2502 | bidirectional-unicode | Contains control characters that can permit obfuscated code | |
|
||||
|
||||
@@ -1434,7 +1470,7 @@ For more, see [Pylint](https://pypi.org/project/pylint/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| PLW0120 | useless-else-on-loop | Else clause on loop without a break statement, remove the else and de-indent all the code inside it | |
|
||||
| PLW0120 | useless-else-on-loop | `else` clause on loop without a `break` statement; remove the `else` and de-indent all the code inside it | |
|
||||
| PLW0602 | global-variable-not-assigned | Using global for `{name}` but no assignment is done | |
|
||||
|
||||
### tryceratops (TRY)
|
||||
@@ -1443,41 +1479,32 @@ For more, see [tryceratops](https://pypi.org/project/tryceratops/1.1.0/) on PyPI
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| TRY002 | [raise-vanilla-class](https://github.com/charliermarsh/ruff/blob/main/docs/rules/raise-vanilla-class.md) | Create your own exception | |
|
||||
| TRY002 | [raise-vanilla-class](https://beta.ruff.rs/docs/rules/raise-vanilla-class/) | Create your own exception | |
|
||||
| TRY003 | raise-vanilla-args | Avoid specifying long messages outside the exception class | |
|
||||
| TRY004 | prefer-type-error | Prefer `TypeError` exception for invalid type | 🛠 |
|
||||
| TRY004 | prefer-type-error | Prefer `TypeError` exception for invalid type | |
|
||||
| TRY200 | reraise-no-cause | Use `raise from` to specify exception cause | |
|
||||
| TRY201 | verbose-raise | Use `raise` without specifying exception name | |
|
||||
| TRY300 | try-consider-else | Consider moving this statement to an `else` block | |
|
||||
| TRY301 | raise-within-try | Abstract `raise` to an inner function | |
|
||||
| TRY400 | error-instead-of-exception | Use `logging.exception` instead of `logging.error` | |
|
||||
|
||||
### flake8-raise (RSE)
|
||||
|
||||
For more, see [flake8-raise](https://pypi.org/project/flake8-raise/) on PyPI.
|
||||
### NumPy-specific rules (NPY)
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| RSE102 | unnecessary-paren-on-raise-exception | Unnecessary parentheses on raised exception | 🛠 |
|
||||
|
||||
### flake8-self (SLF)
|
||||
|
||||
For more, see [flake8-self](https://pypi.org/project/flake8-self/) on PyPI.
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| SLF001 | private-member-access | Private member accessed: `{access}` | |
|
||||
| NPY001 | [numpy-deprecated-type-alias](https://beta.ruff.rs/docs/rules/numpy-deprecated-type-alias/) | Type alias `np.{type_name}` is deprecated, replace with builtin type | 🛠 |
|
||||
|
||||
### Ruff-specific rules (RUF)
|
||||
|
||||
| Code | Name | Message | Fix |
|
||||
| ---- | ---- | ------- | --- |
|
||||
| RUF001 | ambiguous-unicode-character-string | String contains ambiguous unicode character '{confusable}' (did you mean '{representant}'?) | 🛠 |
|
||||
| RUF002 | ambiguous-unicode-character-docstring | Docstring contains ambiguous unicode character '{confusable}' (did you mean '{representant}'?) | 🛠 |
|
||||
| RUF003 | ambiguous-unicode-character-comment | Comment contains ambiguous unicode character '{confusable}' (did you mean '{representant}'?) | 🛠 |
|
||||
| RUF001 | ambiguous-unicode-character-string | String contains ambiguous unicode character `{confusable}` (did you mean `{representant}`?) | 🛠 |
|
||||
| RUF002 | ambiguous-unicode-character-docstring | Docstring contains ambiguous unicode character `{confusable}` (did you mean `{representant}`?) | 🛠 |
|
||||
| RUF003 | ambiguous-unicode-character-comment | Comment contains ambiguous unicode character `{confusable}` (did you mean `{representant}`?) | 🛠 |
|
||||
| RUF004 | keyword-argument-before-star-argument | Keyword argument `{name}` must come after starred arguments | |
|
||||
| RUF005 | unpack-instead-of-concatenating-to-collection-literal | Consider `{expr}` instead of concatenation | 🛠 |
|
||||
| RUF100 | unused-noqa | Unused blanket `noqa` directive | 🛠 |
|
||||
| RUF006 | [asyncio-dangling-task](https://beta.ruff.rs/docs/rules/asyncio-dangling-task/) | Store a reference to the return value of `asyncio.create_task` | |
|
||||
| RUF100 | unused-noqa | Unused `noqa` directive | 🛠 |
|
||||
|
||||
<!-- End auto-generated sections. -->
|
||||
|
||||
@@ -1880,6 +1907,22 @@ implemented in [pyupgrade](https://pypi.org/project/pyupgrade/) ([#827](https://
|
||||
|
||||
If you're looking to use Ruff, but rely on an unsupported Flake8 plugin, feel free to file an Issue.
|
||||
|
||||
### What versions of Python does Ruff support?
|
||||
|
||||
Ruff can lint code for any Python version from 3.7 onwards. However, Ruff lacks support for a few
|
||||
language features that were introduced in Python 3.10 and later. Specifically, Ruff does not
|
||||
support:
|
||||
|
||||
- "Structural Pattern Matching" ([PEP 622](https://peps.python.org/pep-0622/)), introduced in Python 3.10.
|
||||
- "Exception Groups and except* ([PEP 654](https://www.python.org/dev/peps/pep-0654/)), introduced in Python 3.11.
|
||||
|
||||
Support for these features is planned.
|
||||
|
||||
Ruff does not support Python 2. Ruff _may_ run on pre-Python 3.7 code, although such versions
|
||||
are not officially supported (e.g., Ruff does _not_ respect type comments).
|
||||
|
||||
Ruff is installable under any Python version from 3.7 onwards.
|
||||
|
||||
### Do I need to install Rust to use Ruff?
|
||||
|
||||
Nope! Ruff is available as [`ruff`](https://pypi.org/project/ruff/) on PyPI:
|
||||
@@ -4010,6 +4053,32 @@ keep-runtime-typing = true
|
||||
|
||||
<!-- End section: Settings -->
|
||||
|
||||
<!-- Begin section: Acknowledgements -->
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
Ruff's linter draws on both the APIs and implementation details of many other
|
||||
tools in the Python ecosystem, especially [Flake8](https://github.com/PyCQA/flake8), [Pyflakes](https://github.com/PyCQA/pyflakes),
|
||||
[pycodestyle](https://github.com/PyCQA/pycodestyle), [pydocstyle](https://github.com/PyCQA/pydocstyle),
|
||||
[pyupgrade](https://github.com/asottile/pyupgrade), and [isort](https://github.com/PyCQA/isort).
|
||||
|
||||
In some cases, Ruff includes a "direct" Rust port of the corresponding tool.
|
||||
We're grateful to the maintainers of these tools for their work, and for all
|
||||
the value they've provided to the Python community.
|
||||
|
||||
Ruff's autoformatter is built on a fork of Rome's [`rome_formatter`](https://github.com/rome/tools/tree/main/crates/rome_formatter),
|
||||
and again draws on both the APIs and implementation details of [Rome](https://github.com/rome/tools),
|
||||
[Prettier](https://github.com/prettier/prettier), and [Black](https://github.com/psf/black).
|
||||
|
||||
Ruff is also influenced by a number of tools outside the Python ecosystem, like
|
||||
[Clippy](https://github.com/rust-lang/rust-clippy) and [ESLint](https://github.com/eslint/eslint).
|
||||
|
||||
Ruff is the beneficiary of a large number of [contributors](https://github.com/charliermarsh/ruff/graphs/contributors).
|
||||
|
||||
Ruff is released under the MIT license.
|
||||
|
||||
<!-- End section: Acknowledgements -->
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
[files]
|
||||
extend-exclude = ["snapshots"]
|
||||
extend-exclude = ["snapshots", "black"]
|
||||
|
||||
[default.extend-words]
|
||||
trivias = "trivias"
|
||||
hel = "hel"
|
||||
|
||||
7
clippy.toml
Normal file
7
clippy.toml
Normal file
@@ -0,0 +1,7 @@
|
||||
doc-valid-idents = [
|
||||
"StackOverflow",
|
||||
"CodeQL",
|
||||
"IPython",
|
||||
"NumPy",
|
||||
"..",
|
||||
]
|
||||
@@ -1,19 +1,19 @@
|
||||
[package]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.0.246"
|
||||
version = "0.0.247"
|
||||
edition = "2021"
|
||||
|
||||
[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,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff"
|
||||
version = "0.0.246"
|
||||
version = "0.0.247"
|
||||
authors = ["Charlie Marsh <charlie.r.marsh@gmail.com>"]
|
||||
edition = "2021"
|
||||
rust-version = "1.65.0"
|
||||
@@ -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,9 @@ 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
|
||||
|
||||
from somewhere import other_type, strip
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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):
|
||||
@@ -61,3 +68,4 @@ 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
|
||||
|
||||
@@ -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,7 @@
|
||||
from typing import TYPE_CHECKING, Any, ClassVar
|
||||
|
||||
import attrs
|
||||
|
||||
from ..protocol import commands, definitions, responses
|
||||
from ..server import example
|
||||
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")
|
||||
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)
|
||||
52
crates/ruff/resources/test/fixtures/ruff/RUF006.py
vendored
Normal file
52
crates/ruff/resources/test/fixtures/ruff/RUF006.py
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
import asyncio
|
||||
|
||||
|
||||
# Error
|
||||
def f():
|
||||
asyncio.create_task(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():
|
||||
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()))
|
||||
@@ -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
|
||||
|
||||
@@ -38,8 +38,8 @@ use crate::rules::{
|
||||
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 +50,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> {
|
||||
@@ -84,8 +85,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>)>,
|
||||
@@ -464,14 +465,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) =
|
||||
@@ -780,15 +783,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);
|
||||
}
|
||||
@@ -1317,8 +1320,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 +1560,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
|
||||
@@ -1797,6 +1795,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 +2072,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 +2147,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 +2216,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);
|
||||
}
|
||||
@@ -3188,7 +3199,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 +4504,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 +4525,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 +4536,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 +4552,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 +5228,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()),
|
||||
));
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ 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};
|
||||
@@ -20,7 +21,7 @@ pub fn check_noqa(
|
||||
settings: &Settings,
|
||||
autofix: flags::Autofix,
|
||||
) {
|
||||
let mut noqa_directives: IntMap<usize, (Directive, Vec<&str>)> = IntMap::default();
|
||||
let mut noqa_directives: IntMap<usize, (Directive, Vec<NoqaCode>)> = IntMap::default();
|
||||
let mut ignored = vec![];
|
||||
|
||||
let enforce_noqa = settings.rules.enabled(&Rule::UnusedNOQA);
|
||||
@@ -55,13 +56,13 @@ pub fn check_noqa(
|
||||
});
|
||||
match noqa {
|
||||
(Directive::All(..), matches) => {
|
||||
matches.push(diagnostic.kind.rule().code());
|
||||
matches.push(diagnostic.kind.rule().noqa_code());
|
||||
ignored.push(index);
|
||||
continue;
|
||||
}
|
||||
(Directive::Codes(.., codes), matches) => {
|
||||
if noqa::includes(diagnostic.kind.rule(), codes) {
|
||||
matches.push(diagnostic.kind.rule().code());
|
||||
matches.push(diagnostic.kind.rule().noqa_code());
|
||||
ignored.push(index);
|
||||
continue;
|
||||
}
|
||||
@@ -82,12 +83,12 @@ 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());
|
||||
matches.push(diagnostic.kind.rule().noqa_code());
|
||||
ignored.push(index);
|
||||
}
|
||||
(Directive::Codes(.., codes), matches) => {
|
||||
if noqa::includes(diagnostic.kind.rule(), codes) {
|
||||
matches.push(diagnostic.kind.rule().code());
|
||||
matches.push(diagnostic.kind.rule().noqa_code());
|
||||
ignored.push(index);
|
||||
}
|
||||
}
|
||||
@@ -128,12 +129,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) {
|
||||
|
||||
609
crates/ruff/src/codes.rs
Normal file
609
crates/ruff/src/codes.rs
Normal file
@@ -0,0 +1,609 @@
|
||||
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, "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::ConvertLoopToAny,
|
||||
(Flake8Simplify, "111") => Rule::ConvertLoopToAll,
|
||||
(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,
|
||||
|
||||
// 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,
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ mod ast;
|
||||
mod autofix;
|
||||
pub mod cache;
|
||||
mod checkers;
|
||||
mod codes;
|
||||
mod cst;
|
||||
mod directives;
|
||||
mod doc_lines;
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,3 +1,4 @@
|
||||
use std::fmt::{Display, Write};
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
@@ -72,7 +73,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 +87,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),
|
||||
));
|
||||
@@ -205,9 +206,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 +227,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 +252,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;
|
||||
@@ -217,7 +218,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,11 @@ 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([
|
||||
("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),
|
||||
|
||||
@@ -43,7 +43,7 @@ mod tests {
|
||||
#[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),
|
||||
|
||||
@@ -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,14 @@ expression: diagnostics
|
||||
column: 18
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
StripWithMultiCharacters: ~
|
||||
location:
|
||||
row: 22
|
||||
column: 0
|
||||
end_location:
|
||||
row: 22
|
||||
column: 13
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
source: src/rules/flake8_bugbear/mod.rs
|
||||
source: crates/ruff/src/rules/flake8_bugbear/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
@@ -32,4 +32,24 @@ expression: diagnostics
|
||||
column: 39
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
RaiseWithoutFromInsideExcept: ~
|
||||
location:
|
||||
row: 62
|
||||
column: 8
|
||||
end_location:
|
||||
row: 62
|
||||
column: 35
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
RaiseWithoutFromInsideExcept: ~
|
||||
location:
|
||||
row: 64
|
||||
column: 8
|
||||
end_location:
|
||||
row: 64
|
||||
column: 35
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ mod tests {
|
||||
#[test_case(Rule::BuiltinArgumentShadowing, Path::new("A002.py"); "A002")]
|
||||
#[test_case(Rule::BuiltinAttributeShadowing, Path::new("A003.py"); "A003")]
|
||||
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_builtins").join(path).as_path(),
|
||||
&Settings::for_rule(rule_code),
|
||||
@@ -34,7 +34,7 @@ mod tests {
|
||||
fn builtins_ignorelist(rule_code: Rule, path: &Path) -> Result<()> {
|
||||
let snapshot = format!(
|
||||
"{}_{}_builtins_ignorelist",
|
||||
rule_code.code(),
|
||||
rule_code.noqa_code(),
|
||||
path.to_string_lossy()
|
||||
);
|
||||
|
||||
|
||||
@@ -8,6 +8,44 @@ use crate::registry::{Diagnostic, DiagnosticKind};
|
||||
use crate::violation::Violation;
|
||||
|
||||
define_violation!(
|
||||
/// ## What it does
|
||||
/// Checks for variable (and function) assignments that use the same name
|
||||
/// as a builtin.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Reusing a builtin name for the name of a variable increases the
|
||||
/// difficulty of reading and maintaining the code, and can cause
|
||||
/// non-obvious errors, as readers may mistake the variable for the
|
||||
/// builtin and vice versa.
|
||||
///
|
||||
/// Builtins can be marked as exceptions to this rule via the
|
||||
/// [`flake8-builtins.builtins-ignorelist`] configuration option.
|
||||
///
|
||||
/// ## Options
|
||||
///
|
||||
/// * `flake8-builtins.builtins-ignorelist`
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def find_max(list_of_lists):
|
||||
/// max = 0
|
||||
/// for flat_list in list_of_lists:
|
||||
/// for value in flat_list:
|
||||
/// max = max(max, value) # TypeError: 'int' object is not callable
|
||||
/// return max
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// def find_max(list_of_lists):
|
||||
/// result = 0
|
||||
/// for flat_list in list_of_lists:
|
||||
/// for value in flat_list:
|
||||
/// result = max(result, value)
|
||||
/// return result
|
||||
/// ```
|
||||
///
|
||||
/// * [Why is it a bad idea to name a variable `id` in Python?_](https://stackoverflow.com/questions/77552/id-is-a-bad-variable-name-in-python)
|
||||
pub struct BuiltinVariableShadowing {
|
||||
pub name: String,
|
||||
}
|
||||
@@ -21,6 +59,47 @@ impl Violation for BuiltinVariableShadowing {
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
/// ## What it does
|
||||
/// Checks for any function arguments that use the same name as a builtin.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Reusing a builtin name for the name of an argument increases the
|
||||
/// difficulty of reading and maintaining the code, and can cause
|
||||
/// non-obvious errors, as readers may mistake the argument for the
|
||||
/// builtin and vice versa.
|
||||
///
|
||||
/// Builtins can be marked as exceptions to this rule via the
|
||||
/// [`flake8-builtins.builtins-ignorelist`] configuration option.
|
||||
///
|
||||
/// ## Options
|
||||
///
|
||||
/// * `flake8-builtins.builtins-ignorelist`
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// def remove_duplicates(list, list2):
|
||||
/// result = set()
|
||||
/// for value in list:
|
||||
/// result.add(value)
|
||||
/// for value in list2:
|
||||
/// result.add(value)
|
||||
/// return list(result) # TypeError: 'list' object is not callable
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// def remove_duplicates(list1, list2):
|
||||
/// result = set()
|
||||
/// for value in list1:
|
||||
/// result.add(value)
|
||||
/// for value in list2:
|
||||
/// result.add(value)
|
||||
/// return list(result)
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// - [_Is it bad practice to use a built-in function name as an attribute or method identifier?_](https://stackoverflow.com/questions/9109333/is-it-bad-practice-to-use-a-built-in-function-name-as-an-attribute-or-method-ide)
|
||||
/// - [_Why is it a bad idea to name a variable `id` in Python?_](https://stackoverflow.com/questions/77552/id-is-a-bad-variable-name-in-python)
|
||||
pub struct BuiltinArgumentShadowing {
|
||||
pub name: String,
|
||||
}
|
||||
@@ -34,6 +113,48 @@ impl Violation for BuiltinArgumentShadowing {
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
/// ## What it does
|
||||
/// Checks for any class attributes that use the same name as a builtin.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Reusing a builtin name for the name of an attribute increases the
|
||||
/// difficulty of reading and maintaining the code, and can cause
|
||||
/// non-obvious errors, as readers may mistake the attribute for the
|
||||
/// builtin and vice versa.
|
||||
///
|
||||
/// Builtins can be marked as exceptions to this rule via the
|
||||
/// [`flake8-builtins.builtins-ignorelist`] configuration option, or
|
||||
/// converted to the appropriate dunder method.
|
||||
///
|
||||
/// ## Options
|
||||
///
|
||||
/// * `flake8-builtins.builtins-ignorelist`
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// class Shadow:
|
||||
/// def int():
|
||||
/// return 0
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// class Shadow:
|
||||
/// def to_int():
|
||||
/// return 0
|
||||
/// ```
|
||||
///
|
||||
/// Or:
|
||||
/// ```python
|
||||
/// class Shadow:
|
||||
/// # Callable as `int(shadow)`
|
||||
/// def __int__():
|
||||
/// return 0
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// - [_Is it bad practice to use a built-in function name as an attribute or method identifier?_](https://stackoverflow.com/questions/9109333/is-it-bad-practice-to-use-a-built-in-function-name-as-an-attribute-or-method-ide)
|
||||
/// - [_Why is it a bad idea to name a variable `id` in Python?_](https://stackoverflow.com/questions/77552/id-is-a-bad-variable-name-in-python)
|
||||
pub struct BuiltinAttributeShadowing {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ pub fn fix_unnecessary_generator_list(
|
||||
expr: &rustpython_parser::ast::Expr,
|
||||
) -> Result<Fix> {
|
||||
// Expr(Call(GeneratorExp)))) -> Expr(ListComp)))
|
||||
let module_text = locator.slice_source_code_range(&Range::from_located(expr));
|
||||
let module_text = locator.slice(&Range::from_located(expr));
|
||||
let mut tree = match_module(module_text)?;
|
||||
let mut body = match_expr(&mut tree)?;
|
||||
let call = match_call(body)?;
|
||||
@@ -82,7 +82,7 @@ pub fn fix_unnecessary_generator_set(
|
||||
parent: Option<&rustpython_parser::ast::Expr>,
|
||||
) -> Result<Fix> {
|
||||
// Expr(Call(GeneratorExp)))) -> Expr(SetComp)))
|
||||
let module_text = locator.slice_source_code_range(&Range::from_located(expr));
|
||||
let module_text = locator.slice(&Range::from_located(expr));
|
||||
let mut tree = match_module(module_text)?;
|
||||
let mut body = match_expr(&mut tree)?;
|
||||
let call = match_call(body)?;
|
||||
@@ -139,7 +139,7 @@ pub fn fix_unnecessary_generator_dict(
|
||||
expr: &rustpython_parser::ast::Expr,
|
||||
parent: Option<&rustpython_parser::ast::Expr>,
|
||||
) -> Result<Fix> {
|
||||
let module_text = locator.slice_source_code_range(&Range::from_located(expr));
|
||||
let module_text = locator.slice(&Range::from_located(expr));
|
||||
let mut tree = match_module(module_text)?;
|
||||
let mut body = match_expr(&mut tree)?;
|
||||
let call = match_call(body)?;
|
||||
@@ -213,7 +213,7 @@ pub fn fix_unnecessary_list_comprehension_set(
|
||||
) -> Result<Fix> {
|
||||
// Expr(Call(ListComp)))) ->
|
||||
// Expr(SetComp)))
|
||||
let module_text = locator.slice_source_code_range(&Range::from_located(expr));
|
||||
let module_text = locator.slice(&Range::from_located(expr));
|
||||
let mut tree = match_module(module_text)?;
|
||||
let mut body = match_expr(&mut tree)?;
|
||||
let call = match_call(body)?;
|
||||
@@ -257,7 +257,7 @@ pub fn fix_unnecessary_list_comprehension_dict(
|
||||
stylist: &Stylist,
|
||||
expr: &rustpython_parser::ast::Expr,
|
||||
) -> Result<Fix> {
|
||||
let module_text = locator.slice_source_code_range(&Range::from_located(expr));
|
||||
let module_text = locator.slice(&Range::from_located(expr));
|
||||
let mut tree = match_module(module_text)?;
|
||||
let mut body = match_expr(&mut tree)?;
|
||||
let call = match_call(body)?;
|
||||
@@ -356,7 +356,7 @@ pub fn fix_unnecessary_literal_set(
|
||||
expr: &rustpython_parser::ast::Expr,
|
||||
) -> Result<Fix> {
|
||||
// Expr(Call(List|Tuple)))) -> Expr(Set)))
|
||||
let module_text = locator.slice_source_code_range(&Range::from_located(expr));
|
||||
let module_text = locator.slice(&Range::from_located(expr));
|
||||
let mut tree = match_module(module_text)?;
|
||||
let mut body = match_expr(&mut tree)?;
|
||||
let mut call = match_call(body)?;
|
||||
@@ -407,7 +407,7 @@ pub fn fix_unnecessary_literal_dict(
|
||||
expr: &rustpython_parser::ast::Expr,
|
||||
) -> Result<Fix> {
|
||||
// Expr(Call(List|Tuple)))) -> Expr(Dict)))
|
||||
let module_text = locator.slice_source_code_range(&Range::from_located(expr));
|
||||
let module_text = locator.slice(&Range::from_located(expr));
|
||||
let mut tree = match_module(module_text)?;
|
||||
let mut body = match_expr(&mut tree)?;
|
||||
let call = match_call(body)?;
|
||||
@@ -480,7 +480,7 @@ pub fn fix_unnecessary_collection_call(
|
||||
expr: &rustpython_parser::ast::Expr,
|
||||
) -> Result<Fix> {
|
||||
// Expr(Call("list" | "tuple" | "dict")))) -> Expr(List|Tuple|Dict)
|
||||
let module_text = locator.slice_source_code_range(&Range::from_located(expr));
|
||||
let module_text = locator.slice(&Range::from_located(expr));
|
||||
let mut tree = match_module(module_text)?;
|
||||
let mut body = match_expr(&mut tree)?;
|
||||
let call = match_call(body)?;
|
||||
@@ -593,7 +593,7 @@ pub fn fix_unnecessary_literal_within_tuple_call(
|
||||
stylist: &Stylist,
|
||||
expr: &rustpython_parser::ast::Expr,
|
||||
) -> Result<Fix> {
|
||||
let module_text = locator.slice_source_code_range(&Range::from_located(expr));
|
||||
let module_text = locator.slice(&Range::from_located(expr));
|
||||
let mut tree = match_module(module_text)?;
|
||||
let mut body = match_expr(&mut tree)?;
|
||||
let call = match_call(body)?;
|
||||
@@ -652,7 +652,7 @@ pub fn fix_unnecessary_literal_within_list_call(
|
||||
stylist: &Stylist,
|
||||
expr: &rustpython_parser::ast::Expr,
|
||||
) -> Result<Fix> {
|
||||
let module_text = locator.slice_source_code_range(&Range::from_located(expr));
|
||||
let module_text = locator.slice(&Range::from_located(expr));
|
||||
let mut tree = match_module(module_text)?;
|
||||
let mut body = match_expr(&mut tree)?;
|
||||
let call = match_call(body)?;
|
||||
@@ -714,7 +714,7 @@ pub fn fix_unnecessary_list_call(
|
||||
expr: &rustpython_parser::ast::Expr,
|
||||
) -> Result<Fix> {
|
||||
// Expr(Call(List|Tuple)))) -> Expr(List|Tuple)))
|
||||
let module_text = locator.slice_source_code_range(&Range::from_located(expr));
|
||||
let module_text = locator.slice(&Range::from_located(expr));
|
||||
let mut tree = match_module(module_text)?;
|
||||
let mut body = match_expr(&mut tree)?;
|
||||
let call = match_call(body)?;
|
||||
@@ -744,7 +744,7 @@ pub fn fix_unnecessary_call_around_sorted(
|
||||
stylist: &Stylist,
|
||||
expr: &rustpython_parser::ast::Expr,
|
||||
) -> Result<Fix> {
|
||||
let module_text = locator.slice_source_code_range(&Range::from_located(expr));
|
||||
let module_text = locator.slice(&Range::from_located(expr));
|
||||
let mut tree = match_module(module_text)?;
|
||||
let mut body = match_expr(&mut tree)?;
|
||||
let outer_call = match_call(body)?;
|
||||
@@ -871,7 +871,7 @@ pub fn fix_unnecessary_double_cast_or_process(
|
||||
stylist: &Stylist,
|
||||
expr: &rustpython_parser::ast::Expr,
|
||||
) -> Result<Fix> {
|
||||
let module_text = locator.slice_source_code_range(&Range::from_located(expr));
|
||||
let module_text = locator.slice(&Range::from_located(expr));
|
||||
let mut tree = match_module(module_text)?;
|
||||
let body = match_expr(&mut tree)?;
|
||||
let mut outer_call = match_call(body)?;
|
||||
@@ -910,7 +910,7 @@ pub fn fix_unnecessary_comprehension(
|
||||
stylist: &Stylist,
|
||||
expr: &rustpython_parser::ast::Expr,
|
||||
) -> Result<Fix> {
|
||||
let module_text = locator.slice_source_code_range(&Range::from_located(expr));
|
||||
let module_text = locator.slice(&Range::from_located(expr));
|
||||
let mut tree = match_module(module_text)?;
|
||||
let mut body = match_expr(&mut tree)?;
|
||||
|
||||
@@ -986,7 +986,7 @@ pub fn fix_unnecessary_map(
|
||||
parent: Option<&rustpython_parser::ast::Expr>,
|
||||
kind: &str,
|
||||
) -> Result<Fix> {
|
||||
let module_text = locator.slice_source_code_range(&Range::from_located(expr));
|
||||
let module_text = locator.slice(&Range::from_located(expr));
|
||||
let mut tree = match_module(module_text)?;
|
||||
let mut body = match_expr(&mut tree)?;
|
||||
let call = match_call(body)?;
|
||||
|
||||
@@ -31,7 +31,7 @@ mod tests {
|
||||
#[test_case(Rule::UnnecessaryMap, Path::new("C417.py"); "C417")]
|
||||
|
||||
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_comprehensions").join(path).as_path(),
|
||||
&settings::Settings::for_rule(rule_code),
|
||||
|
||||
@@ -22,7 +22,7 @@ mod tests {
|
||||
#[test_case(Rule::CallDateToday, Path::new("DTZ011.py"); "DTZ011")]
|
||||
#[test_case(Rule::CallDateFromtimestamp, Path::new("DTZ012.py"); "DTZ012")]
|
||||
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_datetimez").join(path).as_path(),
|
||||
&settings::Settings::for_rule(rule_code),
|
||||
|
||||
@@ -15,7 +15,7 @@ mod tests {
|
||||
|
||||
#[test_case(Rule::Debugger, Path::new("T100.py"); "T100")]
|
||||
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_debugger").join(path).as_path(),
|
||||
&settings::Settings::for_rule(rule_code),
|
||||
|
||||
@@ -12,11 +12,11 @@ mod tests {
|
||||
use crate::test::test_path;
|
||||
use crate::{assert_yaml_snapshot, settings};
|
||||
|
||||
#[test_case(Rule::ModelStringFieldNullable, Path::new("DJ001.py"); "DJ001")]
|
||||
#[test_case(Rule::ModelDunderStr, Path::new("DJ008.py"); "DJ008")]
|
||||
#[test_case(Rule::ReceiverDecoratorChecker, Path::new("DJ013.py"); "DJ013")]
|
||||
#[test_case(Rule::NullableModelStringField, Path::new("DJ001.py"); "DJ001")]
|
||||
#[test_case(Rule::ModelWithoutDunderStr, Path::new("DJ008.py"); "DJ008")]
|
||||
#[test_case(Rule::NonLeadingReceiverDecorator, Path::new("DJ013.py"); "DJ013")]
|
||||
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_django").join(path).as_path(),
|
||||
&settings::Settings::for_rule(rule_code),
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
mod helpers;
|
||||
mod model_dunder_str;
|
||||
mod model_string_field_nullable;
|
||||
mod receiver_decorator_checker;
|
||||
pub use model_without_dunder_str::{model_without_dunder_str, ModelWithoutDunderStr};
|
||||
pub use non_leading_receiver_decorator::{
|
||||
non_leading_receiver_decorator, NonLeadingReceiverDecorator,
|
||||
};
|
||||
pub use nullable_model_string_field::{nullable_model_string_field, NullableModelStringField};
|
||||
|
||||
pub use model_dunder_str::{model_dunder_str, ModelDunderStr};
|
||||
pub use model_string_field_nullable::{model_string_field_nullable, ModelStringFieldNullable};
|
||||
pub use receiver_decorator_checker::{receiver_decorator_checker, ReceiverDecoratorChecker};
|
||||
mod helpers;
|
||||
mod model_without_dunder_str;
|
||||
mod non_leading_receiver_decorator;
|
||||
mod nullable_model_string_field;
|
||||
|
||||
@@ -40,9 +40,9 @@ define_violation!(
|
||||
/// def __str__(self):
|
||||
/// return f"{self.field}"
|
||||
/// ```
|
||||
pub struct ModelDunderStr;
|
||||
pub struct ModelWithoutDunderStr;
|
||||
);
|
||||
impl Violation for ModelDunderStr {
|
||||
impl Violation for ModelWithoutDunderStr {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Model does not define `__str__` method")
|
||||
@@ -50,7 +50,7 @@ impl Violation for ModelDunderStr {
|
||||
}
|
||||
|
||||
/// DJ008
|
||||
pub fn model_dunder_str(
|
||||
pub fn model_without_dunder_str(
|
||||
checker: &Checker,
|
||||
bases: &[Expr],
|
||||
body: &[Stmt],
|
||||
@@ -61,7 +61,7 @@ pub fn model_dunder_str(
|
||||
}
|
||||
if !has_dunder_method(body) {
|
||||
return Some(Diagnostic::new(
|
||||
ModelDunderStr,
|
||||
ModelWithoutDunderStr,
|
||||
Range::from_located(class_location),
|
||||
));
|
||||
}
|
||||
@@ -38,9 +38,9 @@ define_violation!(
|
||||
/// def my_handler(sender, instance, created, **kwargs):
|
||||
/// pass
|
||||
/// ```
|
||||
pub struct ReceiverDecoratorChecker;
|
||||
pub struct NonLeadingReceiverDecorator;
|
||||
);
|
||||
impl Violation for ReceiverDecoratorChecker {
|
||||
impl Violation for NonLeadingReceiverDecorator {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("`@receiver` decorator must be on top of all the other decorators")
|
||||
@@ -48,28 +48,33 @@ impl Violation for ReceiverDecoratorChecker {
|
||||
}
|
||||
|
||||
/// DJ013
|
||||
pub fn receiver_decorator_checker<'a, F>(
|
||||
pub fn non_leading_receiver_decorator<'a, F>(
|
||||
decorator_list: &'a [Expr],
|
||||
resolve_call_path: F,
|
||||
) -> Option<Diagnostic>
|
||||
) -> Vec<Diagnostic>
|
||||
where
|
||||
F: Fn(&'a Expr) -> Option<CallPath<'a>>,
|
||||
{
|
||||
let mut diagnostics = vec![];
|
||||
let mut seen_receiver = false;
|
||||
for (i, decorator) in decorator_list.iter().enumerate() {
|
||||
if i == 0 {
|
||||
continue;
|
||||
}
|
||||
let ExprKind::Call{ func, ..} = &decorator.node else {
|
||||
continue;
|
||||
let is_receiver = match &decorator.node {
|
||||
ExprKind::Call { func, .. } => resolve_call_path(func).map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["django", "dispatch", "receiver"]
|
||||
}),
|
||||
_ => false,
|
||||
};
|
||||
if resolve_call_path(func).map_or(false, |call_path| {
|
||||
call_path.as_slice() == ["django", "dispatch", "receiver"]
|
||||
}) {
|
||||
return Some(Diagnostic::new(
|
||||
ReceiverDecoratorChecker,
|
||||
if i > 0 && is_receiver && !seen_receiver {
|
||||
diagnostics.push(Diagnostic::new(
|
||||
NonLeadingReceiverDecorator,
|
||||
Range::from_located(decorator),
|
||||
));
|
||||
}
|
||||
if !is_receiver && seen_receiver {
|
||||
seen_receiver = false;
|
||||
} else if is_receiver {
|
||||
seen_receiver = true;
|
||||
}
|
||||
}
|
||||
None
|
||||
diagnostics
|
||||
}
|
||||
@@ -1,11 +1,14 @@
|
||||
use super::helpers;
|
||||
use rustpython_parser::ast::Constant::Bool;
|
||||
use rustpython_parser::ast::{Expr, ExprKind, Stmt, StmtKind};
|
||||
|
||||
use ruff_macros::{define_violation, derive_message_formats};
|
||||
|
||||
use crate::ast::types::Range;
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::violation::Violation;
|
||||
use ruff_macros::{define_violation, derive_message_formats};
|
||||
use rustpython_parser::ast::Constant::Bool;
|
||||
use rustpython_parser::ast::{Expr, ExprKind, Stmt, StmtKind};
|
||||
|
||||
use super::helpers;
|
||||
|
||||
define_violation!(
|
||||
/// ## What it does
|
||||
@@ -36,14 +39,14 @@ define_violation!(
|
||||
/// class MyModel(models.Model):
|
||||
/// field = models.CharField(max_length=255, default="")
|
||||
/// ```
|
||||
pub struct ModelStringFieldNullable {
|
||||
pub struct NullableModelStringField {
|
||||
pub field_name: String,
|
||||
}
|
||||
);
|
||||
impl Violation for ModelStringFieldNullable {
|
||||
impl Violation for NullableModelStringField {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let ModelStringFieldNullable { field_name } = self;
|
||||
let NullableModelStringField { field_name } = self;
|
||||
format!("Avoid using `null=True` on string-based fields such as {field_name}")
|
||||
}
|
||||
}
|
||||
@@ -58,23 +61,15 @@ const NOT_NULL_TRUE_FIELDS: [&str; 6] = [
|
||||
];
|
||||
|
||||
/// DJ001
|
||||
pub fn model_string_field_nullable(
|
||||
checker: &Checker,
|
||||
bases: &[Expr],
|
||||
body: &[Stmt],
|
||||
) -> Vec<Diagnostic> {
|
||||
if !bases.iter().any(|base| helpers::is_model(checker, base)) {
|
||||
return vec![];
|
||||
}
|
||||
|
||||
pub fn nullable_model_string_field(checker: &Checker, body: &[Stmt]) -> Vec<Diagnostic> {
|
||||
let mut errors = Vec::new();
|
||||
for statement in body.iter() {
|
||||
let StmtKind::Assign {value, ..} = &statement.node else {
|
||||
continue
|
||||
};
|
||||
if let Some(field_name) = check_nullable_field(checker, value) {
|
||||
if let Some(field_name) = is_nullable_field(checker, value) {
|
||||
errors.push(Diagnostic::new(
|
||||
ModelStringFieldNullable {
|
||||
NullableModelStringField {
|
||||
field_name: field_name.to_string(),
|
||||
},
|
||||
Range::from_located(value),
|
||||
@@ -84,7 +79,7 @@ pub fn model_string_field_nullable(
|
||||
errors
|
||||
}
|
||||
|
||||
fn check_nullable_field<'a>(checker: &'a Checker, value: &'a Expr) -> Option<&'a str> {
|
||||
fn is_nullable_field<'a>(checker: &'a Checker, value: &'a Expr) -> Option<&'a str> {
|
||||
let ExprKind::Call {func, keywords, ..} = &value.node else {
|
||||
return None;
|
||||
};
|
||||
@@ -3,7 +3,7 @@ source: crates/ruff/src/rules/flake8_django/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
ModelStringFieldNullable:
|
||||
NullableModelStringField:
|
||||
field_name: CharField
|
||||
location:
|
||||
row: 7
|
||||
@@ -14,7 +14,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
ModelStringFieldNullable:
|
||||
NullableModelStringField:
|
||||
field_name: TextField
|
||||
location:
|
||||
row: 8
|
||||
@@ -25,7 +25,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
ModelStringFieldNullable:
|
||||
NullableModelStringField:
|
||||
field_name: SlugField
|
||||
location:
|
||||
row: 9
|
||||
@@ -36,7 +36,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
ModelStringFieldNullable:
|
||||
NullableModelStringField:
|
||||
field_name: EmailField
|
||||
location:
|
||||
row: 10
|
||||
@@ -47,7 +47,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
ModelStringFieldNullable:
|
||||
NullableModelStringField:
|
||||
field_name: FilePathField
|
||||
location:
|
||||
row: 11
|
||||
@@ -58,7 +58,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
ModelStringFieldNullable:
|
||||
NullableModelStringField:
|
||||
field_name: URLField
|
||||
location:
|
||||
row: 12
|
||||
@@ -69,7 +69,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
ModelStringFieldNullable:
|
||||
NullableModelStringField:
|
||||
field_name: CharField
|
||||
location:
|
||||
row: 16
|
||||
@@ -80,7 +80,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
ModelStringFieldNullable:
|
||||
NullableModelStringField:
|
||||
field_name: CharField
|
||||
location:
|
||||
row: 17
|
||||
@@ -91,7 +91,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
ModelStringFieldNullable:
|
||||
NullableModelStringField:
|
||||
field_name: SlugField
|
||||
location:
|
||||
row: 18
|
||||
@@ -102,7 +102,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
ModelStringFieldNullable:
|
||||
NullableModelStringField:
|
||||
field_name: EmailField
|
||||
location:
|
||||
row: 19
|
||||
@@ -113,7 +113,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
ModelStringFieldNullable:
|
||||
NullableModelStringField:
|
||||
field_name: FilePathField
|
||||
location:
|
||||
row: 20
|
||||
@@ -124,7 +124,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
ModelStringFieldNullable:
|
||||
NullableModelStringField:
|
||||
field_name: URLField
|
||||
location:
|
||||
row: 21
|
||||
@@ -134,4 +134,70 @@ expression: diagnostics
|
||||
column: 57
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
NullableModelStringField:
|
||||
field_name: CharField
|
||||
location:
|
||||
row: 25
|
||||
column: 16
|
||||
end_location:
|
||||
row: 25
|
||||
column: 64
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
NullableModelStringField:
|
||||
field_name: CharField
|
||||
location:
|
||||
row: 26
|
||||
column: 16
|
||||
end_location:
|
||||
row: 26
|
||||
column: 56
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
NullableModelStringField:
|
||||
field_name: SlugField
|
||||
location:
|
||||
row: 27
|
||||
column: 16
|
||||
end_location:
|
||||
row: 27
|
||||
column: 59
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
NullableModelStringField:
|
||||
field_name: EmailField
|
||||
location:
|
||||
row: 28
|
||||
column: 17
|
||||
end_location:
|
||||
row: 28
|
||||
column: 61
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
NullableModelStringField:
|
||||
field_name: FilePathField
|
||||
location:
|
||||
row: 29
|
||||
column: 20
|
||||
end_location:
|
||||
row: 29
|
||||
column: 67
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
NullableModelStringField:
|
||||
field_name: URLField
|
||||
location:
|
||||
row: 30
|
||||
column: 15
|
||||
end_location:
|
||||
row: 30
|
||||
column: 57
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ source: crates/ruff/src/rules/flake8_django/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
ModelDunderStr: ~
|
||||
ModelWithoutDunderStr: ~
|
||||
location:
|
||||
row: 6
|
||||
column: 0
|
||||
@@ -13,7 +13,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
ModelDunderStr: ~
|
||||
ModelWithoutDunderStr: ~
|
||||
location:
|
||||
row: 21
|
||||
column: 0
|
||||
@@ -23,7 +23,7 @@ expression: diagnostics
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
ModelDunderStr: ~
|
||||
ModelWithoutDunderStr: ~
|
||||
location:
|
||||
row: 36
|
||||
column: 0
|
||||
|
||||
@@ -3,7 +3,7 @@ source: crates/ruff/src/rules/flake8_django/mod.rs
|
||||
expression: diagnostics
|
||||
---
|
||||
- kind:
|
||||
ReceiverDecoratorChecker: ~
|
||||
NonLeadingReceiverDecorator: ~
|
||||
location:
|
||||
row: 15
|
||||
column: 1
|
||||
@@ -12,4 +12,14 @@ expression: diagnostics
|
||||
column: 35
|
||||
fix: ~
|
||||
parent: ~
|
||||
- kind:
|
||||
NonLeadingReceiverDecorator: ~
|
||||
location:
|
||||
row: 35
|
||||
column: 1
|
||||
end_location:
|
||||
row: 35
|
||||
column: 35
|
||||
fix: ~
|
||||
parent: ~
|
||||
|
||||
|
||||
@@ -7,6 +7,43 @@ use crate::registry::{Diagnostic, Rule};
|
||||
use crate::violation::Violation;
|
||||
|
||||
define_violation!(
|
||||
/// ## What it does
|
||||
/// Checks for the use of string literals in exception constructors.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Python includes the `raise` in the default traceback (and formatters
|
||||
/// like Rich and IPython do too).
|
||||
///
|
||||
/// By using a string literal, the error message will be duplicated in the
|
||||
/// traceback, which can make the traceback less readable.
|
||||
///
|
||||
/// ## Example
|
||||
/// Given:
|
||||
/// ```python
|
||||
/// raise RuntimeError("'Some value' is incorrect")
|
||||
/// ```
|
||||
///
|
||||
/// Python will produce a traceback like:
|
||||
/// ```python
|
||||
/// Traceback (most recent call last):
|
||||
/// File "tmp.py", line 2, in <module>
|
||||
/// raise RuntimeError("Some value is incorrect")
|
||||
/// RuntimeError: 'Some value' is incorrect
|
||||
/// ```
|
||||
///
|
||||
/// Instead, assign the string to a variable:
|
||||
/// ```python
|
||||
/// msg = "'Some value' is incorrect"
|
||||
/// raise RuntimeError(msg)
|
||||
/// ```
|
||||
///
|
||||
/// Which will produce a traceback like:
|
||||
/// ```python
|
||||
/// Traceback (most recent call last):
|
||||
/// File "tmp.py", line 3, in <module>
|
||||
/// raise RuntimeError(msg)
|
||||
/// RuntimeError: 'Some value' is incorrect
|
||||
/// ```
|
||||
pub struct RawStringInException;
|
||||
);
|
||||
impl Violation for RawStringInException {
|
||||
@@ -17,6 +54,45 @@ impl Violation for RawStringInException {
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
/// ## What it does
|
||||
/// Checks for the use of f-strings in exception constructors.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Python includes the `raise` in the default traceback (and formatters
|
||||
/// like Rich and IPython do too).
|
||||
///
|
||||
/// By using an f-string, the error message will be duplicated in the
|
||||
/// traceback, which can make the traceback less readable.
|
||||
///
|
||||
/// ## Example
|
||||
/// Given:
|
||||
/// ```python
|
||||
/// sub = "Some value"
|
||||
/// raise RuntimeError(f"{sub!r} is incorrect")
|
||||
/// ```
|
||||
///
|
||||
/// Python will produce a traceback like:
|
||||
/// ```python
|
||||
/// Traceback (most recent call last):
|
||||
/// File "tmp.py", line 2, in <module>
|
||||
/// raise RuntimeError(f"{sub!r} is incorrect")
|
||||
/// RuntimeError: 'Some value' is incorrect
|
||||
/// ```
|
||||
///
|
||||
/// Instead, assign the string to a variable:
|
||||
/// ```python
|
||||
/// sub = "Some value"
|
||||
/// msg = f"{sub!r} is incorrect"
|
||||
/// raise RuntimeError(msg)
|
||||
/// ```
|
||||
///
|
||||
/// Which will produce a traceback like:
|
||||
/// ```python
|
||||
/// Traceback (most recent call last):
|
||||
/// File "tmp.py", line 3, in <module>
|
||||
/// raise RuntimeError(msg)
|
||||
/// RuntimeError: 'Some value' is incorrect
|
||||
/// ```
|
||||
pub struct FStringInException;
|
||||
);
|
||||
impl Violation for FStringInException {
|
||||
@@ -27,6 +103,46 @@ impl Violation for FStringInException {
|
||||
}
|
||||
|
||||
define_violation!(
|
||||
/// ## What it does
|
||||
/// Checks for the use of `.format` calls on string literals in exception
|
||||
/// constructors.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Python includes the `raise` in the default traceback (and formatters
|
||||
/// like Rich and IPython do too).
|
||||
///
|
||||
/// By using a `.format` call, the error message will be duplicated in the
|
||||
/// traceback, which can make the traceback less readable.
|
||||
///
|
||||
/// ## Example
|
||||
/// Given:
|
||||
/// ```python
|
||||
/// sub = "Some value"
|
||||
/// raise RuntimeError("'{}' is incorrect".format(sub))
|
||||
/// ```
|
||||
///
|
||||
/// Python will produce a traceback like:
|
||||
/// ```python
|
||||
/// Traceback (most recent call last):
|
||||
/// File "tmp.py", line 2, in <module>
|
||||
/// raise RuntimeError("'{}' is incorrect".format(sub))
|
||||
/// RuntimeError: 'Some value' is incorrect
|
||||
/// ```
|
||||
///
|
||||
/// Instead, assign the string to a variable:
|
||||
/// ```python
|
||||
/// sub = "Some value"
|
||||
/// msg = "'{}' is incorrect".format(sub)
|
||||
/// raise RuntimeError(msg)
|
||||
/// ```
|
||||
///
|
||||
/// Which will produce a traceback like:
|
||||
/// ```python
|
||||
/// Traceback (most recent call last):
|
||||
/// File "tmp.py", line 3, in <module>
|
||||
/// raise RuntimeError(msg)
|
||||
/// RuntimeError: 'Some value' is incorrect
|
||||
/// ```
|
||||
pub struct DotFormatInException;
|
||||
);
|
||||
impl Violation for DotFormatInException {
|
||||
|
||||
@@ -12,7 +12,7 @@ define_violation!(
|
||||
impl Violation for ShebangPython {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Shebang should contain \"python\"")
|
||||
format!("Shebang should contain `python`")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ mod tests {
|
||||
#[test_case(Rule::MultiLineImplicitStringConcatenation, Path::new("ISC.py"); "ISC002")]
|
||||
#[test_case(Rule::ExplicitStringConcatenation, Path::new("ISC.py"); "ISC003")]
|
||||
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_implicit_str_concat").join(path).as_path(),
|
||||
&settings::Settings::for_rule(rule_code),
|
||||
@@ -30,7 +30,11 @@ mod tests {
|
||||
#[test_case(Rule::MultiLineImplicitStringConcatenation, Path::new("ISC.py"); "ISC002")]
|
||||
#[test_case(Rule::ExplicitStringConcatenation, Path::new("ISC.py"); "ISC003")]
|
||||
fn multiline(rule_code: Rule, path: &Path) -> Result<()> {
|
||||
let snapshot = format!("multiline_{}_{}", rule_code.code(), path.to_string_lossy());
|
||||
let snapshot = format!(
|
||||
"multiline_{}_{}",
|
||||
rule_code.noqa_code(),
|
||||
path.to_string_lossy()
|
||||
);
|
||||
let diagnostics = test_path(
|
||||
Path::new("flake8_implicit_str_concat").join(path).as_path(),
|
||||
&settings::Settings {
|
||||
|
||||
@@ -25,7 +25,6 @@ define_violation!(
|
||||
/// the absence of the `__init__.py` file is probably an oversight.
|
||||
///
|
||||
/// ## Options
|
||||
///
|
||||
/// * `namespace-packages`
|
||||
pub struct ImplicitNamespacePackage {
|
||||
pub filename: String,
|
||||
|
||||
@@ -20,7 +20,7 @@ mod tests {
|
||||
#[test_case(Rule::PreferListBuiltin, Path::new("PIE807.py"); "PIE807")]
|
||||
#[test_case(Rule::PreferUniqueEnums, Path::new("PIE796.py"); "PIE796")]
|
||||
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_pie").join(path).as_path(),
|
||||
&settings::Settings::for_rule(rule_code),
|
||||
|
||||
@@ -15,7 +15,7 @@ mod tests {
|
||||
#[test_case(Rule::PrintFound, Path::new("T201.py"); "T201")]
|
||||
#[test_case(Rule::PPrintFound, Path::new("T203.py"); "T203")]
|
||||
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_print").join(path).as_path(),
|
||||
&settings::Settings::for_rule(rule_code),
|
||||
|
||||
@@ -19,7 +19,7 @@ mod tests {
|
||||
#[test_case(Rule::UnrecognizedPlatformName, Path::new("PYI008.pyi"))]
|
||||
#[test_case(Rule::UnrecognizedPlatformName, Path::new("PYI008.py"))]
|
||||
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_pyi").join(path).as_path(),
|
||||
&settings::Settings::for_rule(rule_code),
|
||||
|
||||
@@ -55,7 +55,7 @@ impl Violation for PrefixTypeParams {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
let PrefixTypeParams { kind } = self;
|
||||
format!("Name of private `{kind}` must start with _")
|
||||
format!("Name of private `{kind}` must start with `_`")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,13 +36,13 @@ define_violation!(
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// - [PEP 484](https://peps.python.org/pep-0484/#version-and-platform-checking)
|
||||
/// * [PEP 484](https://peps.python.org/pep-0484/#version-and-platform-checking)
|
||||
pub struct UnrecognizedPlatformCheck;
|
||||
);
|
||||
impl Violation for UnrecognizedPlatformCheck {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
format!("Unrecognized sys.platform check")
|
||||
format!("Unrecognized `sys.platform` check")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ define_violation!(
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// - [PEP 484](https://peps.python.org/pep-0484/#version-and-platform-checking)
|
||||
/// * [PEP 484](https://peps.python.org/pep-0484/#version-and-platform-checking)
|
||||
pub struct UnrecognizedPlatformName {
|
||||
pub platform: String,
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ define_violation!(
|
||||
/// strings, but be consistent.
|
||||
///
|
||||
/// ## Options
|
||||
///
|
||||
/// * `flake8-quotes.inline-quotes`
|
||||
///
|
||||
/// ## Example
|
||||
@@ -67,7 +66,6 @@ define_violation!(
|
||||
/// strings, but be consistent.
|
||||
///
|
||||
/// ## Options
|
||||
///
|
||||
/// * `flake8-quotes.multiline-quotes`
|
||||
///
|
||||
/// ## Example
|
||||
@@ -116,7 +114,6 @@ define_violation!(
|
||||
/// strings, but be consistent.
|
||||
///
|
||||
/// ## Options
|
||||
///
|
||||
/// * `flake8-quotes.docstring-quotes`
|
||||
///
|
||||
/// ## Example
|
||||
@@ -266,7 +263,7 @@ fn docstring(
|
||||
) -> Option<Diagnostic> {
|
||||
let quotes_settings = &settings.flake8_quotes;
|
||||
|
||||
let text = locator.slice_source_code_range(&Range::new(start, end));
|
||||
let text = locator.slice(&Range::new(start, end));
|
||||
let trivia: Trivia = text.into();
|
||||
|
||||
if trivia
|
||||
@@ -313,7 +310,7 @@ fn strings(
|
||||
let trivia = sequence
|
||||
.iter()
|
||||
.map(|(start, end)| {
|
||||
let text = locator.slice_source_code_range(&Range::new(*start, *end));
|
||||
let text = locator.slice(&Range::new(*start, *end));
|
||||
let trivia: Trivia = text.into();
|
||||
trivia
|
||||
})
|
||||
|
||||
@@ -25,7 +25,7 @@ mod tests {
|
||||
#[test_case(Rule::SuperfluousElseContinue, Path::new("RET507.py"); "RET507")]
|
||||
#[test_case(Rule::SuperfluousElseBreak, Path::new("RET508.py"); "RET508")]
|
||||
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_return").join(path).as_path(),
|
||||
&Settings::for_rule(rule_code),
|
||||
|
||||
@@ -423,13 +423,7 @@ fn superfluous_elif(checker: &mut Checker, stack: &Stack) -> bool {
|
||||
|
||||
/// RET505, RET506, RET507, RET508
|
||||
fn superfluous_else(checker: &mut Checker, stack: &Stack) -> bool {
|
||||
for stmt in &stack.ifs {
|
||||
let StmtKind::If { orelse, .. } = &stmt.node else {
|
||||
continue;
|
||||
};
|
||||
if orelse.is_empty() {
|
||||
continue;
|
||||
}
|
||||
for stmt in &stack.elses {
|
||||
if superfluous_else_node(checker, stmt, Branch::Else) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::ast::visitor::Visitor;
|
||||
pub struct Stack<'a> {
|
||||
pub returns: Vec<(&'a Stmt, Option<&'a Expr>)>,
|
||||
pub yields: Vec<&'a Expr>,
|
||||
pub ifs: Vec<&'a Stmt>,
|
||||
pub elses: Vec<&'a Stmt>,
|
||||
pub elifs: Vec<&'a Stmt>,
|
||||
pub refs: FxHashMap<&'a str, Vec<Location>>,
|
||||
pub non_locals: FxHashSet<&'a str>,
|
||||
@@ -20,6 +20,7 @@ pub struct Stack<'a> {
|
||||
#[derive(Default)]
|
||||
pub struct ReturnVisitor<'a> {
|
||||
pub stack: Stack<'a>,
|
||||
parents: Vec<&'a Stmt>,
|
||||
}
|
||||
|
||||
impl<'a> ReturnVisitor<'a> {
|
||||
@@ -72,16 +73,37 @@ impl<'a> Visitor<'a> for ReturnVisitor<'a> {
|
||||
self.stack
|
||||
.returns
|
||||
.push((stmt, value.as_ref().map(|expr| &**expr)));
|
||||
|
||||
self.parents.push(stmt);
|
||||
visitor::walk_stmt(self, stmt);
|
||||
self.parents.pop();
|
||||
}
|
||||
StmtKind::If { orelse, .. } => {
|
||||
if orelse.len() == 1 && matches!(orelse.first().unwrap().node, StmtKind::If { .. })
|
||||
{
|
||||
self.stack.elifs.push(stmt);
|
||||
} else {
|
||||
self.stack.ifs.push(stmt);
|
||||
let is_elif_arm = self.parents.iter().any(|parent| {
|
||||
if let StmtKind::If { orelse, .. } = &parent.node {
|
||||
orelse.len() == 1 && &orelse[0] == stmt
|
||||
} else {
|
||||
false
|
||||
}
|
||||
});
|
||||
|
||||
if !is_elif_arm {
|
||||
let has_elif = orelse.len() == 1
|
||||
&& matches!(orelse.first().unwrap().node, StmtKind::If { .. });
|
||||
let has_else = !orelse.is_empty();
|
||||
|
||||
if has_elif {
|
||||
// `stmt` is an `if` block followed by an `elif` clause.
|
||||
self.stack.elifs.push(stmt);
|
||||
} else if has_else {
|
||||
// `stmt` is an `if` block followed by an `else` clause.
|
||||
self.stack.elses.push(stmt);
|
||||
}
|
||||
}
|
||||
|
||||
self.parents.push(stmt);
|
||||
visitor::walk_stmt(self, stmt);
|
||||
self.parents.pop();
|
||||
}
|
||||
StmtKind::Assign { targets, value, .. } => {
|
||||
if let ExprKind::Name { id, .. } = &value.node {
|
||||
@@ -109,16 +131,24 @@ impl<'a> Visitor<'a> for ReturnVisitor<'a> {
|
||||
self.stack
|
||||
.loops
|
||||
.push((stmt.location, stmt.end_location.unwrap()));
|
||||
|
||||
self.parents.push(stmt);
|
||||
visitor::walk_stmt(self, stmt);
|
||||
self.parents.pop();
|
||||
}
|
||||
StmtKind::Try { .. } => {
|
||||
self.stack
|
||||
.tries
|
||||
.push((stmt.location, stmt.end_location.unwrap()));
|
||||
|
||||
self.parents.push(stmt);
|
||||
visitor::walk_stmt(self, stmt);
|
||||
self.parents.pop();
|
||||
}
|
||||
_ => {
|
||||
self.parents.push(stmt);
|
||||
visitor::walk_stmt(self, stmt);
|
||||
self.parents.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,48 @@ use rustpython_parser::ast::{Expr, ExprKind};
|
||||
use ruff_macros::{define_violation, derive_message_formats};
|
||||
|
||||
use crate::ast::helpers::collect_call_path;
|
||||
use crate::ast::types::Range;
|
||||
use crate::ast::types::{BindingKind, Range, ScopeKind};
|
||||
use crate::checkers::ast::Checker;
|
||||
use crate::registry::Diagnostic;
|
||||
use crate::violation::Violation;
|
||||
|
||||
define_violation!(
|
||||
/// ## What it does
|
||||
/// Checks for accesses on "private" class members.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// In Python, the convention is such that class members that are prefixed
|
||||
/// with a single underscore, or prefixed but not suffixed with a double
|
||||
/// underscore, are considered private and intended for internal use.
|
||||
///
|
||||
/// Using such "private" members is considered a misuse of the class, as
|
||||
/// there are no guarantees that the member will be present in future
|
||||
/// versions, that it will have the same type, or that it will have the same
|
||||
/// behavior. Instead, use the class's public interface.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// class Class:
|
||||
/// def __init__(self):
|
||||
/// self._private_member = "..."
|
||||
///
|
||||
/// var = Class()
|
||||
/// print(var._private_member)
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// class Class:
|
||||
/// def __init__(self):
|
||||
/// self.public_member = "..."
|
||||
///
|
||||
/// var = Class()
|
||||
/// print(var.public_member)
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// * [_What is the meaning of single or double underscores before an object name?_](https://stackoverflow.com/questions/1301346/what-is-the-meaning-of-single-and-double-underscore-before-an-object-name)
|
||||
/// ```
|
||||
pub struct PrivateMemberAccess {
|
||||
pub access: String,
|
||||
}
|
||||
@@ -24,13 +60,17 @@ impl Violation for PrivateMemberAccess {
|
||||
/// SLF001
|
||||
pub fn private_member_access(checker: &mut Checker, expr: &Expr) {
|
||||
if let ExprKind::Attribute { value, attr, .. } = &expr.node {
|
||||
if !attr.ends_with("__") && (attr.starts_with('_') || attr.starts_with("__")) {
|
||||
if (attr.starts_with("__") && !attr.ends_with("__"))
|
||||
|| (attr.starts_with('_') && !attr.starts_with("__"))
|
||||
{
|
||||
if let ExprKind::Call { func, .. } = &value.node {
|
||||
// Ignore `super()` calls.
|
||||
let call_path = collect_call_path(func);
|
||||
if call_path.as_slice() == ["super"] {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Ignore `self` and `cls` accesses.
|
||||
let call_path = collect_call_path(value);
|
||||
if call_path.as_slice() == ["self"]
|
||||
|| call_path.as_slice() == ["cls"]
|
||||
@@ -38,6 +78,32 @@ pub fn private_member_access(checker: &mut Checker, expr: &Expr) {
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore accesses on class members from _within_ the class.
|
||||
if checker
|
||||
.scopes
|
||||
.iter()
|
||||
.rev()
|
||||
.find_map(|scope| match &scope.kind {
|
||||
ScopeKind::Class(class_def) => Some(class_def),
|
||||
_ => None,
|
||||
})
|
||||
.map_or(false, |class_def| {
|
||||
if call_path.as_slice() == [class_def.name] {
|
||||
checker
|
||||
.find_binding(class_def.name)
|
||||
.map_or(false, |binding| {
|
||||
// TODO(charlie): Could the name ever be bound to a _different_
|
||||
// class here?
|
||||
matches!(binding.kind, BindingKind::ClassDefinition)
|
||||
})
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
checker.diagnostics.push(Diagnostic::new(
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user