Compare commits
155 Commits
zanie/tupl
...
schemastor
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d65addffa0 | ||
|
|
9d167a1f5c | ||
|
|
9e184a9067 | ||
|
|
9d1027c239 | ||
|
|
f499f0ca60 | ||
|
|
722687ad72 | ||
|
|
4760af3dcb | ||
|
|
4fdf97a95c | ||
|
|
0ea1076f85 | ||
|
|
3956f38999 | ||
|
|
fe9727ac38 | ||
|
|
3ebaca5246 | ||
|
|
7391f74cbc | ||
|
|
71e93a9fa4 | ||
|
|
e2c7b1ece6 | ||
|
|
621e98f452 | ||
|
|
0126f74c29 | ||
|
|
fce9f63418 | ||
|
|
ce549e75bc | ||
|
|
03303a9edd | ||
|
|
7873ca38e5 | ||
|
|
7dabc4598b | ||
|
|
6a1fa4778f | ||
|
|
c3d6d5d006 | ||
|
|
9a8400a287 | ||
|
|
d71c65d0c8 | ||
|
|
7f92bfbc4a | ||
|
|
37301375c8 | ||
|
|
c07947bfac | ||
|
|
72964529a5 | ||
|
|
eab8ca4d7e | ||
|
|
5b3e922050 | ||
|
|
311a7751f9 | ||
|
|
5e2bb8ca07 | ||
|
|
3c8d9d45fb | ||
|
|
82c3c513d2 | ||
|
|
f2dc01e3aa | ||
|
|
5349143fca | ||
|
|
b6f23d57aa | ||
|
|
b7b6e0136e | ||
|
|
218f517487 | ||
|
|
75c669a007 | ||
|
|
2d5ce4532a | ||
|
|
f3e2d12609 | ||
|
|
de2d7e97b1 | ||
|
|
bcb737dd80 | ||
|
|
8c146bbf11 | ||
|
|
4170ef0508 | ||
|
|
72ebde8d38 | ||
|
|
1672a3d3b7 | ||
|
|
8c0d65c98e | ||
|
|
b3c2935fa5 | ||
|
|
e57bccd500 | ||
|
|
75c9be099f | ||
|
|
c4889196e7 | ||
|
|
6e635e99f4 | ||
|
|
260ea41975 | ||
|
|
65effc6666 | ||
|
|
4982694b54 | ||
|
|
536ac550ed | ||
|
|
f2335fe692 | ||
|
|
b0f9a14d9a | ||
|
|
f56bc1983b | ||
|
|
7c12eaf322 | ||
|
|
41e538a748 | ||
|
|
dd2d8cb579 | ||
|
|
a08c5b7fa7 | ||
|
|
9f30ccc1f4 | ||
|
|
31286e1c95 | ||
|
|
b9994dc495 | ||
|
|
f16505d885 | ||
|
|
d04d964ace | ||
|
|
f64c389654 | ||
|
|
2ff1afb15c | ||
|
|
7fa6ac976a | ||
|
|
7dd5137913 | ||
|
|
0d93fbb4a2 | ||
|
|
d350ede992 | ||
|
|
a8a72306f0 | ||
|
|
c8122563a6 | ||
|
|
f8f507cfc8 | ||
|
|
ab6bf50a2d | ||
|
|
df4dc040de | ||
|
|
3a889f4686 | ||
|
|
edc75dc5d6 | ||
|
|
ebad36da06 | ||
|
|
2f7e2a8de3 | ||
|
|
4d23c1fc83 | ||
|
|
29573daef5 | ||
|
|
9558bac64a | ||
|
|
d5abe55b03 | ||
|
|
3fc920cd12 | ||
|
|
e9acb99f7d | ||
|
|
1642f4dbd9 | ||
|
|
38358980f1 | ||
|
|
43691f97d0 | ||
|
|
3076d76b0a | ||
|
|
23ed4e9616 | ||
|
|
97ae617fac | ||
|
|
a8d04cbd88 | ||
|
|
230c93459f | ||
|
|
8977b6ae11 | ||
|
|
982ae6ff08 | ||
|
|
c674db6e51 | ||
|
|
7323c12eee | ||
|
|
161c093c06 | ||
|
|
daea870c3c | ||
|
|
b6c4074836 | ||
|
|
cf74debf42 | ||
|
|
f483ed4240 | ||
|
|
98b3d716c6 | ||
|
|
03df6fa105 | ||
|
|
8cc97f70b4 | ||
|
|
951c59c6ad | ||
|
|
d177df226d | ||
|
|
703e2a9da3 | ||
|
|
bdad5e9a5f | ||
|
|
b21eb1f689 | ||
|
|
b0dc5a86a1 | ||
|
|
b5a4a9a356 | ||
|
|
230c9ce236 | ||
|
|
78bbf6d403 | ||
|
|
ee7d445ef5 | ||
|
|
5776ec1079 | ||
|
|
1f2d4f3ee1 | ||
|
|
221f7cd932 | ||
|
|
c7aa816f17 | ||
|
|
3ccca332bd | ||
|
|
2c84f911c4 | ||
|
|
e799f90782 | ||
|
|
9b89bf7d8a | ||
|
|
d7b966d6cd | ||
|
|
44e21cfada | ||
|
|
cda1c5dd35 | ||
|
|
86cdaea743 | ||
|
|
af4cb34ce2 | ||
|
|
4afff436ff | ||
|
|
f2f2e759c7 | ||
|
|
317b6e8682 | ||
|
|
2f5734d1ac | ||
|
|
c39ea6ef05 | ||
|
|
10a50bf1e2 | ||
|
|
a151e50ad3 | ||
|
|
854f5d09fa | ||
|
|
c2f6c79b3d | ||
|
|
87772c2884 | ||
|
|
aa90a425e0 | ||
|
|
81a2e74fe2 | ||
|
|
3af890f32f | ||
|
|
223873c8c7 | ||
|
|
7b4b004506 | ||
|
|
9f5102d536 | ||
|
|
af95cbaeef | ||
|
|
fc94857a20 | ||
|
|
5f26411577 |
29
.github/release.yml
vendored
29
.github/release.yml
vendored
@@ -1,29 +0,0 @@
|
|||||||
# https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes#configuring-automatically-generated-release-notes
|
|
||||||
changelog:
|
|
||||||
exclude:
|
|
||||||
labels:
|
|
||||||
- internal
|
|
||||||
- documentation
|
|
||||||
categories:
|
|
||||||
- title: Breaking Changes
|
|
||||||
labels:
|
|
||||||
- breaking
|
|
||||||
- title: Rules
|
|
||||||
labels:
|
|
||||||
- rule
|
|
||||||
- title: Settings
|
|
||||||
labels:
|
|
||||||
- configuration
|
|
||||||
- cli
|
|
||||||
- title: Bug Fixes
|
|
||||||
labels:
|
|
||||||
- bug
|
|
||||||
- title: Formatter
|
|
||||||
labels:
|
|
||||||
- formatter
|
|
||||||
- title: Preview
|
|
||||||
labels:
|
|
||||||
- preview
|
|
||||||
- title: Other Changes
|
|
||||||
labels:
|
|
||||||
- "*"
|
|
||||||
71
.github/workflows/ci.yaml
vendored
71
.github/workflows/ci.yaml
vendored
@@ -30,7 +30,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- uses: tj-actions/changed-files@v39
|
- uses: tj-actions/changed-files@v40
|
||||||
id: changed
|
id: changed
|
||||||
with:
|
with:
|
||||||
files_yaml: |
|
files_yaml: |
|
||||||
@@ -132,7 +132,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: "Install Rust toolchain"
|
- name: "Install Rust toolchain"
|
||||||
run: rustup target add wasm32-unknown-unknown
|
run: rustup target add wasm32-unknown-unknown
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 18
|
||||||
cache: "npm"
|
cache: "npm"
|
||||||
@@ -184,7 +184,11 @@ jobs:
|
|||||||
- cargo-test-linux
|
- cargo-test-linux
|
||||||
- determine_changes
|
- determine_changes
|
||||||
# Only runs on pull requests, since that is the only we way we can find the base version for comparison.
|
# Only runs on pull requests, since that is the only we way we can find the base version for comparison.
|
||||||
if: github.event_name == 'pull_request'
|
# Ecosystem check needs linter and/or formatter changes.
|
||||||
|
if: github.event_name == 'pull_request' && ${{
|
||||||
|
needs.determine_changes.outputs.linter == 'true' ||
|
||||||
|
needs.determine_changes.outputs.formatter == 'true'
|
||||||
|
}}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-python@v4
|
- uses: actions/setup-python@v4
|
||||||
@@ -209,28 +213,69 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
pip install ./python/ruff-ecosystem
|
pip install ./python/ruff-ecosystem
|
||||||
|
|
||||||
- name: Run `ruff check` ecosystem check
|
- name: Run `ruff check` stable ecosystem check
|
||||||
if: ${{ needs.determine_changes.outputs.linter == 'true' }}
|
if: ${{ needs.determine_changes.outputs.linter == 'true' }}
|
||||||
run: |
|
run: |
|
||||||
# Make executable, since artifact download doesn't preserve this
|
# Make executable, since artifact download doesn't preserve this
|
||||||
chmod +x ./ruff ${{ steps.ruff-target.outputs.download-path }}/ruff
|
chmod +x ./ruff ${{ steps.ruff-target.outputs.download-path }}/ruff
|
||||||
|
|
||||||
ruff-ecosystem check ./ruff ${{ steps.ruff-target.outputs.download-path }}/ruff --cache ./checkouts --output-format markdown | tee ecosystem-result-check
|
# Set pipefail to avoid hiding errors with tee
|
||||||
|
set -eo pipefail
|
||||||
|
|
||||||
cat ecosystem-result-check > $GITHUB_STEP_SUMMARY
|
ruff-ecosystem check ./ruff ${{ steps.ruff-target.outputs.download-path }}/ruff --cache ./checkouts --output-format markdown | tee ecosystem-result-check-stable
|
||||||
cat ecosystem-result-check > ecosystem-result
|
|
||||||
|
cat ecosystem-result-check-stable > $GITHUB_STEP_SUMMARY
|
||||||
|
echo "### Linter (stable)" > ecosystem-result
|
||||||
|
cat ecosystem-result-check-stable >> ecosystem-result
|
||||||
echo "" >> ecosystem-result
|
echo "" >> ecosystem-result
|
||||||
|
|
||||||
- name: Run `ruff format` ecosystem check
|
- name: Run `ruff check` preview ecosystem check
|
||||||
|
if: ${{ needs.determine_changes.outputs.linter == 'true' }}
|
||||||
|
run: |
|
||||||
|
# Make executable, since artifact download doesn't preserve this
|
||||||
|
chmod +x ./ruff ${{ steps.ruff-target.outputs.download-path }}/ruff
|
||||||
|
|
||||||
|
# Set pipefail to avoid hiding errors with tee
|
||||||
|
set -eo pipefail
|
||||||
|
|
||||||
|
ruff-ecosystem check ./ruff ${{ steps.ruff-target.outputs.download-path }}/ruff --cache ./checkouts --output-format markdown --force-preview | tee ecosystem-result-check-preview
|
||||||
|
|
||||||
|
cat ecosystem-result-check-preview > $GITHUB_STEP_SUMMARY
|
||||||
|
echo "### Linter (preview)" >> ecosystem-result
|
||||||
|
cat ecosystem-result-check-preview >> ecosystem-result
|
||||||
|
echo "" >> ecosystem-result
|
||||||
|
|
||||||
|
- name: Run `ruff format` stable ecosystem check
|
||||||
if: ${{ needs.determine_changes.outputs.formatter == 'true' }}
|
if: ${{ needs.determine_changes.outputs.formatter == 'true' }}
|
||||||
run: |
|
run: |
|
||||||
# Make executable, since artifact download doesn't preserve this
|
# Make executable, since artifact download doesn't preserve this
|
||||||
chmod +x ./ruff ${{ steps.ruff-target.outputs.download-path }}/ruff
|
chmod +x ./ruff ${{ steps.ruff-target.outputs.download-path }}/ruff
|
||||||
|
|
||||||
ruff-ecosystem format ./ruff ${{ steps.ruff-target.outputs.download-path }}/ruff --cache ./checkouts --output-format markdown | tee ecosystem-result-format
|
# Set pipefail to avoid hiding errors with tee
|
||||||
|
set -eo pipefail
|
||||||
|
|
||||||
cat ecosystem-result-format > $GITHUB_STEP_SUMMARY
|
ruff-ecosystem format ./ruff ${{ steps.ruff-target.outputs.download-path }}/ruff --cache ./checkouts --output-format markdown | tee ecosystem-result-format-stable
|
||||||
cat ecosystem-result-format >> ecosystem-result
|
|
||||||
|
cat ecosystem-result-format-stable > $GITHUB_STEP_SUMMARY
|
||||||
|
echo "### Formatter (stable)" >> ecosystem-result
|
||||||
|
cat ecosystem-result-format-stable >> ecosystem-result
|
||||||
|
echo "" >> ecosystem-result
|
||||||
|
|
||||||
|
- name: Run `ruff format` preview ecosystem check
|
||||||
|
if: ${{ needs.determine_changes.outputs.formatter == 'true' }}
|
||||||
|
run: |
|
||||||
|
# Make executable, since artifact download doesn't preserve this
|
||||||
|
chmod +x ./ruff ${{ steps.ruff-target.outputs.download-path }}/ruff
|
||||||
|
|
||||||
|
# Set pipefail to avoid hiding errors with tee
|
||||||
|
set -eo pipefail
|
||||||
|
|
||||||
|
ruff-ecosystem format ./ruff ${{ steps.ruff-target.outputs.download-path }}/ruff --cache ./checkouts --output-format markdown --force-preview | tee ecosystem-result-format-preview
|
||||||
|
|
||||||
|
cat ecosystem-result-format-preview > $GITHUB_STEP_SUMMARY
|
||||||
|
echo "### Formatter (preview)" >> ecosystem-result
|
||||||
|
cat ecosystem-result-format-preview >> ecosystem-result
|
||||||
|
echo "" >> ecosystem-result
|
||||||
|
|
||||||
- name: Export pull request number
|
- name: Export pull request number
|
||||||
run: |
|
run: |
|
||||||
@@ -349,8 +394,8 @@ jobs:
|
|||||||
if: ${{ env.MKDOCS_INSIDERS_SSH_KEY_EXISTS != 'true' }}
|
if: ${{ env.MKDOCS_INSIDERS_SSH_KEY_EXISTS != 'true' }}
|
||||||
run: mkdocs build --strict -f mkdocs.generated.yml
|
run: mkdocs build --strict -f mkdocs.generated.yml
|
||||||
|
|
||||||
check-formatter-ecosystem:
|
check-formatter-instability-and-black-similarity:
|
||||||
name: "Formatter ecosystem and progress checks"
|
name: "formatter instabilities and black similarity"
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: determine_changes
|
needs: determine_changes
|
||||||
if: needs.determine_changes.outputs.formatter == 'true' || github.ref == 'refs/heads/main'
|
if: needs.determine_changes.outputs.formatter == 'true' || github.ref == 'refs/heads/main'
|
||||||
|
|||||||
2
.github/workflows/docs.yaml
vendored
2
.github/workflows/docs.yaml
vendored
@@ -47,7 +47,7 @@ jobs:
|
|||||||
run: mkdocs build --strict -f mkdocs.generated.yml
|
run: mkdocs build --strict -f mkdocs.generated.yml
|
||||||
- name: "Deploy to Cloudflare Pages"
|
- name: "Deploy to Cloudflare Pages"
|
||||||
if: ${{ env.CF_API_TOKEN_EXISTS == 'true' }}
|
if: ${{ env.CF_API_TOKEN_EXISTS == 'true' }}
|
||||||
uses: cloudflare/wrangler-action@v3.3.1
|
uses: cloudflare/wrangler-action@v3.3.2
|
||||||
with:
|
with:
|
||||||
apiToken: ${{ secrets.CF_API_TOKEN }}
|
apiToken: ${{ secrets.CF_API_TOKEN }}
|
||||||
accountId: ${{ secrets.CF_ACCOUNT_ID }}
|
accountId: ${{ secrets.CF_ACCOUNT_ID }}
|
||||||
|
|||||||
4
.github/workflows/playground.yaml
vendored
4
.github/workflows/playground.yaml
vendored
@@ -20,7 +20,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: "Install Rust toolchain"
|
- name: "Install Rust toolchain"
|
||||||
run: rustup target add wasm32-unknown-unknown
|
run: rustup target add wasm32-unknown-unknown
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 18
|
||||||
cache: "npm"
|
cache: "npm"
|
||||||
@@ -40,7 +40,7 @@ jobs:
|
|||||||
working-directory: playground
|
working-directory: playground
|
||||||
- name: "Deploy to Cloudflare Pages"
|
- name: "Deploy to Cloudflare Pages"
|
||||||
if: ${{ env.CF_API_TOKEN_EXISTS == 'true' }}
|
if: ${{ env.CF_API_TOKEN_EXISTS == 'true' }}
|
||||||
uses: cloudflare/wrangler-action@v3.3.1
|
uses: cloudflare/wrangler-action@v3.3.2
|
||||||
with:
|
with:
|
||||||
apiToken: ${{ secrets.CF_API_TOKEN }}
|
apiToken: ${{ secrets.CF_API_TOKEN }}
|
||||||
accountId: ${{ secrets.CF_ACCOUNT_ID }}
|
accountId: ${{ secrets.CF_ACCOUNT_ID }}
|
||||||
|
|||||||
21
.github/workflows/pr-comment.yaml
vendored
21
.github/workflows/pr-comment.yaml
vendored
@@ -1,4 +1,4 @@
|
|||||||
name: PR Check Comment
|
name: Ecosystem check comment
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_run:
|
workflow_run:
|
||||||
@@ -18,13 +18,13 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: dawidd6/action-download-artifact@v2
|
- uses: dawidd6/action-download-artifact@v2
|
||||||
name: Download PR Number
|
name: Download pull request number
|
||||||
with:
|
with:
|
||||||
name: pr-number
|
name: pr-number
|
||||||
run_id: ${{ github.event.workflow_run.id || github.event.inputs.workflow_run_id }}
|
run_id: ${{ github.event.workflow_run.id || github.event.inputs.workflow_run_id }}
|
||||||
if_no_artifact_found: ignore
|
if_no_artifact_found: ignore
|
||||||
|
|
||||||
- name: Extract PR Number
|
- name: Parse pull request number
|
||||||
id: pr-number
|
id: pr-number
|
||||||
run: |
|
run: |
|
||||||
if [[ -f pr-number ]]
|
if [[ -f pr-number ]]
|
||||||
@@ -33,7 +33,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
- uses: dawidd6/action-download-artifact@v2
|
- uses: dawidd6/action-download-artifact@v2
|
||||||
name: "Download Ecosystem Result"
|
name: "Download ecosystem results"
|
||||||
id: download-ecosystem-result
|
id: download-ecosystem-result
|
||||||
if: steps.pr-number.outputs.pr-number
|
if: steps.pr-number.outputs.pr-number
|
||||||
with:
|
with:
|
||||||
@@ -41,15 +41,18 @@ jobs:
|
|||||||
workflow: ci.yaml
|
workflow: ci.yaml
|
||||||
pr: ${{ steps.pr-number.outputs.pr-number }}
|
pr: ${{ steps.pr-number.outputs.pr-number }}
|
||||||
path: pr/ecosystem
|
path: pr/ecosystem
|
||||||
|
workflow_conclusion: completed
|
||||||
if_no_artifact_found: ignore
|
if_no_artifact_found: ignore
|
||||||
|
|
||||||
- name: Generate Comment
|
- name: Generate comment content
|
||||||
id: generate-comment
|
id: generate-comment
|
||||||
if: steps.download-ecosystem-result.outputs.found_artifact == 'true'
|
if: steps.download-ecosystem-result.outputs.found_artifact == 'true'
|
||||||
run: |
|
run: |
|
||||||
echo '## PR Check Results' >> comment.txt
|
# Note this identifier is used to find the comment to update on
|
||||||
|
# subsequent runs
|
||||||
|
echo '<!-- generated-comment ecosystem -->' >> comment.txt
|
||||||
|
|
||||||
echo "### Ecosystem" >> comment.txt
|
echo '## `ruff-ecosystem` results' >> comment.txt
|
||||||
cat pr/ecosystem/ecosystem-result >> comment.txt
|
cat pr/ecosystem/ecosystem-result >> comment.txt
|
||||||
echo "" >> comment.txt
|
echo "" >> comment.txt
|
||||||
|
|
||||||
@@ -57,14 +60,14 @@ jobs:
|
|||||||
cat comment.txt >> $GITHUB_OUTPUT
|
cat comment.txt >> $GITHUB_OUTPUT
|
||||||
echo 'EOF' >> $GITHUB_OUTPUT
|
echo 'EOF' >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Find Comment
|
- name: Find existing comment
|
||||||
uses: peter-evans/find-comment@v2
|
uses: peter-evans/find-comment@v2
|
||||||
if: steps.generate-comment.outcome == 'success'
|
if: steps.generate-comment.outcome == 'success'
|
||||||
id: find-comment
|
id: find-comment
|
||||||
with:
|
with:
|
||||||
issue-number: ${{ steps.pr-number.outputs.pr-number }}
|
issue-number: ${{ steps.pr-number.outputs.pr-number }}
|
||||||
comment-author: "github-actions[bot]"
|
comment-author: "github-actions[bot]"
|
||||||
body-includes: PR Check Results
|
body-includes: "<!-- generated-comment ecosystem -->"
|
||||||
|
|
||||||
- name: Create or update comment
|
- name: Create or update comment
|
||||||
if: steps.find-comment.outcome == 'success'
|
if: steps.find-comment.outcome == 'success'
|
||||||
|
|||||||
1
.github/workflows/release.yaml
vendored
1
.github/workflows/release.yaml
vendored
@@ -48,7 +48,6 @@ jobs:
|
|||||||
args: --out dist
|
args: --out dist
|
||||||
- name: "Test sdist"
|
- name: "Test sdist"
|
||||||
run: |
|
run: |
|
||||||
rustup default $(cat rust-toolchain)
|
|
||||||
pip install dist/${{ env.PACKAGE_NAME }}-*.tar.gz --force-reinstall
|
pip install dist/${{ env.PACKAGE_NAME }}-*.tar.gz --force-reinstall
|
||||||
ruff --help
|
ruff --help
|
||||||
python -m ruff --help
|
python -m ruff --help
|
||||||
|
|||||||
@@ -13,12 +13,12 @@ exclude: |
|
|||||||
|
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/abravalheri/validate-pyproject
|
- repo: https://github.com/abravalheri/validate-pyproject
|
||||||
rev: v0.12.1
|
rev: v0.15
|
||||||
hooks:
|
hooks:
|
||||||
- id: validate-pyproject
|
- id: validate-pyproject
|
||||||
|
|
||||||
- repo: https://github.com/executablebooks/mdformat
|
- repo: https://github.com/executablebooks/mdformat
|
||||||
rev: 0.7.16
|
rev: 0.7.17
|
||||||
hooks:
|
hooks:
|
||||||
- id: mdformat
|
- id: mdformat
|
||||||
additional_dependencies:
|
additional_dependencies:
|
||||||
@@ -26,16 +26,22 @@ repos:
|
|||||||
- mdformat-admon
|
- mdformat-admon
|
||||||
exclude: |
|
exclude: |
|
||||||
(?x)^(
|
(?x)^(
|
||||||
docs/formatter/black.md
|
docs/formatter/black\.md
|
||||||
|
| docs/\w+\.md
|
||||||
)$
|
)$
|
||||||
|
|
||||||
- repo: https://github.com/igorshubovych/markdownlint-cli
|
- repo: https://github.com/igorshubovych/markdownlint-cli
|
||||||
rev: v0.33.0
|
rev: v0.37.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: markdownlint-fix
|
- id: markdownlint-fix
|
||||||
|
exclude: |
|
||||||
|
(?x)^(
|
||||||
|
docs/formatter/black\.md
|
||||||
|
| docs/\w+\.md
|
||||||
|
)$
|
||||||
|
|
||||||
- repo: https://github.com/crate-ci/typos
|
- repo: https://github.com/crate-ci/typos
|
||||||
rev: v1.14.12
|
rev: v1.16.22
|
||||||
hooks:
|
hooks:
|
||||||
- id: typos
|
- id: typos
|
||||||
|
|
||||||
@@ -47,10 +53,13 @@ repos:
|
|||||||
language: system
|
language: system
|
||||||
types: [rust]
|
types: [rust]
|
||||||
pass_filenames: false # This makes it a lot faster
|
pass_filenames: false # This makes it a lot faster
|
||||||
|
|
||||||
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||||
|
rev: v0.1.4
|
||||||
|
hooks:
|
||||||
|
- id: ruff-format
|
||||||
- id: ruff
|
- id: ruff
|
||||||
name: ruff
|
args: [--fix, --exit-non-zero-on-fix]
|
||||||
entry: cargo run --bin ruff -- check --no-cache --force-exclude --fix --exit-non-zero-on-fix
|
|
||||||
language: system
|
|
||||||
types_or: [python, pyi]
|
types_or: [python, pyi]
|
||||||
require_serial: true
|
require_serial: true
|
||||||
exclude: |
|
exclude: |
|
||||||
@@ -59,15 +68,9 @@ repos:
|
|||||||
crates/ruff_python_formatter/resources/.*
|
crates/ruff_python_formatter/resources/.*
|
||||||
)$
|
)$
|
||||||
|
|
||||||
# Black
|
|
||||||
- repo: https://github.com/psf/black
|
|
||||||
rev: 23.1.0
|
|
||||||
hooks:
|
|
||||||
- id: black
|
|
||||||
|
|
||||||
# Prettier
|
# Prettier
|
||||||
- repo: https://github.com/pre-commit/mirrors-prettier
|
- repo: https://github.com/pre-commit/mirrors-prettier
|
||||||
rev: v3.0.0
|
rev: v3.0.3
|
||||||
hooks:
|
hooks:
|
||||||
- id: prettier
|
- id: prettier
|
||||||
types: [yaml]
|
types: [yaml]
|
||||||
|
|||||||
110
CHANGELOG.md
110
CHANGELOG.md
@@ -1,5 +1,115 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.1.5
|
||||||
|
|
||||||
|
### Preview features
|
||||||
|
|
||||||
|
- \[`flake8-bandit`\] Implement `mako-templates` (`S702`) ([#8533](https://github.com/astral-sh/ruff/pull/8533))
|
||||||
|
- \[`flake8-trio`\] Implement `TRIO105` ([#8490](https://github.com/astral-sh/ruff/pull/8490))
|
||||||
|
- \[`flake8-trio`\] Implement `TRIO109` ([#8534](https://github.com/astral-sh/ruff/pull/8534))
|
||||||
|
- \[`flake8-trio`\] Implement `TRIO110` ([#8537](https://github.com/astral-sh/ruff/pull/8537))
|
||||||
|
- \[`flake8-trio`\] Implement `TRIO115` ([#8486](https://github.com/astral-sh/ruff/pull/8486))
|
||||||
|
- \[`refurb`\] Implement `type-none-comparison` (`FURB169`) ([#8487](https://github.com/astral-sh/ruff/pull/8487))
|
||||||
|
- Flag all comparisons against builtin types in `E721` ([#8491](https://github.com/astral-sh/ruff/pull/8491))
|
||||||
|
- Make `SIM118` fix as safe when the expression is a known dictionary ([#8525](https://github.com/astral-sh/ruff/pull/8525))
|
||||||
|
|
||||||
|
### Formatter
|
||||||
|
|
||||||
|
- Fix multiline lambda expression statement formatting ([#8466](https://github.com/astral-sh/ruff/pull/8466))
|
||||||
|
|
||||||
|
### CLI
|
||||||
|
|
||||||
|
- Add hidden `--extension` to override inference of source type from file extension ([#8373](https://github.com/astral-sh/ruff/pull/8373))
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
- Account for selector specificity when merging `extend_unsafe_fixes` and `override extend_safe_fixes` ([#8444](https://github.com/astral-sh/ruff/pull/8444))
|
||||||
|
- Add support for disabling cache with `RUFF_NO_CACHE` environment variable ([#8538](https://github.com/astral-sh/ruff/pull/8538))
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
- \[`E721`\] Flag comparisons to `memoryview` ([#8485](https://github.com/astral-sh/ruff/pull/8485))
|
||||||
|
- Allow collapsed-ellipsis bodies in other statements ([#8499](https://github.com/astral-sh/ruff/pull/8499))
|
||||||
|
- Avoid `D301` autofix for `u` prefixed strings ([#8495](https://github.com/astral-sh/ruff/pull/8495))
|
||||||
|
- Only flag `flake8-trio` rules when `trio` import is present ([#8550](https://github.com/astral-sh/ruff/pull/8550))
|
||||||
|
- Reject more syntactically invalid Python programs ([#8524](https://github.com/astral-sh/ruff/pull/8524))
|
||||||
|
- Avoid raising `TRIO115` violations for `trio.sleep(...)` calls with non-number values ([#8532](https://github.com/astral-sh/ruff/pull/8532))
|
||||||
|
- Fix `F841` false negative on assignment to multiple variables ([#8489](https://github.com/astral-sh/ruff/pull/8489))
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
|
||||||
|
- Fix link to isort `known-first-party` ([#8562](https://github.com/astral-sh/ruff/pull/8562))
|
||||||
|
- Add notes on fix safety to a few rules ([#8500](https://github.com/astral-sh/ruff/pull/8500))
|
||||||
|
- Add missing toml config tabs ([#8512](https://github.com/astral-sh/ruff/pull/8512))
|
||||||
|
- Add instructions for configuration of Emacs ([#8488](https://github.com/astral-sh/ruff/pull/8488))
|
||||||
|
- Improve detail link contrast in dark mode ([#8548](https://github.com/astral-sh/ruff/pull/8548))
|
||||||
|
- Fix typo in example ([#8506](https://github.com/astral-sh/ruff/pull/8506))
|
||||||
|
- Added tabs for configuration files in the documentation ([#8480](https://github.com/astral-sh/ruff/pull/8480))
|
||||||
|
- Recommend `project.requires-python` over `target-version` ([#8513](https://github.com/astral-sh/ruff/pull/8513))
|
||||||
|
- Add singleton escape hatch to `B008` documentation ([#8501](https://github.com/astral-sh/ruff/pull/8501))
|
||||||
|
- Fix tab configuration docs ([#8502](https://github.com/astral-sh/ruff/pull/8502))
|
||||||
|
|
||||||
|
## 0.1.4
|
||||||
|
|
||||||
|
### Preview features
|
||||||
|
|
||||||
|
- \[`flake8-trio`\] Implement `timeout-without-await` (`TRIO001`) ([#8439](https://github.com/astral-sh/ruff/pull/8439))
|
||||||
|
- \[`numpy`\] Implement NumPy 2.0 migration rule (`NPY200`) ([#7702](https://github.com/astral-sh/ruff/pull/7702))
|
||||||
|
- \[`pylint`\] Implement `bad-open-mode` (`W1501`) ([#8294](https://github.com/astral-sh/ruff/pull/8294))
|
||||||
|
- \[`pylint`\] Implement `import-outside-toplevel` (`C0415`) rule ([#5180](https://github.com/astral-sh/ruff/pull/5180))
|
||||||
|
- \[`pylint`\] Implement `useless-with-lock` (`W2101`) ([#8321](https://github.com/astral-sh/ruff/pull/8321))
|
||||||
|
- \[`pyupgrade`\] Implement `timeout-error-alias` (`UP041`) ([#8476](https://github.com/astral-sh/ruff/pull/8476))
|
||||||
|
- \[`refurb`\] Implement `isinstance-type-none` (`FURB168`) ([#8308](https://github.com/astral-sh/ruff/pull/8308))
|
||||||
|
- Detect confusable Unicode-to-Unicode units in `RUF001`, `RUF002`, and `RUF003` ([#4430](https://github.com/astral-sh/ruff/pull/4430))
|
||||||
|
- Add newline after module docstrings in preview style ([#8283](https://github.com/astral-sh/ruff/pull/8283))
|
||||||
|
|
||||||
|
### Formatter
|
||||||
|
|
||||||
|
- Add a note on line-too-long to the formatter docs ([#8314](https://github.com/astral-sh/ruff/pull/8314))
|
||||||
|
- Preserve trailing statement semicolons when using `fmt: skip` ([#8273](https://github.com/astral-sh/ruff/pull/8273))
|
||||||
|
- Preserve trailing semicolons when using `fmt: off` ([#8275](https://github.com/astral-sh/ruff/pull/8275))
|
||||||
|
- Avoid duplicating linter-formatter compatibility warnings ([#8292](https://github.com/astral-sh/ruff/pull/8292))
|
||||||
|
- Avoid inserting a newline after function docstrings ([#8375](https://github.com/astral-sh/ruff/pull/8375))
|
||||||
|
- Insert newline between docstring and following own line comment ([#8216](https://github.com/astral-sh/ruff/pull/8216))
|
||||||
|
- Split tuples in return positions by comma first ([#8280](https://github.com/astral-sh/ruff/pull/8280))
|
||||||
|
- Avoid treating byte strings as docstrings ([#8350](https://github.com/astral-sh/ruff/pull/8350))
|
||||||
|
- Add `--line-length` option to `format` command ([#8363](https://github.com/astral-sh/ruff/pull/8363))
|
||||||
|
- Avoid parenthesizing unsplittable because of comments ([#8431](https://github.com/astral-sh/ruff/pull/8431))
|
||||||
|
|
||||||
|
### CLI
|
||||||
|
|
||||||
|
- Add `--output-format` to `ruff rule` and `ruff linter` ([#8203](https://github.com/astral-sh/ruff/pull/8203))
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
- Respect `--force-exclude` in `lint.exclude` and `format.exclude` ([#8393](https://github.com/astral-sh/ruff/pull/8393))
|
||||||
|
- Respect `--extend-per-file-ignores` on the CLI ([#8329](https://github.com/astral-sh/ruff/pull/8329))
|
||||||
|
- Extend `bad-dunder-method-name` to permit `__index__` ([#8300](https://github.com/astral-sh/ruff/pull/8300))
|
||||||
|
- Fix panic with 8 in octal escape ([#8356](https://github.com/astral-sh/ruff/pull/8356))
|
||||||
|
- Avoid raising `D300` when both triple quote styles are present ([#8462](https://github.com/astral-sh/ruff/pull/8462))
|
||||||
|
- Consider unterminated f-strings in `FStringRanges` ([#8154](https://github.com/astral-sh/ruff/pull/8154))
|
||||||
|
- Avoid including literal `shell=True` for truthy, non-`True` diagnostics ([#8359](https://github.com/astral-sh/ruff/pull/8359))
|
||||||
|
- Avoid triggering single-element test for starred expressions ([#8433](https://github.com/astral-sh/ruff/pull/8433))
|
||||||
|
- Detect and ignore Jupyter automagics ([#8398](https://github.com/astral-sh/ruff/pull/8398))
|
||||||
|
- Fix invalid E231 error with f-strings ([#8369](https://github.com/astral-sh/ruff/pull/8369))
|
||||||
|
- Avoid triggering `NamedTuple` rewrite with starred annotation ([#8434](https://github.com/astral-sh/ruff/pull/8434))
|
||||||
|
- Avoid un-setting bracket flag in logical lines ([#8380](https://github.com/astral-sh/ruff/pull/8380))
|
||||||
|
- Place 'r' prefix before 'f' for raw format strings ([#8464](https://github.com/astral-sh/ruff/pull/8464))
|
||||||
|
- Remove trailing periods from NumPy 2.0 code actions ([#8475](https://github.com/astral-sh/ruff/pull/8475))
|
||||||
|
- Fix bug where `PLE1307` was raised when formatting `%c` with characters ([#8407](https://github.com/astral-sh/ruff/pull/8407))
|
||||||
|
- Remove unicode flag from comparable ([#8440](https://github.com/astral-sh/ruff/pull/8440))
|
||||||
|
- Improve B015 message ([#8295](https://github.com/astral-sh/ruff/pull/8295))
|
||||||
|
- Use `fixedOverflowWidgets` for playground popover ([#8458](https://github.com/astral-sh/ruff/pull/8458))
|
||||||
|
- Mark `byte_bounds` as a non-backwards-compatible NumPy 2.0 change ([#8474](https://github.com/astral-sh/ruff/pull/8474))
|
||||||
|
|
||||||
|
### Internals
|
||||||
|
|
||||||
|
- Add a dedicated cache directory per Ruff version ([#8333](https://github.com/astral-sh/ruff/pull/8333))
|
||||||
|
- Allow selective caching for `--fix` and `--diff` ([#8316](https://github.com/astral-sh/ruff/pull/8316))
|
||||||
|
- Improve performance of comment parsing ([#8193](https://github.com/astral-sh/ruff/pull/8193))
|
||||||
|
- Improve performance of string parsing ([#8227](https://github.com/astral-sh/ruff/pull/8227))
|
||||||
|
- Use a dedicated sort key for isort import sorting ([#7963](https://github.com/astral-sh/ruff/pull/7963))
|
||||||
|
|
||||||
## 0.1.3
|
## 0.1.3
|
||||||
|
|
||||||
This release includes a variety of improvements to the Ruff formatter, removing several known and
|
This release includes a variety of improvements to the Ruff formatter, removing several known and
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ representative at an online or offline event.
|
|||||||
|
|
||||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||||
reported to the community leaders responsible for enforcement at
|
reported to the community leaders responsible for enforcement at
|
||||||
charlie.r.marsh@gmail.com.
|
<charlie.r.marsh@gmail.com>.
|
||||||
All complaints will be reviewed and investigated promptly and fairly.
|
All complaints will be reviewed and investigated promptly and fairly.
|
||||||
|
|
||||||
All community leaders are obligated to respect the privacy and security of the
|
All community leaders are obligated to respect the privacy and security of the
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ such that all crates are contained in a flat `crates` directory.
|
|||||||
The vast majority of the code, including all lint rules, lives in the `ruff` crate (located at
|
The vast majority of the code, including all lint rules, lives in the `ruff` crate (located at
|
||||||
`crates/ruff_linter`). As a contributor, that's the crate that'll be most relevant to you.
|
`crates/ruff_linter`). As a contributor, that's the crate that'll be most relevant to you.
|
||||||
|
|
||||||
At time of writing, the repository includes the following crates:
|
At the time of writing, the repository includes the following crates:
|
||||||
|
|
||||||
- `crates/ruff_linter`: library crate containing all lint rules and the core logic for running them.
|
- `crates/ruff_linter`: library crate containing all lint rules and the core logic for running them.
|
||||||
If you're working on a rule, this is the crate for you.
|
If you're working on a rule, this is the crate for you.
|
||||||
@@ -315,9 +315,18 @@ even patch releases may contain [non-backwards-compatible changes](https://semve
|
|||||||
|
|
||||||
### Creating a new release
|
### Creating a new release
|
||||||
|
|
||||||
1. Update the version with `rg 0.0.269 --files-with-matches | xargs sed -i 's/0.0.269/0.0.270/g'`
|
We use an experimental in-house tool for managing releases.
|
||||||
1. Update `BREAKING_CHANGES.md`
|
|
||||||
1. Create a PR with the version and `BREAKING_CHANGES.md` updated
|
1. Install `rooster`: `pip install git+https://github.com/zanieb/rooster@main`
|
||||||
|
1. Run `rooster release`; this command will:
|
||||||
|
- Generate a changelog entry in `CHANGELOG.md`
|
||||||
|
- Update versions in `pyproject.toml` and `Cargo.toml`
|
||||||
|
- Update references to versions in the `README.md` and documentation
|
||||||
|
1. The changelog should then be editorialized for consistency
|
||||||
|
- 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. Create a pull request with the changelog and version updates
|
||||||
1. Merge the PR
|
1. Merge the PR
|
||||||
1. Run the release workflow with the version number (without starting `v`) as input. Make sure
|
1. Run the release workflow with the version number (without starting `v`) as input. Make sure
|
||||||
main has your merged PR as last commit
|
main has your merged PR as last commit
|
||||||
@@ -330,23 +339,26 @@ even patch releases may contain [non-backwards-compatible changes](https://semve
|
|||||||
1. Attach artifacts to draft GitHub release
|
1. Attach artifacts to draft GitHub release
|
||||||
1. Trigger downstream repositories. This can fail non-catastrophically, as we can run any
|
1. Trigger downstream repositories. This can fail non-catastrophically, as we can run any
|
||||||
downstream jobs manually if needed.
|
downstream jobs manually if needed.
|
||||||
1. Create release notes in GitHub UI and promote from draft.
|
1. Publish the GitHub release
|
||||||
|
1. Open the draft release in the GitHub release section
|
||||||
|
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/charliermarsh/ruff/blob/main/scripts/update_schemastore.py)
|
||||||
1. If needed, update the `ruff-lsp` and `ruff-vscode` repositories.
|
1. If needed, update the `ruff-lsp` and `ruff-vscode` repositories.
|
||||||
|
|
||||||
## Ecosystem CI
|
## Ecosystem CI
|
||||||
|
|
||||||
GitHub Actions will run your changes against a number of real-world projects from GitHub and
|
GitHub Actions will run your changes against a number of real-world projects from GitHub and
|
||||||
report on any diagnostic differences. You can also run those checks locally via:
|
report on any linter or formatter differences. You can also run those checks locally via:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
python scripts/check_ecosystem.py path/to/your/ruff path/to/older/ruff
|
pip install -e ./python/ruff-ecosystem
|
||||||
|
ruff-ecosystem check ruff "./target/debug/ruff"
|
||||||
|
ruff-ecosystem format ruff "./target/debug/ruff"
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also run the Ecosystem CI check in a Docker container across a larger set of projects by
|
See the [ruff-ecosystem package](https://github.com/astral-sh/ruff/tree/main/python/ruff-ecosystem) for more details.
|
||||||
downloading the [`known-github-tomls.json`](https://github.com/akx/ruff-usage-aggregate/blob/master/data/known-github-tomls.jsonl)
|
|
||||||
as `github_search.jsonl` and following the instructions in [scripts/Dockerfile.ecosystem](https://github.com/astral-sh/ruff/blob/main/scripts/Dockerfile.ecosystem).
|
|
||||||
Note that this check will take a while to run.
|
|
||||||
|
|
||||||
## Benchmarking and Profiling
|
## Benchmarking and Profiling
|
||||||
|
|
||||||
@@ -877,5 +889,5 @@ By default, `src` is set to the project root. In the above example, we'd want to
|
|||||||
`src = ["./src"]` to ensure that we locate `./my_project/src/foo` and thus categorize `import foo`
|
`src = ["./src"]` to ensure that we locate `./my_project/src/foo` and thus categorize `import foo`
|
||||||
as first-party in `baz.py`. In practice, for this limited example, setting `src = ["./src"]` is
|
as first-party in `baz.py`. In practice, for this limited example, setting `src = ["./src"]` is
|
||||||
unnecessary, as all imports within `./my_project/src/foo` would be categorized as first-party via
|
unnecessary, as all imports within `./my_project/src/foo` would be categorized as first-party via
|
||||||
the same-package heuristic; but your project contains multiple packages, you'll want to set `src`
|
the same-package heuristic; but if your project contains multiple packages, you'll want to set `src`
|
||||||
explicitly.
|
explicitly.
|
||||||
|
|||||||
146
Cargo.lock
generated
146
Cargo.lock
generated
@@ -210,9 +210,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.4.0"
|
version = "2.4.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
|
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bstr"
|
name = "bstr"
|
||||||
@@ -313,9 +313,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.4.6"
|
version = "4.4.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956"
|
checksum = "ac495e00dcec98c83465d5ad66c5c4fabd652fd6686e7c6269b117e729a6f17b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
@@ -323,9 +323,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.4.6"
|
version = "4.4.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45"
|
checksum = "c77ed9a32a62e6ca27175d00d29d05ca32e396ea1eb5fb01d8256b669cec7663"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
@@ -376,21 +376,21 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_derive"
|
name = "clap_derive"
|
||||||
version = "4.4.2"
|
version = "4.4.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873"
|
checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck",
|
"heck",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.38",
|
"syn 2.0.39",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_lex"
|
name = "clap_lex"
|
||||||
version = "0.5.1"
|
version = "0.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961"
|
checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clearscreen"
|
name = "clearscreen"
|
||||||
@@ -407,9 +407,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "codspeed"
|
name = "codspeed"
|
||||||
version = "2.3.0"
|
version = "2.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d680ccd1eedd2dd7c7a3649a78c7d06e0f16b191b30d81cc58e7bc906488d344"
|
checksum = "918b13a0f1a32460ab3bd5debd56b5a27a7071fa5ff5dfeb3a5cf291a85b174b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"colored",
|
"colored",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -418,9 +418,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "codspeed-criterion-compat"
|
name = "codspeed-criterion-compat"
|
||||||
version = "2.3.0"
|
version = "2.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "58b48b6c8e890d7d4ad0ed85e9ab4949bf7023198c006000ef6338ba84cf5b71"
|
checksum = "c683c7fef2b873fbbdf4062782914c652309951244bf0bd362fe608b7d6f901c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"codspeed",
|
"codspeed",
|
||||||
"colored",
|
"colored",
|
||||||
@@ -608,7 +608,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"strsim",
|
"strsim",
|
||||||
"syn 2.0.38",
|
"syn 2.0.39",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -619,7 +619,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"darling_core",
|
"darling_core",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.38",
|
"syn 2.0.39",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -810,7 +810,7 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flake8-to-ruff"
|
name = "flake8-to-ruff"
|
||||||
version = "0.1.3"
|
version = "0.1.5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"clap",
|
"clap",
|
||||||
@@ -1129,7 +1129,7 @@ dependencies = [
|
|||||||
"pmutil 0.6.1",
|
"pmutil 0.6.1",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.38",
|
"syn 2.0.39",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1262,9 +1262,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.147"
|
version = "0.2.149"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
|
checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libcst"
|
name = "libcst"
|
||||||
@@ -1309,9 +1309,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
version = "0.4.5"
|
version = "0.4.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503"
|
checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
@@ -1440,7 +1440,7 @@ version = "6.1.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d"
|
checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.4.0",
|
"bitflags 2.4.1",
|
||||||
"crossbeam-channel",
|
"crossbeam-channel",
|
||||||
"filetime",
|
"filetime",
|
||||||
"fsevent-sys",
|
"fsevent-sys",
|
||||||
@@ -1707,7 +1707,7 @@ checksum = "52a40bc70c2c58040d2d8b167ba9a5ff59fc9dab7ad44771cfde3dcfde7a09c6"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.38",
|
"syn 2.0.39",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1801,9 +1801,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyproject-toml"
|
name = "pyproject-toml"
|
||||||
version = "0.7.0"
|
version = "0.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "569e259cd132eb8cec5df8b672d187c5260f82ad352156b5da9549d4472e64b0"
|
checksum = "0774c13ff0b8b7ebb4791c050c497aefcfe3f6a222c0829c7017161ed38391ff"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"pep440_rs",
|
"pep440_rs",
|
||||||
@@ -1912,6 +1912,15 @@ dependencies = [
|
|||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_syscall"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_users"
|
name = "redox_users"
|
||||||
version = "0.4.3"
|
version = "0.4.3"
|
||||||
@@ -2051,14 +2060,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruff_cli"
|
name = "ruff_cli"
|
||||||
version = "0.1.3"
|
version = "0.1.5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"annotate-snippets 0.9.1",
|
"annotate-snippets 0.9.1",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"argfile",
|
"argfile",
|
||||||
"assert_cmd",
|
"assert_cmd",
|
||||||
"bincode",
|
"bincode",
|
||||||
"bitflags 2.4.0",
|
"bitflags 2.4.1",
|
||||||
"cachedir",
|
"cachedir",
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
@@ -2072,7 +2081,6 @@ dependencies = [
|
|||||||
"insta-cmd",
|
"insta-cmd",
|
||||||
"is-macro",
|
"is-macro",
|
||||||
"itertools 0.11.0",
|
"itertools 0.11.0",
|
||||||
"itoa",
|
|
||||||
"log",
|
"log",
|
||||||
"mimalloc",
|
"mimalloc",
|
||||||
"notify",
|
"notify",
|
||||||
@@ -2188,12 +2196,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruff_linter"
|
name = "ruff_linter"
|
||||||
version = "0.1.3"
|
version = "0.1.5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"annotate-snippets 0.9.1",
|
"annotate-snippets 0.9.1",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bitflags 2.4.0",
|
"bitflags 2.4.1",
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
"colored",
|
"colored",
|
||||||
@@ -2259,7 +2267,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"ruff_python_trivia",
|
"ruff_python_trivia",
|
||||||
"syn 2.0.38",
|
"syn 2.0.39",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2285,7 +2293,7 @@ dependencies = [
|
|||||||
name = "ruff_python_ast"
|
name = "ruff_python_ast"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.4.0",
|
"bitflags 2.4.1",
|
||||||
"insta",
|
"insta",
|
||||||
"is-macro",
|
"is-macro",
|
||||||
"itertools 0.11.0",
|
"itertools 0.11.0",
|
||||||
@@ -2317,7 +2325,7 @@ name = "ruff_python_formatter"
|
|||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bitflags 2.4.0",
|
"bitflags 2.4.1",
|
||||||
"clap",
|
"clap",
|
||||||
"countme",
|
"countme",
|
||||||
"insta",
|
"insta",
|
||||||
@@ -2361,7 +2369,7 @@ dependencies = [
|
|||||||
name = "ruff_python_literal"
|
name = "ruff_python_literal"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.4.0",
|
"bitflags 2.4.1",
|
||||||
"hexf-parse",
|
"hexf-parse",
|
||||||
"is-macro",
|
"is-macro",
|
||||||
"itertools 0.11.0",
|
"itertools 0.11.0",
|
||||||
@@ -2375,7 +2383,7 @@ name = "ruff_python_parser"
|
|||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bitflags 2.4.0",
|
"bitflags 2.4.1",
|
||||||
"insta",
|
"insta",
|
||||||
"is-macro",
|
"is-macro",
|
||||||
"itertools 0.11.0",
|
"itertools 0.11.0",
|
||||||
@@ -2405,7 +2413,7 @@ dependencies = [
|
|||||||
name = "ruff_python_semantic"
|
name = "ruff_python_semantic"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.4.0",
|
"bitflags 2.4.1",
|
||||||
"is-macro",
|
"is-macro",
|
||||||
"ruff_index",
|
"ruff_index",
|
||||||
"ruff_python_ast",
|
"ruff_python_ast",
|
||||||
@@ -2439,7 +2447,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruff_shrinking"
|
name = "ruff_shrinking"
|
||||||
version = "0.1.3"
|
version = "0.1.5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"clap",
|
"clap",
|
||||||
@@ -2551,11 +2559,11 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.38.10"
|
version = "0.38.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ed6248e1caa625eb708e266e06159f135e8c26f2bb7ceb72dc4b2766d0340964"
|
checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.4.0",
|
"bitflags 2.4.1",
|
||||||
"errno",
|
"errno",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys",
|
"linux-raw-sys",
|
||||||
@@ -2665,18 +2673,18 @@ checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.188"
|
version = "1.0.190"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e"
|
checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde-wasm-bindgen"
|
name = "serde-wasm-bindgen"
|
||||||
version = "0.6.0"
|
version = "0.6.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "30c9933e5689bd420dc6c87b7a1835701810cbc10cd86a26e4da45b73e6b1d78"
|
checksum = "17ba92964781421b6cef36bf0d7da26d201e96d84e1b10e7ae6ed416e516906d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -2685,13 +2693,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.188"
|
version = "1.0.190"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
|
checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.38",
|
"syn 2.0.39",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2707,9 +2715,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.107"
|
version = "1.0.108"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65"
|
checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
@@ -2753,7 +2761,7 @@ dependencies = [
|
|||||||
"darling",
|
"darling",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.38",
|
"syn 2.0.39",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2848,7 +2856,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"rustversion",
|
"rustversion",
|
||||||
"syn 2.0.38",
|
"syn 2.0.39",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2864,9 +2872,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.38"
|
version = "2.0.39"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b"
|
checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -2884,13 +2892,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.8.0"
|
version = "3.8.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef"
|
checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"fastrand",
|
"fastrand",
|
||||||
"redox_syscall 0.3.5",
|
"redox_syscall 0.4.1",
|
||||||
"rustix",
|
"rustix",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
@@ -2953,7 +2961,7 @@ dependencies = [
|
|||||||
"proc-macro-error",
|
"proc-macro-error",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.38",
|
"syn 2.0.39",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2965,7 +2973,7 @@ dependencies = [
|
|||||||
"proc-macro-error",
|
"proc-macro-error",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.38",
|
"syn 2.0.39",
|
||||||
"test-case-core",
|
"test-case-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2986,7 +2994,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.38",
|
"syn 2.0.39",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3123,7 +3131,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.38",
|
"syn 2.0.39",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3323,9 +3331,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "1.4.1"
|
version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d"
|
checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"getrandom",
|
||||||
"rand",
|
"rand",
|
||||||
@@ -3335,13 +3343,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid-macro-internal"
|
name = "uuid-macro-internal"
|
||||||
version = "1.4.1"
|
version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f7e1ba1f333bd65ce3c9f27de592fcbc256dafe3af2717f56d7c87761fbaccf4"
|
checksum = "3d8c6bba9b149ee82950daefc9623b32bb1dacbfb1890e352f6b887bd582adaf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.38",
|
"syn 2.0.39",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3435,7 +3443,7 @@ dependencies = [
|
|||||||
"once_cell",
|
"once_cell",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.38",
|
"syn 2.0.39",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -3469,7 +3477,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.38",
|
"syn 2.0.39",
|
||||||
"wasm-bindgen-backend",
|
"wasm-bindgen-backend",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|||||||
12
Cargo.toml
12
Cargo.toml
@@ -13,9 +13,9 @@ license = "MIT"
|
|||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
anyhow = { version = "1.0.69" }
|
anyhow = { version = "1.0.69" }
|
||||||
bitflags = { version = "2.3.1" }
|
bitflags = { version = "2.4.1" }
|
||||||
chrono = { version = "0.4.31", default-features = false, features = ["clock"] }
|
chrono = { version = "0.4.31", default-features = false, features = ["clock"] }
|
||||||
clap = { version = "4.4.6", features = ["derive"] }
|
clap = { version = "4.4.7", features = ["derive"] }
|
||||||
colored = { version = "2.0.0" }
|
colored = { version = "2.0.0" }
|
||||||
filetime = { version = "0.2.20" }
|
filetime = { version = "0.2.20" }
|
||||||
glob = { version = "0.3.1" }
|
glob = { version = "0.3.1" }
|
||||||
@@ -34,15 +34,15 @@ quote = { version = "1.0.23" }
|
|||||||
regex = { version = "1.10.2" }
|
regex = { version = "1.10.2" }
|
||||||
rustc-hash = { version = "1.1.0" }
|
rustc-hash = { version = "1.1.0" }
|
||||||
schemars = { version = "0.8.15" }
|
schemars = { version = "0.8.15" }
|
||||||
serde = { version = "1.0.152", features = ["derive"] }
|
serde = { version = "1.0.190", features = ["derive"] }
|
||||||
serde_json = { version = "1.0.107" }
|
serde_json = { version = "1.0.108" }
|
||||||
shellexpand = { version = "3.0.0" }
|
shellexpand = { version = "3.0.0" }
|
||||||
similar = { version = "2.3.0", features = ["inline"] }
|
similar = { version = "2.3.0", features = ["inline"] }
|
||||||
smallvec = { version = "1.11.1" }
|
smallvec = { version = "1.11.1" }
|
||||||
static_assertions = "1.1.0"
|
static_assertions = "1.1.0"
|
||||||
strum = { version = "0.25.0", features = ["strum_macros"] }
|
strum = { version = "0.25.0", features = ["strum_macros"] }
|
||||||
strum_macros = { version = "0.25.3" }
|
strum_macros = { version = "0.25.3" }
|
||||||
syn = { version = "2.0.38" }
|
syn = { version = "2.0.39" }
|
||||||
test-case = { version = "3.2.1" }
|
test-case = { version = "3.2.1" }
|
||||||
thiserror = { version = "1.0.50" }
|
thiserror = { version = "1.0.50" }
|
||||||
toml = { version = "0.7.8" }
|
toml = { version = "0.7.8" }
|
||||||
@@ -52,7 +52,7 @@ tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
|
|||||||
unicode-ident = { version = "1.0.12" }
|
unicode-ident = { version = "1.0.12" }
|
||||||
unicode_names2 = { version = "1.2.0" }
|
unicode_names2 = { version = "1.2.0" }
|
||||||
unicode-width = { version = "0.1.11" }
|
unicode-width = { version = "0.1.11" }
|
||||||
uuid = { version = "1.4.1", features = ["v4", "fast-rng", "macro-diagnostics", "js"] }
|
uuid = { version = "1.5.0", features = ["v4", "fast-rng", "macro-diagnostics", "js"] }
|
||||||
wsl = { version = "0.1.0" }
|
wsl = { version = "0.1.0" }
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
|
|||||||
25
LICENSE
25
LICENSE
@@ -1269,6 +1269,31 @@ are:
|
|||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
- flake8-trio, licensed as follows:
|
||||||
|
"""
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022 Zac Hatfield-Dodds
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
"""
|
||||||
|
|
||||||
- Pyright, licensed as follows:
|
- Pyright, licensed as follows:
|
||||||
"""
|
"""
|
||||||
MIT License
|
MIT License
|
||||||
|
|||||||
13
README.md
13
README.md
@@ -33,7 +33,7 @@ An extremely fast Python linter and code formatter, written in Rust.
|
|||||||
- 🔧 Fix support, for automatic error correction (e.g., automatically remove unused imports)
|
- 🔧 Fix support, for automatic error correction (e.g., automatically remove unused imports)
|
||||||
- 📏 Over [700 built-in rules](https://docs.astral.sh/ruff/rules/), with native re-implementations
|
- 📏 Over [700 built-in rules](https://docs.astral.sh/ruff/rules/), with native re-implementations
|
||||||
of popular Flake8 plugins, like flake8-bugbear
|
of popular Flake8 plugins, like flake8-bugbear
|
||||||
- ⌨️ First-party [editor integrations](https://docs.astral.sh/ruff/editor-integrations/) for
|
- ⌨️ First-party [editor integrations](https://docs.astral.sh/ruff/integrations/) for
|
||||||
[VS Code](https://github.com/astral-sh/ruff-vscode) and [more](https://github.com/astral-sh/ruff-lsp)
|
[VS Code](https://github.com/astral-sh/ruff-vscode) and [more](https://github.com/astral-sh/ruff-lsp)
|
||||||
- 🌎 Monorepo-friendly, with [hierarchical and cascading configuration](https://docs.astral.sh/ruff/configuration/#pyprojecttoml-discovery)
|
- 🌎 Monorepo-friendly, with [hierarchical and cascading configuration](https://docs.astral.sh/ruff/configuration/#pyprojecttoml-discovery)
|
||||||
|
|
||||||
@@ -148,14 +148,14 @@ ruff format @arguments.txt # Format using an input file, treating its
|
|||||||
Ruff can also be used as a [pre-commit](https://pre-commit.com/) hook via [`ruff-pre-commit`](https://github.com/astral-sh/ruff-pre-commit):
|
Ruff can also be used as a [pre-commit](https://pre-commit.com/) hook via [`ruff-pre-commit`](https://github.com/astral-sh/ruff-pre-commit):
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# Run the Ruff linter.
|
|
||||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||||
# Ruff version.
|
# Ruff version.
|
||||||
rev: v0.1.3
|
rev: v0.1.5
|
||||||
hooks:
|
hooks:
|
||||||
# Run the Ruff linter.
|
# Run the linter.
|
||||||
- id: ruff
|
- id: ruff
|
||||||
# Run the Ruff formatter.
|
args: [ --fix ]
|
||||||
|
# Run the formatter.
|
||||||
- id: ruff-format
|
- id: ruff-format
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -314,6 +314,7 @@ quality tools, including:
|
|||||||
- [flake8-super](https://pypi.org/project/flake8-super/)
|
- [flake8-super](https://pypi.org/project/flake8-super/)
|
||||||
- [flake8-tidy-imports](https://pypi.org/project/flake8-tidy-imports/)
|
- [flake8-tidy-imports](https://pypi.org/project/flake8-tidy-imports/)
|
||||||
- [flake8-todos](https://pypi.org/project/flake8-todos/)
|
- [flake8-todos](https://pypi.org/project/flake8-todos/)
|
||||||
|
- [flake8-trio](https://pypi.org/project/flake8-trio/)
|
||||||
- [flake8-type-checking](https://pypi.org/project/flake8-type-checking/)
|
- [flake8-type-checking](https://pypi.org/project/flake8-type-checking/)
|
||||||
- [flake8-use-pathlib](https://pypi.org/project/flake8-use-pathlib/)
|
- [flake8-use-pathlib](https://pypi.org/project/flake8-use-pathlib/)
|
||||||
- [flynt](https://pypi.org/project/flynt/) ([#2102](https://github.com/astral-sh/ruff/issues/2102))
|
- [flynt](https://pypi.org/project/flynt/) ([#2102](https://github.com/astral-sh/ruff/issues/2102))
|
||||||
@@ -415,6 +416,7 @@ Ruff is used by a number of major open-source projects and companies, including:
|
|||||||
- [PDM](https://github.com/pdm-project/pdm)
|
- [PDM](https://github.com/pdm-project/pdm)
|
||||||
- [PaddlePaddle](https://github.com/PaddlePaddle/Paddle)
|
- [PaddlePaddle](https://github.com/PaddlePaddle/Paddle)
|
||||||
- [Pandas](https://github.com/pandas-dev/pandas)
|
- [Pandas](https://github.com/pandas-dev/pandas)
|
||||||
|
- [Pillow](https://github.com/python-pillow/Pillow)
|
||||||
- [Poetry](https://github.com/python-poetry/poetry)
|
- [Poetry](https://github.com/python-poetry/poetry)
|
||||||
- [Polars](https://github.com/pola-rs/polars)
|
- [Polars](https://github.com/pola-rs/polars)
|
||||||
- [PostHog](https://github.com/PostHog/posthog)
|
- [PostHog](https://github.com/PostHog/posthog)
|
||||||
@@ -423,6 +425,7 @@ Ruff is used by a number of major open-source projects and companies, including:
|
|||||||
- [PyTorch](https://github.com/pytorch/pytorch)
|
- [PyTorch](https://github.com/pytorch/pytorch)
|
||||||
- [Pydantic](https://github.com/pydantic/pydantic)
|
- [Pydantic](https://github.com/pydantic/pydantic)
|
||||||
- [Pylint](https://github.com/PyCQA/pylint)
|
- [Pylint](https://github.com/PyCQA/pylint)
|
||||||
|
- [PyMC-Marketing](https://github.com/pymc-labs/pymc-marketing)
|
||||||
- [Reflex](https://github.com/reflex-dev/reflex)
|
- [Reflex](https://github.com/reflex-dev/reflex)
|
||||||
- [Rippling](https://rippling.com)
|
- [Rippling](https://rippling.com)
|
||||||
- [Robyn](https://github.com/sansyrox/robyn)
|
- [Robyn](https://github.com/sansyrox/robyn)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
[files]
|
[files]
|
||||||
extend-exclude = ["resources", "snapshots"]
|
# https://github.com/crate-ci/typos/issues/868
|
||||||
|
extend-exclude = ["**/resources/**/*", "**/snapshots/**/*"]
|
||||||
|
|
||||||
[default.extend-words]
|
[default.extend-words]
|
||||||
hel = "hel"
|
hel = "hel"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "flake8-to-ruff"
|
name = "flake8-to-ruff"
|
||||||
version = "0.1.3"
|
version = "0.1.5"
|
||||||
description = """
|
description = """
|
||||||
Convert Flake8 configuration files to Ruff configuration files.
|
Convert Flake8 configuration files to Ruff configuration files.
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ serde_json.workspace = true
|
|||||||
url = "2.3.1"
|
url = "2.3.1"
|
||||||
ureq = "2.8.0"
|
ureq = "2.8.0"
|
||||||
criterion = { version = "0.5.1", default-features = false }
|
criterion = { version = "0.5.1", default-features = false }
|
||||||
codspeed-criterion-compat = { version="2.3.0", default-features = false, optional = true}
|
codspeed-criterion-compat = { version="2.3.1", default-features = false, optional = true}
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
ruff_linter.path = "../ruff_linter"
|
ruff_linter.path = "../ruff_linter"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ruff_cli"
|
name = "ruff_cli"
|
||||||
version = "0.1.3"
|
version = "0.1.5"
|
||||||
publish = false
|
publish = false
|
||||||
authors = { workspace = true }
|
authors = { workspace = true }
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
@@ -44,7 +44,6 @@ glob = { workspace = true }
|
|||||||
ignore = { workspace = true }
|
ignore = { workspace = true }
|
||||||
is-macro = { workspace = true }
|
is-macro = { workspace = true }
|
||||||
itertools = { workspace = true }
|
itertools = { workspace = true }
|
||||||
itoa = { version = "1.0.6" }
|
|
||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
notify = { version = "6.1.1" }
|
notify = { version = "6.1.1" }
|
||||||
path-absolutize = { workspace = true, features = ["once_cell_cache"] }
|
path-absolutize = { workspace = true, features = ["once_cell_cache"] }
|
||||||
@@ -68,7 +67,7 @@ assert_cmd = { version = "2.0.8" }
|
|||||||
colored = { workspace = true, features = ["no-color"]}
|
colored = { workspace = true, features = ["no-color"]}
|
||||||
insta = { workspace = true, features = ["filters", "json"] }
|
insta = { workspace = true, features = ["filters", "json"] }
|
||||||
insta-cmd = { version = "0.4.0" }
|
insta-cmd = { version = "0.4.0" }
|
||||||
tempfile = "3.6.0"
|
tempfile = "3.8.1"
|
||||||
test-case = { workspace = true }
|
test-case = { workspace = true }
|
||||||
ureq = { version = "2.8.0", features = [] }
|
ureq = { version = "2.8.0", features = [] }
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ use ruff_linter::line_width::LineLength;
|
|||||||
use ruff_linter::logging::LogLevel;
|
use ruff_linter::logging::LogLevel;
|
||||||
use ruff_linter::registry::Rule;
|
use ruff_linter::registry::Rule;
|
||||||
use ruff_linter::settings::types::{
|
use ruff_linter::settings::types::{
|
||||||
FilePattern, PatternPrefixPair, PerFileIgnore, PreviewMode, PythonVersion, SerializationFormat,
|
ExtensionPair, FilePattern, PatternPrefixPair, PerFileIgnore, PreviewMode, PythonVersion,
|
||||||
UnsafeFixes,
|
SerializationFormat, UnsafeFixes,
|
||||||
};
|
};
|
||||||
use ruff_linter::{RuleParser, RuleSelector, RuleSelectorParser};
|
use ruff_linter::{RuleParser, RuleSelector, RuleSelectorParser};
|
||||||
use ruff_workspace::configuration::{Configuration, RuleSelection};
|
use ruff_workspace::configuration::{Configuration, RuleSelection};
|
||||||
@@ -50,7 +50,11 @@ pub enum Command {
|
|||||||
|
|
||||||
/// Output format
|
/// Output format
|
||||||
#[arg(long, value_enum, default_value = "text")]
|
#[arg(long, value_enum, default_value = "text")]
|
||||||
format: HelpFormat,
|
output_format: HelpFormat,
|
||||||
|
|
||||||
|
/// Output format (Deprecated: Use `--output-format` instead).
|
||||||
|
#[arg(long, value_enum, conflicts_with = "output_format", hide = true)]
|
||||||
|
format: Option<HelpFormat>,
|
||||||
},
|
},
|
||||||
/// List or describe the available configuration options.
|
/// List or describe the available configuration options.
|
||||||
Config { option: Option<String> },
|
Config { option: Option<String> },
|
||||||
@@ -58,7 +62,11 @@ pub enum Command {
|
|||||||
Linter {
|
Linter {
|
||||||
/// Output format
|
/// Output format
|
||||||
#[arg(long, value_enum, default_value = "text")]
|
#[arg(long, value_enum, default_value = "text")]
|
||||||
format: HelpFormat,
|
output_format: HelpFormat,
|
||||||
|
|
||||||
|
/// Output format (Deprecated: Use `--output-format` instead).
|
||||||
|
#[arg(long, value_enum, conflicts_with = "output_format", hide = true)]
|
||||||
|
format: Option<HelpFormat>,
|
||||||
},
|
},
|
||||||
/// Clear any caches in the current directory and any subdirectories.
|
/// Clear any caches in the current directory and any subdirectories.
|
||||||
#[clap(alias = "--clean")]
|
#[clap(alias = "--clean")]
|
||||||
@@ -270,7 +278,7 @@ pub struct CheckCommand {
|
|||||||
#[arg(long, help_heading = "Rule configuration", hide = true)]
|
#[arg(long, help_heading = "Rule configuration", hide = true)]
|
||||||
pub dummy_variable_rgx: Option<Regex>,
|
pub dummy_variable_rgx: Option<Regex>,
|
||||||
/// Disable cache reads.
|
/// Disable cache reads.
|
||||||
#[arg(short, long, help_heading = "Miscellaneous")]
|
#[arg(short, long, env = "RUFF_NO_CACHE", help_heading = "Miscellaneous")]
|
||||||
pub no_cache: bool,
|
pub no_cache: bool,
|
||||||
/// Ignore all configuration files.
|
/// Ignore all configuration files.
|
||||||
#[arg(long, conflicts_with = "config", help_heading = "Miscellaneous")]
|
#[arg(long, conflicts_with = "config", help_heading = "Miscellaneous")]
|
||||||
@@ -343,6 +351,9 @@ pub struct CheckCommand {
|
|||||||
conflicts_with = "watch",
|
conflicts_with = "watch",
|
||||||
)]
|
)]
|
||||||
pub show_settings: bool,
|
pub show_settings: bool,
|
||||||
|
/// List of mappings from file extension to language (one of ["python", "ipynb", "pyi"]).
|
||||||
|
#[arg(long, value_delimiter = ',', hide = true)]
|
||||||
|
pub extension: Option<Vec<ExtensionPair>>,
|
||||||
/// Dev-only argument to show fixes
|
/// Dev-only argument to show fixes
|
||||||
#[arg(long, hide = true)]
|
#[arg(long, hide = true)]
|
||||||
pub ecosystem_ci: bool,
|
pub ecosystem_ci: bool,
|
||||||
@@ -366,7 +377,7 @@ pub struct FormatCommand {
|
|||||||
pub config: Option<PathBuf>,
|
pub config: Option<PathBuf>,
|
||||||
|
|
||||||
/// Disable cache reads.
|
/// Disable cache reads.
|
||||||
#[arg(short, long, help_heading = "Miscellaneous")]
|
#[arg(short, long, env = "RUFF_NO_CACHE", help_heading = "Miscellaneous")]
|
||||||
pub no_cache: bool,
|
pub no_cache: bool,
|
||||||
/// Path to the cache directory.
|
/// Path to the cache directory.
|
||||||
#[arg(long, env = "RUFF_CACHE_DIR", help_heading = "Miscellaneous")]
|
#[arg(long, env = "RUFF_CACHE_DIR", help_heading = "Miscellaneous")]
|
||||||
@@ -401,6 +412,9 @@ pub struct FormatCommand {
|
|||||||
force_exclude: bool,
|
force_exclude: bool,
|
||||||
#[clap(long, overrides_with("force_exclude"), hide = true)]
|
#[clap(long, overrides_with("force_exclude"), hide = true)]
|
||||||
no_force_exclude: bool,
|
no_force_exclude: bool,
|
||||||
|
/// Set the line-length.
|
||||||
|
#[arg(long, help_heading = "Format configuration")]
|
||||||
|
pub line_length: Option<LineLength>,
|
||||||
/// Ignore all configuration files.
|
/// Ignore all configuration files.
|
||||||
#[arg(long, conflicts_with = "config", help_heading = "Miscellaneous")]
|
#[arg(long, conflicts_with = "config", help_heading = "Miscellaneous")]
|
||||||
pub isolated: bool,
|
pub isolated: bool,
|
||||||
@@ -499,6 +513,7 @@ impl CheckCommand {
|
|||||||
extend_exclude: self.extend_exclude,
|
extend_exclude: self.extend_exclude,
|
||||||
extend_fixable: self.extend_fixable,
|
extend_fixable: self.extend_fixable,
|
||||||
extend_ignore: self.extend_ignore,
|
extend_ignore: self.extend_ignore,
|
||||||
|
extend_per_file_ignores: self.extend_per_file_ignores,
|
||||||
extend_select: self.extend_select,
|
extend_select: self.extend_select,
|
||||||
extend_unfixable: self.extend_unfixable,
|
extend_unfixable: self.extend_unfixable,
|
||||||
fixable: self.fixable,
|
fixable: self.fixable,
|
||||||
@@ -523,6 +538,7 @@ impl CheckCommand {
|
|||||||
force_exclude: resolve_bool_arg(self.force_exclude, self.no_force_exclude),
|
force_exclude: resolve_bool_arg(self.force_exclude, self.no_force_exclude),
|
||||||
output_format: self.output_format,
|
output_format: self.output_format,
|
||||||
show_fixes: resolve_bool_arg(self.show_fixes, self.no_show_fixes),
|
show_fixes: resolve_bool_arg(self.show_fixes, self.no_show_fixes),
|
||||||
|
extension: self.extension,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -543,6 +559,7 @@ impl FormatCommand {
|
|||||||
stdin_filename: self.stdin_filename,
|
stdin_filename: self.stdin_filename,
|
||||||
},
|
},
|
||||||
CliOverrides {
|
CliOverrides {
|
||||||
|
line_length: self.line_length,
|
||||||
respect_gitignore: resolve_bool_arg(
|
respect_gitignore: resolve_bool_arg(
|
||||||
self.respect_gitignore,
|
self.respect_gitignore,
|
||||||
self.no_respect_gitignore,
|
self.no_respect_gitignore,
|
||||||
@@ -619,6 +636,7 @@ pub struct CliOverrides {
|
|||||||
pub ignore: Option<Vec<RuleSelector>>,
|
pub ignore: Option<Vec<RuleSelector>>,
|
||||||
pub line_length: Option<LineLength>,
|
pub line_length: Option<LineLength>,
|
||||||
pub per_file_ignores: Option<Vec<PatternPrefixPair>>,
|
pub per_file_ignores: Option<Vec<PatternPrefixPair>>,
|
||||||
|
pub extend_per_file_ignores: Option<Vec<PatternPrefixPair>>,
|
||||||
pub preview: Option<PreviewMode>,
|
pub preview: Option<PreviewMode>,
|
||||||
pub respect_gitignore: Option<bool>,
|
pub respect_gitignore: Option<bool>,
|
||||||
pub select: Option<Vec<RuleSelector>>,
|
pub select: Option<Vec<RuleSelector>>,
|
||||||
@@ -633,6 +651,7 @@ pub struct CliOverrides {
|
|||||||
pub force_exclude: Option<bool>,
|
pub force_exclude: Option<bool>,
|
||||||
pub output_format: Option<SerializationFormat>,
|
pub output_format: Option<SerializationFormat>,
|
||||||
pub show_fixes: Option<bool>,
|
pub show_fixes: Option<bool>,
|
||||||
|
pub extension: Option<Vec<ExtensionPair>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConfigurationTransformer for CliOverrides {
|
impl ConfigurationTransformer for CliOverrides {
|
||||||
@@ -649,6 +668,12 @@ impl ConfigurationTransformer for CliOverrides {
|
|||||||
if let Some(extend_exclude) = &self.extend_exclude {
|
if let Some(extend_exclude) = &self.extend_exclude {
|
||||||
config.extend_exclude.extend(extend_exclude.clone());
|
config.extend_exclude.extend(extend_exclude.clone());
|
||||||
}
|
}
|
||||||
|
if let Some(extend_per_file_ignores) = &self.extend_per_file_ignores {
|
||||||
|
config
|
||||||
|
.lint
|
||||||
|
.extend_per_file_ignores
|
||||||
|
.extend(collect_per_file_ignores(extend_per_file_ignores.clone()));
|
||||||
|
}
|
||||||
if let Some(fix) = &self.fix {
|
if let Some(fix) = &self.fix {
|
||||||
config.fix = Some(*fix);
|
config.fix = Some(*fix);
|
||||||
}
|
}
|
||||||
@@ -711,6 +736,9 @@ impl ConfigurationTransformer for CliOverrides {
|
|||||||
if let Some(target_version) = &self.target_version {
|
if let Some(target_version) = &self.target_version {
|
||||||
config.target_version = Some(*target_version);
|
config.target_version = Some(*target_version);
|
||||||
}
|
}
|
||||||
|
if let Some(extension) = &self.extension {
|
||||||
|
config.lint.extension = Some(extension.clone().into_iter().collect());
|
||||||
|
}
|
||||||
|
|
||||||
config
|
config
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::fs::{self, File};
|
use std::fs::{self, File};
|
||||||
use std::hash::Hasher;
|
use std::hash::Hasher;
|
||||||
@@ -20,7 +19,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use ruff_cache::{CacheKey, CacheKeyHasher};
|
use ruff_cache::{CacheKey, CacheKeyHasher};
|
||||||
use ruff_diagnostics::{DiagnosticKind, Fix};
|
use ruff_diagnostics::{DiagnosticKind, Fix};
|
||||||
use ruff_linter::message::Message;
|
use ruff_linter::message::Message;
|
||||||
use ruff_linter::warn_user;
|
use ruff_linter::{warn_user, VERSION};
|
||||||
use ruff_macros::CacheKey;
|
use ruff_macros::CacheKey;
|
||||||
use ruff_notebook::NotebookIndex;
|
use ruff_notebook::NotebookIndex;
|
||||||
use ruff_python_ast::imports::ImportMap;
|
use ruff_python_ast::imports::ImportMap;
|
||||||
@@ -102,9 +101,8 @@ impl Cache {
|
|||||||
pub(crate) fn open(package_root: PathBuf, settings: &Settings) -> Self {
|
pub(crate) fn open(package_root: PathBuf, settings: &Settings) -> Self {
|
||||||
debug_assert!(package_root.is_absolute(), "package root not canonicalized");
|
debug_assert!(package_root.is_absolute(), "package root not canonicalized");
|
||||||
|
|
||||||
let mut buf = itoa::Buffer::new();
|
let key = format!("{}", cache_key(&package_root, settings));
|
||||||
let key = Path::new(buf.format(cache_key(&package_root, settings)));
|
let path = PathBuf::from_iter([&settings.cache_dir, Path::new(VERSION), Path::new(&key)]);
|
||||||
let path = PathBuf::from_iter([&settings.cache_dir, Path::new("content"), key]);
|
|
||||||
|
|
||||||
let file = match File::open(&path) {
|
let file = match File::open(&path) {
|
||||||
Ok(file) => file,
|
Ok(file) => file,
|
||||||
@@ -142,7 +140,7 @@ impl Cache {
|
|||||||
fn empty(path: PathBuf, package_root: PathBuf) -> Self {
|
fn empty(path: PathBuf, package_root: PathBuf) -> Self {
|
||||||
let package = PackageCache {
|
let package = PackageCache {
|
||||||
package_root,
|
package_root,
|
||||||
files: HashMap::new(),
|
files: FxHashMap::default(),
|
||||||
};
|
};
|
||||||
Cache::new(path, package)
|
Cache::new(path, package)
|
||||||
}
|
}
|
||||||
@@ -294,7 +292,7 @@ struct PackageCache {
|
|||||||
/// single file "packages", e.g. scripts.
|
/// single file "packages", e.g. scripts.
|
||||||
package_root: PathBuf,
|
package_root: PathBuf,
|
||||||
/// Mapping of source file path to it's cached data.
|
/// Mapping of source file path to it's cached data.
|
||||||
files: HashMap<RelativePathBuf, FileCache>,
|
files: FxHashMap<RelativePathBuf, FileCache>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// On disk representation of the cache per source file.
|
/// On disk representation of the cache per source file.
|
||||||
@@ -350,16 +348,16 @@ struct FileCacheData {
|
|||||||
/// version.
|
/// version.
|
||||||
fn cache_key(package_root: &Path, settings: &Settings) -> u64 {
|
fn cache_key(package_root: &Path, settings: &Settings) -> u64 {
|
||||||
let mut hasher = CacheKeyHasher::new();
|
let mut hasher = CacheKeyHasher::new();
|
||||||
env!("CARGO_PKG_VERSION").cache_key(&mut hasher);
|
|
||||||
package_root.cache_key(&mut hasher);
|
package_root.cache_key(&mut hasher);
|
||||||
settings.cache_key(&mut hasher);
|
settings.cache_key(&mut hasher);
|
||||||
|
|
||||||
hasher.finish()
|
hasher.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize the cache at the specified `Path`.
|
/// Initialize the cache at the specified `Path`.
|
||||||
pub(crate) fn init(path: &Path) -> Result<()> {
|
pub(crate) fn init(path: &Path) -> Result<()> {
|
||||||
// Create the cache directories.
|
// Create the cache directories.
|
||||||
fs::create_dir_all(path.join("content"))?;
|
fs::create_dir_all(path.join(VERSION))?;
|
||||||
|
|
||||||
// Add the CACHEDIR.TAG.
|
// Add the CACHEDIR.TAG.
|
||||||
if !cachedir::is_tagged(path)? {
|
if !cachedir::is_tagged(path)? {
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ use crate::diagnostics::Diagnostics;
|
|||||||
use crate::panic::catch_unwind;
|
use crate::panic::catch_unwind;
|
||||||
|
|
||||||
/// Run the linter over a collection of files.
|
/// Run the linter over a collection of files.
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub(crate) fn check(
|
pub(crate) fn check(
|
||||||
files: &[PathBuf],
|
files: &[PathBuf],
|
||||||
pyproject_config: &PyprojectConfig,
|
pyproject_config: &PyprojectConfig,
|
||||||
@@ -82,7 +83,7 @@ pub(crate) fn check(
|
|||||||
|
|
||||||
let settings = resolver.resolve(path, pyproject_config);
|
let settings = resolver.resolve(path, pyproject_config);
|
||||||
|
|
||||||
if !resolved_file.is_root()
|
if (settings.file_resolver.force_exclude || !resolved_file.is_root())
|
||||||
&& match_exclusion(
|
&& match_exclusion(
|
||||||
resolved_file.path(),
|
resolved_file.path(),
|
||||||
resolved_file.file_name(),
|
resolved_file.file_name(),
|
||||||
@@ -184,6 +185,7 @@ pub(crate) fn check(
|
|||||||
|
|
||||||
/// Wraps [`lint_path`](crate::diagnostics::lint_path) in a [`catch_unwind`](std::panic::catch_unwind) and emits
|
/// Wraps [`lint_path`](crate::diagnostics::lint_path) in a [`catch_unwind`](std::panic::catch_unwind) and emits
|
||||||
/// a diagnostic if the linting the file panics.
|
/// a diagnostic if the linting the file panics.
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn lint_path(
|
fn lint_path(
|
||||||
path: &Path,
|
path: &Path,
|
||||||
package: Option<&Path>,
|
package: Option<&Path>,
|
||||||
|
|||||||
@@ -18,17 +18,19 @@ pub(crate) fn check_stdin(
|
|||||||
noqa: flags::Noqa,
|
noqa: flags::Noqa,
|
||||||
fix_mode: flags::FixMode,
|
fix_mode: flags::FixMode,
|
||||||
) -> Result<Diagnostics> {
|
) -> Result<Diagnostics> {
|
||||||
if let Some(filename) = filename {
|
if pyproject_config.settings.file_resolver.force_exclude {
|
||||||
if !python_file_at_path(filename, pyproject_config, overrides)? {
|
if let Some(filename) = filename {
|
||||||
return Ok(Diagnostics::default());
|
if !python_file_at_path(filename, pyproject_config, overrides)? {
|
||||||
}
|
return Ok(Diagnostics::default());
|
||||||
|
}
|
||||||
|
|
||||||
let lint_settings = &pyproject_config.settings.linter;
|
let lint_settings = &pyproject_config.settings.linter;
|
||||||
if filename
|
if filename
|
||||||
.file_name()
|
.file_name()
|
||||||
.is_some_and(|name| match_exclusion(filename, name, &lint_settings.exclude))
|
.is_some_and(|name| match_exclusion(filename, name, &lint_settings.exclude))
|
||||||
{
|
{
|
||||||
return Ok(Diagnostics::default());
|
return Ok(Diagnostics::default());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let package_root = filename.and_then(Path::parent).and_then(|path| {
|
let package_root = filename.and_then(Path::parent).and_then(|path| {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ use itertools::Itertools;
|
|||||||
use log::{error, warn};
|
use log::{error, warn};
|
||||||
use rayon::iter::Either::{Left, Right};
|
use rayon::iter::Either::{Left, Right};
|
||||||
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
|
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
|
||||||
|
use rustc_hash::FxHashSet;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
@@ -116,14 +117,14 @@ pub(crate) fn format(
|
|||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
let resolved_settings = resolver.resolve(path, &pyproject_config);
|
let settings = resolver.resolve(path, &pyproject_config);
|
||||||
|
|
||||||
// Ignore files that are excluded from formatting
|
// Ignore files that are excluded from formatting
|
||||||
if !resolved_file.is_root()
|
if (settings.file_resolver.force_exclude || !resolved_file.is_root())
|
||||||
&& match_exclusion(
|
&& match_exclusion(
|
||||||
path,
|
path,
|
||||||
resolved_file.file_name(),
|
resolved_file.file_name(),
|
||||||
&resolved_settings.formatter.exclude,
|
&settings.formatter.exclude,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return None;
|
return None;
|
||||||
@@ -138,13 +139,7 @@ pub(crate) fn format(
|
|||||||
|
|
||||||
Some(
|
Some(
|
||||||
match catch_unwind(|| {
|
match catch_unwind(|| {
|
||||||
format_path(
|
format_path(path, &settings.formatter, source_type, mode, cache)
|
||||||
path,
|
|
||||||
&resolved_settings.formatter,
|
|
||||||
source_type,
|
|
||||||
mode,
|
|
||||||
cache,
|
|
||||||
)
|
|
||||||
}) {
|
}) {
|
||||||
Ok(inner) => inner.map(|result| FormatPathResult {
|
Ok(inner) => inner.map(|result| FormatPathResult {
|
||||||
path: resolved_file.path().to_path_buf(),
|
path: resolved_file.path().to_path_buf(),
|
||||||
@@ -695,11 +690,11 @@ pub(super) fn warn_incompatible_formatter_settings(
|
|||||||
pyproject_config: &PyprojectConfig,
|
pyproject_config: &PyprojectConfig,
|
||||||
resolver: Option<&Resolver>,
|
resolver: Option<&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)
|
for setting in std::iter::once(&pyproject_config.settings)
|
||||||
.chain(resolver.iter().flat_map(|resolver| resolver.settings()))
|
.chain(resolver.iter().flat_map(|resolver| resolver.settings()))
|
||||||
{
|
{
|
||||||
let mut incompatible_rules = Vec::new();
|
|
||||||
|
|
||||||
for rule in [
|
for rule in [
|
||||||
// The formatter might collapse implicit string concatenation on a single line.
|
// The formatter might collapse implicit string concatenation on a single line.
|
||||||
Rule::SingleLineImplicitStringConcatenation,
|
Rule::SingleLineImplicitStringConcatenation,
|
||||||
@@ -713,41 +708,48 @@ pub(super) fn warn_incompatible_formatter_settings(
|
|||||||
Rule::MissingTrailingComma,
|
Rule::MissingTrailingComma,
|
||||||
] {
|
] {
|
||||||
if setting.linter.rules.enabled(rule) {
|
if setting.linter.rules.enabled(rule) {
|
||||||
incompatible_rules.push(rule);
|
incompatible_rules.insert(rule);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Rules asserting for space indentation
|
if !incompatible_rules.is_empty() {
|
||||||
if setting.formatter.indent_style.is_tab() {
|
let mut rule_names: Vec<_> = incompatible_rules
|
||||||
for rule in [Rule::TabIndentation, Rule::IndentWithSpaces] {
|
.into_iter()
|
||||||
if setting.linter.rules.enabled(rule) {
|
.map(|rule| format!("`{}`", rule.noqa_code()))
|
||||||
incompatible_rules.push(rule);
|
.collect();
|
||||||
}
|
rule_names.sort();
|
||||||
}
|
warn_user_once!("The following rules may cause conflicts when used with the formatter: {}. To avoid unexpected behavior, we recommend disabling these rules, either by removing them from the `select` or `extend-select` configuration, or adding them to the `ignore` configuration.", rule_names.join(", "));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next, validate settings-specific incompatibilities.
|
||||||
|
for setting in std::iter::once(&pyproject_config.settings)
|
||||||
|
.chain(resolver.iter().flat_map(|resolver| resolver.settings()))
|
||||||
|
{
|
||||||
|
// Validate all rules that rely on tab styles.
|
||||||
|
if setting.linter.rules.enabled(Rule::TabIndentation)
|
||||||
|
&& setting.formatter.indent_style.is_tab()
|
||||||
|
{
|
||||||
|
warn_user_once!("The `format.indent-style=\"tab\"` option is incompatible with `W191`, which lints against all uses of tabs. We recommend disabling these rules when using the formatter, which enforces a consistent indentation style. Alternatively, set the `format.indent-style` option to `\"space\"`.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rules asserting for indent-width=4
|
// Validate all rules that rely on tab styles.
|
||||||
if setting.formatter.indent_width.value() != 4 {
|
if setting.linter.rules.enabled(Rule::IndentWithSpaces)
|
||||||
for rule in [
|
&& setting.formatter.indent_style.is_tab()
|
||||||
Rule::IndentationWithInvalidMultiple,
|
{
|
||||||
Rule::IndentationWithInvalidMultipleComment,
|
warn_user_once!("The `format.indent-style=\"tab\"` option is incompatible with `D206`, with requires space-based indentation. We recommend disabling these rules when using the formatter, which enforces a consistent indentation style. Alternatively, set the `format.indent-style` option to `\"space\"`.");
|
||||||
] {
|
|
||||||
if setting.linter.rules.enabled(rule) {
|
|
||||||
incompatible_rules.push(rule);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !incompatible_rules.is_empty() {
|
// Validate all rules that rely on custom indent widths.
|
||||||
let mut rule_names: Vec<_> = incompatible_rules
|
if setting.linter.rules.any_enabled(&[
|
||||||
.into_iter()
|
Rule::IndentationWithInvalidMultiple,
|
||||||
.map(|rule| format!("`{}`", rule.noqa_code()))
|
Rule::IndentationWithInvalidMultipleComment,
|
||||||
.collect();
|
]) && setting.formatter.indent_width.value() != 4
|
||||||
rule_names.sort();
|
{
|
||||||
warn!("The following rules may cause conflicts when used with the formatter: {}. To avoid unexpected behavior, we recommend disabling these rules, either by removing them from the `select` or `extend-select` configuration, or adding then to the `ignore` configuration.", rule_names.join(", "));
|
warn_user_once!("The `format.indent-width` option with a value other than 4 is incompatible with `E111` and `E114`. We recommend disabling these rules when using the formatter, which enforces a consistent indentation width. Alternatively, set the `format.indent-width` option to `4`.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rules with different quote styles.
|
// Validate all rules that rely on quote styles.
|
||||||
if setting
|
if setting
|
||||||
.linter
|
.linter
|
||||||
.rules
|
.rules
|
||||||
@@ -758,10 +760,10 @@ pub(super) fn warn_incompatible_formatter_settings(
|
|||||||
setting.formatter.quote_style,
|
setting.formatter.quote_style,
|
||||||
) {
|
) {
|
||||||
(Quote::Double, QuoteStyle::Single) => {
|
(Quote::Double, QuoteStyle::Single) => {
|
||||||
warn!("The `flake8-quotes.inline-quotes=\"double\"` option is incompatible with the formatter's `format.quote-style=\"single\"`. We recommend disabling `Q000` and `Q003` when using the formatter, which enforces a consistent quote style. Alternatively, set both options to either `\"single\"` or `\"double\"`.");
|
warn_user_once!("The `flake8-quotes.inline-quotes=\"double\"` option is incompatible with the formatter's `format.quote-style=\"single\"`. We recommend disabling `Q000` and `Q003` when using the formatter, which enforces a consistent quote style. Alternatively, set both options to either `\"single\"` or `\"double\"`.");
|
||||||
}
|
}
|
||||||
(Quote::Single, QuoteStyle::Double) => {
|
(Quote::Single, QuoteStyle::Double) => {
|
||||||
warn!("The `flake8-quotes.inline-quotes=\"single\"` option is incompatible with the formatter's `format.quote-style=\"double\"`. We recommend disabling `Q000` and `Q003` when using the formatter, which enforces a consistent quote style. Alternatively, set both options to either `\"single\"` or `\"double\"`.");
|
warn_user_once!("The `flake8-quotes.inline-quotes=\"single\"` option is incompatible with the formatter's `format.quote-style=\"double\"`. We recommend disabling `Q000` and `Q003` when using the formatter, which enforces a consistent quote style. Alternatively, set both options to either `\"single\"` or `\"double\"`.");
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@@ -770,25 +772,26 @@ pub(super) fn warn_incompatible_formatter_settings(
|
|||||||
if setting.linter.rules.enabled(Rule::BadQuotesMultilineString)
|
if setting.linter.rules.enabled(Rule::BadQuotesMultilineString)
|
||||||
&& setting.linter.flake8_quotes.multiline_quotes == Quote::Single
|
&& setting.linter.flake8_quotes.multiline_quotes == Quote::Single
|
||||||
{
|
{
|
||||||
warn!("The `flake8-quotes.multiline-quotes=\"single\"` option is incompatible with the formatter. We recommend disabling `Q001` when using the formatter, which enforces double quotes for multiline strings. Alternatively, set the `flake8-quotes.multiline-quotes` option to `\"double\"`.`");
|
warn_user_once!("The `flake8-quotes.multiline-quotes=\"single\"` option is incompatible with the formatter. We recommend disabling `Q001` when using the formatter, which enforces double quotes for multiline strings. Alternatively, set the `flake8-quotes.multiline-quotes` option to `\"double\"`.`");
|
||||||
}
|
}
|
||||||
|
|
||||||
if setting.linter.rules.enabled(Rule::BadQuotesDocstring)
|
if setting.linter.rules.enabled(Rule::BadQuotesDocstring)
|
||||||
&& setting.linter.flake8_quotes.docstring_quotes == Quote::Single
|
&& setting.linter.flake8_quotes.docstring_quotes == Quote::Single
|
||||||
{
|
{
|
||||||
warn!("The `flake8-quotes.multiline-quotes=\"single\"` option is incompatible with the formatter. We recommend disabling `Q002` when using the formatter, which enforces double quotes for docstrings. Alternatively, set the `flake8-quotes.docstring-quotes` option to `\"double\"`.`");
|
warn_user_once!("The `flake8-quotes.multiline-quotes=\"single\"` option is incompatible with the formatter. We recommend disabling `Q002` when using the formatter, which enforces double quotes for docstrings. Alternatively, set the `flake8-quotes.docstring-quotes` option to `\"double\"`.`");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate all isort settings.
|
||||||
if setting.linter.rules.enabled(Rule::UnsortedImports) {
|
if setting.linter.rules.enabled(Rule::UnsortedImports) {
|
||||||
// The formatter removes empty lines if the value is larger than 2 but always inserts a empty line after imports.
|
// The formatter removes empty lines if the value is larger than 2 but always inserts a empty line after imports.
|
||||||
// Two empty lines are okay because `isort` only uses this setting for top-level imports (not in nested blocks).
|
// Two empty lines are okay because `isort` only uses this setting for top-level imports (not in nested blocks).
|
||||||
if !matches!(setting.linter.isort.lines_after_imports, 1 | 2 | -1) {
|
if !matches!(setting.linter.isort.lines_after_imports, 1 | 2 | -1) {
|
||||||
warn!("The isort option `isort.lines-after-imports` with a value other than `-1`, `1` or `2` is incompatible with the formatter. To avoid unexpected behavior, we recommend setting the option to one of: `2`, `1`, or `-1` (default).");
|
warn_user_once!("The isort option `isort.lines-after-imports` with a value other than `-1`, `1` or `2` is incompatible with the formatter. To avoid unexpected behavior, we recommend setting the option to one of: `2`, `1`, or `-1` (default).");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Values larger than two get reduced to one line by the formatter if the import is in a nested block.
|
// Values larger than two get reduced to one line by the formatter if the import is in a nested block.
|
||||||
if setting.linter.isort.lines_between_types > 1 {
|
if setting.linter.isort.lines_between_types > 1 {
|
||||||
warn!("The isort option `isort.lines-between-types` with a value greater than 1 is incompatible with the formatter. To avoid unexpected behavior, we recommend setting the option to one of: `1` or `0` (default).");
|
warn_user_once!("The isort option `isort.lines-between-types` with a value greater than 1 is incompatible with the formatter. To avoid unexpected behavior, we recommend setting the option to one of: `1` or `0` (default).");
|
||||||
}
|
}
|
||||||
|
|
||||||
// isort inserts a trailing comma which the formatter preserves, but only if `skip-magic-trailing-comma` isn't false.
|
// isort inserts a trailing comma which the formatter preserves, but only if `skip-magic-trailing-comma` isn't false.
|
||||||
@@ -797,11 +800,11 @@ pub(super) fn warn_incompatible_formatter_settings(
|
|||||||
&& !setting.linter.isort.force_single_line
|
&& !setting.linter.isort.force_single_line
|
||||||
{
|
{
|
||||||
if setting.linter.isort.force_wrap_aliases {
|
if setting.linter.isort.force_wrap_aliases {
|
||||||
warn!("The isort option `isort.force-wrap-aliases` is incompatible with the formatter `format.skip-magic-trailing-comma=true` option. To avoid unexpected behavior, we recommend either setting `isort.force-wrap-aliases=false` or `format.skip-magic-trailing-comma=false`.");
|
warn_user_once!("The isort option `isort.force-wrap-aliases` is incompatible with the formatter `format.skip-magic-trailing-comma=true` option. To avoid unexpected behavior, we recommend either setting `isort.force-wrap-aliases=false` or `format.skip-magic-trailing-comma=false`.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if setting.linter.isort.split_on_trailing_comma {
|
if setting.linter.isort.split_on_trailing_comma {
|
||||||
warn!("The isort option `isort.split-on-trailing-comma` is incompatible with the formatter `format.skip-magic-trailing-comma=true` option. To avoid unexpected behavior, we recommend either setting `isort.split-on-trailing-comma=false` or `format.skip-magic-trailing-comma=false`.");
|
warn_user_once!("The isort option `isort.split-on-trailing-comma` is incompatible with the formatter `format.skip-magic-trailing-comma=true` option. To avoid unexpected behavior, we recommend either setting `isort.split-on-trailing-comma=false` or `format.skip-magic-trailing-comma=false`.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,17 +31,19 @@ pub(crate) fn format_stdin(cli: &FormatArguments, overrides: &CliOverrides) -> R
|
|||||||
|
|
||||||
let mode = FormatMode::from_cli(cli);
|
let mode = FormatMode::from_cli(cli);
|
||||||
|
|
||||||
if let Some(filename) = cli.stdin_filename.as_deref() {
|
if pyproject_config.settings.file_resolver.force_exclude {
|
||||||
if !python_file_at_path(filename, &pyproject_config, overrides)? {
|
if let Some(filename) = cli.stdin_filename.as_deref() {
|
||||||
return Ok(ExitStatus::Success);
|
if !python_file_at_path(filename, &pyproject_config, overrides)? {
|
||||||
}
|
return Ok(ExitStatus::Success);
|
||||||
|
}
|
||||||
|
|
||||||
let format_settings = &pyproject_config.settings.formatter;
|
let format_settings = &pyproject_config.settings.formatter;
|
||||||
if filename
|
if filename
|
||||||
.file_name()
|
.file_name()
|
||||||
.is_some_and(|name| match_exclusion(filename, name, &format_settings.exclude))
|
.is_some_and(|name| match_exclusion(filename, name, &format_settings.exclude))
|
||||||
{
|
{
|
||||||
return Ok(ExitStatus::Success);
|
return Ok(ExitStatus::Success);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,13 +17,13 @@ use ruff_linter::logging::DisplayParseError;
|
|||||||
use ruff_linter::message::Message;
|
use ruff_linter::message::Message;
|
||||||
use ruff_linter::pyproject_toml::lint_pyproject_toml;
|
use ruff_linter::pyproject_toml::lint_pyproject_toml;
|
||||||
use ruff_linter::registry::AsRule;
|
use ruff_linter::registry::AsRule;
|
||||||
use ruff_linter::settings::types::UnsafeFixes;
|
use ruff_linter::settings::types::{ExtensionMapping, UnsafeFixes};
|
||||||
use ruff_linter::settings::{flags, LinterSettings};
|
use ruff_linter::settings::{flags, LinterSettings};
|
||||||
use ruff_linter::source_kind::{SourceError, SourceKind};
|
use ruff_linter::source_kind::{SourceError, SourceKind};
|
||||||
use ruff_linter::{fs, IOError, SyntaxError};
|
use ruff_linter::{fs, IOError, SyntaxError};
|
||||||
use ruff_notebook::{Notebook, NotebookError, NotebookIndex};
|
use ruff_notebook::{Notebook, NotebookError, NotebookIndex};
|
||||||
use ruff_python_ast::imports::ImportMap;
|
use ruff_python_ast::imports::ImportMap;
|
||||||
use ruff_python_ast::{SourceType, TomlSourceType};
|
use ruff_python_ast::{PySourceType, SourceType, TomlSourceType};
|
||||||
use ruff_source_file::{LineIndex, SourceCode, SourceFileBuilder};
|
use ruff_source_file::{LineIndex, SourceCode, SourceFileBuilder};
|
||||||
use ruff_text_size::{TextRange, TextSize};
|
use ruff_text_size::{TextRange, TextSize};
|
||||||
use ruff_workspace::Settings;
|
use ruff_workspace::Settings;
|
||||||
@@ -177,6 +177,11 @@ impl AddAssign for FixMap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn override_source_type(path: Option<&Path>, extension: &ExtensionMapping) -> Option<PySourceType> {
|
||||||
|
let ext = path?.extension()?.to_str()?;
|
||||||
|
extension.get(ext).map(PySourceType::from)
|
||||||
|
}
|
||||||
|
|
||||||
/// Lint the source code at the given `Path`.
|
/// Lint the source code at the given `Path`.
|
||||||
pub(crate) fn lint_path(
|
pub(crate) fn lint_path(
|
||||||
path: &Path,
|
path: &Path,
|
||||||
@@ -188,13 +193,8 @@ pub(crate) fn lint_path(
|
|||||||
unsafe_fixes: UnsafeFixes,
|
unsafe_fixes: UnsafeFixes,
|
||||||
) -> Result<Diagnostics> {
|
) -> Result<Diagnostics> {
|
||||||
// Check the cache.
|
// Check the cache.
|
||||||
// TODO(charlie): `fixer::Mode::Apply` and `fixer::Mode::Diff` both have
|
|
||||||
// side-effects that aren't captured in the cache. (In practice, it's fine
|
|
||||||
// to cache `fixer::Mode::Apply`, since a file either has no fixes, or we'll
|
|
||||||
// write the fixes to disk, thus invalidating the cache. But it's a bit hard
|
|
||||||
// to reason about. We need to come up with a better solution here.)
|
|
||||||
let caching = match cache {
|
let caching = match cache {
|
||||||
Some(cache) if noqa.into() && fix_mode.is_generate() => {
|
Some(cache) if noqa.into() => {
|
||||||
let relative_path = cache
|
let relative_path = cache
|
||||||
.relative_path(path)
|
.relative_path(path)
|
||||||
.expect("wrong package cache for file");
|
.expect("wrong package cache for file");
|
||||||
@@ -204,7 +204,17 @@ pub(crate) fn lint_path(
|
|||||||
.get(relative_path, &cache_key)
|
.get(relative_path, &cache_key)
|
||||||
.and_then(|entry| entry.to_diagnostics(path));
|
.and_then(|entry| entry.to_diagnostics(path));
|
||||||
if let Some(diagnostics) = cached_diagnostics {
|
if let Some(diagnostics) = cached_diagnostics {
|
||||||
return Ok(diagnostics);
|
// `FixMode::Generate` 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 {
|
||||||
|
flags::FixMode::Generate => true,
|
||||||
|
flags::FixMode::Apply | flags::FixMode::Diff => {
|
||||||
|
diagnostics.messages.is_empty() && diagnostics.fixed.is_empty()
|
||||||
|
}
|
||||||
|
} {
|
||||||
|
return Ok(diagnostics);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stash the file metadata for later so when we update the cache it reflects the prerun
|
// Stash the file metadata for later so when we update the cache it reflects the prerun
|
||||||
@@ -216,31 +226,35 @@ pub(crate) fn lint_path(
|
|||||||
|
|
||||||
debug!("Checking: {}", path.display());
|
debug!("Checking: {}", path.display());
|
||||||
|
|
||||||
let source_type = match SourceType::from(path) {
|
let source_type = match override_source_type(Some(path), &settings.extension) {
|
||||||
SourceType::Toml(TomlSourceType::Pyproject) => {
|
Some(source_type) => source_type,
|
||||||
let messages = if settings
|
None => match SourceType::from(path) {
|
||||||
.rules
|
SourceType::Toml(TomlSourceType::Pyproject) => {
|
||||||
.iter_enabled()
|
let messages = if settings
|
||||||
.any(|rule_code| rule_code.lint_source().is_pyproject_toml())
|
.rules
|
||||||
{
|
.iter_enabled()
|
||||||
let contents = match std::fs::read_to_string(path).map_err(SourceError::from) {
|
.any(|rule_code| rule_code.lint_source().is_pyproject_toml())
|
||||||
Ok(contents) => contents,
|
{
|
||||||
Err(err) => {
|
let contents = match std::fs::read_to_string(path).map_err(SourceError::from) {
|
||||||
return Ok(Diagnostics::from_source_error(&err, Some(path), settings));
|
Ok(contents) => contents,
|
||||||
}
|
Err(err) => {
|
||||||
|
return Ok(Diagnostics::from_source_error(&err, Some(path), settings));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let source_file =
|
||||||
|
SourceFileBuilder::new(path.to_string_lossy(), contents).finish();
|
||||||
|
lint_pyproject_toml(source_file, settings)
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
};
|
};
|
||||||
let source_file = SourceFileBuilder::new(path.to_string_lossy(), contents).finish();
|
return Ok(Diagnostics {
|
||||||
lint_pyproject_toml(source_file, settings)
|
messages,
|
||||||
} else {
|
..Diagnostics::default()
|
||||||
vec![]
|
});
|
||||||
};
|
}
|
||||||
return Ok(Diagnostics {
|
SourceType::Toml(_) => return Ok(Diagnostics::default()),
|
||||||
messages,
|
SourceType::Python(source_type) => source_type,
|
||||||
..Diagnostics::default()
|
},
|
||||||
});
|
|
||||||
}
|
|
||||||
SourceType::Toml(_) => return Ok(Diagnostics::default()),
|
|
||||||
SourceType::Python(source_type) => source_type,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Extract the sources from the file.
|
// Extract the sources from the file.
|
||||||
@@ -304,15 +318,25 @@ pub(crate) fn lint_path(
|
|||||||
if let Some((cache, relative_path, key)) = caching {
|
if let Some((cache, relative_path, key)) = caching {
|
||||||
// We don't cache parsing errors.
|
// We don't cache parsing errors.
|
||||||
if parse_error.is_none() {
|
if parse_error.is_none() {
|
||||||
cache.update_lint(
|
// `FixMode::Generate` and `FixMode::Diff` rely on side-effects (writing to disk,
|
||||||
relative_path.to_owned(),
|
// and writing the diff to stdout, respectively). If a file has diagnostics, we
|
||||||
&key,
|
// need to avoid reading from and writing to the cache in these modes.
|
||||||
LintCacheData::from_messages(
|
if match fix_mode {
|
||||||
&messages,
|
flags::FixMode::Generate => true,
|
||||||
imports.clone(),
|
flags::FixMode::Apply | flags::FixMode::Diff => {
|
||||||
source_kind.as_ipy_notebook().map(Notebook::index).cloned(),
|
messages.is_empty() && fixed.is_empty()
|
||||||
),
|
}
|
||||||
);
|
} {
|
||||||
|
cache.update_lint(
|
||||||
|
relative_path.to_owned(),
|
||||||
|
&key,
|
||||||
|
LintCacheData::from_messages(
|
||||||
|
&messages,
|
||||||
|
imports.clone(),
|
||||||
|
source_kind.as_ipy_notebook().map(Notebook::index).cloned(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,8 +379,15 @@ pub(crate) fn lint_stdin(
|
|||||||
fix_mode: flags::FixMode,
|
fix_mode: flags::FixMode,
|
||||||
) -> Result<Diagnostics> {
|
) -> Result<Diagnostics> {
|
||||||
// TODO(charlie): Support `pyproject.toml`.
|
// TODO(charlie): Support `pyproject.toml`.
|
||||||
let SourceType::Python(source_type) = path.map(SourceType::from).unwrap_or_default() else {
|
let source_type = if let Some(source_type) =
|
||||||
return Ok(Diagnostics::default());
|
override_source_type(path, &settings.linter.extension)
|
||||||
|
{
|
||||||
|
source_type
|
||||||
|
} else {
|
||||||
|
let SourceType::Python(source_type) = path.map(SourceType::from).unwrap_or_default() else {
|
||||||
|
return Ok(Diagnostics::default());
|
||||||
|
};
|
||||||
|
source_type
|
||||||
};
|
};
|
||||||
|
|
||||||
// Extract the sources from the file.
|
// Extract the sources from the file.
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ use ruff_linter::settings::types::SerializationFormat;
|
|||||||
use ruff_linter::{fs, warn_user, warn_user_once};
|
use ruff_linter::{fs, warn_user, warn_user_once};
|
||||||
use ruff_workspace::Settings;
|
use ruff_workspace::Settings;
|
||||||
|
|
||||||
use crate::args::{Args, CheckCommand, Command, FormatCommand};
|
use crate::args::{Args, CheckCommand, Command, FormatCommand, HelpFormat};
|
||||||
use crate::printer::{Flags as PrinterFlags, Printer};
|
use crate::printer::{Flags as PrinterFlags, Printer};
|
||||||
|
|
||||||
pub mod args;
|
pub mod args;
|
||||||
@@ -101,6 +101,15 @@ fn is_stdin(files: &[PathBuf], stdin_filename: Option<&Path>) -> bool {
|
|||||||
file == Path::new("-")
|
file == Path::new("-")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the actual value of the `format` desired from either `output_format`
|
||||||
|
/// or `format`, and warn the user if they're using the deprecated form.
|
||||||
|
fn resolve_help_output_format(output_format: HelpFormat, format: Option<HelpFormat>) -> HelpFormat {
|
||||||
|
if format.is_some() {
|
||||||
|
warn_user!("The `--format` argument is deprecated. Use `--output-format` instead.");
|
||||||
|
}
|
||||||
|
format.unwrap_or(output_format)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn run(
|
pub fn run(
|
||||||
Args {
|
Args {
|
||||||
command,
|
command,
|
||||||
@@ -141,12 +150,18 @@ pub fn run(
|
|||||||
commands::version::version(output_format)?;
|
commands::version::version(output_format)?;
|
||||||
Ok(ExitStatus::Success)
|
Ok(ExitStatus::Success)
|
||||||
}
|
}
|
||||||
Command::Rule { rule, all, format } => {
|
Command::Rule {
|
||||||
|
rule,
|
||||||
|
all,
|
||||||
|
format,
|
||||||
|
mut output_format,
|
||||||
|
} => {
|
||||||
|
output_format = resolve_help_output_format(output_format, format);
|
||||||
if all {
|
if all {
|
||||||
commands::rule::rules(format)?;
|
commands::rule::rules(output_format)?;
|
||||||
}
|
}
|
||||||
if let Some(rule) = rule {
|
if let Some(rule) = rule {
|
||||||
commands::rule::rule(rule, format)?;
|
commands::rule::rule(rule, output_format)?;
|
||||||
}
|
}
|
||||||
Ok(ExitStatus::Success)
|
Ok(ExitStatus::Success)
|
||||||
}
|
}
|
||||||
@@ -154,8 +169,12 @@ pub fn run(
|
|||||||
commands::config::config(option.as_deref())?;
|
commands::config::config(option.as_deref())?;
|
||||||
Ok(ExitStatus::Success)
|
Ok(ExitStatus::Success)
|
||||||
}
|
}
|
||||||
Command::Linter { format } => {
|
Command::Linter {
|
||||||
commands::linter::linter(format)?;
|
format,
|
||||||
|
mut output_format,
|
||||||
|
} => {
|
||||||
|
output_format = resolve_help_output_format(output_format, format);
|
||||||
|
commands::linter::linter(output_format)?;
|
||||||
Ok(ExitStatus::Success)
|
Ok(ExitStatus::Success)
|
||||||
}
|
}
|
||||||
Command::Clean => {
|
Command::Clean => {
|
||||||
|
|||||||
@@ -188,6 +188,73 @@ OTHER = "OTHER"
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn force_exclude() -> Result<()> {
|
||||||
|
let tempdir = TempDir::new()?;
|
||||||
|
let ruff_toml = tempdir.path().join("ruff.toml");
|
||||||
|
fs::write(
|
||||||
|
&ruff_toml,
|
||||||
|
r#"
|
||||||
|
extend-exclude = ["out"]
|
||||||
|
|
||||||
|
[format]
|
||||||
|
exclude = ["test.py", "generated.py"]
|
||||||
|
"#,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
fs::write(
|
||||||
|
tempdir.path().join("main.py"),
|
||||||
|
r#"
|
||||||
|
from test import say_hy
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
say_hy("dear Ruff contributor")
|
||||||
|
"#,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Excluded file but passed to the CLI directly, should be formatted
|
||||||
|
let test_path = tempdir.path().join("test.py");
|
||||||
|
fs::write(
|
||||||
|
&test_path,
|
||||||
|
r#"
|
||||||
|
def say_hy(name: str):
|
||||||
|
print(f"Hy {name}")"#,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
fs::write(
|
||||||
|
tempdir.path().join("generated.py"),
|
||||||
|
r#"NUMBERS = [
|
||||||
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
|
||||||
|
10, 11, 12, 13, 14, 15, 16, 17, 18, 19
|
||||||
|
]
|
||||||
|
OTHER = "OTHER"
|
||||||
|
"#,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let out_dir = tempdir.path().join("out");
|
||||||
|
fs::create_dir(&out_dir)?;
|
||||||
|
|
||||||
|
fs::write(out_dir.join("a.py"), "a = a")?;
|
||||||
|
|
||||||
|
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
||||||
|
.current_dir(tempdir.path())
|
||||||
|
.args(["format", "--no-cache", "--force-exclude", "--check", "--config"])
|
||||||
|
.arg(ruff_toml.file_name().unwrap())
|
||||||
|
// Explicitly pass test.py, should be respect the `format.exclude` when `--force-exclude` is present
|
||||||
|
.arg(test_path.file_name().unwrap())
|
||||||
|
// Format all other files in the directory, should respect the `exclude` and `format.exclude` options
|
||||||
|
.arg("."), @r###"
|
||||||
|
success: false
|
||||||
|
exit_code: 1
|
||||||
|
----- stdout -----
|
||||||
|
Would reformat: main.py
|
||||||
|
1 file would be reformatted
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
"###);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn exclude_stdin() -> Result<()> {
|
fn exclude_stdin() -> Result<()> {
|
||||||
let tempdir = TempDir::new()?;
|
let tempdir = TempDir::new()?;
|
||||||
@@ -209,6 +276,43 @@ exclude = ["generated.py"]
|
|||||||
.pass_stdin(r#"
|
.pass_stdin(r#"
|
||||||
from test import say_hy
|
from test import say_hy
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
say_hy("dear Ruff contributor")
|
||||||
|
"#), @r###"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
from test import say_hy
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
say_hy("dear Ruff contributor")
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
"###);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn force_exclude_stdin() -> Result<()> {
|
||||||
|
let tempdir = TempDir::new()?;
|
||||||
|
let ruff_toml = tempdir.path().join("ruff.toml");
|
||||||
|
fs::write(
|
||||||
|
&ruff_toml,
|
||||||
|
r#"
|
||||||
|
extend-select = ["B", "Q"]
|
||||||
|
ignore = ["Q000", "Q001", "Q002", "Q003"]
|
||||||
|
|
||||||
|
[format]
|
||||||
|
exclude = ["generated.py"]
|
||||||
|
"#,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
||||||
|
.current_dir(tempdir.path())
|
||||||
|
.args(["format", "--config", &ruff_toml.file_name().unwrap().to_string_lossy(), "--stdin-filename", "generated.py", "--force-exclude", "-"])
|
||||||
|
.pass_stdin(r#"
|
||||||
|
from test import say_hy
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
say_hy("dear Ruff contributor")
|
say_hy("dear Ruff contributor")
|
||||||
"#), @r###"
|
"#), @r###"
|
||||||
@@ -275,7 +379,7 @@ if condition:
|
|||||||
print('Should change quotes')
|
print('Should change quotes')
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
warning: The following rules may cause conflicts when used with the formatter: `COM812`. To avoid unexpected behavior, we recommend disabling these rules, either by removing them from the `select` or `extend-select` configuration, or adding then to the `ignore` configuration.
|
warning: The following rules may cause conflicts when used with the formatter: `COM812`. To avoid unexpected behavior, we recommend disabling these rules, either by removing them from the `select` or `extend-select` configuration, or adding them to the `ignore` configuration.
|
||||||
"###);
|
"###);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -403,7 +507,9 @@ def say_hy(name: str):
|
|||||||
1 file reformatted
|
1 file reformatted
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
warning: The following rules may cause conflicts when used with the formatter: `COM812`, `D206`, `ISC001`, `W191`. To avoid unexpected behavior, we recommend disabling these rules, either by removing them from the `select` or `extend-select` configuration, or adding then to the `ignore` configuration.
|
warning: The following rules may cause conflicts when used with the formatter: `COM812`, `ISC001`. To avoid unexpected behavior, we recommend disabling these rules, either by removing them from the `select` or `extend-select` configuration, or adding them to the `ignore` configuration.
|
||||||
|
warning: The `format.indent-style="tab"` option is incompatible with `W191`, which lints against all uses of tabs. We recommend disabling these rules when using the formatter, which enforces a consistent indentation style. Alternatively, set the `format.indent-style` option to `"space"`.
|
||||||
|
warning: The `format.indent-style="tab"` option is incompatible with `D206`, with requires space-based indentation. We recommend disabling these rules when using the formatter, which enforces a consistent indentation style. Alternatively, set the `format.indent-style` option to `"space"`.
|
||||||
warning: The `flake8-quotes.inline-quotes="single"` option is incompatible with the formatter's `format.quote-style="double"`. We recommend disabling `Q000` and `Q003` when using the formatter, which enforces a consistent quote style. Alternatively, set both options to either `"single"` or `"double"`.
|
warning: The `flake8-quotes.inline-quotes="single"` option is incompatible with the formatter's `format.quote-style="double"`. We recommend disabling `Q000` and `Q003` when using the formatter, which enforces a consistent quote style. Alternatively, set both options to either `"single"` or `"double"`.
|
||||||
warning: The `flake8-quotes.multiline-quotes="single"` option is incompatible with the formatter. We recommend disabling `Q001` when using the formatter, which enforces double quotes for multiline strings. Alternatively, set the `flake8-quotes.multiline-quotes` option to `"double"`.`
|
warning: The `flake8-quotes.multiline-quotes="single"` option is incompatible with the formatter. We recommend disabling `Q001` when using the formatter, which enforces double quotes for multiline strings. Alternatively, set the `flake8-quotes.multiline-quotes` option to `"double"`.`
|
||||||
warning: The `flake8-quotes.multiline-quotes="single"` option is incompatible with the formatter. We recommend disabling `Q002` when using the formatter, which enforces double quotes for docstrings. Alternatively, set the `flake8-quotes.docstring-quotes` option to `"double"`.`
|
warning: The `flake8-quotes.multiline-quotes="single"` option is incompatible with the formatter. We recommend disabling `Q002` when using the formatter, which enforces double quotes for docstrings. Alternatively, set the `flake8-quotes.docstring-quotes` option to `"double"`.`
|
||||||
@@ -460,7 +566,9 @@ def say_hy(name: str):
|
|||||||
print(f"Hy {name}")
|
print(f"Hy {name}")
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
warning: The following rules may cause conflicts when used with the formatter: `COM812`, `D206`, `ISC001`, `W191`. To avoid unexpected behavior, we recommend disabling these rules, either by removing them from the `select` or `extend-select` configuration, or adding then to the `ignore` configuration.
|
warning: The following rules may cause conflicts when used with the formatter: `COM812`, `ISC001`. To avoid unexpected behavior, we recommend disabling these rules, either by removing them from the `select` or `extend-select` configuration, or adding them to the `ignore` configuration.
|
||||||
|
warning: The `format.indent-style="tab"` option is incompatible with `W191`, which lints against all uses of tabs. We recommend disabling these rules when using the formatter, which enforces a consistent indentation style. Alternatively, set the `format.indent-style` option to `"space"`.
|
||||||
|
warning: The `format.indent-style="tab"` option is incompatible with `D206`, with requires space-based indentation. We recommend disabling these rules when using the formatter, which enforces a consistent indentation style. Alternatively, set the `format.indent-style` option to `"space"`.
|
||||||
warning: The `flake8-quotes.inline-quotes="single"` option is incompatible with the formatter's `format.quote-style="double"`. We recommend disabling `Q000` and `Q003` when using the formatter, which enforces a consistent quote style. Alternatively, set both options to either `"single"` or `"double"`.
|
warning: The `flake8-quotes.inline-quotes="single"` option is incompatible with the formatter's `format.quote-style="double"`. We recommend disabling `Q000` and `Q003` when using the formatter, which enforces a consistent quote style. Alternatively, set both options to either `"single"` or `"double"`.
|
||||||
warning: The `flake8-quotes.multiline-quotes="single"` option is incompatible with the formatter. We recommend disabling `Q001` when using the formatter, which enforces double quotes for multiline strings. Alternatively, set the `flake8-quotes.multiline-quotes` option to `"double"`.`
|
warning: The `flake8-quotes.multiline-quotes="single"` option is incompatible with the formatter. We recommend disabling `Q001` when using the formatter, which enforces double quotes for multiline strings. Alternatively, set the `flake8-quotes.multiline-quotes` option to `"double"`.`
|
||||||
warning: The `flake8-quotes.multiline-quotes="single"` option is incompatible with the formatter. We recommend disabling `Q002` when using the formatter, which enforces double quotes for docstrings. Alternatively, set the `flake8-quotes.docstring-quotes` option to `"double"`.`
|
warning: The `flake8-quotes.multiline-quotes="single"` option is incompatible with the formatter. We recommend disabling `Q002` when using the formatter, which enforces double quotes for docstrings. Alternatively, set the `flake8-quotes.docstring-quotes` option to `"double"`.`
|
||||||
@@ -556,7 +664,7 @@ def say_hy(name: str):
|
|||||||
----- stderr -----
|
----- stderr -----
|
||||||
warning: `one-blank-line-before-class` (D203) and `no-blank-line-before-class` (D211) are incompatible. Ignoring `one-blank-line-before-class`.
|
warning: `one-blank-line-before-class` (D203) and `no-blank-line-before-class` (D211) are incompatible. Ignoring `one-blank-line-before-class`.
|
||||||
warning: `multi-line-summary-first-line` (D212) and `multi-line-summary-second-line` (D213) are incompatible. Ignoring `multi-line-summary-second-line`.
|
warning: `multi-line-summary-first-line` (D212) and `multi-line-summary-second-line` (D213) are incompatible. Ignoring `multi-line-summary-second-line`.
|
||||||
warning: The following rules may cause conflicts when used with the formatter: `COM812`, `ISC001`. To avoid unexpected behavior, we recommend disabling these rules, either by removing them from the `select` or `extend-select` configuration, or adding then to the `ignore` configuration.
|
warning: The following rules may cause conflicts when used with the formatter: `COM812`, `ISC001`. To avoid unexpected behavior, we recommend disabling these rules, either by removing them from the `select` or `extend-select` configuration, or adding them to the `ignore` configuration.
|
||||||
"###);
|
"###);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -320,6 +320,119 @@ fn stdin_fix_jupyter() {
|
|||||||
Found 2 errors (2 fixed, 0 remaining).
|
Found 2 errors (2 fixed, 0 remaining).
|
||||||
"###);
|
"###);
|
||||||
}
|
}
|
||||||
|
#[test]
|
||||||
|
fn stdin_override_parser_ipynb() {
|
||||||
|
let args = ["--extension", "py:ipynb", "--stdin-filename", "Jupyter.py"];
|
||||||
|
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
||||||
|
.args(STDIN_BASE_OPTIONS)
|
||||||
|
.args(args)
|
||||||
|
.pass_stdin(r#"{
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 1,
|
||||||
|
"id": "dccc687c-96e2-4604-b957-a8a89b5bec06",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"import os"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "19e1b029-f516-4662-a9b9-623b93edac1a",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"Foo"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 2,
|
||||||
|
"id": "cdce7b92-b0fb-4c02-86f6-e233b26fa84f",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"import sys"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 3,
|
||||||
|
"id": "e40b33d2-7fe4-46c5-bdf0-8802f3052565",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"1\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"print(1)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"id": "a1899bc8-d46f-4ec0-b1d1-e1ca0f04bf60",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"kernelspec": {
|
||||||
|
"display_name": "Python 3 (ipykernel)",
|
||||||
|
"language": "python",
|
||||||
|
"name": "python3"
|
||||||
|
},
|
||||||
|
"language_info": {
|
||||||
|
"codemirror_mode": {
|
||||||
|
"name": "ipython",
|
||||||
|
"version": 3
|
||||||
|
},
|
||||||
|
"file_extension": ".py",
|
||||||
|
"mimetype": "text/x-python",
|
||||||
|
"name": "python",
|
||||||
|
"nbconvert_exporter": "python",
|
||||||
|
"pygments_lexer": "ipython3",
|
||||||
|
"version": "3.11.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nbformat": 4,
|
||||||
|
"nbformat_minor": 5
|
||||||
|
}"#), @r###"
|
||||||
|
success: false
|
||||||
|
exit_code: 1
|
||||||
|
----- stdout -----
|
||||||
|
Jupyter.py:cell 1:1:8: F401 [*] `os` imported but unused
|
||||||
|
Jupyter.py:cell 3:1:8: F401 [*] `sys` imported but unused
|
||||||
|
Found 2 errors.
|
||||||
|
[*] 2 fixable with the `--fix` option.
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
"###);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn stdin_override_parser_py() {
|
||||||
|
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
||||||
|
.args(STDIN_BASE_OPTIONS)
|
||||||
|
.args(["--extension", "ipynb:python", "--stdin-filename", "F401.ipynb"])
|
||||||
|
.pass_stdin("import os\n"), @r###"
|
||||||
|
success: false
|
||||||
|
exit_code: 1
|
||||||
|
----- stdout -----
|
||||||
|
F401.ipynb:1:8: F401 [*] `os` imported but unused
|
||||||
|
Found 1 error.
|
||||||
|
[*] 1 fixable with the `--fix` option.
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
"###);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn stdin_fix_when_not_fixable_should_still_print_contents() {
|
fn stdin_fix_when_not_fixable_should_still_print_contents() {
|
||||||
@@ -1407,3 +1520,47 @@ extend-safe-fixes = ["UP034"]
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn check_extend_unsafe_fixes_conflict_with_extend_safe_fixes_by_specificity() -> Result<()> {
|
||||||
|
// Adding a rule to one option with a more specific selector should override the other option
|
||||||
|
let tempdir = TempDir::new()?;
|
||||||
|
let ruff_toml = tempdir.path().join("ruff.toml");
|
||||||
|
fs::write(
|
||||||
|
&ruff_toml,
|
||||||
|
r#"
|
||||||
|
target-version = "py310"
|
||||||
|
[lint]
|
||||||
|
extend-unsafe-fixes = ["UP", "UP034"]
|
||||||
|
extend-safe-fixes = ["UP03"]
|
||||||
|
"#,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
||||||
|
.args(["check", "--config"])
|
||||||
|
.arg(&ruff_toml)
|
||||||
|
.arg("-")
|
||||||
|
.args([
|
||||||
|
"--output-format",
|
||||||
|
"text",
|
||||||
|
"--no-cache",
|
||||||
|
"--select",
|
||||||
|
"F601,UP018,UP034,UP038",
|
||||||
|
])
|
||||||
|
.pass_stdin("x = {'a': 1, 'a': 1}\nprint(('foo'))\nprint(str('foo'))\nisinstance(x, (int, str))\n"),
|
||||||
|
@r###"
|
||||||
|
success: false
|
||||||
|
exit_code: 1
|
||||||
|
----- stdout -----
|
||||||
|
-:1:14: F601 Dictionary key literal `'a'` repeated
|
||||||
|
-:2:7: UP034 Avoid extraneous parentheses
|
||||||
|
-:3:7: UP018 Unnecessary `str` call (rewrite as a literal)
|
||||||
|
-:4:1: UP038 [*] Use `X | Y` in `isinstance` call instead of `(X, Y)`
|
||||||
|
Found 4 errors.
|
||||||
|
[*] 1 fixable with the `--fix` option (3 hidden fixes can be enabled with the `--unsafe-fixes` option).
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
"###);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|||||||
@@ -262,9 +262,13 @@ from test import say_hy
|
|||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
say_hy("dear Ruff contributor")
|
say_hy("dear Ruff contributor")
|
||||||
"#), @r###"
|
"#), @r###"
|
||||||
success: true
|
success: false
|
||||||
exit_code: 0
|
exit_code: 1
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
generated.py:4:16: Q000 [*] Double quotes found but single quotes preferred
|
||||||
|
generated.py:5:12: Q000 [*] Double quotes found but single quotes preferred
|
||||||
|
Found 2 errors.
|
||||||
|
[*] 2 fixable with the `--fix` option.
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
"###);
|
"###);
|
||||||
@@ -308,3 +312,87 @@ _ = "---------------------------------------------------------------------------
|
|||||||
"###);
|
"###);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn per_file_ignores_stdin() -> Result<()> {
|
||||||
|
let tempdir = TempDir::new()?;
|
||||||
|
let ruff_toml = tempdir.path().join("ruff.toml");
|
||||||
|
fs::write(
|
||||||
|
&ruff_toml,
|
||||||
|
r#"
|
||||||
|
extend-select = ["B", "Q"]
|
||||||
|
|
||||||
|
[lint.flake8-quotes]
|
||||||
|
inline-quotes = "single"
|
||||||
|
"#,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
||||||
|
.current_dir(tempdir.path())
|
||||||
|
.arg("check")
|
||||||
|
.args(STDIN_BASE_OPTIONS)
|
||||||
|
.args(["--config", &ruff_toml.file_name().unwrap().to_string_lossy()])
|
||||||
|
.args(["--stdin-filename", "generated.py"])
|
||||||
|
.args(["--per-file-ignores", "generated.py:Q"])
|
||||||
|
.arg("-")
|
||||||
|
.pass_stdin(r#"
|
||||||
|
import os
|
||||||
|
|
||||||
|
from test import say_hy
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
say_hy("dear Ruff contributor")
|
||||||
|
"#), @r###"
|
||||||
|
success: false
|
||||||
|
exit_code: 1
|
||||||
|
----- stdout -----
|
||||||
|
generated.py:2:8: F401 [*] `os` imported but unused
|
||||||
|
Found 1 error.
|
||||||
|
[*] 1 fixable with the `--fix` option.
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
"###);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn extend_per_file_ignores_stdin() -> Result<()> {
|
||||||
|
let tempdir = TempDir::new()?;
|
||||||
|
let ruff_toml = tempdir.path().join("ruff.toml");
|
||||||
|
fs::write(
|
||||||
|
&ruff_toml,
|
||||||
|
r#"
|
||||||
|
extend-select = ["B", "Q"]
|
||||||
|
|
||||||
|
[lint.flake8-quotes]
|
||||||
|
inline-quotes = "single"
|
||||||
|
"#,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
||||||
|
.current_dir(tempdir.path())
|
||||||
|
.arg("check")
|
||||||
|
.args(STDIN_BASE_OPTIONS)
|
||||||
|
.args(["--config", &ruff_toml.file_name().unwrap().to_string_lossy()])
|
||||||
|
.args(["--stdin-filename", "generated.py"])
|
||||||
|
.args(["--extend-per-file-ignores", "generated.py:Q"])
|
||||||
|
.arg("-")
|
||||||
|
.pass_stdin(r#"
|
||||||
|
import os
|
||||||
|
|
||||||
|
from test import say_hy
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
say_hy("dear Ruff contributor")
|
||||||
|
"#), @r###"
|
||||||
|
success: false
|
||||||
|
exit_code: 1
|
||||||
|
----- stdout -----
|
||||||
|
generated.py:2:8: F401 [*] `os` imported but unused
|
||||||
|
Found 1 error.
|
||||||
|
[*] 1 fixable with the `--fix` option.
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
"###);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ serde_json = { workspace = true }
|
|||||||
similar = { workspace = true }
|
similar = { workspace = true }
|
||||||
strum = { workspace = true }
|
strum = { workspace = true }
|
||||||
strum_macros = { workspace = true }
|
strum_macros = { workspace = true }
|
||||||
tempfile = "3.6.0"
|
tempfile = "3.8.1"
|
||||||
toml = { workspace = true, features = ["parse"] }
|
toml = { workspace = true, features = ["parse"] }
|
||||||
tracing = { workspace = true }
|
tracing = { workspace = true }
|
||||||
tracing-indicatif = { workspace = true }
|
tracing-indicatif = { workspace = true }
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
//! Used for <https://docs.astral.sh/ruff/settings/>.
|
//! Used for <https://docs.astral.sh/ruff/settings/>.
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
|
use ruff_python_trivia::textwrap;
|
||||||
use ruff_workspace::options::Options;
|
use ruff_workspace::options::Options;
|
||||||
use ruff_workspace::options_base::{OptionField, OptionSet, OptionsMetadata, Visit};
|
use ruff_workspace::options_base::{OptionField, OptionSet, OptionsMetadata, Visit};
|
||||||
|
|
||||||
@@ -125,18 +126,57 @@ fn emit_field(output: &mut String, name: &str, field: &OptionField, parent_set:
|
|||||||
output.push('\n');
|
output.push('\n');
|
||||||
output.push_str(&format!("**Type**: `{}`\n", field.value_type));
|
output.push_str(&format!("**Type**: `{}`\n", field.value_type));
|
||||||
output.push('\n');
|
output.push('\n');
|
||||||
output.push_str(&format!(
|
output.push_str("**Example usage**:\n\n");
|
||||||
"**Example usage**:\n\n```toml\n[tool.ruff{}]\n{}\n```\n",
|
output.push_str(&format_tab(
|
||||||
if let Some(set_name) = parent_set.name() {
|
"pyproject.toml",
|
||||||
format!(".{set_name}")
|
&format_header(parent_set, ConfigurationFile::PyprojectToml),
|
||||||
} else {
|
field.example,
|
||||||
String::new()
|
));
|
||||||
},
|
output.push_str(&format_tab(
|
||||||
field.example
|
"ruff.toml",
|
||||||
|
&format_header(parent_set, ConfigurationFile::RuffToml),
|
||||||
|
field.example,
|
||||||
));
|
));
|
||||||
output.push('\n');
|
output.push('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn format_tab(tab_name: &str, header: &str, content: &str) -> String {
|
||||||
|
format!(
|
||||||
|
"=== \"{}\"\n\n ```toml\n {}\n{}\n ```\n",
|
||||||
|
tab_name,
|
||||||
|
header,
|
||||||
|
textwrap::indent(content, " ")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn format_header(parent_set: &Set, configuration: ConfigurationFile) -> String {
|
||||||
|
let fmt = if let Some(set_name) = parent_set.name() {
|
||||||
|
if set_name == "format" {
|
||||||
|
String::from(".format")
|
||||||
|
} else {
|
||||||
|
format!(".lint.{set_name}")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
String::new()
|
||||||
|
};
|
||||||
|
match configuration {
|
||||||
|
ConfigurationFile::PyprojectToml => format!("[tool.ruff{fmt}]"),
|
||||||
|
ConfigurationFile::RuffToml => {
|
||||||
|
if fmt.is_empty() {
|
||||||
|
String::new()
|
||||||
|
} else {
|
||||||
|
format!("[{}]", fmt.strip_prefix('.').unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
enum ConfigurationFile {
|
||||||
|
PyprojectToml,
|
||||||
|
RuffToml,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct CollectOptionsVisitor {
|
struct CollectOptionsVisitor {
|
||||||
groups: Vec<(String, OptionSet)>,
|
groups: Vec<(String, OptionSet)>,
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ pub(crate) fn generate() -> String {
|
|||||||
table_out.push('\n');
|
table_out.push('\n');
|
||||||
|
|
||||||
table_out.push_str(&format!(
|
table_out.push_str(&format!(
|
||||||
"The {PREVIEW_SYMBOL} emoji indicates that a rule in [\"preview\"](faq.md#what-is-preview)."
|
"The {PREVIEW_SYMBOL} emoji indicates that a rule is in [\"preview\"](faq.md#what-is-preview)."
|
||||||
));
|
));
|
||||||
table_out.push('\n');
|
table_out.push('\n');
|
||||||
table_out.push('\n');
|
table_out.push('\n');
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use crate::edit::Edit;
|
|||||||
pub enum Applicability {
|
pub enum Applicability {
|
||||||
/// The fix is unsafe and should only be displayed for manual application by the user.
|
/// The fix is unsafe and should only be displayed for manual application by the user.
|
||||||
/// The fix is likely to be incorrect or the resulting code may have invalid syntax.
|
/// The fix is likely to be incorrect or the resulting code may have invalid syntax.
|
||||||
Display,
|
DisplayOnly,
|
||||||
|
|
||||||
/// The fix is unsafe and should only be applied with user opt-in.
|
/// The fix is unsafe and should only be applied with user opt-in.
|
||||||
/// The fix may be what the user intended, but it is uncertain; the resulting code will have valid syntax.
|
/// The fix may be what the user intended, but it is uncertain; the resulting code will have valid syntax.
|
||||||
@@ -87,22 +87,46 @@ impl Fix {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new [`Fix`] that should only [display](Applicability::Display) and not apply from an [`Edit`] element .
|
/// Create a new [`Fix`] that should only [display](Applicability::DisplayOnly) and not apply from an [`Edit`] element .
|
||||||
pub fn display_edit(edit: Edit) -> Self {
|
pub fn display_only_edit(edit: Edit) -> Self {
|
||||||
Self {
|
Self {
|
||||||
edits: vec![edit],
|
edits: vec![edit],
|
||||||
applicability: Applicability::Display,
|
applicability: Applicability::DisplayOnly,
|
||||||
isolation_level: IsolationLevel::default(),
|
isolation_level: IsolationLevel::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new [`Fix`] that should only [display](Applicability::Display) and not apply from multiple [`Edit`] elements.
|
/// Create a new [`Fix`] that should only [display](Applicability::DisplayOnly) and not apply from multiple [`Edit`] elements.
|
||||||
pub fn display_edits(edit: Edit, rest: impl IntoIterator<Item = Edit>) -> Self {
|
pub fn display_only_edits(edit: Edit, rest: impl IntoIterator<Item = Edit>) -> Self {
|
||||||
let mut edits: Vec<Edit> = std::iter::once(edit).chain(rest).collect();
|
let mut edits: Vec<Edit> = std::iter::once(edit).chain(rest).collect();
|
||||||
edits.sort_by_key(|edit| (edit.start(), edit.end()));
|
edits.sort_by_key(|edit| (edit.start(), edit.end()));
|
||||||
Self {
|
Self {
|
||||||
edits,
|
edits,
|
||||||
applicability: Applicability::Display,
|
applicability: Applicability::DisplayOnly,
|
||||||
|
isolation_level: IsolationLevel::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new [`Fix`] with the specified [`Applicability`] to apply an [`Edit`] element.
|
||||||
|
pub fn applicable_edit(edit: Edit, applicability: Applicability) -> Self {
|
||||||
|
Self {
|
||||||
|
edits: vec![edit],
|
||||||
|
applicability,
|
||||||
|
isolation_level: IsolationLevel::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new [`Fix`] with the specified [`Applicability`] to apply multiple [`Edit`] elements.
|
||||||
|
pub fn applicable_edits(
|
||||||
|
edit: Edit,
|
||||||
|
rest: impl IntoIterator<Item = Edit>,
|
||||||
|
applicability: Applicability,
|
||||||
|
) -> Self {
|
||||||
|
let mut edits: Vec<Edit> = std::iter::once(edit).chain(rest).collect();
|
||||||
|
edits.sort_by_key(|edit| (edit.start(), edit.end()));
|
||||||
|
Self {
|
||||||
|
edits,
|
||||||
|
applicability,
|
||||||
isolation_level: IsolationLevel::default(),
|
isolation_level: IsolationLevel::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ruff_linter"
|
name = "ruff_linter"
|
||||||
version = "0.1.3"
|
version = "0.1.5"
|
||||||
publish = false
|
publish = false
|
||||||
authors = { workspace = true }
|
authors = { workspace = true }
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
@@ -53,7 +53,7 @@ path-absolutize = { workspace = true, features = [
|
|||||||
] }
|
] }
|
||||||
pathdiff = { version = "0.2.1" }
|
pathdiff = { version = "0.2.1" }
|
||||||
pep440_rs = { version = "0.3.12", features = ["serde"] }
|
pep440_rs = { version = "0.3.12", features = ["serde"] }
|
||||||
pyproject-toml = { version = "0.7.0" }
|
pyproject-toml = { version = "0.8.0" }
|
||||||
quick-junit = { version = "0.3.2" }
|
quick-junit = { version = "0.3.2" }
|
||||||
regex = { workspace = true }
|
regex = { workspace = true }
|
||||||
result-like = { version = "0.4.6" }
|
result-like = { version = "0.4.6" }
|
||||||
@@ -79,7 +79,7 @@ pretty_assertions = "1.3.0"
|
|||||||
test-case = { workspace = true }
|
test-case = { workspace = true }
|
||||||
# Disable colored output in tests
|
# Disable colored output in tests
|
||||||
colored = { workspace = true, features = ["no-color"] }
|
colored = { workspace = true, features = ["no-color"] }
|
||||||
tempfile = "3.6.0"
|
tempfile = "3.8.1"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
|
|||||||
9
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S702.py
vendored
Normal file
9
crates/ruff_linter/resources/test/fixtures/flake8_bandit/S702.py
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
from mako.template import Template
|
||||||
|
from mako import template
|
||||||
|
import mako
|
||||||
|
|
||||||
|
|
||||||
|
Template("hello")
|
||||||
|
|
||||||
|
mako.template.Template("hern")
|
||||||
|
template.Template("hern")
|
||||||
@@ -58,3 +58,33 @@ def f_fix_indentation_check(foo):
|
|||||||
# Report these, but don't fix them
|
# Report these, but don't fix them
|
||||||
if foo: raise RuntimeError("This is an example exception")
|
if foo: raise RuntimeError("This is an example exception")
|
||||||
if foo: x = 1; raise RuntimeError("This is an example exception")
|
if foo: x = 1; raise RuntimeError("This is an example exception")
|
||||||
|
|
||||||
|
|
||||||
|
def f_triple_quoted_string():
|
||||||
|
raise RuntimeError(f"""This is an {"example"} exception""")
|
||||||
|
|
||||||
|
|
||||||
|
def f_multi_line_string():
|
||||||
|
raise RuntimeError(
|
||||||
|
"first"
|
||||||
|
"second"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def f_multi_line_string2():
|
||||||
|
raise RuntimeError(
|
||||||
|
"This is an {example} exception".format(
|
||||||
|
example="example"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def f_multi_line_string2():
|
||||||
|
raise RuntimeError(
|
||||||
|
(
|
||||||
|
"This is an "
|
||||||
|
"{example} exception"
|
||||||
|
).format(
|
||||||
|
example="example"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
obj = {}
|
||||||
|
|
||||||
key in obj.keys() # SIM118
|
key in obj.keys() # SIM118
|
||||||
|
|
||||||
key not in obj.keys() # SIM118
|
key not in obj.keys() # SIM118
|
||||||
|
|||||||
18
crates/ruff_linter/resources/test/fixtures/flake8_trio/TRIO100.py
vendored
Normal file
18
crates/ruff_linter/resources/test/fixtures/flake8_trio/TRIO100.py
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import trio
|
||||||
|
|
||||||
|
|
||||||
|
async def foo():
|
||||||
|
with trio.fail_after():
|
||||||
|
...
|
||||||
|
|
||||||
|
async def foo():
|
||||||
|
with trio.fail_at():
|
||||||
|
await ...
|
||||||
|
|
||||||
|
async def foo():
|
||||||
|
with trio.move_on_after():
|
||||||
|
...
|
||||||
|
|
||||||
|
async def foo():
|
||||||
|
with trio.move_at():
|
||||||
|
await ...
|
||||||
64
crates/ruff_linter/resources/test/fixtures/flake8_trio/TRIO105.py
vendored
Normal file
64
crates/ruff_linter/resources/test/fixtures/flake8_trio/TRIO105.py
vendored
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import trio
|
||||||
|
|
||||||
|
|
||||||
|
async def func() -> None:
|
||||||
|
trio.run(foo) # OK, not async
|
||||||
|
|
||||||
|
# OK
|
||||||
|
await trio.aclose_forcefully(foo)
|
||||||
|
await trio.open_file(foo)
|
||||||
|
await trio.open_ssl_over_tcp_listeners(foo, foo)
|
||||||
|
await trio.open_ssl_over_tcp_stream(foo, foo)
|
||||||
|
await trio.open_tcp_listeners(foo)
|
||||||
|
await trio.open_tcp_stream(foo, foo)
|
||||||
|
await trio.open_unix_socket(foo)
|
||||||
|
await trio.run_process(foo)
|
||||||
|
await trio.sleep(5)
|
||||||
|
await trio.sleep_until(5)
|
||||||
|
await trio.lowlevel.cancel_shielded_checkpoint()
|
||||||
|
await trio.lowlevel.checkpoint()
|
||||||
|
await trio.lowlevel.checkpoint_if_cancelled()
|
||||||
|
await trio.lowlevel.open_process(foo)
|
||||||
|
await trio.lowlevel.permanently_detach_coroutine_object(foo)
|
||||||
|
await trio.lowlevel.reattach_detached_coroutine_object(foo, foo)
|
||||||
|
await trio.lowlevel.temporarily_detach_coroutine_object(foo)
|
||||||
|
await trio.lowlevel.wait_readable(foo)
|
||||||
|
await trio.lowlevel.wait_task_rescheduled(foo)
|
||||||
|
await trio.lowlevel.wait_writable(foo)
|
||||||
|
|
||||||
|
# TRIO105
|
||||||
|
trio.aclose_forcefully(foo)
|
||||||
|
trio.open_file(foo)
|
||||||
|
trio.open_ssl_over_tcp_listeners(foo, foo)
|
||||||
|
trio.open_ssl_over_tcp_stream(foo, foo)
|
||||||
|
trio.open_tcp_listeners(foo)
|
||||||
|
trio.open_tcp_stream(foo, foo)
|
||||||
|
trio.open_unix_socket(foo)
|
||||||
|
trio.run_process(foo)
|
||||||
|
trio.serve_listeners(foo, foo)
|
||||||
|
trio.serve_ssl_over_tcp(foo, foo, foo)
|
||||||
|
trio.serve_tcp(foo, foo)
|
||||||
|
trio.sleep(foo)
|
||||||
|
trio.sleep_forever()
|
||||||
|
trio.sleep_until(foo)
|
||||||
|
trio.lowlevel.cancel_shielded_checkpoint()
|
||||||
|
trio.lowlevel.checkpoint()
|
||||||
|
trio.lowlevel.checkpoint_if_cancelled()
|
||||||
|
trio.lowlevel.open_process()
|
||||||
|
trio.lowlevel.permanently_detach_coroutine_object(foo)
|
||||||
|
trio.lowlevel.reattach_detached_coroutine_object(foo, foo)
|
||||||
|
trio.lowlevel.temporarily_detach_coroutine_object(foo)
|
||||||
|
trio.lowlevel.wait_readable(foo)
|
||||||
|
trio.lowlevel.wait_task_rescheduled(foo)
|
||||||
|
trio.lowlevel.wait_writable(foo)
|
||||||
|
|
||||||
|
async with await trio.open_file(foo): # Ok
|
||||||
|
pass
|
||||||
|
|
||||||
|
async with trio.open_file(foo): # TRIO105
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def func() -> None:
|
||||||
|
# TRIO105 (without fix)
|
||||||
|
trio.open_file(foo)
|
||||||
13
crates/ruff_linter/resources/test/fixtures/flake8_trio/TRIO109.py
vendored
Normal file
13
crates/ruff_linter/resources/test/fixtures/flake8_trio/TRIO109.py
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import trio
|
||||||
|
|
||||||
|
|
||||||
|
async def func():
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
async def func(timeout):
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
async def func(timeout=10):
|
||||||
|
...
|
||||||
16
crates/ruff_linter/resources/test/fixtures/flake8_trio/TRIO110.py
vendored
Normal file
16
crates/ruff_linter/resources/test/fixtures/flake8_trio/TRIO110.py
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import trio
|
||||||
|
|
||||||
|
|
||||||
|
async def func():
|
||||||
|
while True:
|
||||||
|
await trio.sleep(10)
|
||||||
|
|
||||||
|
|
||||||
|
async def func():
|
||||||
|
while True:
|
||||||
|
await trio.sleep_until(10)
|
||||||
|
|
||||||
|
|
||||||
|
async def func():
|
||||||
|
while True:
|
||||||
|
trio.sleep(10)
|
||||||
28
crates/ruff_linter/resources/test/fixtures/flake8_trio/TRIO115.py
vendored
Normal file
28
crates/ruff_linter/resources/test/fixtures/flake8_trio/TRIO115.py
vendored
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import trio
|
||||||
|
from trio import sleep
|
||||||
|
|
||||||
|
|
||||||
|
async def func():
|
||||||
|
await trio.sleep(0) # TRIO115
|
||||||
|
await trio.sleep(1) # OK
|
||||||
|
await trio.sleep(0, 1) # OK
|
||||||
|
await trio.sleep(...) # OK
|
||||||
|
await trio.sleep() # OK
|
||||||
|
|
||||||
|
trio.sleep(0) # TRIO115
|
||||||
|
foo = 0
|
||||||
|
trio.sleep(foo) # TRIO115
|
||||||
|
trio.sleep(1) # OK
|
||||||
|
time.sleep(0) # OK
|
||||||
|
|
||||||
|
sleep(0) # TRIO115
|
||||||
|
|
||||||
|
bar = "bar"
|
||||||
|
trio.sleep(bar)
|
||||||
|
|
||||||
|
|
||||||
|
trio.sleep(0) # TRIO115
|
||||||
|
|
||||||
|
|
||||||
|
def func():
|
||||||
|
trio.run(trio.sleep(0)) # TRIO115
|
||||||
0
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/module/__init__.py
vendored
Normal file
0
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/module/__init__.py
vendored
Normal file
11
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/module/direct.py
vendored
Normal file
11
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/module/direct.py
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from collections.abc import Sequence
|
||||||
|
|
||||||
|
|
||||||
|
class MyBaseClass:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Foo(MyBaseClass):
|
||||||
|
foo: Sequence
|
||||||
9
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/module/import.py
vendored
Normal file
9
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/module/import.py
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from collections.abc import Sequence
|
||||||
|
|
||||||
|
from module.direct import MyBaseClass
|
||||||
|
|
||||||
|
|
||||||
|
class Foo(MyBaseClass):
|
||||||
|
foo: Sequence
|
||||||
7
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/module/undefined.py
vendored
Normal file
7
crates/ruff_linter/resources/test/fixtures/flake8_type_checking/module/undefined.py
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from collections.abc import Sequence
|
||||||
|
|
||||||
|
|
||||||
|
class Foo(MyBaseClass):
|
||||||
|
foo: Sequence
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from collections.abc import Sequence # TCH003
|
||||||
|
|
||||||
|
|
||||||
|
class MyBaseClass:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Foo(MyBaseClass):
|
||||||
|
foo: Sequence
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
line-length = 88
|
line-length = 88
|
||||||
|
|
||||||
[tool.ruff.isort]
|
[tool.ruff.lint.isort]
|
||||||
lines-after-imports = 3
|
lines-after-imports = 3
|
||||||
lines-between-types = 2
|
lines-between-types = 2
|
||||||
known-local-folder = ["ruff"]
|
known-local-folder = ["ruff"]
|
||||||
|
|||||||
106
crates/ruff_linter/resources/test/fixtures/numpy/NPY201.py
vendored
Normal file
106
crates/ruff_linter/resources/test/fixtures/numpy/NPY201.py
vendored
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
def func():
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
np.add_docstring
|
||||||
|
|
||||||
|
np.add_newdoc
|
||||||
|
|
||||||
|
np.add_newdoc_ufunc
|
||||||
|
|
||||||
|
np.asfarray([1,2,3])
|
||||||
|
|
||||||
|
np.byte_bounds(np.array([1,2,3]))
|
||||||
|
|
||||||
|
np.cast
|
||||||
|
|
||||||
|
np.cfloat(12+34j)
|
||||||
|
|
||||||
|
np.clongfloat(12+34j)
|
||||||
|
|
||||||
|
np.compat
|
||||||
|
|
||||||
|
np.complex_(12+34j)
|
||||||
|
|
||||||
|
np.DataSource
|
||||||
|
|
||||||
|
np.deprecate
|
||||||
|
|
||||||
|
np.deprecate_with_doc
|
||||||
|
|
||||||
|
np.disp(10)
|
||||||
|
|
||||||
|
np.fastCopyAndTranspose
|
||||||
|
|
||||||
|
np.find_common_type
|
||||||
|
|
||||||
|
np.get_array_wrap
|
||||||
|
|
||||||
|
np.float_
|
||||||
|
|
||||||
|
np.geterrobj
|
||||||
|
|
||||||
|
np.Inf
|
||||||
|
|
||||||
|
np.Infinity
|
||||||
|
|
||||||
|
np.infty
|
||||||
|
|
||||||
|
np.issctype
|
||||||
|
|
||||||
|
np.issubclass_(np.int32, np.integer)
|
||||||
|
|
||||||
|
np.issubsctype
|
||||||
|
|
||||||
|
np.mat
|
||||||
|
|
||||||
|
np.maximum_sctype
|
||||||
|
|
||||||
|
np.NaN
|
||||||
|
|
||||||
|
np.nbytes[np.int64]
|
||||||
|
|
||||||
|
np.NINF
|
||||||
|
|
||||||
|
np.NZERO
|
||||||
|
|
||||||
|
np.longcomplex(12+34j)
|
||||||
|
|
||||||
|
np.longfloat(12+34j)
|
||||||
|
|
||||||
|
np.lookfor
|
||||||
|
|
||||||
|
np.obj2sctype(int)
|
||||||
|
|
||||||
|
np.PINF
|
||||||
|
|
||||||
|
np.PZERO
|
||||||
|
|
||||||
|
np.recfromcsv
|
||||||
|
|
||||||
|
np.recfromtxt
|
||||||
|
|
||||||
|
np.round_(12.34)
|
||||||
|
|
||||||
|
np.safe_eval
|
||||||
|
|
||||||
|
np.sctype2char
|
||||||
|
|
||||||
|
np.sctypes
|
||||||
|
|
||||||
|
np.seterrobj
|
||||||
|
|
||||||
|
np.set_numeric_ops
|
||||||
|
|
||||||
|
np.set_string_function
|
||||||
|
|
||||||
|
np.singlecomplex(12+1j)
|
||||||
|
|
||||||
|
np.string_("asdf")
|
||||||
|
|
||||||
|
np.source
|
||||||
|
|
||||||
|
np.tracemalloc_domain
|
||||||
|
|
||||||
|
np.unicode_("asf")
|
||||||
|
|
||||||
|
np.who()
|
||||||
@@ -12,3 +12,19 @@ dict['key'] = list[index]
|
|||||||
# This is not prohibited by PEP8, but avoid it.
|
# This is not prohibited by PEP8, but avoid it.
|
||||||
class Foo (Bar, Baz):
|
class Foo (Bar, Baz):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_name () -> Union[str, None]:
|
||||||
|
"""Fetch name from --person-name in sys.argv.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
name of the person if available, otherwise None
|
||||||
|
"""
|
||||||
|
test = len(5)
|
||||||
|
Logger.info(test)
|
||||||
|
# test commented code
|
||||||
|
# Logger.info("test code")
|
||||||
|
for i in range (0, len (sys.argv)) :
|
||||||
|
if sys.argv[i] == "--name" :
|
||||||
|
return sys.argv[i + 1]
|
||||||
|
return None
|
||||||
|
|||||||
@@ -40,5 +40,11 @@ f"{(a:=1)}"
|
|||||||
f"{(lambda x:x)}"
|
f"{(lambda x:x)}"
|
||||||
f"normal{f"{a:.3f}"}normal"
|
f"normal{f"{a:.3f}"}normal"
|
||||||
|
|
||||||
|
#: Okay
|
||||||
|
snapshot.file_uri[len(f's3://{self.s3_bucket_name}/'):]
|
||||||
|
|
||||||
|
#: E231
|
||||||
|
{len(f's3://{self.s3_bucket_name}/'):1}
|
||||||
|
|
||||||
#: Okay
|
#: Okay
|
||||||
a = (1,
|
a = (1,
|
||||||
|
|||||||
@@ -69,3 +69,5 @@ while 1:
|
|||||||
#: E701:2:3
|
#: E701:2:3
|
||||||
a = \
|
a = \
|
||||||
5;
|
5;
|
||||||
|
#:
|
||||||
|
with x(y) as z: ...
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ if type(res) == type(42):
|
|||||||
#: E721
|
#: E721
|
||||||
if type(res) != type(""):
|
if type(res) != type(""):
|
||||||
pass
|
pass
|
||||||
|
#: E721
|
||||||
|
if type(res) == memoryview:
|
||||||
|
pass
|
||||||
#: Okay
|
#: Okay
|
||||||
import types
|
import types
|
||||||
|
|
||||||
@@ -47,6 +50,14 @@ if isinstance(res, str):
|
|||||||
pass
|
pass
|
||||||
if isinstance(res, types.MethodType):
|
if isinstance(res, types.MethodType):
|
||||||
pass
|
pass
|
||||||
|
if isinstance(res, memoryview):
|
||||||
|
pass
|
||||||
|
#: Okay
|
||||||
|
if type(res) is type:
|
||||||
|
pass
|
||||||
|
#: E721
|
||||||
|
if type(res) == type:
|
||||||
|
pass
|
||||||
#: Okay
|
#: Okay
|
||||||
def func_histype(a, b, c):
|
def func_histype(a, b, c):
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -8,3 +8,19 @@ def ends_in_quote():
|
|||||||
|
|
||||||
def contains_quote():
|
def contains_quote():
|
||||||
'Sum"\\mary.'
|
'Sum"\\mary.'
|
||||||
|
|
||||||
|
|
||||||
|
# OK
|
||||||
|
def contains_triples(t):
|
||||||
|
"""('''|\""")"""
|
||||||
|
|
||||||
|
|
||||||
|
# OK
|
||||||
|
def contains_triples(t):
|
||||||
|
'''(\'''|""")'''
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: here should raise D300 for using dobule quotes instead,
|
||||||
|
# because escaped double quote does allow us.
|
||||||
|
def contains_triples(t):
|
||||||
|
'''(\""")'''
|
||||||
|
|||||||
@@ -31,3 +31,7 @@ def make_unique_pod_id(pod_id: str) -> str | None:
|
|||||||
:param pod_id: requested pod name
|
:param pod_id: requested pod name
|
||||||
:return: ``str`` valid Pod name of appropriate length
|
:return: ``str`` valid Pod name of appropriate length
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def shouldnt_add_raw_here2():
|
||||||
|
u"Sum\\mary."
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
def f(tup):
|
def f(tup):
|
||||||
x, y = tup # this does NOT trigger F841
|
x, y = tup
|
||||||
|
|
||||||
|
|
||||||
def f():
|
def f():
|
||||||
@@ -7,17 +7,17 @@ def f():
|
|||||||
|
|
||||||
|
|
||||||
def f():
|
def f():
|
||||||
(x, y) = coords = 1, 2 # this does NOT trigger F841
|
(x, y) = coords = 1, 2
|
||||||
if x > 1:
|
if x > 1:
|
||||||
print(coords)
|
print(coords)
|
||||||
|
|
||||||
|
|
||||||
def f():
|
def f():
|
||||||
(x, y) = coords = 1, 2 # this triggers F841 on coords
|
(x, y) = coords = 1, 2
|
||||||
|
|
||||||
|
|
||||||
def f():
|
def f():
|
||||||
coords = (x, y) = 1, 2 # this triggers F841 on coords
|
coords = (x, y) = 1, 2
|
||||||
|
|
||||||
|
|
||||||
def f():
|
def f():
|
||||||
|
|||||||
32
crates/ruff_linter/resources/test/fixtures/pyflakes/F841_4.py
vendored
Normal file
32
crates/ruff_linter/resources/test/fixtures/pyflakes/F841_4.py
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
"""Test fix for issue #8441.
|
||||||
|
|
||||||
|
Ref: https://github.com/astral-sh/ruff/issues/8441
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def foo():
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
def bar():
|
||||||
|
a = foo()
|
||||||
|
b, c = foo()
|
||||||
|
|
||||||
|
|
||||||
|
def baz():
|
||||||
|
d, _e = foo()
|
||||||
|
print(d)
|
||||||
|
|
||||||
|
|
||||||
|
def qux():
|
||||||
|
f, _ = foo()
|
||||||
|
print(f)
|
||||||
|
|
||||||
|
|
||||||
|
def quux():
|
||||||
|
g, h = foo()
|
||||||
|
print(g, h)
|
||||||
|
|
||||||
|
|
||||||
|
def quuz():
|
||||||
|
_i, _j = foo()
|
||||||
@@ -70,6 +70,10 @@ class Apples:
|
|||||||
def __html__(self):
|
def __html__(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# Allow Python's __index__
|
||||||
|
def __index__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
# Allow _missing_, used by enum.Enum.
|
# Allow _missing_, used by enum.Enum.
|
||||||
@classmethod
|
@classmethod
|
||||||
def _missing_(cls, value):
|
def _missing_(cls, value):
|
||||||
|
|||||||
34
crates/ruff_linter/resources/test/fixtures/pylint/bad_open_mode.py
vendored
Normal file
34
crates/ruff_linter/resources/test/fixtures/pylint/bad_open_mode.py
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import pathlib
|
||||||
|
|
||||||
|
NAME = "foo.bar"
|
||||||
|
open(NAME, "wb")
|
||||||
|
open(NAME, "w", encoding="utf-8")
|
||||||
|
open(NAME, "rb")
|
||||||
|
open(NAME, "x", encoding="utf-8")
|
||||||
|
open(NAME, "br")
|
||||||
|
open(NAME, "+r", encoding="utf-8")
|
||||||
|
open(NAME, "xb")
|
||||||
|
open(NAME, "rwx") # [bad-open-mode]
|
||||||
|
open(NAME, mode="rwx") # [bad-open-mode]
|
||||||
|
open(NAME, "rwx", encoding="utf-8") # [bad-open-mode]
|
||||||
|
open(NAME, "rr", encoding="utf-8") # [bad-open-mode]
|
||||||
|
open(NAME, "+", encoding="utf-8") # [bad-open-mode]
|
||||||
|
open(NAME, "xw", encoding="utf-8") # [bad-open-mode]
|
||||||
|
open(NAME, "ab+")
|
||||||
|
open(NAME, "a+b")
|
||||||
|
open(NAME, "+ab")
|
||||||
|
open(NAME, "+rUb")
|
||||||
|
open(NAME, "x+b")
|
||||||
|
open(NAME, "Ua", encoding="utf-8") # [bad-open-mode]
|
||||||
|
open(NAME, "Ur++", encoding="utf-8") # [bad-open-mode]
|
||||||
|
open(NAME, "Ut", encoding="utf-8")
|
||||||
|
open(NAME, "Ubr")
|
||||||
|
|
||||||
|
mode = "rw"
|
||||||
|
open(NAME, mode)
|
||||||
|
|
||||||
|
pathlib.Path(NAME).open("wb")
|
||||||
|
pathlib.Path(NAME).open(mode)
|
||||||
|
pathlib.Path(NAME).open("rwx") # [bad-open-mode]
|
||||||
|
pathlib.Path(NAME).open(mode="rwx") # [bad-open-mode]
|
||||||
|
pathlib.Path(NAME).open("rwx", encoding="utf-8") # [bad-open-mode]
|
||||||
@@ -57,3 +57,9 @@ r'\%03o' % (ord(c),)
|
|||||||
'(%r, %r, %r, %r)' % (hostname, address, username, '$PASSWORD')
|
'(%r, %r, %r, %r)' % (hostname, address, username, '$PASSWORD')
|
||||||
'%r' % ({'server_school_roles': server_school_roles, 'is_school_multiserver_domain': is_school_multiserver_domain}, )
|
'%r' % ({'server_school_roles': server_school_roles, 'is_school_multiserver_domain': is_school_multiserver_domain}, )
|
||||||
"%d" % (1 if x > 0 else 2)
|
"%d" % (1 if x > 0 else 2)
|
||||||
|
|
||||||
|
# Special cases for %c allowing single character strings
|
||||||
|
# https://github.com/astral-sh/ruff/issues/8406
|
||||||
|
"%c" % ("x",)
|
||||||
|
"%c" % "x"
|
||||||
|
"%c" % "œ"
|
||||||
|
|||||||
22
crates/ruff_linter/resources/test/fixtures/pylint/import_outside_top_level.py
vendored
Normal file
22
crates/ruff_linter/resources/test/fixtures/pylint/import_outside_top_level.py
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
# Verify that statements nested in conditionals (such as top-level type-checking blocks)
|
||||||
|
# are still considered top-level
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
import string
|
||||||
|
|
||||||
|
|
||||||
|
def import_in_function():
|
||||||
|
import symtable # [import-outside-toplevel]
|
||||||
|
import os, sys # [import-outside-toplevel]
|
||||||
|
import time as thyme # [import-outside-toplevel]
|
||||||
|
import random as rand, socket as sock # [import-outside-toplevel]
|
||||||
|
from collections import defaultdict # [import-outside-toplevel]
|
||||||
|
from math import sin as sign, cos as cosplay # [import-outside-toplevel]
|
||||||
|
|
||||||
|
|
||||||
|
class ClassWithImports:
|
||||||
|
import tokenize # [import-outside-toplevel]
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
import trace # [import-outside-toplevel]
|
||||||
56
crates/ruff_linter/resources/test/fixtures/pylint/useless_with_lock.py
vendored
Normal file
56
crates/ruff_linter/resources/test/fixtures/pylint/useless_with_lock.py
vendored
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import threading
|
||||||
|
from threading import Lock, RLock, Condition, Semaphore, BoundedSemaphore
|
||||||
|
|
||||||
|
|
||||||
|
with threading.Lock(): # [useless-with-lock]
|
||||||
|
...
|
||||||
|
|
||||||
|
with Lock(): # [useless-with-lock]
|
||||||
|
...
|
||||||
|
|
||||||
|
with threading.Lock() as this_shouldnt_matter: # [useless-with-lock]
|
||||||
|
...
|
||||||
|
|
||||||
|
with threading.RLock(): # [useless-with-lock]
|
||||||
|
...
|
||||||
|
|
||||||
|
with RLock(): # [useless-with-lock]
|
||||||
|
...
|
||||||
|
|
||||||
|
with threading.Condition(): # [useless-with-lock]
|
||||||
|
...
|
||||||
|
|
||||||
|
with Condition(): # [useless-with-lock]
|
||||||
|
...
|
||||||
|
|
||||||
|
with threading.Semaphore(): # [useless-with-lock]
|
||||||
|
...
|
||||||
|
|
||||||
|
with Semaphore(): # [useless-with-lock]
|
||||||
|
...
|
||||||
|
|
||||||
|
with threading.BoundedSemaphore(): # [useless-with-lock]
|
||||||
|
...
|
||||||
|
|
||||||
|
with BoundedSemaphore(): # [useless-with-lock]
|
||||||
|
...
|
||||||
|
|
||||||
|
lock = threading.Lock()
|
||||||
|
with lock: # this is ok
|
||||||
|
...
|
||||||
|
|
||||||
|
rlock = threading.RLock()
|
||||||
|
with rlock: # this is ok
|
||||||
|
...
|
||||||
|
|
||||||
|
cond = threading.Condition()
|
||||||
|
with cond: # this is ok
|
||||||
|
...
|
||||||
|
|
||||||
|
sem = threading.Semaphore()
|
||||||
|
with sem: # this is ok
|
||||||
|
...
|
||||||
|
|
||||||
|
b_sem = threading.BoundedSemaphore()
|
||||||
|
with b_sem: # this is ok
|
||||||
|
...
|
||||||
@@ -5,4 +5,6 @@ extend-exclude = [
|
|||||||
"migrations",
|
"migrations",
|
||||||
"with_excluded_file/other_excluded_file.py",
|
"with_excluded_file/other_excluded_file.py",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[tool.ruff.lint]
|
||||||
per-file-ignores = { "__init__.py" = ["F401"] }
|
per-file-ignores = { "__init__.py" = ["F401"] }
|
||||||
|
|||||||
@@ -23,3 +23,11 @@ MyType = typing.NamedTuple("MyType", a=int, b=tuple[str, ...])
|
|||||||
MyType = typing.NamedTuple("MyType", [("a", int)], [("b", str)])
|
MyType = typing.NamedTuple("MyType", [("a", int)], [("b", str)])
|
||||||
MyType = typing.NamedTuple("MyType", [("a", int)], b=str)
|
MyType = typing.NamedTuple("MyType", [("a", int)], b=str)
|
||||||
MyType = typing.NamedTuple(typename="MyType", a=int, b=str)
|
MyType = typing.NamedTuple(typename="MyType", a=int, b=str)
|
||||||
|
|
||||||
|
# Regression test for: https://github.com/astral-sh/ruff/issues/8402#issuecomment-1788787357
|
||||||
|
S3File = NamedTuple(
|
||||||
|
"S3File",
|
||||||
|
[
|
||||||
|
("dataHPK",* str),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|||||||
68
crates/ruff_linter/resources/test/fixtures/pyupgrade/UP041.py
vendored
Normal file
68
crates/ruff_linter/resources/test/fixtures/pyupgrade/UP041.py
vendored
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
import asyncio, socket
|
||||||
|
# These should be fixed
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
except socket.timeout:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Should NOT be in parentheses when replaced
|
||||||
|
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
except (asyncio.TimeoutError,):
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
except (socket.timeout,):
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
except (asyncio.TimeoutError, socket.timeout,):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Should be kept in parentheses (because multiple)
|
||||||
|
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
except (asyncio.TimeoutError, socket.timeout, KeyError, TimeoutError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# First should change, second should not
|
||||||
|
|
||||||
|
from .mmap import error
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
except (asyncio.TimeoutError, error):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# These should not change
|
||||||
|
|
||||||
|
from foo import error
|
||||||
|
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
except (TimeoutError, error):
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
except TimeoutError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
except (TimeoutError, KeyError):
|
||||||
|
pass
|
||||||
@@ -123,6 +123,15 @@ def yes_six(x: list):
|
|||||||
x.append(2)
|
x.append(2)
|
||||||
|
|
||||||
|
|
||||||
|
if True:
|
||||||
|
# FURB113
|
||||||
|
nums.append(1)
|
||||||
|
# comment
|
||||||
|
nums.append(2)
|
||||||
|
# comment
|
||||||
|
nums.append(3)
|
||||||
|
|
||||||
|
|
||||||
# Non-errors.
|
# Non-errors.
|
||||||
|
|
||||||
nums.append(1)
|
nums.append(1)
|
||||||
|
|||||||
@@ -43,6 +43,12 @@ def yes_four(x: Dict[int, str]):
|
|||||||
del x[:]
|
del x[:]
|
||||||
|
|
||||||
|
|
||||||
|
def yes_five(x: Dict[int, str]):
|
||||||
|
# FURB131
|
||||||
|
del x[:]
|
||||||
|
|
||||||
|
x = 1
|
||||||
|
|
||||||
# these should not
|
# these should not
|
||||||
|
|
||||||
del names["key"]
|
del names["key"]
|
||||||
|
|||||||
51
crates/ruff_linter/resources/test/fixtures/refurb/FURB168.py
vendored
Normal file
51
crates/ruff_linter/resources/test/fixtures/refurb/FURB168.py
vendored
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
foo: object
|
||||||
|
|
||||||
|
# Errors.
|
||||||
|
|
||||||
|
if isinstance(foo, type(None)):
|
||||||
|
pass
|
||||||
|
|
||||||
|
if isinstance(foo, (type(None))):
|
||||||
|
pass
|
||||||
|
|
||||||
|
if isinstance(foo, (type(None), type(None), type(None))):
|
||||||
|
pass
|
||||||
|
|
||||||
|
if isinstance(foo, None | None):
|
||||||
|
pass
|
||||||
|
|
||||||
|
if isinstance(foo, (None | None)):
|
||||||
|
pass
|
||||||
|
|
||||||
|
if isinstance(foo, None | type(None)):
|
||||||
|
pass
|
||||||
|
|
||||||
|
if isinstance(foo, (None | type(None))):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# A bit contrived, but is both technically valid and equivalent to the above.
|
||||||
|
if isinstance(foo, (type(None) | ((((type(None))))) | ((None | type(None))))):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# Okay.
|
||||||
|
|
||||||
|
if isinstance(foo, int):
|
||||||
|
pass
|
||||||
|
|
||||||
|
if isinstance(foo, (int)):
|
||||||
|
pass
|
||||||
|
|
||||||
|
if isinstance(foo, (int, str)):
|
||||||
|
pass
|
||||||
|
|
||||||
|
if isinstance(foo, (int, type(None), str)):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# This is a TypeError, which the rule ignores.
|
||||||
|
if isinstance(foo, None):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# This is also a TypeError, which the rule ignores.
|
||||||
|
if isinstance(foo, (None,)):
|
||||||
|
pass
|
||||||
67
crates/ruff_linter/resources/test/fixtures/refurb/FURB169.py
vendored
Normal file
67
crates/ruff_linter/resources/test/fixtures/refurb/FURB169.py
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
foo = None
|
||||||
|
|
||||||
|
# Error.
|
||||||
|
|
||||||
|
type(foo) is type(None)
|
||||||
|
|
||||||
|
type(None) is type(foo)
|
||||||
|
|
||||||
|
type(None) is type(None)
|
||||||
|
|
||||||
|
type(foo) is not type(None)
|
||||||
|
|
||||||
|
type(None) is not type(foo)
|
||||||
|
|
||||||
|
type(None) is not type(None)
|
||||||
|
|
||||||
|
type(foo) == type(None)
|
||||||
|
|
||||||
|
type(None) == type(foo)
|
||||||
|
|
||||||
|
type(None) == type(None)
|
||||||
|
|
||||||
|
type(foo) != type(None)
|
||||||
|
|
||||||
|
type(None) != type(foo)
|
||||||
|
|
||||||
|
type(None) != type(None)
|
||||||
|
|
||||||
|
# Ok.
|
||||||
|
|
||||||
|
foo is None
|
||||||
|
|
||||||
|
foo is not None
|
||||||
|
|
||||||
|
None is foo
|
||||||
|
|
||||||
|
None is not foo
|
||||||
|
|
||||||
|
None is None
|
||||||
|
|
||||||
|
None is not None
|
||||||
|
|
||||||
|
foo is type(None)
|
||||||
|
|
||||||
|
type(foo) is None
|
||||||
|
|
||||||
|
type(None) is None
|
||||||
|
|
||||||
|
foo is not type(None)
|
||||||
|
|
||||||
|
type(foo) is not None
|
||||||
|
|
||||||
|
type(None) is not None
|
||||||
|
|
||||||
|
foo == type(None)
|
||||||
|
|
||||||
|
type(foo) == None
|
||||||
|
|
||||||
|
type(None) == None
|
||||||
|
|
||||||
|
foo != type(None)
|
||||||
|
|
||||||
|
type(foo) != None
|
||||||
|
|
||||||
|
type(None) != None
|
||||||
|
|
||||||
|
type(foo) > type(None)
|
||||||
@@ -43,3 +43,6 @@ if 1 is {1}:
|
|||||||
|
|
||||||
if "a" == "a":
|
if "a" == "a":
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
if 1 in {*[1]}:
|
||||||
|
pass
|
||||||
|
|||||||
@@ -45,3 +45,11 @@ x = f"string { # And here's a comment with an unusual parenthesis: )
|
|||||||
# And here's a comment with a greek alpha: ∗
|
# And here's a comment with a greek alpha: ∗
|
||||||
foo # And here's a comment with an unusual punctuation mark: ᜵
|
foo # And here's a comment with an unusual punctuation mark: ᜵
|
||||||
}"
|
}"
|
||||||
|
|
||||||
|
# At runtime the attribute will be stored as Greek small letter mu instead of
|
||||||
|
# micro sign because of PEP 3131's NFKC normalization
|
||||||
|
class Labware:
|
||||||
|
µL = 1.5
|
||||||
|
|
||||||
|
|
||||||
|
assert getattr(Labware(), "µL") == 1.5
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
src = [".", "python_modules/*"]
|
src = [".", "python_modules/*"]
|
||||||
exclude = ["examples/excluded"]
|
exclude = ["examples/excluded"]
|
||||||
|
|
||||||
|
[tool.ruff.lint]
|
||||||
extend-select = ["I001"]
|
extend-select = ["I001"]
|
||||||
extend-ignore = ["F841"]
|
extend-ignore = ["F841"]
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ pub(crate) fn definitions(checker: &mut Checker) {
|
|||||||
expr.start(),
|
expr.start(),
|
||||||
));
|
));
|
||||||
|
|
||||||
if pydocstyle::helpers::should_ignore_docstring(expr) {
|
if expr.implicit_concatenated {
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
let location = checker.locator.compute_source_location(expr.start());
|
let location = checker.locator.compute_source_location(expr.start());
|
||||||
warn_user!(
|
warn_user!(
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use ruff_python_ast::{self as ast, Arguments, Constant, Expr, ExprContext, Operator};
|
use ruff_python_ast::{self as ast, Arguments, Expr, ExprContext, Operator};
|
||||||
use ruff_python_literal::cformat::{CFormatError, CFormatErrorType};
|
use ruff_python_literal::cformat::{CFormatError, CFormatErrorType};
|
||||||
|
|
||||||
use ruff_diagnostics::Diagnostic;
|
use ruff_diagnostics::Diagnostic;
|
||||||
@@ -15,8 +15,8 @@ use crate::rules::{
|
|||||||
flake8_comprehensions, flake8_datetimez, flake8_debugger, flake8_django,
|
flake8_comprehensions, flake8_datetimez, flake8_debugger, flake8_django,
|
||||||
flake8_future_annotations, flake8_gettext, flake8_implicit_str_concat, flake8_logging,
|
flake8_future_annotations, flake8_gettext, flake8_implicit_str_concat, flake8_logging,
|
||||||
flake8_logging_format, flake8_pie, flake8_print, flake8_pyi, flake8_pytest_style, flake8_self,
|
flake8_logging_format, flake8_pie, flake8_print, flake8_pyi, flake8_pytest_style, flake8_self,
|
||||||
flake8_simplify, flake8_tidy_imports, flake8_use_pathlib, flynt, numpy, pandas_vet,
|
flake8_simplify, flake8_tidy_imports, flake8_trio, flake8_use_pathlib, flynt, numpy,
|
||||||
pep8_naming, pycodestyle, pyflakes, pygrep_hooks, pylint, pyupgrade, refurb, ruff,
|
pandas_vet, pep8_naming, pycodestyle, pyflakes, pygrep_hooks, pylint, pyupgrade, refurb, ruff,
|
||||||
};
|
};
|
||||||
use crate::settings::types::PythonVersion;
|
use crate::settings::types::PythonVersion;
|
||||||
|
|
||||||
@@ -158,6 +158,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
|
|||||||
if checker.enabled(Rule::NumpyDeprecatedFunction) {
|
if checker.enabled(Rule::NumpyDeprecatedFunction) {
|
||||||
numpy::rules::deprecated_function(checker, expr);
|
numpy::rules::deprecated_function(checker, expr);
|
||||||
}
|
}
|
||||||
|
if checker.enabled(Rule::Numpy2Deprecation) {
|
||||||
|
numpy::rules::numpy_2_0_deprecation(checker, expr);
|
||||||
|
}
|
||||||
if checker.enabled(Rule::CollectionsNamedTuple) {
|
if checker.enabled(Rule::CollectionsNamedTuple) {
|
||||||
flake8_pyi::rules::collections_named_tuple(checker, expr);
|
flake8_pyi::rules::collections_named_tuple(checker, expr);
|
||||||
}
|
}
|
||||||
@@ -314,6 +317,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
|
|||||||
if checker.enabled(Rule::NumpyDeprecatedFunction) {
|
if checker.enabled(Rule::NumpyDeprecatedFunction) {
|
||||||
numpy::rules::deprecated_function(checker, expr);
|
numpy::rules::deprecated_function(checker, expr);
|
||||||
}
|
}
|
||||||
|
if checker.enabled(Rule::Numpy2Deprecation) {
|
||||||
|
numpy::rules::numpy_2_0_deprecation(checker, expr);
|
||||||
|
}
|
||||||
if checker.enabled(Rule::DeprecatedMockImport) {
|
if checker.enabled(Rule::DeprecatedMockImport) {
|
||||||
pyupgrade::rules::deprecated_mock_attribute(checker, expr);
|
pyupgrade::rules::deprecated_mock_attribute(checker, expr);
|
||||||
}
|
}
|
||||||
@@ -363,20 +369,18 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
|
|||||||
]) {
|
]) {
|
||||||
if let Expr::Attribute(ast::ExprAttribute { value, attr, .. }) = func.as_ref() {
|
if let Expr::Attribute(ast::ExprAttribute { value, attr, .. }) = func.as_ref() {
|
||||||
let attr = attr.as_str();
|
let attr = attr.as_str();
|
||||||
if let Expr::Constant(ast::ExprConstant {
|
if let Expr::StringLiteral(ast::ExprStringLiteral { value: string, .. }) =
|
||||||
value: Constant::Str(val),
|
value.as_ref()
|
||||||
..
|
|
||||||
}) = value.as_ref()
|
|
||||||
{
|
{
|
||||||
if attr == "join" {
|
if attr == "join" {
|
||||||
// "...".join(...) call
|
// "...".join(...) call
|
||||||
if checker.enabled(Rule::StaticJoinToFString) {
|
if checker.enabled(Rule::StaticJoinToFString) {
|
||||||
flynt::rules::static_join_to_fstring(checker, expr, val);
|
flynt::rules::static_join_to_fstring(checker, expr, string);
|
||||||
}
|
}
|
||||||
} else if attr == "format" {
|
} else if attr == "format" {
|
||||||
// "...".format(...) call
|
// "...".format(...) call
|
||||||
let location = expr.range();
|
let location = expr.range();
|
||||||
match pyflakes::format::FormatSummary::try_from(val.as_ref()) {
|
match pyflakes::format::FormatSummary::try_from(string.as_ref()) {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
if checker.enabled(Rule::StringDotFormatInvalidFormat) {
|
if checker.enabled(Rule::StringDotFormatInvalidFormat) {
|
||||||
checker.diagnostics.push(Diagnostic::new(
|
checker.diagnostics.push(Diagnostic::new(
|
||||||
@@ -421,7 +425,7 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
|
|||||||
|
|
||||||
if checker.enabled(Rule::BadStringFormatCharacter) {
|
if checker.enabled(Rule::BadStringFormatCharacter) {
|
||||||
pylint::rules::bad_string_format_character::call(
|
pylint::rules::bad_string_format_character::call(
|
||||||
checker, val, location,
|
checker, string, location,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -462,6 +466,11 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
|
|||||||
if checker.enabled(Rule::OSErrorAlias) {
|
if checker.enabled(Rule::OSErrorAlias) {
|
||||||
pyupgrade::rules::os_error_alias_call(checker, func);
|
pyupgrade::rules::os_error_alias_call(checker, func);
|
||||||
}
|
}
|
||||||
|
if checker.enabled(Rule::TimeoutErrorAlias) {
|
||||||
|
if checker.settings.target_version >= PythonVersion::Py310 {
|
||||||
|
pyupgrade::rules::timeout_error_alias_call(checker, func);
|
||||||
|
}
|
||||||
|
}
|
||||||
if checker.enabled(Rule::NonPEP604Isinstance) {
|
if checker.enabled(Rule::NonPEP604Isinstance) {
|
||||||
if checker.settings.target_version >= PythonVersion::Py310 {
|
if checker.settings.target_version >= PythonVersion::Py310 {
|
||||||
pyupgrade::rules::use_pep604_isinstance(checker, expr, func, args);
|
pyupgrade::rules::use_pep604_isinstance(checker, expr, func, args);
|
||||||
@@ -562,6 +571,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
|
|||||||
if checker.enabled(Rule::Jinja2AutoescapeFalse) {
|
if checker.enabled(Rule::Jinja2AutoescapeFalse) {
|
||||||
flake8_bandit::rules::jinja2_autoescape_false(checker, call);
|
flake8_bandit::rules::jinja2_autoescape_false(checker, call);
|
||||||
}
|
}
|
||||||
|
if checker.enabled(Rule::MakoTemplates) {
|
||||||
|
flake8_bandit::rules::mako_templates(checker, call);
|
||||||
|
}
|
||||||
if checker.enabled(Rule::HardcodedPasswordFuncArg) {
|
if checker.enabled(Rule::HardcodedPasswordFuncArg) {
|
||||||
flake8_bandit::rules::hardcoded_password_func_arg(checker, keywords);
|
flake8_bandit::rules::hardcoded_password_func_arg(checker, keywords);
|
||||||
}
|
}
|
||||||
@@ -749,6 +761,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
|
|||||||
if checker.enabled(Rule::SysExitAlias) {
|
if checker.enabled(Rule::SysExitAlias) {
|
||||||
pylint::rules::sys_exit_alias(checker, func);
|
pylint::rules::sys_exit_alias(checker, func);
|
||||||
}
|
}
|
||||||
|
if checker.enabled(Rule::BadOpenMode) {
|
||||||
|
pylint::rules::bad_open_mode(checker, call);
|
||||||
|
}
|
||||||
if checker.enabled(Rule::BadStrStripCall) {
|
if checker.enabled(Rule::BadStrStripCall) {
|
||||||
pylint::rules::bad_str_strip_call(checker, func, args);
|
pylint::rules::bad_str_strip_call(checker, func, args);
|
||||||
}
|
}
|
||||||
@@ -908,9 +923,18 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
|
|||||||
if checker.enabled(Rule::ExceptionWithoutExcInfo) {
|
if checker.enabled(Rule::ExceptionWithoutExcInfo) {
|
||||||
flake8_logging::rules::exception_without_exc_info(checker, call);
|
flake8_logging::rules::exception_without_exc_info(checker, call);
|
||||||
}
|
}
|
||||||
|
if checker.enabled(Rule::IsinstanceTypeNone) {
|
||||||
|
refurb::rules::isinstance_type_none(checker, call);
|
||||||
|
}
|
||||||
if checker.enabled(Rule::ImplicitCwd) {
|
if checker.enabled(Rule::ImplicitCwd) {
|
||||||
refurb::rules::no_implicit_cwd(checker, call);
|
refurb::rules::no_implicit_cwd(checker, call);
|
||||||
}
|
}
|
||||||
|
if checker.enabled(Rule::TrioSyncCall) {
|
||||||
|
flake8_trio::rules::sync_call(checker, call);
|
||||||
|
}
|
||||||
|
if checker.enabled(Rule::TrioZeroSleepCall) {
|
||||||
|
flake8_trio::rules::zero_sleep_call(checker, call);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Expr::Dict(
|
Expr::Dict(
|
||||||
dict @ ast::ExprDict {
|
dict @ ast::ExprDict {
|
||||||
@@ -987,11 +1011,7 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
|
|||||||
right,
|
right,
|
||||||
range: _,
|
range: _,
|
||||||
}) => {
|
}) => {
|
||||||
if let Expr::Constant(ast::ExprConstant {
|
if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = left.as_ref() {
|
||||||
value: Constant::Str(ast::StringConstant { value, .. }),
|
|
||||||
..
|
|
||||||
}) = left.as_ref()
|
|
||||||
{
|
|
||||||
if checker.any_enabled(&[
|
if checker.any_enabled(&[
|
||||||
Rule::PercentFormatInvalidFormat,
|
Rule::PercentFormatInvalidFormat,
|
||||||
Rule::PercentFormatExpectedMapping,
|
Rule::PercentFormatExpectedMapping,
|
||||||
@@ -1224,42 +1244,36 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
|
|||||||
comparators,
|
comparators,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if checker.enabled(Rule::TypeNoneComparison) {
|
||||||
|
refurb::rules::type_none_comparison(checker, compare);
|
||||||
|
}
|
||||||
if checker.enabled(Rule::SingleItemMembershipTest) {
|
if checker.enabled(Rule::SingleItemMembershipTest) {
|
||||||
refurb::rules::single_item_membership_test(checker, expr, left, ops, comparators);
|
refurb::rules::single_item_membership_test(checker, expr, left, ops, comparators);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Constant(ast::ExprConstant {
|
Expr::NumberLiteral(_) => {
|
||||||
value: Constant::Int(_) | Constant::Float(_) | Constant::Complex { .. },
|
|
||||||
range: _,
|
|
||||||
}) => {
|
|
||||||
if checker.source_type.is_stub() && checker.enabled(Rule::NumericLiteralTooLong) {
|
if checker.source_type.is_stub() && checker.enabled(Rule::NumericLiteralTooLong) {
|
||||||
flake8_pyi::rules::numeric_literal_too_long(checker, expr);
|
flake8_pyi::rules::numeric_literal_too_long(checker, expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Constant(ast::ExprConstant {
|
Expr::BytesLiteral(_) => {
|
||||||
value: Constant::Bytes(_),
|
|
||||||
range: _,
|
|
||||||
}) => {
|
|
||||||
if checker.source_type.is_stub() && checker.enabled(Rule::StringOrBytesTooLong) {
|
if checker.source_type.is_stub() && checker.enabled(Rule::StringOrBytesTooLong) {
|
||||||
flake8_pyi::rules::string_or_bytes_too_long(checker, expr);
|
flake8_pyi::rules::string_or_bytes_too_long(checker, expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Constant(ast::ExprConstant {
|
Expr::StringLiteral(string) => {
|
||||||
value: Constant::Str(value),
|
|
||||||
range: _,
|
|
||||||
}) => {
|
|
||||||
if checker.enabled(Rule::HardcodedBindAllInterfaces) {
|
if checker.enabled(Rule::HardcodedBindAllInterfaces) {
|
||||||
if let Some(diagnostic) =
|
if let Some(diagnostic) =
|
||||||
flake8_bandit::rules::hardcoded_bind_all_interfaces(value, expr.range())
|
flake8_bandit::rules::hardcoded_bind_all_interfaces(string)
|
||||||
{
|
{
|
||||||
checker.diagnostics.push(diagnostic);
|
checker.diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::HardcodedTempFile) {
|
if checker.enabled(Rule::HardcodedTempFile) {
|
||||||
flake8_bandit::rules::hardcoded_tmp_directory(checker, expr, value);
|
flake8_bandit::rules::hardcoded_tmp_directory(checker, string);
|
||||||
}
|
}
|
||||||
if checker.enabled(Rule::UnicodeKindPrefix) {
|
if checker.enabled(Rule::UnicodeKindPrefix) {
|
||||||
pyupgrade::rules::unicode_kind_prefix(checker, expr, value.unicode);
|
pyupgrade::rules::unicode_kind_prefix(checker, string);
|
||||||
}
|
}
|
||||||
if checker.source_type.is_stub() {
|
if checker.source_type.is_stub() {
|
||||||
if checker.enabled(Rule::StringOrBytesTooLong) {
|
if checker.enabled(Rule::StringOrBytesTooLong) {
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ use crate::rules::{
|
|||||||
airflow, flake8_bandit, flake8_boolean_trap, flake8_bugbear, flake8_builtins, flake8_debugger,
|
airflow, flake8_bandit, flake8_boolean_trap, flake8_bugbear, flake8_builtins, flake8_debugger,
|
||||||
flake8_django, flake8_errmsg, flake8_import_conventions, flake8_pie, flake8_pyi,
|
flake8_django, flake8_errmsg, flake8_import_conventions, flake8_pie, flake8_pyi,
|
||||||
flake8_pytest_style, flake8_raise, flake8_return, flake8_simplify, flake8_slots,
|
flake8_pytest_style, flake8_raise, flake8_return, flake8_simplify, flake8_slots,
|
||||||
flake8_tidy_imports, flake8_type_checking, mccabe, pandas_vet, pep8_naming, perflint,
|
flake8_tidy_imports, flake8_trio, flake8_type_checking, mccabe, pandas_vet, pep8_naming,
|
||||||
pycodestyle, pyflakes, pygrep_hooks, pylint, pyupgrade, refurb, ruff, tryceratops,
|
perflint, pycodestyle, pyflakes, pygrep_hooks, pylint, pyupgrade, refurb, ruff, tryceratops,
|
||||||
};
|
};
|
||||||
use crate::settings::types::PythonVersion;
|
use crate::settings::types::PythonVersion;
|
||||||
|
|
||||||
@@ -356,6 +356,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
|||||||
flake8_builtins::rules::builtin_variable_shadowing(checker, name, name.range());
|
flake8_builtins::rules::builtin_variable_shadowing(checker, name, name.range());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if checker.enabled(Rule::TrioAsyncFunctionWithTimeout) {
|
||||||
|
flake8_trio::rules::async_function_with_timeout(checker, function_def);
|
||||||
|
}
|
||||||
#[cfg(feature = "unreachable-code")]
|
#[cfg(feature = "unreachable-code")]
|
||||||
if checker.enabled(Rule::UnreachableCode) {
|
if checker.enabled(Rule::UnreachableCode) {
|
||||||
checker
|
checker
|
||||||
@@ -530,6 +533,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
|||||||
if checker.enabled(Rule::ModuleImportNotAtTopOfFile) {
|
if checker.enabled(Rule::ModuleImportNotAtTopOfFile) {
|
||||||
pycodestyle::rules::module_import_not_at_top_of_file(checker, stmt);
|
pycodestyle::rules::module_import_not_at_top_of_file(checker, stmt);
|
||||||
}
|
}
|
||||||
|
if checker.enabled(Rule::ImportOutsideTopLevel) {
|
||||||
|
pylint::rules::import_outside_top_level(checker, stmt);
|
||||||
|
}
|
||||||
if checker.enabled(Rule::GlobalStatement) {
|
if checker.enabled(Rule::GlobalStatement) {
|
||||||
for name in names {
|
for name in names {
|
||||||
if let Some(asname) = name.asname.as_ref() {
|
if let Some(asname) = name.asname.as_ref() {
|
||||||
@@ -706,6 +712,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
|||||||
if checker.enabled(Rule::ModuleImportNotAtTopOfFile) {
|
if checker.enabled(Rule::ModuleImportNotAtTopOfFile) {
|
||||||
pycodestyle::rules::module_import_not_at_top_of_file(checker, stmt);
|
pycodestyle::rules::module_import_not_at_top_of_file(checker, stmt);
|
||||||
}
|
}
|
||||||
|
if checker.enabled(Rule::ImportOutsideTopLevel) {
|
||||||
|
pylint::rules::import_outside_top_level(checker, stmt);
|
||||||
|
}
|
||||||
if checker.enabled(Rule::GlobalStatement) {
|
if checker.enabled(Rule::GlobalStatement) {
|
||||||
for name in names {
|
for name in names {
|
||||||
if let Some(asname) = name.asname.as_ref() {
|
if let Some(asname) = name.asname.as_ref() {
|
||||||
@@ -1000,6 +1009,13 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
|||||||
pyupgrade::rules::os_error_alias_raise(checker, item);
|
pyupgrade::rules::os_error_alias_raise(checker, item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if checker.enabled(Rule::TimeoutErrorAlias) {
|
||||||
|
if checker.settings.target_version >= PythonVersion::Py310 {
|
||||||
|
if let Some(item) = exc {
|
||||||
|
pyupgrade::rules::timeout_error_alias_raise(checker, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if checker.enabled(Rule::RaiseVanillaClass) {
|
if checker.enabled(Rule::RaiseVanillaClass) {
|
||||||
if let Some(expr) = exc {
|
if let Some(expr) = exc {
|
||||||
tryceratops::rules::raise_vanilla_class(checker, expr);
|
tryceratops::rules::raise_vanilla_class(checker, expr);
|
||||||
@@ -1186,8 +1202,14 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
|||||||
if checker.enabled(Rule::ReadWholeFile) {
|
if checker.enabled(Rule::ReadWholeFile) {
|
||||||
refurb::rules::read_whole_file(checker, with_stmt);
|
refurb::rules::read_whole_file(checker, with_stmt);
|
||||||
}
|
}
|
||||||
|
if checker.enabled(Rule::UselessWithLock) {
|
||||||
|
pylint::rules::useless_with_lock(checker, with_stmt);
|
||||||
|
}
|
||||||
|
if checker.enabled(Rule::TrioTimeoutWithoutAwait) {
|
||||||
|
flake8_trio::rules::timeout_without_await(checker, with_stmt, items);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Stmt::While(ast::StmtWhile { body, orelse, .. }) => {
|
Stmt::While(while_stmt @ ast::StmtWhile { body, orelse, .. }) => {
|
||||||
if checker.enabled(Rule::FunctionUsesLoopVariable) {
|
if checker.enabled(Rule::FunctionUsesLoopVariable) {
|
||||||
flake8_bugbear::rules::function_uses_loop_variable(checker, &Node::Stmt(stmt));
|
flake8_bugbear::rules::function_uses_loop_variable(checker, &Node::Stmt(stmt));
|
||||||
}
|
}
|
||||||
@@ -1197,6 +1219,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
|||||||
if checker.enabled(Rule::TryExceptInLoop) {
|
if checker.enabled(Rule::TryExceptInLoop) {
|
||||||
perflint::rules::try_except_in_loop(checker, body);
|
perflint::rules::try_except_in_loop(checker, body);
|
||||||
}
|
}
|
||||||
|
if checker.enabled(Rule::TrioUnneededSleep) {
|
||||||
|
flake8_trio::rules::unneeded_sleep(checker, while_stmt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Stmt::For(
|
Stmt::For(
|
||||||
for_stmt @ ast::StmtFor {
|
for_stmt @ ast::StmtFor {
|
||||||
@@ -1292,6 +1317,11 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
|
|||||||
if checker.enabled(Rule::OSErrorAlias) {
|
if checker.enabled(Rule::OSErrorAlias) {
|
||||||
pyupgrade::rules::os_error_alias_handlers(checker, handlers);
|
pyupgrade::rules::os_error_alias_handlers(checker, handlers);
|
||||||
}
|
}
|
||||||
|
if checker.enabled(Rule::TimeoutErrorAlias) {
|
||||||
|
if checker.settings.target_version >= PythonVersion::Py310 {
|
||||||
|
pyupgrade::rules::timeout_error_alias_handlers(checker, handlers);
|
||||||
|
}
|
||||||
|
}
|
||||||
if checker.enabled(Rule::PytestAssertInExcept) {
|
if checker.enabled(Rule::PytestAssertInExcept) {
|
||||||
flake8_pytest_style::rules::assert_in_exception_handler(checker, handlers);
|
flake8_pytest_style::rules::assert_in_exception_handler(checker, handlers);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,9 +31,8 @@ use std::path::Path;
|
|||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use ruff_python_ast::{
|
use ruff_python_ast::{
|
||||||
self as ast, Arguments, Comprehension, Constant, ElifElseClause, ExceptHandler, Expr,
|
self as ast, Arguments, Comprehension, ElifElseClause, ExceptHandler, Expr, ExprContext,
|
||||||
ExprContext, Keyword, MatchCase, Parameter, ParameterWithDefault, Parameters, Pattern, Stmt,
|
Keyword, MatchCase, Parameter, ParameterWithDefault, Parameters, Pattern, Stmt, Suite, UnaryOp,
|
||||||
Suite, UnaryOp,
|
|
||||||
};
|
};
|
||||||
use ruff_text_size::{Ranged, TextRange, TextSize};
|
use ruff_text_size::{Ranged, TextRange, TextSize};
|
||||||
|
|
||||||
@@ -787,11 +786,7 @@ where
|
|||||||
&& self.semantic.in_type_definition()
|
&& self.semantic.in_type_definition()
|
||||||
&& self.semantic.future_annotations()
|
&& self.semantic.future_annotations()
|
||||||
{
|
{
|
||||||
if let Expr::Constant(ast::ExprConstant {
|
if let Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) = expr {
|
||||||
value: Constant::Str(value),
|
|
||||||
..
|
|
||||||
}) = expr
|
|
||||||
{
|
|
||||||
self.deferred.string_type_definitions.push((
|
self.deferred.string_type_definitions.push((
|
||||||
expr.range(),
|
expr.range(),
|
||||||
value,
|
value,
|
||||||
@@ -1186,10 +1181,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Constant(ast::ExprConstant {
|
Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => {
|
||||||
value: Constant::Str(value),
|
|
||||||
range: _,
|
|
||||||
}) => {
|
|
||||||
if self.semantic.in_type_definition()
|
if self.semantic.in_type_definition()
|
||||||
&& !self.semantic.in_literal()
|
&& !self.semantic.in_literal()
|
||||||
&& !self.semantic.in_f_string()
|
&& !self.semantic.in_f_string()
|
||||||
@@ -1423,7 +1415,7 @@ impl<'a> Checker<'a> {
|
|||||||
// subsequent nodes are evaluated in the inner scope.
|
// subsequent nodes are evaluated in the inner scope.
|
||||||
//
|
//
|
||||||
// For example, given:
|
// For example, given:
|
||||||
// ```py
|
// ```python
|
||||||
// class A:
|
// class A:
|
||||||
// T = range(10)
|
// T = range(10)
|
||||||
//
|
//
|
||||||
@@ -1431,7 +1423,7 @@ impl<'a> Checker<'a> {
|
|||||||
// ```
|
// ```
|
||||||
//
|
//
|
||||||
// Conceptually, this is compiled as:
|
// Conceptually, this is compiled as:
|
||||||
// ```py
|
// ```python
|
||||||
// class A:
|
// class A:
|
||||||
// T = range(10)
|
// T = range(10)
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -211,6 +211,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
|
|||||||
(Pylint, "C0205") => (RuleGroup::Stable, rules::pylint::rules::SingleStringSlots),
|
(Pylint, "C0205") => (RuleGroup::Stable, rules::pylint::rules::SingleStringSlots),
|
||||||
(Pylint, "C0208") => (RuleGroup::Stable, rules::pylint::rules::IterationOverSet),
|
(Pylint, "C0208") => (RuleGroup::Stable, rules::pylint::rules::IterationOverSet),
|
||||||
(Pylint, "C0414") => (RuleGroup::Stable, rules::pylint::rules::UselessImportAlias),
|
(Pylint, "C0414") => (RuleGroup::Stable, rules::pylint::rules::UselessImportAlias),
|
||||||
|
(Pylint, "C0415") => (RuleGroup::Preview, rules::pylint::rules::ImportOutsideTopLevel),
|
||||||
(Pylint, "C2401") => (RuleGroup::Preview, rules::pylint::rules::NonAsciiName),
|
(Pylint, "C2401") => (RuleGroup::Preview, rules::pylint::rules::NonAsciiName),
|
||||||
(Pylint, "C2403") => (RuleGroup::Preview, rules::pylint::rules::NonAsciiImportName),
|
(Pylint, "C2403") => (RuleGroup::Preview, rules::pylint::rules::NonAsciiImportName),
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
@@ -270,12 +271,14 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
|
|||||||
(Pylint, "W0604") => (RuleGroup::Preview, rules::pylint::rules::GlobalAtModuleLevel),
|
(Pylint, "W0604") => (RuleGroup::Preview, rules::pylint::rules::GlobalAtModuleLevel),
|
||||||
(Pylint, "W0603") => (RuleGroup::Stable, rules::pylint::rules::GlobalStatement),
|
(Pylint, "W0603") => (RuleGroup::Stable, rules::pylint::rules::GlobalStatement),
|
||||||
(Pylint, "W0711") => (RuleGroup::Stable, rules::pylint::rules::BinaryOpException),
|
(Pylint, "W0711") => (RuleGroup::Stable, rules::pylint::rules::BinaryOpException),
|
||||||
|
(Pylint, "W1501") => (RuleGroup::Preview, rules::pylint::rules::BadOpenMode),
|
||||||
(Pylint, "W1508") => (RuleGroup::Stable, rules::pylint::rules::InvalidEnvvarDefault),
|
(Pylint, "W1508") => (RuleGroup::Stable, rules::pylint::rules::InvalidEnvvarDefault),
|
||||||
(Pylint, "W1509") => (RuleGroup::Stable, rules::pylint::rules::SubprocessPopenPreexecFn),
|
(Pylint, "W1509") => (RuleGroup::Stable, rules::pylint::rules::SubprocessPopenPreexecFn),
|
||||||
(Pylint, "W1510") => (RuleGroup::Stable, rules::pylint::rules::SubprocessRunWithoutCheck),
|
(Pylint, "W1510") => (RuleGroup::Stable, rules::pylint::rules::SubprocessRunWithoutCheck),
|
||||||
(Pylint, "W1514") => (RuleGroup::Preview, rules::pylint::rules::UnspecifiedEncoding),
|
(Pylint, "W1514") => (RuleGroup::Preview, rules::pylint::rules::UnspecifiedEncoding),
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
(Pylint, "W1641") => (RuleGroup::Nursery, rules::pylint::rules::EqWithoutHash),
|
(Pylint, "W1641") => (RuleGroup::Nursery, rules::pylint::rules::EqWithoutHash),
|
||||||
|
(Pylint, "W2101") => (RuleGroup::Preview, rules::pylint::rules::UselessWithLock),
|
||||||
(Pylint, "R0904") => (RuleGroup::Preview, rules::pylint::rules::TooManyPublicMethods),
|
(Pylint, "R0904") => (RuleGroup::Preview, rules::pylint::rules::TooManyPublicMethods),
|
||||||
(Pylint, "W2901") => (RuleGroup::Stable, rules::pylint::rules::RedefinedLoopName),
|
(Pylint, "W2901") => (RuleGroup::Stable, rules::pylint::rules::RedefinedLoopName),
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
@@ -287,6 +290,13 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
|
|||||||
(Flake8Async, "101") => (RuleGroup::Stable, rules::flake8_async::rules::OpenSleepOrSubprocessInAsyncFunction),
|
(Flake8Async, "101") => (RuleGroup::Stable, rules::flake8_async::rules::OpenSleepOrSubprocessInAsyncFunction),
|
||||||
(Flake8Async, "102") => (RuleGroup::Stable, rules::flake8_async::rules::BlockingOsCallInAsyncFunction),
|
(Flake8Async, "102") => (RuleGroup::Stable, rules::flake8_async::rules::BlockingOsCallInAsyncFunction),
|
||||||
|
|
||||||
|
// flake8-trio
|
||||||
|
(Flake8Trio, "100") => (RuleGroup::Preview, rules::flake8_trio::rules::TrioTimeoutWithoutAwait),
|
||||||
|
(Flake8Trio, "105") => (RuleGroup::Preview, rules::flake8_trio::rules::TrioSyncCall),
|
||||||
|
(Flake8Trio, "109") => (RuleGroup::Preview, rules::flake8_trio::rules::TrioAsyncFunctionWithTimeout),
|
||||||
|
(Flake8Trio, "110") => (RuleGroup::Preview, rules::flake8_trio::rules::TrioUnneededSleep),
|
||||||
|
(Flake8Trio, "115") => (RuleGroup::Preview, rules::flake8_trio::rules::TrioZeroSleepCall),
|
||||||
|
|
||||||
// flake8-builtins
|
// flake8-builtins
|
||||||
(Flake8Builtins, "001") => (RuleGroup::Stable, rules::flake8_builtins::rules::BuiltinVariableShadowing),
|
(Flake8Builtins, "001") => (RuleGroup::Stable, rules::flake8_builtins::rules::BuiltinVariableShadowing),
|
||||||
(Flake8Builtins, "002") => (RuleGroup::Stable, rules::flake8_builtins::rules::BuiltinArgumentShadowing),
|
(Flake8Builtins, "002") => (RuleGroup::Stable, rules::flake8_builtins::rules::BuiltinArgumentShadowing),
|
||||||
@@ -494,6 +504,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
|
|||||||
(Pyupgrade, "038") => (RuleGroup::Stable, rules::pyupgrade::rules::NonPEP604Isinstance),
|
(Pyupgrade, "038") => (RuleGroup::Stable, rules::pyupgrade::rules::NonPEP604Isinstance),
|
||||||
(Pyupgrade, "039") => (RuleGroup::Stable, rules::pyupgrade::rules::UnnecessaryClassParentheses),
|
(Pyupgrade, "039") => (RuleGroup::Stable, rules::pyupgrade::rules::UnnecessaryClassParentheses),
|
||||||
(Pyupgrade, "040") => (RuleGroup::Stable, rules::pyupgrade::rules::NonPEP695TypeAlias),
|
(Pyupgrade, "040") => (RuleGroup::Stable, rules::pyupgrade::rules::NonPEP695TypeAlias),
|
||||||
|
(Pyupgrade, "041") => (RuleGroup::Preview, rules::pyupgrade::rules::TimeoutErrorAlias),
|
||||||
|
|
||||||
// pydocstyle
|
// pydocstyle
|
||||||
(Pydocstyle, "100") => (RuleGroup::Stable, rules::pydocstyle::rules::UndocumentedPublicModule),
|
(Pydocstyle, "100") => (RuleGroup::Stable, rules::pydocstyle::rules::UndocumentedPublicModule),
|
||||||
@@ -620,6 +631,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
|
|||||||
(Flake8Bandit, "609") => (RuleGroup::Stable, rules::flake8_bandit::rules::UnixCommandWildcardInjection),
|
(Flake8Bandit, "609") => (RuleGroup::Stable, rules::flake8_bandit::rules::UnixCommandWildcardInjection),
|
||||||
(Flake8Bandit, "612") => (RuleGroup::Stable, rules::flake8_bandit::rules::LoggingConfigInsecureListen),
|
(Flake8Bandit, "612") => (RuleGroup::Stable, rules::flake8_bandit::rules::LoggingConfigInsecureListen),
|
||||||
(Flake8Bandit, "701") => (RuleGroup::Stable, rules::flake8_bandit::rules::Jinja2AutoescapeFalse),
|
(Flake8Bandit, "701") => (RuleGroup::Stable, rules::flake8_bandit::rules::Jinja2AutoescapeFalse),
|
||||||
|
(Flake8Bandit, "702") => (RuleGroup::Preview, rules::flake8_bandit::rules::MakoTemplates),
|
||||||
|
|
||||||
// flake8-boolean-trap
|
// flake8-boolean-trap
|
||||||
(Flake8BooleanTrap, "001") => (RuleGroup::Stable, rules::flake8_boolean_trap::rules::BooleanTypeHintPositionalArgument),
|
(Flake8BooleanTrap, "001") => (RuleGroup::Stable, rules::flake8_boolean_trap::rules::BooleanTypeHintPositionalArgument),
|
||||||
@@ -853,6 +865,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
|
|||||||
(Numpy, "001") => (RuleGroup::Stable, rules::numpy::rules::NumpyDeprecatedTypeAlias),
|
(Numpy, "001") => (RuleGroup::Stable, rules::numpy::rules::NumpyDeprecatedTypeAlias),
|
||||||
(Numpy, "002") => (RuleGroup::Stable, rules::numpy::rules::NumpyLegacyRandom),
|
(Numpy, "002") => (RuleGroup::Stable, rules::numpy::rules::NumpyLegacyRandom),
|
||||||
(Numpy, "003") => (RuleGroup::Stable, rules::numpy::rules::NumpyDeprecatedFunction),
|
(Numpy, "003") => (RuleGroup::Stable, rules::numpy::rules::NumpyDeprecatedFunction),
|
||||||
|
(Numpy, "201") => (RuleGroup::Preview, rules::numpy::rules::Numpy2Deprecation),
|
||||||
|
|
||||||
// ruff
|
// ruff
|
||||||
(Ruff, "001") => (RuleGroup::Stable, rules::ruff::rules::AmbiguousUnicodeCharacterString),
|
(Ruff, "001") => (RuleGroup::Stable, rules::ruff::rules::AmbiguousUnicodeCharacterString),
|
||||||
@@ -935,6 +948,8 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
|
|||||||
(Refurb, "140") => (RuleGroup::Preview, rules::refurb::rules::ReimplementedStarmap),
|
(Refurb, "140") => (RuleGroup::Preview, rules::refurb::rules::ReimplementedStarmap),
|
||||||
(Refurb, "145") => (RuleGroup::Preview, rules::refurb::rules::SliceCopy),
|
(Refurb, "145") => (RuleGroup::Preview, rules::refurb::rules::SliceCopy),
|
||||||
(Refurb, "148") => (RuleGroup::Preview, rules::refurb::rules::UnnecessaryEnumerate),
|
(Refurb, "148") => (RuleGroup::Preview, rules::refurb::rules::UnnecessaryEnumerate),
|
||||||
|
(Refurb, "168") => (RuleGroup::Preview, rules::refurb::rules::IsinstanceTypeNone),
|
||||||
|
(Refurb, "169") => (RuleGroup::Preview, rules::refurb::rules::TypeNoneComparison),
|
||||||
(Refurb, "171") => (RuleGroup::Preview, rules::refurb::rules::SingleItemMembershipTest),
|
(Refurb, "171") => (RuleGroup::Preview, rules::refurb::rules::SingleItemMembershipTest),
|
||||||
(Refurb, "177") => (RuleGroup::Preview, rules::refurb::rules::ImplicitCwd),
|
(Refurb, "177") => (RuleGroup::Preview, rules::refurb::rules::ImplicitCwd),
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
use std::iter::FusedIterator;
|
use std::iter::FusedIterator;
|
||||||
|
|
||||||
use ruff_python_ast::{self as ast, Constant, Expr, Stmt, Suite};
|
use ruff_python_ast::{self as ast, Stmt, Suite};
|
||||||
use ruff_python_parser::lexer::LexResult;
|
use ruff_python_parser::lexer::LexResult;
|
||||||
use ruff_python_parser::Tok;
|
use ruff_python_parser::Tok;
|
||||||
use ruff_text_size::{Ranged, TextSize};
|
use ruff_text_size::{Ranged, TextSize};
|
||||||
@@ -69,15 +69,15 @@ struct StringLinesVisitor<'a> {
|
|||||||
|
|
||||||
impl StatementVisitor<'_> for StringLinesVisitor<'_> {
|
impl StatementVisitor<'_> for StringLinesVisitor<'_> {
|
||||||
fn visit_stmt(&mut self, stmt: &Stmt) {
|
fn visit_stmt(&mut self, stmt: &Stmt) {
|
||||||
if let Stmt::Expr(ast::StmtExpr { value, range: _ }) = stmt {
|
if let Stmt::Expr(ast::StmtExpr {
|
||||||
if let Expr::Constant(ast::ExprConstant {
|
value: expr,
|
||||||
value: Constant::Str(..),
|
range: _,
|
||||||
..
|
}) = stmt
|
||||||
}) = value.as_ref()
|
{
|
||||||
{
|
if expr.is_string_literal_expr() {
|
||||||
for line in UniversalNewlineIterator::with_offset(
|
for line in UniversalNewlineIterator::with_offset(
|
||||||
self.locator.slice(value.as_ref()),
|
self.locator.slice(expr.as_ref()),
|
||||||
value.start(),
|
expr.start(),
|
||||||
) {
|
) {
|
||||||
self.string_lines.push(line.start());
|
self.string_lines.push(line.start());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,30 +1,23 @@
|
|||||||
//! Extract docstrings from an AST.
|
//! Extract docstrings from an AST.
|
||||||
|
|
||||||
use ruff_python_ast::{self as ast, Constant, Expr, Stmt};
|
use ruff_python_ast::{self as ast, Stmt};
|
||||||
use ruff_python_semantic::{Definition, DefinitionId, Definitions, Member, MemberKind};
|
use ruff_python_semantic::{Definition, DefinitionId, Definitions, Member, MemberKind};
|
||||||
|
|
||||||
/// Extract a docstring from a function or class body.
|
/// Extract a docstring from a function or class body.
|
||||||
pub(crate) fn docstring_from(suite: &[Stmt]) -> Option<&Expr> {
|
pub(crate) fn docstring_from(suite: &[Stmt]) -> Option<&ast::ExprStringLiteral> {
|
||||||
let stmt = suite.first()?;
|
let stmt = suite.first()?;
|
||||||
// Require the docstring to be a standalone expression.
|
// Require the docstring to be a standalone expression.
|
||||||
let Stmt::Expr(ast::StmtExpr { value, range: _ }) = stmt else {
|
let Stmt::Expr(ast::StmtExpr { value, range: _ }) = stmt else {
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
// Only match strings.
|
// Only match strings.
|
||||||
if !matches!(
|
value.as_string_literal_expr()
|
||||||
value.as_ref(),
|
|
||||||
Expr::Constant(ast::ExprConstant {
|
|
||||||
value: Constant::Str(_),
|
|
||||||
..
|
|
||||||
})
|
|
||||||
) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
Some(value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extract a docstring from a `Definition`.
|
/// Extract a docstring from a `Definition`.
|
||||||
pub(crate) fn extract_docstring<'a>(definition: &'a Definition<'a>) -> Option<&'a Expr> {
|
pub(crate) fn extract_docstring<'a>(
|
||||||
|
definition: &'a Definition<'a>,
|
||||||
|
) -> Option<&'a ast::ExprStringLiteral> {
|
||||||
match definition {
|
match definition {
|
||||||
Definition::Module(module) => docstring_from(module.python_ast),
|
Definition::Module(module) => docstring_from(module.python_ast),
|
||||||
Definition::Member(member) => docstring_from(member.body()),
|
Definition::Member(member) => docstring_from(member.body()),
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use ruff_python_ast::Expr;
|
use ruff_python_ast::ExprStringLiteral;
|
||||||
use ruff_python_semantic::Definition;
|
use ruff_python_semantic::Definition;
|
||||||
use ruff_text_size::{Ranged, TextRange};
|
use ruff_text_size::{Ranged, TextRange};
|
||||||
|
|
||||||
@@ -14,7 +14,8 @@ pub(crate) mod styles;
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct Docstring<'a> {
|
pub(crate) struct Docstring<'a> {
|
||||||
pub(crate) definition: &'a Definition<'a>,
|
pub(crate) definition: &'a Definition<'a>,
|
||||||
pub(crate) expr: &'a Expr,
|
/// The literal AST node representing the docstring.
|
||||||
|
pub(crate) expr: &'a ExprStringLiteral,
|
||||||
/// The content of the docstring, including the leading and trailing quotes.
|
/// The content of the docstring, including the leading and trailing quotes.
|
||||||
pub(crate) contents: &'a str,
|
pub(crate) contents: &'a str,
|
||||||
/// The range of the docstring body (without the quotes). The range is relative to [`Self::contents`].
|
/// The range of the docstring body (without the quotes). The range is relative to [`Self::contents`].
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ impl<'a> Insertion<'a> {
|
|||||||
Tok::NonLogicalNewline => {}
|
Tok::NonLogicalNewline => {}
|
||||||
Tok::Indent => {
|
Tok::Indent => {
|
||||||
// This is like:
|
// This is like:
|
||||||
// ```py
|
// ```python
|
||||||
// if True:
|
// if True:
|
||||||
// pass
|
// pass
|
||||||
// ```
|
// ```
|
||||||
|
|||||||
@@ -209,7 +209,7 @@ impl<'a> Importer<'a> {
|
|||||||
// We also add a no-op edit to force conflicts with any other fixes that might try to
|
// We also add a no-op edit to force conflicts with any other fixes that might try to
|
||||||
// remove the import. Consider:
|
// remove the import. Consider:
|
||||||
//
|
//
|
||||||
// ```py
|
// ```python
|
||||||
// import sys
|
// import sys
|
||||||
//
|
//
|
||||||
// quit()
|
// quit()
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use itertools::Itertools;
|
|||||||
use log::error;
|
use log::error;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
use ruff_diagnostics::{Applicability, Diagnostic};
|
use ruff_diagnostics::Diagnostic;
|
||||||
use ruff_python_ast::imports::ImportMap;
|
use ruff_python_ast::imports::ImportMap;
|
||||||
use ruff_python_ast::PySourceType;
|
use ruff_python_ast::PySourceType;
|
||||||
use ruff_python_codegen::Stylist;
|
use ruff_python_codegen::Stylist;
|
||||||
@@ -268,24 +268,13 @@ pub fn check_path(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update fix applicability to account for overrides
|
// Update fix applicability to account for overrides
|
||||||
if !settings.extend_safe_fixes.is_empty() || !settings.extend_unsafe_fixes.is_empty() {
|
if !settings.fix_safety.is_empty() {
|
||||||
for diagnostic in &mut diagnostics {
|
for diagnostic in &mut diagnostics {
|
||||||
if let Some(fix) = diagnostic.fix.take() {
|
if let Some(fix) = diagnostic.fix.take() {
|
||||||
// Enforce demotions over promotions so if someone puts a rule in both we are conservative
|
let fixed_applicability = settings
|
||||||
if fix.applicability().is_safe()
|
.fix_safety
|
||||||
&& settings
|
.resolve_applicability(diagnostic.kind.rule(), fix.applicability());
|
||||||
.extend_unsafe_fixes
|
diagnostic.set_fix(fix.with_applicability(fixed_applicability));
|
||||||
.contains(diagnostic.kind.rule())
|
|
||||||
{
|
|
||||||
diagnostic.set_fix(fix.with_applicability(Applicability::Unsafe));
|
|
||||||
} else if fix.applicability().is_unsafe()
|
|
||||||
&& settings.extend_safe_fixes.contains(diagnostic.kind.rule())
|
|
||||||
{
|
|
||||||
diagnostic.set_fix(fix.with_applicability(Applicability::Safe));
|
|
||||||
} else {
|
|
||||||
// Retain the existing fix (will be dropped from `.take()` otherwise)
|
|
||||||
diagnostic.set_fix(fix);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,9 +54,9 @@ impl Display for Diff<'_> {
|
|||||||
|
|
||||||
let message = match self.fix.applicability() {
|
let message = match self.fix.applicability() {
|
||||||
// TODO(zanieb): Adjust this messaging once it's user-facing
|
// TODO(zanieb): Adjust this messaging once it's user-facing
|
||||||
Applicability::Safe => "Fix",
|
Applicability::Safe => "Safe fix",
|
||||||
Applicability::Unsafe => "Suggested fix",
|
Applicability::Unsafe => "Unsafe fix",
|
||||||
Applicability::Display => "Possible fix",
|
Applicability::DisplayOnly => "Display-only fix",
|
||||||
};
|
};
|
||||||
writeln!(f, "ℹ {}", message.blue())?;
|
writeln!(f, "ℹ {}", message.blue())?;
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use pyproject_toml::{BuildSystem, Project};
|
use pyproject_toml::PyProjectToml;
|
||||||
use ruff_text_size::{TextRange, TextSize};
|
use ruff_text_size::{TextRange, TextSize};
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use ruff_diagnostics::Diagnostic;
|
use ruff_diagnostics::Diagnostic;
|
||||||
use ruff_source_file::SourceFile;
|
use ruff_source_file::SourceFile;
|
||||||
@@ -13,16 +12,6 @@ use crate::rules::ruff::rules::InvalidPyprojectToml;
|
|||||||
use crate::settings::LinterSettings;
|
use crate::settings::LinterSettings;
|
||||||
use crate::IOError;
|
use crate::IOError;
|
||||||
|
|
||||||
/// Unlike [`pyproject_toml::PyProjectToml`], in our case `build_system` is also optional
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
|
||||||
#[serde(rename_all = "kebab-case")]
|
|
||||||
struct PyProjectToml {
|
|
||||||
/// Build-related data
|
|
||||||
build_system: Option<BuildSystem>,
|
|
||||||
/// Project metadata
|
|
||||||
project: Option<Project>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn lint_pyproject_toml(source_file: SourceFile, settings: &LinterSettings) -> Vec<Message> {
|
pub fn lint_pyproject_toml(source_file: SourceFile, settings: &LinterSettings) -> Vec<Message> {
|
||||||
let Some(err) = toml::from_str::<PyProjectToml>(source_file.source_text()).err() else {
|
let Some(err) = toml::from_str::<PyProjectToml>(source_file.source_text()).err() else {
|
||||||
return Vec::default();
|
return Vec::default();
|
||||||
|
|||||||
@@ -64,6 +64,9 @@ pub enum Linter {
|
|||||||
/// [flake8-async](https://pypi.org/project/flake8-async/)
|
/// [flake8-async](https://pypi.org/project/flake8-async/)
|
||||||
#[prefix = "ASYNC"]
|
#[prefix = "ASYNC"]
|
||||||
Flake8Async,
|
Flake8Async,
|
||||||
|
/// [flake8-trio](https://pypi.org/project/flake8-trio/)
|
||||||
|
#[prefix = "TRIO"]
|
||||||
|
Flake8Trio,
|
||||||
/// [flake8-bandit](https://pypi.org/project/flake8-bandit/)
|
/// [flake8-bandit](https://pypi.org/project/flake8-bandit/)
|
||||||
#[prefix = "S"]
|
#[prefix = "S"]
|
||||||
Flake8Bandit,
|
Flake8Bandit,
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
use ruff_python_ast as ast;
|
use ruff_python_ast as ast;
|
||||||
use ruff_python_ast::Constant;
|
|
||||||
use ruff_python_ast::Expr;
|
use ruff_python_ast::Expr;
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
@@ -79,13 +78,7 @@ pub(crate) fn variable_name_task_id(
|
|||||||
let keyword = arguments.find_keyword("task_id")?;
|
let keyword = arguments.find_keyword("task_id")?;
|
||||||
|
|
||||||
// If the keyword argument is not a string, we can't do anything.
|
// If the keyword argument is not a string, we can't do anything.
|
||||||
let task_id = match &keyword.value {
|
let ast::ExprStringLiteral { value: task_id, .. } = keyword.value.as_string_literal_expr()?;
|
||||||
Expr::Constant(constant) => match &constant.value {
|
|
||||||
Constant::Str(ast::StringConstant { value, .. }) => value,
|
|
||||||
_ => return None,
|
|
||||||
},
|
|
||||||
_ => return None,
|
|
||||||
};
|
|
||||||
|
|
||||||
// If the target name is the same as the task_id, no violation.
|
// If the target name is the same as the task_id, no violation.
|
||||||
if id == task_id {
|
if id == task_id {
|
||||||
|
|||||||
@@ -163,11 +163,15 @@ mod tests {
|
|||||||
"# ( user_content_type , _ )= TimelineEvent.objects.using(db_alias).get_or_create(",
|
"# ( user_content_type , _ )= TimelineEvent.objects.using(db_alias).get_or_create(",
|
||||||
&[]
|
&[]
|
||||||
));
|
));
|
||||||
assert!(comment_contains_code(
|
assert!(comment_contains_code("# )", &[]));
|
||||||
|
|
||||||
|
// This used to return true, but our parser has gotten a bit better
|
||||||
|
// at rejecting invalid Python syntax. And indeed, this is not valid
|
||||||
|
// Python code.
|
||||||
|
assert!(!comment_contains_code(
|
||||||
"# app_label=\"core\", model=\"user\"",
|
"# app_label=\"core\", model=\"user\"",
|
||||||
&[]
|
&[]
|
||||||
));
|
));
|
||||||
assert!(comment_contains_code("# )", &[]));
|
|
||||||
|
|
||||||
// TODO(charlie): This should be `true` under aggressive mode.
|
// TODO(charlie): This should be `true` under aggressive mode.
|
||||||
assert!(!comment_contains_code("#def foo():", &[]));
|
assert!(!comment_contains_code("#def foo():", &[]));
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ pub(crate) fn commented_out_code(
|
|||||||
if is_standalone_comment(line) && comment_contains_code(line, &settings.task_tags[..]) {
|
if is_standalone_comment(line) && comment_contains_code(line, &settings.task_tags[..]) {
|
||||||
let mut diagnostic = Diagnostic::new(CommentedOutCode, *range);
|
let mut diagnostic = Diagnostic::new(CommentedOutCode, *range);
|
||||||
|
|
||||||
diagnostic.set_fix(Fix::display_edit(Edit::range_deletion(
|
diagnostic.set_fix(Fix::display_only_edit(Edit::range_deletion(
|
||||||
locator.full_lines_range(*range),
|
locator.full_lines_range(*range),
|
||||||
)));
|
)));
|
||||||
diagnostics.push(diagnostic);
|
diagnostics.push(diagnostic);
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ ERA001.py:1:1: ERA001 Found commented-out code
|
|||||||
|
|
|
|
||||||
= help: Remove commented-out code
|
= help: Remove commented-out code
|
||||||
|
|
||||||
ℹ Possible fix
|
ℹ Display-only fix
|
||||||
1 |-#import os
|
1 |-#import os
|
||||||
2 1 | # from foo import junk
|
2 1 | # from foo import junk
|
||||||
3 2 | #a = 3
|
3 2 | #a = 3
|
||||||
@@ -26,7 +26,7 @@ ERA001.py:2:1: ERA001 Found commented-out code
|
|||||||
|
|
|
|
||||||
= help: Remove commented-out code
|
= help: Remove commented-out code
|
||||||
|
|
||||||
ℹ Possible fix
|
ℹ Display-only fix
|
||||||
1 1 | #import os
|
1 1 | #import os
|
||||||
2 |-# from foo import junk
|
2 |-# from foo import junk
|
||||||
3 2 | #a = 3
|
3 2 | #a = 3
|
||||||
@@ -44,7 +44,7 @@ ERA001.py:3:1: ERA001 Found commented-out code
|
|||||||
|
|
|
|
||||||
= help: Remove commented-out code
|
= help: Remove commented-out code
|
||||||
|
|
||||||
ℹ Possible fix
|
ℹ Display-only fix
|
||||||
1 1 | #import os
|
1 1 | #import os
|
||||||
2 2 | # from foo import junk
|
2 2 | # from foo import junk
|
||||||
3 |-#a = 3
|
3 |-#a = 3
|
||||||
@@ -63,7 +63,7 @@ ERA001.py:5:1: ERA001 Found commented-out code
|
|||||||
|
|
|
|
||||||
= help: Remove commented-out code
|
= help: Remove commented-out code
|
||||||
|
|
||||||
ℹ Possible fix
|
ℹ Display-only fix
|
||||||
2 2 | # from foo import junk
|
2 2 | # from foo import junk
|
||||||
3 3 | #a = 3
|
3 3 | #a = 3
|
||||||
4 4 | a = 4
|
4 4 | a = 4
|
||||||
@@ -82,7 +82,7 @@ ERA001.py:13:5: ERA001 Found commented-out code
|
|||||||
|
|
|
|
||||||
= help: Remove commented-out code
|
= help: Remove commented-out code
|
||||||
|
|
||||||
ℹ Possible fix
|
ℹ Display-only fix
|
||||||
10 10 |
|
10 10 |
|
||||||
11 11 | # This is a real comment.
|
11 11 | # This is a real comment.
|
||||||
12 12 | # # This is a (nested) comment.
|
12 12 | # # This is a (nested) comment.
|
||||||
@@ -100,7 +100,7 @@ ERA001.py:21:5: ERA001 Found commented-out code
|
|||||||
|
|
|
|
||||||
= help: Remove commented-out code
|
= help: Remove commented-out code
|
||||||
|
|
||||||
ℹ Possible fix
|
ℹ Display-only fix
|
||||||
18 18 |
|
18 18 |
|
||||||
19 19 | class A():
|
19 19 | class A():
|
||||||
20 20 | pass
|
20 20 | pass
|
||||||
@@ -120,7 +120,7 @@ ERA001.py:26:5: ERA001 Found commented-out code
|
|||||||
|
|
|
|
||||||
= help: Remove commented-out code
|
= help: Remove commented-out code
|
||||||
|
|
||||||
ℹ Possible fix
|
ℹ Display-only fix
|
||||||
23 23 |
|
23 23 |
|
||||||
24 24 | dictionary = {
|
24 24 | dictionary = {
|
||||||
25 25 | # "key1": 123, # noqa: ERA001
|
25 25 | # "key1": 123, # noqa: ERA001
|
||||||
@@ -139,7 +139,7 @@ ERA001.py:27:5: ERA001 Found commented-out code
|
|||||||
|
|
|
|
||||||
= help: Remove commented-out code
|
= help: Remove commented-out code
|
||||||
|
|
||||||
ℹ Possible fix
|
ℹ Display-only fix
|
||||||
24 24 | dictionary = {
|
24 24 | dictionary = {
|
||||||
25 25 | # "key1": 123, # noqa: ERA001
|
25 25 | # "key1": 123, # noqa: ERA001
|
||||||
26 26 | # "key2": 456,
|
26 26 | # "key2": 456,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
use ruff_python_ast::{self as ast, CmpOp, Constant, Expr};
|
use ruff_python_ast::{self as ast, CmpOp, Expr};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
@@ -230,16 +230,16 @@ pub(crate) fn compare(checker: &mut Checker, left: &Expr, ops: &[CmpOp], compara
|
|||||||
Expr::Subscript(ast::ExprSubscript { value, slice, .. })
|
Expr::Subscript(ast::ExprSubscript { value, slice, .. })
|
||||||
if is_sys(value, "version_info", checker.semantic()) =>
|
if is_sys(value, "version_info", checker.semantic()) =>
|
||||||
{
|
{
|
||||||
if let Expr::Constant(ast::ExprConstant {
|
if let Expr::NumberLiteral(ast::ExprNumberLiteral {
|
||||||
value: Constant::Int(i),
|
value: ast::Number::Int(i),
|
||||||
..
|
..
|
||||||
}) = slice.as_ref()
|
}) = slice.as_ref()
|
||||||
{
|
{
|
||||||
if *i == 0 {
|
if *i == 0 {
|
||||||
if let (
|
if let (
|
||||||
[CmpOp::Eq | CmpOp::NotEq],
|
[CmpOp::Eq | CmpOp::NotEq],
|
||||||
[Expr::Constant(ast::ExprConstant {
|
[Expr::NumberLiteral(ast::ExprNumberLiteral {
|
||||||
value: Constant::Int(n),
|
value: ast::Number::Int(n),
|
||||||
..
|
..
|
||||||
})],
|
})],
|
||||||
) = (ops, comparators)
|
) = (ops, comparators)
|
||||||
@@ -253,8 +253,8 @@ pub(crate) fn compare(checker: &mut Checker, left: &Expr, ops: &[CmpOp], compara
|
|||||||
} else if *i == 1 {
|
} else if *i == 1 {
|
||||||
if let (
|
if let (
|
||||||
[CmpOp::Lt | CmpOp::LtE | CmpOp::Gt | CmpOp::GtE],
|
[CmpOp::Lt | CmpOp::LtE | CmpOp::Gt | CmpOp::GtE],
|
||||||
[Expr::Constant(ast::ExprConstant {
|
[Expr::NumberLiteral(ast::ExprNumberLiteral {
|
||||||
value: Constant::Int(_),
|
value: ast::Number::Int(_),
|
||||||
..
|
..
|
||||||
})],
|
})],
|
||||||
) = (ops, comparators)
|
) = (ops, comparators)
|
||||||
@@ -274,8 +274,8 @@ pub(crate) fn compare(checker: &mut Checker, left: &Expr, ops: &[CmpOp], compara
|
|||||||
{
|
{
|
||||||
if let (
|
if let (
|
||||||
[CmpOp::Lt | CmpOp::LtE | CmpOp::Gt | CmpOp::GtE],
|
[CmpOp::Lt | CmpOp::LtE | CmpOp::Gt | CmpOp::GtE],
|
||||||
[Expr::Constant(ast::ExprConstant {
|
[Expr::NumberLiteral(ast::ExprNumberLiteral {
|
||||||
value: Constant::Int(_),
|
value: ast::Number::Int(_),
|
||||||
..
|
..
|
||||||
})],
|
})],
|
||||||
) = (ops, comparators)
|
) = (ops, comparators)
|
||||||
@@ -294,13 +294,10 @@ pub(crate) fn compare(checker: &mut Checker, left: &Expr, ops: &[CmpOp], compara
|
|||||||
if is_sys(left, "version", checker.semantic()) {
|
if is_sys(left, "version", checker.semantic()) {
|
||||||
if let (
|
if let (
|
||||||
[CmpOp::Lt | CmpOp::LtE | CmpOp::Gt | CmpOp::GtE],
|
[CmpOp::Lt | CmpOp::LtE | CmpOp::Gt | CmpOp::GtE],
|
||||||
[Expr::Constant(ast::ExprConstant {
|
[Expr::StringLiteral(ast::ExprStringLiteral { value, .. })],
|
||||||
value: Constant::Str(s),
|
|
||||||
..
|
|
||||||
})],
|
|
||||||
) = (ops, comparators)
|
) = (ops, comparators)
|
||||||
{
|
{
|
||||||
if s.len() == 1 {
|
if value.len() == 1 {
|
||||||
if checker.enabled(Rule::SysVersionCmpStr10) {
|
if checker.enabled(Rule::SysVersionCmpStr10) {
|
||||||
checker
|
checker
|
||||||
.diagnostics
|
.diagnostics
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
use ruff_python_ast::{self as ast, Constant, Expr};
|
use ruff_python_ast::{self as ast, Expr};
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
@@ -177,8 +177,8 @@ pub(crate) fn subscript(checker: &mut Checker, value: &Expr, slice: &Expr) {
|
|||||||
step: None,
|
step: None,
|
||||||
range: _,
|
range: _,
|
||||||
}) => {
|
}) => {
|
||||||
if let Expr::Constant(ast::ExprConstant {
|
if let Expr::NumberLiteral(ast::ExprNumberLiteral {
|
||||||
value: Constant::Int(i),
|
value: ast::Number::Int(i),
|
||||||
..
|
..
|
||||||
}) = upper.as_ref()
|
}) = upper.as_ref()
|
||||||
{
|
{
|
||||||
@@ -194,8 +194,8 @@ pub(crate) fn subscript(checker: &mut Checker, value: &Expr, slice: &Expr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::Constant(ast::ExprConstant {
|
Expr::NumberLiteral(ast::ExprNumberLiteral {
|
||||||
value: Constant::Int(i),
|
value: ast::Number::Int(i),
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
if *i == 2 && checker.enabled(Rule::SysVersion2) {
|
if *i == 2 && checker.enabled(Rule::SysVersion2) {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use ruff_macros::{derive_message_formats, violation};
|
|||||||
use ruff_python_ast::helpers::ReturnStatementVisitor;
|
use ruff_python_ast::helpers::ReturnStatementVisitor;
|
||||||
use ruff_python_ast::identifier::Identifier;
|
use ruff_python_ast::identifier::Identifier;
|
||||||
use ruff_python_ast::statement_visitor::StatementVisitor;
|
use ruff_python_ast::statement_visitor::StatementVisitor;
|
||||||
use ruff_python_ast::{self as ast, Constant, Expr, ParameterWithDefault, Stmt};
|
use ruff_python_ast::{self as ast, Expr, ParameterWithDefault, Stmt};
|
||||||
use ruff_python_parser::typing::parse_type_annotation;
|
use ruff_python_parser::typing::parse_type_annotation;
|
||||||
use ruff_python_semantic::analyze::visibility;
|
use ruff_python_semantic::analyze::visibility;
|
||||||
use ruff_python_semantic::Definition;
|
use ruff_python_semantic::Definition;
|
||||||
@@ -265,7 +265,7 @@ impl Violation for MissingReturnTypePrivateFunction {
|
|||||||
/// or `ruff.toml` file:
|
/// or `ruff.toml` file:
|
||||||
///
|
///
|
||||||
/// ```toml
|
/// ```toml
|
||||||
/// [tool.ruff.flake8-annotations]
|
/// [tool.ruff.lint.flake8-annotations]
|
||||||
/// mypy-init-return = true
|
/// mypy-init-return = true
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
@@ -431,10 +431,7 @@ fn is_none_returning(body: &[Stmt]) -> bool {
|
|||||||
visitor.visit_body(body);
|
visitor.visit_body(body);
|
||||||
for stmt in visitor.returns {
|
for stmt in visitor.returns {
|
||||||
if let Some(value) = stmt.value.as_deref() {
|
if let Some(value) = stmt.value.as_deref() {
|
||||||
if !matches!(
|
if !value.is_none_literal_expr() {
|
||||||
value,
|
|
||||||
Expr::Constant(constant) if constant.value.is_none()
|
|
||||||
) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -451,9 +448,10 @@ fn check_dynamically_typed<F>(
|
|||||||
) where
|
) where
|
||||||
F: FnOnce() -> String,
|
F: FnOnce() -> String,
|
||||||
{
|
{
|
||||||
if let Expr::Constant(ast::ExprConstant {
|
if let Expr::StringLiteral(ast::ExprStringLiteral {
|
||||||
range,
|
range,
|
||||||
value: Constant::Str(string),
|
value: string,
|
||||||
|
..
|
||||||
}) = annotation
|
}) = annotation
|
||||||
{
|
{
|
||||||
// Quoted annotations
|
// Quoted annotations
|
||||||
|
|||||||
@@ -252,7 +252,7 @@ annotation_presence.py:159:9: ANN204 [*] Missing return type annotation for spec
|
|||||||
|
|
|
|
||||||
= help: Add `None` return type
|
= help: Add `None` return type
|
||||||
|
|
||||||
ℹ Suggested fix
|
ℹ Unsafe fix
|
||||||
156 156 |
|
156 156 |
|
||||||
157 157 | class Foo:
|
157 157 | class Foo:
|
||||||
158 158 | @decorator()
|
158 158 | @decorator()
|
||||||
@@ -272,7 +272,7 @@ annotation_presence.py:165:9: ANN204 [*] Missing return type annotation for spec
|
|||||||
|
|
|
|
||||||
= help: Add `None` return type
|
= help: Add `None` return type
|
||||||
|
|
||||||
ℹ Suggested fix
|
ℹ Unsafe fix
|
||||||
162 162 |
|
162 162 |
|
||||||
163 163 | # Regression test for: https://github.com/astral-sh/ruff/issues/7711
|
163 163 | # Regression test for: https://github.com/astral-sh/ruff/issues/7711
|
||||||
164 164 | class Class:
|
164 164 | class Class:
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ mypy_init_return.py:5:9: ANN204 [*] Missing return type annotation for special m
|
|||||||
|
|
|
|
||||||
= help: Add `None` return type
|
= help: Add `None` return type
|
||||||
|
|
||||||
ℹ Suggested fix
|
ℹ Unsafe fix
|
||||||
2 2 |
|
2 2 |
|
||||||
3 3 | # Error
|
3 3 | # Error
|
||||||
4 4 | class Foo:
|
4 4 | class Foo:
|
||||||
@@ -31,7 +31,7 @@ mypy_init_return.py:11:9: ANN204 [*] Missing return type annotation for special
|
|||||||
|
|
|
|
||||||
= help: Add `None` return type
|
= help: Add `None` return type
|
||||||
|
|
||||||
ℹ Suggested fix
|
ℹ Unsafe fix
|
||||||
8 8 |
|
8 8 |
|
||||||
9 9 | # Error
|
9 9 | # Error
|
||||||
10 10 | class Foo:
|
10 10 | class Foo:
|
||||||
@@ -59,7 +59,7 @@ mypy_init_return.py:47:9: ANN204 [*] Missing return type annotation for special
|
|||||||
|
|
|
|
||||||
= help: Add `None` return type
|
= help: Add `None` return type
|
||||||
|
|
||||||
ℹ Suggested fix
|
ℹ Unsafe fix
|
||||||
44 44 | # Error – used to be ok for a moment since the mere presence
|
44 44 | # Error – used to be ok for a moment since the mere presence
|
||||||
45 45 | # of a vararg falsely indicated that the function has a typed argument.
|
45 45 | # of a vararg falsely indicated that the function has a typed argument.
|
||||||
46 46 | class Foo:
|
46 46 | class Foo:
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ simple_magic_methods.py:2:9: ANN204 [*] Missing return type annotation for speci
|
|||||||
|
|
|
|
||||||
= help: Add `None` return type
|
= help: Add `None` return type
|
||||||
|
|
||||||
ℹ Suggested fix
|
ℹ Unsafe fix
|
||||||
1 1 | class Foo:
|
1 1 | class Foo:
|
||||||
2 |- def __str__(self):
|
2 |- def __str__(self):
|
||||||
2 |+ def __str__(self) -> str:
|
2 |+ def __str__(self) -> str:
|
||||||
@@ -28,7 +28,7 @@ simple_magic_methods.py:5:9: ANN204 [*] Missing return type annotation for speci
|
|||||||
|
|
|
|
||||||
= help: Add `None` return type
|
= help: Add `None` return type
|
||||||
|
|
||||||
ℹ Suggested fix
|
ℹ Unsafe fix
|
||||||
2 2 | def __str__(self):
|
2 2 | def __str__(self):
|
||||||
3 3 | ...
|
3 3 | ...
|
||||||
4 4 |
|
4 4 |
|
||||||
@@ -48,7 +48,7 @@ simple_magic_methods.py:8:9: ANN204 [*] Missing return type annotation for speci
|
|||||||
|
|
|
|
||||||
= help: Add `None` return type
|
= help: Add `None` return type
|
||||||
|
|
||||||
ℹ Suggested fix
|
ℹ Unsafe fix
|
||||||
5 5 | def __repr__(self):
|
5 5 | def __repr__(self):
|
||||||
6 6 | ...
|
6 6 | ...
|
||||||
7 7 |
|
7 7 |
|
||||||
@@ -68,7 +68,7 @@ simple_magic_methods.py:11:9: ANN204 [*] Missing return type annotation for spec
|
|||||||
|
|
|
|
||||||
= help: Add `None` return type
|
= help: Add `None` return type
|
||||||
|
|
||||||
ℹ Suggested fix
|
ℹ Unsafe fix
|
||||||
8 8 | def __len__(self):
|
8 8 | def __len__(self):
|
||||||
9 9 | ...
|
9 9 | ...
|
||||||
10 10 |
|
10 10 |
|
||||||
@@ -88,7 +88,7 @@ simple_magic_methods.py:14:9: ANN204 [*] Missing return type annotation for spec
|
|||||||
|
|
|
|
||||||
= help: Add `None` return type
|
= help: Add `None` return type
|
||||||
|
|
||||||
ℹ Suggested fix
|
ℹ Unsafe fix
|
||||||
11 11 | def __length_hint__(self):
|
11 11 | def __length_hint__(self):
|
||||||
12 12 | ...
|
12 12 | ...
|
||||||
13 13 |
|
13 13 |
|
||||||
@@ -108,7 +108,7 @@ simple_magic_methods.py:17:9: ANN204 [*] Missing return type annotation for spec
|
|||||||
|
|
|
|
||||||
= help: Add `None` return type
|
= help: Add `None` return type
|
||||||
|
|
||||||
ℹ Suggested fix
|
ℹ Unsafe fix
|
||||||
14 14 | def __init__(self):
|
14 14 | def __init__(self):
|
||||||
15 15 | ...
|
15 15 | ...
|
||||||
16 16 |
|
16 16 |
|
||||||
@@ -128,7 +128,7 @@ simple_magic_methods.py:20:9: ANN204 [*] Missing return type annotation for spec
|
|||||||
|
|
|
|
||||||
= help: Add `None` return type
|
= help: Add `None` return type
|
||||||
|
|
||||||
ℹ Suggested fix
|
ℹ Unsafe fix
|
||||||
17 17 | def __del__(self):
|
17 17 | def __del__(self):
|
||||||
18 18 | ...
|
18 18 | ...
|
||||||
19 19 |
|
19 19 |
|
||||||
@@ -148,7 +148,7 @@ simple_magic_methods.py:23:9: ANN204 [*] Missing return type annotation for spec
|
|||||||
|
|
|
|
||||||
= help: Add `None` return type
|
= help: Add `None` return type
|
||||||
|
|
||||||
ℹ Suggested fix
|
ℹ Unsafe fix
|
||||||
20 20 | def __bool__(self):
|
20 20 | def __bool__(self):
|
||||||
21 21 | ...
|
21 21 | ...
|
||||||
22 22 |
|
22 22 |
|
||||||
@@ -168,7 +168,7 @@ simple_magic_methods.py:26:9: ANN204 [*] Missing return type annotation for spec
|
|||||||
|
|
|
|
||||||
= help: Add `None` return type
|
= help: Add `None` return type
|
||||||
|
|
||||||
ℹ Suggested fix
|
ℹ Unsafe fix
|
||||||
23 23 | def __bytes__(self):
|
23 23 | def __bytes__(self):
|
||||||
24 24 | ...
|
24 24 | ...
|
||||||
25 25 |
|
25 25 |
|
||||||
@@ -188,7 +188,7 @@ simple_magic_methods.py:29:9: ANN204 [*] Missing return type annotation for spec
|
|||||||
|
|
|
|
||||||
= help: Add `None` return type
|
= help: Add `None` return type
|
||||||
|
|
||||||
ℹ Suggested fix
|
ℹ Unsafe fix
|
||||||
26 26 | def __format__(self, format_spec):
|
26 26 | def __format__(self, format_spec):
|
||||||
27 27 | ...
|
27 27 | ...
|
||||||
28 28 |
|
28 28 |
|
||||||
@@ -208,7 +208,7 @@ simple_magic_methods.py:32:9: ANN204 [*] Missing return type annotation for spec
|
|||||||
|
|
|
|
||||||
= help: Add `None` return type
|
= help: Add `None` return type
|
||||||
|
|
||||||
ℹ Suggested fix
|
ℹ Unsafe fix
|
||||||
29 29 | def __contains__(self, item):
|
29 29 | def __contains__(self, item):
|
||||||
30 30 | ...
|
30 30 | ...
|
||||||
31 31 |
|
31 31 |
|
||||||
@@ -228,7 +228,7 @@ simple_magic_methods.py:35:9: ANN204 [*] Missing return type annotation for spec
|
|||||||
|
|
|
|
||||||
= help: Add `None` return type
|
= help: Add `None` return type
|
||||||
|
|
||||||
ℹ Suggested fix
|
ℹ Unsafe fix
|
||||||
32 32 | def __complex__(self):
|
32 32 | def __complex__(self):
|
||||||
33 33 | ...
|
33 33 | ...
|
||||||
34 34 |
|
34 34 |
|
||||||
@@ -248,7 +248,7 @@ simple_magic_methods.py:38:9: ANN204 [*] Missing return type annotation for spec
|
|||||||
|
|
|
|
||||||
= help: Add `None` return type
|
= help: Add `None` return type
|
||||||
|
|
||||||
ℹ Suggested fix
|
ℹ Unsafe fix
|
||||||
35 35 | def __int__(self):
|
35 35 | def __int__(self):
|
||||||
36 36 | ...
|
36 36 | ...
|
||||||
37 37 |
|
37 37 |
|
||||||
@@ -268,7 +268,7 @@ simple_magic_methods.py:41:9: ANN204 [*] Missing return type annotation for spec
|
|||||||
|
|
|
|
||||||
= help: Add `None` return type
|
= help: Add `None` return type
|
||||||
|
|
||||||
ℹ Suggested fix
|
ℹ Unsafe fix
|
||||||
38 38 | def __float__(self):
|
38 38 | def __float__(self):
|
||||||
39 39 | ...
|
39 39 | ...
|
||||||
40 40 |
|
40 40 |
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use ruff_python_ast::{self as ast, Constant, Expr};
|
use ruff_python_ast::{self as ast, Expr};
|
||||||
|
|
||||||
use ruff_python_semantic::SemanticModel;
|
use ruff_python_semantic::SemanticModel;
|
||||||
|
|
||||||
@@ -10,10 +10,7 @@ static PASSWORD_CANDIDATE_REGEX: Lazy<Regex> = Lazy::new(|| {
|
|||||||
|
|
||||||
pub(super) fn string_literal(expr: &Expr) -> Option<&str> {
|
pub(super) fn string_literal(expr: &Expr) -> Option<&str> {
|
||||||
match expr {
|
match expr {
|
||||||
Expr::Constant(ast::ExprConstant {
|
Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => Some(value),
|
||||||
value: Constant::Str(string),
|
|
||||||
..
|
|
||||||
}) => Some(string),
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ mod tests {
|
|||||||
#[test_case(Rule::HardcodedTempFile, Path::new("S108.py"))]
|
#[test_case(Rule::HardcodedTempFile, Path::new("S108.py"))]
|
||||||
#[test_case(Rule::HashlibInsecureHashFunction, Path::new("S324.py"))]
|
#[test_case(Rule::HashlibInsecureHashFunction, Path::new("S324.py"))]
|
||||||
#[test_case(Rule::Jinja2AutoescapeFalse, Path::new("S701.py"))]
|
#[test_case(Rule::Jinja2AutoescapeFalse, Path::new("S701.py"))]
|
||||||
|
#[test_case(Rule::MakoTemplates, Path::new("S702.py"))]
|
||||||
#[test_case(Rule::LoggingConfigInsecureListen, Path::new("S612.py"))]
|
#[test_case(Rule::LoggingConfigInsecureListen, Path::new("S612.py"))]
|
||||||
#[test_case(Rule::ParamikoCall, Path::new("S601.py"))]
|
#[test_case(Rule::ParamikoCall, Path::new("S601.py"))]
|
||||||
#[test_case(Rule::RequestWithNoCertValidation, Path::new("S501.py"))]
|
#[test_case(Rule::RequestWithNoCertValidation, Path::new("S501.py"))]
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use anyhow::Result;
|
|||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
use ruff_python_ast::call_path::CallPath;
|
use ruff_python_ast::call_path::CallPath;
|
||||||
use ruff_python_ast::{self as ast, Constant, Expr, Operator};
|
use ruff_python_ast::{self as ast, Expr, Operator};
|
||||||
use ruff_python_semantic::SemanticModel;
|
use ruff_python_semantic::SemanticModel;
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
||||||
@@ -144,8 +144,8 @@ fn py_stat(call_path: &CallPath) -> Option<u16> {
|
|||||||
/// an integer value, but that value is out of range.
|
/// an integer value, but that value is out of range.
|
||||||
fn parse_mask(expr: &Expr, semantic: &SemanticModel) -> Result<Option<u16>> {
|
fn parse_mask(expr: &Expr, semantic: &SemanticModel) -> Result<Option<u16>> {
|
||||||
match expr {
|
match expr {
|
||||||
Expr::Constant(ast::ExprConstant {
|
Expr::NumberLiteral(ast::ExprNumberLiteral {
|
||||||
value: Constant::Int(int),
|
value: ast::Number::Int(int),
|
||||||
..
|
..
|
||||||
}) => match int.as_u16() {
|
}) => match int.as_u16() {
|
||||||
Some(value) => Ok(Some(value)),
|
Some(value) => Ok(Some(value)),
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
use ruff_text_size::TextRange;
|
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
use ruff_python_ast::ExprStringLiteral;
|
||||||
|
|
||||||
/// ## What it does
|
/// ## What it does
|
||||||
/// Checks for hardcoded bindings to all network interfaces (`0.0.0.0`).
|
/// Checks for hardcoded bindings to all network interfaces (`0.0.0.0`).
|
||||||
@@ -35,9 +34,9 @@ impl Violation for HardcodedBindAllInterfaces {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// S104
|
/// S104
|
||||||
pub(crate) fn hardcoded_bind_all_interfaces(value: &str, range: TextRange) -> Option<Diagnostic> {
|
pub(crate) fn hardcoded_bind_all_interfaces(string: &ExprStringLiteral) -> Option<Diagnostic> {
|
||||||
if value == "0.0.0.0" {
|
if string.value == "0.0.0.0" {
|
||||||
Some(Diagnostic::new(HardcodedBindAllInterfaces, range))
|
Some(Diagnostic::new(HardcodedBindAllInterfaces, string.range))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user