Compare commits
198 Commits
v0.1.8
...
simplify-S
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
827747ddcd | ||
|
|
e871037f7c | ||
|
|
957aba0be9 | ||
|
|
76e40b2ed3 | ||
|
|
f192c72596 | ||
|
|
25bafd2d66 | ||
|
|
7fc51d29c5 | ||
|
|
2d362e9366 | ||
|
|
501bc1c270 | ||
|
|
a4c6246ad7 | ||
|
|
14d3fe6bfa | ||
|
|
7e1309b854 | ||
|
|
4a3bb67b5f | ||
|
|
0ae19efe74 | ||
|
|
79f4abbb8d | ||
|
|
58fcd96ac1 | ||
|
|
ac02d3aedd | ||
|
|
6be73322da | ||
|
|
ad1ca72a35 | ||
|
|
381811b4a6 | ||
|
|
20af5a774f | ||
|
|
86b1ae9383 | ||
|
|
84ab21f073 | ||
|
|
985f1d10f6 | ||
|
|
f419af494f | ||
|
|
94968fedd5 | ||
|
|
ba71772d93 | ||
|
|
b1a5df8694 | ||
|
|
0c84782060 | ||
|
|
d9fc9702cf | ||
|
|
c58d1aa87d | ||
|
|
1d1824787b | ||
|
|
04afdf177b | ||
|
|
d5a439cbd3 | ||
|
|
63953431a6 | ||
|
|
f6841757eb | ||
|
|
1666c7a5cb | ||
|
|
e80b3db10d | ||
|
|
701697c37e | ||
|
|
c2c9997682 | ||
|
|
cee09765ef | ||
|
|
cde4a7d7bf | ||
|
|
62eca330a8 | ||
|
|
59078c5403 | ||
|
|
6bf6521197 | ||
|
|
c11f65381f | ||
|
|
6dfc1ccd6f | ||
|
|
60ba7a7c0d | ||
|
|
4b8b3a1ced | ||
|
|
967b2dcaf4 | ||
|
|
aaa00976ae | ||
|
|
328262bfac | ||
|
|
f0d43dafcf | ||
|
|
9a14f403c8 | ||
|
|
1293383cdc | ||
|
|
3b323a09cb | ||
|
|
5c93a524f1 | ||
|
|
e3ad163785 | ||
|
|
0e202718fd | ||
|
|
7b6baff734 | ||
|
|
1ffc738c84 | ||
|
|
dc5094d42a | ||
|
|
fd36754beb | ||
|
|
154d3b9f4b | ||
|
|
6c0734680e | ||
|
|
eac67a9464 | ||
|
|
fefc7e8199 | ||
|
|
973ae7e922 | ||
|
|
3fcc1402f6 | ||
|
|
08c60f513b | ||
|
|
38f4d9e335 | ||
|
|
f07d35051c | ||
|
|
2743387910 | ||
|
|
a268648c58 | ||
|
|
9073220887 | ||
|
|
0157cdb81a | ||
|
|
1f4dc12631 | ||
|
|
8db5bce92f | ||
|
|
d04d49cc0e | ||
|
|
cd0493db2a | ||
|
|
d0a1e201a3 | ||
|
|
0a0020583f | ||
|
|
6821b81d06 | ||
|
|
b3087849ee | ||
|
|
0c52710da5 | ||
|
|
a96c8db95c | ||
|
|
15f6213cb0 | ||
|
|
1f9353fed3 | ||
|
|
cea2ec8dd0 | ||
|
|
686abbc97a | ||
|
|
195f7c097a | ||
|
|
772e5d587d | ||
|
|
da8a3af524 | ||
|
|
b3789cd9e9 | ||
|
|
003851c41d | ||
|
|
1c9268d2ff | ||
|
|
158367bf91 | ||
|
|
48e04cc2c8 | ||
|
|
e80260a3c5 | ||
|
|
eb9a1bc5f1 | ||
|
|
c01bb0d485 | ||
|
|
fca9dc5ce2 | ||
|
|
94727996e8 | ||
|
|
97e9d3c54f | ||
|
|
2895e7d126 | ||
|
|
00f3c7d1d5 | ||
|
|
ec88acc291 | ||
|
|
d86d3bd0b6 | ||
|
|
375c175d53 | ||
|
|
57b6a8cedd | ||
|
|
f8fc309855 | ||
|
|
5d5f56d563 | ||
|
|
465f835cf9 | ||
|
|
edfad461a8 | ||
|
|
87086195c8 | ||
|
|
e178d938cc | ||
|
|
5d4825b60f | ||
|
|
c716acc7a6 | ||
|
|
50187016cb | ||
|
|
29513398d2 | ||
|
|
fa78d2d97c | ||
|
|
8b70240fa2 | ||
|
|
e85e0d45f3 | ||
|
|
9b43203575 | ||
|
|
bae3fa435d | ||
|
|
6e65601055 | ||
|
|
9d6444138b | ||
|
|
6d0c9c4e95 | ||
|
|
20def33fb7 | ||
|
|
506ffade6c | ||
|
|
5040fb8cec | ||
|
|
09ac0f9e72 | ||
|
|
34d7584ca3 | ||
|
|
097d0a4322 | ||
|
|
9a672ec112 | ||
|
|
7a109164a6 | ||
|
|
74dba3ee59 | ||
|
|
cdea7d71a3 | ||
|
|
bb86d359d4 | ||
|
|
9cc257ee7d | ||
|
|
a06723da2b | ||
|
|
fa2c37b411 | ||
|
|
3cc719bd74 | ||
|
|
d835b28d01 | ||
|
|
1e7bc1dffe | ||
|
|
e241c1c5df | ||
|
|
b0ae1199e8 | ||
|
|
a9ceef5b5d | ||
|
|
a3e06e5a9d | ||
|
|
3c2b800d26 | ||
|
|
0263f2715e | ||
|
|
c6d8076034 | ||
|
|
8cb7950102 | ||
|
|
ef4bd8d5ff | ||
|
|
5d41c84ef7 | ||
|
|
cbe3bf9bde | ||
|
|
4b4160eb48 | ||
|
|
29846f5b09 | ||
|
|
07b293d949 | ||
|
|
5ccc21aea2 | ||
|
|
f5d4019c2b | ||
|
|
bc0bf6f41c | ||
|
|
a2bc635584 | ||
|
|
09296e3e3c | ||
|
|
7c894921df | ||
|
|
be8f8e62b5 | ||
|
|
c97d3ddafb | ||
|
|
a7514295c1 | ||
|
|
0bf7683a3f | ||
|
|
c532089fb3 | ||
|
|
0977fa987b | ||
|
|
b4e101e157 | ||
|
|
2345cf1ec9 | ||
|
|
7489e6b881 | ||
|
|
02f8cc9ad3 | ||
|
|
0854f8cfa4 | ||
|
|
6feea863a6 | ||
|
|
2643f74a5d | ||
|
|
c944d23053 | ||
|
|
93d8c56d41 | ||
|
|
a336c1bc95 | ||
|
|
85b27a994f | ||
|
|
0029b4fd07 | ||
|
|
2c6b534e1f | ||
|
|
6ecf844214 | ||
|
|
82731b8194 | ||
|
|
cd3c2f773f | ||
|
|
3ce145c476 | ||
|
|
db38078ca3 | ||
|
|
c8d6958d15 | ||
|
|
25b2361411 | ||
|
|
d1a7bc38ff | ||
|
|
6c224cec52 | ||
|
|
189e947808 | ||
|
|
28b1aa201b | ||
|
|
c99eae2c08 | ||
|
|
7256b882b9 | ||
|
|
b8fc006e52 |
4
.github/dependabot.yml
vendored
4
.github/dependabot.yml
vendored
@@ -5,6 +5,10 @@ updates:
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
labels: ["internal"]
|
||||
groups:
|
||||
actions:
|
||||
patterns:
|
||||
- "*"
|
||||
|
||||
- package-ecosystem: "cargo"
|
||||
directory: "/"
|
||||
|
||||
8
.github/workflows/ci.yaml
vendored
8
.github/workflows/ci.yaml
vendored
@@ -95,9 +95,9 @@ jobs:
|
||||
rustup target add wasm32-unknown-unknown
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- name: "Clippy"
|
||||
run: cargo clippy --workspace --all-targets --all-features -- -D warnings
|
||||
run: cargo clippy --workspace --all-targets --all-features --locked -- -D warnings
|
||||
- name: "Clippy (wasm)"
|
||||
run: cargo clippy -p ruff_wasm --target wasm32-unknown-unknown --all-features -- -D warnings
|
||||
run: cargo clippy -p ruff_wasm --target wasm32-unknown-unknown --all-features --locked -- -D warnings
|
||||
|
||||
cargo-test-linux:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -180,7 +180,7 @@ jobs:
|
||||
- name: "Install cargo-fuzz"
|
||||
uses: taiki-e/install-action@v2
|
||||
with:
|
||||
tool: cargo-fuzz@0.11
|
||||
tool: cargo-fuzz@0.11.2
|
||||
- run: cargo fuzz build -s none
|
||||
|
||||
scripts:
|
||||
@@ -226,7 +226,7 @@ jobs:
|
||||
name: ruff
|
||||
path: target/debug
|
||||
|
||||
- uses: dawidd6/action-download-artifact@v2
|
||||
- uses: dawidd6/action-download-artifact@v3
|
||||
name: Download baseline Ruff binary
|
||||
with:
|
||||
name: ruff
|
||||
|
||||
247
.github/workflows/flake8-to-ruff.yaml
vendored
247
.github/workflows/flake8-to-ruff.yaml
vendored
@@ -1,247 +0,0 @@
|
||||
name: "[flake8-to-ruff] Release"
|
||||
|
||||
on: workflow_dispatch
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
PACKAGE_NAME: flake8-to-ruff
|
||||
CRATE_NAME: flake8_to_ruff
|
||||
PYTHON_VERSION: "3.11"
|
||||
CARGO_INCREMENTAL: 0
|
||||
CARGO_NET_RETRY: 10
|
||||
CARGO_TERM_COLOR: always
|
||||
RUSTUP_MAX_RETRIES: 10
|
||||
|
||||
jobs:
|
||||
macos-x86_64:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
architecture: x64
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup show
|
||||
- name: "Build wheels - x86_64"
|
||||
uses: PyO3/maturin-action@v1
|
||||
with:
|
||||
target: x86_64
|
||||
args: --release --out dist --sdist -m ./${{ env.CRATE_NAME }}/Cargo.toml
|
||||
- name: "Install built wheel - 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
|
||||
macos-universal:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
architecture: x64
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup show
|
||||
- name: "Build wheels - universal2"
|
||||
uses: PyO3/maturin-action@v1
|
||||
with:
|
||||
args: --release --target universal2-apple-darwin --out dist -m ./${{ env.CRATE_NAME }}/Cargo.toml
|
||||
- name: "Install built wheel - universal2"
|
||||
run: |
|
||||
pip install dist/${{ env.CRATE_NAME }}-*universal2.whl --force-reinstall
|
||||
- name: "Upload wheels"
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: wheels
|
||||
path: dist
|
||||
|
||||
windows:
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
matrix:
|
||||
target: [x64, x86]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
architecture: ${{ matrix.target }}
|
||||
- name: "Install Rust toolchain"
|
||||
run: rustup show
|
||||
- name: "Build wheels"
|
||||
uses: PyO3/maturin-action@v1
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
args: --release --out dist -m ./${{ env.CRATE_NAME }}/Cargo.toml
|
||||
- name: "Install built wheel"
|
||||
shell: bash
|
||||
run: |
|
||||
python -m pip install dist/${{ env.CRATE_NAME }}-*.whl --force-reinstall
|
||||
- name: "Upload wheels"
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: wheels
|
||||
path: dist
|
||||
|
||||
linux:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
target: [x86_64, i686]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
architecture: x64
|
||||
- name: "Build wheels"
|
||||
uses: PyO3/maturin-action@v1
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
manylinux: auto
|
||||
args: --release --out dist -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
|
||||
|
||||
linux-cross:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
target: [aarch64, armv7, s390x, ppc64le, ppc64]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
- name: "Build wheels"
|
||||
uses: PyO3/maturin-action@v1
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
manylinux: auto
|
||||
args: --no-default-features --release --out dist -m ./${{ env.CRATE_NAME }}/Cargo.toml
|
||||
- uses: uraimo/run-on-arch-action@v2
|
||||
if: matrix.target != 'ppc64'
|
||||
name: Install built wheel
|
||||
with:
|
||||
arch: ${{ matrix.target }}
|
||||
distro: ubuntu20.04
|
||||
githubToken: ${{ github.token }}
|
||||
install: |
|
||||
apt-get update
|
||||
apt-get install -y --no-install-recommends python3 python3-pip
|
||||
pip3 install -U pip
|
||||
run: |
|
||||
pip3 install ${{ env.PACKAGE_NAME }} --no-index --find-links dist/ --force-reinstall
|
||||
- name: "Upload wheels"
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: wheels
|
||||
path: dist
|
||||
|
||||
musllinux:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
target:
|
||||
- x86_64-unknown-linux-musl
|
||||
- i686-unknown-linux-musl
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
architecture: x64
|
||||
- name: "Build wheels"
|
||||
uses: PyO3/maturin-action@v1
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
manylinux: musllinux_1_2
|
||||
args: --release --out dist -m ./${{ env.CRATE_NAME }}/Cargo.toml
|
||||
- name: "Install built wheel"
|
||||
if: matrix.target == 'x86_64-unknown-linux-musl'
|
||||
uses: addnab/docker-run-action@v3
|
||||
with:
|
||||
image: alpine:latest
|
||||
options: -v ${{ github.workspace }}:/io -w /io
|
||||
run: |
|
||||
apk add py3-pip
|
||||
pip3 install ${{ env.PACKAGE_NAME }} --no-index --find-links /io/dist/ --force-reinstall
|
||||
- name: "Upload wheels"
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: wheels
|
||||
path: dist
|
||||
|
||||
musllinux-cross:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
platform:
|
||||
- target: aarch64-unknown-linux-musl
|
||||
arch: aarch64
|
||||
- target: armv7-unknown-linux-musleabihf
|
||||
arch: armv7
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
- name: "Build wheels"
|
||||
uses: PyO3/maturin-action@v1
|
||||
with:
|
||||
target: ${{ matrix.platform.target }}
|
||||
manylinux: musllinux_1_2
|
||||
args: --release --out dist -m ./${{ env.CRATE_NAME }}/Cargo.toml
|
||||
- uses: uraimo/run-on-arch-action@v2
|
||||
name: Install built wheel
|
||||
with:
|
||||
arch: ${{ matrix.platform.arch }}
|
||||
distro: alpine_latest
|
||||
githubToken: ${{ github.token }}
|
||||
install: |
|
||||
apk add py3-pip
|
||||
run: |
|
||||
pip3 install ${{ env.PACKAGE_NAME }} --no-index --find-links dist/ --force-reinstall
|
||||
- name: "Upload wheels"
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: wheels
|
||||
path: dist
|
||||
|
||||
release:
|
||||
name: Release
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- macos-universal
|
||||
- macos-x86_64
|
||||
- windows
|
||||
- linux
|
||||
- linux-cross
|
||||
- musllinux
|
||||
- musllinux-cross
|
||||
steps:
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: wheels
|
||||
- uses: actions/setup-python@v5
|
||||
- name: "Publish to PyPi"
|
||||
env:
|
||||
TWINE_USERNAME: __token__
|
||||
TWINE_PASSWORD: ${{ secrets.FLAKE8_TO_RUFF_TOKEN }}
|
||||
run: |
|
||||
pip install --upgrade twine
|
||||
twine upload --skip-existing *
|
||||
4
.github/workflows/pr-comment.yaml
vendored
4
.github/workflows/pr-comment.yaml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
comment:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dawidd6/action-download-artifact@v2
|
||||
- uses: dawidd6/action-download-artifact@v3
|
||||
name: Download pull request number
|
||||
with:
|
||||
name: pr-number
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
echo "pr-number=$(<pr-number)" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- uses: dawidd6/action-download-artifact@v2
|
||||
- uses: dawidd6/action-download-artifact@v3
|
||||
name: "Download ecosystem results"
|
||||
id: download-ecosystem-result
|
||||
if: steps.pr-number.outputs.pr-number
|
||||
|
||||
14
.github/workflows/release.yaml
vendored
14
.github/workflows/release.yaml
vendored
@@ -73,7 +73,7 @@ jobs:
|
||||
uses: PyO3/maturin-action@v1
|
||||
with:
|
||||
target: x86_64
|
||||
args: --release --out dist
|
||||
args: --release --locked --out dist
|
||||
- name: "Test wheel - x86_64"
|
||||
run: |
|
||||
pip install dist/${{ env.PACKAGE_NAME }}-*.whl --force-reinstall
|
||||
@@ -112,7 +112,7 @@ jobs:
|
||||
- name: "Build wheels - universal2"
|
||||
uses: PyO3/maturin-action@v1
|
||||
with:
|
||||
args: --release --target universal2-apple-darwin --out dist
|
||||
args: --release --locked --target universal2-apple-darwin --out dist
|
||||
- name: "Test wheel - universal2"
|
||||
run: |
|
||||
pip install dist/${{ env.PACKAGE_NAME }}-*universal2.whl --force-reinstall
|
||||
@@ -161,7 +161,7 @@ jobs:
|
||||
uses: PyO3/maturin-action@v1
|
||||
with:
|
||||
target: ${{ matrix.platform.target }}
|
||||
args: --release --out dist
|
||||
args: --release --locked --out dist
|
||||
- name: "Test wheel"
|
||||
if: ${{ !startsWith(matrix.platform.target, 'aarch64') }}
|
||||
shell: bash
|
||||
@@ -210,7 +210,7 @@ jobs:
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
manylinux: auto
|
||||
args: --release --out dist
|
||||
args: --release --locked --out dist
|
||||
- name: "Test wheel"
|
||||
if: ${{ startsWith(matrix.target, 'x86_64') }}
|
||||
run: |
|
||||
@@ -269,7 +269,7 @@ jobs:
|
||||
target: ${{ matrix.platform.target }}
|
||||
manylinux: auto
|
||||
docker-options: ${{ matrix.platform.maturin_docker_options }}
|
||||
args: --release --out dist
|
||||
args: --release --locked --out dist
|
||||
- uses: uraimo/run-on-arch-action@v2
|
||||
if: matrix.platform.arch != 'ppc64'
|
||||
name: Test wheel
|
||||
@@ -324,7 +324,7 @@ jobs:
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
manylinux: musllinux_1_2
|
||||
args: --release --out dist
|
||||
args: --release --locked --out dist
|
||||
- name: "Test wheel"
|
||||
if: matrix.target == 'x86_64-unknown-linux-musl'
|
||||
uses: addnab/docker-run-action@v3
|
||||
@@ -379,7 +379,7 @@ jobs:
|
||||
with:
|
||||
target: ${{ matrix.platform.target }}
|
||||
manylinux: musllinux_1_2
|
||||
args: --release --out dist
|
||||
args: --release --locked --out dist
|
||||
docker-options: ${{ matrix.platform.maturin_docker_options }}
|
||||
- uses: uraimo/run-on-arch-action@v2
|
||||
name: Test wheel
|
||||
|
||||
@@ -1,5 +1,42 @@
|
||||
# Breaking Changes
|
||||
|
||||
## 0.1.9
|
||||
|
||||
### `site-packages` is now excluded by default ([#5513](https://github.com/astral-sh/ruff/pull/5513))
|
||||
|
||||
Ruff maintains a list of default exclusions, which now consists of the following patterns:
|
||||
|
||||
- `.bzr`
|
||||
- `.direnv`
|
||||
- `.eggs`
|
||||
- `.git-rewrite`
|
||||
- `.git`
|
||||
- `.hg`
|
||||
- `.ipynb_checkpoints`
|
||||
- `.mypy_cache`
|
||||
- `.nox`
|
||||
- `.pants.d`
|
||||
- `.pyenv`
|
||||
- `.pytest_cache`
|
||||
- `.pytype`
|
||||
- `.ruff_cache`
|
||||
- `.svn`
|
||||
- `.tox`
|
||||
- `.venv`
|
||||
- `.vscode`
|
||||
- `__pypackages__`
|
||||
- `_build`
|
||||
- `buck-out`
|
||||
- `build`
|
||||
- `dist`
|
||||
- `node_modules`
|
||||
- `site-packages`
|
||||
- `venv`
|
||||
|
||||
Previously, the `site-packages` directory was not excluded by default. While `site-packages` tends
|
||||
to be excluded anyway by virtue of the `.venv` exclusion, this may not be the case when using Ruff
|
||||
from VS Code outside a virtual environment.
|
||||
|
||||
## 0.1.0
|
||||
|
||||
### The deprecated `format` setting has been removed
|
||||
|
||||
125
CHANGELOG.md
125
CHANGELOG.md
@@ -1,10 +1,133 @@
|
||||
# Changelog
|
||||
|
||||
## 0.1.11
|
||||
|
||||
### Preview features
|
||||
|
||||
- \[`pylint`\] Implement `super-without-brackets` (`W0245`) ([#9257](https://github.com/astral-sh/ruff/pull/9257))
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- Check path string properly in `python -m ruff` invocations ([#9367](https://github.com/astral-sh/ruff/pull/9367))
|
||||
|
||||
### Documentation
|
||||
|
||||
- Tweak `relative-imports` message ([#9365](https://github.com/astral-sh/ruff/pull/9365))
|
||||
- Add fix safety note for `yield-in-for-loop` ([#9364](https://github.com/astral-sh/ruff/pull/9364))
|
||||
|
||||
## 0.1.10
|
||||
|
||||
### Preview features
|
||||
|
||||
- Improve `dummy_implementations` preview style formatting ([#9240](https://github.com/astral-sh/ruff/pull/9240))
|
||||
- Normalise Hex and unicode escape sequences in strings ([#9280](https://github.com/astral-sh/ruff/pull/9280))
|
||||
- Parenthesize long type annotations in annotated assignments ([#9210](https://github.com/astral-sh/ruff/pull/9210))
|
||||
- Parenthesize multi-context managers in `with` statements ([#9222](https://github.com/astral-sh/ruff/pull/9222))
|
||||
- \[`flake8-pyi`\] Implement `generator-return-from-iter-method` (`PYI058`) ([#9313](https://github.com/astral-sh/ruff/pull/9313))
|
||||
- \[`pylint`\] Implement `empty-comment` (`PLR2044`) ([#9174](https://github.com/astral-sh/ruff/pull/9174))
|
||||
- \[`refurb`\] Implement `bit-count` (`FURB161`) ([#9265](https://github.com/astral-sh/ruff/pull/9265))
|
||||
- \[`ruff`\] Add `never-union` rule to detect redundant `typing.NoReturn` and `typing.Never` ([#9217](https://github.com/astral-sh/ruff/pull/9217))
|
||||
|
||||
### CLI
|
||||
|
||||
- Add paths to TOML parse errors ([#9358](https://github.com/astral-sh/ruff/pull/9358))
|
||||
- Add row and column numbers to formatter parse errors ([#9321](https://github.com/astral-sh/ruff/pull/9321))
|
||||
- Improve responsiveness when invoked via Python ([#9315](https://github.com/astral-sh/ruff/pull/9315))
|
||||
- Short rule messages should not end with a period ([#9345](https://github.com/astral-sh/ruff/pull/9345))
|
||||
|
||||
### Configuration
|
||||
|
||||
- Respect runtime-required decorators on functions ([#9317](https://github.com/astral-sh/ruff/pull/9317))
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- Avoid `asyncio-dangling-task` for nonlocal and global bindings ([#9263](https://github.com/astral-sh/ruff/pull/9263))
|
||||
- Escape trailing placeholders in rule documentation ([#9301](https://github.com/astral-sh/ruff/pull/9301))
|
||||
- Fix continuation detection following multi-line strings ([#9332](https://github.com/astral-sh/ruff/pull/9332))
|
||||
- Fix scoping for generators in named expressions in classes ([#9248](https://github.com/astral-sh/ruff/pull/9248))
|
||||
- Port from obsolete wsl crate to is-wsl ([#9356](https://github.com/astral-sh/ruff/pull/9356))
|
||||
- Remove special pre-visit for module docstrings ([#9261](https://github.com/astral-sh/ruff/pull/9261))
|
||||
- Respect `__str__` definitions from super classes ([#9338](https://github.com/astral-sh/ruff/pull/9338))
|
||||
- Respect `unused-noqa` via `per-file-ignores` ([#9300](https://github.com/astral-sh/ruff/pull/9300))
|
||||
- Respect attribute chains when resolving builtin call paths ([#9309](https://github.com/astral-sh/ruff/pull/9309))
|
||||
- Treat all `typing_extensions` members as typing aliases ([#9335](https://github.com/astral-sh/ruff/pull/9335))
|
||||
- Use `Display` for formatter parse errors ([#9316](https://github.com/astral-sh/ruff/pull/9316))
|
||||
- Wrap subscripted dicts in parens for f-string conversion ([#9238](https://github.com/astral-sh/ruff/pull/9238))
|
||||
- \[`flake8-annotations`\] Avoid adding return types to stub methods ([#9277](https://github.com/astral-sh/ruff/pull/9277))
|
||||
- \[`flake8-annotations`\] Respect mixed `return` and `raise` cases in return-type analysis ([#9310](https://github.com/astral-sh/ruff/pull/9310))
|
||||
- \[`flake8-bandit`\] Don't report violations when `SafeLoader` is imported from `yaml.loader` (`S506`) ([#9299](https://github.com/astral-sh/ruff/pull/9299))
|
||||
- \[`pylint`\] Avoid panic when comment is preceded by Unicode ([#9331](https://github.com/astral-sh/ruff/pull/9331))
|
||||
- \[`pylint`\] Change `PLR0917` error message to match other `PLR09XX` messages ([#9308](https://github.com/astral-sh/ruff/pull/9308))
|
||||
- \[`refurb`\] Avoid false positives for `math-constant` (`FURB152`) ([#9290](https://github.com/astral-sh/ruff/pull/9290))
|
||||
|
||||
### Documentation
|
||||
|
||||
- Expand target name for better rule documentation ([#9302](https://github.com/astral-sh/ruff/pull/9302))
|
||||
- Fix typos found by codespell ([#9346](https://github.com/astral-sh/ruff/pull/9346))
|
||||
- \[`perflint`\] Document `PERF102` fix un-safety ([#9351](https://github.com/astral-sh/ruff/pull/9351))
|
||||
- \[`pyupgrade`\] Document `UP007` fix un-safety ([#9306](https://github.com/astral-sh/ruff/pull/9306))
|
||||
|
||||
## 0.1.9
|
||||
|
||||
### Breaking changes
|
||||
|
||||
- Add site-packages to default exclusions ([#9188](https://github.com/astral-sh/ruff/pull/9188))
|
||||
|
||||
### Preview features
|
||||
|
||||
- Fix: Avoid parenthesizing subscript targets and values ([#9209](https://github.com/astral-sh/ruff/pull/9209))
|
||||
- \[`pylint`\] Implement `too-many-locals` (`PLR0914`) ([#9163](https://github.com/astral-sh/ruff/pull/9163))
|
||||
- Implement `reimplemented_operator` (FURB118) ([#9171](https://github.com/astral-sh/ruff/pull/9171))
|
||||
- Add a rule to detect string members in runtime-evaluated unions ([#9143](https://github.com/astral-sh/ruff/pull/9143))
|
||||
- Implement `no_blank_line_before_class_docstring` preview style ([#9154](https://github.com/astral-sh/ruff/pull/9154))
|
||||
|
||||
### Rule changes
|
||||
|
||||
- `CONSTANT_CASE` variables are improperly flagged for yoda violation (`SIM300`) ([#9164](https://github.com/astral-sh/ruff/pull/9164))
|
||||
- \[`flake8-pyi`\] Cover ParamSpecs and TypeVarTuples (`PYI018`) ([#9198](https://github.com/astral-sh/ruff/pull/9198))
|
||||
- \[`flake8-bugbear`\] Add fix for `zip-without-explicit-strict` (`B905`) ([#9176](https://github.com/astral-sh/ruff/pull/9176))
|
||||
- Add fix to automatically remove `print` and `pprint` statements (`T201`, `T203`) ([#9208](https://github.com/astral-sh/ruff/pull/9208))
|
||||
- Prefer `Never` to `NoReturn` in auto-typing in Python >= 3.11 (`ANN201`) ([#9213](https://github.com/astral-sh/ruff/pull/9213))
|
||||
|
||||
### Formatter
|
||||
|
||||
- `can_omit_optional_parentheses`: Exit early for unparenthesized expressions ([#9125](https://github.com/astral-sh/ruff/pull/9125))
|
||||
- Fix `dynamic` mode with doctests so that it doesn't exceed configured line width ([#9129](https://github.com/astral-sh/ruff/pull/9129))
|
||||
- Fix `can_omit_optional_parentheses` for expressions with a right most fstring ([#9124](https://github.com/astral-sh/ruff/pull/9124))
|
||||
- Add `target_version` to formatter options ([#9220](https://github.com/astral-sh/ruff/pull/9220))
|
||||
|
||||
### CLI
|
||||
|
||||
- Update `ruff format --check` to display message for already formatted files ([#9153](https://github.com/astral-sh/ruff/pull/9153))
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- Reverse order of arguments for `operator.contains` ([#9192](https://github.com/astral-sh/ruff/pull/9192))
|
||||
- Iterate over lambdas in deferred type annotations ([#9175](https://github.com/astral-sh/ruff/pull/9175))
|
||||
- Fix panic in `D208` with multibyte indent ([#9147](https://github.com/astral-sh/ruff/pull/9147))
|
||||
- Add support for `NoReturn` in auto-return-typing ([#9206](https://github.com/astral-sh/ruff/pull/9206))
|
||||
- Allow removal of `typing` from `exempt-modules` ([#9214](https://github.com/astral-sh/ruff/pull/9214))
|
||||
- Avoid `mutable-class-default` violations for Pydantic subclasses ([#9187](https://github.com/astral-sh/ruff/pull/9187))
|
||||
- Fix dropped union expressions for piped non-types in `PYI055` autofix ([#9161](https://github.com/astral-sh/ruff/pull/9161))
|
||||
- Enable annotation quoting for multi-line expressions ([#9142](https://github.com/astral-sh/ruff/pull/9142))
|
||||
- Deduplicate edits when quoting annotations ([#9140](https://github.com/astral-sh/ruff/pull/9140))
|
||||
- Prevent invalid utf8 indexing in cell magic detection ([#9146](https://github.com/astral-sh/ruff/pull/9146))
|
||||
- Avoid nested quotations in auto-quoting fix ([#9168](https://github.com/astral-sh/ruff/pull/9168))
|
||||
- Add base-class inheritance detection to flake8-django rules ([#9151](https://github.com/astral-sh/ruff/pull/9151))
|
||||
- Avoid `asyncio-dangling-task` violations on shadowed bindings ([#9215](https://github.com/astral-sh/ruff/pull/9215))
|
||||
|
||||
### Documentation
|
||||
|
||||
- Fix blog post URL in changelog ([#9119](https://github.com/astral-sh/ruff/pull/9119))
|
||||
- Add error suppression hint for multi-line strings ([#9205](https://github.com/astral-sh/ruff/pull/9205))
|
||||
- Fix typo in SemanticModel.parent_expression docstring ([#9167](https://github.com/astral-sh/ruff/pull/9167))
|
||||
- Document link between import sorting and formatter ([#9117](https://github.com/astral-sh/ruff/pull/9117))
|
||||
|
||||
## 0.1.8
|
||||
|
||||
This release includes opt-in support for formatting Python snippets within
|
||||
docstrings via the `docstring-code-format` setting.
|
||||
[Check out the blog post](https://astral.sh/blog/v0.1.8) for more details!
|
||||
[Check out the blog post](https://astral.sh/blog/ruff-v0.1.8) for more details!
|
||||
|
||||
### Preview features
|
||||
|
||||
|
||||
@@ -326,16 +326,18 @@ We use an experimental in-house tool for managing releases.
|
||||
- Often labels will be missing from pull requests they will need to be manually organized into the proper section
|
||||
- Changes should be edited to be user-facing descriptions, avoiding internal details
|
||||
1. Highlight any breaking changes in `BREAKING_CHANGES.md`
|
||||
1. Run `cargo check`. This should update the lock file with new versions.
|
||||
1. Create a pull request with the changelog and version updates
|
||||
1. Merge the PR
|
||||
1. Run the release workflow with the version number (without starting `v`) as input. Make sure
|
||||
main has your merged PR as last commit
|
||||
1. Run the [release workflow](https://github.com/astral-sh/ruff/actions/workflows/release.yaml) with:
|
||||
- The new version number (without starting `v`)
|
||||
- The commit hash of the merged release pull request on `main`
|
||||
1. The release workflow will do the following:
|
||||
1. Build all the assets. If this fails (even though we tested in step 4), we haven't tagged or
|
||||
uploaded anything, you can restart after pushing a fix.
|
||||
1. Upload to PyPI.
|
||||
1. Create and push the Git tag (as extracted from `pyproject.toml`). We create the Git tag only
|
||||
after building the wheels and uploading to PyPI, since we can't delete or modify the tag ([#4468](https://github.com/charliermarsh/ruff/issues/4468)).
|
||||
after building the wheels and uploading to PyPI, since we can't delete or modify the tag ([#4468](https://github.com/astral-sh/ruff/issues/4468)).
|
||||
1. Attach artifacts to draft GitHub release
|
||||
1. Trigger downstream repositories. This can fail non-catastrophically, as we can run any
|
||||
downstream jobs manually if needed.
|
||||
@@ -344,7 +346,10 @@ We use an experimental in-house tool for managing releases.
|
||||
1. Copy the changelog for the release into the GitHub release
|
||||
- See previous releases for formatting of section headers
|
||||
1. Generate the contributor list with `rooster contributors` and add to the release notes
|
||||
1. If needed, [update the schemastore](https://github.com/charliermarsh/ruff/blob/main/scripts/update_schemastore.py)
|
||||
1. If needed, [update the schemastore](https://github.com/astral-sh/ruff/blob/main/scripts/update_schemastore.py).
|
||||
1. One can determine if an update is needed when
|
||||
`git diff old-version-tag new-version-tag -- ruff.schema.json` returns a non-empty diff.
|
||||
1. Once run successfully, you should follow the link in the output to create a PR.
|
||||
1. If needed, update the `ruff-lsp` and `ruff-vscode` repositories.
|
||||
|
||||
## Ecosystem CI
|
||||
@@ -365,7 +370,7 @@ See the [ruff-ecosystem package](https://github.com/astral-sh/ruff/tree/main/pyt
|
||||
We have several ways of benchmarking and profiling Ruff:
|
||||
|
||||
- Our main performance benchmark comparing Ruff with other tools on the CPython codebase
|
||||
- Microbenchmarks which the linter or the formatter on individual files. There run on pull requests.
|
||||
- Microbenchmarks which run the linter or the formatter on individual files. These run on pull requests.
|
||||
- Profiling the linter on either the microbenchmarks or entire projects
|
||||
|
||||
### CPython Benchmark
|
||||
@@ -556,10 +561,10 @@ examples.
|
||||
|
||||
#### Linux
|
||||
|
||||
Install `perf` and build `ruff_benchmark` with the `release-debug` profile and then run it with perf
|
||||
Install `perf` and build `ruff_benchmark` with the `profiling` profile and then run it with perf
|
||||
|
||||
```shell
|
||||
cargo bench -p ruff_benchmark --no-run --profile=release-debug && perf record --call-graph dwarf -F 9999 cargo bench -p ruff_benchmark --profile=release-debug -- --profile-time=1
|
||||
cargo bench -p ruff_benchmark --no-run --profile=profiling && perf record --call-graph dwarf -F 9999 cargo bench -p ruff_benchmark --profile=profiling -- --profile-time=1
|
||||
```
|
||||
|
||||
You can also use the `ruff_dev` launcher to run `ruff check` multiple times on a repository to
|
||||
@@ -567,8 +572,8 @@ gather enough samples for a good flamegraph (change the 999, the sample rate, an
|
||||
of checks, to your liking)
|
||||
|
||||
```shell
|
||||
cargo build --bin ruff_dev --profile=release-debug
|
||||
perf record -g -F 999 target/release-debug/ruff_dev repeat --repeat 30 --exit-zero --no-cache path/to/cpython > /dev/null
|
||||
cargo build --bin ruff_dev --profile=profiling
|
||||
perf record -g -F 999 target/profiling/ruff_dev repeat --repeat 30 --exit-zero --no-cache path/to/cpython > /dev/null
|
||||
```
|
||||
|
||||
Then convert the recorded profile
|
||||
@@ -598,7 +603,7 @@ cargo install cargo-instruments
|
||||
Then run the profiler with
|
||||
|
||||
```shell
|
||||
cargo instruments -t time --bench linter --profile release-debug -p ruff_benchmark -- --profile-time=1
|
||||
cargo instruments -t time --bench linter --profile profiling -p ruff_benchmark -- --profile-time=1
|
||||
```
|
||||
|
||||
- `-t`: Specifies what to profile. Useful options are `time` to profile the wall time and `alloc`
|
||||
|
||||
388
Cargo.lock
generated
388
Cargo.lock
generated
@@ -123,9 +123,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.75"
|
||||
version = "1.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
||||
checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
|
||||
|
||||
[[package]]
|
||||
name = "argfile"
|
||||
@@ -234,9 +234,9 @@ checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
|
||||
|
||||
[[package]]
|
||||
name = "cachedir"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e236bf5873ea57ec2877445297f4da008916bfae51567131acfc54a073d694f3"
|
||||
checksum = "4703f3937077db8fa35bee3c8789343c1aec2585f0146f09d658d4ccc0e8d873"
|
||||
dependencies = [
|
||||
"tempfile",
|
||||
]
|
||||
@@ -312,9 +312,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.4.7"
|
||||
version = "4.4.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac495e00dcec98c83465d5ad66c5c4fabd652fd6686e7c6269b117e729a6f17b"
|
||||
checksum = "52bdc885e4cacc7f7c9eedc1ef6da641603180c783c41a15c264944deeaab642"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@@ -322,9 +322,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.4.7"
|
||||
version = "4.4.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c77ed9a32a62e6ca27175d00d29d05ca32e396ea1eb5fb01d8256b669cec7663"
|
||||
checksum = "fb7fb5e4e979aec3be7791562fcba452f94ad85e954da024396433e0e25a79e9"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -382,7 +382,7 @@ dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.40",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -434,21 +434,14 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||
|
||||
[[package]]
|
||||
name = "colored"
|
||||
version = "2.0.4"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6"
|
||||
checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8"
|
||||
dependencies = [
|
||||
"is-terminal",
|
||||
"lazy_static",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "configparser"
|
||||
version = "3.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0e56e414a2a52ab2a104f85cd40933c2fbc278b83637facf646ecf451b49237"
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.15.7"
|
||||
@@ -607,7 +600,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn 2.0.40",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -618,7 +611,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn 2.0.40",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -736,9 +729,9 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.10.0"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0"
|
||||
checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece"
|
||||
dependencies = [
|
||||
"humantime",
|
||||
"is-terminal",
|
||||
@@ -755,23 +748,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.3"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd"
|
||||
checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
|
||||
dependencies = [
|
||||
"errno-dragonfly",
|
||||
"libc",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno-dragonfly"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -807,30 +789,6 @@ version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.1.8"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"colored",
|
||||
"configparser",
|
||||
"itertools 0.11.0",
|
||||
"log",
|
||||
"once_cell",
|
||||
"pep440_rs",
|
||||
"pretty_assertions",
|
||||
"regex",
|
||||
"ruff_linter",
|
||||
"ruff_workspace",
|
||||
"rustc-hash",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"toml 0.7.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.27"
|
||||
@@ -998,17 +956,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ignore"
|
||||
version = "0.4.20"
|
||||
version = "0.4.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492"
|
||||
checksum = "747ad1b4ae841a78e8aba0d63adbfbeaea26b517b63705d47856b73015d27060"
|
||||
dependencies = [
|
||||
"crossbeam-deque",
|
||||
"globset",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"memchr",
|
||||
"regex",
|
||||
"regex-automata 0.4.3",
|
||||
"same-file",
|
||||
"thread_local",
|
||||
"walkdir",
|
||||
"winapi-util",
|
||||
]
|
||||
@@ -1122,16 +1079,24 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is-macro"
|
||||
version = "0.3.1"
|
||||
name = "is-docker"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc74b7abae208af9314a406bd7dcc65091230b6e749c09e07a645885fecf34f9"
|
||||
checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is-macro"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b75828adcb53122ef5ea649a39f50f82d94b754099bf6331b32e255e1891e8fb"
|
||||
dependencies = [
|
||||
"Inflector",
|
||||
"pmutil 0.6.1",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.40",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1145,6 +1110,16 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is-wsl"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5"
|
||||
dependencies = [
|
||||
"is-docker",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.5"
|
||||
@@ -1156,9 +1131,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.11.0"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
|
||||
checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
@@ -1264,9 +1239,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.149"
|
||||
version = "0.2.152"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b"
|
||||
checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
|
||||
|
||||
[[package]]
|
||||
name = "libcst"
|
||||
@@ -1311,9 +1286,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.10"
|
||||
version = "0.4.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f"
|
||||
checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
@@ -1482,9 +1457,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.18.0"
|
||||
version = "1.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||
|
||||
[[package]]
|
||||
name = "oorandom"
|
||||
@@ -1605,6 +1580,18 @@ dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pep440_rs"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0c29f9c43de378b4e4e0cd7dbcce0e5cfb80443de8c05620368b2948bc936a1"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"regex",
|
||||
"serde",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pep508_rs"
|
||||
version = "0.2.1"
|
||||
@@ -1612,7 +1599,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0713d7bb861ca2b7d4c50a38e1f31a4b63a2e2df35ef1e5855cc29e108453e2"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"pep440_rs",
|
||||
"pep440_rs 0.3.12",
|
||||
"regex",
|
||||
"serde",
|
||||
"thiserror",
|
||||
@@ -1690,17 +1677,6 @@ version = "0.2.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
|
||||
|
||||
[[package]]
|
||||
name = "pmutil"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3894e5d549cccbe44afecf72922f277f603cd4bb0219c8342631ef18fffbe004"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pmutil"
|
||||
version = "0.6.1"
|
||||
@@ -1709,7 +1685,7 @@ checksum = "52a40bc70c2c58040d2d8b167ba9a5ff59fc9dab7ad44771cfde3dcfde7a09c6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.40",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1794,9 +1770,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.70"
|
||||
version = "1.0.76"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
|
||||
checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -1808,10 +1784,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46d4a5e69187f23a29f8aa0ea57491d104ba541bc55f76552c2a74962aa20e04"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"pep440_rs",
|
||||
"pep440_rs 0.3.12",
|
||||
"pep508_rs",
|
||||
"serde",
|
||||
"toml 0.8.2",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1840,9 +1816,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.33"
|
||||
version = "1.0.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
||||
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
@@ -1993,24 +1969,23 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||
|
||||
[[package]]
|
||||
name = "result-like"
|
||||
version = "0.4.6"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ccc7ce6435c33898517a30e85578cd204cbb696875efb93dec19a2d31294f810"
|
||||
checksum = "abf7172fef6a7d056b5c26bf6c826570267562d51697f4982ff3ba4aec68a9df"
|
||||
dependencies = [
|
||||
"result-like-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "result-like-derive"
|
||||
version = "0.4.6"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fabf0a2e54f711c68c50d49f648a1a8a37adcb57353f518ac4df374f0788f42"
|
||||
checksum = "a8d6574c02e894d66370cfc681e5d68fedbc9a548fb55b30a96b3f0ae22d0fe5"
|
||||
dependencies = [
|
||||
"pmutil 0.5.3",
|
||||
"pmutil",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"syn-ext",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2055,7 +2030,7 @@ dependencies = [
|
||||
"filetime",
|
||||
"glob",
|
||||
"globset",
|
||||
"itertools 0.11.0",
|
||||
"itertools 0.12.0",
|
||||
"regex",
|
||||
"ruff_macros",
|
||||
"seahash",
|
||||
@@ -2063,9 +2038,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_cli"
|
||||
version = "0.1.8"
|
||||
version = "0.1.11"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.9.2",
|
||||
"anyhow",
|
||||
"argfile",
|
||||
"assert_cmd",
|
||||
@@ -2078,12 +2052,11 @@ dependencies = [
|
||||
"clearscreen",
|
||||
"colored",
|
||||
"filetime",
|
||||
"glob",
|
||||
"ignore",
|
||||
"insta",
|
||||
"insta-cmd",
|
||||
"is-macro",
|
||||
"itertools 0.11.0",
|
||||
"itertools 0.12.0",
|
||||
"log",
|
||||
"mimalloc",
|
||||
"notify",
|
||||
@@ -2092,14 +2065,11 @@ dependencies = [
|
||||
"regex",
|
||||
"ruff_cache",
|
||||
"ruff_diagnostics",
|
||||
"ruff_formatter",
|
||||
"ruff_linter",
|
||||
"ruff_macros",
|
||||
"ruff_notebook",
|
||||
"ruff_python_ast",
|
||||
"ruff_python_formatter",
|
||||
"ruff_python_stdlib",
|
||||
"ruff_python_trivia",
|
||||
"ruff_source_file",
|
||||
"ruff_text_size",
|
||||
"ruff_workspace",
|
||||
@@ -2107,14 +2077,12 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"shellexpand",
|
||||
"similar",
|
||||
"strum",
|
||||
"tempfile",
|
||||
"test-case",
|
||||
"thiserror",
|
||||
"tikv-jemallocator",
|
||||
"tracing",
|
||||
"ureq",
|
||||
"walkdir",
|
||||
"wild",
|
||||
]
|
||||
@@ -2129,7 +2097,7 @@ dependencies = [
|
||||
"imara-diff",
|
||||
"indicatif",
|
||||
"indoc",
|
||||
"itertools 0.11.0",
|
||||
"itertools 0.12.0",
|
||||
"libcst",
|
||||
"once_cell",
|
||||
"pretty_assertions",
|
||||
@@ -2143,7 +2111,6 @@ dependencies = [
|
||||
"ruff_python_ast",
|
||||
"ruff_python_codegen",
|
||||
"ruff_python_formatter",
|
||||
"ruff_python_literal",
|
||||
"ruff_python_parser",
|
||||
"ruff_python_stdlib",
|
||||
"ruff_python_trivia",
|
||||
@@ -2153,9 +2120,8 @@ dependencies = [
|
||||
"serde_json",
|
||||
"similar",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"tempfile",
|
||||
"toml 0.7.8",
|
||||
"toml",
|
||||
"tracing",
|
||||
"tracing-indicatif",
|
||||
"tracing-subscriber",
|
||||
@@ -2199,7 +2165,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_linter"
|
||||
version = "0.1.8"
|
||||
version = "0.1.11"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"annotate-snippets 0.9.2",
|
||||
@@ -2214,7 +2180,8 @@ dependencies = [
|
||||
"imperative",
|
||||
"insta",
|
||||
"is-macro",
|
||||
"itertools 0.11.0",
|
||||
"is-wsl",
|
||||
"itertools 0.12.0",
|
||||
"libcst",
|
||||
"log",
|
||||
"memchr",
|
||||
@@ -2222,7 +2189,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"path-absolutize",
|
||||
"pathdiff",
|
||||
"pep440_rs",
|
||||
"pep440_rs 0.4.0",
|
||||
"pretty_assertions",
|
||||
"pyproject-toml",
|
||||
"quick-junit",
|
||||
@@ -2255,23 +2222,22 @@ dependencies = [
|
||||
"tempfile",
|
||||
"test-case",
|
||||
"thiserror",
|
||||
"toml 0.7.8",
|
||||
"toml",
|
||||
"typed-arena",
|
||||
"unicode-width",
|
||||
"unicode_names2",
|
||||
"url",
|
||||
"wsl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff_macros"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"itertools 0.11.0",
|
||||
"itertools 0.12.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"ruff_python_trivia",
|
||||
"syn 2.0.40",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2280,8 +2246,9 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"insta",
|
||||
"itertools 0.11.0",
|
||||
"itertools 0.12.0",
|
||||
"once_cell",
|
||||
"rand",
|
||||
"ruff_diagnostics",
|
||||
"ruff_source_file",
|
||||
"ruff_text_size",
|
||||
@@ -2300,9 +2267,7 @@ dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"insta",
|
||||
"is-macro",
|
||||
"itertools 0.11.0",
|
||||
"memchr",
|
||||
"once_cell",
|
||||
"itertools 0.12.0",
|
||||
"ruff_python_parser",
|
||||
"ruff_python_trivia",
|
||||
"ruff_source_file",
|
||||
@@ -2333,7 +2298,7 @@ dependencies = [
|
||||
"clap",
|
||||
"countme",
|
||||
"insta",
|
||||
"itertools 0.11.0",
|
||||
"itertools 0.12.0",
|
||||
"memchr",
|
||||
"once_cell",
|
||||
"regex",
|
||||
@@ -2362,7 +2327,6 @@ dependencies = [
|
||||
name = "ruff_python_index"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"itertools 0.11.0",
|
||||
"ruff_python_ast",
|
||||
"ruff_python_parser",
|
||||
"ruff_python_trivia",
|
||||
@@ -2377,7 +2341,7 @@ dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"hexf-parse",
|
||||
"is-macro",
|
||||
"itertools 0.11.0",
|
||||
"itertools 0.12.0",
|
||||
"lexical-parse-float",
|
||||
"rand",
|
||||
"unic-ucd-category",
|
||||
@@ -2391,7 +2355,7 @@ dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"insta",
|
||||
"is-macro",
|
||||
"itertools 0.11.0",
|
||||
"itertools 0.12.0",
|
||||
"lalrpop",
|
||||
"lalrpop-util",
|
||||
"memchr",
|
||||
@@ -2442,8 +2406,9 @@ name = "ruff_python_trivia"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"insta",
|
||||
"itertools 0.11.0",
|
||||
"itertools 0.12.0",
|
||||
"ruff_python_ast",
|
||||
"ruff_python_index",
|
||||
"ruff_python_parser",
|
||||
"ruff_source_file",
|
||||
"ruff_text_size",
|
||||
@@ -2452,7 +2417,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff_shrinking"
|
||||
version = "0.1.8"
|
||||
version = "0.1.11"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@@ -2495,7 +2460,6 @@ dependencies = [
|
||||
"console_log",
|
||||
"js-sys",
|
||||
"log",
|
||||
"ruff_diagnostics",
|
||||
"ruff_formatter",
|
||||
"ruff_linter",
|
||||
"ruff_python_ast",
|
||||
@@ -2524,11 +2488,11 @@ dependencies = [
|
||||
"globset",
|
||||
"ignore",
|
||||
"is-macro",
|
||||
"itertools 0.11.0",
|
||||
"itertools 0.12.0",
|
||||
"log",
|
||||
"once_cell",
|
||||
"path-absolutize",
|
||||
"pep440_rs",
|
||||
"pep440_rs 0.4.0",
|
||||
"regex",
|
||||
"ruff_cache",
|
||||
"ruff_formatter",
|
||||
@@ -2543,7 +2507,7 @@ dependencies = [
|
||||
"shellexpand",
|
||||
"strum",
|
||||
"tempfile",
|
||||
"toml 0.7.8",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2564,15 +2528,15 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.21"
|
||||
version = "0.38.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3"
|
||||
checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316"
|
||||
dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2678,9 +2642,9 @@ checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.193"
|
||||
version = "1.0.195"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
|
||||
checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
@@ -2698,13 +2662,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.193"
|
||||
version = "1.0.195"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
|
||||
checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.40",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2720,9 +2684,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.108"
|
||||
version = "1.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
|
||||
checksum = "cb0652c533506ad7a2e353cce269330d6afd8bdfb6d75e0ace5b35aacbd7b9e9"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
@@ -2731,9 +2695,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.3"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186"
|
||||
checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
@@ -2766,7 +2730,7 @@ dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.40",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2870,7 +2834,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn 2.0.40",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2886,35 +2850,26 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.40"
|
||||
version = "2.0.48"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13fa70a4ee923979ffb522cacce59d34421ebdea5625e1073c4326ef9d2dd42e"
|
||||
checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn-ext"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b86cb2b68c5b3c078cac02588bc23f3c04bb828c5d3aedd17980876ec6a7be6"
|
||||
dependencies = [
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.8.1"
|
||||
version = "3.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5"
|
||||
checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"redox_syscall 0.4.1",
|
||||
"rustix",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2958,9 +2913,9 @@ checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76"
|
||||
|
||||
[[package]]
|
||||
name = "test-case"
|
||||
version = "3.2.1"
|
||||
version = "3.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8f1e820b7f1d95a0cdbf97a5df9de10e1be731983ab943e56703ac1b8e9d425"
|
||||
checksum = "eb2550dd13afcd286853192af8601920d959b14c401fcece38071d53bf0768a8"
|
||||
dependencies = [
|
||||
"test-case-macros",
|
||||
]
|
||||
@@ -2975,7 +2930,7 @@ dependencies = [
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.40",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2987,28 +2942,28 @@ dependencies = [
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.40",
|
||||
"syn 2.0.48",
|
||||
"test-case-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.50"
|
||||
version = "1.0.51"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2"
|
||||
checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.50"
|
||||
version = "1.0.51"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
|
||||
checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.40",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3093,55 +3048,30 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.7.8"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257"
|
||||
checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_edit 0.19.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_edit 0.20.2",
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.3"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b"
|
||||
checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.19.15"
|
||||
version = "0.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338"
|
||||
checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
@@ -3170,7 +3100,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.40",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3185,9 +3115,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tracing-indicatif"
|
||||
version = "0.3.5"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57e05fe4a1c906d94b275d8aeb8ff8b9deaca502aeb59ae8ab500a92b8032ac8"
|
||||
checksum = "069580424efe11d97c3fef4197fa98c004fa26672cc71ad8770d224e23b1951d"
|
||||
dependencies = [
|
||||
"indicatif",
|
||||
"tracing",
|
||||
@@ -3307,9 +3237,9 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
||||
|
||||
[[package]]
|
||||
name = "unicode_names2"
|
||||
version = "1.2.0"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d5506ae2c3c1ccbdf468e52fc5ef536c2ccd981f01273a4cb81aa61021f3a5f"
|
||||
checksum = "ac64ef2f016dc69dfa8283394a70b057066eb054d5fcb6b9eb17bd2ec5097211"
|
||||
dependencies = [
|
||||
"phf",
|
||||
"unicode_names2_generator",
|
||||
@@ -3317,9 +3247,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "unicode_names2_generator"
|
||||
version = "1.2.0"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6dfc680313e95bc6637fa278cd7a22390c3c2cd7b8b2bd28755bc6c0fc811e7"
|
||||
checksum = "013f6a731e80f3930de580e55ba41dfa846de4e0fdee4a701f97989cb1597d6a"
|
||||
dependencies = [
|
||||
"getopts",
|
||||
"log",
|
||||
@@ -3388,7 +3318,7 @@ checksum = "f49e7f3f3db8040a100710a11932239fd30697115e2ba4107080d8252939845e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.40",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3482,15 +3412,15 @@ dependencies = [
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.40",
|
||||
"syn 2.0.48",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.38"
|
||||
version = "0.4.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02"
|
||||
checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
@@ -3516,7 +3446,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.40",
|
||||
"syn 2.0.48",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
@@ -3529,9 +3459,9 @@ checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-test"
|
||||
version = "0.3.38"
|
||||
version = "0.3.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6433b7c56db97397842c46b67e11873eda263170afeb3a2dc74a7cb370fee0d"
|
||||
checksum = "2cf9242c0d27999b831eae4767b2a146feb0b27d332d553e605864acd2afd403"
|
||||
dependencies = [
|
||||
"console_error_panic_hook",
|
||||
"js-sys",
|
||||
@@ -3543,13 +3473,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-test-macro"
|
||||
version = "0.3.38"
|
||||
version = "0.3.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "493fcbab756bb764fa37e6bee8cec2dd709eb4273d06d0c282a5e74275ded735"
|
||||
checksum = "794645f5408c9a039fd09f4d113cdfb2e7eba5ff1956b07bcf701cf4b394fe89"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.40",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3835,12 +3765,6 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wsl"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8dab7ac864710bdea6594becbea5b5050333cf34fefb0dc319567eb347950d4"
|
||||
|
||||
[[package]]
|
||||
name = "yaml-rust"
|
||||
version = "0.4.5"
|
||||
@@ -3882,5 +3806,5 @@ checksum = "be912bf68235a88fbefd1b73415cb218405958d1655b2ece9035a19920bdf6ba"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.40",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
108
Cargo.toml
108
Cargo.toml
@@ -12,48 +12,103 @@ authors = ["Charlie Marsh <charlie.r.marsh@gmail.com>"]
|
||||
license = "MIT"
|
||||
|
||||
[workspace.dependencies]
|
||||
anyhow = { version = "1.0.69" }
|
||||
aho-corasick = { version = "1.1.2" }
|
||||
annotate-snippets = { version = "0.9.2", features = ["color"] }
|
||||
anyhow = { version = "1.0.79" }
|
||||
argfile = { version = "0.1.6" }
|
||||
assert_cmd = { version = "2.0.8" }
|
||||
bincode = { version = "1.3.3" }
|
||||
bitflags = { version = "2.4.1" }
|
||||
cachedir = { version = "0.3.1" }
|
||||
chrono = { version = "0.4.31", default-features = false, features = ["clock"] }
|
||||
clap = { version = "4.4.7", features = ["derive"] }
|
||||
colored = { version = "2.0.0" }
|
||||
clap = { version = "4.4.13", features = ["derive"] }
|
||||
clap_complete_command = { version = "0.5.1" }
|
||||
clearscreen = { version = "2.0.0" }
|
||||
codspeed-criterion-compat = { version = "2.3.3", default-features = false }
|
||||
colored = { version = "2.1.0" }
|
||||
configparser = { version = "3.0.3" }
|
||||
console_error_panic_hook = { version = "0.1.7" }
|
||||
console_log = { version = "1.0.0" }
|
||||
countme = { version ="3.0.1"}
|
||||
criterion = { version = "0.5.1", default-features = false }
|
||||
dirs = { version = "5.0.0" }
|
||||
drop_bomb = { version = "0.1.5" }
|
||||
env_logger = { version ="0.10.1"}
|
||||
fern = { version = "0.6.1" }
|
||||
filetime = { version = "0.2.23" }
|
||||
fs-err = { version ="2.11.0"}
|
||||
glob = { version = "0.3.1" }
|
||||
globset = { version = "0.4.14" }
|
||||
ignore = { version = "0.4.20" }
|
||||
hexf-parse = { version ="0.2.1"}
|
||||
ignore = { version = "0.4.21" }
|
||||
imara-diff ={ version = "0.1.5"}
|
||||
imperative = { version = "1.0.4" }
|
||||
indicatif ={ version = "0.17.7"}
|
||||
indoc ={ version = "2.0.4"}
|
||||
insta = { version = "1.34.0", feature = ["filters", "glob"] }
|
||||
is-macro = { version = "0.3.1" }
|
||||
itertools = { version = "0.11.0" }
|
||||
insta-cmd = { version = "0.4.0" }
|
||||
is-macro = { version = "0.3.4" }
|
||||
is-wsl = { version = "0.4.0" }
|
||||
itertools = { version = "0.12.0" }
|
||||
js-sys = { version = "0.3.66" }
|
||||
lalrpop-util = { version = "0.20.0", default-features = false }
|
||||
lexical-parse-float = { version = "0.8.0", features = ["format"] }
|
||||
libcst = { version = "1.1.0", default-features = false }
|
||||
log = { version = "0.4.17" }
|
||||
memchr = { version = "2.6.4" }
|
||||
once_cell = { version = "1.17.1" }
|
||||
mimalloc = { version ="0.1.39"}
|
||||
natord = { version = "1.0.9" }
|
||||
notify = { version = "6.1.1" }
|
||||
once_cell = { version = "1.19.0" }
|
||||
path-absolutize = { version = "3.1.1" }
|
||||
proc-macro2 = { version = "1.0.70" }
|
||||
pathdiff = { version = "0.2.1" }
|
||||
pep440_rs = { version = "0.4.0", features = ["serde"] }
|
||||
pretty_assertions = "1.3.0"
|
||||
proc-macro2 = { version = "1.0.73" }
|
||||
pyproject-toml = { version = "0.8.1" }
|
||||
quick-junit = { version = "0.3.5" }
|
||||
quote = { version = "1.0.23" }
|
||||
rand = { version = "0.8.5" }
|
||||
rayon = { version = "1.8.0" }
|
||||
regex = { version = "1.10.2" }
|
||||
result-like = { version = "0.5.0" }
|
||||
rustc-hash = { version = "1.1.0" }
|
||||
schemars = { version = "0.8.16" }
|
||||
serde = { version = "1.0.193", features = ["derive"] }
|
||||
serde_json = { version = "1.0.108" }
|
||||
seahash = { version ="4.1.0"}
|
||||
semver = { version = "1.0.20" }
|
||||
serde = { version = "1.0.195", features = ["derive"] }
|
||||
serde-wasm-bindgen = { version = "0.6.3" }
|
||||
serde_json = { version = "1.0.109" }
|
||||
serde_test = { version = "1.0.152" }
|
||||
serde_with = { version = "3.4.0", default-features = false, features = ["macros"] }
|
||||
shellexpand = { version = "3.0.0" }
|
||||
shlex = { version ="1.2.0"}
|
||||
similar = { version = "2.3.0", features = ["inline"] }
|
||||
smallvec = { version = "1.11.2" }
|
||||
static_assertions = "1.1.0"
|
||||
strum = { version = "0.25.0", features = ["strum_macros"] }
|
||||
strum_macros = { version = "0.25.3" }
|
||||
syn = { version = "2.0.40" }
|
||||
test-case = { version = "3.2.1" }
|
||||
thiserror = { version = "1.0.50" }
|
||||
toml = { version = "0.7.8" }
|
||||
tempfile = { version ="3.9.0"}
|
||||
test-case = { version = "3.3.1" }
|
||||
thiserror = { version = "1.0.51" }
|
||||
tikv-jemallocator = { version ="0.5.0"}
|
||||
toml = { version = "0.8.8" }
|
||||
tracing = { version = "0.1.40" }
|
||||
tracing-indicatif = { version = "0.3.4" }
|
||||
tracing-indicatif = { version = "0.3.6" }
|
||||
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
||||
typed-arena = { version = "2.0.2" }
|
||||
unic-ucd-category = { version ="0.9"}
|
||||
unicode-ident = { version = "1.0.12" }
|
||||
unicode_names2 = { version = "1.2.0" }
|
||||
unicode-width = { version = "0.1.11" }
|
||||
unicode_names2 = { version = "1.2.1" }
|
||||
ureq = { version = "2.9.1" }
|
||||
url = { version = "2.5.0" }
|
||||
uuid = { version = "1.6.1", features = ["v4", "fast-rng", "macro-diagnostics", "js"] }
|
||||
wsl = { version = "0.1.0" }
|
||||
walkdir = { version = "2.3.2" }
|
||||
wasm-bindgen = { version = "0.2.84" }
|
||||
wasm-bindgen-test = { version = "0.3.39" }
|
||||
wild = { version = "2" }
|
||||
|
||||
[workspace.lints.rust]
|
||||
unsafe_code = "warn"
|
||||
@@ -88,7 +143,20 @@ rc_mutex = "warn"
|
||||
rest_pat_in_fully_bound_structs = "warn"
|
||||
|
||||
[profile.release]
|
||||
lto = "fat"
|
||||
# Note that we set these explicitly, and these values
|
||||
# were chosen based on a trade-off between compile times
|
||||
# and runtime performance[1].
|
||||
#
|
||||
# [1]: https://github.com/astral-sh/ruff/pull/9031
|
||||
lto = "thin"
|
||||
codegen-units = 16
|
||||
|
||||
# Some crates don't change as much but benefit more from
|
||||
# more expensive optimization passes, so we selectively
|
||||
# decrease codegen-units in some cases.
|
||||
[profile.release.package.ruff_python_parser]
|
||||
codegen-units = 1
|
||||
[profile.release.package.ruff_python_ast]
|
||||
codegen-units = 1
|
||||
|
||||
[profile.dev.package.insta]
|
||||
@@ -102,8 +170,8 @@ opt-level = 3
|
||||
[profile.dev.package.ruff_python_parser]
|
||||
opt-level = 1
|
||||
|
||||
# Use the `--profile release-debug` flag to show symbols in release mode.
|
||||
# e.g. `cargo build --profile release-debug`
|
||||
[profile.release-debug]
|
||||
# Use the `--profile profiling` flag to show symbols in release mode.
|
||||
# e.g. `cargo build --profile profiling`
|
||||
[profile.profiling]
|
||||
inherits = "release"
|
||||
debug = 1
|
||||
|
||||
11
README.md
11
README.md
@@ -150,7 +150,7 @@ Ruff can also be used as a [pre-commit](https://pre-commit.com/) hook via [`ruff
|
||||
```yaml
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: v0.1.8
|
||||
rev: v0.1.11
|
||||
hooks:
|
||||
# Run the linter.
|
||||
- id: ruff
|
||||
@@ -194,20 +194,25 @@ exclude = [
|
||||
".git",
|
||||
".git-rewrite",
|
||||
".hg",
|
||||
".ipynb_checkpoints",
|
||||
".mypy_cache",
|
||||
".nox",
|
||||
".pants.d",
|
||||
".pyenv",
|
||||
".pytest_cache",
|
||||
".pytype",
|
||||
".ruff_cache",
|
||||
".svn",
|
||||
".tox",
|
||||
".venv",
|
||||
".vscode",
|
||||
"__pypackages__",
|
||||
"_build",
|
||||
"buck-out",
|
||||
"build",
|
||||
"dist",
|
||||
"node_modules",
|
||||
"site-packages",
|
||||
"venv",
|
||||
]
|
||||
|
||||
@@ -381,6 +386,7 @@ Ruff is used by a number of major open-source projects and companies, including:
|
||||
- Benchling ([Refac](https://github.com/benchling/refac))
|
||||
- [Bokeh](https://github.com/bokeh/bokeh)
|
||||
- [Cryptography (PyCA)](https://github.com/pyca/cryptography)
|
||||
- CERN ([Indico](https://getindico.io/))
|
||||
- [DVC](https://github.com/iterative/dvc)
|
||||
- [Dagger](https://github.com/dagger/dagger)
|
||||
- [Dagster](https://github.com/dagster-io/dagster)
|
||||
@@ -412,6 +418,7 @@ Ruff is used by a number of major open-source projects and companies, including:
|
||||
- Netflix ([Dispatch](https://github.com/Netflix/dispatch))
|
||||
- [Neon](https://github.com/neondatabase/neon)
|
||||
- [NoneBot](https://github.com/nonebot/nonebot2)
|
||||
- [NumPyro](https://github.com/pyro-ppl/numpyro)
|
||||
- [ONNX](https://github.com/onnx/onnx)
|
||||
- [OpenBB](https://github.com/OpenBB-finance/OpenBBTerminal)
|
||||
- [PDM](https://github.com/pdm-project/pdm)
|
||||
@@ -423,10 +430,12 @@ Ruff is used by a number of major open-source projects and companies, including:
|
||||
- [PostHog](https://github.com/PostHog/posthog)
|
||||
- Prefect ([Python SDK](https://github.com/PrefectHQ/prefect), [Marvin](https://github.com/PrefectHQ/marvin))
|
||||
- [PyInstaller](https://github.com/pyinstaller/pyinstaller)
|
||||
- [PyMC](https://github.com/pymc-devs/pymc/)
|
||||
- [PyMC-Marketing](https://github.com/pymc-labs/pymc-marketing)
|
||||
- [PyTorch](https://github.com/pytorch/pytorch)
|
||||
- [Pydantic](https://github.com/pydantic/pydantic)
|
||||
- [Pylint](https://github.com/PyCQA/pylint)
|
||||
- [PyVista](https://github.com/pyvista/pyvista)
|
||||
- [Reflex](https://github.com/reflex-dev/reflex)
|
||||
- [River](https://github.com/online-ml/river)
|
||||
- [Rippling](https://rippling.com)
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
[package]
|
||||
name = "flake8-to-ruff"
|
||||
version = "0.1.8"
|
||||
description = """
|
||||
Convert Flake8 configuration files to Ruff configuration files.
|
||||
"""
|
||||
authors = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
rust-version = { workspace = true }
|
||||
homepage = { workspace = true }
|
||||
documentation = { workspace = true }
|
||||
repository = { workspace = true }
|
||||
license = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
ruff_linter = { path = "../ruff_linter", default-features = false }
|
||||
ruff_workspace = { path = "../ruff_workspace" }
|
||||
|
||||
anyhow = { workspace = true }
|
||||
clap = { workspace = true }
|
||||
colored = { workspace = true }
|
||||
configparser = { version = "3.0.3" }
|
||||
itertools = { workspace = true }
|
||||
log = { workspace = true }
|
||||
once_cell = { workspace = true }
|
||||
pep440_rs = { version = "0.3.12", features = ["serde"] }
|
||||
regex = { workspace = true }
|
||||
rustc-hash = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
strum = { workspace = true }
|
||||
strum_macros = { workspace = true }
|
||||
toml = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "1.3.0"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
@@ -1,99 +0,0 @@
|
||||
# flake8-to-ruff
|
||||
|
||||
Convert existing Flake8 configuration files (`setup.cfg`, `tox.ini`, or `.flake8`) for use with
|
||||
[Ruff](https://github.com/astral-sh/ruff).
|
||||
|
||||
Generates a Ruff-compatible `pyproject.toml` section.
|
||||
|
||||
## Installation and Usage
|
||||
|
||||
### Installation
|
||||
|
||||
Available as [`flake8-to-ruff`](https://pypi.org/project/flake8-to-ruff/) on PyPI:
|
||||
|
||||
```shell
|
||||
pip install flake8-to-ruff
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
To run `flake8-to-ruff`:
|
||||
|
||||
```shell
|
||||
flake8-to-ruff path/to/setup.cfg
|
||||
flake8-to-ruff path/to/tox.ini
|
||||
flake8-to-ruff path/to/.flake8
|
||||
```
|
||||
|
||||
`flake8-to-ruff` will print the relevant `pyproject.toml` sections to standard output, like so:
|
||||
|
||||
```toml
|
||||
[tool.ruff]
|
||||
exclude = [
|
||||
'.svn',
|
||||
'CVS',
|
||||
'.bzr',
|
||||
'.hg',
|
||||
'.git',
|
||||
'__pycache__',
|
||||
'.tox',
|
||||
'.idea',
|
||||
'.mypy_cache',
|
||||
'.venv',
|
||||
'node_modules',
|
||||
'_state_machine.py',
|
||||
'test_fstring.py',
|
||||
'bad_coding2.py',
|
||||
'badsyntax_*.py',
|
||||
]
|
||||
select = [
|
||||
'A',
|
||||
'E',
|
||||
'F',
|
||||
'Q',
|
||||
]
|
||||
ignore = []
|
||||
|
||||
[tool.ruff.flake8-quotes]
|
||||
inline-quotes = 'single'
|
||||
|
||||
[tool.ruff.pep8-naming]
|
||||
ignore-names = [
|
||||
'foo',
|
||||
'bar',
|
||||
]
|
||||
```
|
||||
|
||||
### Plugins
|
||||
|
||||
`flake8-to-ruff` will attempt to infer any activated plugins based on the settings provided in your
|
||||
configuration file.
|
||||
|
||||
For example, if your `.flake8` file includes a `docstring-convention` property, `flake8-to-ruff`
|
||||
will enable the appropriate [`flake8-docstrings`](https://pypi.org/project/flake8-docstrings/)
|
||||
checks.
|
||||
|
||||
Alternatively, you can manually specify plugins on the command-line:
|
||||
|
||||
```shell
|
||||
flake8-to-ruff path/to/.flake8 --plugin flake8-builtins --plugin flake8-quotes
|
||||
```
|
||||
|
||||
## Limitations
|
||||
|
||||
1. Ruff only supports a subset of the Flake configuration options. `flake8-to-ruff` will warn on and
|
||||
ignore unsupported options in the `.flake8` file (or equivalent). (Similarly, Ruff has a few
|
||||
configuration options that don't exist in Flake8.)
|
||||
1. Ruff will omit any rule codes that are unimplemented or unsupported by Ruff, including rule
|
||||
codes from unsupported plugins. (See the
|
||||
[documentation](https://docs.astral.sh/ruff/faq/#how-does-ruff-compare-to-flake8) for the complete
|
||||
list of supported plugins.)
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome and hugely appreciated. To get started, check out the
|
||||
[contributing guidelines](https://github.com/astral-sh/ruff/blob/main/CONTRIBUTING.md).
|
||||
@@ -1,65 +0,0 @@
|
||||
[build-system]
|
||||
requires = [
|
||||
# The minimum setuptools version is specific to the PEP 517 backend,
|
||||
# and may be stricter than the version required in `setup.cfg`
|
||||
"setuptools>=40.6.0,!=60.9.0",
|
||||
"wheel",
|
||||
# Must be kept in sync with the `install_requirements` in `setup.cfg`
|
||||
"cffi>=1.12; platform_python_implementation != 'PyPy'",
|
||||
"setuptools-rust>=0.11.4",
|
||||
]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[tool.black]
|
||||
line-length = 79
|
||||
target-version = ["py36"]
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
addopts = "-r s --capture=no --strict-markers --benchmark-disable"
|
||||
markers = [
|
||||
"skip_fips: this test is not executed in FIPS mode",
|
||||
"supported: parametrized test requiring only_if and skip_message",
|
||||
]
|
||||
|
||||
[tool.mypy]
|
||||
show_error_codes = true
|
||||
check_untyped_defs = true
|
||||
no_implicit_reexport = true
|
||||
warn_redundant_casts = true
|
||||
warn_unused_ignores = true
|
||||
warn_unused_configs = true
|
||||
strict_equality = true
|
||||
|
||||
[[tool.mypy.overrides]]
|
||||
module = [
|
||||
"pretend"
|
||||
]
|
||||
ignore_missing_imports = true
|
||||
|
||||
[tool.coverage.run]
|
||||
branch = true
|
||||
relative_files = true
|
||||
source = [
|
||||
"cryptography",
|
||||
"tests/",
|
||||
]
|
||||
|
||||
[tool.coverage.paths]
|
||||
source = [
|
||||
"src/cryptography",
|
||||
"*.tox/*/lib*/python*/site-packages/cryptography",
|
||||
"*.tox\\*\\Lib\\site-packages\\cryptography",
|
||||
"*.tox/pypy/site-packages/cryptography",
|
||||
]
|
||||
tests =[
|
||||
"tests/",
|
||||
"*tests\\",
|
||||
]
|
||||
|
||||
[tool.coverage.report]
|
||||
exclude_lines = [
|
||||
"@abc.abstractmethod",
|
||||
"@abc.abstractproperty",
|
||||
"@typing.overload",
|
||||
"if typing.TYPE_CHECKING",
|
||||
]
|
||||
@@ -1,91 +0,0 @@
|
||||
[metadata]
|
||||
name = cryptography
|
||||
version = attr: cryptography.__version__
|
||||
description = cryptography is a package which provides cryptographic recipes and primitives to Python developers.
|
||||
long_description = file: README.rst
|
||||
long_description_content_type = text/x-rst
|
||||
license = BSD-3-Clause OR Apache-2.0
|
||||
url = https://github.com/pyca/cryptography
|
||||
author = The Python Cryptographic Authority and individual contributors
|
||||
author_email = cryptography-dev@python.org
|
||||
project_urls =
|
||||
Documentation=https://cryptography.io/
|
||||
Source=https://github.com/pyca/cryptography/
|
||||
Issues=https://github.com/pyca/cryptography/issues
|
||||
Changelog=https://cryptography.io/en/latest/changelog/
|
||||
classifiers =
|
||||
Development Status :: 5 - Production/Stable
|
||||
Intended Audience :: Developers
|
||||
License :: OSI Approved :: Apache Software License
|
||||
License :: OSI Approved :: BSD License
|
||||
Natural Language :: English
|
||||
Operating System :: MacOS :: MacOS X
|
||||
Operating System :: POSIX
|
||||
Operating System :: POSIX :: BSD
|
||||
Operating System :: POSIX :: Linux
|
||||
Operating System :: Microsoft :: Windows
|
||||
Programming Language :: Python
|
||||
Programming Language :: Python :: 3
|
||||
Programming Language :: Python :: 3 :: Only
|
||||
Programming Language :: Python :: 3.6
|
||||
Programming Language :: Python :: 3.7
|
||||
Programming Language :: Python :: 3.8
|
||||
Programming Language :: Python :: 3.9
|
||||
Programming Language :: Python :: 3.10
|
||||
Programming Language :: Python :: 3.11
|
||||
Programming Language :: Python :: Implementation :: CPython
|
||||
Programming Language :: Python :: Implementation :: PyPy
|
||||
Topic :: Security :: Cryptography
|
||||
|
||||
[options]
|
||||
python_requires = >=3.6
|
||||
include_package_data = True
|
||||
zip_safe = False
|
||||
package_dir =
|
||||
=src
|
||||
packages = find:
|
||||
# `install_requires` must be kept in sync with `pyproject.toml`
|
||||
install_requires =
|
||||
cffi >=1.12
|
||||
|
||||
[options.packages.find]
|
||||
where = src
|
||||
exclude =
|
||||
_cffi_src
|
||||
_cffi_src.*
|
||||
|
||||
[options.extras_require]
|
||||
test =
|
||||
pytest>=6.2.0
|
||||
pytest-benchmark
|
||||
pytest-cov
|
||||
pytest-subtests
|
||||
pytest-xdist
|
||||
pretend
|
||||
iso8601
|
||||
pytz
|
||||
hypothesis>=1.11.4,!=3.79.2
|
||||
docs =
|
||||
sphinx >= 1.6.5,!=1.8.0,!=3.1.0,!=3.1.1,!=5.2.0,!=5.2.0.post0
|
||||
sphinx_rtd_theme
|
||||
docstest =
|
||||
pyenchant >= 1.6.11
|
||||
twine >= 1.12.0
|
||||
sphinxcontrib-spelling >= 4.0.1
|
||||
sdist =
|
||||
setuptools_rust >= 0.11.4
|
||||
pep8test =
|
||||
black
|
||||
flake8
|
||||
flake8-import-order
|
||||
pep8-naming
|
||||
# This extra is for OpenSSH private keys that use bcrypt KDF
|
||||
# Versions: v3.1.3 - ignore_few_rounds, v3.1.5 - abi3
|
||||
ssh =
|
||||
bcrypt >= 3.1.5
|
||||
|
||||
[flake8]
|
||||
ignore = E203,E211,W503,W504,N818
|
||||
exclude = .tox,*.egg,.git,_build,.hypothesis
|
||||
select = E,W,F,N,I
|
||||
application-import-names = cryptography,cryptography_vectors,tests
|
||||
@@ -1,19 +0,0 @@
|
||||
[flake8]
|
||||
# Ignore style and complexity
|
||||
# E: style errors
|
||||
# W: style warnings
|
||||
# C: complexity
|
||||
# D: docstring warnings (unused pydocstyle extension)
|
||||
# F841: local variable assigned but never used
|
||||
ignore = E, C, W, D, F841
|
||||
builtins = c, get_config
|
||||
exclude =
|
||||
.cache,
|
||||
.github,
|
||||
docs,
|
||||
jupyterhub/alembic*,
|
||||
onbuild,
|
||||
scripts,
|
||||
share,
|
||||
tools,
|
||||
setup.py
|
||||
@@ -1,43 +0,0 @@
|
||||
[flake8]
|
||||
# Exclude the grpc generated code
|
||||
exclude = ./manim/grpc/gen/*
|
||||
max-complexity = 15
|
||||
max-line-length = 88
|
||||
statistics = True
|
||||
# Prevents some flake8-rst-docstrings errors
|
||||
rst-roles = attr,class,func,meth,mod,obj,ref,doc,exc
|
||||
rst-directives = manim, SEEALSO, seealso
|
||||
docstring-convention=numpy
|
||||
|
||||
select = A,A00,B,B9,C4,C90,D,E,F,F,PT,RST,SIM,W
|
||||
|
||||
# General Compatibility
|
||||
extend-ignore = E203, W503, D202, D212, D213, D404
|
||||
|
||||
# Misc
|
||||
F401, F403, F405, F841, E501, E731, E402, F811, F821,
|
||||
|
||||
# Plug-in: flake8-builtins
|
||||
A001, A002, A003,
|
||||
|
||||
# Plug-in: flake8-bugbear
|
||||
B006, B007, B008, B009, B010, B903, B950,
|
||||
|
||||
# Plug-in: flake8-simplify
|
||||
SIM105, SIM106, SIM119,
|
||||
|
||||
# Plug-in: flake8-comprehensions
|
||||
C901
|
||||
|
||||
# Plug-in: flake8-pytest-style
|
||||
PT001, PT004, PT006, PT011, PT018, PT022, PT023,
|
||||
|
||||
# Plug-in: flake8-docstrings
|
||||
D100, D101, D102, D103, D104, D105, D106, D107,
|
||||
D200, D202, D204, D205, D209,
|
||||
D301,
|
||||
D400, D401, D402, D403, D405, D406, D407, D409, D411, D412, D414,
|
||||
|
||||
# Plug-in: flake8-rst-docstrings
|
||||
RST201, RST203, RST210, RST212, RST213, RST215,
|
||||
RST301, RST303,
|
||||
@@ -1,36 +0,0 @@
|
||||
[flake8]
|
||||
min_python_version = 3.7.0
|
||||
max-line-length = 88
|
||||
ban-relative-imports = true
|
||||
# flake8-use-fstring: https://github.com/MichaelKim0407/flake8-use-fstring#--percent-greedy-and---format-greedy
|
||||
format-greedy = 1
|
||||
inline-quotes = double
|
||||
enable-extensions = TC, TC1
|
||||
type-checking-strict = true
|
||||
eradicate-whitelist-extend = ^-.*;
|
||||
extend-ignore =
|
||||
# E203: Whitespace before ':' (pycqa/pycodestyle#373)
|
||||
E203,
|
||||
# SIM106: Handle error-cases first
|
||||
SIM106,
|
||||
# ANN101: Missing type annotation for self in method
|
||||
ANN101,
|
||||
# ANN102: Missing type annotation for cls in classmethod
|
||||
ANN102,
|
||||
# PIE781: assign-and-return
|
||||
PIE781,
|
||||
# PIE798 no-unnecessary-class: Consider using a module for namespacing instead
|
||||
PIE798,
|
||||
per-file-ignores =
|
||||
# TC002: Move third-party import '...' into a type-checking block
|
||||
__init__.py:TC002,
|
||||
# ANN201: Missing return type annotation for public function
|
||||
tests/test_*:ANN201
|
||||
tests/**/test_*:ANN201
|
||||
extend-exclude =
|
||||
# Frozen and not subject to change in this repo:
|
||||
get-poetry.py,
|
||||
install-poetry.py,
|
||||
# External to the project's coding standards:
|
||||
tests/fixtures/*,
|
||||
tests/**/fixtures/*,
|
||||
@@ -1,19 +0,0 @@
|
||||
[flake8]
|
||||
max-line-length=120
|
||||
docstring-convention=all
|
||||
import-order-style=pycharm
|
||||
application_import_names=bot,tests
|
||||
exclude=.cache,.venv,.git,constants.py
|
||||
extend-ignore=
|
||||
B311,W503,E226,S311,T000,E731
|
||||
# Missing Docstrings
|
||||
D100,D104,D105,D107,
|
||||
# Docstring Whitespace
|
||||
D203,D212,D214,D215,
|
||||
# Docstring Quotes
|
||||
D301,D302,
|
||||
# Docstring Content
|
||||
D400,D401,D402,D404,D405,D406,D407,D408,D409,D410,D411,D412,D413,D414,D416,D417
|
||||
# Type Annotations
|
||||
ANN002,ANN003,ANN101,ANN102,ANN204,ANN206,ANN401
|
||||
per-file-ignores=tests/*:D,ANN
|
||||
@@ -1,6 +0,0 @@
|
||||
[flake8]
|
||||
ignore = E203, E501, W503
|
||||
per-file-ignores =
|
||||
requests/__init__.py:E402, F401
|
||||
requests/compat.py:E402, F401
|
||||
tests/compat.py:F401
|
||||
@@ -1,34 +0,0 @@
|
||||
[project]
|
||||
name = "flake8-to-ruff"
|
||||
keywords = ["automation", "flake8", "pycodestyle", "pyflakes", "pylint", "clippy"]
|
||||
classifiers = [
|
||||
"Development Status :: 3 - Alpha",
|
||||
"Environment :: Console",
|
||||
"Intended Audience :: Developers",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Operating System :: OS Independent",
|
||||
"Programming Language :: Python",
|
||||
"Programming Language :: Python :: 3.7",
|
||||
"Programming Language :: Python :: 3.8",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3 :: Only",
|
||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||
"Topic :: Software Development :: Quality Assurance",
|
||||
]
|
||||
author = "Charlie Marsh"
|
||||
author_email = "charlie.r.marsh@gmail.com"
|
||||
description = "Convert existing Flake8 configuration to Ruff."
|
||||
requires-python = ">=3.7"
|
||||
|
||||
[project.urls]
|
||||
repository = "https://github.com/astral-sh/ruff#subdirectory=crates/flake8_to_ruff"
|
||||
|
||||
[build-system]
|
||||
requires = ["maturin>=1.0,<2.0"]
|
||||
build-backend = "maturin"
|
||||
|
||||
[tool.maturin]
|
||||
bindings = "bin"
|
||||
strip = true
|
||||
@@ -1,13 +0,0 @@
|
||||
//! Extract Black configuration settings from a pyproject.toml.
|
||||
|
||||
use ruff_linter::line_width::LineLength;
|
||||
use ruff_linter::settings::types::PythonVersion;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
pub(crate) struct Black {
|
||||
#[serde(alias = "line-length", alias = "line_length")]
|
||||
pub(crate) line_length: Option<LineLength>,
|
||||
#[serde(alias = "target-version", alias = "target_version")]
|
||||
pub(crate) target_version: Option<Vec<PythonVersion>>,
|
||||
}
|
||||
@@ -1,687 +0,0 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::str::FromStr;
|
||||
|
||||
use itertools::Itertools;
|
||||
|
||||
use ruff_linter::line_width::LineLength;
|
||||
use ruff_linter::registry::Linter;
|
||||
use ruff_linter::rule_selector::RuleSelector;
|
||||
use ruff_linter::rules::flake8_pytest_style::types::{
|
||||
ParametrizeNameType, ParametrizeValuesRowType, ParametrizeValuesType,
|
||||
};
|
||||
use ruff_linter::rules::flake8_quotes::settings::Quote;
|
||||
use ruff_linter::rules::flake8_tidy_imports::settings::Strictness;
|
||||
use ruff_linter::rules::pydocstyle::settings::Convention;
|
||||
use ruff_linter::settings::types::PythonVersion;
|
||||
use ruff_linter::settings::DEFAULT_SELECTORS;
|
||||
use ruff_linter::warn_user;
|
||||
use ruff_workspace::options::{
|
||||
Flake8AnnotationsOptions, Flake8BugbearOptions, Flake8BuiltinsOptions, Flake8ErrMsgOptions,
|
||||
Flake8PytestStyleOptions, Flake8QuotesOptions, Flake8TidyImportsOptions, LintCommonOptions,
|
||||
LintOptions, McCabeOptions, Options, Pep8NamingOptions, PydocstyleOptions,
|
||||
};
|
||||
use ruff_workspace::pyproject::Pyproject;
|
||||
|
||||
use super::external_config::ExternalConfig;
|
||||
use super::plugin::Plugin;
|
||||
use super::{parser, plugin};
|
||||
|
||||
pub(crate) fn convert(
|
||||
config: &HashMap<String, HashMap<String, Option<String>>>,
|
||||
external_config: &ExternalConfig,
|
||||
plugins: Option<Vec<Plugin>>,
|
||||
) -> Pyproject {
|
||||
// Extract the Flake8 section.
|
||||
let flake8 = config
|
||||
.get("flake8")
|
||||
.expect("Unable to find flake8 section in INI file");
|
||||
|
||||
// Extract all referenced rule code prefixes, to power plugin inference.
|
||||
let mut referenced_codes: HashSet<RuleSelector> = HashSet::default();
|
||||
for (key, value) in flake8 {
|
||||
if let Some(value) = value {
|
||||
match key.as_str() {
|
||||
"select" | "ignore" | "extend-select" | "extend_select" | "extend-ignore"
|
||||
| "extend_ignore" => {
|
||||
referenced_codes.extend(parser::parse_prefix_codes(value.as_ref()));
|
||||
}
|
||||
"per-file-ignores" | "per_file_ignores" => {
|
||||
if let Ok(per_file_ignores) =
|
||||
parser::parse_files_to_codes_mapping(value.as_ref())
|
||||
{
|
||||
for (_, codes) in parser::collect_per_file_ignores(per_file_ignores) {
|
||||
referenced_codes.extend(codes);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Infer plugins, if not provided.
|
||||
let plugins = plugins.unwrap_or_else(|| {
|
||||
let from_options = plugin::infer_plugins_from_options(flake8);
|
||||
if !from_options.is_empty() {
|
||||
#[allow(clippy::print_stderr)]
|
||||
{
|
||||
eprintln!("Inferred plugins from settings: {from_options:#?}");
|
||||
}
|
||||
}
|
||||
let from_codes = plugin::infer_plugins_from_codes(&referenced_codes);
|
||||
if !from_codes.is_empty() {
|
||||
#[allow(clippy::print_stderr)]
|
||||
{
|
||||
eprintln!("Inferred plugins from referenced codes: {from_codes:#?}");
|
||||
}
|
||||
}
|
||||
from_options.into_iter().chain(from_codes).collect()
|
||||
});
|
||||
|
||||
// Check if the user has specified a `select`. If not, we'll add our own
|
||||
// default `select`, and populate it based on user plugins.
|
||||
let mut select = flake8
|
||||
.get("select")
|
||||
.and_then(|value| {
|
||||
value
|
||||
.as_ref()
|
||||
.map(|value| HashSet::from_iter(parser::parse_prefix_codes(value)))
|
||||
})
|
||||
.unwrap_or_else(|| resolve_select(&plugins));
|
||||
let mut ignore: HashSet<RuleSelector> = flake8
|
||||
.get("ignore")
|
||||
.and_then(|value| {
|
||||
value
|
||||
.as_ref()
|
||||
.map(|value| HashSet::from_iter(parser::parse_prefix_codes(value)))
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
// Parse each supported option.
|
||||
let mut options = Options::default();
|
||||
let mut lint_options = LintCommonOptions::default();
|
||||
let mut flake8_annotations = Flake8AnnotationsOptions::default();
|
||||
let mut flake8_bugbear = Flake8BugbearOptions::default();
|
||||
let mut flake8_builtins = Flake8BuiltinsOptions::default();
|
||||
let mut flake8_errmsg = Flake8ErrMsgOptions::default();
|
||||
let mut flake8_pytest_style = Flake8PytestStyleOptions::default();
|
||||
let mut flake8_quotes = Flake8QuotesOptions::default();
|
||||
let mut flake8_tidy_imports = Flake8TidyImportsOptions::default();
|
||||
let mut mccabe = McCabeOptions::default();
|
||||
let mut pep8_naming = Pep8NamingOptions::default();
|
||||
let mut pydocstyle = PydocstyleOptions::default();
|
||||
for (key, value) in flake8 {
|
||||
if let Some(value) = value {
|
||||
match key.as_str() {
|
||||
// flake8
|
||||
"builtins" => {
|
||||
options.builtins = Some(parser::parse_strings(value.as_ref()));
|
||||
}
|
||||
"max-line-length" | "max_line_length" => match LineLength::from_str(value) {
|
||||
Ok(line_length) => options.line_length = Some(line_length),
|
||||
Err(e) => {
|
||||
warn_user!("Unable to parse '{key}' property: {e}");
|
||||
}
|
||||
},
|
||||
"select" => {
|
||||
// No-op (handled above).
|
||||
select.extend(parser::parse_prefix_codes(value.as_ref()));
|
||||
}
|
||||
"ignore" => {
|
||||
// No-op (handled above).
|
||||
}
|
||||
"extend-select" | "extend_select" => {
|
||||
// Unlike Flake8, use a single explicit `select`.
|
||||
select.extend(parser::parse_prefix_codes(value.as_ref()));
|
||||
}
|
||||
"extend-ignore" | "extend_ignore" => {
|
||||
// Unlike Flake8, use a single explicit `ignore`.
|
||||
ignore.extend(parser::parse_prefix_codes(value.as_ref()));
|
||||
}
|
||||
"exclude" => {
|
||||
options.exclude = Some(parser::parse_strings(value.as_ref()));
|
||||
}
|
||||
"extend-exclude" | "extend_exclude" => {
|
||||
options.extend_exclude = Some(parser::parse_strings(value.as_ref()));
|
||||
}
|
||||
"per-file-ignores" | "per_file_ignores" => {
|
||||
match parser::parse_files_to_codes_mapping(value.as_ref()) {
|
||||
Ok(per_file_ignores) => {
|
||||
lint_options.per_file_ignores =
|
||||
Some(parser::collect_per_file_ignores(per_file_ignores));
|
||||
}
|
||||
Err(e) => {
|
||||
warn_user!("Unable to parse '{key}' property: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
// flake8-bugbear
|
||||
"extend-immutable-calls" | "extend_immutable_calls" => {
|
||||
flake8_bugbear.extend_immutable_calls =
|
||||
Some(parser::parse_strings(value.as_ref()));
|
||||
}
|
||||
// flake8-builtins
|
||||
"builtins-ignorelist" | "builtins_ignorelist" => {
|
||||
flake8_builtins.builtins_ignorelist =
|
||||
Some(parser::parse_strings(value.as_ref()));
|
||||
}
|
||||
// flake8-annotations
|
||||
"suppress-none-returning" | "suppress_none_returning" => {
|
||||
match parser::parse_bool(value.as_ref()) {
|
||||
Ok(bool) => flake8_annotations.suppress_none_returning = Some(bool),
|
||||
Err(e) => {
|
||||
warn_user!("Unable to parse '{key}' property: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
"suppress-dummy-args" | "suppress_dummy_args" => {
|
||||
match parser::parse_bool(value.as_ref()) {
|
||||
Ok(bool) => flake8_annotations.suppress_dummy_args = Some(bool),
|
||||
Err(e) => {
|
||||
warn_user!("Unable to parse '{key}' property: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
"mypy-init-return" | "mypy_init_return" => {
|
||||
match parser::parse_bool(value.as_ref()) {
|
||||
Ok(bool) => flake8_annotations.mypy_init_return = Some(bool),
|
||||
Err(e) => {
|
||||
warn_user!("Unable to parse '{key}' property: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
"allow-star-arg-any" | "allow_star_arg_any" => {
|
||||
match parser::parse_bool(value.as_ref()) {
|
||||
Ok(bool) => flake8_annotations.allow_star_arg_any = Some(bool),
|
||||
Err(e) => {
|
||||
warn_user!("Unable to parse '{key}' property: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
// flake8-quotes
|
||||
"quotes" | "inline-quotes" | "inline_quotes" => match value.trim() {
|
||||
"'" | "single" => flake8_quotes.inline_quotes = Some(Quote::Single),
|
||||
"\"" | "double" => flake8_quotes.inline_quotes = Some(Quote::Double),
|
||||
_ => {
|
||||
warn_user!("Unexpected '{key}' value: {value}");
|
||||
}
|
||||
},
|
||||
"multiline-quotes" | "multiline_quotes" => match value.trim() {
|
||||
"'" | "single" => flake8_quotes.multiline_quotes = Some(Quote::Single),
|
||||
"\"" | "double" => flake8_quotes.multiline_quotes = Some(Quote::Double),
|
||||
_ => {
|
||||
warn_user!("Unexpected '{key}' value: {value}");
|
||||
}
|
||||
},
|
||||
"docstring-quotes" | "docstring_quotes" => match value.trim() {
|
||||
"'" | "single" => flake8_quotes.docstring_quotes = Some(Quote::Single),
|
||||
"\"" | "double" => flake8_quotes.docstring_quotes = Some(Quote::Double),
|
||||
_ => {
|
||||
warn_user!("Unexpected '{key}' value: {value}");
|
||||
}
|
||||
},
|
||||
"avoid-escape" | "avoid_escape" => match parser::parse_bool(value.as_ref()) {
|
||||
Ok(bool) => flake8_quotes.avoid_escape = Some(bool),
|
||||
Err(e) => {
|
||||
warn_user!("Unable to parse '{key}' property: {e}");
|
||||
}
|
||||
},
|
||||
// pep8-naming
|
||||
"ignore-names" | "ignore_names" => {
|
||||
pep8_naming.ignore_names = Some(parser::parse_strings(value.as_ref()));
|
||||
}
|
||||
"classmethod-decorators" | "classmethod_decorators" => {
|
||||
pep8_naming.classmethod_decorators =
|
||||
Some(parser::parse_strings(value.as_ref()));
|
||||
}
|
||||
"staticmethod-decorators" | "staticmethod_decorators" => {
|
||||
pep8_naming.staticmethod_decorators =
|
||||
Some(parser::parse_strings(value.as_ref()));
|
||||
}
|
||||
// flake8-tidy-imports
|
||||
"ban-relative-imports" | "ban_relative_imports" => match value.trim() {
|
||||
"true" => flake8_tidy_imports.ban_relative_imports = Some(Strictness::All),
|
||||
"parents" => {
|
||||
flake8_tidy_imports.ban_relative_imports = Some(Strictness::Parents);
|
||||
}
|
||||
_ => {
|
||||
warn_user!("Unexpected '{key}' value: {value}");
|
||||
}
|
||||
},
|
||||
// flake8-docstrings
|
||||
"docstring-convention" => match value.trim() {
|
||||
"google" => pydocstyle.convention = Some(Convention::Google),
|
||||
"numpy" => pydocstyle.convention = Some(Convention::Numpy),
|
||||
"pep257" => pydocstyle.convention = Some(Convention::Pep257),
|
||||
"all" => pydocstyle.convention = None,
|
||||
_ => {
|
||||
warn_user!("Unexpected '{key}' value: {value}");
|
||||
}
|
||||
},
|
||||
// mccabe
|
||||
"max-complexity" | "max_complexity" => match value.parse::<usize>() {
|
||||
Ok(max_complexity) => mccabe.max_complexity = Some(max_complexity),
|
||||
Err(e) => {
|
||||
warn_user!("Unable to parse '{key}' property: {e}");
|
||||
}
|
||||
},
|
||||
// flake8-errmsg
|
||||
"errmsg-max-string-length" | "errmsg_max_string_length" => {
|
||||
match value.parse::<usize>() {
|
||||
Ok(max_string_length) => {
|
||||
flake8_errmsg.max_string_length = Some(max_string_length);
|
||||
}
|
||||
Err(e) => {
|
||||
warn_user!("Unable to parse '{key}' property: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
// flake8-pytest-style
|
||||
"pytest-fixture-no-parentheses" | "pytest_fixture_no_parentheses " => {
|
||||
match parser::parse_bool(value.as_ref()) {
|
||||
Ok(bool) => flake8_pytest_style.fixture_parentheses = Some(!bool),
|
||||
Err(e) => {
|
||||
warn_user!("Unable to parse '{key}' property: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
"pytest-parametrize-names-type" | "pytest_parametrize_names_type" => {
|
||||
match value.trim() {
|
||||
"csv" => {
|
||||
flake8_pytest_style.parametrize_names_type =
|
||||
Some(ParametrizeNameType::Csv);
|
||||
}
|
||||
"tuple" => {
|
||||
flake8_pytest_style.parametrize_names_type =
|
||||
Some(ParametrizeNameType::Tuple);
|
||||
}
|
||||
"list" => {
|
||||
flake8_pytest_style.parametrize_names_type =
|
||||
Some(ParametrizeNameType::List);
|
||||
}
|
||||
_ => {
|
||||
warn_user!("Unexpected '{key}' value: {value}");
|
||||
}
|
||||
}
|
||||
}
|
||||
"pytest-parametrize-values-type" | "pytest_parametrize_values_type" => {
|
||||
match value.trim() {
|
||||
"tuple" => {
|
||||
flake8_pytest_style.parametrize_values_type =
|
||||
Some(ParametrizeValuesType::Tuple);
|
||||
}
|
||||
"list" => {
|
||||
flake8_pytest_style.parametrize_values_type =
|
||||
Some(ParametrizeValuesType::List);
|
||||
}
|
||||
_ => {
|
||||
warn_user!("Unexpected '{key}' value: {value}");
|
||||
}
|
||||
}
|
||||
}
|
||||
"pytest-parametrize-values-row-type" | "pytest_parametrize_values_row_type" => {
|
||||
match value.trim() {
|
||||
"tuple" => {
|
||||
flake8_pytest_style.parametrize_values_row_type =
|
||||
Some(ParametrizeValuesRowType::Tuple);
|
||||
}
|
||||
"list" => {
|
||||
flake8_pytest_style.parametrize_values_row_type =
|
||||
Some(ParametrizeValuesRowType::List);
|
||||
}
|
||||
_ => {
|
||||
warn_user!("Unexpected '{key}' value: {value}");
|
||||
}
|
||||
}
|
||||
}
|
||||
"pytest-raises-require-match-for" | "pytest_raises_require_match_for" => {
|
||||
flake8_pytest_style.raises_require_match_for =
|
||||
Some(parser::parse_strings(value.as_ref()));
|
||||
}
|
||||
"pytest-mark-no-parentheses" | "pytest_mark_no_parentheses" => {
|
||||
match parser::parse_bool(value.as_ref()) {
|
||||
Ok(bool) => flake8_pytest_style.mark_parentheses = Some(!bool),
|
||||
Err(e) => {
|
||||
warn_user!("Unable to parse '{key}' property: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
// Unknown
|
||||
_ => {
|
||||
warn_user!("Skipping unsupported property: {}", key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Deduplicate and sort.
|
||||
lint_options.select = Some(
|
||||
select
|
||||
.into_iter()
|
||||
.sorted_by_key(RuleSelector::prefix_and_code)
|
||||
.collect(),
|
||||
);
|
||||
lint_options.ignore = Some(
|
||||
ignore
|
||||
.into_iter()
|
||||
.sorted_by_key(RuleSelector::prefix_and_code)
|
||||
.collect(),
|
||||
);
|
||||
if flake8_annotations != Flake8AnnotationsOptions::default() {
|
||||
lint_options.flake8_annotations = Some(flake8_annotations);
|
||||
}
|
||||
if flake8_bugbear != Flake8BugbearOptions::default() {
|
||||
lint_options.flake8_bugbear = Some(flake8_bugbear);
|
||||
}
|
||||
if flake8_builtins != Flake8BuiltinsOptions::default() {
|
||||
lint_options.flake8_builtins = Some(flake8_builtins);
|
||||
}
|
||||
if flake8_errmsg != Flake8ErrMsgOptions::default() {
|
||||
lint_options.flake8_errmsg = Some(flake8_errmsg);
|
||||
}
|
||||
if flake8_pytest_style != Flake8PytestStyleOptions::default() {
|
||||
lint_options.flake8_pytest_style = Some(flake8_pytest_style);
|
||||
}
|
||||
if flake8_quotes != Flake8QuotesOptions::default() {
|
||||
lint_options.flake8_quotes = Some(flake8_quotes);
|
||||
}
|
||||
if flake8_tidy_imports != Flake8TidyImportsOptions::default() {
|
||||
lint_options.flake8_tidy_imports = Some(flake8_tidy_imports);
|
||||
}
|
||||
if mccabe != McCabeOptions::default() {
|
||||
lint_options.mccabe = Some(mccabe);
|
||||
}
|
||||
if pep8_naming != Pep8NamingOptions::default() {
|
||||
lint_options.pep8_naming = Some(pep8_naming);
|
||||
}
|
||||
if pydocstyle != PydocstyleOptions::default() {
|
||||
lint_options.pydocstyle = Some(pydocstyle);
|
||||
}
|
||||
|
||||
// Extract any settings from the existing `pyproject.toml`.
|
||||
if let Some(black) = &external_config.black {
|
||||
if let Some(line_length) = &black.line_length {
|
||||
options.line_length = Some(*line_length);
|
||||
}
|
||||
|
||||
if let Some(target_version) = &black.target_version {
|
||||
if let Some(target_version) = target_version.iter().min() {
|
||||
options.target_version = Some(*target_version);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(isort) = &external_config.isort {
|
||||
if let Some(src_paths) = &isort.src_paths {
|
||||
match options.src.as_mut() {
|
||||
Some(src) => {
|
||||
src.extend_from_slice(src_paths);
|
||||
}
|
||||
None => {
|
||||
options.src = Some(src_paths.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(project) = &external_config.project {
|
||||
if let Some(requires_python) = &project.requires_python {
|
||||
if options.target_version.is_none() {
|
||||
options.target_version =
|
||||
PythonVersion::get_minimum_supported_version(requires_python);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if lint_options != LintCommonOptions::default() {
|
||||
options.lint = Some(LintOptions {
|
||||
common: lint_options,
|
||||
..LintOptions::default()
|
||||
});
|
||||
}
|
||||
|
||||
// Create the pyproject.toml.
|
||||
Pyproject::new(options)
|
||||
}
|
||||
|
||||
/// Resolve the set of enabled `RuleSelector` values for the given
|
||||
/// plugins.
|
||||
fn resolve_select(plugins: &[Plugin]) -> HashSet<RuleSelector> {
|
||||
let mut select: HashSet<_> = DEFAULT_SELECTORS.iter().cloned().collect();
|
||||
select.extend(plugins.iter().map(|p| Linter::from(p).into()));
|
||||
select
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
|
||||
use anyhow::Result;
|
||||
use itertools::Itertools;
|
||||
use pep440_rs::VersionSpecifiers;
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
use ruff_linter::line_width::LineLength;
|
||||
use ruff_linter::registry::Linter;
|
||||
use ruff_linter::rule_selector::RuleSelector;
|
||||
use ruff_linter::rules::flake8_quotes;
|
||||
use ruff_linter::rules::pydocstyle::settings::Convention;
|
||||
use ruff_linter::settings::types::PythonVersion;
|
||||
use ruff_workspace::options::{
|
||||
Flake8QuotesOptions, LintCommonOptions, LintOptions, Options, PydocstyleOptions,
|
||||
};
|
||||
use ruff_workspace::pyproject::Pyproject;
|
||||
|
||||
use crate::converter::DEFAULT_SELECTORS;
|
||||
use crate::pep621::Project;
|
||||
use crate::ExternalConfig;
|
||||
|
||||
use super::super::plugin::Plugin;
|
||||
use super::convert;
|
||||
|
||||
fn lint_default_options(plugins: impl IntoIterator<Item = RuleSelector>) -> LintCommonOptions {
|
||||
LintCommonOptions {
|
||||
ignore: Some(vec![]),
|
||||
select: Some(
|
||||
DEFAULT_SELECTORS
|
||||
.iter()
|
||||
.cloned()
|
||||
.chain(plugins)
|
||||
.sorted_by_key(RuleSelector::prefix_and_code)
|
||||
.collect(),
|
||||
),
|
||||
..LintCommonOptions::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_converts_empty() {
|
||||
let actual = convert(
|
||||
&HashMap::from([("flake8".to_string(), HashMap::default())]),
|
||||
&ExternalConfig::default(),
|
||||
None,
|
||||
);
|
||||
let expected = Pyproject::new(Options {
|
||||
lint: Some(LintOptions {
|
||||
common: lint_default_options([]),
|
||||
..LintOptions::default()
|
||||
}),
|
||||
..Options::default()
|
||||
});
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_converts_dashes() {
|
||||
let actual = convert(
|
||||
&HashMap::from([(
|
||||
"flake8".to_string(),
|
||||
HashMap::from([("max-line-length".to_string(), Some("100".to_string()))]),
|
||||
)]),
|
||||
&ExternalConfig::default(),
|
||||
Some(vec![]),
|
||||
);
|
||||
let expected = Pyproject::new(Options {
|
||||
line_length: Some(LineLength::try_from(100).unwrap()),
|
||||
lint: Some(LintOptions {
|
||||
common: lint_default_options([]),
|
||||
..LintOptions::default()
|
||||
}),
|
||||
..Options::default()
|
||||
});
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_converts_underscores() {
|
||||
let actual = convert(
|
||||
&HashMap::from([(
|
||||
"flake8".to_string(),
|
||||
HashMap::from([("max_line_length".to_string(), Some("100".to_string()))]),
|
||||
)]),
|
||||
&ExternalConfig::default(),
|
||||
Some(vec![]),
|
||||
);
|
||||
let expected = Pyproject::new(Options {
|
||||
line_length: Some(LineLength::try_from(100).unwrap()),
|
||||
lint: Some(LintOptions {
|
||||
common: lint_default_options([]),
|
||||
..LintOptions::default()
|
||||
}),
|
||||
..Options::default()
|
||||
});
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_ignores_parse_errors() {
|
||||
let actual = convert(
|
||||
&HashMap::from([(
|
||||
"flake8".to_string(),
|
||||
HashMap::from([("max_line_length".to_string(), Some("abc".to_string()))]),
|
||||
)]),
|
||||
&ExternalConfig::default(),
|
||||
Some(vec![]),
|
||||
);
|
||||
let expected = Pyproject::new(Options {
|
||||
lint: Some(LintOptions {
|
||||
common: lint_default_options([]),
|
||||
..LintOptions::default()
|
||||
}),
|
||||
..Options::default()
|
||||
});
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_converts_plugin_options() {
|
||||
let actual = convert(
|
||||
&HashMap::from([(
|
||||
"flake8".to_string(),
|
||||
HashMap::from([("inline-quotes".to_string(), Some("single".to_string()))]),
|
||||
)]),
|
||||
&ExternalConfig::default(),
|
||||
Some(vec![]),
|
||||
);
|
||||
let expected = Pyproject::new(Options {
|
||||
lint: Some(LintOptions {
|
||||
common: LintCommonOptions {
|
||||
flake8_quotes: Some(Flake8QuotesOptions {
|
||||
inline_quotes: Some(flake8_quotes::settings::Quote::Single),
|
||||
multiline_quotes: None,
|
||||
docstring_quotes: None,
|
||||
avoid_escape: None,
|
||||
}),
|
||||
..lint_default_options([])
|
||||
},
|
||||
..LintOptions::default()
|
||||
}),
|
||||
..Options::default()
|
||||
});
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_converts_docstring_conventions() {
|
||||
let actual = convert(
|
||||
&HashMap::from([(
|
||||
"flake8".to_string(),
|
||||
HashMap::from([(
|
||||
"docstring-convention".to_string(),
|
||||
Some("numpy".to_string()),
|
||||
)]),
|
||||
)]),
|
||||
&ExternalConfig::default(),
|
||||
Some(vec![Plugin::Flake8Docstrings]),
|
||||
);
|
||||
let expected = Pyproject::new(Options {
|
||||
lint: Some(LintOptions {
|
||||
common: LintCommonOptions {
|
||||
pydocstyle: Some(PydocstyleOptions {
|
||||
convention: Some(Convention::Numpy),
|
||||
ignore_decorators: None,
|
||||
property_decorators: None,
|
||||
}),
|
||||
..lint_default_options([Linter::Pydocstyle.into()])
|
||||
},
|
||||
..LintOptions::default()
|
||||
}),
|
||||
..Options::default()
|
||||
});
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_infers_plugins_if_omitted() {
|
||||
let actual = convert(
|
||||
&HashMap::from([(
|
||||
"flake8".to_string(),
|
||||
HashMap::from([("inline-quotes".to_string(), Some("single".to_string()))]),
|
||||
)]),
|
||||
&ExternalConfig::default(),
|
||||
None,
|
||||
);
|
||||
let expected = Pyproject::new(Options {
|
||||
lint: Some(LintOptions {
|
||||
common: LintCommonOptions {
|
||||
flake8_quotes: Some(Flake8QuotesOptions {
|
||||
inline_quotes: Some(flake8_quotes::settings::Quote::Single),
|
||||
multiline_quotes: None,
|
||||
docstring_quotes: None,
|
||||
avoid_escape: None,
|
||||
}),
|
||||
..lint_default_options([Linter::Flake8Quotes.into()])
|
||||
},
|
||||
..LintOptions::default()
|
||||
}),
|
||||
..Options::default()
|
||||
});
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_converts_project_requires_python() -> Result<()> {
|
||||
let actual = convert(
|
||||
&HashMap::from([("flake8".to_string(), HashMap::default())]),
|
||||
&ExternalConfig {
|
||||
project: Some(&Project {
|
||||
requires_python: Some(VersionSpecifiers::from_str(">=3.8.16, <3.11")?),
|
||||
}),
|
||||
..ExternalConfig::default()
|
||||
},
|
||||
Some(vec![]),
|
||||
);
|
||||
let expected = Pyproject::new(Options {
|
||||
target_version: Some(PythonVersion::Py38),
|
||||
lint: Some(LintOptions {
|
||||
common: lint_default_options([]),
|
||||
..LintOptions::default()
|
||||
}),
|
||||
..Options::default()
|
||||
});
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
use super::black::Black;
|
||||
use super::isort::Isort;
|
||||
use super::pep621::Project;
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct ExternalConfig<'a> {
|
||||
pub(crate) black: Option<&'a Black>,
|
||||
pub(crate) isort: Option<&'a Isort>,
|
||||
pub(crate) project: Option<&'a Project>,
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
//! Extract isort configuration settings from a pyproject.toml.
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// The [isort configuration](https://pycqa.github.io/isort/docs/configuration/config_files.html).
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
pub(crate) struct Isort {
|
||||
#[serde(alias = "src-paths", alias = "src_paths")]
|
||||
pub(crate) src_paths: Option<Vec<String>>,
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
//! Utility to generate Ruff's `pyproject.toml` section from a Flake8 INI file.
|
||||
|
||||
mod black;
|
||||
mod converter;
|
||||
mod external_config;
|
||||
mod isort;
|
||||
mod parser;
|
||||
mod pep621;
|
||||
mod plugin;
|
||||
mod pyproject;
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
use anyhow::Result;
|
||||
use clap::Parser;
|
||||
use configparser::ini::Ini;
|
||||
|
||||
use crate::converter::convert;
|
||||
use crate::external_config::ExternalConfig;
|
||||
use crate::plugin::Plugin;
|
||||
use crate::pyproject::parse;
|
||||
use ruff_linter::logging::{set_up_logging, LogLevel};
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(
|
||||
about = "Convert existing Flake8 configuration to Ruff.",
|
||||
long_about = None
|
||||
)]
|
||||
struct Args {
|
||||
/// Path to the Flake8 configuration file (e.g., `setup.cfg`, `tox.ini`, or
|
||||
/// `.flake8`).
|
||||
#[arg(required = true)]
|
||||
file: PathBuf,
|
||||
/// Optional path to a `pyproject.toml` file, used to ensure compatibility
|
||||
/// with Black.
|
||||
#[arg(long)]
|
||||
pyproject: Option<PathBuf>,
|
||||
/// List of plugins to enable.
|
||||
#[arg(long, value_delimiter = ',')]
|
||||
plugin: Option<Vec<Plugin>>,
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
set_up_logging(&LogLevel::Default)?;
|
||||
|
||||
let args = Args::parse();
|
||||
|
||||
// Read the INI file.
|
||||
let mut ini = Ini::new_cs();
|
||||
ini.set_multiline(true);
|
||||
let config = ini.load(args.file).map_err(|msg| anyhow::anyhow!(msg))?;
|
||||
|
||||
// Read the pyproject.toml file.
|
||||
let pyproject = args.pyproject.map(parse).transpose()?;
|
||||
let external_config = pyproject
|
||||
.as_ref()
|
||||
.and_then(|pyproject| pyproject.tool.as_ref())
|
||||
.map(|tool| ExternalConfig {
|
||||
black: tool.black.as_ref(),
|
||||
isort: tool.isort.as_ref(),
|
||||
..Default::default()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
let external_config = ExternalConfig {
|
||||
project: pyproject
|
||||
.as_ref()
|
||||
.and_then(|pyproject| pyproject.project.as_ref()),
|
||||
..external_config
|
||||
};
|
||||
|
||||
// Create Ruff's pyproject.toml section.
|
||||
let pyproject = convert(&config, &external_config, args.plugin);
|
||||
|
||||
#[allow(clippy::print_stdout)]
|
||||
{
|
||||
println!("{}", toml::to_string_pretty(&pyproject)?);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,391 +0,0 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use ruff_linter::settings::types::PatternPrefixPair;
|
||||
use ruff_linter::{warn_user, RuleSelector};
|
||||
|
||||
static COMMA_SEPARATED_LIST_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"[,\s]").unwrap());
|
||||
|
||||
/// Parse a comma-separated list of `RuleSelector` values (e.g.,
|
||||
/// "F401,E501").
|
||||
pub(crate) fn parse_prefix_codes(value: &str) -> Vec<RuleSelector> {
|
||||
let mut codes: Vec<RuleSelector> = vec![];
|
||||
for code in COMMA_SEPARATED_LIST_RE.split(value) {
|
||||
let code = code.trim();
|
||||
if code.is_empty() {
|
||||
continue;
|
||||
}
|
||||
if let Ok(code) = RuleSelector::from_str(code) {
|
||||
codes.push(code);
|
||||
} else {
|
||||
warn_user!("Unsupported prefix code: {code}");
|
||||
}
|
||||
}
|
||||
codes
|
||||
}
|
||||
|
||||
/// Parse a comma-separated list of strings (e.g., "__init__.py,__main__.py").
|
||||
pub(crate) fn parse_strings(value: &str) -> Vec<String> {
|
||||
COMMA_SEPARATED_LIST_RE
|
||||
.split(value)
|
||||
.map(str::trim)
|
||||
.filter(|part| !part.is_empty())
|
||||
.map(String::from)
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Parse a boolean.
|
||||
pub(crate) fn parse_bool(value: &str) -> Result<bool> {
|
||||
match value.trim() {
|
||||
"true" => Ok(true),
|
||||
"false" => Ok(false),
|
||||
_ => bail!("Unexpected boolean value: {value}"),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Token {
|
||||
token_name: TokenType,
|
||||
src: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
enum TokenType {
|
||||
Code,
|
||||
File,
|
||||
Colon,
|
||||
Comma,
|
||||
Ws,
|
||||
Eof,
|
||||
}
|
||||
|
||||
struct State {
|
||||
seen_sep: bool,
|
||||
seen_colon: bool,
|
||||
filenames: Vec<String>,
|
||||
codes: Vec<String>,
|
||||
}
|
||||
|
||||
impl State {
|
||||
const fn new() -> Self {
|
||||
Self {
|
||||
seen_sep: true,
|
||||
seen_colon: false,
|
||||
filenames: vec![],
|
||||
codes: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate the list of `StrRuleCodePair` pairs for the current
|
||||
/// state.
|
||||
fn parse(&self) -> Vec<PatternPrefixPair> {
|
||||
let mut codes: Vec<PatternPrefixPair> = vec![];
|
||||
for code in &self.codes {
|
||||
if let Ok(code) = RuleSelector::from_str(code) {
|
||||
for filename in &self.filenames {
|
||||
codes.push(PatternPrefixPair {
|
||||
pattern: filename.clone(),
|
||||
prefix: code.clone(),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
warn_user!("Unsupported prefix code: {code}");
|
||||
}
|
||||
}
|
||||
codes
|
||||
}
|
||||
}
|
||||
|
||||
/// Tokenize the raw 'files-to-codes' mapping.
|
||||
fn tokenize_files_to_codes_mapping(value: &str) -> Vec<Token> {
|
||||
let mut tokens = vec![];
|
||||
let mut i = 0;
|
||||
while i < value.len() {
|
||||
for (token_re, token_name) in [
|
||||
(
|
||||
Regex::new(r"([A-Z]+[0-9]*)(?:$|\s|,)").unwrap(),
|
||||
TokenType::Code,
|
||||
),
|
||||
(Regex::new(r"([^\s:,]+)").unwrap(), TokenType::File),
|
||||
(Regex::new(r"(\s*:\s*)").unwrap(), TokenType::Colon),
|
||||
(Regex::new(r"(\s*,\s*)").unwrap(), TokenType::Comma),
|
||||
(Regex::new(r"(\s+)").unwrap(), TokenType::Ws),
|
||||
] {
|
||||
if let Some(cap) = token_re.captures(&value[i..]) {
|
||||
let mat = cap.get(1).unwrap();
|
||||
if mat.start() == 0 {
|
||||
tokens.push(Token {
|
||||
token_name,
|
||||
src: mat.as_str().trim().to_string(),
|
||||
});
|
||||
i += mat.end();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
tokens.push(Token {
|
||||
token_name: TokenType::Eof,
|
||||
src: String::new(),
|
||||
});
|
||||
tokens
|
||||
}
|
||||
|
||||
/// Parse a 'files-to-codes' mapping, mimicking Flake8's internal logic.
|
||||
/// See: <https://github.com/PyCQA/flake8/blob/7dfe99616fc2f07c0017df2ba5fa884158f3ea8a/src/flake8/utils.py#L45>
|
||||
pub(crate) fn parse_files_to_codes_mapping(value: &str) -> Result<Vec<PatternPrefixPair>> {
|
||||
if value.trim().is_empty() {
|
||||
return Ok(vec![]);
|
||||
}
|
||||
let mut codes: Vec<PatternPrefixPair> = vec![];
|
||||
let mut state = State::new();
|
||||
for token in tokenize_files_to_codes_mapping(value) {
|
||||
if matches!(token.token_name, TokenType::Comma | TokenType::Ws) {
|
||||
state.seen_sep = true;
|
||||
} else if !state.seen_colon {
|
||||
if matches!(token.token_name, TokenType::Colon) {
|
||||
state.seen_colon = true;
|
||||
state.seen_sep = true;
|
||||
} else if state.seen_sep && matches!(token.token_name, TokenType::File) {
|
||||
state.filenames.push(token.src);
|
||||
state.seen_sep = false;
|
||||
} else {
|
||||
bail!("Unexpected token: {:?}", token.token_name);
|
||||
}
|
||||
} else {
|
||||
if matches!(token.token_name, TokenType::Eof) {
|
||||
codes.extend(state.parse());
|
||||
state = State::new();
|
||||
} else if state.seen_sep && matches!(token.token_name, TokenType::Code) {
|
||||
state.codes.push(token.src);
|
||||
state.seen_sep = false;
|
||||
} else if state.seen_sep && matches!(token.token_name, TokenType::File) {
|
||||
codes.extend(state.parse());
|
||||
state = State::new();
|
||||
state.filenames.push(token.src);
|
||||
state.seen_sep = false;
|
||||
} else {
|
||||
bail!("Unexpected token: {:?}", token.token_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(codes)
|
||||
}
|
||||
|
||||
/// Collect a list of `PatternPrefixPair` structs as a `BTreeMap`.
|
||||
pub(crate) fn collect_per_file_ignores(
|
||||
pairs: Vec<PatternPrefixPair>,
|
||||
) -> FxHashMap<String, Vec<RuleSelector>> {
|
||||
let mut per_file_ignores: FxHashMap<String, Vec<RuleSelector>> = FxHashMap::default();
|
||||
for pair in pairs {
|
||||
per_file_ignores
|
||||
.entry(pair.pattern)
|
||||
.or_default()
|
||||
.push(pair.prefix);
|
||||
}
|
||||
per_file_ignores
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use anyhow::Result;
|
||||
|
||||
use ruff_linter::codes;
|
||||
use ruff_linter::registry::Linter;
|
||||
use ruff_linter::settings::types::PatternPrefixPair;
|
||||
use ruff_linter::RuleSelector;
|
||||
|
||||
use super::{parse_files_to_codes_mapping, parse_prefix_codes, parse_strings};
|
||||
|
||||
#[test]
|
||||
fn it_parses_prefix_codes() {
|
||||
let actual = parse_prefix_codes("");
|
||||
let expected: Vec<RuleSelector> = vec![];
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
let actual = parse_prefix_codes(" ");
|
||||
let expected: Vec<RuleSelector> = vec![];
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
let actual = parse_prefix_codes("F401");
|
||||
let expected = vec![codes::Pyflakes::_401.into()];
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
let actual = parse_prefix_codes("F401,");
|
||||
let expected = vec![codes::Pyflakes::_401.into()];
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
let actual = parse_prefix_codes("F401,E501");
|
||||
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![
|
||||
codes::Pyflakes::_401.into(),
|
||||
codes::Pycodestyle::E501.into(),
|
||||
];
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_parses_strings() {
|
||||
let actual = parse_strings("");
|
||||
let expected: Vec<String> = vec![];
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
let actual = parse_strings(" ");
|
||||
let expected: Vec<String> = vec![];
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
let actual = parse_strings("__init__.py");
|
||||
let expected = vec!["__init__.py".to_string()];
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
let actual = parse_strings("__init__.py,");
|
||||
let expected = vec!["__init__.py".to_string()];
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
let actual = parse_strings("__init__.py,__main__.py");
|
||||
let expected = vec!["__init__.py".to_string(), "__main__.py".to_string()];
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
let actual = parse_strings("__init__.py, __main__.py");
|
||||
let expected = vec!["__init__.py".to_string(), "__main__.py".to_string()];
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_parse_files_to_codes_mapping() -> Result<()> {
|
||||
let actual = parse_files_to_codes_mapping("")?;
|
||||
let expected: Vec<PatternPrefixPair> = vec![];
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
let actual = parse_files_to_codes_mapping(" ")?;
|
||||
let expected: Vec<PatternPrefixPair> = vec![];
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
// Ex) locust
|
||||
let actual = parse_files_to_codes_mapping(
|
||||
"per-file-ignores =
|
||||
locust/test/*: F841
|
||||
examples/*: F841
|
||||
*.pyi: E302,E704"
|
||||
.strip_prefix("per-file-ignores =")
|
||||
.unwrap(),
|
||||
)?;
|
||||
let expected: Vec<PatternPrefixPair> = vec![
|
||||
PatternPrefixPair {
|
||||
pattern: "locust/test/*".to_string(),
|
||||
prefix: codes::Pyflakes::_841.into(),
|
||||
},
|
||||
PatternPrefixPair {
|
||||
pattern: "examples/*".to_string(),
|
||||
prefix: codes::Pyflakes::_841.into(),
|
||||
},
|
||||
];
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
// Ex) celery
|
||||
let actual = parse_files_to_codes_mapping(
|
||||
"per-file-ignores =
|
||||
t/*,setup.py,examples/*,docs/*,extra/*:
|
||||
D,"
|
||||
.strip_prefix("per-file-ignores =")
|
||||
.unwrap(),
|
||||
)?;
|
||||
let expected: Vec<PatternPrefixPair> = vec![
|
||||
PatternPrefixPair {
|
||||
pattern: "t/*".to_string(),
|
||||
prefix: Linter::Pydocstyle.into(),
|
||||
},
|
||||
PatternPrefixPair {
|
||||
pattern: "setup.py".to_string(),
|
||||
prefix: Linter::Pydocstyle.into(),
|
||||
},
|
||||
PatternPrefixPair {
|
||||
pattern: "examples/*".to_string(),
|
||||
prefix: Linter::Pydocstyle.into(),
|
||||
},
|
||||
PatternPrefixPair {
|
||||
pattern: "docs/*".to_string(),
|
||||
prefix: Linter::Pydocstyle.into(),
|
||||
},
|
||||
PatternPrefixPair {
|
||||
pattern: "extra/*".to_string(),
|
||||
prefix: Linter::Pydocstyle.into(),
|
||||
},
|
||||
];
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
// Ex) scrapy
|
||||
let actual = parse_files_to_codes_mapping(
|
||||
"per-file-ignores =
|
||||
scrapy/__init__.py:E402
|
||||
scrapy/core/downloader/handlers/http.py:F401
|
||||
scrapy/http/__init__.py:F401
|
||||
scrapy/linkextractors/__init__.py:E402,F401
|
||||
scrapy/selector/__init__.py:F401
|
||||
scrapy/spiders/__init__.py:E402,F401
|
||||
scrapy/utils/url.py:F403,F405
|
||||
tests/test_loader.py:E741"
|
||||
.strip_prefix("per-file-ignores =")
|
||||
.unwrap(),
|
||||
)?;
|
||||
let expected: Vec<PatternPrefixPair> = vec![
|
||||
PatternPrefixPair {
|
||||
pattern: "scrapy/__init__.py".to_string(),
|
||||
prefix: codes::Pycodestyle::E402.into(),
|
||||
},
|
||||
PatternPrefixPair {
|
||||
pattern: "scrapy/core/downloader/handlers/http.py".to_string(),
|
||||
prefix: codes::Pyflakes::_401.into(),
|
||||
},
|
||||
PatternPrefixPair {
|
||||
pattern: "scrapy/http/__init__.py".to_string(),
|
||||
prefix: codes::Pyflakes::_401.into(),
|
||||
},
|
||||
PatternPrefixPair {
|
||||
pattern: "scrapy/linkextractors/__init__.py".to_string(),
|
||||
prefix: codes::Pycodestyle::E402.into(),
|
||||
},
|
||||
PatternPrefixPair {
|
||||
pattern: "scrapy/linkextractors/__init__.py".to_string(),
|
||||
prefix: codes::Pyflakes::_401.into(),
|
||||
},
|
||||
PatternPrefixPair {
|
||||
pattern: "scrapy/selector/__init__.py".to_string(),
|
||||
prefix: codes::Pyflakes::_401.into(),
|
||||
},
|
||||
PatternPrefixPair {
|
||||
pattern: "scrapy/spiders/__init__.py".to_string(),
|
||||
prefix: codes::Pycodestyle::E402.into(),
|
||||
},
|
||||
PatternPrefixPair {
|
||||
pattern: "scrapy/spiders/__init__.py".to_string(),
|
||||
prefix: codes::Pyflakes::_401.into(),
|
||||
},
|
||||
PatternPrefixPair {
|
||||
pattern: "scrapy/utils/url.py".to_string(),
|
||||
prefix: codes::Pyflakes::_403.into(),
|
||||
},
|
||||
PatternPrefixPair {
|
||||
pattern: "scrapy/utils/url.py".to_string(),
|
||||
prefix: codes::Pyflakes::_405.into(),
|
||||
},
|
||||
PatternPrefixPair {
|
||||
pattern: "tests/test_loader.py".to_string(),
|
||||
prefix: codes::Pycodestyle::E741.into(),
|
||||
},
|
||||
];
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
//! Extract PEP 621 configuration settings from a pyproject.toml.
|
||||
|
||||
use pep440_rs::VersionSpecifiers;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
pub(crate) struct Project {
|
||||
#[serde(alias = "requires-python", alias = "requires_python")]
|
||||
pub(crate) requires_python: Option<VersionSpecifiers>,
|
||||
}
|
||||
@@ -1,368 +0,0 @@
|
||||
use std::collections::{BTreeSet, HashMap, HashSet};
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use ruff_linter::registry::Linter;
|
||||
use ruff_linter::rule_selector::PreviewOptions;
|
||||
use ruff_linter::RuleSelector;
|
||||
|
||||
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
|
||||
pub enum Plugin {
|
||||
Flake82020,
|
||||
Flake8Annotations,
|
||||
Flake8Bandit,
|
||||
Flake8BlindExcept,
|
||||
Flake8BooleanTrap,
|
||||
Flake8Bugbear,
|
||||
Flake8Builtins,
|
||||
Flake8Commas,
|
||||
Flake8Comprehensions,
|
||||
Flake8Datetimez,
|
||||
Flake8Debugger,
|
||||
Flake8Docstrings,
|
||||
Flake8Eradicate,
|
||||
Flake8ErrMsg,
|
||||
Flake8Executable,
|
||||
Flake8ImplicitStrConcat,
|
||||
Flake8ImportConventions,
|
||||
Flake8NoPep420,
|
||||
Flake8Pie,
|
||||
Flake8Print,
|
||||
Flake8PytestStyle,
|
||||
Flake8Quotes,
|
||||
Flake8Return,
|
||||
Flake8Simplify,
|
||||
Flake8TidyImports,
|
||||
Flake8TypeChecking,
|
||||
Flake8UnusedArguments,
|
||||
Flake8UsePathlib,
|
||||
McCabe,
|
||||
PEP8Naming,
|
||||
PandasVet,
|
||||
Pyupgrade,
|
||||
Tryceratops,
|
||||
}
|
||||
|
||||
impl FromStr for Plugin {
|
||||
type Err = anyhow::Error;
|
||||
|
||||
fn from_str(string: &str) -> Result<Self, Self::Err> {
|
||||
match string {
|
||||
"flake8-2020" => Ok(Plugin::Flake82020),
|
||||
"flake8-annotations" => Ok(Plugin::Flake8Annotations),
|
||||
"flake8-bandit" => Ok(Plugin::Flake8Bandit),
|
||||
"flake8-blind-except" => Ok(Plugin::Flake8BlindExcept),
|
||||
"flake8-boolean-trap" => Ok(Plugin::Flake8BooleanTrap),
|
||||
"flake8-bugbear" => Ok(Plugin::Flake8Bugbear),
|
||||
"flake8-builtins" => Ok(Plugin::Flake8Builtins),
|
||||
"flake8-commas" => Ok(Plugin::Flake8Commas),
|
||||
"flake8-comprehensions" => Ok(Plugin::Flake8Comprehensions),
|
||||
"flake8-datetimez" => Ok(Plugin::Flake8Datetimez),
|
||||
"flake8-debugger" => Ok(Plugin::Flake8Debugger),
|
||||
"flake8-docstrings" => Ok(Plugin::Flake8Docstrings),
|
||||
"flake8-eradicate" => Ok(Plugin::Flake8Eradicate),
|
||||
"flake8-errmsg" => Ok(Plugin::Flake8ErrMsg),
|
||||
"flake8-executable" => Ok(Plugin::Flake8Executable),
|
||||
"flake8-implicit-str-concat" => Ok(Plugin::Flake8ImplicitStrConcat),
|
||||
"flake8-import-conventions" => Ok(Plugin::Flake8ImportConventions),
|
||||
"flake8-no-pep420" => Ok(Plugin::Flake8NoPep420),
|
||||
"flake8-pie" => Ok(Plugin::Flake8Pie),
|
||||
"flake8-print" => Ok(Plugin::Flake8Print),
|
||||
"flake8-pytest-style" => Ok(Plugin::Flake8PytestStyle),
|
||||
"flake8-quotes" => Ok(Plugin::Flake8Quotes),
|
||||
"flake8-return" => Ok(Plugin::Flake8Return),
|
||||
"flake8-simplify" => Ok(Plugin::Flake8Simplify),
|
||||
"flake8-tidy-imports" => Ok(Plugin::Flake8TidyImports),
|
||||
"flake8-type-checking" => Ok(Plugin::Flake8TypeChecking),
|
||||
"flake8-unused-arguments" => Ok(Plugin::Flake8UnusedArguments),
|
||||
"flake8-use-pathlib" => Ok(Plugin::Flake8UsePathlib),
|
||||
"mccabe" => Ok(Plugin::McCabe),
|
||||
"pep8-naming" => Ok(Plugin::PEP8Naming),
|
||||
"pandas-vet" => Ok(Plugin::PandasVet),
|
||||
"pyupgrade" => Ok(Plugin::Pyupgrade),
|
||||
"tryceratops" => Ok(Plugin::Tryceratops),
|
||||
_ => Err(anyhow!("Unknown plugin: {string}")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Plugin {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match self {
|
||||
Plugin::Flake82020 => "flake8-2020",
|
||||
Plugin::Flake8Annotations => "flake8-annotations",
|
||||
Plugin::Flake8Bandit => "flake8-bandit",
|
||||
Plugin::Flake8BlindExcept => "flake8-blind-except",
|
||||
Plugin::Flake8BooleanTrap => "flake8-boolean-trap",
|
||||
Plugin::Flake8Bugbear => "flake8-bugbear",
|
||||
Plugin::Flake8Builtins => "flake8-builtins",
|
||||
Plugin::Flake8Commas => "flake8-commas",
|
||||
Plugin::Flake8Comprehensions => "flake8-comprehensions",
|
||||
Plugin::Flake8Datetimez => "flake8-datetimez",
|
||||
Plugin::Flake8Debugger => "flake8-debugger",
|
||||
Plugin::Flake8Docstrings => "flake8-docstrings",
|
||||
Plugin::Flake8Eradicate => "flake8-eradicate",
|
||||
Plugin::Flake8ErrMsg => "flake8-errmsg",
|
||||
Plugin::Flake8Executable => "flake8-executable",
|
||||
Plugin::Flake8ImplicitStrConcat => "flake8-implicit-str-concat",
|
||||
Plugin::Flake8ImportConventions => "flake8-import-conventions",
|
||||
Plugin::Flake8NoPep420 => "flake8-no-pep420",
|
||||
Plugin::Flake8Pie => "flake8-pie",
|
||||
Plugin::Flake8Print => "flake8-print",
|
||||
Plugin::Flake8PytestStyle => "flake8-pytest-style",
|
||||
Plugin::Flake8Quotes => "flake8-quotes",
|
||||
Plugin::Flake8Return => "flake8-return",
|
||||
Plugin::Flake8Simplify => "flake8-simplify",
|
||||
Plugin::Flake8TidyImports => "flake8-tidy-imports",
|
||||
Plugin::Flake8TypeChecking => "flake8-type-checking",
|
||||
Plugin::Flake8UnusedArguments => "flake8-unused-arguments",
|
||||
Plugin::Flake8UsePathlib => "flake8-use-pathlib",
|
||||
Plugin::McCabe => "mccabe",
|
||||
Plugin::PEP8Naming => "pep8-naming",
|
||||
Plugin::PandasVet => "pandas-vet",
|
||||
Plugin::Pyupgrade => "pyupgrade",
|
||||
Plugin::Tryceratops => "tryceratops",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Infer the enabled plugins based on user-provided options.
|
||||
///
|
||||
/// For example, if the user specified a `mypy-init-return` setting, we should
|
||||
/// infer that `flake8-annotations` is active.
|
||||
pub(crate) fn infer_plugins_from_options(flake8: &HashMap<String, Option<String>>) -> Vec<Plugin> {
|
||||
let mut plugins = BTreeSet::new();
|
||||
for key in flake8.keys() {
|
||||
match key.as_str() {
|
||||
// flake8-annotations
|
||||
"suppress-none-returning" | "suppress_none_returning" => {
|
||||
plugins.insert(Plugin::Flake8Annotations);
|
||||
}
|
||||
"suppress-dummy-args" | "suppress_dummy_args" => {
|
||||
plugins.insert(Plugin::Flake8Annotations);
|
||||
}
|
||||
"allow-untyped-defs" | "allow_untyped_defs" => {
|
||||
plugins.insert(Plugin::Flake8Annotations);
|
||||
}
|
||||
"allow-untyped-nested" | "allow_untyped_nested" => {
|
||||
plugins.insert(Plugin::Flake8Annotations);
|
||||
}
|
||||
"mypy-init-return" | "mypy_init_return" => {
|
||||
plugins.insert(Plugin::Flake8Annotations);
|
||||
}
|
||||
"dispatch-decorators" | "dispatch_decorators" => {
|
||||
plugins.insert(Plugin::Flake8Annotations);
|
||||
}
|
||||
"overload-decorators" | "overload_decorators" => {
|
||||
plugins.insert(Plugin::Flake8Annotations);
|
||||
}
|
||||
"allow-star-arg-any" | "allow_star_arg_any" => {
|
||||
plugins.insert(Plugin::Flake8Annotations);
|
||||
}
|
||||
// flake8-bugbear
|
||||
"extend-immutable-calls" | "extend_immutable_calls" => {
|
||||
plugins.insert(Plugin::Flake8Bugbear);
|
||||
}
|
||||
// flake8-builtins
|
||||
"builtins-ignorelist" | "builtins_ignorelist" => {
|
||||
plugins.insert(Plugin::Flake8Builtins);
|
||||
}
|
||||
// flake8-docstrings
|
||||
"docstring-convention" | "docstring_convention" => {
|
||||
plugins.insert(Plugin::Flake8Docstrings);
|
||||
}
|
||||
// flake8-eradicate
|
||||
"eradicate-aggressive" | "eradicate_aggressive" => {
|
||||
plugins.insert(Plugin::Flake8Eradicate);
|
||||
}
|
||||
"eradicate-whitelist" | "eradicate_whitelist" => {
|
||||
plugins.insert(Plugin::Flake8Eradicate);
|
||||
}
|
||||
"eradicate-whitelist-extend" | "eradicate_whitelist_extend" => {
|
||||
plugins.insert(Plugin::Flake8Eradicate);
|
||||
}
|
||||
// flake8-pytest-style
|
||||
"pytest-fixture-no-parentheses" | "pytest_fixture_no_parentheses " => {
|
||||
plugins.insert(Plugin::Flake8PytestStyle);
|
||||
}
|
||||
"pytest-parametrize-names-type" | "pytest_parametrize_names_type" => {
|
||||
plugins.insert(Plugin::Flake8PytestStyle);
|
||||
}
|
||||
"pytest-parametrize-values-type" | "pytest_parametrize_values_type" => {
|
||||
plugins.insert(Plugin::Flake8PytestStyle);
|
||||
}
|
||||
"pytest-parametrize-values-row-type" | "pytest_parametrize_values_row_type" => {
|
||||
plugins.insert(Plugin::Flake8PytestStyle);
|
||||
}
|
||||
"pytest-raises-require-match-for" | "pytest_raises_require_match_for" => {
|
||||
plugins.insert(Plugin::Flake8PytestStyle);
|
||||
}
|
||||
"pytest-mark-no-parentheses" | "pytest_mark_no_parentheses" => {
|
||||
plugins.insert(Plugin::Flake8PytestStyle);
|
||||
}
|
||||
// flake8-quotes
|
||||
"quotes" | "inline-quotes" | "inline_quotes" => {
|
||||
plugins.insert(Plugin::Flake8Quotes);
|
||||
}
|
||||
"multiline-quotes" | "multiline_quotes" => {
|
||||
plugins.insert(Plugin::Flake8Quotes);
|
||||
}
|
||||
"docstring-quotes" | "docstring_quotes" => {
|
||||
plugins.insert(Plugin::Flake8Quotes);
|
||||
}
|
||||
"avoid-escape" | "avoid_escape" => {
|
||||
plugins.insert(Plugin::Flake8Quotes);
|
||||
}
|
||||
// flake8-tidy-imports
|
||||
"ban-relative-imports" | "ban_relative_imports" => {
|
||||
plugins.insert(Plugin::Flake8TidyImports);
|
||||
}
|
||||
"banned-modules" | "banned_modules" => {
|
||||
plugins.insert(Plugin::Flake8TidyImports);
|
||||
}
|
||||
// mccabe
|
||||
"max-complexity" | "max_complexity" => {
|
||||
plugins.insert(Plugin::McCabe);
|
||||
}
|
||||
// pep8-naming
|
||||
"ignore-names" | "ignore_names" => {
|
||||
plugins.insert(Plugin::PEP8Naming);
|
||||
}
|
||||
"classmethod-decorators" | "classmethod_decorators" => {
|
||||
plugins.insert(Plugin::PEP8Naming);
|
||||
}
|
||||
"staticmethod-decorators" | "staticmethod_decorators" => {
|
||||
plugins.insert(Plugin::PEP8Naming);
|
||||
}
|
||||
"max-string-length" | "max_string_length" => {
|
||||
plugins.insert(Plugin::Flake8ErrMsg);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Vec::from_iter(plugins)
|
||||
}
|
||||
|
||||
/// Infer the enabled plugins based on the referenced prefixes.
|
||||
///
|
||||
/// For example, if the user ignores `ANN101`, we should infer that
|
||||
/// `flake8-annotations` is active.
|
||||
pub(crate) fn infer_plugins_from_codes(selectors: &HashSet<RuleSelector>) -> Vec<Plugin> {
|
||||
// Ignore cases in which we've knowingly changed rule prefixes.
|
||||
[
|
||||
Plugin::Flake82020,
|
||||
Plugin::Flake8Annotations,
|
||||
Plugin::Flake8Bandit,
|
||||
// Plugin::Flake8BlindExcept,
|
||||
Plugin::Flake8BooleanTrap,
|
||||
Plugin::Flake8Bugbear,
|
||||
Plugin::Flake8Builtins,
|
||||
// Plugin::Flake8Commas,
|
||||
Plugin::Flake8Comprehensions,
|
||||
Plugin::Flake8Datetimez,
|
||||
Plugin::Flake8Debugger,
|
||||
Plugin::Flake8Docstrings,
|
||||
// Plugin::Flake8Eradicate,
|
||||
Plugin::Flake8ErrMsg,
|
||||
Plugin::Flake8Executable,
|
||||
Plugin::Flake8ImplicitStrConcat,
|
||||
// Plugin::Flake8ImportConventions,
|
||||
Plugin::Flake8NoPep420,
|
||||
Plugin::Flake8Pie,
|
||||
Plugin::Flake8Print,
|
||||
Plugin::Flake8PytestStyle,
|
||||
Plugin::Flake8Quotes,
|
||||
Plugin::Flake8Return,
|
||||
Plugin::Flake8Simplify,
|
||||
// Plugin::Flake8TidyImports,
|
||||
// Plugin::Flake8TypeChecking,
|
||||
Plugin::Flake8UnusedArguments,
|
||||
// Plugin::Flake8UsePathlib,
|
||||
Plugin::McCabe,
|
||||
Plugin::PEP8Naming,
|
||||
Plugin::PandasVet,
|
||||
Plugin::Tryceratops,
|
||||
]
|
||||
.into_iter()
|
||||
.filter(|plugin| {
|
||||
for selector in selectors {
|
||||
if selector
|
||||
.rules(&PreviewOptions::default())
|
||||
.any(|rule| Linter::from(plugin).rules().any(|r| r == rule))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::collections::HashMap;
|
||||
|
||||
use super::{infer_plugins_from_options, Plugin};
|
||||
|
||||
#[test]
|
||||
fn it_infers_plugins() {
|
||||
let actual = infer_plugins_from_options(&HashMap::from([(
|
||||
"inline-quotes".to_string(),
|
||||
Some("single".to_string()),
|
||||
)]));
|
||||
let expected = vec![Plugin::Flake8Quotes];
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
let actual = infer_plugins_from_options(&HashMap::from([(
|
||||
"staticmethod-decorators".to_string(),
|
||||
Some("[]".to_string()),
|
||||
)]));
|
||||
let expected = vec![Plugin::PEP8Naming];
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::Result;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::black::Black;
|
||||
use super::isort::Isort;
|
||||
use super::pep621::Project;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub(crate) struct Tools {
|
||||
pub(crate) black: Option<Black>,
|
||||
pub(crate) isort: Option<Isort>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub(crate) struct Pyproject {
|
||||
pub(crate) tool: Option<Tools>,
|
||||
pub(crate) project: Option<Project>,
|
||||
}
|
||||
|
||||
pub(crate) fn parse<P: AsRef<Path>>(path: P) -> Result<Pyproject> {
|
||||
let contents = std::fs::read_to_string(path)?;
|
||||
let pyproject = toml::from_str::<Pyproject>(&contents)?;
|
||||
Ok(pyproject)
|
||||
}
|
||||
@@ -31,17 +31,17 @@ name = "formatter"
|
||||
harness = false
|
||||
|
||||
[dependencies]
|
||||
once_cell.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
url = "2.5.0"
|
||||
ureq = "2.9.1"
|
||||
criterion = { version = "0.5.1", default-features = false }
|
||||
codspeed-criterion-compat = { version="2.3.3", default-features = false, optional = true}
|
||||
once_cell = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
url = { workspace = true }
|
||||
ureq = { workspace = true }
|
||||
criterion = { workspace = true, default-features = false }
|
||||
codspeed-criterion-compat = { workspace = true, default-features = false, optional = true}
|
||||
|
||||
[dev-dependencies]
|
||||
ruff_linter.path = "../ruff_linter"
|
||||
ruff_python_ast.path = "../ruff_python_ast"
|
||||
ruff_linter = { path = "../ruff_linter" }
|
||||
ruff_python_ast = { path = "../ruff_python_ast" }
|
||||
ruff_python_formatter = { path = "../ruff_python_formatter" }
|
||||
ruff_python_index = { path = "../ruff_python_index" }
|
||||
ruff_python_parser = { path = "../ruff_python_parser" }
|
||||
@@ -53,7 +53,7 @@ workspace = true
|
||||
codspeed = ["codspeed-criterion-compat"]
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dev-dependencies]
|
||||
mimalloc = "0.1.39"
|
||||
mimalloc = { workspace = true }
|
||||
|
||||
[target.'cfg(all(not(target_os = "windows"), not(target_os = "openbsd"), any(target_arch = "x86_64", target_arch = "aarch64", target_arch = "powerpc64")))'.dev-dependencies]
|
||||
tikv-jemallocator = "0.5.0"
|
||||
tikv-jemallocator = { workspace = true }
|
||||
|
||||
@@ -65,7 +65,7 @@ fn benchmark_formatter(criterion: &mut Criterion) {
|
||||
let comment_ranges = comment_ranges.finish();
|
||||
|
||||
// Parse the AST.
|
||||
let module = parse_tokens(tokens, case.code(), Mode::Module, "<filename>")
|
||||
let module = parse_tokens(tokens, case.code(), Mode::Module)
|
||||
.expect("Input to be a valid python program");
|
||||
|
||||
b.iter(|| {
|
||||
|
||||
@@ -2,7 +2,7 @@ use ruff_benchmark::criterion::{
|
||||
criterion_group, criterion_main, BenchmarkGroup, BenchmarkId, Criterion, Throughput,
|
||||
};
|
||||
use ruff_benchmark::{TestCase, TestFile, TestFileDownloadError};
|
||||
use ruff_linter::linter::lint_only;
|
||||
use ruff_linter::linter::{lint_only, ParseSource};
|
||||
use ruff_linter::rule_selector::PreviewOptions;
|
||||
use ruff_linter::settings::rule_table::RuleTable;
|
||||
use ruff_linter::settings::types::PreviewMode;
|
||||
@@ -10,6 +10,7 @@ use ruff_linter::settings::{flags, LinterSettings};
|
||||
use ruff_linter::source_kind::SourceKind;
|
||||
use ruff_linter::{registry::Rule, RuleSelector};
|
||||
use ruff_python_ast::PySourceType;
|
||||
use ruff_python_parser::{lexer, parse_program_tokens, Mode};
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
#[global_allocator]
|
||||
@@ -53,7 +54,12 @@ fn benchmark_linter(mut group: BenchmarkGroup, settings: &LinterSettings) {
|
||||
BenchmarkId::from_parameter(case.name()),
|
||||
&case,
|
||||
|b, case| {
|
||||
let kind = SourceKind::Python(case.code().to_string());
|
||||
// Tokenize the source.
|
||||
let tokens: Vec<_> = lexer::lex(case.code(), Mode::Module).collect();
|
||||
|
||||
// Parse the source.
|
||||
let ast = parse_program_tokens(tokens.clone(), case.code(), false).unwrap();
|
||||
|
||||
b.iter(|| {
|
||||
let path = case.path();
|
||||
let result = lint_only(
|
||||
@@ -61,8 +67,12 @@ fn benchmark_linter(mut group: BenchmarkGroup, settings: &LinterSettings) {
|
||||
None,
|
||||
settings,
|
||||
flags::Noqa::Enabled,
|
||||
&kind,
|
||||
&SourceKind::Python(case.code().to_string()),
|
||||
PySourceType::from(path.as_path()),
|
||||
ParseSource::Precomputed {
|
||||
tokens: &tokens,
|
||||
ast: &ast,
|
||||
},
|
||||
);
|
||||
|
||||
// Assert that file contains no parse errors
|
||||
|
||||
@@ -60,7 +60,7 @@ fn benchmark_parser(criterion: &mut Criterion<WallTime>) {
|
||||
&case,
|
||||
|b, case| {
|
||||
b.iter(|| {
|
||||
let parsed = parse_suite(case.code(), case.name()).unwrap();
|
||||
let parsed = parse_suite(case.code()).unwrap();
|
||||
|
||||
let mut visitor = CountVisitor { count: 0 };
|
||||
visitor.visit_body(&parsed);
|
||||
|
||||
@@ -16,7 +16,7 @@ glob = { workspace = true }
|
||||
globset = { workspace = true }
|
||||
regex = { workspace = true }
|
||||
filetime = { workspace = true }
|
||||
seahash = "4.1.0"
|
||||
seahash = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
ruff_macros = { path = "../ruff_macros" }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff_cli"
|
||||
version = "0.1.8"
|
||||
version = "0.1.11"
|
||||
publish = false
|
||||
authors = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
@@ -15,67 +15,60 @@ readme = "../../README.md"
|
||||
name = "ruff"
|
||||
|
||||
[dependencies]
|
||||
ruff_linter = { path = "../ruff_linter", features = ["clap"] }
|
||||
ruff_cache = { path = "../ruff_cache" }
|
||||
ruff_diagnostics = { path = "../ruff_diagnostics" }
|
||||
ruff_formatter = { path = "../ruff_formatter" }
|
||||
ruff_notebook = { path = "../ruff_notebook" }
|
||||
ruff_linter = { path = "../ruff_linter", features = ["clap"] }
|
||||
ruff_macros = { path = "../ruff_macros" }
|
||||
ruff_notebook = { path = "../ruff_notebook" }
|
||||
ruff_python_ast = { path = "../ruff_python_ast" }
|
||||
ruff_python_formatter = { path = "../ruff_python_formatter" }
|
||||
ruff_source_file = { path = "../ruff_source_file" }
|
||||
ruff_python_trivia = { path = "../ruff_python_trivia" }
|
||||
ruff_workspace = { path = "../ruff_workspace" }
|
||||
ruff_text_size = { path = "../ruff_text_size" }
|
||||
ruff_workspace = { path = "../ruff_workspace" }
|
||||
|
||||
annotate-snippets = { version = "0.9.2", features = ["color"] }
|
||||
anyhow = { workspace = true }
|
||||
argfile = { version = "0.1.6" }
|
||||
bincode = { version = "1.3.3" }
|
||||
argfile = { workspace = true }
|
||||
bincode = { workspace = true }
|
||||
bitflags = { workspace = true }
|
||||
cachedir = { version = "0.3.0" }
|
||||
cachedir = { workspace = true }
|
||||
chrono = { workspace = true }
|
||||
clap = { workspace = true, features = ["derive", "env"] }
|
||||
clap_complete_command = { version = "0.5.1" }
|
||||
clearscreen = { version = "2.0.0" }
|
||||
clap_complete_command = { workspace = true }
|
||||
clearscreen = { workspace = true }
|
||||
colored = { workspace = true }
|
||||
filetime = { workspace = true }
|
||||
glob = { workspace = true }
|
||||
ignore = { workspace = true }
|
||||
is-macro = { workspace = true }
|
||||
itertools = { workspace = true }
|
||||
log = { workspace = true }
|
||||
notify = { version = "6.1.1" }
|
||||
notify = { workspace = true }
|
||||
path-absolutize = { workspace = true, features = ["once_cell_cache"] }
|
||||
rayon = { version = "1.8.0" }
|
||||
rayon = { workspace = true }
|
||||
regex = { workspace = true }
|
||||
ruff_python_stdlib = { path = "../ruff_python_stdlib" }
|
||||
rustc-hash = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
shellexpand = { workspace = true }
|
||||
similar = { workspace = true }
|
||||
strum = { workspace = true, features = [] }
|
||||
thiserror = { workspace = true }
|
||||
tracing = { workspace = true, features = ["log"] }
|
||||
walkdir = { version = "2.3.2" }
|
||||
wild = { version = "2" }
|
||||
walkdir = { workspace = true }
|
||||
wild = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
assert_cmd = { version = "2.0.8" }
|
||||
assert_cmd = { workspace = true }
|
||||
# Avoid writing colored snapshots when running tests from the terminal
|
||||
colored = { workspace = true, features = ["no-color"]}
|
||||
insta = { workspace = true, features = ["filters", "json"] }
|
||||
insta-cmd = { version = "0.4.0" }
|
||||
tempfile = "3.8.1"
|
||||
insta-cmd = { workspace = true }
|
||||
tempfile = { workspace = true }
|
||||
test-case = { workspace = true }
|
||||
ureq = { version = "2.9.1", features = [] }
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
mimalloc = "0.1.39"
|
||||
mimalloc = { workspace = true }
|
||||
|
||||
[target.'cfg(all(not(target_os = "windows"), not(target_os = "openbsd"), any(target_arch = "x86_64", target_arch = "aarch64", target_arch = "powerpc64")))'.dependencies]
|
||||
tikv-jemallocator = "0.5.0"
|
||||
tikv-jemallocator = { workspace = true }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@@ -25,10 +25,9 @@ use ruff_notebook::NotebookIndex;
|
||||
use ruff_python_ast::imports::ImportMap;
|
||||
use ruff_source_file::SourceFileBuilder;
|
||||
use ruff_text_size::{TextRange, TextSize};
|
||||
use ruff_workspace::resolver::{PyprojectConfig, PyprojectDiscoveryStrategy, Resolver};
|
||||
use ruff_workspace::resolver::Resolver;
|
||||
use ruff_workspace::Settings;
|
||||
|
||||
use crate::cache;
|
||||
use crate::diagnostics::Diagnostics;
|
||||
|
||||
/// [`Path`] that is relative to the package root in [`PackageCache`].
|
||||
@@ -86,6 +85,7 @@ pub(crate) struct Cache {
|
||||
changes: Mutex<Vec<Change>>,
|
||||
/// The "current" timestamp used as cache for the updates of
|
||||
/// [`FileCache::last_seen`]
|
||||
#[allow(clippy::struct_field_names)]
|
||||
last_seen_cache: u64,
|
||||
}
|
||||
|
||||
@@ -442,7 +442,7 @@ pub(super) struct CacheMessage {
|
||||
pub(crate) trait PackageCaches {
|
||||
fn get(&self, package_root: &Path) -> Option<&Cache>;
|
||||
|
||||
fn persist(self) -> anyhow::Result<()>;
|
||||
fn persist(self) -> Result<()>;
|
||||
}
|
||||
|
||||
impl<T> PackageCaches for Option<T>
|
||||
@@ -468,27 +468,17 @@ pub(crate) struct PackageCacheMap<'a>(FxHashMap<&'a Path, Cache>);
|
||||
|
||||
impl<'a> PackageCacheMap<'a> {
|
||||
pub(crate) fn init(
|
||||
pyproject_config: &PyprojectConfig,
|
||||
package_roots: &FxHashMap<&'a Path, Option<&'a Path>>,
|
||||
resolver: &Resolver,
|
||||
) -> Self {
|
||||
fn init_cache(path: &Path) {
|
||||
if let Err(e) = cache::init(path) {
|
||||
if let Err(e) = init(path) {
|
||||
error!("Failed to initialize cache at {}: {e:?}", path.display());
|
||||
}
|
||||
}
|
||||
|
||||
match pyproject_config.strategy {
|
||||
PyprojectDiscoveryStrategy::Fixed => {
|
||||
init_cache(&pyproject_config.settings.cache_dir);
|
||||
}
|
||||
PyprojectDiscoveryStrategy::Hierarchical => {
|
||||
for settings in
|
||||
std::iter::once(&pyproject_config.settings).chain(resolver.settings())
|
||||
{
|
||||
init_cache(&settings.cache_dir);
|
||||
}
|
||||
}
|
||||
for settings in resolver.settings() {
|
||||
init_cache(&settings.cache_dir);
|
||||
}
|
||||
|
||||
Self(
|
||||
@@ -498,7 +488,7 @@ impl<'a> PackageCacheMap<'a> {
|
||||
.unique()
|
||||
.par_bridge()
|
||||
.map(|cache_root| {
|
||||
let settings = resolver.resolve(cache_root, pyproject_config);
|
||||
let settings = resolver.resolve(cache_root);
|
||||
let cache = Cache::open(cache_root.to_path_buf(), settings);
|
||||
(cache_root, cache)
|
||||
})
|
||||
|
||||
@@ -38,7 +38,6 @@ pub(crate) fn add_noqa(
|
||||
.flatten()
|
||||
.map(ResolvedFile::path)
|
||||
.collect::<Vec<_>>(),
|
||||
pyproject_config,
|
||||
);
|
||||
|
||||
let start = Instant::now();
|
||||
@@ -57,7 +56,7 @@ pub(crate) fn add_noqa(
|
||||
.parent()
|
||||
.and_then(|parent| package_roots.get(parent))
|
||||
.and_then(|package| *package);
|
||||
let settings = resolver.resolve(path, pyproject_config);
|
||||
let settings = resolver.resolve(path);
|
||||
let source_kind = match SourceKind::from_path(path, source_type) {
|
||||
Ok(Some(source_kind)) => source_kind,
|
||||
Ok(None) => return None,
|
||||
|
||||
@@ -57,16 +57,11 @@ pub(crate) fn check(
|
||||
.flatten()
|
||||
.map(ResolvedFile::path)
|
||||
.collect::<Vec<_>>(),
|
||||
pyproject_config,
|
||||
);
|
||||
|
||||
// Load the caches.
|
||||
let caches = if bool::from(cache) {
|
||||
Some(PackageCacheMap::init(
|
||||
pyproject_config,
|
||||
&package_roots,
|
||||
&resolver,
|
||||
))
|
||||
Some(PackageCacheMap::init(&package_roots, &resolver))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@@ -81,7 +76,7 @@ pub(crate) fn check(
|
||||
.and_then(|parent| package_roots.get(parent))
|
||||
.and_then(|package| *package);
|
||||
|
||||
let settings = resolver.resolve(path, pyproject_config);
|
||||
let settings = resolver.resolve(path);
|
||||
|
||||
if (settings.file_resolver.force_exclude || !resolved_file.is_root())
|
||||
&& match_exclusion(
|
||||
@@ -128,7 +123,7 @@ pub(crate) fn check(
|
||||
|
||||
Some(result.unwrap_or_else(|(path, message)| {
|
||||
if let Some(path) = &path {
|
||||
let settings = resolver.resolve(path, pyproject_config);
|
||||
let settings = resolver.resolve(path);
|
||||
if settings.linter.rules.enabled(Rule::IOError) {
|
||||
let dummy =
|
||||
SourceFileBuilder::new(path.to_string_lossy().as_ref(), "").finish();
|
||||
|
||||
@@ -4,7 +4,7 @@ use anyhow::Result;
|
||||
|
||||
use ruff_linter::packaging;
|
||||
use ruff_linter::settings::flags;
|
||||
use ruff_workspace::resolver::{match_exclusion, python_file_at_path, PyprojectConfig};
|
||||
use ruff_workspace::resolver::{match_exclusion, python_file_at_path, PyprojectConfig, Resolver};
|
||||
|
||||
use crate::args::CliOverrides;
|
||||
use crate::diagnostics::{lint_stdin, Diagnostics};
|
||||
@@ -18,20 +18,20 @@ pub(crate) fn check_stdin(
|
||||
noqa: flags::Noqa,
|
||||
fix_mode: flags::FixMode,
|
||||
) -> Result<Diagnostics> {
|
||||
if pyproject_config.settings.file_resolver.force_exclude {
|
||||
let mut resolver = Resolver::new(pyproject_config);
|
||||
|
||||
if resolver.force_exclude() {
|
||||
if let Some(filename) = filename {
|
||||
if !python_file_at_path(filename, pyproject_config, overrides)? {
|
||||
if !python_file_at_path(filename, &mut resolver, overrides)? {
|
||||
if fix_mode.is_apply() {
|
||||
parrot_stdin()?;
|
||||
}
|
||||
return Ok(Diagnostics::default());
|
||||
}
|
||||
|
||||
let lint_settings = &pyproject_config.settings.linter;
|
||||
if filename
|
||||
.file_name()
|
||||
.is_some_and(|name| match_exclusion(filename, name, &lint_settings.exclude))
|
||||
{
|
||||
if filename.file_name().is_some_and(|name| {
|
||||
match_exclusion(filename, name, &resolver.base_settings().linter.exclude)
|
||||
}) {
|
||||
if fix_mode.is_apply() {
|
||||
parrot_stdin()?;
|
||||
}
|
||||
@@ -41,13 +41,13 @@ pub(crate) fn check_stdin(
|
||||
}
|
||||
let stdin = read_from_stdin()?;
|
||||
let package_root = filename.and_then(Path::parent).and_then(|path| {
|
||||
packaging::detect_package_root(path, &pyproject_config.settings.linter.namespace_packages)
|
||||
packaging::detect_package_root(path, &resolver.base_settings().linter.namespace_packages)
|
||||
});
|
||||
let mut diagnostics = lint_stdin(
|
||||
filename,
|
||||
package_root,
|
||||
stdin,
|
||||
&pyproject_config.settings,
|
||||
resolver.base_settings(),
|
||||
noqa,
|
||||
fix_mode,
|
||||
)?;
|
||||
|
||||
@@ -17,7 +17,7 @@ use tracing::debug;
|
||||
|
||||
use ruff_diagnostics::SourceMap;
|
||||
use ruff_linter::fs;
|
||||
use ruff_linter::logging::LogLevel;
|
||||
use ruff_linter::logging::{DisplayParseError, LogLevel};
|
||||
use ruff_linter::registry::Rule;
|
||||
use ruff_linter::rules::flake8_quotes::settings::Quote;
|
||||
use ruff_linter::source_kind::{SourceError, SourceKind};
|
||||
@@ -25,9 +25,7 @@ use ruff_linter::warn_user_once;
|
||||
use ruff_python_ast::{PySourceType, SourceType};
|
||||
use ruff_python_formatter::{format_module_source, FormatModuleError, QuoteStyle};
|
||||
use ruff_text_size::{TextLen, TextRange, TextSize};
|
||||
use ruff_workspace::resolver::{
|
||||
match_exclusion, python_files_in_path, PyprojectConfig, ResolvedFile, Resolver,
|
||||
};
|
||||
use ruff_workspace::resolver::{match_exclusion, python_files_in_path, ResolvedFile, Resolver};
|
||||
use ruff_workspace::FormatterSettings;
|
||||
|
||||
use crate::args::{CliOverrides, FormatArguments};
|
||||
@@ -79,7 +77,7 @@ pub(crate) fn format(
|
||||
return Ok(ExitStatus::Success);
|
||||
}
|
||||
|
||||
warn_incompatible_formatter_settings(&pyproject_config, Some(&resolver));
|
||||
warn_incompatible_formatter_settings(&resolver);
|
||||
|
||||
// Discover the package root for each Python file.
|
||||
let package_roots = resolver.package_roots(
|
||||
@@ -88,7 +86,6 @@ pub(crate) fn format(
|
||||
.flatten()
|
||||
.map(ResolvedFile::path)
|
||||
.collect::<Vec<_>>(),
|
||||
&pyproject_config,
|
||||
);
|
||||
|
||||
let caches = if cli.no_cache {
|
||||
@@ -99,11 +96,7 @@ pub(crate) fn format(
|
||||
#[cfg(debug_assertions)]
|
||||
crate::warn_user!("Detected debug build without --no-cache.");
|
||||
|
||||
Some(PackageCacheMap::init(
|
||||
&pyproject_config,
|
||||
&package_roots,
|
||||
&resolver,
|
||||
))
|
||||
Some(PackageCacheMap::init(&package_roots, &resolver))
|
||||
};
|
||||
|
||||
let start = Instant::now();
|
||||
@@ -118,7 +111,7 @@ pub(crate) fn format(
|
||||
return None;
|
||||
};
|
||||
|
||||
let settings = resolver.resolve(path, &pyproject_config);
|
||||
let settings = resolver.resolve(path);
|
||||
|
||||
// Ignore files that are excluded from formatting
|
||||
if (settings.file_resolver.force_exclude || !resolved_file.is_root())
|
||||
@@ -244,7 +237,7 @@ pub(crate) fn format_path(
|
||||
// Extract the sources from the file.
|
||||
let unformatted = match SourceKind::from_path(path, source_type) {
|
||||
Ok(Some(source_kind)) => source_kind,
|
||||
// Non Python Jupyter notebook
|
||||
// Non-Python Jupyter notebook.
|
||||
Ok(None) => return Ok(FormatResult::Skipped),
|
||||
Err(err) => {
|
||||
return Err(FormatCommandError::Read(Some(path.to_path_buf()), err));
|
||||
@@ -321,12 +314,22 @@ pub(crate) fn format_source(
|
||||
path: Option<&Path>,
|
||||
settings: &FormatterSettings,
|
||||
) -> Result<FormattedSource, FormatCommandError> {
|
||||
match source_kind {
|
||||
match &source_kind {
|
||||
SourceKind::Python(unformatted) => {
|
||||
let options = settings.to_format_options(source_type, unformatted);
|
||||
|
||||
let formatted = format_module_source(unformatted, options)
|
||||
.map_err(|err| FormatCommandError::Format(path.map(Path::to_path_buf), err))?;
|
||||
let formatted = format_module_source(unformatted, options).map_err(|err| {
|
||||
if let FormatModuleError::ParseError(err) = err {
|
||||
DisplayParseError::from_source_kind(
|
||||
err,
|
||||
path.map(Path::to_path_buf),
|
||||
source_kind,
|
||||
)
|
||||
.into()
|
||||
} else {
|
||||
FormatCommandError::Format(path.map(Path::to_path_buf), err)
|
||||
}
|
||||
})?;
|
||||
|
||||
let formatted = formatted.into_code();
|
||||
if formatted.len() == unformatted.len() && formatted == *unformatted {
|
||||
@@ -352,8 +355,19 @@ pub(crate) fn format_source(
|
||||
let unformatted = ¬ebook.source_code()[range];
|
||||
|
||||
// Format the cell.
|
||||
let formatted = format_module_source(unformatted, options.clone())
|
||||
.map_err(|err| FormatCommandError::Format(path.map(Path::to_path_buf), err))?;
|
||||
let formatted =
|
||||
format_module_source(unformatted, options.clone()).map_err(|err| {
|
||||
if let FormatModuleError::ParseError(err) = err {
|
||||
DisplayParseError::from_source_kind(
|
||||
err,
|
||||
path.map(Path::to_path_buf),
|
||||
source_kind,
|
||||
)
|
||||
.into()
|
||||
} else {
|
||||
FormatCommandError::Format(path.map(Path::to_path_buf), err)
|
||||
}
|
||||
})?;
|
||||
|
||||
// If the cell is unchanged, skip it.
|
||||
let formatted = formatted.as_code();
|
||||
@@ -408,11 +422,13 @@ pub(crate) fn format_source(
|
||||
pub(crate) enum FormatResult {
|
||||
/// The file was formatted.
|
||||
Formatted,
|
||||
|
||||
/// The file was formatted, [`SourceKind`] contains the formatted code
|
||||
Diff {
|
||||
unformatted: SourceKind,
|
||||
formatted: SourceKind,
|
||||
},
|
||||
|
||||
/// The file was unchanged, as the formatted contents matched the existing contents.
|
||||
Unchanged,
|
||||
|
||||
@@ -515,7 +531,7 @@ impl<'a> FormatResults<'a> {
|
||||
if changed > 0 && unchanged > 0 {
|
||||
writeln!(
|
||||
f,
|
||||
"{} file{} {}, {} file{} left unchanged",
|
||||
"{} file{} {}, {} file{} {}",
|
||||
changed,
|
||||
if changed == 1 { "" } else { "s" },
|
||||
match self.mode {
|
||||
@@ -524,6 +540,10 @@ impl<'a> FormatResults<'a> {
|
||||
},
|
||||
unchanged,
|
||||
if unchanged == 1 { "" } else { "s" },
|
||||
match self.mode {
|
||||
FormatMode::Write => "left unchanged",
|
||||
FormatMode::Check | FormatMode::Diff => "already formatted",
|
||||
},
|
||||
)
|
||||
} else if changed > 0 {
|
||||
writeln!(
|
||||
@@ -539,9 +559,13 @@ impl<'a> FormatResults<'a> {
|
||||
} else if unchanged > 0 {
|
||||
writeln!(
|
||||
f,
|
||||
"{} file{} left unchanged",
|
||||
"{} file{} {}",
|
||||
unchanged,
|
||||
if unchanged == 1 { "" } else { "s" },
|
||||
match self.mode {
|
||||
FormatMode::Write => "left unchanged",
|
||||
FormatMode::Check | FormatMode::Diff => "already formatted",
|
||||
},
|
||||
)
|
||||
} else {
|
||||
Ok(())
|
||||
@@ -553,6 +577,7 @@ impl<'a> FormatResults<'a> {
|
||||
#[derive(Error, Debug)]
|
||||
pub(crate) enum FormatCommandError {
|
||||
Ignore(#[from] ignore::Error),
|
||||
Parse(#[from] DisplayParseError),
|
||||
Panic(Option<PathBuf>, PanicError),
|
||||
Read(Option<PathBuf>, SourceError),
|
||||
Format(Option<PathBuf>, FormatModuleError),
|
||||
@@ -570,6 +595,7 @@ impl FormatCommandError {
|
||||
None
|
||||
}
|
||||
}
|
||||
Self::Parse(err) => err.path(),
|
||||
Self::Panic(path, _)
|
||||
| Self::Read(path, _)
|
||||
| Self::Format(path, _)
|
||||
@@ -603,6 +629,9 @@ impl Display for FormatCommandError {
|
||||
)
|
||||
}
|
||||
}
|
||||
Self::Parse(err) => {
|
||||
write!(f, "{err}")
|
||||
}
|
||||
Self::Read(path, err) => {
|
||||
if let Some(path) = path {
|
||||
write!(
|
||||
@@ -687,15 +716,10 @@ impl Display for FormatCommandError {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn warn_incompatible_formatter_settings(
|
||||
pyproject_config: &PyprojectConfig,
|
||||
resolver: Option<&Resolver>,
|
||||
) {
|
||||
pub(super) fn warn_incompatible_formatter_settings(resolver: &Resolver) {
|
||||
// First, collect all rules that are incompatible regardless of the linter-specific settings.
|
||||
let mut incompatible_rules = FxHashSet::default();
|
||||
for setting in std::iter::once(&pyproject_config.settings)
|
||||
.chain(resolver.iter().flat_map(|resolver| resolver.settings()))
|
||||
{
|
||||
for setting in resolver.settings() {
|
||||
for rule in [
|
||||
// The formatter might collapse implicit string concatenation on a single line.
|
||||
Rule::SingleLineImplicitStringConcatenation,
|
||||
@@ -724,9 +748,7 @@ pub(super) fn warn_incompatible_formatter_settings(
|
||||
}
|
||||
|
||||
// Next, validate settings-specific incompatibilities.
|
||||
for setting in std::iter::once(&pyproject_config.settings)
|
||||
.chain(resolver.iter().flat_map(|resolver| resolver.settings()))
|
||||
{
|
||||
for setting in resolver.settings() {
|
||||
// Validate all rules that rely on tab styles.
|
||||
if setting.linter.rules.enabled(Rule::TabIndentation)
|
||||
&& setting.formatter.indent_style.is_tab()
|
||||
|
||||
@@ -6,7 +6,7 @@ use log::error;
|
||||
|
||||
use ruff_linter::source_kind::SourceKind;
|
||||
use ruff_python_ast::{PySourceType, SourceType};
|
||||
use ruff_workspace::resolver::{match_exclusion, python_file_at_path};
|
||||
use ruff_workspace::resolver::{match_exclusion, python_file_at_path, Resolver};
|
||||
use ruff_workspace::FormatterSettings;
|
||||
|
||||
use crate::args::{CliOverrides, FormatArguments};
|
||||
@@ -27,24 +27,23 @@ pub(crate) fn format_stdin(cli: &FormatArguments, overrides: &CliOverrides) -> R
|
||||
cli.stdin_filename.as_deref(),
|
||||
)?;
|
||||
|
||||
warn_incompatible_formatter_settings(&pyproject_config, None);
|
||||
let mut resolver = Resolver::new(&pyproject_config);
|
||||
warn_incompatible_formatter_settings(&resolver);
|
||||
|
||||
let mode = FormatMode::from_cli(cli);
|
||||
|
||||
if pyproject_config.settings.file_resolver.force_exclude {
|
||||
if resolver.force_exclude() {
|
||||
if let Some(filename) = cli.stdin_filename.as_deref() {
|
||||
if !python_file_at_path(filename, &pyproject_config, overrides)? {
|
||||
if !python_file_at_path(filename, &mut resolver, overrides)? {
|
||||
if mode.is_write() {
|
||||
parrot_stdin()?;
|
||||
}
|
||||
return Ok(ExitStatus::Success);
|
||||
}
|
||||
|
||||
let format_settings = &pyproject_config.settings.formatter;
|
||||
if filename
|
||||
.file_name()
|
||||
.is_some_and(|name| match_exclusion(filename, name, &format_settings.exclude))
|
||||
{
|
||||
if filename.file_name().is_some_and(|name| {
|
||||
match_exclusion(filename, name, &resolver.base_settings().formatter.exclude)
|
||||
}) {
|
||||
if mode.is_write() {
|
||||
parrot_stdin()?;
|
||||
}
|
||||
@@ -63,12 +62,7 @@ pub(crate) fn format_stdin(cli: &FormatArguments, overrides: &CliOverrides) -> R
|
||||
};
|
||||
|
||||
// Format the file.
|
||||
match format_source_code(
|
||||
path,
|
||||
&pyproject_config.settings.formatter,
|
||||
source_type,
|
||||
mode,
|
||||
) {
|
||||
match format_source_code(path, &resolver.base_settings().formatter, source_type, mode) {
|
||||
Ok(result) => match mode {
|
||||
FormatMode::Write => Ok(ExitStatus::Success),
|
||||
FormatMode::Check | FormatMode::Diff => {
|
||||
|
||||
@@ -18,6 +18,7 @@ struct Explanation<'a> {
|
||||
summary: &'a str,
|
||||
message_formats: &'a [&'a str],
|
||||
fix: String,
|
||||
#[allow(clippy::struct_field_names)]
|
||||
explanation: Option<&'a str>,
|
||||
preview: bool,
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ pub(crate) fn show_settings(
|
||||
bail!("No files found under the given path");
|
||||
};
|
||||
|
||||
let settings = resolver.resolve(&path, pyproject_config);
|
||||
let settings = resolver.resolve(&path);
|
||||
|
||||
writeln!(writer, "Resolved settings for: {path:?}")?;
|
||||
if let Some(settings_path) = pyproject_config.path.as_ref() {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#![cfg_attr(target_family = "wasm", allow(dead_code))]
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::ops::{Add, AddAssign};
|
||||
@@ -10,9 +11,8 @@ use colored::Colorize;
|
||||
use log::{debug, error, warn};
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::cache::{Cache, FileCacheKey, LintCacheData};
|
||||
use ruff_diagnostics::Diagnostic;
|
||||
use ruff_linter::linter::{lint_fix, lint_only, FixTable, FixerResult, LinterResult};
|
||||
use ruff_linter::linter::{lint_fix, lint_only, FixTable, FixerResult, LinterResult, ParseSource};
|
||||
use ruff_linter::logging::DisplayParseError;
|
||||
use ruff_linter::message::Message;
|
||||
use ruff_linter::pyproject_toml::lint_pyproject_toml;
|
||||
@@ -24,10 +24,12 @@ use ruff_linter::{fs, IOError, SyntaxError};
|
||||
use ruff_notebook::{Notebook, NotebookError, NotebookIndex};
|
||||
use ruff_python_ast::imports::ImportMap;
|
||||
use ruff_python_ast::{PySourceType, SourceType, TomlSourceType};
|
||||
use ruff_source_file::{LineIndex, SourceCode, SourceFileBuilder};
|
||||
use ruff_source_file::SourceFileBuilder;
|
||||
use ruff_text_size::{TextRange, TextSize};
|
||||
use ruff_workspace::Settings;
|
||||
|
||||
use crate::cache::{Cache, FileCacheKey, LintCacheData};
|
||||
|
||||
#[derive(Debug, Default, PartialEq)]
|
||||
pub(crate) struct Diagnostics {
|
||||
pub(crate) messages: Vec<Message>,
|
||||
@@ -272,6 +274,7 @@ pub(crate) fn lint_path(
|
||||
data: (messages, imports),
|
||||
error: parse_error,
|
||||
},
|
||||
transformed,
|
||||
fixed,
|
||||
) = if matches!(fix_mode, flags::FixMode::Apply | flags::FixMode::Diff) {
|
||||
if let Ok(FixerResult {
|
||||
@@ -300,17 +303,40 @@ pub(crate) fn lint_path(
|
||||
flags::FixMode::Generate => {}
|
||||
}
|
||||
}
|
||||
(result, fixed)
|
||||
let transformed = if let Cow::Owned(transformed) = transformed {
|
||||
transformed
|
||||
} else {
|
||||
source_kind
|
||||
};
|
||||
(result, transformed, fixed)
|
||||
} else {
|
||||
// If we fail to fix, lint the original source code.
|
||||
let result = lint_only(path, package, settings, noqa, &source_kind, source_type);
|
||||
let result = lint_only(
|
||||
path,
|
||||
package,
|
||||
settings,
|
||||
noqa,
|
||||
&source_kind,
|
||||
source_type,
|
||||
ParseSource::None,
|
||||
);
|
||||
let transformed = source_kind;
|
||||
let fixed = FxHashMap::default();
|
||||
(result, fixed)
|
||||
(result, transformed, fixed)
|
||||
}
|
||||
} else {
|
||||
let result = lint_only(path, package, settings, noqa, &source_kind, source_type);
|
||||
let result = lint_only(
|
||||
path,
|
||||
package,
|
||||
settings,
|
||||
noqa,
|
||||
&source_kind,
|
||||
source_type,
|
||||
ParseSource::None,
|
||||
);
|
||||
let transformed = source_kind;
|
||||
let fixed = FxHashMap::default();
|
||||
(result, fixed)
|
||||
(result, transformed, fixed)
|
||||
};
|
||||
|
||||
let imports = imports.unwrap_or_default();
|
||||
@@ -318,7 +344,7 @@ pub(crate) fn lint_path(
|
||||
if let Some((cache, relative_path, key)) = caching {
|
||||
// We don't cache parsing errors.
|
||||
if parse_error.is_none() {
|
||||
// `FixMode::Generate` and `FixMode::Diff` rely on side-effects (writing to disk,
|
||||
// `FixMode::Apply` and `FixMode::Diff` rely on side-effects (writing to disk,
|
||||
// and writing the diff to stdout, respectively). If a file has diagnostics, we
|
||||
// need to avoid reading from and writing to the cache in these modes.
|
||||
if match fix_mode {
|
||||
@@ -333,28 +359,21 @@ pub(crate) fn lint_path(
|
||||
LintCacheData::from_messages(
|
||||
&messages,
|
||||
imports.clone(),
|
||||
source_kind.as_ipy_notebook().map(Notebook::index).cloned(),
|
||||
transformed.as_ipy_notebook().map(Notebook::index).cloned(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(err) = parse_error {
|
||||
if let Some(error) = parse_error {
|
||||
error!(
|
||||
"{}",
|
||||
DisplayParseError::new(
|
||||
err,
|
||||
SourceCode::new(
|
||||
source_kind.source_code(),
|
||||
&LineIndex::from_source_text(source_kind.source_code())
|
||||
),
|
||||
&source_kind,
|
||||
)
|
||||
DisplayParseError::from_source_kind(error, Some(path.to_path_buf()), &transformed)
|
||||
);
|
||||
}
|
||||
|
||||
let notebook_indexes = if let SourceKind::IpyNotebook(notebook) = source_kind {
|
||||
let notebook_indexes = if let SourceKind::IpyNotebook(notebook) = transformed {
|
||||
FxHashMap::from_iter([(path.to_string_lossy().to_string(), notebook.into_index())])
|
||||
} else {
|
||||
FxHashMap::default()
|
||||
@@ -405,6 +424,7 @@ pub(crate) fn lint_stdin(
|
||||
data: (messages, imports),
|
||||
error: parse_error,
|
||||
},
|
||||
transformed,
|
||||
fixed,
|
||||
) = if matches!(fix_mode, flags::FixMode::Apply | flags::FixMode::Diff) {
|
||||
if let Ok(FixerResult {
|
||||
@@ -433,8 +453,12 @@ pub(crate) fn lint_stdin(
|
||||
}
|
||||
flags::FixMode::Generate => {}
|
||||
}
|
||||
|
||||
(result, fixed)
|
||||
let transformed = if let Cow::Owned(transformed) = transformed {
|
||||
transformed
|
||||
} else {
|
||||
source_kind
|
||||
};
|
||||
(result, transformed, fixed)
|
||||
} else {
|
||||
// If we fail to fix, lint the original source code.
|
||||
let result = lint_only(
|
||||
@@ -444,15 +468,17 @@ pub(crate) fn lint_stdin(
|
||||
noqa,
|
||||
&source_kind,
|
||||
source_type,
|
||||
ParseSource::None,
|
||||
);
|
||||
let fixed = FxHashMap::default();
|
||||
|
||||
// Write the contents to stdout anyway.
|
||||
if fix_mode.is_apply() {
|
||||
source_kind.write(&mut io::stdout().lock())?;
|
||||
}
|
||||
|
||||
(result, fixed)
|
||||
let transformed = source_kind;
|
||||
let fixed = FxHashMap::default();
|
||||
(result, transformed, fixed)
|
||||
}
|
||||
} else {
|
||||
let result = lint_only(
|
||||
@@ -462,21 +488,23 @@ pub(crate) fn lint_stdin(
|
||||
noqa,
|
||||
&source_kind,
|
||||
source_type,
|
||||
ParseSource::None,
|
||||
);
|
||||
let transformed = source_kind;
|
||||
let fixed = FxHashMap::default();
|
||||
(result, fixed)
|
||||
(result, transformed, fixed)
|
||||
};
|
||||
|
||||
let imports = imports.unwrap_or_default();
|
||||
|
||||
if let Some(err) = parse_error {
|
||||
if let Some(error) = parse_error {
|
||||
error!(
|
||||
"Failed to parse {}: {err}",
|
||||
path.map_or_else(|| "-".into(), fs::relativize_path).bold()
|
||||
"{}",
|
||||
DisplayParseError::from_source_kind(error, path.map(Path::to_path_buf), &transformed)
|
||||
);
|
||||
}
|
||||
|
||||
let notebook_indexes = if let SourceKind::IpyNotebook(notebook) = source_kind {
|
||||
let notebook_indexes = if let SourceKind::IpyNotebook(notebook) = transformed {
|
||||
FxHashMap::from_iter([(
|
||||
path.map_or_else(|| "-".into(), |path| path.to_string_lossy().to_string()),
|
||||
notebook.into_index(),
|
||||
|
||||
@@ -255,7 +255,7 @@ fn mixed_line_endings() -> Result<()> {
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
2 files left unchanged
|
||||
2 files already formatted
|
||||
"###);
|
||||
Ok(())
|
||||
}
|
||||
@@ -328,6 +328,86 @@ OTHER = "OTHER"
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn syntax_error() -> Result<()> {
|
||||
let tempdir = TempDir::new()?;
|
||||
|
||||
fs::write(
|
||||
tempdir.path().join("main.py"),
|
||||
r#"
|
||||
from module import =
|
||||
"#,
|
||||
)?;
|
||||
|
||||
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
||||
.current_dir(tempdir.path())
|
||||
.args(["format", "--no-cache", "--isolated", "--check"])
|
||||
.arg("main.py"), @r###"
|
||||
success: false
|
||||
exit_code: 2
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
error: Failed to parse main.py:2:20: Unexpected token '='
|
||||
"###);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn messages() -> Result<()> {
|
||||
let tempdir = TempDir::new()?;
|
||||
|
||||
fs::write(
|
||||
tempdir.path().join("main.py"),
|
||||
r#"
|
||||
from test import say_hy
|
||||
|
||||
if __name__ == "__main__":
|
||||
say_hy("dear Ruff contributor")
|
||||
"#,
|
||||
)?;
|
||||
|
||||
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
||||
.current_dir(tempdir.path())
|
||||
.args(["format", "--no-cache", "--isolated", "--check"])
|
||||
.arg("main.py"), @r###"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
Would reformat: main.py
|
||||
1 file would be reformatted
|
||||
|
||||
----- stderr -----
|
||||
"###);
|
||||
|
||||
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
||||
.current_dir(tempdir.path())
|
||||
.args(["format", "--no-cache", "--isolated"])
|
||||
.arg("main.py"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
1 file reformatted
|
||||
|
||||
----- stderr -----
|
||||
"###);
|
||||
|
||||
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
||||
.current_dir(tempdir.path())
|
||||
.args(["format", "--no-cache", "--isolated"])
|
||||
.arg("main.py"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
1 file left unchanged
|
||||
|
||||
----- stderr -----
|
||||
"###);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn force_exclude() -> Result<()> {
|
||||
let tempdir = TempDir::new()?;
|
||||
@@ -592,7 +672,8 @@ format = "json"
|
||||
|
||||
----- stderr -----
|
||||
ruff failed
|
||||
Cause: Failed to parse `[RUFF-TOML-PATH]`: TOML parse error at line 2, column 10
|
||||
Cause: Failed to parse [RUFF-TOML-PATH]
|
||||
Cause: TOML parse error at line 2, column 10
|
||||
|
|
||||
2 | format = "json"
|
||||
| ^^^^^^
|
||||
@@ -876,7 +957,7 @@ fn test_diff() {
|
||||
|
||||
|
||||
----- stderr -----
|
||||
2 files would be reformatted, 1 file left unchanged
|
||||
2 files would be reformatted, 1 file already formatted
|
||||
"###);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -284,7 +284,8 @@ fn stdin_fix_jupyter() {
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import os"
|
||||
"import os\n",
|
||||
"print(1)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -302,7 +303,8 @@ fn stdin_fix_jupyter() {
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import sys"
|
||||
"import sys\n",
|
||||
"print(x)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -354,8 +356,8 @@ fn stdin_fix_jupyter() {
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}"#), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
{
|
||||
"cells": [
|
||||
@@ -365,7 +367,9 @@ fn stdin_fix_jupyter() {
|
||||
"id": "dccc687c-96e2-4604-b957-a8a89b5bec06",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
"source": [
|
||||
"print(1)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -381,7 +385,9 @@ fn stdin_fix_jupyter() {
|
||||
"id": "cdce7b92-b0fb-4c02-86f6-e233b26fa84f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
"source": [
|
||||
"print(x)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -433,7 +439,8 @@ fn stdin_fix_jupyter() {
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
----- stderr -----
|
||||
Found 2 errors (2 fixed, 0 remaining).
|
||||
Jupyter.ipynb:cell 3:1:7: F821 Undefined name `x`
|
||||
Found 3 errors (2 fixed, 1 remaining).
|
||||
"###);
|
||||
}
|
||||
|
||||
@@ -719,6 +726,22 @@ fn stdin_format_jupyter() {
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stdin_parse_error() {
|
||||
let mut cmd = RuffCheck::default().build();
|
||||
assert_cmd_snapshot!(cmd
|
||||
.pass_stdin("from foo import =\n"), @r###"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
-:1:17: E999 SyntaxError: Unexpected token '='
|
||||
Found 1 error.
|
||||
|
||||
----- stderr -----
|
||||
error: Failed to parse at 1:17: Unexpected token '='
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn show_source() {
|
||||
let mut cmd = RuffCheck::default().args(["--show-source"]).build();
|
||||
@@ -743,6 +766,7 @@ fn show_source() {
|
||||
fn explain_status_codes_f401() {
|
||||
assert_cmd_snapshot!(ruff_cmd().args(["--explain", "F401"]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn explain_status_codes_ruf404() {
|
||||
assert_cmd_snapshot!(ruff_cmd().args(["--explain", "RUF404"]), @r###"
|
||||
@@ -1047,7 +1071,10 @@ fn unreadable_pyproject_toml() -> Result<()> {
|
||||
err.chain()
|
||||
.map(std::string::ToString::to_string)
|
||||
.collect::<Vec<_>>(),
|
||||
vec!["Permission denied (os error 13)".to_string()],
|
||||
vec![
|
||||
format!("Failed to read {}/pyproject.toml", tempdir.path().display()),
|
||||
"Permission denied (os error 13)".to_string()
|
||||
],
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ ruff_python_ast = { path = "../ruff_python_ast" }
|
||||
ruff_python_codegen = { path = "../ruff_python_codegen" }
|
||||
ruff_python_formatter = { path = "../ruff_python_formatter" }
|
||||
ruff_notebook = { path = "../ruff_notebook" }
|
||||
ruff_python_literal = { path = "../ruff_python_literal" }
|
||||
ruff_python_parser = { path = "../ruff_python_parser" }
|
||||
ruff_python_stdlib = { path = "../ruff_python_stdlib" }
|
||||
ruff_python_trivia = { path = "../ruff_python_trivia" }
|
||||
@@ -28,28 +27,27 @@ ruff_workspace = { path = "../ruff_workspace", features = ["schemars"]}
|
||||
anyhow = { workspace = true }
|
||||
clap = { workspace = true }
|
||||
ignore = { workspace = true }
|
||||
indicatif = "0.17.7"
|
||||
imara-diff = { workspace = true }
|
||||
indicatif = { workspace = true }
|
||||
itertools = { workspace = true }
|
||||
libcst = { workspace = true }
|
||||
once_cell = { workspace = true }
|
||||
pretty_assertions = { version = "1.3.0" }
|
||||
rayon = "1.8.0"
|
||||
pretty_assertions = { workspace = true }
|
||||
rayon = { workspace = true }
|
||||
regex = { workspace = true }
|
||||
schemars = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true }
|
||||
similar = { workspace = true }
|
||||
strum = { workspace = true }
|
||||
strum_macros = { workspace = true }
|
||||
tempfile = "3.8.1"
|
||||
tempfile = { workspace = true }
|
||||
toml = { workspace = true, features = ["parse"] }
|
||||
tracing = { workspace = true }
|
||||
tracing-indicatif = { workspace = true }
|
||||
tracing-subscriber = { workspace = true, features = ["env-filter"] }
|
||||
imara-diff = "0.1.5"
|
||||
|
||||
[dev-dependencies]
|
||||
indoc = "2.0.4"
|
||||
indoc = { workspace = true }
|
||||
|
||||
[features]
|
||||
# Turn off rayon for profiling
|
||||
|
||||
@@ -27,7 +27,7 @@ use tracing_subscriber::layer::SubscriberExt;
|
||||
use tracing_subscriber::util::SubscriberInitExt;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
|
||||
use ruff_cli::args::{FormatCommand, LogLevelArgs};
|
||||
use ruff_cli::args::{CliOverrides, FormatArguments, FormatCommand, LogLevelArgs};
|
||||
use ruff_cli::resolve::resolve;
|
||||
use ruff_formatter::{FormatError, LineWidth, PrintError};
|
||||
use ruff_linter::logging::LogLevel;
|
||||
@@ -35,26 +35,27 @@ use ruff_linter::settings::types::{FilePattern, FilePatternSet};
|
||||
use ruff_python_formatter::{
|
||||
format_module_source, FormatModuleError, MagicTrailingComma, PreviewMode, PyFormatOptions,
|
||||
};
|
||||
use ruff_python_parser::ParseError;
|
||||
use ruff_workspace::resolver::{python_files_in_path, PyprojectConfig, ResolvedFile, Resolver};
|
||||
|
||||
/// Find files that ruff would check so we can format them. Adapted from `ruff_cli`.
|
||||
#[allow(clippy::type_complexity)]
|
||||
fn ruff_check_paths(
|
||||
dirs: &[PathBuf],
|
||||
) -> anyhow::Result<(
|
||||
Vec<Result<ResolvedFile, ignore::Error>>,
|
||||
Resolver,
|
||||
PyprojectConfig,
|
||||
)> {
|
||||
fn parse_cli(dirs: &[PathBuf]) -> anyhow::Result<(FormatArguments, CliOverrides)> {
|
||||
let args_matches = FormatCommand::command()
|
||||
.no_binary_name(true)
|
||||
.get_matches_from(dirs);
|
||||
let arguments: FormatCommand = FormatCommand::from_arg_matches(&args_matches)?;
|
||||
let (cli, overrides) = arguments.partition();
|
||||
Ok((cli, overrides))
|
||||
}
|
||||
|
||||
/// Find the [`PyprojectConfig`] to use for formatting.
|
||||
fn find_pyproject_config(
|
||||
cli: &FormatArguments,
|
||||
overrides: &CliOverrides,
|
||||
) -> anyhow::Result<PyprojectConfig> {
|
||||
let mut pyproject_config = resolve(
|
||||
cli.isolated,
|
||||
cli.config.as_deref(),
|
||||
&overrides,
|
||||
overrides,
|
||||
cli.stdin_filename.as_deref(),
|
||||
)?;
|
||||
// We don't want to format pyproject.toml
|
||||
@@ -63,11 +64,18 @@ fn ruff_check_paths(
|
||||
FilePattern::Builtin("*.pyi"),
|
||||
])
|
||||
.unwrap();
|
||||
let (paths, resolver) = python_files_in_path(&cli.files, &pyproject_config, &overrides)?;
|
||||
if paths.is_empty() {
|
||||
bail!("no python files in {:?}", dirs)
|
||||
}
|
||||
Ok((paths, resolver, pyproject_config))
|
||||
Ok(pyproject_config)
|
||||
}
|
||||
|
||||
/// Find files that ruff would check so we can format them. Adapted from `ruff_cli`.
|
||||
#[allow(clippy::type_complexity)]
|
||||
fn ruff_check_paths<'a>(
|
||||
pyproject_config: &'a PyprojectConfig,
|
||||
cli: &FormatArguments,
|
||||
overrides: &CliOverrides,
|
||||
) -> anyhow::Result<(Vec<Result<ResolvedFile, ignore::Error>>, Resolver<'a>)> {
|
||||
let (paths, resolver) = python_files_in_path(&cli.files, pyproject_config, overrides)?;
|
||||
Ok((paths, resolver))
|
||||
}
|
||||
|
||||
/// Collects statistics over the formatted files to compute the Jaccard index or the similarity
|
||||
@@ -215,6 +223,7 @@ pub(crate) struct Args {
|
||||
#[arg(long)]
|
||||
pub(crate) files_with_errors: Option<u32>,
|
||||
#[clap(flatten)]
|
||||
#[allow(clippy::struct_field_names)]
|
||||
pub(crate) log_level_args: LogLevelArgs,
|
||||
}
|
||||
|
||||
@@ -450,11 +459,17 @@ fn format_dev_project(
|
||||
files[0].display()
|
||||
);
|
||||
|
||||
// TODO(konstin): black excludes
|
||||
// TODO(konstin): Respect black's excludes.
|
||||
|
||||
// Find files to check (or in this case, format twice). Adapted from ruff_cli
|
||||
// First argument is ignored
|
||||
let (paths, resolver, pyproject_config) = ruff_check_paths(files)?;
|
||||
let (cli, overrides) = parse_cli(files)?;
|
||||
let pyproject_config = find_pyproject_config(&cli, &overrides)?;
|
||||
let (paths, resolver) = ruff_check_paths(&pyproject_config, &cli, &overrides)?;
|
||||
|
||||
if paths.is_empty() {
|
||||
bail!("No Python files found under the given path(s)");
|
||||
}
|
||||
|
||||
let results = {
|
||||
let pb_span =
|
||||
@@ -467,14 +482,7 @@ fn format_dev_project(
|
||||
#[cfg(feature = "singlethreaded")]
|
||||
let iter = { paths.into_iter() };
|
||||
iter.map(|path| {
|
||||
let result = format_dir_entry(
|
||||
path,
|
||||
stability_check,
|
||||
write,
|
||||
&black_options,
|
||||
&resolver,
|
||||
&pyproject_config,
|
||||
);
|
||||
let result = format_dir_entry(path, stability_check, write, &black_options, &resolver);
|
||||
pb_span.pb_inc(1);
|
||||
result
|
||||
})
|
||||
@@ -524,14 +532,13 @@ fn format_dev_project(
|
||||
})
|
||||
}
|
||||
|
||||
/// Error handling in between walkdir and `format_dev_file`
|
||||
/// Error handling in between walkdir and `format_dev_file`.
|
||||
fn format_dir_entry(
|
||||
resolved_file: Result<ResolvedFile, ignore::Error>,
|
||||
stability_check: bool,
|
||||
write: bool,
|
||||
options: &BlackOptions,
|
||||
resolver: &Resolver,
|
||||
pyproject_config: &PyprojectConfig,
|
||||
) -> anyhow::Result<(Result<Statistics, CheckFileError>, PathBuf), Error> {
|
||||
let resolved_file = resolved_file.context("Iterating the files in the repository failed")?;
|
||||
// For some reason it does not filter in the beginning
|
||||
@@ -542,7 +549,7 @@ fn format_dir_entry(
|
||||
let path = resolved_file.into_path();
|
||||
let mut options = options.to_py_format_options(&path);
|
||||
|
||||
let settings = resolver.resolve(&path, pyproject_config);
|
||||
let settings = resolver.resolve(&path);
|
||||
// That's a bad way of doing this but it's not worth doing something better for format_dev
|
||||
if settings.formatter.line_width != LineWidth::default() {
|
||||
options = options.with_line_width(settings.formatter.line_width);
|
||||
@@ -742,11 +749,11 @@ enum CheckFileError {
|
||||
reformatted: String,
|
||||
},
|
||||
/// The input file was already invalid (not a bug)
|
||||
SyntaxErrorInInput(FormatModuleError),
|
||||
SyntaxErrorInInput(ParseError),
|
||||
/// The formatter introduced a syntax error
|
||||
SyntaxErrorInOutput {
|
||||
formatted: String,
|
||||
error: FormatModuleError,
|
||||
error: ParseError,
|
||||
},
|
||||
/// The formatter failed (bug)
|
||||
FormatError(FormatError),
|
||||
@@ -796,7 +803,7 @@ fn format_dev_file(
|
||||
let start = Instant::now();
|
||||
let printed = match format_module_source(&content, options.clone()) {
|
||||
Ok(printed) => printed,
|
||||
Err(err @ (FormatModuleError::LexError(_) | FormatModuleError::ParseError(_))) => {
|
||||
Err(FormatModuleError::ParseError(err)) => {
|
||||
return Err(CheckFileError::SyntaxErrorInInput(err));
|
||||
}
|
||||
Err(FormatModuleError::FormatError(err)) => {
|
||||
@@ -823,7 +830,7 @@ fn format_dev_file(
|
||||
if stability_check {
|
||||
let reformatted = match format_module_source(formatted, options) {
|
||||
Ok(reformatted) => reformatted,
|
||||
Err(err @ (FormatModuleError::LexError(_) | FormatModuleError::ParseError(_))) => {
|
||||
Err(FormatModuleError::ParseError(err)) => {
|
||||
return Err(CheckFileError::SyntaxErrorInOutput {
|
||||
formatted: formatted.to_string(),
|
||||
error: err,
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
//! Used for <https://docs.astral.sh/ruff/rules/>.
|
||||
|
||||
use itertools::Itertools;
|
||||
use std::borrow::Cow;
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use ruff_diagnostics::FixAvailability;
|
||||
@@ -37,6 +38,16 @@ fn generate_table(table_out: &mut String, rules: impl IntoIterator<Item = Rule>,
|
||||
|
||||
let rule_name = rule.as_ref();
|
||||
|
||||
// If the message ends in a bracketed expression (like: "Use {replacement}"), escape the
|
||||
// brackets. Otherwise, it'll be interpreted as an HTML attribute via the `attr_list`
|
||||
// plugin. (Above, we'd convert to "Use {replacement\}".)
|
||||
let message = rule.message_formats()[0];
|
||||
let message = if let Some(prefix) = message.strip_suffix('}') {
|
||||
Cow::Owned(format!("{prefix}\\}}"))
|
||||
} else {
|
||||
Cow::Borrowed(message)
|
||||
};
|
||||
|
||||
#[allow(clippy::or_fun_call)]
|
||||
table_out.push_str(&format!(
|
||||
"| {0}{1} {{ #{0}{1} }} | {2} | {3} | {4} |",
|
||||
@@ -46,7 +57,7 @@ fn generate_table(table_out: &mut String, rules: impl IntoIterator<Item = Rule>,
|
||||
.is_some()
|
||||
.then_some(format_args!("[{rule_name}](rules/{rule_name}.md)"))
|
||||
.unwrap_or(format_args!("{rule_name}")),
|
||||
rule.message_formats()[0],
|
||||
message,
|
||||
status_token,
|
||||
));
|
||||
table_out.push('\n');
|
||||
|
||||
@@ -24,11 +24,7 @@ pub(crate) fn main(args: &Args) -> Result<()> {
|
||||
args.file.display()
|
||||
)
|
||||
})?;
|
||||
let python_ast = parse(
|
||||
source_kind.source_code(),
|
||||
source_type.as_mode(),
|
||||
&args.file.to_string_lossy(),
|
||||
)?;
|
||||
let python_ast = parse(source_kind.source_code(), source_type.as_mode())?;
|
||||
println!("{python_ast:#?}");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ pub(crate) fn main(args: &Args) -> Result<()> {
|
||||
println!("{}", ruff_notebook::round_trip(path)?);
|
||||
} else {
|
||||
let contents = fs::read_to_string(&args.file)?;
|
||||
println!("{}", round_trip(&contents, &args.file.to_string_lossy())?);
|
||||
println!("{}", round_trip(&contents)?);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ use ruff_text_size::{Ranged, TextRange, TextSize};
|
||||
|
||||
/// A text edit to be applied to a source file. Inserts, deletes, or replaces
|
||||
/// content at a given location.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct Edit {
|
||||
/// The start location of the edit.
|
||||
|
||||
@@ -15,7 +15,7 @@ ruff_cache = { path = "../ruff_cache" }
|
||||
ruff_macros = { path = "../ruff_macros" }
|
||||
ruff_text_size = { path = "../ruff_text_size" }
|
||||
|
||||
drop_bomb = { version = "0.1.5" }
|
||||
drop_bomb = { workspace = true }
|
||||
rustc-hash = { workspace = true }
|
||||
schemars = { workspace = true, optional = true }
|
||||
serde = { workspace = true, optional = true }
|
||||
|
||||
@@ -1472,6 +1472,11 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> {
|
||||
}
|
||||
|
||||
fn fits_text(&mut self, text: Text, args: PrintElementArgs) -> Fits {
|
||||
fn exceeds_width(fits: &FitsMeasurer, args: PrintElementArgs) -> bool {
|
||||
fits.state.line_width > fits.options().line_width.into()
|
||||
&& !args.measure_mode().allows_text_overflow()
|
||||
}
|
||||
|
||||
let indent = std::mem::take(&mut self.state.pending_indent);
|
||||
self.state.line_width +=
|
||||
u32::from(indent.level()) * self.options().indent_width() + u32::from(indent.align());
|
||||
@@ -1493,7 +1498,13 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> {
|
||||
return Fits::No;
|
||||
}
|
||||
match args.measure_mode() {
|
||||
MeasureMode::FirstLine => return Fits::Yes,
|
||||
MeasureMode::FirstLine => {
|
||||
return if exceeds_width(self, args) {
|
||||
Fits::No
|
||||
} else {
|
||||
Fits::Yes
|
||||
};
|
||||
}
|
||||
MeasureMode::AllLines
|
||||
| MeasureMode::AllLinesAllowTextOverflow => {
|
||||
self.state.line_width = 0;
|
||||
@@ -1511,9 +1522,7 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> {
|
||||
}
|
||||
}
|
||||
|
||||
if self.state.line_width > self.options().line_width.into()
|
||||
&& !args.measure_mode().allows_text_overflow()
|
||||
{
|
||||
if exceeds_width(self, args) {
|
||||
return Fits::No;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ license = { workspace = true }
|
||||
ruff_macros = { path = "../ruff_macros" }
|
||||
|
||||
[dev-dependencies]
|
||||
static_assertions = "1.1.0"
|
||||
static_assertions = { workspace = true }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ruff_linter"
|
||||
version = "0.1.8"
|
||||
version = "0.1.11"
|
||||
publish = false
|
||||
authors = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
@@ -29,37 +29,38 @@ ruff_python_parser = { path = "../ruff_python_parser" }
|
||||
ruff_source_file = { path = "../ruff_source_file", features = ["serde"] }
|
||||
ruff_text_size = { path = "../ruff_text_size" }
|
||||
|
||||
aho-corasick = { version = "1.1.2" }
|
||||
annotate-snippets = { version = "0.9.2", features = ["color"] }
|
||||
aho-corasick = { workspace = true }
|
||||
annotate-snippets = { workspace = true, features = ["color"] }
|
||||
anyhow = { workspace = true }
|
||||
bitflags = { workspace = true }
|
||||
chrono = { workspace = true }
|
||||
clap = { workspace = true, features = ["derive", "string"], optional = true }
|
||||
colored = { workspace = true }
|
||||
fern = { version = "0.6.1" }
|
||||
fern = { workspace = true }
|
||||
glob = { workspace = true }
|
||||
globset = { workspace = true }
|
||||
imperative = { version = "1.0.4" }
|
||||
imperative = { workspace = true }
|
||||
is-macro = { workspace = true }
|
||||
is-wsl = { workspace = true }
|
||||
itertools = { workspace = true }
|
||||
libcst = { workspace = true }
|
||||
log = { workspace = true }
|
||||
memchr = { workspace = true }
|
||||
natord = { version = "1.0.9" }
|
||||
natord = { workspace = true }
|
||||
once_cell = { workspace = true }
|
||||
path-absolutize = { workspace = true, features = [
|
||||
"once_cell_cache",
|
||||
"use_unix_paths_on_wasm",
|
||||
] }
|
||||
pathdiff = { version = "0.2.1" }
|
||||
pep440_rs = { version = "0.3.12", features = ["serde"] }
|
||||
pyproject-toml = { version = "0.8.1" }
|
||||
quick-junit = { version = "0.3.5" }
|
||||
pathdiff = { workspace = true }
|
||||
pep440_rs = { workspace = true, features = ["serde"] }
|
||||
pyproject-toml = { workspace = true }
|
||||
quick-junit = { workspace = true }
|
||||
regex = { workspace = true }
|
||||
result-like = { version = "0.4.6" }
|
||||
result-like = { workspace = true }
|
||||
rustc-hash = { workspace = true }
|
||||
schemars = { workspace = true, optional = true }
|
||||
semver = { version = "1.0.20" }
|
||||
semver = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
similar = { workspace = true }
|
||||
@@ -68,19 +69,18 @@ strum = { workspace = true }
|
||||
strum_macros = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
toml = { workspace = true }
|
||||
typed-arena = { version = "2.0.2" }
|
||||
typed-arena = { workspace = true }
|
||||
unicode-width = { workspace = true }
|
||||
unicode_names2 = { workspace = true }
|
||||
url = { version = "2.2.2" }
|
||||
wsl = { version = "0.1.0" }
|
||||
url = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
insta = { workspace = true }
|
||||
pretty_assertions = "1.3.0"
|
||||
pretty_assertions = { workspace = true }
|
||||
test-case = { workspace = true }
|
||||
# Disable colored output in tests
|
||||
colored = { workspace = true, features = ["no-color"] }
|
||||
tempfile = "3.8.1"
|
||||
tempfile = { workspace = true }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
||||
@@ -182,3 +182,123 @@ class Foo(abc.ABC):
|
||||
return 1
|
||||
else:
|
||||
return 1.5
|
||||
|
||||
|
||||
def func(x: int):
|
||||
try:
|
||||
pass
|
||||
except:
|
||||
return 2
|
||||
|
||||
|
||||
def func(x: int):
|
||||
try:
|
||||
pass
|
||||
except:
|
||||
return 2
|
||||
else:
|
||||
return 3
|
||||
|
||||
|
||||
def func(x: int):
|
||||
if not x:
|
||||
raise ValueError
|
||||
else:
|
||||
raise TypeError
|
||||
|
||||
|
||||
def func(x: int):
|
||||
if not x:
|
||||
raise ValueError
|
||||
else:
|
||||
return 1
|
||||
|
||||
|
||||
from typing import overload
|
||||
|
||||
|
||||
@overload
|
||||
def overloaded(i: int) -> "int":
|
||||
...
|
||||
|
||||
|
||||
@overload
|
||||
def overloaded(i: "str") -> "str":
|
||||
...
|
||||
|
||||
|
||||
def overloaded(i):
|
||||
return i
|
||||
|
||||
|
||||
def func(x: int):
|
||||
if not x:
|
||||
return 1
|
||||
raise ValueError
|
||||
|
||||
|
||||
def func(x: int):
|
||||
if not x:
|
||||
return 1
|
||||
else:
|
||||
return 2
|
||||
raise ValueError
|
||||
|
||||
|
||||
def func():
|
||||
try:
|
||||
raise ValueError
|
||||
except:
|
||||
return 2
|
||||
|
||||
|
||||
def func():
|
||||
try:
|
||||
return 1
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def func(x: int):
|
||||
for _ in range(3):
|
||||
if x > 0:
|
||||
return 1
|
||||
raise ValueError
|
||||
|
||||
|
||||
def func(x: int):
|
||||
if x > 5:
|
||||
raise ValueError
|
||||
else:
|
||||
pass
|
||||
|
||||
|
||||
def func(x: int):
|
||||
if x > 5:
|
||||
raise ValueError
|
||||
elif x > 10:
|
||||
pass
|
||||
|
||||
|
||||
def func(x: int):
|
||||
if x > 5:
|
||||
raise ValueError
|
||||
elif x > 10:
|
||||
return 5
|
||||
|
||||
|
||||
def func():
|
||||
try:
|
||||
return 5
|
||||
except:
|
||||
pass
|
||||
|
||||
raise ValueError
|
||||
|
||||
|
||||
def func(x: int):
|
||||
match x:
|
||||
case [1, 2, 3]:
|
||||
return 1
|
||||
case y:
|
||||
return "foo"
|
||||
|
||||
2
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S401.py
vendored
Normal file
2
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S401.py
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
import telnetlib # S401
|
||||
from telnetlib import Telnet # S401
|
||||
2
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S402.py
vendored
Normal file
2
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S402.py
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
import ftplib # S402
|
||||
from ftplib import FTP # S402
|
||||
8
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S403.py
vendored
Normal file
8
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S403.py
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import dill # S403
|
||||
from dill import objects # S403
|
||||
import shelve
|
||||
from shelve import open
|
||||
import cPickle
|
||||
from cPickle import load
|
||||
import pickle
|
||||
from pickle import load
|
||||
3
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S404.py
vendored
Normal file
3
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S404.py
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
import subprocess # S404
|
||||
from subprocess import Popen # S404
|
||||
from subprocess import Popen as pop # S404
|
||||
4
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S405.py
vendored
Normal file
4
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S405.py
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import xml.etree.cElementTree # S405
|
||||
from xml.etree import cElementTree # S405
|
||||
import xml.etree.ElementTree # S405
|
||||
from xml.etree import ElementTree # S405
|
||||
3
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S406.py
vendored
Normal file
3
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S406.py
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
from xml import sax # S406
|
||||
import xml.sax as xmls # S406
|
||||
import xml.sax # S406
|
||||
2
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S407.py
vendored
Normal file
2
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S407.py
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
from xml.dom import expatbuilder # S407
|
||||
import xml.dom.expatbuilder # S407
|
||||
2
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S408.py
vendored
Normal file
2
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S408.py
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
from xml.dom.minidom import parseString # S408
|
||||
import xml.dom.minidom # S408
|
||||
2
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S409.py
vendored
Normal file
2
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S409.py
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
from xml.dom.pulldom import parseString # S409
|
||||
import xml.dom.pulldom # S409
|
||||
2
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S410.py
vendored
Normal file
2
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S410.py
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
import lxml # S410
|
||||
from lxml import etree # S410
|
||||
2
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S411.py
vendored
Normal file
2
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S411.py
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
import xmlrpc # S411
|
||||
from xmlrpc import server # S411
|
||||
1
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S412.py
vendored
Normal file
1
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S412.py
vendored
Normal file
@@ -0,0 +1 @@
|
||||
from twisted.web.twcgi import CGIScript # S412
|
||||
4
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S413.py
vendored
Normal file
4
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S413.py
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import Crypto.Hash # S413
|
||||
from Crypto.Hash import MD2 # S413
|
||||
import Crypto.PublicKey # S413
|
||||
from Crypto.PublicKey import RSA # S413
|
||||
3
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S415.py
vendored
Normal file
3
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S415.py
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
import pyghmi # S415
|
||||
from pyghmi import foo # S415
|
||||
|
||||
16
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S502.py
vendored
Normal file
16
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S502.py
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
import ssl
|
||||
from ssl import wrap_socket
|
||||
from OpenSSL import SSL
|
||||
from OpenSSL.SSL import Context
|
||||
|
||||
wrap_socket(ssl_version=ssl.PROTOCOL_SSLv3) # S502
|
||||
ssl.wrap_socket(ssl_version=ssl.PROTOCOL_TLSv1) # S502
|
||||
ssl.wrap_socket(ssl_version=ssl.PROTOCOL_SSLv2) # S502
|
||||
SSL.Context(method=SSL.SSLv2_METHOD) # S502
|
||||
SSL.Context(method=SSL.SSLv23_METHOD) # S502
|
||||
Context(method=SSL.SSLv3_METHOD) # S502
|
||||
Context(method=SSL.TLSv1_METHOD) # S502
|
||||
|
||||
wrap_socket(ssl_version=ssl.PROTOCOL_TLS_CLIENT) # OK
|
||||
SSL.Context(method=SSL.TLS_SERVER_METHOD) # OK
|
||||
func(ssl_version=ssl.PROTOCOL_TLSv1_2) # OK
|
||||
23
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S503.py
vendored
Normal file
23
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S503.py
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
import ssl
|
||||
from OpenSSL import SSL
|
||||
from ssl import PROTOCOL_TLSv1
|
||||
|
||||
|
||||
def func(version=ssl.PROTOCOL_SSLv2): # S503
|
||||
pass
|
||||
|
||||
|
||||
def func(protocol=SSL.SSLv2_METHOD): # S503
|
||||
pass
|
||||
|
||||
|
||||
def func(version=SSL.SSLv23_METHOD): # S503
|
||||
pass
|
||||
|
||||
|
||||
def func(protocol=PROTOCOL_TLSv1): # S503
|
||||
pass
|
||||
|
||||
|
||||
def func(version=SSL.TLSv1_2_METHOD): # OK
|
||||
pass
|
||||
15
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S504.py
vendored
Normal file
15
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S504.py
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
import ssl
|
||||
from ssl import wrap_socket
|
||||
|
||||
ssl.wrap_socket() # S504
|
||||
wrap_socket() # S504
|
||||
ssl.wrap_socket(ssl_version=ssl.PROTOCOL_TLSv1_2) # OK
|
||||
|
||||
|
||||
class Class:
|
||||
def wrap_socket(self):
|
||||
pass
|
||||
|
||||
|
||||
obj = Class()
|
||||
obj.wrap_socket() # OK
|
||||
@@ -2,7 +2,7 @@ import json
|
||||
import yaml
|
||||
from yaml import CSafeLoader
|
||||
from yaml import SafeLoader
|
||||
from yaml import SafeLoader as NewSafeLoader
|
||||
from yaml.loader import SafeLoader as NewSafeLoader
|
||||
|
||||
|
||||
def test_yaml_load():
|
||||
@@ -29,3 +29,8 @@ yaml.load("{}", yaml.SafeLoader)
|
||||
yaml.load("{}", CSafeLoader)
|
||||
yaml.load("{}", yaml.CSafeLoader)
|
||||
yaml.load("{}", NewSafeLoader)
|
||||
yaml.load("{}", Loader=SafeLoader)
|
||||
yaml.load("{}", Loader=yaml.SafeLoader)
|
||||
yaml.load("{}", Loader=CSafeLoader)
|
||||
yaml.load("{}", Loader=yaml.CSafeLoader)
|
||||
yaml.load("{}", Loader=NewSafeLoader)
|
||||
|
||||
@@ -71,6 +71,8 @@ foo.is_(True)
|
||||
bar.is_not(False)
|
||||
next(iter([]), False)
|
||||
sa.func.coalesce(tbl.c.valid, False)
|
||||
setVisible(True)
|
||||
set_visible(True)
|
||||
|
||||
|
||||
class Registry:
|
||||
@@ -114,3 +116,6 @@ from typing import override
|
||||
@override
|
||||
def func(x: bool):
|
||||
pass
|
||||
|
||||
|
||||
settings(True)
|
||||
|
||||
@@ -8,46 +8,14 @@ class MyClass:
|
||||
self.id = 10
|
||||
self.dir = "."
|
||||
|
||||
def str(self):
|
||||
pass
|
||||
|
||||
|
||||
from typing import TypedDict
|
||||
|
||||
|
||||
class MyClass(TypedDict):
|
||||
id: int
|
||||
|
||||
|
||||
from threading import Event
|
||||
|
||||
|
||||
class CustomEvent(Event):
|
||||
def set(self) -> None:
|
||||
...
|
||||
|
||||
def str(self) -> None:
|
||||
...
|
||||
|
||||
|
||||
from logging import Filter, LogRecord
|
||||
|
||||
|
||||
class CustomFilter(Filter):
|
||||
def filter(self, record: LogRecord) -> bool:
|
||||
...
|
||||
|
||||
def str(self) -> None:
|
||||
...
|
||||
|
||||
|
||||
from typing_extensions import override
|
||||
|
||||
|
||||
class MyClass:
|
||||
@override
|
||||
def str(self):
|
||||
pass
|
||||
|
||||
def int(self):
|
||||
pass
|
||||
|
||||
def str(self):
|
||||
pass
|
||||
|
||||
def method_usage(self) -> str:
|
||||
pass
|
||||
|
||||
def attribute_usage(self) -> id:
|
||||
pass
|
||||
|
||||
@@ -165,3 +165,19 @@ class AbstractTestModel5(models.Model):
|
||||
|
||||
def my_beautiful_method(self):
|
||||
return 2
|
||||
|
||||
|
||||
# Subclass with its own __str__
|
||||
class SubclassTestModel1(TestModel1):
|
||||
def __str__(self):
|
||||
return self.new_field
|
||||
|
||||
|
||||
# Subclass with inherited __str__
|
||||
class SubclassTestModel2(TestModel4):
|
||||
pass
|
||||
|
||||
|
||||
# Subclass without __str__
|
||||
class SubclassTestModel3(TestModel1):
|
||||
pass
|
||||
|
||||
@@ -127,3 +127,21 @@ class MultipleConsecutiveFields(models.Model):
|
||||
pass
|
||||
|
||||
middle_name = models.CharField(max_length=32)
|
||||
|
||||
|
||||
class BaseModel(models.Model):
|
||||
pass
|
||||
|
||||
|
||||
class StrBeforeFieldInheritedModel(BaseModel):
|
||||
"""Model with `__str__` before fields."""
|
||||
|
||||
class Meta:
|
||||
verbose_name = "test"
|
||||
verbose_name_plural = "tests"
|
||||
|
||||
def __str__(self):
|
||||
return "foobar"
|
||||
|
||||
first_name = models.CharField(max_length=32)
|
||||
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
import typing
|
||||
import typing_extensions
|
||||
from typing import TypeVar
|
||||
from typing_extensions import ParamSpec, TypeVarTuple
|
||||
|
||||
_T = typing.TypeVar("_T")
|
||||
_P = TypeVar("_P")
|
||||
_Ts = typing_extensions.TypeVarTuple("_Ts")
|
||||
_P = ParamSpec("_P")
|
||||
_P2 = typing.ParamSpec("_P2")
|
||||
_Ts2 = TypeVarTuple("_Ts2")
|
||||
|
||||
# OK
|
||||
_UsedTypeVar = TypeVar("_UsedTypeVar")
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
import typing
|
||||
import typing_extensions
|
||||
from typing import TypeVar
|
||||
from typing_extensions import ParamSpec, TypeVarTuple
|
||||
|
||||
_T = typing.TypeVar("_T")
|
||||
_P = TypeVar("_P")
|
||||
_Ts = typing_extensions.TypeVarTuple("_Ts")
|
||||
_P = ParamSpec("_P")
|
||||
_P2 = typing.ParamSpec("_P2")
|
||||
_Ts2 = TypeVarTuple("_Ts2")
|
||||
|
||||
# OK
|
||||
_UsedTypeVar = TypeVar("_UsedTypeVar")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import typing
|
||||
from typing import Protocol
|
||||
from typing import Protocol, TypeVar
|
||||
|
||||
|
||||
class _Foo(Protocol):
|
||||
@@ -10,9 +10,23 @@ class _Bar(typing.Protocol):
|
||||
bar: int
|
||||
|
||||
|
||||
_T = TypeVar("_T")
|
||||
|
||||
|
||||
class _Baz(Protocol[_T]):
|
||||
x: _T
|
||||
|
||||
|
||||
# OK
|
||||
class _UsedPrivateProtocol(Protocol):
|
||||
bar: int
|
||||
|
||||
|
||||
def uses__UsedPrivateProtocol(arg: _UsedPrivateProtocol) -> None: ...
|
||||
# Also OK
|
||||
class _UsedGenericPrivateProtocol(Protocol[_T]):
|
||||
x: _T
|
||||
|
||||
|
||||
def uses_some_private_protocols(
|
||||
arg: _UsedPrivateProtocol, arg2: _UsedGenericPrivateProtocol[int]
|
||||
) -> None: ...
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import typing
|
||||
from typing import Protocol
|
||||
from typing import Protocol, TypeVar
|
||||
|
||||
|
||||
class _Foo(object, Protocol):
|
||||
@@ -10,9 +10,23 @@ class _Bar(typing.Protocol):
|
||||
bar: int
|
||||
|
||||
|
||||
_T = TypeVar("_T")
|
||||
|
||||
|
||||
class _Baz(Protocol[_T]):
|
||||
x: _T
|
||||
|
||||
|
||||
# OK
|
||||
class _UsedPrivateProtocol(Protocol):
|
||||
bar: int
|
||||
|
||||
|
||||
def uses__UsedPrivateProtocol(arg: _UsedPrivateProtocol) -> None: ...
|
||||
# Also OK
|
||||
class _UsedGenericPrivateProtocol(Protocol[_T]):
|
||||
x: _T
|
||||
|
||||
|
||||
def uses_some_private_protocols(
|
||||
arg: _UsedPrivateProtocol, arg2: _UsedGenericPrivateProtocol[int]
|
||||
) -> None: ...
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
import warnings
|
||||
import typing_extensions
|
||||
from collections.abc import Callable
|
||||
from warnings import deprecated
|
||||
|
||||
|
||||
def f1(x: str = "50 character stringggggggggggggggggggggggggggggggg") -> None:
|
||||
...
|
||||
|
||||
@@ -45,3 +51,24 @@ class Demo:
|
||||
|
||||
def func() -> None:
|
||||
"""Docstrings are excluded from this rule. Some padding."""
|
||||
|
||||
|
||||
@warnings.deprecated("Veeeeeeeeeeeeeeeeeeeeeeery long deprecation message, but that's okay")
|
||||
def deprecated_function() -> None: ...
|
||||
|
||||
|
||||
@typing_extensions.deprecated("Another loooooooooooooooooooooong deprecation message, it's still okay")
|
||||
def another_deprecated_function() -> None: ...
|
||||
|
||||
|
||||
@deprecated("A third loooooooooooooooooooooooooooooong deprecation message")
|
||||
def a_third_deprecated_function() -> None: ...
|
||||
|
||||
|
||||
def not_warnings_dot_deprecated(
|
||||
msg: str
|
||||
) -> Callable[[Callable[[], None]], Callable[[], None]]: ...
|
||||
|
||||
|
||||
@not_warnings_dot_deprecated("Not warnings.deprecated, so this one *should* lead to PYI053 in a stub!")
|
||||
def not_a_deprecated_function() -> None: ...
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
import warnings
|
||||
import typing_extensions
|
||||
from typing_extensions import deprecated
|
||||
|
||||
def f1(x: str = "50 character stringggggggggggggggggggggggggggggggg") -> None: ... # OK
|
||||
def f2(
|
||||
x: str = "51 character stringgggggggggggggggggggggggggggggggg", # Error: PYI053
|
||||
@@ -38,3 +42,25 @@ class Demo:
|
||||
|
||||
def func() -> None:
|
||||
"""Docstrings are excluded from this rule. Some padding.""" # OK
|
||||
|
||||
@warnings.deprecated(
|
||||
"Veeeeeeeeeeeeeeeeeeeeeeery long deprecation message, but that's okay" # OK
|
||||
)
|
||||
def deprecated_function() -> None: ...
|
||||
|
||||
@typing_extensions.deprecated(
|
||||
"Another loooooooooooooooooooooong deprecation message, it's still okay" # OK
|
||||
)
|
||||
def another_deprecated_function() -> None: ...
|
||||
|
||||
@deprecated("A third loooooooooooooooooooooooooooooong deprecation message") # OK
|
||||
def a_third_deprecated_function() -> None: ...
|
||||
|
||||
def not_warnings_dot_deprecated(
|
||||
msg: str
|
||||
) -> Callable[[Callable[[], None]], Callable[[], None]]: ...
|
||||
|
||||
@not_warnings_dot_deprecated(
|
||||
"Not warnings.deprecated, so this one *should* lead to PYI053 in a stub!" # Error: PYI053
|
||||
)
|
||||
def not_a_deprecated_function() -> None: ...
|
||||
|
||||
@@ -37,3 +37,28 @@ def func():
|
||||
|
||||
# PYI055
|
||||
x: Union[type[requests_mock.Mocker], type[httpretty], type[str]] = requests_mock.Mocker
|
||||
|
||||
|
||||
def convert_union(union: UnionType) -> _T | None:
|
||||
converters: tuple[
|
||||
type[_T] | type[Converter[_T]] | Converter[_T] | Callable[[str], _T], ... # PYI055
|
||||
] = union.__args__
|
||||
...
|
||||
|
||||
def convert_union(union: UnionType) -> _T | None:
|
||||
converters: tuple[
|
||||
Union[type[_T] | type[Converter[_T]] | Converter[_T] | Callable[[str], _T]], ... # PYI055
|
||||
] = union.__args__
|
||||
...
|
||||
|
||||
def convert_union(union: UnionType) -> _T | None:
|
||||
converters: tuple[
|
||||
Union[type[_T] | type[Converter[_T]]] | Converter[_T] | Callable[[str], _T], ... # PYI055
|
||||
] = union.__args__
|
||||
...
|
||||
|
||||
def convert_union(union: UnionType) -> _T | None:
|
||||
converters: tuple[
|
||||
Union[type[_T] | type[Converter[_T]] | str] | Converter[_T] | Callable[[str], _T], ... # PYI055
|
||||
] = union.__args__
|
||||
...
|
||||
|
||||
174
crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI058.py
vendored
Normal file
174
crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI058.py
vendored
Normal file
@@ -0,0 +1,174 @@
|
||||
def scope():
|
||||
from collections.abc import Generator
|
||||
|
||||
class IteratorReturningSimpleGenerator1:
|
||||
def __iter__(self) -> Generator:
|
||||
... # PYI058 (use `Iterator`)
|
||||
|
||||
|
||||
def scope():
|
||||
import typing
|
||||
|
||||
class IteratorReturningSimpleGenerator2:
|
||||
def __iter__(self) -> typing.Generator:
|
||||
... # PYI058 (use `Iterator`)
|
||||
|
||||
|
||||
def scope():
|
||||
import collections.abc
|
||||
|
||||
class IteratorReturningSimpleGenerator3:
|
||||
def __iter__(self) -> collections.abc.Generator:
|
||||
... # PYI058 (use `Iterator`)
|
||||
|
||||
|
||||
def scope():
|
||||
import collections.abc
|
||||
from typing import Any
|
||||
|
||||
class IteratorReturningSimpleGenerator4:
|
||||
def __iter__(self, /) -> collections.abc.Generator[str, Any, None]:
|
||||
... # PYI058 (use `Iterator`)
|
||||
|
||||
|
||||
def scope():
|
||||
import collections.abc
|
||||
import typing
|
||||
|
||||
class IteratorReturningSimpleGenerator5:
|
||||
def __iter__(self, /) -> collections.abc.Generator[str, None, typing.Any]:
|
||||
... # PYI058 (use `Iterator`)
|
||||
|
||||
|
||||
def scope():
|
||||
from collections.abc import Generator
|
||||
|
||||
class IteratorReturningSimpleGenerator6:
|
||||
def __iter__(self, /) -> Generator[str, None, None]:
|
||||
... # PYI058 (use `Iterator`)
|
||||
|
||||
|
||||
def scope():
|
||||
import typing_extensions
|
||||
|
||||
class AsyncIteratorReturningSimpleAsyncGenerator1:
|
||||
def __aiter__(
|
||||
self,
|
||||
) -> typing_extensions.AsyncGenerator:
|
||||
... # PYI058 (Use `AsyncIterator`)
|
||||
|
||||
|
||||
def scope():
|
||||
import collections.abc
|
||||
|
||||
class AsyncIteratorReturningSimpleAsyncGenerator2:
|
||||
def __aiter__(self, /) -> collections.abc.AsyncGenerator[str, Any]:
|
||||
... # PYI058 (Use `AsyncIterator`)
|
||||
|
||||
|
||||
def scope():
|
||||
import collections.abc
|
||||
|
||||
class AsyncIteratorReturningSimpleAsyncGenerator3:
|
||||
def __aiter__(self, /) -> collections.abc.AsyncGenerator[str, None]:
|
||||
... # PYI058 (Use `AsyncIterator`)
|
||||
|
||||
|
||||
def scope():
|
||||
from typing import Iterator
|
||||
|
||||
class CorrectIterator:
|
||||
def __iter__(self) -> Iterator[str]:
|
||||
... # OK
|
||||
|
||||
|
||||
def scope():
|
||||
import collections.abc
|
||||
|
||||
class CorrectAsyncIterator:
|
||||
def __aiter__(self) -> collections.abc.AsyncIterator[int]:
|
||||
... # OK
|
||||
|
||||
|
||||
def scope():
|
||||
import typing
|
||||
|
||||
class Fine:
|
||||
def __iter__(self) -> typing.Self:
|
||||
... # OK
|
||||
|
||||
|
||||
def scope():
|
||||
class StrangeButWeWontComplainHere:
|
||||
def __aiter__(self) -> list[bytes]:
|
||||
... # OK
|
||||
|
||||
|
||||
def scope():
|
||||
from collections.abc import Generator
|
||||
|
||||
def __iter__(self) -> Generator:
|
||||
... # OK (not in class scope)
|
||||
|
||||
|
||||
def scope():
|
||||
from collections.abc import AsyncGenerator
|
||||
|
||||
def __aiter__(self) -> AsyncGenerator:
|
||||
... # OK (not in class scope)
|
||||
|
||||
|
||||
def scope():
|
||||
from collections.abc import Generator
|
||||
|
||||
class IteratorReturningComplexGenerator:
|
||||
def __iter__(self) -> Generator[str, int, bytes]:
|
||||
... # OK
|
||||
|
||||
|
||||
def scope():
|
||||
from collections.abc import AsyncGenerator
|
||||
|
||||
class AsyncIteratorReturningComplexAsyncGenerator:
|
||||
def __aiter__(self) -> AsyncGenerator[str, int]:
|
||||
... # OK
|
||||
|
||||
|
||||
def scope():
|
||||
from collections.abc import AsyncGenerator
|
||||
|
||||
class ClassWithInvalidAsyncAiterMethod:
|
||||
async def __aiter__(self) -> AsyncGenerator:
|
||||
... # OK
|
||||
|
||||
|
||||
def scope():
|
||||
from collections.abc import Generator
|
||||
|
||||
class IteratorWithUnusualParameters1:
|
||||
def __iter__(self, foo) -> Generator:
|
||||
... # OK
|
||||
|
||||
|
||||
def scope():
|
||||
from collections.abc import Generator
|
||||
|
||||
class IteratorWithUnusualParameters2:
|
||||
def __iter__(self, *, bar) -> Generator:
|
||||
... # OK
|
||||
|
||||
|
||||
def scope():
|
||||
from collections.abc import Generator
|
||||
|
||||
class IteratorWithUnusualParameters3:
|
||||
def __iter__(self, *args) -> Generator:
|
||||
... # OK
|
||||
|
||||
|
||||
def scope():
|
||||
from collections.abc import Generator
|
||||
|
||||
class IteratorWithUnusualParameters4:
|
||||
def __iter__(self, **kwargs) -> Generator:
|
||||
... # OK
|
||||
128
crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI058.pyi
vendored
Normal file
128
crates/ruff_linter/resources/test/fixtures/flake8_pyi/PYI058.pyi
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
def scope():
|
||||
from collections.abc import Generator
|
||||
|
||||
class IteratorReturningSimpleGenerator1:
|
||||
def __iter__(self) -> Generator: ... # PYI058 (use `Iterator`)
|
||||
|
||||
def scope():
|
||||
import typing
|
||||
|
||||
class IteratorReturningSimpleGenerator2:
|
||||
def __iter__(self) -> typing.Generator: ... # PYI058 (use `Iterator`)
|
||||
|
||||
def scope():
|
||||
import collections.abc
|
||||
|
||||
class IteratorReturningSimpleGenerator3:
|
||||
def __iter__(self) -> collections.abc.Generator: ... # PYI058 (use `Iterator`)
|
||||
|
||||
def scope():
|
||||
import collections.abc
|
||||
from typing import Any
|
||||
|
||||
class IteratorReturningSimpleGenerator4:
|
||||
def __iter__(self, /) -> collections.abc.Generator[str, Any, None]: ... # PYI058 (use `Iterator`)
|
||||
|
||||
def scope():
|
||||
import collections.abc
|
||||
import typing
|
||||
|
||||
class IteratorReturningSimpleGenerator5:
|
||||
def __iter__(self, /) -> collections.abc.Generator[str, None, typing.Any]: ... # PYI058 (use `Iterator`)
|
||||
|
||||
def scope():
|
||||
from collections.abc import Generator
|
||||
|
||||
class IteratorReturningSimpleGenerator6:
|
||||
def __iter__(self, /) -> Generator[str, None, None]: ... # PYI058 (use `Iterator`)
|
||||
|
||||
def scope():
|
||||
import typing_extensions
|
||||
|
||||
class AsyncIteratorReturningSimpleAsyncGenerator1:
|
||||
def __aiter__(self,) -> typing_extensions.AsyncGenerator: ... # PYI058 (Use `AsyncIterator`)
|
||||
|
||||
def scope():
|
||||
import collections.abc
|
||||
|
||||
class AsyncIteratorReturningSimpleAsyncGenerator3:
|
||||
def __aiter__(self, /) -> collections.abc.AsyncGenerator[str, None]:
|
||||
... # PYI058 (Use `AsyncIterator`)
|
||||
|
||||
def scope():
|
||||
import collections.abc
|
||||
|
||||
class AsyncIteratorReturningSimpleAsyncGenerator3:
|
||||
def __aiter__(self, /) -> collections.abc.AsyncGenerator[str, None]: ... # PYI058 (Use `AsyncIterator`)
|
||||
|
||||
def scope():
|
||||
from typing import Iterator
|
||||
|
||||
class CorrectIterator:
|
||||
def __iter__(self) -> Iterator[str]: ... # OK
|
||||
|
||||
def scope():
|
||||
import collections.abc
|
||||
|
||||
class CorrectAsyncIterator:
|
||||
def __aiter__(self) -> collections.abc.AsyncIterator[int]: ... # OK
|
||||
|
||||
def scope():
|
||||
import typing
|
||||
|
||||
class Fine:
|
||||
def __iter__(self) -> typing.Self: ... # OK
|
||||
|
||||
def scope():
|
||||
class StrangeButWeWontComplainHere:
|
||||
def __aiter__(self) -> list[bytes]: ... # OK
|
||||
|
||||
def scope():
|
||||
from collections.abc import Generator
|
||||
def __iter__(self) -> Generator: ... # OK (not in class scope)
|
||||
|
||||
def scope():
|
||||
from collections.abc import AsyncGenerator
|
||||
def __aiter__(self) -> AsyncGenerator: ... # OK (not in class scope)
|
||||
|
||||
def scope():
|
||||
from collections.abc import Generator
|
||||
|
||||
class IteratorReturningComplexGenerator:
|
||||
def __iter__(self) -> Generator[str, int, bytes]: ... # OK
|
||||
|
||||
def scope():
|
||||
from collections.abc import AsyncGenerator
|
||||
|
||||
class AsyncIteratorReturningComplexAsyncGenerator:
|
||||
def __aiter__(self) -> AsyncGenerator[str, int]: ... # OK
|
||||
|
||||
def scope():
|
||||
from collections.abc import AsyncGenerator
|
||||
|
||||
class ClassWithInvalidAsyncAiterMethod:
|
||||
async def __aiter__(self) -> AsyncGenerator: ... # OK
|
||||
|
||||
def scope():
|
||||
from collections.abc import Generator
|
||||
|
||||
class IteratorWithUnusualParameters1:
|
||||
def __iter__(self, foo) -> Generator: ... # OK
|
||||
|
||||
def scope():
|
||||
from collections.abc import Generator
|
||||
|
||||
class IteratorWithUnusualParameters2:
|
||||
def __iter__(self, *, bar) -> Generator: ... # OK
|
||||
|
||||
def scope():
|
||||
from collections.abc import Generator
|
||||
|
||||
class IteratorWithUnusualParameters3:
|
||||
def __iter__(self, *args) -> Generator: ... # OK
|
||||
|
||||
def scope():
|
||||
from collections.abc import Generator
|
||||
|
||||
class IteratorWithUnusualParameters4:
|
||||
def __iter__(self, **kwargs) -> Generator: ... # OK
|
||||
@@ -159,7 +159,7 @@ async with asyncio.timeout(1):
|
||||
async with trio.move_on_at(1):
|
||||
pass
|
||||
|
||||
# Do not supress combination, if a context manager is already combined with another.
|
||||
# Do not suppress combination, if a context manager is already combined with another.
|
||||
async with asyncio.timeout(1), A():
|
||||
async with B():
|
||||
pass
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
# Errors
|
||||
"yoda" == compare # SIM300
|
||||
"yoda" == compare # SIM300
|
||||
42 == age # SIM300
|
||||
("a", "b") == compare # SIM300
|
||||
"yoda" <= compare # SIM300
|
||||
@@ -13,10 +12,17 @@ YODA > age # SIM300
|
||||
YODA >= age # SIM300
|
||||
JediOrder.YODA == age # SIM300
|
||||
0 < (number - 100) # SIM300
|
||||
SomeClass().settings.SOME_CONSTANT_VALUE > (60 * 60) # SIM300
|
||||
B<A[0][0]or B
|
||||
B or(B)<A[0][0]
|
||||
|
||||
# Errors in preview
|
||||
['upper'] == UPPER_LIST
|
||||
{} == DummyHandler.CONFIG
|
||||
|
||||
# Errors in stable
|
||||
UPPER_LIST == ['upper']
|
||||
DummyHandler.CONFIG == {}
|
||||
|
||||
# OK
|
||||
compare == "yoda"
|
||||
age == 42
|
||||
@@ -31,3 +37,6 @@ age <= YODA
|
||||
YODA == YODA
|
||||
age == JediOrder.YODA
|
||||
(number - 100) > 0
|
||||
SECONDS_IN_DAY == 60 * 60 * 24 # Error in 0.1.8
|
||||
SomeClass().settings.SOME_CONSTANT_VALUE > (60 * 60) # Error in 0.1.8
|
||||
{"non-empty-dict": "is-ok"} == DummyHandler.CONFIG
|
||||
|
||||
23
crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM911.py
vendored
Normal file
23
crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM911.py
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
def foo(d: dict[str, str]) -> None:
|
||||
for k, v in zip(d.keys(), d.values()): # SIM911
|
||||
...
|
||||
|
||||
for k, v in zip(d.keys(), d.values(), strict=True): # SIM911
|
||||
...
|
||||
|
||||
for k, v in zip(d.keys(), d.values(), struct=True): # OK
|
||||
...
|
||||
|
||||
|
||||
d1 = d2 = {}
|
||||
|
||||
for k, v in zip(d1.keys(), d2.values()): # OK
|
||||
...
|
||||
|
||||
for k, v in zip(d1.items(), d2.values()): # OK
|
||||
...
|
||||
|
||||
for k, v in zip(d2.keys(), d2.values()): # SIM911
|
||||
...
|
||||
|
||||
items = zip(x.keys(), x.values()) # OK
|
||||
18
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/TCH006_1.py
vendored
Normal file
18
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/TCH006_1.py
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TypeVar
|
||||
|
||||
|
||||
x: "int" | str # TCH006
|
||||
x: ("int" | str) | "bool" # TCH006
|
||||
|
||||
|
||||
def func():
|
||||
x: "int" | str # OK
|
||||
|
||||
|
||||
z: list[str, str | "int"] = [] # TCH006
|
||||
|
||||
type A = Value["int" | str] # OK
|
||||
|
||||
OldS = TypeVar('OldS', int | 'str', str) # TCH006
|
||||
16
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/TCH006_2.py
vendored
Normal file
16
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/TCH006_2.py
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
from typing import TypeVar
|
||||
|
||||
|
||||
x: "int" | str # TCH006
|
||||
x: ("int" | str) | "bool" # TCH006
|
||||
|
||||
|
||||
def func():
|
||||
x: "int" | str # OK
|
||||
|
||||
|
||||
z: list[str, str | "int"] = [] # TCH006
|
||||
|
||||
type A = Value["int" | str] # OK
|
||||
|
||||
OldS = TypeVar('OldS', int | 'str', str) # TCH006
|
||||
7
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/exempt_type_checking_1.py
vendored
Normal file
7
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/exempt_type_checking_1.py
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
"""Add `TYPE_CHECKING` to an existing `typing` import. Another member is moved."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Final
|
||||
|
||||
Const: Final[dict] = {}
|
||||
7
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/exempt_type_checking_2.py
vendored
Normal file
7
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/exempt_type_checking_2.py
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
"""Using `TYPE_CHECKING` from an existing `typing` import. Another member is moved."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Final, TYPE_CHECKING
|
||||
|
||||
Const: Final[dict] = {}
|
||||
7
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/exempt_type_checking_3.py
vendored
Normal file
7
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/exempt_type_checking_3.py
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
"""Using `TYPE_CHECKING` from an existing `typing` import. Another member is moved."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Final, Mapping
|
||||
|
||||
Const: Final[dict] = {}
|
||||
@@ -65,3 +65,28 @@ def f():
|
||||
|
||||
def func(value: DataFrame):
|
||||
...
|
||||
|
||||
|
||||
def f():
|
||||
from pandas import DataFrame, Series
|
||||
|
||||
def baz() -> DataFrame | Series:
|
||||
...
|
||||
|
||||
|
||||
def f():
|
||||
from pandas import DataFrame, Series
|
||||
|
||||
def baz() -> (
|
||||
DataFrame |
|
||||
Series
|
||||
):
|
||||
...
|
||||
|
||||
class C:
|
||||
x: DataFrame[
|
||||
int
|
||||
] = 1
|
||||
|
||||
def func() -> DataFrame[[DataFrame[_P, _R]], DataFrame[_P, _R]]:
|
||||
...
|
||||
|
||||
@@ -4,6 +4,8 @@ import datetime
|
||||
from array import array
|
||||
from dataclasses import dataclass
|
||||
from uuid import UUID # TCH003
|
||||
from collections.abc import Sequence
|
||||
from pydantic import validate_call
|
||||
|
||||
import attrs
|
||||
from attrs import frozen
|
||||
@@ -22,3 +24,8 @@ class B:
|
||||
@dataclass
|
||||
class C:
|
||||
x: UUID
|
||||
|
||||
|
||||
@validate_call(config={'arbitrary_types_allowed': True})
|
||||
def test(user: Sequence):
|
||||
...
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user